diff --git a/Config.h b/Config.h index a8aeca6..ec87d76 100644 --- a/Config.h +++ b/Config.h @@ -1,13 +1,14 @@ +#include "ROM.h" + #ifndef CONFIG_H #define CONFIG_H + #define MAJ_VERS 0x01 + #define MIN_VERS 0x03 + #define MCU_328P 0x90 #define MCU_1284P 0x91 - #define PRODUCT_RNODE 0x03 - #define MODEL_A4 0xA4 - #define MODEL_A9 0xA9 - #if defined(__AVR_ATmega328P__) #define MCU_VARIANT MCU_328P #warning "Firmware is being compiled for atmega328p based boards" @@ -33,6 +34,9 @@ #define FLOW_CONTROL_ENABLED true #define QUEUE_SIZE 0 + + #define EEPROM_SIZE 512 + #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED #endif #if MCU_VARIANT == MCU_1284P @@ -44,8 +48,13 @@ #define FLOW_CONTROL_ENABLED true #define QUEUE_SIZE 24 + + #define EEPROM_SIZE 4096 + #define EEPROM_OFFSET EEPROM_SIZE-EEPROM_RESERVED #endif + #define eeprom_addr(a) (a+EEPROM_OFFSET) + // MCU independent configuration parameters const long serial_baudrate = 115200; const int rssi_offset = 164; @@ -62,6 +71,9 @@ // Operational variables bool radio_locked = true; bool radio_online = false; + bool hw_ready = false; + uint8_t model = 0x00; + uint8_t hwrev = 0x00; int last_rssi = -164; size_t read_len = 0; diff --git a/EEPROM.cpp b/EEPROM.cpp deleted file mode 100644 index b1990c1..0000000 --- a/EEPROM.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include -#include "Config.h" -#include "Framing.h" - -#define ADDR_PRODUCT 0x00 -#define ADDR_MODEL 0x01 -#define ADDR_HW_REV 0x02 -#define ADDR_SERIAL 0x03 -#define ADDR_MADE 0x06 -#define ADDR_CHKSUM 0x0A -#define ADDR_SIGNATURE 0x1A -#define ADDR_INFO_LOCK 0x9A -#define INFO_LOCK_BYTE 0x73 - -#define ADDR_CONF_SF 0x74 -#define ADDR_CONF_CR 0x75 -#define ADDR_CONF_TXP 0x76 -#define ADDR_CONF_BW 0x77 -#define ADDR_CONF_FREQ 0x7B -#define ADDR_CONF_OK 0x7F -#define CONF_OK_BYTE 0x73 - -void eeprom_dump_info() { - for (int addr = ADDR_PRODUCT; addr <= ADDR_INFO_LOCK; addr++) { - uint8_t rom_byte = EEPROM.read(addr); - Serial.write(rom_byte); - } -} - -void eeprom_dump_config() { - for (int addr = ADDR_CONF_SF; addr <= ADDR_CONF_OK; addr++) { - uint8_t rom_byte = EEPROM.read(addr); - Serial.write(rom_byte); - } -} \ No newline at end of file diff --git a/Framing.h b/Framing.h index af81042..eeebdf5 100644 --- a/Framing.h +++ b/Framing.h @@ -12,8 +12,10 @@ #define CMD_BANDWIDTH 0x02 #define CMD_TXPOWER 0x03 #define CMD_SF 0x04 - #define CMD_RADIO_STATE 0x05 - #define CMD_RADIO_LOCK 0x06 + #define CMD_CR 0x05 + #define CMD_RADIO_STATE 0x06 + #define CMD_RADIO_LOCK 0x07 + #define CMD_DETECT 0x08 #define CMD_READY 0x0F #define CMD_STAT_RX 0x21 @@ -22,23 +24,29 @@ #define CMD_BLINK 0x30 #define CMD_RANDOM 0x40 - #define CMD_INFO_READ 0x50 - #define CMD_INFO_WRITE 0x51 - #define CMD_CONF_READ 0x52 - #define CMD_CONF_WRITE 0x53 + #define CMD_FW_VERSION 0x50 + #define CMD_ROM_READ 0x51 + #define CMD_ROM_WRITE 0x52 + #define CMD_CONF_SAVE 0x53 + #define CMD_UNLOCK_ROM 0x59 + #define ROM_UNLOCK_BYTE 0xF8 + + #define DETECT_REQ 0x73 + #define DETECT_RESP 0x46 #define RADIO_STATE_OFF 0x00 #define RADIO_STATE_ON 0x01 - #define CMD_ERROR 0x90 - #define ERROR_INITRADIO 0x01 - #define ERROR_TXFAILED 0x02 - #define NIBBLE_SEQ 0xF0 #define NIBBLE_FLAGS 0x0F #define FLAG_SPLIT 0x01 #define SEQ_UNSET 0xFF + #define CMD_ERROR 0x90 + #define ERROR_INITRADIO 0x01 + #define ERROR_TXFAILED 0x02 + #define ERROR_EEPROM_LOCKED 0x03 + // Serial framing variables size_t frame_len; bool IN_FRAME = false; @@ -57,7 +65,7 @@ All: 0xc00119d21b80c00200005140c00308c00407c0 Radio on 0xc00501c0 -Config+on 0xc00119d21b80c00200005140c00308c00407c00501c0 +Config+on 0xc00119d21b80c00200005140c00301c00407c00601c0 c1 = self.bandwidth >> 24 diff --git a/RNode_Firmware.ino b/RNode_Firmware.ino index 5d1c851..9a9e2a6 100644 --- a/RNode_Firmware.ino +++ b/RNode_Firmware.ino @@ -2,7 +2,6 @@ #include #include "Config.h" #include "Framing.h" -#include "EEPROM.cpp" #include "Utilities.cpp" void setup() { @@ -25,12 +24,15 @@ void setup() { // Set chip select, reset and interrupt // pins for the LoRa module LoRa.setPins(pin_cs, pin_reset, pin_dio); + + // Validate board health, EEPROM and config + validateStatus(); } bool startRadio() { update_radio_lock(); if (!radio_online) { - if (!radio_locked) { + if (!radio_locked && hw_ready) { if (!LoRa.begin(lora_freq)) { // The radio could not be started. // Indicate this failure over both the @@ -280,6 +282,18 @@ void serialCallback(uint8_t sbyte) { setSpreadingFactor(); kiss_indicate_spreadingfactor(); } + } else if (command == CMD_CR) { + if (sbyte == 0xFF) { + kiss_indicate_codingrate(); + } else { + int cr = sbyte; + if (cr < 5) cr = 5; + if (cr > 8) cr = 8; + + lora_cr = cr; + setCodingRate(); + kiss_indicate_codingrate(); + } } else if (command == CMD_RADIO_STATE) { if (sbyte == 0xFF) { kiss_indicate_radiostate(); @@ -303,6 +317,33 @@ void serialCallback(uint8_t sbyte) { led_indicate_info(sbyte); } else if (command == CMD_RANDOM) { kiss_indicate_random(getRandom()); + } else if (command == CMD_DETECT) { + if (sbyte == DETECT_REQ) { + kiss_indicate_detect(); + } + } else if (command == CMD_UNLOCK_ROM) { + if (sbyte == ROM_UNLOCK_BYTE) { + unlock_rom(); + } + } else if (command == CMD_ROM_READ) { + kiss_dump_eeprom(); + } else if (command == CMD_ROM_WRITE) { + if (sbyte == FESC) { + ESCAPE = true; + } else { + if (ESCAPE) { + if (sbyte == TFEND) sbyte = FEND; + if (sbyte == TFESC) sbyte = FESC; + ESCAPE = false; + } + cbuf[frame_len++] = sbyte; + } + + if (frame_len == 2) { + eeprom_write(cbuf[0], cbuf[1]); + } + } else if (command == CMD_FW_VERSION) { + kiss_indicate_version(); } } } @@ -344,6 +385,20 @@ void checkModemStatus() { } } +void validateStatus() { + if (eeprom_lock_set()) { + if (eeprom_product_valid() && eeprom_model_valid() && eeprom_hwrev_valid()) { + if (eeprom_checksum_valid()) { + hw_ready = true; + } + } else { + hw_ready = false; + } + } else { + hw_ready = false; + } +} + void loop() { if (radio_online) { checkModemStatus(); @@ -362,7 +417,12 @@ void loop() { } } } else { - led_indicate_standby(); + if (hw_ready) { + led_indicate_standby(); + } else { + led_indicate_not_ready(); + stopRadio(); + } } if (Serial.available()) { diff --git a/Utilities.cpp b/Utilities.cpp index 29d9639..7417086 100644 --- a/Utilities.cpp +++ b/Utilities.cpp @@ -1,7 +1,10 @@ #include +#include #include +#include "ROM.h" #include "Config.h" #include "Framing.h" +#include "MD5.h" void led_rx_on() { digitalWrite(pin_led_rx, HIGH); } void led_rx_off() { digitalWrite(pin_led_rx, LOW); } @@ -68,6 +71,22 @@ void led_indicate_standby() { } led_standby_value += led_standby_direction; analogWrite(pin_led_rx, led_standby_value); + digitalWrite(pin_led_tx, 0); + } +} + +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); } } @@ -132,6 +151,13 @@ void kiss_indicate_spreadingfactor() { Serial.write(FEND); } +void kiss_indicate_codingrate() { + Serial.write(FEND); + Serial.write(CMD_CR); + Serial.write((uint8_t)lora_cr); + Serial.write(FEND); +} + void kiss_indicate_txpower() { Serial.write(FEND); Serial.write(CMD_TXPOWER); @@ -173,6 +199,21 @@ void kiss_indicate_ready() { Serial.write(FEND); } +void kiss_indicate_detect() { + Serial.write(FEND); + Serial.write(CMD_DETECT); + Serial.write(DETECT_RESP); + Serial.write(FEND); +} + +void kiss_indicate_version() { + Serial.write(FEND); + Serial.write(CMD_FW_VERSION); + Serial.write(MAJ_VERS); + Serial.write(MIN_VERS); + Serial.write(FEND); +} + bool isSplitPacket(uint8_t header) { return (header & FLAG_SPLIT); } @@ -197,7 +238,10 @@ void setCodingRate() { } void setTXPower() { - if (radio_online) LoRa.setTxPower(lora_txp); + if (radio_online) { + if (model == MODEL_A4) LoRa.setTxPower(lora_txp, PA_OUTPUT_RFO_PIN); + if (model == MODEL_A9) LoRa.setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN); + } } @@ -235,3 +279,116 @@ uint8_t getRandom() { } } +bool eeprom_info_locked() { + uint8_t lock_byte = EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)); + if (lock_byte == INFO_LOCK_BYTE) { + return true; + } else { + return false; + } +} + +void eeprom_dump_info() { + for (int addr = ADDR_PRODUCT; addr <= ADDR_INFO_LOCK; addr++) { + uint8_t byte = EEPROM.read(eeprom_addr(addr)); + escapedSerialWrite(byte); + } +} + +void eeprom_dump_config() { + for (int addr = ADDR_CONF_SF; addr <= ADDR_CONF_OK; addr++) { + uint8_t byte = EEPROM.read(eeprom_addr(addr)); + escapedSerialWrite(byte); + } +} + +void eeprom_dump_all() { + for (int addr = 0; addr < EEPROM_RESERVED; addr++) { + uint8_t byte = EEPROM.read(eeprom_addr(addr)); + escapedSerialWrite(byte); + } +} + +void kiss_dump_eeprom() { + Serial.write(FEND); + Serial.write(CMD_ROM_READ); + eeprom_dump_all(); + Serial.write(FEND); +} + +void eeprom_write(uint8_t addr, uint8_t byte) { + if (!eeprom_info_locked() && addr >= 0 && addr < EEPROM_RESERVED) { + EEPROM.update(eeprom_addr(addr), byte); + } else { + kiss_indicate_error(ERROR_EEPROM_LOCKED); + } +} + +void eeprom_erase() { + for (int addr = 0; addr < EEPROM_RESERVED; addr++) { + EEPROM.update(eeprom_addr(addr), 0xFF); + } + while (true) { led_tx_on(); led_rx_off(); } +} + +bool eeprom_lock_set() { + if (EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)) == INFO_LOCK_BYTE) { + return true; + } else { + return false; + } +} + +bool eeprom_product_valid() { + if (EEPROM.read(eeprom_addr(ADDR_PRODUCT)) == PRODUCT_RNODE) { + return true; + } else { + return false; + } +} + +bool eeprom_model_valid() { + model = EEPROM.read(eeprom_addr(ADDR_MODEL)); + if (model == MODEL_A4 || model == MODEL_A9) { + return true; + } else { + return false; + } +} + +bool eeprom_hwrev_valid() { + hwrev = EEPROM.read(eeprom_addr(ADDR_HW_REV)); + if (hwrev != 0x00 && hwrev != 0xFF) { + return true; + } else { + return false; + } +} + +bool eeprom_checksum_valid() { + char *data = (char*)malloc(CHECKSUMMED_SIZE); + for (uint8_t i = 0; i < CHECKSUMMED_SIZE; i++) { + char byte = EEPROM.read(eeprom_addr(i)); + data[i] = byte; + } + + unsigned char *hash = MD5::make_hash(data, CHECKSUMMED_SIZE); + bool checksum_valid = true; + for (uint8_t i = 0; i < 16; i++) { + uint8_t stored_chk_byte = EEPROM.read(eeprom_addr(ADDR_CHKSUM+i)); + uint8_t calced_chk_byte = (uint8_t)hash[i]; + if (stored_chk_byte != calced_chk_byte) { + checksum_valid = false; + } + } + + free(hash); + free(data); + return checksum_valid; +} + +void unlock_rom() { + led_indicate_error(50); + eeprom_erase(); +} +