diff --git a/software/firmware/source/SoftRF/Makefile b/software/firmware/source/SoftRF/Makefile index c7284a5e9..9d63b0d0a 100644 --- a/software/firmware/source/SoftRF/Makefile +++ b/software/firmware/source/SoftRF/Makefile @@ -138,7 +138,8 @@ PLAT_CPPS := $(PLATFORM_PATH)/ESP8266.cpp \ $(PLATFORM_PATH)/SAMD.cpp \ $(PLATFORM_PATH)/AVR.cpp \ $(PLATFORM_PATH)/ASR66.cpp \ - $(PLATFORM_PATH)/RP2040.cpp + $(PLATFORM_PATH)/RP2040.cpp \ + $(PLATFORM_PATH)/RA4M1.cpp DRV_CPPS := $(DRIVER_PATH)/RF.cpp \ $(DRIVER_PATH)/GNSS.cpp \ diff --git a/software/firmware/source/SoftRF/src/platform/RA4M1.cpp b/software/firmware/source/SoftRF/src/platform/RA4M1.cpp new file mode 100644 index 000000000..61f45c9fa --- /dev/null +++ b/software/firmware/source/SoftRF/src/platform/RA4M1.cpp @@ -0,0 +1,862 @@ +/* + * Platform_RA4M1.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_RENESAS) + +#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" + +#if !defined(ARDUINO_ARCH_RENESAS_UNO) +#error "ARDUINO UNO is the only one supported at this time" +#endif + +typedef volatile uint32_t REG32; +#define pREG32 (REG32 *) + +#define DEVICE_ID_HIGH (*(pREG32 (0x0080A044))) +#define DEVICE_ID_LOW (*(pREG32 (0x0080A048))) + +// 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, +}; + +//SPIClass SPI1(&PERIPH_SPI1, SOC_GPIO_PIN_MISO, SOC_GPIO_PIN_SCK, SOC_GPIO_PIN_MOSI, PAD_SPI1_TX, PAD_SPI1_RX); + +#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 */ + +char UDPpacketBuffer[4]; // Dummy definition to satisfy build sequence + +static struct rst_info reset_info = { + .reason = REASON_DEFAULT_RST, +}; + +static uint32_t bootCount __attribute__ ((section (".noinit"))); +static bool wdt_is_active = false; + +const char *RA4M1_Device_Manufacturer = SOFTRF_IDENT; +const char *RA4M1_Device_Model = "Academy Edition"; +const uint16_t RA4M1_Device_Version = SOFTRF_USB_FW_VERSION; + +#if defined(USE_USB_HOST) + +#include +#include + +class ACMAsyncOper : public CDCAsyncOper +{ +public: + uint8_t OnInit(ACM *pacm); +}; + +uint8_t ACMAsyncOper::OnInit(ACM *pacm) +{ + uint8_t rcode; + // Set DTR = 1 RTS=1 + rcode = pacm->SetControlLineState(3); + + if (rcode) + { + ErrorMessage(PSTR("SetControlLineState"), rcode); + return rcode; + } + + LINE_CODING lc; + lc.dwDTERate = 115200; + lc.bCharFormat = 0; + lc.bParityType = 0; + lc.bDataBits = 8; + + rcode = pacm->SetLineCoding(&lc); + + if (rcode) + ErrorMessage(PSTR("SetLineCoding"), rcode); + + return rcode; +} + +USBHost UsbH; +ACMAsyncOper AsyncOper; +ACM AcmSerial(&UsbH, &AsyncOper); + +#endif /* USE_USB_HOST */ + +static void RA4M1_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 */ + +#if defined(USE_TINYUSB) + USBDevice.setManufacturerDescriptor(RA4M1_Device_Manufacturer); + USBDevice.setProductDescriptor(RA4M1_Device_Model); + USBDevice.setDeviceVersion(RA4M1_Device_Version); +#endif /* USE_TINYUSB */ + +#if defined(USE_USB_HOST) + UsbH.Init(); +#endif /* USE_USB_HOST */ + + Serial.begin(SERIAL_OUT_BR, SERIAL_OUT_BITS); + +#if defined(USBCON) + for (int i=0; i < 20; i++) {if (Serial) break; else delay(100);} +#endif +} + +static void RA4M1_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; +extern uint32_t tx_packets_counter, rx_packets_counter; +static unsigned long tx_led_time_marker = 0; +static unsigned long rx_led_time_marker = 0; + +#define LED_BLINK_TIME 100 + +static void RA4M1_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 RA4M1_fini(int reason) +{ +#if defined(USE_TINYUSB) + // Disable USB + USBDevice.detach(); +#endif /* USE_TINYUSB */ + + NVIC_SystemReset(); +} + +static void RA4M1_reset() +{ + NVIC_SystemReset(); +} + +static uint32_t RA4M1_getChipId() +{ +#if !defined(SOFTRF_ADDRESS) + uint32_t id = DEVICE_ID_LOW; + + return DevID_Mapper(id); +#else + return (SOFTRF_ADDRESS & 0xFFFFFFFFU ); +#endif +} + +static void* RA4M1_getResetInfoPtr() +{ + return (void *) &reset_info; +} + +static String RA4M1_getResetInfo() +{ + switch (reset_info.reason) + { + default : return F("No reset information available"); + } +} + +static String RA4M1_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 RA4M1_getFreeHeap() +{ + char top; + return &top - reinterpret_cast(_sbrk(0)); +} + +static long RA4M1_random(long howsmall, long howBig) +{ + if(howsmall >= howBig) { + return howsmall; + } + long diff = howBig - howsmall; + + return random(diff) + howsmall; +} + +static void RA4M1_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 RA4M1_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 RA4M1_WiFi_set_param(int ndx, int value) +{ + /* NONE */ +} + +static void RA4M1_WiFi_transmit_UDP(int port, byte *buf, size_t size) +{ + /* NONE */ +} + +static bool RA4M1_EEPROM_begin(size_t size) +{ + return true; +} + +static void RA4M1_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_USB; + } + if (settings->gdl90 == GDL90_BLUETOOTH || + settings->gdl90 == GDL90_UDP) { + settings->gdl90 = GDL90_USB; + } + if (settings->d1090 == D1090_BLUETOOTH || + settings->d1090 == D1090_UDP) { + settings->d1090 = D1090_USB; + } + +#if defined(USE_USB_HOST) + if (settings->nmea_out != NMEA_OFF) { + settings->nmea_out = NMEA_UART; + } + if (settings->gdl90 != GDL90_OFF) { + settings->gdl90 = GDL90_UART; + } + if (settings->d1090 != D1090_OFF) { + settings->d1090 = D1090_UART; + } +#endif /* USE_USB_HOST */ + + /* 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 RA4M1_SPI_begin() +{ +#if USE_ISP_PORT + SPI.begin(); +#else +// SPI1.begin(); +#endif +} + +static void RA4M1_swSer_begin(unsigned long baud) +{ + Serial_GNSS_In.begin(baud); +} + +static void RA4M1_swSer_enableRx(boolean arg) +{ + /* NONE */ +} + +static byte RA4M1_Display_setup() +{ + byte rval = DISPLAY_NONE; + +#if defined(USE_OLED) + rval = OLED_setup(); +#endif /* USE_OLED */ + + return rval; +} + +static void RA4M1_Display_loop() +{ +#if defined(USE_OLED) + OLED_loop(); +#endif /* USE_OLED */ +} + +static void RA4M1_Display_fini(int reason) +{ +#if defined(USE_OLED) + OLED_fini(reason); +#endif /* USE_OLED */ +} + +static void RA4M1_Battery_setup() +{ + +} + +static float RA4M1_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 RA4M1_GNSS_PPS_Interrupt_handler() { + PPS_TimeMarker = millis(); +} + +static unsigned long RA4M1_get_PPS_TimeMarker() { + return PPS_TimeMarker; +} + +static bool RA4M1_Baro_setup() { + return true; +} + +static void RA4M1_UATSerial_begin(unsigned long baud) +{ + +} + +static void RA4M1_UATModule_restart() +{ + +} + +static void RA4M1_WDT_setup() +{ + /* TBD */ +} + +static void RA4M1_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 RA4M1_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 RA4M1_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 RA4M1_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 */ +} + +static void RA4M1_USB_setup() +{ + if (USBSerial && USBSerial != Serial) { + USBSerial.begin(SERIAL_OUT_BR, SERIAL_OUT_BITS); + } +} + +#include + +#if (CFG_TUSB_RHPORT1_MODE & OPT_MODE_DEVICE) +#define USBD_CDC_IN_OUT_MAX_SIZE (512) +#else +#define USBD_CDC_IN_OUT_MAX_SIZE (64) +#endif + +#define USB_TX_FIFO_SIZE (MAX_TRACKING_OBJECTS * 65 + 75 + 75 + 42 + 20) +#define USB_RX_FIFO_SIZE (256) + +RingBufferN USB_TX_FIFO = RingBufferN(); +RingBufferN USB_RX_FIFO = RingBufferN(); + +static void RA4M1_USB_loop() +{ +#if defined(USE_USB_HOST) + + UsbH.Task(); + + if (AcmSerial.isReady()) { + uint8_t rcode; + uint8_t data[USBD_CDC_IN_OUT_MAX_SIZE]; + size_t size; + + while ((size = USB_TX_FIFO.available()) != 0) { + + if (size > sizeof(data)) { + size = sizeof(data); + } + + for (size_t i=0; i < size; i++) { + data[i] = USB_TX_FIFO.read_char(); + } + + rcode = AcmSerial.SndData(size, data); + if (rcode) { + ErrorMessage(PSTR("SndData"), rcode); + } + } + + uint16_t rcvd = sizeof(data); + rcode = AcmSerial.RcvData(&rcvd, data); + if (rcode && rcode != USB_ERRORFLOW) { + ErrorMessage(PSTR("RcvData"), rcode); + } else { + if( rcvd ) { +#if 1 + SerialOutput.write(data, rcvd); +#else + size_t written; + + for (written=0; written < rcvd; written++) { + if (!USB_RX_FIFO.isFull()) { + USB_RX_FIFO.store_char(data[written]); + } else { + break; + } + } +#endif + } + } + } + +#elif !defined(USE_TINYUSB) + + uint8_t buf[USBD_CDC_IN_OUT_MAX_SIZE]; + size_t size; + + while (USBSerial && (size = USBSerial.availableForWrite()) > 0) { + size_t avail = USB_TX_FIFO.available(); + + if (avail == 0) { + break; + } + + if (size > avail) { + size = avail; + } + + if (size > sizeof(buf)) { + size = sizeof(buf); + } + + for (size_t i=0; i < size; i++) { + buf[i] = USB_TX_FIFO.read_char(); + } + + if (USBSerial) { + USBSerial.write(buf, size); + } + } + + while (USBSerial && USBSerial.available() > 0) { + if (!USB_RX_FIFO.isFull()) { + USB_RX_FIFO.store_char(USBSerial.read()); + } else { + break; + } + } + +#endif /* USE_TINYUSB */ +} + +static void RA4M1_USB_fini() +{ + if (USBSerial && USBSerial != Serial) { + USBSerial.end(); + } +} + +static int RA4M1_USB_available() +{ + int rval = 0; + +#if defined(USE_TINYUSB) + if (USBSerial) { + rval = USBSerial.available(); + } +#else + rval = USB_RX_FIFO.available(); +#endif /* USE_TINYUSB */ + + return rval; +} + +static int RA4M1_USB_read() +{ + int rval = -1; + +#if defined(USE_TINYUSB) + if (USBSerial) { + rval = USBSerial.read(); + } +#else + rval = USB_RX_FIFO.read_char(); +#endif /* USE_TINYUSB */ + + return rval; +} + +static size_t RA4M1_USB_write(const uint8_t *buffer, size_t size) +{ +#if !defined(USE_TINYUSB) + size_t written; + + for (written=0; written < size; written++) { + if (!USB_TX_FIFO.isFull()) { + USB_TX_FIFO.store_char(buffer[written]); + } else { + break; + } + } + return written; +#else + size_t rval = size; + + if (USBSerial && (size < USBSerial.availableForWrite())) { + rval = USBSerial.write(buffer, size); + } + + return rval; +#endif /* USE_TINYUSB */ +} + +IODev_ops_t RA4M1_USBSerial_ops = { + "RA4M1 USBSerial", + RA4M1_USB_setup, + RA4M1_USB_loop, + RA4M1_USB_fini, + RA4M1_USB_available, + RA4M1_USB_read, + RA4M1_USB_write +}; + +const SoC_ops_t RA4M1_ops = { + SOC_RA4M1, + "RA4M1", + RA4M1_setup, + RA4M1_post_init, + RA4M1_loop, + RA4M1_fini, + RA4M1_reset, + RA4M1_getChipId, + RA4M1_getResetInfoPtr, + RA4M1_getResetInfo, + RA4M1_getResetReason, + RA4M1_getFreeHeap, + RA4M1_random, + RA4M1_Sound_test, + RA4M1_Sound_tone, + NULL, + RA4M1_WiFi_set_param, + RA4M1_WiFi_transmit_UDP, + NULL, + NULL, + NULL, + RA4M1_EEPROM_begin, + RA4M1_EEPROM_extension, + RA4M1_SPI_begin, + RA4M1_swSer_begin, + RA4M1_swSer_enableRx, + NULL, /* RA4M1 has no built-in Bluetooth */ + &RA4M1_USBSerial_ops, + NULL, + RA4M1_Display_setup, + RA4M1_Display_loop, + RA4M1_Display_fini, + RA4M1_Battery_setup, + RA4M1_Battery_param, + RA4M1_GNSS_PPS_Interrupt_handler, + RA4M1_get_PPS_TimeMarker, + RA4M1_Baro_setup, + RA4M1_UATSerial_begin, + RA4M1_UATModule_restart, + RA4M1_WDT_setup, + RA4M1_WDT_fini, + RA4M1_Button_setup, + RA4M1_Button_loop, + RA4M1_Button_fini, + NULL +}; + +#endif /* ARDUINO_ARCH_RENESAS */ diff --git a/software/firmware/source/SoftRF/src/platform/RA4M1.h b/software/firmware/source/SoftRF/src/platform/RA4M1.h new file mode 100644 index 000000000..0c43d58c7 --- /dev/null +++ b/software/firmware/source/SoftRF/src/platform/RA4M1.h @@ -0,0 +1,205 @@ +/* + * Platform_RA4M1.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_RENESAS) + +#ifndef PLATFORM_RA4M1_H +#define PLATFORM_RA4M1_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 SerialUSB +//#define SerialOutput Serial1 + +#define USBSerial SerialUSB +#define Serial_GNSS_In Serial1 +#define Serial_GNSS_Out Serial_GNSS_In +#define UATSerial SerialUSB + +#define SOC_ADC_VOLTAGE_DIV 2 /* TBD */ + +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(ARDUINO_UNOR4_MINIMA) + +/* Peripherals */ +#define SOC_GPIO_PIN_CONS_RX PIN_SERIAL_RX // PB23 +#define SOC_GPIO_PIN_CONS_TX PIN_SERIAL_TX // PB22 + +#define SOC_GPIO_PIN_GNSS_RX PIN_SERIAL1_RX // PA11 +#define SOC_GPIO_PIN_GNSS_TX PIN_SERIAL1_TX // PA10 + +#define USE_ISP_PORT 1 + +#if USE_ISP_PORT +#define SOC_GPIO_PIN_STATUS LED_BUILTIN // PA17 +#else +#define SOC_GPIO_PIN_STATUS PIN_LED_RXL // PB03 +#endif /* USE_ISP_PORT */ +#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 */ +#if USE_ISP_PORT +/* ISP port */ +#define SOC_GPIO_PIN_MOSI PIN_SPI_MOSI // PB10 +#define SOC_GPIO_PIN_MISO PIN_SPI_MISO // PB12 +#define SOC_GPIO_PIN_SCK PIN_SPI_SCK // PB11 +#else +/* Port B */ +#define SOC_GPIO_PIN_MOSI 11 // PA16 +#define SOC_GPIO_PIN_MISO 12 // PA19 +#define SOC_GPIO_PIN_SCK 13 // PA17 +#endif /* USE_ISP_PORT */ +#define SOC_GPIO_PIN_SS 10 // PA18 +//#define SOC_GPIO_PIN_SS 4 // NL +//#define SOC_GPIO_PIN_SS 5 // NL + +/* 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 9 // PA07 +#define SOC_GPIO_PIN_BUSY SOC_UNUSED_PIN +#define SOC_GPIO_PIN_DIO1 6 // PA20 + +/* RF antenna switch */ +#define SOC_GPIO_PIN_ANT_RXTX SOC_UNUSED_PIN + +/* I2C */ +#define SOC_GPIO_PIN_SDA PIN_WIRE_SDA // PA22 +#define SOC_GPIO_PIN_SCL PIN_WIRE_SCL // PA23 + +#define SOC_GPIO_PIN_LED SOC_UNUSED_PIN +#define SOC_GPIO_PIN_GNSS_PPS PIN_A3 // PA04 +#define SOC_GPIO_PIN_BATTERY PIN_A0 // PA02 +#define SOC_GPIO_PIN_BUTTON SOC_UNUSED_PIN + +#if defined(USE_TINYUSB) +#define SOC_GPIO_RADIO_LED_RX PIN_LED_RXL +#define SOC_GPIO_RADIO_LED_TX PIN_LED_TXL +#else +#define SOC_GPIO_RADIO_LED_RX SOC_UNUSED_PIN +#define SOC_GPIO_RADIO_LED_TX SOC_UNUSED_PIN +#endif /* USE_TINYUSB */ + +#else +#error "This RA4M1 build variant is not supported!" +#endif + +#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_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 */ + +#if defined(USE_USB_HOST) + +#if defined(Serial) +#undef Serial +#endif +#define Serial Serial1 + +#if defined(SerialOutput) +#undef SerialOutput +#endif +#define SerialOutput Serial1 + +#endif /* USE_USB_HOST */ + +#endif /* PLATFORM_RA4M1_H */ + +#endif /* ARDUINO_ARCH_RENESAS */ diff --git a/software/firmware/source/SoftRF/src/system/SoC.cpp b/software/firmware/source/SoftRF/src/system/SoC.cpp index 92da54d55..ede9e52c9 100644 --- a/software/firmware/source/SoftRF/src/system/SoC.cpp +++ b/software/firmware/source/SoftRF/src/system/SoC.cpp @@ -46,6 +46,8 @@ byte SoC_setup() SoC = &ASR66_ops; #elif defined(ARDUINO_ARCH_RP2040) SoC = &RP2040_ops; +#elif defined(ARDUINO_ARCH_RENESAS) + SoC = &RA4M1_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 59f0f214b..757e32282 100644 --- a/software/firmware/source/SoftRF/src/system/SoC.h +++ b/software/firmware/source/SoftRF/src/system/SoC.h @@ -34,6 +34,7 @@ #include "../platform/AVR.h" #include "../platform/ASR66.h" #include "../platform/RP2040.h" +#include "../platform/RA4M1.h" typedef struct SoC_ops_struct { uint8_t id; @@ -106,7 +107,8 @@ enum SOC_SAMD, SOC_AVR, SOC_ASR66, - SOC_RP2040 + SOC_RP2040, + SOC_RA4M1 }; extern const SoC_ops_t *SoC; @@ -146,6 +148,9 @@ extern const SoC_ops_t ASR66_ops; #if defined(ARDUINO_ARCH_RP2040) extern const SoC_ops_t RP2040_ops; #endif +#if defined(ARDUINO_ARCH_RENESAS) +extern const SoC_ops_t RA4M1_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 6ebd3ce75..8675efe95 100644 --- a/software/firmware/source/libraries/Adafruit_BMP280_Library/Adafruit_BMP280.h +++ b/software/firmware/source/libraries/Adafruit_BMP280_Library/Adafruit_BMP280.h @@ -28,7 +28,7 @@ defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \ defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_SAMD) || \ defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_RP2040) || \ - defined(HACKRF_ONE)) + defined(HACKRF_ONE) || defined(ARDUINO_ARCH_RENESAS)) #include #endif diff --git a/software/firmware/source/libraries/libmodes/src/mode-s.c b/software/firmware/source/libraries/libmodes/src/mode-s.c index 29c4864a0..ec032c639 100644 --- a/software/firmware/source/libraries/libmodes/src/mode-s.c +++ b/software/firmware/source/libraries/libmodes/src/mode-s.c @@ -822,7 +822,9 @@ void mode_s_detect(mode_s_t *self, mag_t *mag, uint32_t maglen, mode_s_callback_ /* ============================= Utility functions ========================== */ static ms_time_t mstime(void) { -#if !defined(HACKRF_ONE) && !defined(ARDUINO_ARCH_AVR) +#if !defined(HACKRF_ONE) && !defined(ARDUINO_ARCH_AVR) && \ + !defined(ARDUINO_ARCH_RENESAS) + struct timeval tv; ms_time_t mst; diff --git a/software/firmware/source/libraries/libmodes/src/mode-s.h b/software/firmware/source/libraries/libmodes/src/mode-s.h index 9c109f051..454095ce4 100644 --- a/software/firmware/source/libraries/libmodes/src/mode-s.h +++ b/software/firmware/source/libraries/libmodes/src/mode-s.h @@ -39,10 +39,12 @@ #include #include #include -#ifndef ARDUINO_ARCH_AVR -#include -#else +#if defined(ARDUINO_ARCH_AVR) typedef unsigned long time_t; +#elif defined(ARDUINO_ARCH_RENESAS) +typedef _TIME_T_ time_t; +#else +#include #endif #ifndef __cplusplus diff --git a/software/firmware/source/libraries/nRF905/nRF905.cpp b/software/firmware/source/libraries/nRF905/nRF905.cpp index 37e8536cb..284e4a5fa 100644 --- a/software/firmware/source/libraries/nRF905/nRF905.cpp +++ b/software/firmware/source/libraries/nRF905/nRF905.cpp @@ -12,7 +12,8 @@ !defined(ARDUINO_ARCH_STM32) && !defined(ARDUINO_ARCH_NRF52) && \ !defined(__ASR6501__) && !defined(HACKRF_ONE) && \ !defined(ARDUINO_ARCH_SAMD) && !defined(ARDUINO_ARCH_ASR650X) && \ - !defined(ARDUINO_ARCH_ASR6601) && !defined(ARDUINO_ARCH_RP2040) + !defined(ARDUINO_ARCH_ASR6601) && !defined(ARDUINO_ARCH_RP2040) && \ + !defined(ARDUINO_ARCH_RENESAS) #include #include @@ -24,10 +25,10 @@ #ifdef ARDUINO #include #include -#if defined(ENERGIA_ARCH_CC13XX) || defined(ENERGIA_ARCH_CC13X2) || \ - defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_SAMD) || \ - defined(ARDUINO_ARCH_RP2040) || (defined(ARDUINO_ARCH_STM32) && \ - defined(ARDUINO_WisDuo_RAK3172_Evaluation_Board)) +#if defined(ENERGIA_ARCH_CC13XX) || defined(ENERGIA_ARCH_CC13X2) || \ + defined(ARDUINO_ARCH_NRF52) || defined(ARDUINO_ARCH_SAMD) || \ + defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) || \ + (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 */ #else @@ -183,7 +184,7 @@ void nRF905_init() #if !defined(RASPBERRY_PI) && !defined(__ASR6501__) && \ !defined(ARDUINO_ARCH_ASR650X) && !defined(ARDUINO_ARCH_ASR6601) && \ - !defined(ARDUINO_ARCH_RP2040) + !defined(ARDUINO_ARCH_RP2040) && !defined(ARDUINO_ARCH_RENESAS) SPI.setClockDivider(SPI_CLOCK_DIV2); #endif /* RASPBERRY_PI */ #else diff --git a/software/firmware/source/libraries/nRF905/nRF905_config.h b/software/firmware/source/libraries/nRF905/nRF905_config.h index b9aa1d773..d37276439 100644 --- a/software/firmware/source/libraries/nRF905/nRF905_config.h +++ b/software/firmware/source/libraries/nRF905/nRF905_config.h @@ -27,7 +27,7 @@ defined(__ASR6501__) || defined(HACKRF_ONE) || \ defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \ defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \ - defined(ARDUINO_ARCH_RP2040) + defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) #define NRF905_INTERRUPTS 0 #else #define NRF905_INTERRUPTS 1 @@ -54,7 +54,7 @@ defined(__ASR6501__) || defined(HACKRF_ONE) || \ defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \ defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \ - defined(ARDUINO_ARCH_RP2040) + defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) #define NRF905_AM_SW 1 #else #define NRF905_AM_SW 0 @@ -71,7 +71,7 @@ defined(__ASR6501__) || defined(HACKRF_ONE) || \ defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \ defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \ - defined(ARDUINO_ARCH_RP2040) + defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) #define NRF905_COLLISION_AVOID 0 #else #define NRF905_COLLISION_AVOID 1 @@ -178,7 +178,9 @@ #define CD 0 // Carrier detect pin (for collision avoidance, if enabled) -#elif defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_RP2040) +#elif defined(ARDUINO_ARCH_SAMD) || \ + defined(ARDUINO_ARCH_RP2040) || \ + defined(ARDUINO_ARCH_RENESAS) // TBD #define TRX_EN 0 // Enable/standby pin @@ -319,7 +321,7 @@ defined(__ASR6501__) || defined(HACKRF_ONE) || \ defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \ defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \ - defined(ARDUINO_ARCH_RP2040) + defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) #define NRF905_FREQ 868400000UL #else #define NRF905_FREQ 433200000UL @@ -334,7 +336,7 @@ defined(__ASR6501__) || defined(HACKRF_ONE) || \ defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \ defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \ - defined(ARDUINO_ARCH_RP2040) + defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) #define NRF905_BAND NRF905_BAND_868 #else #define NRF905_BAND NRF905_BAND_433 @@ -383,7 +385,7 @@ defined(__ASR6501__) || defined(HACKRF_ONE) || \ defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \ defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \ - defined(ARDUINO_ARCH_RP2040) + defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) #define NRF905_ADDR_SIZE NRF905_ADDR_SIZE_3 //#define NRF905_ADDR_SIZE NRF905_ADDR_SIZE_2 #else @@ -396,7 +398,7 @@ defined(__ASR6501__) || defined(HACKRF_ONE) || \ defined(ARDUINO_ARCH_SAMD) || defined(ARDUINO_ARCH_AVR) || \ defined(ARDUINO_ARCH_ASR650X) || defined(ARDUINO_ARCH_ASR6601) || \ - defined(ARDUINO_ARCH_RP2040) + defined(ARDUINO_ARCH_RP2040) || defined(ARDUINO_ARCH_RENESAS) #define NRF905_PAYLOAD_SIZE 24 #else #define NRF905_PAYLOAD_SIZE 32 //NRF905_MAX_PAYLOAD