]> git.tnoah.ca Git - lora-radio.git/commitdiff
Initial multiplatform support
authorMark Qvist <mark@unsigned.io>
Sun, 9 Jan 2022 22:40:30 +0000 (23:40 +0100)
committerMark Qvist <mark@unsigned.io>
Sun, 9 Jan 2022 22:40:30 +0000 (23:40 +0100)
Config.h
Framing.h
LoRa.cpp
Makefile
RNode_Firmware.ino
ROM.h
Utilities.h

index e729380d2065695d848aa320f080b350b6452e2a..db07c091a20c90a6e142e6e634ae8d7db808517b 100644 (file)
--- a/Config.h
+++ b/Config.h
@@ -4,20 +4,30 @@
        #define CONFIG_H
 
        #define MAJ_VERS  0x01
-       #define MIN_VERS  0x12
+       #define MIN_VERS  0x13
+
+       #define PLATFORM_AVR   0x90
+    #define PLATFORM_ESP32 0x80
 
        #define MCU_1284P 0x91
        #define MCU_2560  0x92
+       #define MCU_ESP32 0x81
 
        #define MODE_HOST 0x11
        #define MODE_TNC  0x12
 
        #if defined(__AVR_ATmega1284P__)
+               #define PLATFORM PLATFORM_AVR
                #define MCU_VARIANT MCU_1284P
                #warning "Firmware is being compiled for atmega1284p based boards"
        #elif defined(__AVR_ATmega2560__)
+               #define PLATFORM PLATFORM_AVR
                #define MCU_VARIANT MCU_2560
                #warning "Firmware is being compiled for atmega2560 based boards"
+       #elif defined(ESP32)
+               #define PLATFORM PLATFORM_ESP32
+               #define MCU_VARIANT MCU_ESP32
+               #warning "Firmware is being compiled for ESP32 based boards"
        #else
                #error "The firmware cannot be compiled for the selected MCU variant"
        #endif
                const int pin_led_rx = 12;
                const int pin_led_tx = 13;
 
-               // TODO: Reset
                #define CONFIG_UART_BUFFER_SIZE 6144
                #define CONFIG_QUEUE_SIZE 6144
                #define CONFIG_QUEUE_MAX_LENGTH 250
 
                #define EEPROM_SIZE 4096
                #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
-       #endif
-
-       #if MCU_VARIANT == MCU_2560
+       
+       #elif MCU_VARIANT == MCU_2560
                const int pin_cs = 10;
                const int pin_reset = 9;
                const int pin_dio = 2;
                const int pin_led_rx = 12;
                const int pin_led_tx = 13;
 
-               // TODO: Reset
                #define CONFIG_UART_BUFFER_SIZE 2048
                #define CONFIG_QUEUE_SIZE 2048
-               #define CONFIG_QUEUE_MAX_LENGTH 250
+               #define CONFIG_QUEUE_MAX_LENGTH 80
 
                #define EEPROM_SIZE 4096
                #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
+
+       #elif MCU_VARIANT == MCU_ESP32
+               const int pin_cs = 18;
+               const int pin_reset = 23;
+               const int pin_dio = 26;
+               const int pin_led_rx = 2;
+               const int pin_led_tx = 4;
+
+               #define CONFIG_UART_BUFFER_SIZE 6144
+               #define CONFIG_QUEUE_SIZE 6144
+               #define CONFIG_QUEUE_MAX_LENGTH 250
+
+               #define EEPROM_SIZE 1024
+               #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED
        #endif
 
        #define eeprom_addr(a) (a+EEPROM_OFFSET)
@@ -71,7 +92,7 @@
 
        // SX1276 RSSI offset to get dBm value from
        // packet RSSI register
-       const int  rssi_offset      = 157;
+       const int  rssi_offset = 157;
 
        // Default LoRa settings
        int  lora_sf       = 0;
index 7290167e574d991e92d65df3bb898879a846cafd..756993d43e058df5de34ca5157f50ec3c9d946c7 100644 (file)
--- a/Framing.h
+++ b/Framing.h
@@ -27,6 +27,8 @@
        #define CMD_BLINK               0x30
        #define CMD_RANDOM              0x40
 
+       #define CMD_PLATFORM    0x48
+       #define CMD_MCU         0x49
        #define CMD_FW_VERSION  0x50
        #define CMD_ROM_READ    0x51
        #define CMD_ROM_WRITE   0x52
