mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-09-26 22:17:58 +00:00
238 lines
7.1 KiB
C++
238 lines
7.1 KiB
C++
#include <Arduino.h>
|
|
#include <target.h>
|
|
#include <helpers/ArduinoHelpers.h>
|
|
#include <helpers/IdentityGeneration.h>
|
|
#include <helpers/IdentityStore.h>
|
|
#include "KissModem.h"
|
|
|
|
#if defined(ESP32_PLATFORM)
|
|
#include <helpers/ESP32TrueRandom.h>
|
|
#endif
|
|
|
|
#if defined(NRF52_PLATFORM)
|
|
#include <InternalFileSystem.h>
|
|
#include <helpers/nrf52/InternalPrimaryFsBoot.h>
|
|
#include <helpers/nrf52/RamFallbackFileSystem.h>
|
|
#elif defined(RP2040_PLATFORM)
|
|
#include <LittleFS.h>
|
|
#elif defined(ESP32)
|
|
#include <SPIFFS.h>
|
|
#else
|
|
#include <InternalFileSystem.h>
|
|
#endif
|
|
|
|
#if defined(KISS_UART_RX) && defined(KISS_UART_TX)
|
|
#include <HardwareSerial.h>
|
|
#endif
|
|
|
|
#define NOISE_FLOOR_CALIB_INTERVAL_MS 2000
|
|
#define AGC_RESET_INTERVAL_MS 30000
|
|
#define USB_TX_TIMEOUT_MS 50
|
|
#define USB_TX_BUFFER_SIZE 1024
|
|
|
|
StdRNG rng;
|
|
mesh::LocalIdentity identity;
|
|
KissModem* modem;
|
|
static uint32_t next_noise_floor_calib_ms = 0;
|
|
static uint32_t next_agc_reset_ms = 0;
|
|
|
|
void halt() {
|
|
while (1) ;
|
|
}
|
|
|
|
void loadOrCreateIdentity() {
|
|
#if defined(NRF52_PLATFORM)
|
|
bool volatile_primary_fs = false;
|
|
mesh::storage::RamFallbackFileSystem* ram_primary_fs = nullptr;
|
|
FILESYSTEM* identity_fs = nullptr;
|
|
const auto primary_fs_boot =
|
|
mesh::storage::beginInternalPrimaryFilesystemSafely(InternalFS);
|
|
if (mesh::storage::internalPrimaryFilesystemReady(primary_fs_boot)) {
|
|
identity_fs = &InternalFS;
|
|
} else {
|
|
ram_primary_fs = mesh::storage::createRamFallbackFileSystem();
|
|
if (ram_primary_fs == nullptr) {
|
|
MESH_DEBUG_PRINTLN("InternalFS and RAM fallback initialization failed; rebooting");
|
|
board.reboot();
|
|
halt();
|
|
}
|
|
identity_fs = &ram_primary_fs->filesystem();
|
|
volatile_primary_fs = true;
|
|
}
|
|
IdentityStore store(*identity_fs, "");
|
|
#elif defined(STM32_PLATFORM)
|
|
InternalFS.begin();
|
|
IdentityStore store(InternalFS, "");
|
|
#elif defined(ESP32)
|
|
SPIFFS.begin(true);
|
|
IdentityStore store(SPIFFS, "/identity");
|
|
#elif defined(RP2040_PLATFORM)
|
|
LittleFS.begin();
|
|
IdentityStore store(LittleFS, "/identity");
|
|
store.begin();
|
|
#else
|
|
#error "Filesystem not defined"
|
|
#endif
|
|
|
|
#if defined(NRF52_PLATFORM)
|
|
IdentityLoadResult identity_load = volatile_primary_fs
|
|
? store.loadResult("_main", identity)
|
|
: mesh::storage::loadIdentityWithPrimaryRecovery(
|
|
InternalFS,
|
|
[&store]() { return store.loadResult("_main", identity); });
|
|
if (identity_load == IdentityLoadResult::Unreadable) {
|
|
ram_primary_fs = mesh::storage::createRamFallbackFileSystem();
|
|
if (ram_primary_fs != nullptr) {
|
|
identity_fs = &ram_primary_fs->filesystem();
|
|
store.useFileSystem(*identity_fs);
|
|
volatile_primary_fs = true;
|
|
identity_load = IdentityLoadResult::Missing;
|
|
}
|
|
}
|
|
#else
|
|
const IdentityLoadResult identity_load = store.loadResult("_main", identity);
|
|
#endif
|
|
const bool needs_identity = identity_load == IdentityLoadResult::Missing
|
|
|| (identity_load == IdentityLoadResult::Loaded
|
|
&& mesh::hasReservedIdentityPrefix(identity));
|
|
bool identity_ready = identity_load != IdentityLoadResult::Unreadable;
|
|
if (needs_identity) {
|
|
identity_ready = mesh::generateUsableLocalIdentity(identity, radio_new_identity);
|
|
if (identity_ready) identity_ready = store.saveWithRetry("_main", identity);
|
|
}
|
|
|
|
#if defined(ESP32_PLATFORM)
|
|
mesh::discardESP32TrueRandom();
|
|
#endif
|
|
if (!identity_ready) {
|
|
MESH_DEBUG_PRINTLN("Identity generation or persistence failed after retries; rebooting");
|
|
board.reboot();
|
|
halt(); // Never let setup continue if a platform's reboot returns.
|
|
}
|
|
#if defined(NRF52_PLATFORM)
|
|
if (volatile_primary_fs) {
|
|
MESH_DEBUG_PRINTLN("Node: %s (volatile RAM storage)",
|
|
mesh::storage::BAD_FILESYSTEM_NODE_NAME);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
void onSetRadio(float freq, float bw, uint8_t sf, uint8_t cr) {
|
|
radio_driver.setParams(freq, bw, sf, cr);
|
|
}
|
|
|
|
void onSetTxPower(uint8_t power) {
|
|
radio_driver.setTxPower(power);
|
|
}
|
|
|
|
float onGetCurrentRssi() {
|
|
return radio_driver.getCurrentRSSI();
|
|
}
|
|
|
|
void onGetStats(uint32_t* rx, uint32_t* tx, uint32_t* errors) {
|
|
*rx = radio_driver.getPacketsRecv();
|
|
*tx = radio_driver.getPacketsSent();
|
|
*errors = radio_driver.getPacketsRecvErrors();
|
|
}
|
|
|
|
void setup() {
|
|
board.begin();
|
|
|
|
int radioinit_attempts = 0;
|
|
while (!radio_init()) {
|
|
++radioinit_attempts;
|
|
MESH_DEBUG_PRINTLN("Radio init failed! (attempt %d)", radioinit_attempts);
|
|
if (radioinit_attempts >= 3) {
|
|
MESH_DEBUG_PRINTLN("Radio init failed 3x - rebooting");
|
|
board.reboot();
|
|
}
|
|
delay(500);
|
|
}
|
|
|
|
radio_driver.begin();
|
|
|
|
rng.begin(radio_driver.getRngSeed());
|
|
loadOrCreateIdentity();
|
|
|
|
sensors.begin();
|
|
|
|
#if defined(KISS_UART_RX) && defined(KISS_UART_TX)
|
|
#if defined(ESP32)
|
|
Serial1.setPins(KISS_UART_RX, KISS_UART_TX);
|
|
Serial1.begin(115200);
|
|
#elif defined(NRF52_PLATFORM)
|
|
((Uart *)&Serial1)->setPins(KISS_UART_RX, KISS_UART_TX);
|
|
Serial1.begin(115200);
|
|
#elif defined(RP2040_PLATFORM)
|
|
((SerialUART *)&Serial1)->setRX(KISS_UART_RX);
|
|
((SerialUART *)&Serial1)->setTX(KISS_UART_TX);
|
|
Serial1.begin(115200);
|
|
#elif defined(STM32_PLATFORM)
|
|
((HardwareSerial *)&Serial1)->setRx(KISS_UART_RX);
|
|
((HardwareSerial *)&Serial1)->setTx(KISS_UART_TX);
|
|
Serial1.begin(115200);
|
|
#else
|
|
#error "KISS UART not supported on this platform"
|
|
#endif
|
|
modem = new KissModem(Serial1, identity, rng, radio_driver, board, sensors);
|
|
#else
|
|
Serial.begin(115200);
|
|
uint32_t start = millis();
|
|
while (!Serial && millis() - start < 3000) delay(10);
|
|
delay(100);
|
|
#if defined(ESP32) && ARDUINO_USB_MODE && ARDUINO_USB_CDC_ON_BOOT
|
|
Serial.setTxTimeoutMs(USB_TX_TIMEOUT_MS);
|
|
Serial.setTxBufferSize(USB_TX_BUFFER_SIZE);
|
|
#endif
|
|
modem = new KissModem(Serial, identity, rng, radio_driver, board, sensors);
|
|
#endif
|
|
|
|
modem->setRadioCallback(onSetRadio);
|
|
modem->setTxPowerCallback(onSetTxPower);
|
|
modem->setGetCurrentRssiCallback(onGetCurrentRssi);
|
|
modem->setGetStatsCallback(onGetStats);
|
|
modem->begin();
|
|
|
|
board.onBootComplete();
|
|
}
|
|
|
|
void loop() {
|
|
#if defined(NRF52_PLATFORM)
|
|
board.feedWatchdog();
|
|
#endif
|
|
modem->loop();
|
|
// GPS acquisition, cache refresh, and delayed shutdown are driven by the
|
|
// sensor manager loop even though KISS itself is normally host powered.
|
|
sensors.loop();
|
|
#ifdef TBEAM_1W
|
|
board.updateFanControl();
|
|
#endif
|
|
|
|
if (!modem->isActuallyTransmitting() && !modem->isHostOutputBackedUp()) {
|
|
if (!modem->isTxBusy()) {
|
|
if ((uint32_t)(millis() - next_agc_reset_ms) >= AGC_RESET_INTERVAL_MS) {
|
|
radio_driver.resetAGC();
|
|
next_agc_reset_ms = millis();
|
|
}
|
|
}
|
|
|
|
uint8_t rx_buf[256];
|
|
int rx_len = radio_driver.recvRaw(rx_buf, sizeof(rx_buf));
|
|
if (rx_len > 0) {
|
|
// Snapshot before the receive-complete hook or fast profile scanner can
|
|
// retune the one physical radio. KISS port 0/1 reports this origin.
|
|
const uint8_t profile = radio_driver.receiveProfile();
|
|
int8_t snr = (int8_t)(radio_driver.getLastSNR() * 4);
|
|
int8_t rssi = (int8_t)radio_driver.getLastRSSI();
|
|
modem->onPacketReceived(snr, rssi, rx_buf, rx_len, profile);
|
|
radio_driver.onReceiveProcessed();
|
|
}
|
|
}
|
|
|
|
if ((uint32_t)(millis() - next_noise_floor_calib_ms) >= NOISE_FLOOR_CALIB_INTERVAL_MS) {
|
|
radio_driver.triggerNoiseFloorCalibrate(0);
|
|
next_noise_floor_calib_ms = millis();
|
|
}
|
|
radio_driver.loop();
|
|
}
|