This is a copy of the community maintained fork of the open firmware which powers RNode devices. This version will have support for the hardware made by Mees Electronics.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

802 lines
18 KiB

#include <EEPROM.h>
#include <stddef.h>
#include "LoRa.h"
#include "ROM.h"
7 years ago
#include "Config.h"
#include "Framing.h"
#include "MD5.h"
7 years ago
#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;
#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, HIGH); }
void led_rx_off() { digitalWrite(pin_led_rx, LOW); }
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
}
7 years ago
void led_indicate_error(int cycles) {
bool forever = (cycles == 0) ? true : false;
cycles = forever ? 1 : cycles;
while(cycles > 0) {
digitalWrite(pin_led_rx, HIGH);
digitalWrite(pin_led_tx, LOW);
delay(100);
digitalWrite(pin_led_rx, LOW);
digitalWrite(pin_led_tx, HIGH);
delay(100);
if (!forever) cycles--;
}
led_rx_off();
led_tx_off();
7 years ago
}
void led_indicate_boot_error() {
while (true) {
led_tx_on();
led_rx_off();
delay(10);
led_rx_on();
led_tx_off();
delay(5);
}
}
7 years ago
void led_indicate_warning(int cycles) {
bool forever = (cycles == 0) ? true : false;
cycles = forever ? 1 : cycles;
digitalWrite(pin_led_tx, HIGH);
while(cycles > 0) {
led_tx_off();
7 years ago
delay(100);
led_tx_on();
7 years ago
delay(100);
if (!forever) cycles--;
}
led_tx_off();
7 years ago
}
#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
7 years ago
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 = 1768;
unsigned long led_notready_wait = 150;
#endif
uint8_t led_standby_value = led_standby_min;
int8_t led_standby_direction = 0;
#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();
}
}
#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;
if (led_standby_value > 253) {
led_tx_on();
} else {
led_tx_off();
}
led_rx_off();
}
}
#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; }
if (byte == FESC) { Serial.write(FESC); byte = TFESC; }
Serial.write(byte);
}
void kiss_indicate_reset() {
Serial.write(FEND);
Serial.write(CMD_RESET);
Serial.write(CMD_RESET_BYTE);
Serial.write(FEND);
}
7 years ago
void kiss_indicate_error(uint8_t error_code) {
Serial.write(FEND);
Serial.write(CMD_ERROR);
Serial.write(error_code);
Serial.write(FEND);
}
void kiss_indicate_radiostate() {
Serial.write(FEND);
Serial.write(CMD_RADIO_STATE);
Serial.write(radio_online);
Serial.write(FEND);
}
void kiss_indicate_stat_rx() {
Serial.write(FEND);
Serial.write(CMD_STAT_RX);
escapedSerialWrite(stat_rx>>24);
escapedSerialWrite(stat_rx>>16);
escapedSerialWrite(stat_rx>>8);
escapedSerialWrite(stat_rx);
7 years ago
Serial.write(FEND);
}
void kiss_indicate_stat_tx() {
Serial.write(FEND);
Serial.write(CMD_STAT_TX);
escapedSerialWrite(stat_tx>>24);
escapedSerialWrite(stat_tx>>16);
escapedSerialWrite(stat_tx>>8);
escapedSerialWrite(stat_tx);
7 years ago
Serial.write(FEND);
}
void kiss_indicate_stat_rssi() {
uint8_t packet_rssi_val = (uint8_t)(last_rssi+rssi_offset);
7 years ago
Serial.write(FEND);
Serial.write(CMD_STAT_RSSI);
escapedSerialWrite(packet_rssi_val);
Serial.write(FEND);
}
void kiss_indicate_stat_snr() {
Serial.write(FEND);
Serial.write(CMD_STAT_SNR);
escapedSerialWrite(last_snr_raw);
7 years ago
Serial.write(FEND);
}
void kiss_indicate_radio_lock() {
Serial.write(FEND);
Serial.write(CMD_RADIO_LOCK);
Serial.write(radio_locked);
Serial.write(FEND);
}
void kiss_indicate_spreadingfactor() {
Serial.write(FEND);
Serial.write(CMD_SF);
Serial.write((uint8_t)lora_sf);
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_implicit_length() {
Serial.write(FEND);
Serial.write(CMD_IMPLICIT);
Serial.write(implicit_l);
Serial.write(FEND);
}
7 years ago
void kiss_indicate_txpower() {
Serial.write(FEND);
Serial.write(CMD_TXPOWER);
Serial.write((uint8_t)lora_txp);
Serial.write(FEND);
}
void kiss_indicate_bandwidth() {
Serial.write(FEND);
Serial.write(CMD_BANDWIDTH);
escapedSerialWrite(lora_bw>>24);
escapedSerialWrite(lora_bw>>16);
escapedSerialWrite(lora_bw>>8);
escapedSerialWrite(lora_bw);
7 years ago
Serial.write(FEND);
}
void kiss_indicate_frequency() {
Serial.write(FEND);
Serial.write(CMD_FREQUENCY);
escapedSerialWrite(lora_freq>>24);
escapedSerialWrite(lora_freq>>16);
escapedSerialWrite(lora_freq>>8);
escapedSerialWrite(lora_freq);
7 years ago
Serial.write(FEND);
}
void kiss_indicate_random(uint8_t byte) {
Serial.write(FEND);
Serial.write(CMD_RANDOM);
Serial.write(byte);
Serial.write(FEND);
}
void kiss_indicate_ready() {
Serial.write(FEND);
Serial.write(CMD_READY);
Serial.write(0x01);
Serial.write(FEND);
}
void kiss_indicate_not_ready() {
Serial.write(FEND);
Serial.write(CMD_READY);
Serial.write(0x00);
Serial.write(FEND);
}
void kiss_indicate_promisc() {
Serial.write(FEND);
Serial.write(CMD_PROMISC);
if (promisc) {
Serial.write(0x01);
} else {
Serial.write(0x00);
}
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);
}
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);
}
inline bool isSplitPacket(uint8_t header) {
7 years ago
return (header & FLAG_SPLIT);
}
inline uint8_t packetSequence(uint8_t header) {
7 years ago
return header >> 4;
}
void setSpreadingFactor() {
if (radio_online) LoRa.setSpreadingFactor(lora_sf);
}
void setCodingRate() {
if (radio_online) LoRa.setCodingRate4(lora_cr);
}
void set_implicit_length(uint8_t len) {
implicit_l = len;
if (implicit_l != 0) {
implicit = true;
} else {
implicit = false;
}
}
7 years ago
void setTXPower() {
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);
}
7 years ago
}
void getBandwidth() {
if (radio_online) {
lora_bw = LoRa.getSignalBandwidth();
}
}
void setBandwidth() {
if (radio_online) {
LoRa.setSignalBandwidth(lora_bw);
getBandwidth();
}
}
void getFrequency() {
if (radio_online) {
lora_freq = LoRa.getFrequency();
}
}
void setFrequency() {
if (radio_online) {
LoRa.setFrequency(lora_freq);
getFrequency();
}
}
uint8_t getRandom() {
if (radio_online) {
return LoRa.random();
} else {
return 0x00;
}
}
void promisc_enable() {
promisc = true;
}
void promisc_disable() {
promisc = false;
}
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_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);
} else {
kiss_indicate_error(ERROR_EEPROM_LOCKED);
}
}
void eeprom_erase() {
for (int addr = 0; addr < EEPROM_RESERVED; addr++) {
eeprom_update(eeprom_addr(addr), 0xFF);
}
hard_reset();
}
bool eeprom_lock_set() {
if (EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)) == INFO_LOCK_BYTE) {
return true;
} else {
return false;
}
}
bool eeprom_product_valid() {
uint8_t rval = EEPROM.read(eeprom_addr(ADDR_PRODUCT));
if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM) {
return true;
} else {
return false;
}
}
bool eeprom_model_valid() {
model = EEPROM.read(eeprom_addr(ADDR_MODEL));
if (model == MODEL_A4 || model == MODEL_A9 || model == MODEL_FF || model == MODEL_E4 || model == MODEL_E9) {
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;
}
bool eeprom_have_conf() {
if (EEPROM.read(eeprom_addr(ADDR_CONF_OK)) == CONF_OK_BYTE) {
return true;
} else {
return false;
}
}
void eeprom_conf_load() {
if (eeprom_have_conf()) {
lora_sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF));
lora_cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR));
lora_txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP));
lora_freq = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_FREQ)+0x03);
lora_bw = (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x00) << 24 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x01) << 16 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x02) << 8 | (uint32_t)EEPROM.read(eeprom_addr(ADDR_CONF_BW)+0x03);
}
}
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_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_OK), CONF_OK_BYTE);
led_indicate_info(10);
} else {
led_indicate_warning(10);
}
}
void eeprom_conf_delete() {
eeprom_update(eeprom_addr(ADDR_CONF_OK), 0x00);
}
void unlock_rom() {
led_indicate_error(50);
eeprom_erase();
}
typedef struct FIFOBuffer
{
unsigned char *begin;
unsigned char *end;
unsigned char * volatile head;
unsigned char * volatile tail;
} FIFOBuffer;
inline bool fifo_isempty(const FIFOBuffer *f) {
return f->head == f->tail;
}
inline bool fifo_isfull(const FIFOBuffer *f) {
return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1);
}
inline void fifo_push(FIFOBuffer *f, unsigned char c) {
*(f->tail) = c;
if (f->tail == f->end) {
f->tail = f->begin;
} else {
f->tail++;
}
}
inline unsigned char fifo_pop(FIFOBuffer *f) {
if(f->head == f->end) {
f->head = f->begin;
return *(f->end);
} else {
return *(f->head++);
}
}
inline void fifo_flush(FIFOBuffer *f) {
f->head = f->tail;
}
#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 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) {
c = fifo_pop(f);
}
return c;
}
*/
inline void fifo_init(FIFOBuffer *f, unsigned char *buffer, size_t size) {
f->head = f->tail = f->begin = buffer;
f->end = buffer + size;
}
inline size_t fifo_len(FIFOBuffer *f) {
return f->end - f->begin;
}
typedef struct FIFOBuffer16
{
uint16_t *begin;
uint16_t *end;
uint16_t * volatile head;
uint16_t * volatile tail;
} FIFOBuffer16;
inline bool fifo16_isempty(const FIFOBuffer16 *f) {
return f->head == f->tail;
}
inline bool fifo16_isfull(const FIFOBuffer16 *f) {
return ((f->head == f->begin) && (f->tail == f->end)) || (f->tail == f->head - 1);
}
inline void fifo16_push(FIFOBuffer16 *f, uint16_t c) {
*(f->tail) = c;
if (f->tail == f->end) {
f->tail = f->begin;
} else {
f->tail++;
}
}
inline uint16_t fifo16_pop(FIFOBuffer16 *f) {
if(f->head == f->end) {
f->head = f->begin;
return *(f->end);
} else {
return *(f->head++);
}
}
inline void fifo16_flush(FIFOBuffer16 *f) {
f->head = f->tail;
}
#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) {
result = fifo16_isfull(f);
}
return result;
}
static inline void fifo16_push_locked(FIFOBuffer16 *f, uint16_t c) {
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
fifo16_push(f, c);
}
}
static inline size_t fifo16_pop_locked(FIFOBuffer16 *f) {
size_t c;
ATOMIC_BLOCK(ATOMIC_RESTORESTATE) {
c = fifo16_pop(f);
}
return c;
}
*/
inline void fifo16_init(FIFOBuffer16 *f, uint16_t *buffer, uint16_t size) {
f->head = f->tail = f->begin = buffer;
f->end = buffer + size;
}
inline uint16_t fifo16_len(FIFOBuffer16 *f) {
return (f->end - f->begin);
}