@@ -34,6 +36,9 @@
        #define CMD_CONF_DELETE 0x54
        #define CMD_UNLOCK_ROM  0x59
        #define ROM_UNLOCK_BYTE 0xF8
+       #define CMD_RESET       0x55
+       #define CMD_RESET_BYTE  0xF8
+
 
        #define DETECT_REQ              0x73
        #define DETECT_RESP             0x46
index d567b8145848ed287372d5d1beb9eb38f4c4a401..f91272ca859bb0c8a93383652a9599748d27530d 100644 (file)
--- a/LoRa.cpp
+++ b/LoRa.cpp
@@ -449,6 +449,8 @@ long LoRaClass::getSignalBandwidth()
     case 8: return 250E3; 
     case 9: return 500E3; 
   }
+  
+  return 0;
 }
 
 void LoRaClass::handleLowDataRate(){
index 37585bdd93c119f97ab86fa453e0f96cb5da1205..79cc8b35a483033e4e7cf2da9d5a09a57c5693e0 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,29 @@
+prep:
+       arduino-cli core update-index --config-file arduino-cli.yaml
+       arduino-cli core install unsignedio:avr
 
 firmware:
        arduino-cli compile --fqbn unsignedio:avr:rnode
 
+release:
+       arduino-cli compile --fqbn unsignedio:avr:rnode -e
+       cp build/unsignedio.avr.rnode/RNode_Firmware.ino.hex Precompiled/rnode_firmware_latest.hex
+       rm -r build
+
 upload:
        arduino-cli upload -p /dev/ttyUSB0 --fqbn unsignedio:avr:rnode
+
+prep-tbeam:
+       arduino-cli core update-index --config-file arduino-cli.yaml
+       arduino-cli core install esp32:esp32
+
+firmware-tbeam:
+       arduino-cli compile --fqbn esp32:esp32:t-beam
+
+upload-tbeam:
+       arduino-cli upload -p /dev/ttyUSB0 --fqbn esp32:esp32:t-beam
+
+release-tbeam:
+       arduino-cli compile --fqbn esp32:esp32:t-beam -e
+       cp build/esp32.esp32.t-beam/RNode_Firmware.ino.bin Precompiled/rnode_firmware_latest_tbeam.bin
+       rm -r build
\ No newline at end of file
index dfcaae4c13532ebf5cd01c43088b3097b5e01513..1f1801ad47040fbd25f1973458828dc219edea37 100644 (file)
@@ -22,6 +22,12 @@ volatile bool serial_buffering = false;
 char sbuf[128];
 
 void setup() {
+  #if MCU_VARIANT == MCU_ESP32
+    delay(1500);
+    EEPROM.begin(EEPROM_SIZE);
+    Serial.setRxBufferSize(CONFIG_UART_BUFFER_SIZE);
+  #endif
+
   // Seed the PRNG
   randomSeed(analogRead(0));
 
@@ -54,6 +60,12 @@ void setup() {
   // pins for the LoRa module
   LoRa.setPins(pin_cs, pin_reset, pin_dio);
 
+  #if MCU_VARIANT == MCU_ESP32
+    radio_locked  = true;
+    radio_online  = false;
+    hw_ready      = false;
+  #endif
+
   // Validate board health, EEPROM and config
   validateStatus();
 }
@@ -76,6 +88,7 @@ bool startRadio() {
         // serial port and with the onboard LEDs
         kiss_indicate_error(ERROR_INITRADIO);
         led_indicate_error(0);
+        return false;
       } else {
         radio_online = true;
 
@@ -86,13 +99,17 @@ bool startRadio() {
         getFrequency();
 
         LoRa.enableCrc();
-        LoRa.onReceive(receiveCallback);
+
+        #if MCU_VARIANT != MCU_ESP32
+          LoRa.onReceive(receive_callback);
+        #endif
 
         lora_receive();
 
         // Flash an info pattern to indicate
         // that the radio is now on
         led_indicate_info(3);
+        return true;
       }
 
     } else {
@@ -100,10 +117,12 @@ bool startRadio() {
       // that the radio was locked, and thus
       // not started
       led_indicate_warning(3);
+      return false;
     }
   } else {
     // If radio is already on, we silently
     // ignore the request.
+    return true;
   }
 }
 
@@ -120,7 +139,7 @@ void update_radio_lock() {
   }
 }
 
