diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml
index acb48669c..f85085c63 100644
--- a/.github/workflows/main.yml
+++ b/.github/workflows/main.yml
@@ -45,7 +45,8 @@ jobs:
'rp2040:rp2040:generic',
'rp2040:rp2040:rpipicow',
'arduino:mbed_rp2040:pico',
- 'SiliconLabs:silabs:nano_matter'
+ 'SiliconLabs:silabs:nano_matter',
+ 'WCH:ch32v:CH32V30x_EVT'
]
env:
@@ -416,6 +417,12 @@ jobs:
# arduino-cli board attach -b $BOARD ;
cd $GITHUB_WORKSPACE ;
fi
+ if [[ "$BOARD" =~ "WCH:ch32v:" ]]; then
+ arduino --pref "boardsmanager.additional.urls=https://github.com/openwch/board_manager_files/raw/main/package_ch32v_index.json" --save-prefs ;
+ arduino --install-boards WCH:ch32v:1.0.4 ;
+ arduino --board $BOARD --save-prefs ;
+ cd $GITHUB_WORKSPACE ;
+ fi
- name: Run script
run: |
@@ -504,3 +511,6 @@ jobs:
if [[ "$BOARD" =~ "SiliconLabs:silabs:" ]]; then
arduino-cli compile -v -b "$BOARD" $PWD/software/firmware/source/SoftRF ;
fi ;
+ #if [[ "$BOARD" =~ "WCH:ch32v:" ]]; then
+ # arduino --verify --verbose-build --board $BOARD $PWD/software/firmware/source/SoftRF/SoftRF.ino ;
+ #fi ;
diff --git a/software/firmware/source/SoftRF/Makefile b/software/firmware/source/SoftRF/Makefile
index 7cdf9ddd7..c4e0ac573 100644
--- a/software/firmware/source/SoftRF/Makefile
+++ b/software/firmware/source/SoftRF/Makefile
@@ -141,7 +141,8 @@ PLAT_CPPS := $(PLATFORM_PATH)/ESP8266.cpp \
$(PLATFORM_PATH)/ASR66.cpp \
$(PLATFORM_PATH)/RP2040.cpp \
$(PLATFORM_PATH)/RA4M1.cpp \
- $(PLATFORM_PATH)/EFR32.cpp
+ $(PLATFORM_PATH)/EFR32.cpp \
+ $(PLATFORM_PATH)/CH32.cpp
DRV_CPPS := $(DRIVER_PATH)/RF.cpp \
$(DRIVER_PATH)/radio/nordic.cpp \
diff --git a/software/firmware/source/SoftRF/src/platform/CH32.cpp b/software/firmware/source/SoftRF/src/platform/CH32.cpp
new file mode 100644
index 000000000..089060984
--- /dev/null
+++ b/software/firmware/source/SoftRF/src/platform/CH32.cpp
@@ -0,0 +1,592 @@
+/*
+ * Platform_CH32.cpp
+ * Copyright (C) 2024 Linar Yusupov
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+
+#if defined(ARDUINO_ARCH_CH32)
+
+#include
+#include
+
+#include "../system/SoC.h"
+#include "../driver/RF.h"
+#include "../driver/EEPROM.h"
+#include "../driver/LED.h"
+#include "../driver/OLED.h"
+#include "../driver/Baro.h"
+#include "../driver/Sound.h"
+#include "../driver/Battery.h"
+#include "../protocol/data/NMEA.h"
+#include "../protocol/data/GDL90.h"
+#include "../protocol/data/D1090.h"
+
+// SX127x pin mapping
+lmic_pinmap lmic_pins = {
+ .nss = SOC_GPIO_PIN_SS,
+ .txe = LMIC_UNUSED_PIN,
+ .rxe = LMIC_UNUSED_PIN,
+ .rst = SOC_GPIO_PIN_RST,
+ .dio = {LMIC_UNUSED_PIN, LMIC_UNUSED_PIN, LMIC_UNUSED_PIN},
+ .busy = LMIC_UNUSED_PIN,
+ .tcxo = LMIC_UNUSED_PIN,
+};
+
+#if !defined(EXCLUDE_LED_RING)
+// Parameter 1 = number of pixels in strip
+// Parameter 2 = Arduino pin number (most are valid)
+// Parameter 3 = pixel type flags, add together as needed:
+// NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs)
+// NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers)
+// NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products)
+// NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2)
+Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIX_NUM, SOC_GPIO_PIN_LED,
+ NEO_GRB + NEO_KHZ800);
+#endif /* EXCLUDE_LED_RING */
+
+#if defined(EXCLUDE_WIFI)
+char UDPpacketBuffer[4]; // Dummy definition to satisfy build sequence
+#endif /* EXCLUDE_WIFI */
+
+static struct rst_info reset_info = {
+ .reason = REASON_DEFAULT_RST,
+};
+
+static uint32_t bootCount __attribute__ ((section (".noinit")));
+static bool wdt_is_active = false;
+
+#if defined(EXCLUDE_EEPROM)
+eeprom_t eeprom_block;
+settings_t *settings = &eeprom_block.field.settings;
+#endif /* EXCLUDE_EEPROM */
+
+static void CH32_setup()
+{
+#if SOC_GPIO_RADIO_LED_TX != SOC_UNUSED_PIN
+ pinMode(SOC_GPIO_RADIO_LED_TX, OUTPUT);
+ digitalWrite(SOC_GPIO_RADIO_LED_TX, ! LED_STATE_ON);
+#endif /* SOC_GPIO_RADIO_LED_TX */
+#if SOC_GPIO_RADIO_LED_RX != SOC_UNUSED_PIN
+ pinMode(SOC_GPIO_RADIO_LED_RX, OUTPUT);
+ digitalWrite(SOC_GPIO_RADIO_LED_RX, ! LED_STATE_ON);
+#endif /* SOC_GPIO_RADIO_LED_RX */
+
+ Serial.begin(SERIAL_OUT_BR, SERIAL_OUT_BITS);
+}
+
+static void CH32_post_init()
+{
+ {
+ Serial.println();
+ Serial.println(F("SoftRF Academy Edition Power-on Self Test"));
+ Serial.println();
+ Serial.flush();
+
+ Serial.println(F("Built-in components:"));
+
+ Serial.print(F("RADIO : "));
+ Serial.println(hw_info.rf == RF_IC_SX1276 ? F("PASS") : F("FAIL"));
+ Serial.print(F("GNSS : "));
+ Serial.println(hw_info.gnss != GNSS_MODULE_NONE ? F("PASS") : F("FAIL"));
+
+ Serial.println();
+ Serial.println(F("External components:"));
+ Serial.print(F("BARO : "));
+ Serial.println(hw_info.baro != BARO_MODULE_NONE ? F("PASS") : F("N/A"));
+ Serial.print(F("DISPLAY : "));
+ Serial.println(hw_info.display != DISPLAY_NONE ? F("PASS") : F("N/A"));
+
+ Serial.println();
+ Serial.println(F("Power-on Self Test is complete."));
+ Serial.println();
+ Serial.flush();
+ }
+
+ Serial.println(F("Data output device(s):"));
+
+ Serial.print(F("NMEA - "));
+ switch (settings->nmea_out)
+ {
+ case NMEA_UART : Serial.println(F("UART")); break;
+ case NMEA_USB : Serial.println(F("USB CDC")); break;
+ case NMEA_OFF :
+ default : Serial.println(F("NULL")); break;
+ }
+
+ Serial.print(F("GDL90 - "));
+ switch (settings->gdl90)
+ {
+ case GDL90_UART : Serial.println(F("UART")); break;
+ case GDL90_USB : Serial.println(F("USB CDC")); break;
+ case GDL90_OFF :
+ default : Serial.println(F("NULL")); break;
+ }
+
+ Serial.print(F("D1090 - "));
+ switch (settings->d1090)
+ {
+ case D1090_UART : Serial.println(F("UART")); break;
+ case D1090_USB : Serial.println(F("USB CDC")); break;
+ case D1090_OFF :
+ default : Serial.println(F("NULL")); break;
+ }
+
+ Serial.println();
+ Serial.flush();
+
+#if defined(USE_OLED)
+ OLED_info1();
+#endif /* USE_OLED */
+}
+
+static uint32_t prev_tx_packets_counter = 0;
+static uint32_t prev_rx_packets_counter = 0;
+static unsigned long tx_led_time_marker = 0;
+static unsigned long rx_led_time_marker = 0;
+
+#define LED_BLINK_TIME 100
+
+static void CH32_loop()
+{
+#if SOC_GPIO_RADIO_LED_TX != SOC_UNUSED_PIN
+ if (digitalRead(SOC_GPIO_RADIO_LED_TX) != LED_STATE_ON) {
+ if (tx_packets_counter != prev_tx_packets_counter) {
+ digitalWrite(SOC_GPIO_RADIO_LED_TX, LED_STATE_ON);
+ prev_tx_packets_counter = tx_packets_counter;
+ tx_led_time_marker = millis();
+ }
+ } else {
+ if (millis() - tx_led_time_marker > LED_BLINK_TIME) {
+ digitalWrite(SOC_GPIO_RADIO_LED_TX, ! LED_STATE_ON);
+ prev_tx_packets_counter = tx_packets_counter;
+ }
+ }
+#endif /* SOC_GPIO_RADIO_LED_TX */
+
+#if SOC_GPIO_RADIO_LED_RX != SOC_UNUSED_PIN
+ if (digitalRead(SOC_GPIO_RADIO_LED_RX) != LED_STATE_ON) {
+ if (rx_packets_counter != prev_rx_packets_counter) {
+ digitalWrite(SOC_GPIO_RADIO_LED_RX, LED_STATE_ON);
+ prev_rx_packets_counter = rx_packets_counter;
+ rx_led_time_marker = millis();
+ }
+ } else {
+ if (millis() - rx_led_time_marker > LED_BLINK_TIME) {
+ digitalWrite(SOC_GPIO_RADIO_LED_RX, ! LED_STATE_ON);
+ prev_rx_packets_counter = rx_packets_counter;
+ }
+ }
+#endif /* SOC_GPIO_RADIO_LED_RX */
+}
+
+static void CH32_fini(int reason)
+{
+ NVIC_SystemReset(); /* TODO */
+}
+
+static void CH32_reset()
+{
+ NVIC_SystemReset();
+}
+
+static uint32_t CH32_getChipId()
+{
+#if !defined(SOFTRF_ADDRESS)
+ uint32_t id = DBGMCU_GetCHIPID(); /* TBD */
+
+ return DevID_Mapper(id);
+#else
+ return (SOFTRF_ADDRESS & 0xFFFFFFFFU );
+#endif
+}
+
+static void* CH32_getResetInfoPtr()
+{
+ return (void *) &reset_info;
+}
+
+static String CH32_getResetInfo()
+{
+ switch (reset_info.reason)
+ {
+ default : return F("No reset information available");
+ }
+}
+
+static String CH32_getResetReason()
+{
+ switch (reset_info.reason)
+ {
+ case REASON_DEFAULT_RST : return F("DEFAULT");
+ case REASON_WDT_RST : return F("WDT");
+ case REASON_EXCEPTION_RST : return F("EXCEPTION");
+ case REASON_SOFT_WDT_RST : return F("SOFT_WDT");
+ case REASON_SOFT_RESTART : return F("SOFT_RESTART");
+ case REASON_DEEP_SLEEP_AWAKE : return F("DEEP_SLEEP_AWAKE");
+ case REASON_EXT_SYS_RST : return F("EXT_SYS");
+ default : return F("NO_MEAN");
+ }
+}
+
+extern "C" void * _sbrk (int);
+
+static uint32_t CH32_getFreeHeap()
+{
+ char top;
+ return &top - reinterpret_cast(_sbrk(0));
+}
+
+static long CH32_random(long howsmall, long howBig)
+{
+ if(howsmall >= howBig) {
+ return howsmall;
+ }
+ long diff = howBig - howsmall;
+
+ return random(diff) + howsmall;
+}
+
+static void CH32_Sound_test(int var)
+{
+ if (SOC_GPIO_PIN_BUZZER != SOC_UNUSED_PIN && settings->volume != BUZZER_OFF) {
+ tone(SOC_GPIO_PIN_BUZZER, 440, 500); delay(500);
+ tone(SOC_GPIO_PIN_BUZZER, 640, 500); delay(500);
+ tone(SOC_GPIO_PIN_BUZZER, 840, 500); delay(500);
+ tone(SOC_GPIO_PIN_BUZZER, 1040, 500); delay(600);
+ }
+}
+
+static void CH32_Sound_tone(int hz, uint8_t volume)
+{
+ if (SOC_GPIO_PIN_BUZZER != SOC_UNUSED_PIN && volume != BUZZER_OFF) {
+ if (hz > 0) {
+ tone(SOC_GPIO_PIN_BUZZER, hz, ALARM_TONE_MS);
+ } else {
+ noTone(SOC_GPIO_PIN_BUZZER);
+ }
+ }
+}
+
+static void CH32_WiFi_set_param(int ndx, int value)
+{
+ /* NONE */
+}
+
+static void CH32_WiFi_transmit_UDP(int port, byte *buf, size_t size)
+{
+ /* NONE */
+}
+
+static bool CH32_EEPROM_begin(size_t size)
+{
+ return true;
+}
+
+static void CH32_EEPROM_extension(int cmd)
+{
+ if (cmd == EEPROM_EXT_LOAD) {
+ if (settings->mode != SOFTRF_MODE_NORMAL
+#if !defined(EXCLUDE_TEST_MODE)
+ &&
+ settings->mode != SOFTRF_MODE_TXRX_TEST
+#endif /* EXCLUDE_TEST_MODE */
+ ) {
+ settings->mode = SOFTRF_MODE_NORMAL;
+ }
+
+ if (settings->nmea_out == NMEA_BLUETOOTH ||
+ settings->nmea_out == NMEA_UDP ||
+ settings->nmea_out == NMEA_TCP ) {
+ settings->nmea_out = NMEA_UART;
+ }
+ if (settings->gdl90 == GDL90_BLUETOOTH ||
+ settings->gdl90 == GDL90_UDP) {
+ settings->gdl90 = GDL90_UART;
+ }
+ if (settings->d1090 == D1090_BLUETOOTH ||
+ settings->d1090 == D1090_UDP) {
+ settings->d1090 = D1090_UART;
+ }
+
+ /* AUTO and UK RF bands are deprecated since Release v1.3 */
+ if (settings->band == RF_BAND_AUTO || settings->band == RF_BAND_UK) {
+ settings->band = RF_BAND_EU;
+ }
+ }
+}
+
+static void CH32_SPI_begin()
+{
+ SPI.begin();
+}
+
+static void CH32_swSer_begin(unsigned long baud)
+{
+ Serial_GNSS_In.begin(baud);
+}
+
+static void CH32_swSer_enableRx(boolean arg)
+{
+ /* NONE */
+}
+
+static byte CH32_Display_setup()
+{
+ byte rval = DISPLAY_NONE;
+
+#if defined(USE_OLED)
+ rval = OLED_setup();
+#endif /* USE_OLED */
+
+ return rval;
+}
+
+static void CH32_Display_loop()
+{
+#if defined(USE_OLED)
+ OLED_loop();
+#endif /* USE_OLED */
+}
+
+static void CH32_Display_fini(int reason)
+{
+#if defined(USE_OLED)
+ OLED_fini(reason);
+#endif /* USE_OLED */
+}
+
+static void CH32_Battery_setup()
+{
+
+}
+
+static float CH32_Battery_param(uint8_t param)
+{
+ float rval, voltage;
+
+ switch (param)
+ {
+ case BATTERY_PARAM_THRESHOLD:
+ rval = hw_info.model == SOFTRF_MODEL_ACADEMY ? BATTERY_THRESHOLD_LIPO :
+ BATTERY_THRESHOLD_NIMHX2;
+ break;
+
+ case BATTERY_PARAM_CUTOFF:
+ rval = hw_info.model == SOFTRF_MODEL_ACADEMY ? BATTERY_CUTOFF_LIPO :
+ BATTERY_CUTOFF_NIMHX2;
+ break;
+
+ case BATTERY_PARAM_CHARGE:
+ voltage = Battery_voltage();
+ if (voltage < Battery_cutoff())
+ return 0;
+
+ if (voltage > 4.2)
+ return 100;
+
+ if (voltage < 3.6) {
+ voltage -= 3.3;
+ return (voltage * 100) / 3;
+ }
+
+ voltage -= 3.6;
+ rval = 10 + (voltage * 150 );
+ break;
+
+ case BATTERY_PARAM_VOLTAGE:
+ default:
+
+ {
+ uint16_t mV = 0;
+#if SOC_GPIO_PIN_BATTERY != SOC_UNUSED_PIN
+ mV = analogRead(SOC_GPIO_PIN_BATTERY);
+#endif
+ rval = mV * SOC_ADC_VOLTAGE_DIV / 1000.0;
+ }
+ break;
+ }
+
+ return rval;
+}
+
+void CH32_GNSS_PPS_Interrupt_handler() {
+ PPS_TimeMarker = millis();
+}
+
+static unsigned long CH32_get_PPS_TimeMarker() {
+ return PPS_TimeMarker;
+}
+
+static bool CH32_Baro_setup() {
+ return true;
+}
+
+static void CH32_UATSerial_begin(unsigned long baud)
+{
+
+}
+
+static void CH32_UATModule_restart()
+{
+
+}
+
+static void CH32_WDT_setup()
+{
+ /* TBD */
+}
+
+static void CH32_WDT_fini()
+{
+ /* TBD */
+}
+
+#if SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN
+#include
+using namespace ace_button;
+
+AceButton button_1(SOC_GPIO_PIN_BUTTON);
+
+// The event handler for the button.
+void handleEvent(AceButton* button, uint8_t eventType,
+ uint8_t buttonState) {
+
+ switch (eventType) {
+ case AceButton::kEventClicked:
+ case AceButton::kEventReleased:
+#if defined(USE_OLED)
+ if (button == &button_1) {
+ OLED_Next_Page();
+ }
+#endif
+ break;
+ case AceButton::kEventDoubleClicked:
+ break;
+ case AceButton::kEventLongPressed:
+ if (button == &button_1) {
+ shutdown(SOFTRF_SHUTDOWN_BUTTON);
+// Serial.println(F("This will never be printed."));
+ }
+ break;
+ }
+}
+
+/* Callbacks for push button interrupt */
+void onPageButtonEvent() {
+ button_1.check();
+}
+#endif /* SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN */
+
+static void CH32_Button_setup()
+{
+#if SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN
+ if (hw_info.model == SOFTRF_MODEL_ACADEMY) {
+ int button_pin = SOC_GPIO_PIN_BUTTON;
+
+ // Button(s) uses external pull up resistor.
+ pinMode(button_pin, INPUT);
+
+ button_1.init(button_pin);
+
+ // Configure the ButtonConfig with the event handler, and enable all higher
+ // level events.
+ ButtonConfig* PageButtonConfig = button_1.getButtonConfig();
+ PageButtonConfig->setEventHandler(handleEvent);
+ PageButtonConfig->setFeature(ButtonConfig::kFeatureClick);
+// PageButtonConfig->setFeature(ButtonConfig::kFeatureDoubleClick);
+ PageButtonConfig->setFeature(ButtonConfig::kFeatureLongPress);
+ PageButtonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterClick);
+// PageButtonConfig->setFeature(ButtonConfig::kFeatureSuppressAfterDoubleClick);
+// PageButtonConfig->setFeature(
+// ButtonConfig::kFeatureSuppressClickBeforeDoubleClick);
+// PageButtonConfig->setDebounceDelay(15);
+ PageButtonConfig->setClickDelay(600);
+// PageButtonConfig->setDoubleClickDelay(1500);
+ PageButtonConfig->setLongPressDelay(2000);
+
+// attachInterrupt(digitalPinToInterrupt(button_pin), onPageButtonEvent, CHANGE );
+ }
+#endif /* SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN */
+}
+
+static void CH32_Button_loop()
+{
+#if SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN
+ if (hw_info.model == SOFTRF_MODEL_ACADEMY) {
+ button_1.check();
+ }
+#endif /* SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN */
+}
+
+static void CH32_Button_fini()
+{
+#if SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN
+ if (hw_info.model == SOFTRF_MODEL_ACADEMY) {
+// detachInterrupt(digitalPinToInterrupt(SOC_GPIO_PIN_BUTTON));
+ while (digitalRead(SOC_GPIO_PIN_BUTTON) == LOW);
+ pinMode(SOC_GPIO_PIN_BUTTON, ANALOG);
+ }
+#endif /* SOC_GPIO_PIN_BUTTON != SOC_UNUSED_PIN */
+}
+
+const SoC_ops_t CH32_ops = {
+ SOC_CH32,
+ "CH32",
+ CH32_setup,
+ CH32_post_init,
+ CH32_loop,
+ CH32_fini,
+ CH32_reset,
+ CH32_getChipId,
+ CH32_getResetInfoPtr,
+ CH32_getResetInfo,
+ CH32_getResetReason,
+ CH32_getFreeHeap,
+ CH32_random,
+ CH32_Sound_test,
+ CH32_Sound_tone,
+ NULL,
+ CH32_WiFi_set_param,
+ CH32_WiFi_transmit_UDP,
+ NULL,
+ NULL,
+ NULL,
+ CH32_EEPROM_begin,
+ CH32_EEPROM_extension,
+ CH32_SPI_begin,
+ CH32_swSer_begin,
+ CH32_swSer_enableRx,
+ NULL, /* TODO */
+ NULL,
+ NULL,
+ CH32_Display_setup,
+ CH32_Display_loop,
+ CH32_Display_fini,
+ CH32_Battery_setup,
+ CH32_Battery_param,
+ CH32_GNSS_PPS_Interrupt_handler,
+ CH32_get_PPS_TimeMarker,
+ CH32_Baro_setup,
+ CH32_UATSerial_begin,
+ CH32_UATModule_restart,
+ CH32_WDT_setup,
+ CH32_WDT_fini,
+ CH32_Button_setup,
+ CH32_Button_loop,
+ CH32_Button_fini,
+ NULL
+};
+
+#endif /* ARDUINO_ARCH_CH32 */
diff --git a/software/firmware/source/SoftRF/src/platform/CH32.h b/software/firmware/source/SoftRF/src/platform/CH32.h
new file mode 100644
index 000000000..cc3144141
--- /dev/null
+++ b/software/firmware/source/SoftRF/src/platform/CH32.h
@@ -0,0 +1,175 @@
+/*
+ * Platform_CH32.h
+ * Copyright (C) 2024 Linar Yusupov
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ */
+#if defined(ARDUINO_ARCH_CH32)
+
+#ifndef PLATFORM_CH32_H
+#define PLATFORM_CH32_H
+
+#include
+
+/* Maximum of tracked flying objects is now SoC-specific constant */
+#define MAX_TRACKING_OBJECTS 8
+
+#define DEFAULT_SOFTRF_MODEL SOFTRF_MODEL_ACADEMY
+
+#define isValidFix() isValidGNSSFix()
+
+#define uni_begin() strip.begin()
+#define uni_show() strip.show()
+#define uni_setPixelColor(i, c) strip.setPixelColor(i, c)
+#define uni_numPixels() strip.numPixels()
+#define uni_Color(r,g,b) strip.Color(r,g,b)
+#define color_t uint32_t
+
+#define EEPROM_commit() {}
+
+#define LED_STATE_ON LOW // State when LED is litted
+
+#define SerialOutput Serial /* TBD */
+
+#define USBSerial Serial /* TBD */
+#define Serial_GNSS_In Serial /* TBD */
+#define Serial_GNSS_Out Serial_GNSS_In
+#define UATSerial Serial /* TBD */
+
+#define SOC_ADC_VOLTAGE_DIV 2 /* TBD */
+
+#ifndef strnlen
+#define strnlen(x,y) strlen(x) /* TBD */
+#endif
+
+enum rst_reason {
+ REASON_DEFAULT_RST = 0, /* normal startup by power on */
+ REASON_WDT_RST = 1, /* hardware watch dog reset */
+ REASON_EXCEPTION_RST = 2, /* exception reset, GPIO status won't change */
+ REASON_SOFT_WDT_RST = 3, /* software watch dog reset, GPIO status won't change */
+ REASON_SOFT_RESTART = 4, /* software restart ,system_restart , GPIO status won't change */
+ REASON_DEEP_SLEEP_AWAKE = 5, /* wake up from deep-sleep */
+ REASON_EXT_SYS_RST = 6 /* external system reset */
+};
+
+struct rst_info {
+ uint32_t reason;
+ uint32_t exccause;
+ uint32_t epc1;
+ uint32_t epc2;
+ uint32_t epc3;
+ uint32_t excvaddr;
+ uint32_t depc;
+};
+
+#if defined(CH32V30x)
+
+/* Peripherals */
+#define SOC_GPIO_PIN_CONS_RX PIN_SERIAL_RX // TBD
+#define SOC_GPIO_PIN_CONS_TX PIN_SERIAL_TX // TBD
+
+#define SOC_GPIO_PIN_GNSS_RX PIN_SERIAL1_RX // TBD
+#define SOC_GPIO_PIN_GNSS_TX PIN_SERIAL1_TX // TBD
+
+#define SOC_GPIO_PIN_STATUS LED_BUILTIN // TBD
+#define SOC_GPIO_PIN_BUZZER SOC_UNUSED_PIN
+
+#define SOC_GPIO_PIN_RX3 SOC_UNUSED_PIN
+#define SOC_GPIO_PIN_TX3 SOC_UNUSED_PIN
+
+/* SPI */
+#define SOC_GPIO_PIN_MOSI PIN_SPI_MOSI // TBD
+#define SOC_GPIO_PIN_MISO PIN_SPI_MISO // TBD
+#define SOC_GPIO_PIN_SCK PIN_SPI_SCK // TBD
+#define SOC_GPIO_PIN_SS SOC_UNUSED_PIN // TBD
+
+/* NRF905 */
+#define SOC_GPIO_PIN_TXE SOC_UNUSED_PIN
+#define SOC_GPIO_PIN_CE SOC_UNUSED_PIN
+#define SOC_GPIO_PIN_PWR SOC_UNUSED_PIN
+
+/* SX1276 */
+#define SOC_GPIO_PIN_RST SOC_UNUSED_PIN // TBD
+#define SOC_GPIO_PIN_BUSY SOC_UNUSED_PIN
+#define SOC_GPIO_PIN_DIO1 SOC_UNUSED_PIN // TBD
+
+/* RF antenna switch */
+#define SOC_GPIO_PIN_ANT_RXTX SOC_UNUSED_PIN
+
+/* I2C */
+#define SOC_GPIO_PIN_SDA PIN_WIRE_SDA // TBD
+#define SOC_GPIO_PIN_SCL PIN_WIRE_SCL // TBD
+
+#define SOC_GPIO_PIN_LED SOC_UNUSED_PIN
+#define SOC_GPIO_PIN_GNSS_PPS SOC_UNUSED_PIN /* TBD */
+#define SOC_GPIO_PIN_BATTERY SOC_UNUSED_PIN /* TBD */
+#define SOC_GPIO_PIN_BUTTON SOC_UNUSED_PIN
+
+#define SOC_GPIO_RADIO_LED_RX SOC_UNUSED_PIN
+#define SOC_GPIO_RADIO_LED_TX SOC_UNUSED_PIN
+
+#else
+#error "This CH32 build variant is not supported!"
+#endif
+
+//#define EXCLUDE_EEPROM
+#define EXCLUDE_WIFI
+#define EXCLUDE_CC13XX
+#define EXCLUDE_TEST_MODE
+#define EXCLUDE_WATCHOUT_MODE
+//#define EXCLUDE_TRAFFIC_FILTER_EXTENSION
+//#define EXCLUDE_LK8EX1
+
+#define EXCLUDE_GNSS_UBLOX
+#define EXCLUDE_GNSS_SONY
+//#define EXCLUDE_GNSS_MTK
+#define EXCLUDE_GNSS_GOKE
+#define EXCLUDE_GNSS_AT65
+#define EXCLUDE_GNSS_UC65
+//#define EXCLUDE_LOG_GNSS_VERSION
+
+/* Component Cost */
+/* -------------------------------------- */
+#define USE_NMEA_CFG // + kb
+#define EXCLUDE_BMP180 // - kb
+//#define EXCLUDE_BMP280 // - kb
+#define EXCLUDE_BME680 // - kb
+#define EXCLUDE_MPL3115A2 // - kb
+#define EXCLUDE_NRF905 // - kb
+#define EXCLUDE_UATM // - kb
+#define EXCLUDE_MAVLINK // - kb
+//#define EXCLUDE_EGM96 // - kb
+#define EXCLUDE_LED_RING // - kb
+#define EXCLUDE_SOUND
+
+#define USE_OLED // kb
+#define EXCLUDE_OLED_049
+//#define EXCLUDE_OLED_BARO_PAGE
+
+#define USE_TIME_SLOTS
+#define USE_OGN_ENCRYPTION
+
+#if !defined(EXCLUDE_LED_RING)
+#include
+
+extern Adafruit_NeoPixel strip;
+#endif /* EXCLUDE_LED_RING */
+
+#if defined(USE_OLED)
+#define U8X8_OLED_I2C_BUS_TYPE U8X8_SSD1306_128X64_NONAME_HW_I2C
+#endif /* USE_OLED */
+
+#endif /* PLATFORM_CH32_H */
+
+#endif /* ARDUINO_ARCH_CH32 */
diff --git a/software/firmware/source/SoftRF/src/system/SoC.cpp b/software/firmware/source/SoftRF/src/system/SoC.cpp
index 0908dfab7..44fa140fc 100644
--- a/software/firmware/source/SoftRF/src/system/SoC.cpp
+++ b/software/firmware/source/SoftRF/src/system/SoC.cpp
@@ -50,6 +50,8 @@ byte SoC_setup()
SoC = &RA4M1_ops;
#elif defined(ARDUINO_ARCH_SILABS)
SoC = &EFR32_ops;
+#elif defined(ARDUINO_ARCH_CH32)
+ SoC = &CH32_ops;
#else
#error "This hardware platform is not supported!"
#endif
diff --git a/software/firmware/source/SoftRF/src/system/SoC.h b/software/firmware/source/SoftRF/src/system/SoC.h
index ebf1a9f03..15c940b5e 100644
--- a/software/firmware/source/SoftRF/src/system/SoC.h
+++ b/software/firmware/source/SoftRF/src/system/SoC.h
@@ -36,6 +36,7 @@
#include "../platform/RP2040.h"
#include "../platform/RA4M1.h"
#include "../platform/EFR32.h"
+#include "../platform/CH32.h"
typedef struct SoC_ops_struct {
uint8_t id;
@@ -112,7 +113,8 @@ enum
SOC_ASR66,
SOC_RP2040,
SOC_RA4M1,
- SOC_EFR32
+ SOC_EFR32,
+ SOC_CH32
};
extern const SoC_ops_t *SoC;
@@ -158,6 +160,9 @@ extern const SoC_ops_t RA4M1_ops;
#if defined(ARDUINO_ARCH_SILABS)
extern const SoC_ops_t EFR32_ops;
#endif
+#if defined(ARDUINO_ARCH_CH32)
+extern const SoC_ops_t CH32_ops;
+#endif
byte SoC_setup(void);
void SoC_fini(int);
diff --git a/software/firmware/source/libraries/Adafruit_BMP280_Library/Adafruit_BMP280.h b/software/firmware/source/libraries/Adafruit_BMP280_Library/Adafruit_BMP280.h
index be9e06873..40f1ed9e3 100644
--- a/software/firmware/source/libraries/Adafruit_BMP280_Library/Adafruit_BMP280.h
+++ b/software/firmware/source/libraries/Adafruit_BMP280_Library/Adafruit_BMP280.h
@@ -29,7 +29,8 @@
defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || \
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \
defined(ARDUINO_ARCH_RP2040) || defined(HACKRF_ONE) || \
- defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_SILABS))
+ defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_SILABS) || \
+ defined(ARDUINO_ARCH_CH32))
#include
#endif
diff --git a/software/firmware/source/libraries/nRF905/nRF905.cpp b/software/firmware/source/libraries/nRF905/nRF905.cpp
index f7c9529a2..ae788fff9 100644
--- a/software/firmware/source/libraries/nRF905/nRF905.cpp
+++ b/software/firmware/source/libraries/nRF905/nRF905.cpp
@@ -14,7 +14,7 @@
!defined(HACKRF_ONE) && !defined(ARDUINO_ARCH_SAMD) && \
!defined(ARDUINO_ARCH_ASR650X) && !defined(ARDUINO_ARCH_ASR6601) && \
!defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_ARCH_RENESAS) && \
- !defined(ARDUINO_ARCH_SILABS)
+ !defined(ARDUINO_ARCH_SILABS) && !defined(ARDUINO_ARCH_CH32)
#include
#include
@@ -30,6 +30,7 @@
defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_NRF52840) || \
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_RP2040) || \
defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_SILABS) || \
+ defined(ARDUINO_ARCH_CH32) || \
(defined(ARDUINO_ARCH_STM32) && defined(ARDUINO_WisDuo_RAK3172_Evaluation_Board))
#define _BV(bit) (1 << (bit))
#endif /* ENERGIA_ARCH_CC13XX || ENERGIA_ARCH_CC13X2 || ARDUINO_ARCH_NRF52 */
diff --git a/software/firmware/source/libraries/nRF905/nRF905_config.h b/software/firmware/source/libraries/nRF905/nRF905_config.h
index 5138ae180..77aeae032 100644
--- a/software/firmware/source/libraries/nRF905/nRF905_config.h
+++ b/software/firmware/source/libraries/nRF905/nRF905_config.h
@@ -28,7 +28,8 @@
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \
defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \
defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) || \
- defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_NRF52840)
+ defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_CH32) || \
+ defined(ARDUINO_ARCH_NRF52840)
#define NRF905_INTERRUPTS 0
#else
#define NRF905_INTERRUPTS 1
@@ -56,7 +57,8 @@
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \
defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \
defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) || \
- defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_NRF52840)
+ defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_CH32) || \
+ defined(ARDUINO_ARCH_NRF52840)
#define NRF905_AM_SW 1
#else
#define NRF905_AM_SW 0
@@ -74,7 +76,8 @@
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \
defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \
defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) || \
- defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_NRF52840)
+ defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_CH32) || \
+ defined(ARDUINO_ARCH_NRF52840)
#define NRF905_COLLISION_AVOID 0
#else
#define NRF905_COLLISION_AVOID 1
@@ -200,7 +203,8 @@
#define CD 0 // Carrier detect pin (for collision avoidance, if enabled)
#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_RP2040) || \
- defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_SILABS)
+ defined(ARDUINO_ARCH_RENESAS) || defined(ARDUINO_ARCH_SILABS) || \
+ defined(ARDUINO_ARCH_CH32)
// TBD
#define TRX_EN 0 // Enable/standby pin
@@ -342,7 +346,8 @@
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \
defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \
defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) || \
- defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_NRF52840)
+ defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_CH32) || \
+ defined(ARDUINO_ARCH_NRF52840)
#define NRF905_FREQ 868400000UL
#else
#define NRF905_FREQ 433200000UL
@@ -358,7 +363,8 @@
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \
defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \
defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) || \
- defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_NRF52840)
+ defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_CH32) || \
+ defined(ARDUINO_ARCH_NRF52840)
#define NRF905_BAND NRF905_BAND_868
#else
#define NRF905_BAND NRF905_BAND_433
@@ -408,7 +414,8 @@
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \
defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \
defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) || \
- defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_NRF52840)
+ defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_CH32) || \
+ defined(ARDUINO_ARCH_NRF52840)
#define NRF905_ADDR_SIZE NRF905_ADDR_SIZE_3
//#define NRF905_ADDR_SIZE NRF905_ADDR_SIZE_2
#else
@@ -422,7 +429,8 @@
defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \
defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \
defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) || \
- defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_NRF52840)
+ defined(ARDUINO_ARCH_SILABS) || defined(ARDUINO_ARCH_CH32) || \
+ defined(ARDUINO_ARCH_NRF52840)
#define NRF905_PAYLOAD_SIZE 24
#else
#define NRF905_PAYLOAD_SIZE 32 //NRF905_MAX_PAYLOAD