1530 lines
42 KiB
C++
1530 lines
42 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 "Radio.hpp"
|
|
#include "Config.h"
|
|
|
|
// Included for sorting
|
|
#include <algorithm>
|
|
#include <iterator>
|
|
|
|
#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>
|
|
|
|
#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"
|
|
#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_T3S3
|
|
#include "hal/wdt_hal.h"
|
|
#else BOARD_MODEL != BOARD_T3S3
|
|
#include "soc/rtc_wdt.h"
|
|
#endif
|
|
#define ISR_VECT IRAM_ATTR
|
|
#else
|
|
#define ISR_VECT
|
|
#endif
|
|
|
|
uint8_t boot_vector = 0x00;
|
|
|
|
#if 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;
|
|
bool pixels_started = false;
|
|
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*NP_M, npg*NP_M, npb*NP_M));
|
|
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_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_T3S3
|
|
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_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_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_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_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_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
|
|
|
|
|
|
bool interface_bitrate_cmp(RadioInterface* p, RadioInterface* q) {
|
|
long p_bitrate = p->getBitrate();
|
|
long q_bitrate = q->getBitrate();
|
|
return p_bitrate > q_bitrate;
|
|
}
|
|
|
|
// Sort interfaces in descending order according to bitrate.
|
|
void sort_interfaces() {
|
|
std::sort(std::begin(interface_obj_sorted), std::end(interface_obj_sorted), interface_bitrate_cmp);
|
|
}
|
|
|
|
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);
|
|
|
|
// This ensures that the TX buffer is flushed after a frame is queued in serial.
|
|
// serial_in_frame is used to ensure that the flush only happens at the end of the frame
|
|
if (serial_in_frame && byte == FEND) {
|
|
SerialBT.flushTXD();
|
|
serial_in_frame = false;
|
|
}
|
|
else if (!serial_in_frame && byte == FEND) {
|
|
serial_in_frame = true;
|
|
}
|
|
}
|
|
#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(RadioInterface* radio) {
|
|
serial_write(FEND);
|
|
serial_write(CMD_RADIO_STATE);
|
|
serial_write(radio->getRadioOnline());
|
|
serial_write(FEND);
|
|
}
|
|
|
|
void kiss_indicate_stat_rx() {
|
|
// todo, implement
|
|
//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() {
|
|
// todo, implement
|
|
//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(RadioInterface* radio) {
|
|
serial_write(FEND);
|
|
serial_write(CMD_RADIO_LOCK);
|
|
serial_write(radio->getRadioLock());
|
|
serial_write(FEND);
|
|
}
|
|
|
|
void kiss_indicate_spreadingfactor(RadioInterface* radio) {
|
|
serial_write(FEND);
|
|
serial_write(CMD_SF);
|
|
serial_write(radio->getSpreadingFactor());
|
|
serial_write(FEND);
|
|
}
|
|
|
|
void kiss_indicate_codingrate(RadioInterface* radio) {
|
|
serial_write(FEND);
|
|
serial_write(CMD_CR);
|
|
serial_write(radio->getCodingRate4());
|
|
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(RadioInterface* radio) {
|
|
int8_t txp = radio->getTxPower();
|
|
serial_write(FEND);
|
|
serial_write(CMD_TXPOWER);
|
|
serial_write(txp);
|
|
serial_write(FEND);
|
|
}
|
|
|
|
void kiss_indicate_bandwidth(RadioInterface* radio) {
|
|
uint32_t bw = radio->getSignalBandwidth();
|
|
serial_write(FEND);
|
|
serial_write(CMD_BANDWIDTH);
|
|
escaped_serial_write(bw>>24);
|
|
escaped_serial_write(bw>>16);
|
|
escaped_serial_write(bw>>8);
|
|
escaped_serial_write(bw);
|
|
serial_write(FEND);
|
|
}
|
|
|
|
void kiss_indicate_frequency(RadioInterface* radio) {
|
|
uint32_t freq = radio->getFrequency();
|
|
serial_write(FEND);
|
|
serial_write(CMD_FREQUENCY);
|
|
escaped_serial_write(freq>>24);
|
|
escaped_serial_write(freq>>16);
|
|
escaped_serial_write(freq>>8);
|
|
escaped_serial_write(freq);
|
|
serial_write(FEND);
|
|
}
|
|
|
|
void kiss_indicate_interface(int index) {
|
|
serial_write(FEND);
|
|
serial_write(CMD_INTERFACES);
|
|
// print the index to the interface and the interface type
|
|
serial_write(index);
|
|
serial_write(interfaces[index]);
|
|
serial_write(FEND);
|
|
}
|
|
|
|
void kiss_indicate_st_alock(RadioInterface* radio) {
|
|
uint16_t at = (uint16_t)(radio->getSTALock()*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(RadioInterface* radio) {
|
|
uint16_t at = (uint16_t)(radio->getLTALock()*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(RadioInterface* radio) {
|
|
uint16_t ats = (uint16_t)(radio->getAirtime()*100*100);
|
|
uint16_t atl = (uint16_t)(radio->getLongtermAirtime()*100*100);
|
|
uint16_t cls = (uint16_t)(radio->getTotalChannelUtil()*100*100);
|
|
uint16_t cll = (uint16_t)(radio->getLongtermChannelUtil()*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);
|
|
}
|
|
|
|
void kiss_indicate_phy_stats(RadioInterface* radio) {
|
|
uint16_t lst = (uint16_t)(radio->getSymbolTime()*1000);
|
|
uint16_t lsr = (uint16_t)(radio->getSymbolRate());
|
|
uint16_t prs = (uint16_t)(radio->getPreambleLength()+4);
|
|
uint16_t prt = (uint16_t)((radio->getPreambleLength()+4)*radio->getSymbolTime());
|
|
uint16_t cst = (uint16_t)(radio->getCSMASlotMS());
|
|
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);
|
|
}
|
|
|
|
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 set_implicit_length(uint8_t len) {
|
|
implicit_l = len;
|
|
if (implicit_l != 0) {
|
|
implicit = true;
|
|
} else {
|
|
implicit = false;
|
|
}
|
|
}
|
|
|
|
void setTXPower(RadioInterface* radio, int txp) {
|
|
// Todo, revamp this function. The current parameters for setTxPower are
|
|
// suboptimal, as some chips have power amplifiers which means that the max
|
|
// dBm is not always the same.
|
|
if (model == MODEL_11) {
|
|
if (interfaces[radio->getIndex()] == SX128X) {
|
|
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
} else {
|
|
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
|
}
|
|
}
|
|
if (model == MODEL_12) {
|
|
if (interfaces[radio->getIndex()] == SX128X) {
|
|
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
} else {
|
|
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
|
}
|
|
}
|
|
|
|
if (model == MODEL_21) {
|
|
if (interfaces[radio->getIndex()] == SX128X) {
|
|
radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
} else {
|
|
radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
|
}
|
|
}
|
|
|
|
if (model == MODEL_A1) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_A2) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_A3) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
|
if (model == MODEL_A4) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
|
if (model == MODEL_A5) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
|
if (model == MODEL_A6) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_A7) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_A8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_A9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
|
|
if (model == MODEL_B3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_B4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_B8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_B9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
|
|
if (model == MODEL_C4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_C9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
|
|
if (model == MODEL_E4) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_E9) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_E3) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_E8) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
|
|
if (model == MODEL_FE) radio->setTxPower(txp, PA_OUTPUT_PA_BOOST_PIN);
|
|
if (model == MODEL_FF) radio->setTxPower(txp, PA_OUTPUT_RFO_PIN);
|
|
}
|
|
|
|
uint8_t getRandom(RadioInterface* radio) {
|
|
if (radio->getRadioOnline()) {
|
|
return radio->random();
|
|
} else {
|
|
return 0x00;
|
|
}
|
|
}
|
|
|
|
uint8_t getInterfaceIndex(uint8_t byte) {
|
|
switch (byte) {
|
|
case CMD_INT0_DATA:
|
|
case CMD_SEL_INT0:
|
|
return 0;
|
|
case CMD_INT1_DATA:
|
|
case CMD_SEL_INT1:
|
|
return 1;
|
|
case CMD_INT2_DATA:
|
|
case CMD_SEL_INT2:
|
|
return 2;
|
|
case CMD_INT3_DATA:
|
|
case CMD_SEL_INT3:
|
|
return 3;
|
|
case CMD_INT4_DATA:
|
|
case CMD_SEL_INT4:
|
|
return 4;
|
|
case CMD_INT5_DATA:
|
|
case CMD_SEL_INT5:
|
|
return 5;
|
|
case CMD_INT6_DATA:
|
|
case CMD_SEL_INT6:
|
|
return 6;
|
|
case CMD_INT7_DATA:
|
|
case CMD_SEL_INT7:
|
|
return 7;
|
|
case CMD_INT8_DATA:
|
|
case CMD_SEL_INT8:
|
|
return 8;
|
|
case CMD_INT9_DATA:
|
|
case CMD_SEL_INT9:
|
|
return 9;
|
|
case CMD_INT10_DATA:
|
|
case CMD_SEL_INT10:
|
|
return 10;
|
|
case CMD_INT11_DATA:
|
|
case CMD_SEL_INT11:
|
|
return 11;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint8_t getInterfaceCommandByte(uint8_t index) {
|
|
switch (index) {
|
|
case 0:
|
|
return CMD_INT0_DATA;
|
|
case 1:
|
|
return CMD_INT1_DATA;
|
|
case 2:
|
|
return CMD_INT2_DATA;
|
|
case 3:
|
|
return CMD_INT3_DATA;
|
|
case 4:
|
|
return CMD_INT4_DATA;
|
|
case 5:
|
|
return CMD_INT5_DATA;
|
|
case 6:
|
|
return CMD_INT6_DATA;
|
|
case 7:
|
|
return CMD_INT7_DATA;
|
|
case 8:
|
|
return CMD_INT8_DATA;
|
|
case 9:
|
|
return CMD_INT9_DATA;
|
|
case 10:
|
|
return CMD_INT10_DATA;
|
|
case 11:
|
|
return CMD_INT11_DATA;
|
|
default:
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
uint16_t getQueueSize(uint8_t index) {
|
|
switch (index) {
|
|
case 0:
|
|
return CONFIG_QUEUE_0_SIZE;
|
|
#if INTERFACE_COUNT > 1
|
|
case 1:
|
|
return CONFIG_QUEUE_1_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 2
|
|
case 2:
|
|
return CONFIG_QUEUE_2_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 3
|
|
case 3:
|
|
return CONFIG_QUEUE_3_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 4
|
|
case 4:
|
|
return CONFIG_QUEUE_4_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 5
|
|
case 5:
|
|
return CONFIG_QUEUE_5_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 6
|
|
case 6:
|
|
return CONFIG_QUEUE_6_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 7
|
|
case 7:
|
|
return CONFIG_QUEUE_7_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 8
|
|
case 8:
|
|
return CONFIG_QUEUE_8_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 9
|
|
case 9:
|
|
return CONFIG_QUEUE_9_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 10
|
|
case 10:
|
|
return CONFIG_QUEUE_10_SIZE;
|
|
#endif
|
|
#if INTERFACE_COUNT > 11
|
|
case 11:
|
|
return CONFIG_QUEUE_11_SIZE;
|
|
#endif
|
|
}
|
|
}
|
|
|
|
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_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) || (mapped_addr - eeprom_addr(0)) == ADDR_CONF_OK) {
|
|
// have to do a flush because we're only writing 1 byte and it syncs after 4
|
|
eeprom_flush();
|
|
}
|
|
|
|
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_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 || rval == PRODUCT_FREENODE) {
|
|
#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_T3S3
|
|
if (model == MODEL_A1 || model == MODEL_A5 || 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 || model == MODEL_13 || model == MODEL_14 || model == MODEL_21) {
|
|
#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);
|
|
}
|
|
|
|
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(RadioInterface* radio) {
|
|
if (eeprom_have_conf()) {
|
|
if (!(radio->getRadioOnline())) {
|
|
#if HAS_EEPROM
|
|
uint8_t sf = EEPROM.read(eeprom_addr(ADDR_CONF_SF));
|
|
uint8_t cr = EEPROM.read(eeprom_addr(ADDR_CONF_CR));
|
|
uint8_t txp = EEPROM.read(eeprom_addr(ADDR_CONF_TXP));
|
|
uint32_t 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);
|
|
uint32_t 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
|
|
uint8_t sf = eeprom_read(eeprom_addr(ADDR_CONF_SF));
|
|
uint8_t cr = eeprom_read(eeprom_addr(ADDR_CONF_CR));
|
|
uint8_t txp = eeprom_read(eeprom_addr(ADDR_CONF_TXP));
|
|
uint32_t 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);
|
|
uint32_t 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
|
|
radio->setSpreadingFactor(sf);
|
|
radio->setCodingRate4(cr);
|
|
setTXPower(radio, txp);
|
|
radio->setFrequency(freq);
|
|
radio->setSignalBandwidth(bw);
|
|
radio->updateBitrate();
|
|
}
|
|
}
|
|
}
|
|
|
|
void eeprom_conf_save(RadioInterface* radio) {
|
|
if (hw_ready && radio->getRadioOnline()) {
|
|
eeprom_update(eeprom_addr(ADDR_CONF_SF), radio->getSpreadingFactor());
|
|
eeprom_update(eeprom_addr(ADDR_CONF_CR), radio->getCodingRate4());
|
|
eeprom_update(eeprom_addr(ADDR_CONF_TXP), radio->getTxPower());
|
|
|
|
uint32_t bw = radio->getSignalBandwidth();
|
|
|
|
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x00, bw>>24);
|
|
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x01, bw>>16);
|
|
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x02, bw>>8);
|
|
eeprom_update(eeprom_addr(ADDR_CONF_BW)+0x03, bw);
|
|
|
|
uint32_t freq = radio->getFrequency();
|
|
|
|
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x00, freq>>24);
|
|
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x01, freq>>16);
|
|
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x02, freq>>8);
|
|
eeprom_update(eeprom_addr(ADDR_CONF_FREQ)+0x03, 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();
|
|
}
|
|
|
|
#include "src/misc/FIFOBuffer.h"
|