RNode_Firmware/Utilities.h

1701 lines
45 KiB
C++

// Copyright (C) 2023, Mark Qvist
// 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 <https://www.gnu.org/licenses/>.
#include "Config.h"
#if HAS_EEPROM
#include <EEPROM.h>
#elif PLATFORM == PLATFORM_NRF52
#include <Adafruit_LittleFS.h>
#include <InternalFileSystem.h>
using namespace Adafruit_LittleFS_Namespace;
#define EEPROM_FILE "eeprom"
bool file_exists = false;
int written_bytes = 4;
File file(InternalFS);
#endif
#include <stddef.h>
#if MODEM == SX1262
#include "sx126x.h"
sx126x *LoRa = &sx126x_modem;
#elif MODEM == SX1276 || MODEM == SX1278
#include "sx127x.h"
sx127x *LoRa = &sx127x_modem;
#elif MODEM == SX1280
#include "sx128x.h"
sx128x *LoRa = &sx128x_modem;
#endif
#include "ROM.h"
#include "Framing.h"
#include "MD5.h"
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
uint8_t eeprom_read(uint32_t mapped_addr);
#endif
#if HAS_DISPLAY == true
#include "Display.h"
#else
void display_unblank() {}
#endif
#if HAS_BLUETOOTH == true || HAS_BLE == true
void kiss_indicate_btpin();
#include "Bluetooth.h"
#endif
#if HAS_PMU == true
#include "Power.h"
#endif
#if HAS_INPUT == true
#include "Input.h"
#endif
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
#include "Device.h"
#endif
#if MCU_VARIANT == MCU_ESP32
#if BOARD_MODEL == BOARD_HELTEC32_V3
//https://github.com/espressif/esp-idf/issues/8855
#include "hal/wdt_hal.h"
#elif BOARD_MODEL == BOARD_RNODE_NG_22
#include "hal/wdt_hal.h"
#else
#include "hal/wdt_hal.h"
#endif
#define ISR_VECT IRAM_ATTR
#else
#define ISR_VECT
#endif
#if MCU_VARIANT == MCU_1284P || MCU_VARIANT == MCU_2560
#include <avr/wdt.h>
#include <util/atomic.h>
#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
#elif MCU_VARIANT == MCU_NRF52
// TODO: Get NRF52 boot flags
#endif
#if HAS_NP == true
#include <Adafruit_NeoPixel.h>
#define NUMPIXELS 1
#define NP_M 0.15
Adafruit_NeoPixel pixels(NUMPIXELS, pin_np, NEO_GRB + NEO_KHZ800);
uint8_t npr = 0;
uint8_t npg = 0;
uint8_t npb = 0;
float npi = NP_M;
bool pixels_started = false;
void led_set_intensity(uint8_t intensity) {
npi = (float)intensity/255.0;
}
void led_init() {
if (EEPROM.read(eeprom_addr(ADDR_CONF_PSET)) == CONF_OK_BYTE) {
uint8_t int_val = EEPROM.read(eeprom_addr(ADDR_CONF_PINT));
led_set_intensity(int_val);
}
}
void npset(uint8_t r, uint8_t g, uint8_t b) {
if (pixels_started != true) {
pixels.begin();
pixels_started = true;
}
if (r != npr || g != npg || b != npb) {
npr = r; npg = g; npb = b;
pixels.setPixelColor(0, pixels.Color(npr*npi, npg*npi, npb*npi));
pixels.show();
}
}
void boot_seq() {
uint8_t rs[] = { 0x00, 0x00, 0x00 };
uint8_t gs[] = { 0x10, 0x08, 0x00 };
uint8_t bs[] = { 0x00, 0x08, 0x10 };
for (int i = 0; i < 1*sizeof(rs); i++) {
npset(rs[i%sizeof(rs)], gs[i%sizeof(gs)], bs[i%sizeof(bs)]);
delay(33);
npset(0x00, 0x00, 0x00);
delay(66);
}
}
#else
void boot_seq() { }
#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
#if HAS_NP == true
void led_rx_on() { npset(0, 0, 0xFF); }
void led_rx_off() { npset(0, 0, 0); }
void led_tx_on() { npset(0xFF, 0x50, 0x00); }
void led_tx_off() { npset(0, 0, 0); }
#elif BOARD_MODEL == BOARD_RNODE_NG_20
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 BOARD_MODEL == BOARD_RNODE_NG_21
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 BOARD_MODEL == BOARD_RNODE_NG_22
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 BOARD_MODEL == BOARD_TBEAM
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); }
#elif BOARD_MODEL == BOARD_LORA32_V1_0
#if defined(EXTERNAL_LEDS)
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); }
#else
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); }
#endif
#elif BOARD_MODEL == BOARD_LORA32_V2_0
#if defined(EXTERNAL_LEDS)
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); }
#else
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
#elif BOARD_MODEL == BOARD_HELTEC32_V2
#if defined(EXTERNAL_LEDS)
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); }
#else
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); }
#endif
#elif BOARD_MODEL == BOARD_HELTEC32_V3
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 BOARD_MODEL == BOARD_LORA32_V2_1
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 BOARD_MODEL == BOARD_HUZZAH32
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 BOARD_MODEL == BOARD_GENERIC_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, HIGH); }
void led_tx_off() { digitalWrite(pin_led_tx, LOW); }
#endif
#elif MCU_VARIANT == MCU_NRF52
#if BOARD_MODEL == BOARD_RAK4631
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); }
#endif
#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();
#elif MCU_VARIANT == MCU_NRF52
NVIC_SystemReset();
#endif
}
// LED Indication: Error
void led_indicate_error(int cycles) {
#if HAS_NP == true
bool forever = (cycles == 0) ? true : false;
cycles = forever ? 1 : cycles;
while(cycles > 0) {
npset(0xFF, 0x00, 0x00);
delay(100);
npset(0xFF, 0x50, 0x00);
delay(100);
if (!forever) cycles--;
}
npset(0,0,0);
#else
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();
#endif
}
// LED Indication: Airtime Lock
void led_indicate_airtime_lock() {
#if HAS_NP == true
npset(32,0,2);
#endif
}
// LED Indication: Boot Error
void led_indicate_boot_error() {
#if HAS_NP == true
while(true) {
npset(0xFF, 0xFF, 0xFF);
}
#else
while (true) {
led_tx_on();
led_rx_off();
delay(10);
led_rx_on();
led_tx_off();
delay(5);
}
#endif
}
// LED Indication: Warning
void led_indicate_warning(int cycles) {
#if HAS_NP == true
bool forever = (cycles == 0) ? true : false;
cycles = forever ? 1 : cycles;
while(cycles > 0) {
npset(0xFF, 0x50, 0x00);
delay(100);
npset(0x00, 0x00, 0x00);
delay(100);
if (!forever) cycles--;
}
npset(0,0,0);
#else
bool forever = (cycles == 0) ? true : false;
cycles = forever ? 1 : cycles;
digitalWrite(pin_led_tx, HIGH);
while(cycles > 0) {
led_tx_off();
delay(100);
led_tx_on();
delay(100);
if (!forever) cycles--;
}
led_tx_off();
#endif
}
// LED Indication: Info
#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 || MCU_VARIANT == MCU_NRF52
#if HAS_NP == true
void led_indicate_info(int cycles) {
bool forever = (cycles == 0) ? true : false;
cycles = forever ? 1 : cycles;
while(cycles > 0) {
npset(0x00, 0x00, 0xFF);
delay(100);
npset(0x00, 0x00, 0x00);
delay(100);
if (!forever) cycles--;
}
npset(0,0,0);
}
#elif BOARD_MODEL == BOARD_LORA32_V2_1
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 BOARD_MODEL == BOARD_LORA32_V2_0
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();
}
#else
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
#endif
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
#if HAS_NP == true
int led_standby_lng = 100;
int led_standby_cut = 200;
int led_standby_min = 0;
int led_standby_max = 375+led_standby_lng;
int led_notready_min = 0;
int led_notready_max = led_standby_max;
int led_notready_value = led_notready_min;
int8_t led_notready_direction = 0;
unsigned long led_notready_ticks = 0;
unsigned long led_standby_wait = 350;
unsigned long led_console_wait = 1;
unsigned long led_notready_wait = 200;
#else
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
#elif MCU_VARIANT == MCU_NRF52
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
unsigned long 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 || MCU_VARIANT == MCU_NRF52
#if HAS_NP == true
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;
}
uint8_t led_standby_intensity;
led_standby_value += led_standby_direction;
int led_standby_ti = led_standby_value - led_standby_lng;
if (led_standby_ti < 0) {
led_standby_intensity = 0;
} else if (led_standby_ti > led_standby_cut) {
led_standby_intensity = led_standby_cut;
} else {
led_standby_intensity = led_standby_ti;
}
npset(0x00, 0x00, led_standby_intensity);
}
}
void led_indicate_console() {
npset(0x60, 0x00, 0x60);
// led_standby_ticks++;
// if (led_standby_ticks > led_console_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;
// }
// uint8_t led_standby_intensity;
// led_standby_value += led_standby_direction;
// int led_standby_ti = led_standby_value - led_standby_lng;
// if (led_standby_ti < 0) {
// led_standby_intensity = 0;
// } else if (led_standby_ti > led_standby_cut) {
// led_standby_intensity = led_standby_cut;
// } else {
// led_standby_intensity = led_standby_ti;
// }
// npset(led_standby_intensity, 0x00, led_standby_intensity);
// }
}
#else
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();
}
#if BOARD_MODEL == BOARD_LORA32_V2_1
#if defined(EXTERNAL_LEDS)
led_rx_off();
#endif
#elif BOARD_MODEL == BOARD_LORA32_V2_0
#if defined(EXTERNAL_LEDS)
led_rx_off();
#endif
#else
led_rx_off();
#endif
}
}
void led_indicate_console() {
led_indicate_standby();
}
#endif
#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 || MCU_VARIANT == MCU_NRF52
#if HAS_NP == true
void led_indicate_not_ready() {
led_standby_ticks++;
if (led_standby_ticks > led_notready_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;
}
uint8_t led_standby_intensity;
led_standby_value += led_standby_direction;
int led_standby_ti = led_standby_value - led_standby_lng;
if (led_standby_ti < 0) {
led_standby_intensity = 0;
} else if (led_standby_ti > led_standby_cut) {
led_standby_intensity = led_standby_cut;
} else {
led_standby_intensity = led_standby_ti;
}
npset(led_standby_intensity, 0x00, 0x00);
}
}
#else
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();
}
#if BOARD_MODEL == BOARD_LORA32_V2_1
#if defined(EXTERNAL_LEDS)
led_rx_off();
#endif
#elif BOARD_MODEL == BOARD_LORA32_V2_0
#if defined(EXTERNAL_LEDS)
led_rx_off();
#endif
#else
led_rx_off();
#endif
}
}
#endif
#endif
void serial_write(uint8_t byte) {
#if HAS_BLUETOOTH || HAS_BLE == true
if (bt_state != BT_STATE_CONNECTED) {
Serial.write(byte);
} else {
SerialBT.write(byte);
}
#else
Serial.write(byte);
#endif
}
void escaped_serial_write(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);
}
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);
escaped_serial_write(stat_rx>>24);
escaped_serial_write(stat_rx>>16);
escaped_serial_write(stat_rx>>8);
escaped_serial_write(stat_rx);
serial_write(FEND);
}
void kiss_indicate_stat_tx() {
serial_write(FEND);
serial_write(CMD_STAT_TX);
escaped_serial_write(stat_tx>>24);
escaped_serial_write(stat_tx>>16);
escaped_serial_write(stat_tx>>8);
escaped_serial_write(stat_tx);
serial_write(FEND);
}
void kiss_indicate_stat_rssi() {
uint8_t packet_rssi_val = (uint8_t)(last_rssi+rssi_offset);
serial_write(FEND);
serial_write(CMD_STAT_RSSI);
escaped_serial_write(packet_rssi_val);
serial_write(FEND);
}
void kiss_indicate_stat_snr() {
serial_write(FEND);
serial_write(CMD_STAT_SNR);
escaped_serial_write(last_snr_raw);
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);
}
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);
escaped_serial_write(lora_bw>>24);
escaped_serial_write(lora_bw>>16);
escaped_serial_write(lora_bw>>8);
escaped_serial_write(lora_bw);
serial_write(FEND);
}
void kiss_indicate_frequency() {
serial_write(FEND);
serial_write(CMD_FREQUENCY);
escaped_serial_write(lora_freq>>24);
escaped_serial_write(lora_freq>>16);
escaped_serial_write(lora_freq>>8);
escaped_serial_write(lora_freq);
serial_write(FEND);
}
void kiss_indicate_st_alock() {
uint16_t at = (uint16_t)(st_airtime_limit*100*100);
serial_write(FEND);
serial_write(CMD_ST_ALOCK);
escaped_serial_write(at>>8);
escaped_serial_write(at);
serial_write(FEND);
}
void kiss_indicate_lt_alock() {
uint16_t at = (uint16_t)(lt_airtime_limit*100*100);
serial_write(FEND);
serial_write(CMD_LT_ALOCK);
escaped_serial_write(at>>8);
escaped_serial_write(at);
serial_write(FEND);
}
void kiss_indicate_channel_stats() {
#if MCU_VARIANT == MCU_ESP32
uint16_t ats = (uint16_t)(airtime*100*100);
uint16_t atl = (uint16_t)(longterm_airtime*100*100);
uint16_t cls = (uint16_t)(total_channel_util*100*100);
uint16_t cll = (uint16_t)(longterm_channel_util*100*100);
serial_write(FEND);
serial_write(CMD_STAT_CHTM);
escaped_serial_write(ats>>8);
escaped_serial_write(ats);
escaped_serial_write(atl>>8);
escaped_serial_write(atl);
escaped_serial_write(cls>>8);
escaped_serial_write(cls);
escaped_serial_write(cll>>8);
escaped_serial_write(cll);
serial_write(FEND);
#endif
}
void kiss_indicate_phy_stats() {
#if MCU_VARIANT == MCU_ESP32
uint16_t lst = (uint16_t)(lora_symbol_time_ms*1000);
uint16_t lsr = (uint16_t)(lora_symbol_rate);
uint16_t prs = (uint16_t)(lora_preamble_symbols+4);
uint16_t prt = (uint16_t)((lora_preamble_symbols+4)*lora_symbol_time_ms);
uint16_t cst = (uint16_t)(csma_slot_ms);
serial_write(FEND);
serial_write(CMD_STAT_PHYPRM);
escaped_serial_write(lst>>8);
escaped_serial_write(lst);
escaped_serial_write(lsr>>8);
escaped_serial_write(lsr);
escaped_serial_write(prs>>8);
escaped_serial_write(prs);
escaped_serial_write(prt>>8);
escaped_serial_write(prt);
escaped_serial_write(cst>>8);
escaped_serial_write(cst);
serial_write(FEND);
#endif
}
void kiss_indicate_battery() {
#if MCU_VARIANT == MCU_ESP32
serial_write(FEND);
serial_write(CMD_STAT_BAT);
escaped_serial_write(battery_state);
escaped_serial_write((uint8_t)int(battery_percent));
serial_write(FEND);
#endif
}
void kiss_indicate_btpin() {
#if HAS_BLUETOOTH || HAS_BLE == true
serial_write(FEND);
serial_write(CMD_BT_PIN);
escaped_serial_write(bt_ssp_pin>>24);
escaped_serial_write(bt_ssp_pin>>16);
escaped_serial_write(bt_ssp_pin>>8);
escaped_serial_write(bt_ssp_pin);
serial_write(FEND);
#endif
}
void kiss_indicate_random(uint8_t byte) {
serial_write(FEND);
serial_write(CMD_RANDOM);
serial_write(byte);
serial_write(FEND);
}
void kiss_indicate_fbstate() {
serial_write(FEND);
serial_write(CMD_FB_EXT);
#if HAS_DISPLAY
if (disp_ext_fb) {
serial_write(0x01);
} else {
serial_write(0x00);
}
#else
serial_write(0xFF);
#endif
serial_write(FEND);
}
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
void kiss_indicate_device_hash() {
serial_write(FEND);
serial_write(CMD_DEV_HASH);
for (int i = 0; i < DEV_HASH_LEN; i++) {
uint8_t byte = dev_hash[i];
escaped_serial_write(byte);
}
serial_write(FEND);
}
void kiss_indicate_target_fw_hash() {
serial_write(FEND);
serial_write(CMD_HASHES);
serial_write(0x01);
for (int i = 0; i < DEV_HASH_LEN; i++) {
uint8_t byte = dev_firmware_hash_target[i];
escaped_serial_write(byte);
}
serial_write(FEND);
}
void kiss_indicate_fw_hash() {
serial_write(FEND);
serial_write(CMD_HASHES);
serial_write(0x02);
for (int i = 0; i < DEV_HASH_LEN; i++) {
uint8_t byte = dev_firmware_hash[i];
escaped_serial_write(byte);
}
serial_write(FEND);
}
void kiss_indicate_bootloader_hash() {
serial_write(FEND);
serial_write(CMD_HASHES);
serial_write(0x03);
for (int i = 0; i < DEV_HASH_LEN; i++) {
uint8_t byte = dev_bootloader_hash[i];
escaped_serial_write(byte);
}
serial_write(FEND);
}
void kiss_indicate_partition_table_hash() {
serial_write(FEND);
serial_write(CMD_HASHES);
serial_write(0x04);
for (int i = 0; i < DEV_HASH_LEN; i++) {
uint8_t byte = dev_partition_table_hash[i];
escaped_serial_write(byte);
}
serial_write(FEND);
}
#endif
void kiss_indicate_fb() {
serial_write(FEND);
serial_write(CMD_FB_READ);
#if HAS_DISPLAY
for (int i = 0; i < 512; i++) {
uint8_t byte = fb[i];
escaped_serial_write(byte);
}
#else
serial_write(0xFF);
#endif
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_board() {
serial_write(FEND);
serial_write(CMD_BOARD);
serial_write(BOARD_MODEL);
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) {
return (header & FLAG_SPLIT);
}
inline uint8_t packetSequence(uint8_t header) {
return header >> 4;
}
void setPreamble() {
if (radio_online) LoRa->setPreambleLength(lora_preamble_symbols);
kiss_indicate_phy_stats();
}
void updateBitrate() {
#if MCU_VARIANT == MCU_ESP32 || MCU_VARIANT == MCU_NRF52
if (radio_online) {
lora_symbol_rate = (float)lora_bw/(float)(pow(2, lora_sf));
lora_symbol_time_ms = (1.0/lora_symbol_rate)*1000.0;
lora_bitrate = (uint32_t)(lora_sf * ( (4.0/(float)lora_cr) / ((float)(pow(2, lora_sf))/((float)lora_bw/1000.0)) ) * 1000.0);
lora_us_per_byte = 1000000.0/((float)lora_bitrate/8.0);
// csma_slot_ms = lora_symbol_time_ms*10;
float target_preamble_symbols = (LORA_PREAMBLE_TARGET_MS/lora_symbol_time_ms)-LORA_PREAMBLE_SYMBOLS_HW;
if (target_preamble_symbols < LORA_PREAMBLE_SYMBOLS_MIN) {
target_preamble_symbols = LORA_PREAMBLE_SYMBOLS_MIN;
} else {
target_preamble_symbols = ceil(target_preamble_symbols);
}
lora_preamble_symbols = (long)target_preamble_symbols;
setPreamble();
} else {
lora_bitrate = 0;
}
#endif
}
void setSpreadingFactor() {
if (radio_online) LoRa->setSpreadingFactor(lora_sf);
updateBitrate();
}
void setCodingRate() {
if (radio_online) LoRa->setCodingRate4(lora_cr);
updateBitrate();
}
void set_implicit_length(uint8_t len) {
implicit_l = len;
if (implicit_l != 0) {
implicit = true;
} else {
implicit = false;
}
}
int getTxPower() {
uint8_t txp = LoRa->getTxPower();
return (int)txp;
}
void setTXPower() {
if (radio_online) {
if (model == MODEL_11) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_12) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A1) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A2) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A3) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A4) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
if (model == MODEL_A6) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A7) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_A9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_B9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_C9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E4) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E9) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E3) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_E8) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FE) LoRa->setTxPower(lora_txp, PA_OUTPUT_PA_BOOST_PIN);
if (model == MODEL_FF) LoRa->setTxPower(lora_txp, PA_OUTPUT_RFO_PIN);
}
}
void getBandwidth() {
if (radio_online) {
lora_bw = LoRa->getSignalBandwidth();
}
updateBitrate();
}
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;
}
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
bool eeprom_begin() {
InternalFS.begin();
file.open(EEPROM_FILE, FILE_O_READ);
// if file doesn't exist
if (!file) {
if (file.open(EEPROM_FILE, FILE_O_WRITE)) {
// initialise the file with empty content
uint8_t empty_content[EEPROM_SIZE] = {0};
file.write(empty_content, EEPROM_SIZE);
return true;
} else {
return false;
}
} else {
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
return true;
}
}
uint8_t eeprom_read(uint32_t mapped_addr) {
uint8_t byte;
void* byte_ptr = &byte;
file.seek(mapped_addr);
file.read(byte_ptr, 1);
return byte;
}
#endif
bool eeprom_info_locked() {
#if HAS_EEPROM
uint8_t lock_byte = EEPROM.read(eeprom_addr(ADDR_INFO_LOCK));
#elif MCU_VARIANT == MCU_NRF52
uint8_t lock_byte = eeprom_read(eeprom_addr(ADDR_INFO_LOCK));
#endif
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++) {
#if HAS_EEPROM
uint8_t byte = EEPROM.read(eeprom_addr(addr));
#elif MCU_VARIANT == MCU_NRF52
uint8_t byte = eeprom_read(eeprom_addr(addr));
#endif
escaped_serial_write(byte);
}
}
void eeprom_dump_config() {
for (int addr = ADDR_CONF_SF; addr <= ADDR_CONF_OK; addr++) {
#if HAS_EEPROM
uint8_t byte = EEPROM.read(eeprom_addr(addr));
#elif MCU_VARIANT == MCU_NRF52
uint8_t byte = eeprom_read(eeprom_addr(addr));
#endif
escaped_serial_write(byte);
}
}
void eeprom_dump_all() {
for (int addr = 0; addr < EEPROM_RESERVED; addr++) {
#if HAS_EEPROM
uint8_t byte = EEPROM.read(eeprom_addr(addr));
#elif MCU_VARIANT == MCU_NRF52
uint8_t byte = eeprom_read(eeprom_addr(addr));
#endif
escaped_serial_write(byte);
}
}
void kiss_dump_eeprom() {
serial_write(FEND);
serial_write(CMD_ROM_READ);
eeprom_dump_all();
serial_write(FEND);
}
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
void eeprom_flush() {
// sync file contents to flash
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
written_bytes = 0;
}
#endif
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();
}
#elif !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
// todo: clean up this implementation, writing one byte and syncing
// each time is really slow, but this is also suboptimal
uint8_t read_byte;
void* read_byte_ptr = &read_byte;
file.seek(mapped_addr);
file.read(read_byte_ptr, 1);
file.seek(mapped_addr);
if (read_byte != byte) {
file.write(byte);
}
written_bytes++;
if ((mapped_addr - eeprom_addr(0)) == ADDR_INFO_LOCK) {
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
// have to do a flush because we're only writing 1 byte and it syncs after 4
eeprom_flush();
#endif
}
if (written_bytes >= 4) {
file.close();
file.open(EEPROM_FILE, FILE_O_WRITE);
written_bytes = 0;
}
#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 HAS_EEPROM
if (EEPROM.read(eeprom_addr(ADDR_INFO_LOCK)) == INFO_LOCK_BYTE) {
#elif MCU_VARIANT == MCU_NRF52
if (eeprom_read(eeprom_addr(ADDR_INFO_LOCK)) == INFO_LOCK_BYTE) {
#endif
return true;
} else {
return false;
}
}
bool eeprom_product_valid() {
#if HAS_EEPROM
uint8_t rval = EEPROM.read(eeprom_addr(ADDR_PRODUCT));
#elif MCU_VARIANT == MCU_NRF52
uint8_t rval = eeprom_read(eeprom_addr(ADDR_PRODUCT));
#endif
#if PLATFORM == PLATFORM_AVR
if (rval == PRODUCT_RNODE || rval == PRODUCT_HMBRW) {
#elif PLATFORM == PLATFORM_ESP32
if (rval == PRODUCT_RNODE || rval == BOARD_RNODE_NG_20 || rval == BOARD_RNODE_NG_21 || rval == PRODUCT_HMBRW || rval == PRODUCT_TBEAM || rval == PRODUCT_T32_10 || rval == PRODUCT_T32_20 || rval == PRODUCT_T32_21 || rval == PRODUCT_H32_V2 || rval == PRODUCT_H32_V3) {
#elif PLATFORM == PLATFORM_NRF52
if (rval == PRODUCT_RAK4631 || rval == PRODUCT_HMBRW) {
#else
if (false) {
#endif
return true;
} else {
return false;
}
}
bool eeprom_model_valid() {
#if HAS_EEPROM
model = EEPROM.read(eeprom_addr(ADDR_MODEL));
#elif MCU_VARIANT == MCU_NRF52
model = eeprom_read(eeprom_addr(ADDR_MODEL));
#endif
#if BOARD_MODEL == BOARD_RNODE
if (model == MODEL_A4 || model == MODEL_A9 || model == MODEL_FF || model == MODEL_FE) {
#elif BOARD_MODEL == BOARD_RNODE_NG_20
if (model == MODEL_A3 || model == MODEL_A8) {
#elif BOARD_MODEL == BOARD_RNODE_NG_21
if (model == MODEL_A2 || model == MODEL_A7) {
#elif BOARD_MODEL == BOARD_RNODE_NG_22
if (model == MODEL_A1 || model == MODEL_A6) {
#elif BOARD_MODEL == BOARD_HMBRW
if (model == MODEL_FF || model == MODEL_FE) {
#elif BOARD_MODEL == BOARD_TBEAM
if (model == MODEL_E4 || model == MODEL_E9 || model == MODEL_E3 || model == MODEL_E8) {
#elif BOARD_MODEL == BOARD_LORA32_V1_0
if (model == MODEL_BA || model == MODEL_BB) {
#elif BOARD_MODEL == BOARD_LORA32_V2_0
if (model == MODEL_B3 || model == MODEL_B8) {
#elif BOARD_MODEL == BOARD_LORA32_V2_1
if (model == MODEL_B4 || model == MODEL_B9) {
#elif BOARD_MODEL == BOARD_HELTEC32_V2
if (model == MODEL_C4 || model == MODEL_C9) {
#elif BOARD_MODEL == BOARD_HELTEC32_V3
if (model == MODEL_C5 || model == MODEL_CA) {
#elif BOARD_MODEL == BOARD_RAK4631
if (model == MODEL_11 || model == MODEL_12) {
#elif BOARD_MODEL == BOARD_HUZZAH32
if (model == MODEL_FF) {
#elif BOARD_MODEL == BOARD_GENERIC_ESP32
if (model == MODEL_FF || model == MODEL_FE) {
#else
if (false) {
#endif
return true;
} else {
return false;
}
}
bool eeprom_hwrev_valid() {
#if HAS_EEPROM
hwrev = EEPROM.read(eeprom_addr(ADDR_HW_REV));
#elif MCU_VARIANT == MCU_NRF52
hwrev = eeprom_read(eeprom_addr(ADDR_HW_REV));
#endif
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++) {
#if HAS_EEPROM
char byte = EEPROM.read(eeprom_addr(i));
#elif MCU_VARIANT == MCU_NRF52
char byte = eeprom_read(eeprom_addr(i));
#endif
data[i] = byte;
}
unsigned char *hash = MD5::make_hash(data, CHECKSUMMED_SIZE);
bool checksum_valid = true;
for (uint8_t i = 0; i < 16; i++) {
#if HAS_EEPROM
uint8_t stored_chk_byte = EEPROM.read(eeprom_addr(ADDR_CHKSUM+i));
#elif MCU_VARIANT == MCU_NRF52
uint8_t stored_chk_byte = eeprom_read(eeprom_addr(ADDR_CHKSUM+i));
#endif
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 bt_conf_save(bool is_enabled) {
if (is_enabled) {
eeprom_update(eeprom_addr(ADDR_CONF_BT), BT_ENABLE_BYTE);
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
// have to do a flush because we're only writing 1 byte and it syncs after 8
eeprom_flush();
#endif
} else {
eeprom_update(eeprom_addr(ADDR_CONF_BT), 0x00);
#if !HAS_EEPROM && MCU_VARIANT == MCU_NRF52
// have to do a flush because we're only writing 1 byte and it syncs after 8
eeprom_flush();
#endif
}
}
void di_conf_save(uint8_t dint) {
eeprom_update(eeprom_addr(ADDR_CONF_DINT), dint);
}
void da_conf_save(uint8_t dadr) {
eeprom_update(eeprom_addr(ADDR_CONF_DADR), dadr);
}
void db_conf_save(uint8_t val) {
#if HAS_DISPLAY
if (val == 0x00) {
display_blanking_enabled = false;
} else {
display_blanking_enabled = true;
display_blanking_timeout = val*1000;
}
eeprom_update(eeprom_addr(ADDR_CONF_BSET), CONF_OK_BYTE);
eeprom_update(eeprom_addr(ADDR_CONF_DBLK), val);
#endif
}
void np_int_conf_save(uint8_t p_int) {
eeprom_update(eeprom_addr(ADDR_CONF_PSET), CONF_OK_BYTE);
eeprom_update(eeprom_addr(ADDR_CONF_PINT), p_int);
}
bool eeprom_have_conf() {
#if HAS_EEPROM
if (EEPROM.read(eeprom_addr(ADDR_CONF_OK)) == CONF_OK_BYTE) {
#elif MCU_VARIANT == MCU_NRF52
if (eeprom_read(eeprom_addr(ADDR_CONF_OK)) == CONF_OK_BYTE) {
#endif
return true;
} else {
return false;
}
}
void eeprom_conf_load() {
if (eeprom_have_conf()) {
#if HAS_EEPROM
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);
#elif MCU_VARIANT == MCU_NRF52
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);
#endif
}
}
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();
}
void init_channel_stats() {
#if MCU_VARIANT == MCU_ESP32
for (uint16_t ai = 0; ai < DCD_SAMPLES; ai++) { util_samples[ai] = false; }
for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { airtime_bins[ai] = 0; }
for (uint16_t ai = 0; ai < AIRTIME_BINS; ai++) { longterm_bins[ai] = 0.0; }
local_channel_util = 0.0;
total_channel_util = 0.0;
airtime = 0.0;
longterm_airtime = 0.0;
#endif
}
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 && MCU_VARIANT != MCU_NRF52
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 && MCU_VARIANT != MCU_NRF52
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);
}