-void receiveCallback(int packet_size) {
+void receive_callback(int packet_size) {
   if (!promisc) {
     // The standard operating mode allows large
     // packets with a payload up to 500 bytes,
@@ -197,7 +216,7 @@ void receiveCallback(int packet_size) {
     }  
   } else {
     // In promiscuous mode, raw packets are
-    // output directly over to the host
+    // output directly to the host
     read_len = 0;
     last_rssi = LoRa.packetRssi();
     last_snr_raw = LoRa.packetSnrRaw();
@@ -232,7 +251,13 @@ void flushQueue(void) {
     queue_flushing = true;
 
     size_t processed = 0;
+
+    #if MCU_VARIANT == MCU_ESP32
+    while (!fifo16_isempty(&packet_starts)) {
+    #else
     while (!fifo16_isempty_locked(&packet_starts)) {
+    #endif
+
       size_t start = fifo16_pop(&packet_starts);
       size_t length = fifo16_pop(&packet_lengths);
 
@@ -497,6 +522,10 @@ void serialCallback(uint8_t sbyte) {
       if (sbyte == ROM_UNLOCK_BYTE) {
         unlock_rom();
       }
+    } else if (command == CMD_RESET) {
+      if (sbyte == CMD_RESET_BYTE) {
+        hard_reset();
+      }
     } else if (command == CMD_ROM_READ) {
       kiss_dump_eeprom();
     } else if (command == CMD_ROM_WRITE) {
@@ -516,6 +545,10 @@ void serialCallback(uint8_t sbyte) {
         }
     } else if (command == CMD_FW_VERSION) {
       kiss_indicate_version();
+    } else if (command == CMD_PLATFORM) {
+      kiss_indicate_platform();
+    } else if (command == CMD_MCU) {
+      kiss_indicate_mcu();
     } else if (command == CMD_CONF_SAVE) {
       eeprom_conf_save();
     } else if (command == CMD_CONF_DELETE) {
@@ -562,18 +595,31 @@ void checkModemStatus() {
 }
 
 void validateStatus() {
-  if (OPTIBOOT_MCUSR & (1<<PORF)) {
+  #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+      uint8_t boot_flags = OPTIBOOT_MCUSR;
+      uint8_t F_POR = PORF;
+      uint8_t F_BOR = BORF;
+      uint8_t F_WDR = WDRF;
+  #elif MCU_VARIANT == MCU_ESP32
+      // TODO: Get ESP32 boot flags
+      uint8_t boot_flags = 0x02;
+      uint8_t F_POR = 0x00;
+      uint8_t F_BOR = 0x00;
+      uint8_t F_WDR = 0x01;
+  #endif
+
+  if (boot_flags & (1<<F_POR)) {
     boot_vector = START_FROM_POWERON;
-  } else if (OPTIBOOT_MCUSR & (1<<BORF)) {
+  } else if (boot_flags & (1<<F_BOR)) {
     boot_vector = START_FROM_BROWNOUT;
-  } else if (OPTIBOOT_MCUSR & (1<<WDRF)) {
+  } else if (boot_flags & (1<<F_WDR)) {
     boot_vector = START_FROM_BOOTLOADER;
   } else {
       Serial.write("Error, indeterminate boot vector\r\n");
       led_indicate_boot_error();
   }
 
-  if (boot_vector == START_FROM_BOOTLOADER) {
+  if (boot_vector == START_FROM_BOOTLOADER || boot_vector == START_FROM_POWERON) {
     if (eeprom_lock_set()) {
       if (eeprom_product_valid() && eeprom_model_valid() && eeprom_hwrev_valid()) {
         if (eeprom_checksum_valid()) {
@@ -602,6 +648,13 @@ void loop() {
   if (radio_online) {
     checkModemStatus();
 
+    #if MCU_VARIANT == MCU_ESP32
+      int packet_size = LoRa.parsePacket();
+      if (packet_size) {
+        receive_callback(packet_size);
+      }
+    #endif
+
     if (queue_height > 0) {
       if (!dcd_waiting) updateModemStatus();
 
@@ -630,14 +683,26 @@ void loop() {
     }
   }
 
-  if (!fifo_isempty_locked(&serialFIFO)) serial_poll();
+  #if MCU_VARIANT == MCU_ESP32
+    buffer_serial();
+  #endif
+
+  #if MCU_VARIANT != MCU_ESP32
+    if (!fifo_isempty_locked(&serialFIFO)) serial_poll();
+  #else
+    if (!fifo_isempty(&serialFIFO)) serial_poll();
+  #endif
 }
 
 volatile bool serial_polling = false;
 void serial_poll() {
   serial_polling = true;
 
+  #if MCU_VARIANT != MCU_ESP32
   while (!fifo_isempty_locked(&serialFIFO)) {
+  #else
+  while (!fifo_isempty(&serialFIFO)) {
+  #endif
     char sbyte = fifo_pop(&serialFIFO);
     serialCallback(sbyte);
   }
@@ -645,6 +710,7 @@ void serial_poll() {
   serial_polling = false;
 }
 
+
 #define MAX_CYCLES 20
 void buffer_serial() {
   if (!serial_buffering) {
@@ -654,9 +720,15 @@ void buffer_serial() {
     while (c < MAX_CYCLES && Serial.available()) {
       c++;
 
-      if (!fifo_isfull_locked(&serialFIFO)) {
-        fifo_push_locked(&serialFIFO, Serial.read());
-      }
+      #if MCU_VARIANT != MCU_ESP32
+        if (!fifo_isfull_locked(&serialFIFO)) {
+          fifo_push_locked(&serialFIFO, Serial.read());
+        }
+      #else
+        if (!fifo_isfull(&serialFIFO)) {
+          fifo_push(&serialFIFO, Serial.read());
+        }
+      #endif
     }
 
     serial_buffering = false;
@@ -664,17 +736,39 @@ void buffer_serial() {
 }
 
 void serial_interrupt_init() {
-  TCCR3A = 0;
-  TCCR3B = _BV(CS10) |
-           _BV(WGM33)|
-           _BV(WGM32);
+  #if MCU_VARIANT == MCU_1284P
+      TCCR3A = 0;
+      TCCR3B = _BV(CS10) |
+               _BV(WGM33)|
+               _BV(WGM32);
+
+      // Buffer incoming frames every 1ms
+      ICR3 = 16000;
+
+      TIMSK3 = _BV(ICIE3);
 
-  // Buffer incoming frames every 1ms
-  ICR3 = 16000;
+  #elif MCU_VARIANT == MCU_2560
+      // TODO: This should probably be updated for
+      // atmega2560 support. Might be source of
+      // reported issues from snh.
+      TCCR3A = 0;
+      TCCR3B = _BV(CS10) |
+               _BV(WGM33)|
+               _BV(WGM32);
+
+      // Buffer incoming frames every 1ms
+      ICR3 = 16000;
+
+      TIMSK3 = _BV(ICIE3);
+
+  #elif MCU_VARIANT == MCU_ESP32
+      // No interrupt-based polling on ESP32
+  #endif
 
-  TIMSK3 = _BV(ICIE3);
 }
 
-ISR(TIMER3_CAPT_vect) {
-  buffer_serial();
-}
\ No newline at end of file
+#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+  ISR(TIMER3_CAPT_vect) {
+    buffer_serial();
+  }
+#endif
\ No newline at end of file
diff --git a/ROM.h b/ROM.h
index 551e5125775b8efd3e3f3947db4440aaffc4322b..14348876ca3e4e54de3c937f2667e9b6f26942e2 100644 (file)
--- a/ROM.h
+++ b/ROM.h
@@ -4,8 +4,13 @@
        #define CHECKSUMMED_SIZE 0x0B
 
        #define PRODUCT_RNODE 0x03
+       #define PRODUCT_HMBRW 0xF0
+       #define PRODUCT_TBEAM 0xE0
        #define MODEL_A4 0xA4
        #define MODEL_A9 0xA9
+       #define MODEL_E4 0xE4
+       #define MODEL_E9 0xE9
+       #define MODEL_FF 0xFF
 
        #define ADDR_PRODUCT   0x00
        #define ADDR_MODEL     0x01
index 2431e1fb14a59fd0532c9e7c0724aec2aff375da..31c26780494deb8c49e760360b11a00093d07f17 100644 (file)
@@ -1,23 +1,52 @@
 #include <EEPROM.h>
 #include <stddef.h>
-#include <util/atomic.h>
 #include "LoRa.h"
 #include "ROM.h"
 #include "Config.h"
 #include "Framing.h"
 #include "MD5.h"
 
+#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+       #include <avr/wdt.h>
+       #include <util/atomic.h>
+#elif MCU_VARIANT == MCU_ESP32
+       // TODO: Hard reset on ESP32
+#endif
+
 uint8_t boot_vector = 0x00;
-uint8_t OPTIBOOT_MCUSR __attribute__ ((section(".noinit")));
-void resetFlagsInit(void) __attribute__ ((naked)) __attribute__ ((used)) __attribute__ ((section (".init0")));
-void resetFlagsInit(void) {
-    __asm__ __volatile__ ("sts %0, r2\n" : "=m" (OPTIBOOT_MCUSR) :);
-}
 
-void led_rx_on()  { digitalWrite(pin_led_rx, HIGH); }
-void led_rx_off() {    digitalWrite(pin_led_rx, LOW); }
-void led_tx_on()  { digitalWrite(pin_led_tx, HIGH); }
-void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
+#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+       uint8_t OPTIBOOT_MCUSR __attribute__ ((section(".noinit")));
+       void resetFlagsInit(void) __attribute__ ((naked)) __attribute__ ((used)) __attribute__ ((section (".init0")));
+       void resetFlagsInit(void) {
+           __asm__ __volatile__ ("sts %0, r2\n" : "=m" (OPTIBOOT_MCUSR) :);
+       }
+#elif MCU_VARIANT == MCU_ESP32
+       // TODO: Get ESP32 boot flags
+#endif
+
+#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+       void led_rx_on()  { digitalWrite(pin_led_rx, HIGH); }
+       void led_rx_off() {     digitalWrite(pin_led_rx, LOW); }
+       void led_tx_on()  { digitalWrite(pin_led_tx, HIGH); }
+       void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
+#elif MCU_VARIANT == MCU_ESP32
+       void led_rx_on()  { digitalWrite(pin_led_rx, LOW); }
+       void led_rx_off() {     digitalWrite(pin_led_rx, HIGH); }
+       void led_tx_on()  { digitalWrite(pin_led_tx, LOW); }
+       void led_tx_off() { digitalWrite(pin_led_tx, HIGH); }
+#endif
+
+void hard_reset(void) {
+       #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+               wdt_enable(WDTO_15MS);
+               while(true) {
+                       led_tx_on(); led_rx_off();
+               }
+       #elif MCU_VARIANT == MCU_ESP32
+               ESP.restart();
+       #endif
+}
 
 void led_indicate_error(int cycles) {
        bool forever = (cycles == 0) ? true : false;
@@ -31,8 +60,8 @@ void led_indicate_error(int cycles) {
         delay(100);
         if (!forever) cycles--;
     }
-    digitalWrite(pin_led_rx, LOW);
-    digitalWrite(pin_led_tx, LOW);
+    led_rx_off();
+    led_tx_off();
 }
 
 void led_indicate_boot_error() {
@@ -51,63 +80,131 @@ void led_indicate_warning(int cycles) {
        cycles = forever ? 1 : cycles;
        digitalWrite(pin_led_tx, HIGH);
        while(cycles > 0) {
-        digitalWrite(pin_led_tx, LOW);
+        led_tx_off();
         delay(100);
-        digitalWrite(pin_led_tx, HIGH);
+        led_tx_on();
         delay(100);
         if (!forever) cycles--;
     }
-    digitalWrite(pin_led_tx, LOW);
+   led_tx_off();
 }
 
-void led_indicate_info(int cycles) {
-       bool forever = (cycles == 0) ? true : false;
-       cycles = forever ? 1 : cycles;
-       while(cycles > 0) {
-        digitalWrite(pin_led_rx, LOW);
-        delay(100);
-        digitalWrite(pin_led_rx, HIGH);
-        delay(100);
-        if (!forever) cycles--;
-    }
-    digitalWrite(pin_led_rx, LOW);
-}
+#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+       void led_indicate_info(int cycles) {
+               bool forever = (cycles == 0) ? true : false;
+               cycles = forever ? 1 : cycles;
+               while(cycles > 0) {
+           led_rx_off();
+           delay(100);
+           led_rx_on();
+           delay(100);
+           if (!forever) cycles--;
+         }
+         led_rx_off();
+       }
+#elif MCU_VARIANT == MCU_ESP32
+       void led_indicate_info(int cycles) {
+               bool forever = (cycles == 0) ? true : false;
+               cycles = forever ? 1 : cycles;
+               while(cycles > 0) {
+           led_tx_off();
+           delay(100);
+           led_tx_on();
+           delay(100);
+           if (!forever) cycles--;
+         }
+         led_tx_off();
+       }
+#endif
 
-uint8_t led_standby_min = 1;
-uint8_t led_standby_max = 40;
+
+unsigned long led_standby_ticks = 0;
+#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+       uint8_t led_standby_min = 1;
+       uint8_t led_standby_max = 40;
+       unsigned long led_standby_wait = 11000;
+#elif MCU_VARIANT == MCU_ESP32
+       uint8_t led_standby_min = 200;
+       uint8_t led_standby_max = 255;
+       uint8_t led_notready_min = 0;
+       uint8_t led_notready_max = 255;
+       uint8_t led_notready_value = led_notready_min;
+       int8_t  led_notready_direction = 0;
+       unsigned long led_notready_ticks = 0;
+       unsigned long led_standby_wait = 4000;
+       unsigned long led_notready_wait = 150;
+#endif
 uint8_t led_standby_value = led_standby_min;
 int8_t  led_standby_direction = 0;
-unsigned long led_standby_ticks = 0;
-unsigned long led_standby_wait = 11000;
-void led_indicate_standby() {
-       led_standby_ticks++;
-       if (led_standby_ticks > led_standby_wait) {
-               led_standby_ticks = 0;
-               if (led_standby_value <= led_standby_min) {
-                       led_standby_direction = 1;
-               } else if (led_standby_value >= led_standby_max) {
-                       led_standby_direction = -1;
+
+#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+       void led_indicate_standby() {
+               led_standby_ticks++;
+               if (led_standby_ticks > led_standby_wait) {
+                       led_standby_ticks = 0;
+                       if (led_standby_value <= led_standby_min) {
+                               led_standby_direction = 1;
+                       } else if (led_standby_value >= led_standby_max) {
+                               led_standby_direction = -1;
+                       }
+                       led_standby_value += led_standby_direction;
+                       analogWrite(pin_led_rx, led_standby_value);
+                       led_tx_off();
                }
-               led_standby_value += led_standby_direction;
-               analogWrite(pin_led_rx, led_standby_value);
-               digitalWrite(pin_led_tx, 0);
        }
-}
+#elif MCU_VARIANT == MCU_ESP32
+       void led_indicate_standby() {
+               led_standby_ticks++;
+               if (led_standby_ticks > led_standby_wait) {
+                       led_standby_ticks = 0;
+                       if (led_standby_value <= led_standby_min) {
+                               led_standby_direction = 1;
+                       } else if (led_standby_value >= led_standby_max) {
+                               led_standby_direction = -1;
+                       }
+                       led_standby_value += led_standby_direction;
+                       analogWrite(pin_led_tx, led_standby_value);
+                       led_rx_off();
 
-void led_indicate_not_ready() {
-       led_standby_ticks++;
-       if (led_standby_ticks > led_standby_wait) {
-               led_standby_ticks = 0;
-               if (led_standby_value <= led_standby_min) {
-                       led_standby_direction = 1;
-               } else if (led_standby_value >= led_standby_max) {
-                       led_standby_direction = -1;
                }
-               led_standby_value += led_standby_direction;
-               analogWrite(pin_led_tx, led_standby_value);
-               digitalWrite(pin_led_rx, 0);
        }
-}
+#endif
+
+#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+       void led_indicate_not_ready() {
+               led_standby_ticks++;
+               if (led_standby_ticks > led_standby_wait) {
+                       led_standby_ticks = 0;
+                       if (led_standby_value <= led_standby_min) {
+                               led_standby_direction = 1;
+                       } else if (led_standby_value >= led_standby_max) {
+                               led_standby_direction = -1;
+                       }
+                       led_standby_value += led_standby_direction;
+                       analogWrite(pin_led_tx, led_standby_value);
+                       led_rx_off();
+               }
+       }
+#elif MCU_VARIANT == MCU_ESP32
+       void led_indicate_not_ready() {
+               led_notready_ticks++;
+               if (led_notready_ticks > led_notready_wait) {
+                       led_notready_ticks = 0;
+                       if (led_notready_value <= led_notready_min) {
+                               led_notready_direction = 1;
+                       } else if (led_notready_value >= led_notready_max) {
+                               led_notready_direction = -1;
+                       }
+                       led_notready_value += led_notready_direction;
+                       if (led_notready_value > 128) {
+                               led_tx_on();
+                       } else {
+                               led_tx_off();
+                       }
+                       led_rx_off();
+               }
+       }
+#endif
 
 void escapedSerialWrite(uint8_t byte) {
        if (byte == FEND) { Serial.write(FESC); byte = TFEND; }
@@ -266,6 +363,20 @@ void kiss_indicate_version() {
        Serial.write(FEND);
 }
 
+void kiss_indicate_platform() {
+       Serial.write(FEND);
+       Serial.write(CMD_PLATFORM);
+       Serial.write(PLATFORM);
+       Serial.write(FEND);
+}
+
+void kiss_indicate_mcu() {
+       Serial.write(FEND);
+       Serial.write(CMD_MCU);
+       Serial.write(MCU_VARIANT);
+       Serial.write(FEND);
+}
+
 bool isSplitPacket(uint8_t header) {
        return (header & FLAG_SPLIT);
 }
@@ -384,9 +495,21 @@ void kiss_dump_eeprom() {
        Serial.write(FEND);
 }
 
+void eeprom_update(int mapped_addr, uint8_t byte) {
+       #if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
+               EEPROM.update(mapped_addr, byte);
+       #elif MCU_VARIANT == MCU_ESP32
+               if (EEPROM.read(mapped_addr) != byte) {
+                       EEPROM.write(mapped_addr, byte);
+                       EEPROM.commit();
+               }
+       #endif
+
+}
+
 void eeprom_write(uint8_t addr, uint8_t byte) {
        if (!eeprom_info_locked() && addr >= 0 && addr < EEPROM_RESERVED) {
-               EEPROM.update(eeprom_addr(addr), byte);
+               eeprom_update(eeprom_addr(addr), byte);
        } else {
                kiss_indicate_error(ERROR_EEPROM_LOCKED);
        }
@@ -394,9 +517,9 @@ void eeprom_write(uint8_t addr, uint8_t byte) {
 
 void eeprom_erase() {
        for (int addr = 0; addr < EEPROM_RESERVED; addr++) {
-               EEPROM.update(eeprom_addr(addr), 0xFF);
+               eeprom_update(eeprom_addr(addr), 0xFF);
        }
-       while (true) { led_tx_on(); led_rx_off(); }
+       hard_reset();
 }
 
 bool eeprom_lock_set() {
@@ -408,7 +531,8 @@ bool eeprom_lock_set() {
 }
 
 bool eeprom_product_valid() {
-       if (EEPROM.read(eeprom_addr(ADDR_PRODUCT)) == PRODUCT_RNODE) {
+       uint8_t rval = EEPROM.read(eeprom_addr(ADDR_PRODUCT));
+       if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM) {
                return true;
        } else {
                return false;
@@ -417,7 +541,7 @@ bool eeprom_product_valid() {
 
 bool eeprom_model_valid() {
        model = EEPROM.read(eeprom_addr(ADDR_MODEL));
-       if (model == MODEL_A4 || model == MODEL_A9) {
+       if (model == MODEL_A4 || model == MODEL_A9 || model == MODEL_FF || model == MODEL_E4 || model == MODEL_E9) {
                return true;
        } else {
                return false;
@@ -475,21 +599,21 @@ void eeprom_conf_load() {
 
 void eeprom_conf_save() {
        if (hw_ready && radio_online) {
-               EEPROM.update(eeprom_addr(ADDR_CONF_SF), lora_sf);
-               EEPROM.update(eeprom_addr(ADDR_CONF_CR), lora_cr);
-               EEPROM.update(eeprom_addr(ADDR_CONF_TXP), lora_txp);
+               eeprom_update(eeprom_addr(ADDR_CONF_SF), lora_sf);
+               eeprom_update(eeprom_addr(ADDR_CONF_CR), lora_cr);
+               eeprom_update(eeprom_addr(ADDR_CONF_TXP), lora_txp);
 
-               EEPROM.update(eeprom_addr(ADDR_CONF_BW)+0x00, lora_bw>>24);
-               EEPROM.update(eeprom_addr(ADDR_CONF_BW)+0x01, lora_bw>>16);
-               EEPROM.update(eeprom_addr(ADDR_CONF_BW)+0x02, lora_bw>>8);
-               EEPROM.update(eeprom_addr(ADDR_CONF_BW)+0x03, lora_bw);
+               eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, lora_bw>>24);
+               eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, lora_bw>>16);
+               eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, lora_bw>>8);
+               eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x03, lora_bw);
 
-               EEPROM.update(eeprom_addr(ADDR_CONF_FREQ)+0x00, lora_freq>>24);
-               EEPROM.update(eeprom_addr(ADDR_CONF_FREQ)+0x01, lora_freq>>16);
-               EEPROM.update(eeprom_addr(ADDR_CONF_FREQ)+0x02, lora_freq>>8);
-               EEPROM.update(eeprom_addr(ADDR_CONF_FREQ)+0x03, lora_freq);
+               eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, lora_freq>>24);
+               eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, lora_freq>>16);
+               eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, lora_freq>>8);
+               eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, lora_freq);
 
-               EEPROM.update(eeprom_addr(ADDR_CONF_OK), CONF_OK_BYTE);
+               eeprom_update(eeprom_addr(ADDR_CONF_OK), CONF_OK_BYTE);
                led_indicate_info(10);
        } else {
                led_indicate_warning(10);
@@ -497,7 +621,7 @@ void eeprom_conf_save() {
 }
 
 void eeprom_conf_delete() {
-       EEPROM.update(eeprom_addr(ADDR_CONF_OK), 0x00);
+       eeprom_update(eeprom_addr(ADDR_CONF_OK), 0x00);
 }
 
 void unlock_rom() {
@@ -544,28 +668,31 @@ inline void fifo_flush(FIFOBuffer *f) {
   f->head = f->tail;
 }
 
-static inline bool fifo_isempty_locked(const FIFOBuffer *f) {
-  bool result;
-  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
-    result = fifo_isempty(f);
-  }
-  return result;
-}
+#if MCU_VARIANT != MCU_ESP32
+       static inline bool fifo_isempty_locked(const FIFOBuffer *f) {
+         bool result;
+         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+           result = fifo_isempty(f);
+         }
+         return result;
+       }
 
-static inline bool fifo_isfull_locked(const FIFOBuffer *f) {
-  bool result;
-  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
-    result = fifo_isfull(f);
-  }
-  return result;
-}
+       static inline bool fifo_isfull_locked(const FIFOBuffer *f) {
+         bool result;
+         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+           result = fifo_isfull(f);
+         }
+         return result;
+       }
 
-static inline void fifo_push_locked(FIFOBuffer *f, unsigned char c) {
-  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
-    fifo_push(f, c);
-  }
-}
+       static inline void fifo_push_locked(FIFOBuffer *f, unsigned char c) {
+         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+           fifo_push(f, c);
+         }
+       }
+#endif
 
+/*
 static inline unsigned char fifo_pop_locked(FIFOBuffer *f) {
   unsigned char c;
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
@@ -573,6 +700,7 @@ static inline unsigned char fifo_pop_locked(FIFOBuffer *f) {
   }
   return c;
 }
+*/
 
 inline void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size) {
   f->head = f->tail = f->begin = buffer;
@@ -622,14 +750,18 @@ inline void fifo16_flush(FIFOBuffer16 *f) {
   f->head = f->tail;
 }
 
-static inline bool fifo16_isempty_locked(const FIFOBuffer16 *f) {
-  bool result;
-  ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
-    result = fifo16_isempty(f);
-  }
-  return result;
-}
+#if MCU_VARIANT != MCU_ESP32
+       static inline bool fifo16_isempty_locked(const FIFOBuffer16 *f) {
+         bool result;
+         ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
+           result = fifo16_isempty(f);
+         }
+
+         return result;
+       }
+#endif
 
+/*
 static inline bool fifo16_isfull_locked(const FIFOBuffer16 *f) {
   bool result;
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
@@ -638,6 +770,7 @@ static inline bool fifo16_isfull_locked(const FIFOBuffer16 *f) {
   return result;
 }
 
+
 static inline void fifo16_push_locked(FIFOBuffer16 *f, size_t c) {
   ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
     fifo16_push(f, c);
@@ -651,6 +784,7 @@ static inline size_t fifo16_pop_locked(FIFOBuffer16 *f) {
   }
   return c;
 }
+*/
 
 inline void fifo16_init(FIFOBuffer16 *f, size_t *buffer, size_t size) {
   f->head = f->tail = f->begin = buffer;