From 4575800e4069004cf8fb024517b2b33387bd2e5a Mon Sep 17 00:00:00 2001 From: Socalix <48040807+Socalix@users.noreply.github.com> Date: Wed, 14 Jan 2026 17:52:15 -0600 Subject: [PATCH 01/35] Turn on register 0x8B5 LSB for improved RX, turn off boosted gain --- src/helpers/radiolib/CustomSX1262.h | 8 ++++++++ variants/heltec_v4/platformio.ini | 11 ++++++----- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/helpers/radiolib/CustomSX1262.h b/src/helpers/radiolib/CustomSX1262.h index bfaea7c76..be6812c6f 100644 --- a/src/helpers/radiolib/CustomSX1262.h +++ b/src/helpers/radiolib/CustomSX1262.h @@ -76,6 +76,14 @@ class CustomSX1262 : public SX1262 { setRfSwitchPins(SX126X_RXEN, SX126X_TXEN); #endif + // for improved RX with Heltec v4 + #ifdef SX126X_REGISTER_PATCH + uint8_t r_data = 0; + readRegister(0x8B5, &r_data, 1); + r_data |= 0x01; + writeRegister(0x8B5, &r_data, 1); + #endif + return true; // success } diff --git a/variants/heltec_v4/platformio.ini b/variants/heltec_v4/platformio.ini index ecfd7889b..9ab3e1625 100644 --- a/variants/heltec_v4/platformio.ini +++ b/variants/heltec_v4/platformio.ini @@ -17,9 +17,9 @@ build_flags = -D P_LORA_SCLK=9 -D P_LORA_MISO=11 -D P_LORA_MOSI=10 - -D P_LORA_PA_POWER=7 ;power en - -D P_LORA_PA_EN=2 - -D P_LORA_PA_TX_EN=46 ;enable tx + -D P_LORA_PA_POWER=7 ; VFEM_Ctrl - Power on GC1109 + -D P_LORA_PA_EN=2 ; PA CSD - Enable GC1109 + -D P_LORA_PA_TX_EN=46 ; PA CPS - GC1109 TX PA full(High) / bypass(Low) -D PIN_BOARD_SDA=17 -D PIN_BOARD_SCL=18 -D PIN_USER_BTN=0 @@ -27,10 +27,11 @@ build_flags = -D PIN_VEXT_EN_ACTIVE=HIGH -D LORA_TX_POWER=10 ;If it is configured as 10 here, the final output will be 22 dbm. -D MAX_LORA_TX_POWER=22 ; Max SX1262 output - -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_REGISTER_PATCH=1 ; Patch register 0x8B5 for improved RX + -D SX126X_DIO2_AS_RF_SWITCH=true ; GC1109 CTX is controlled by SX1262 DIO2 -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 - -D SX126X_RX_BOOSTED_GAIN=1 +; -D SX126X_RX_BOOSTED_GAIN=1 ; Turned off for improved RX -D PIN_GPS_RX=38 -D PIN_GPS_TX=39 -D PIN_GPS_RESET=42 From 46e4cc06e39043c74cd4d164cc2aedb0f5bbeccf Mon Sep 17 00:00:00 2001 From: Socalix <48040807+Socalix@users.noreply.github.com> Date: Wed, 21 Jan 2026 21:12:54 -0600 Subject: [PATCH 02/35] Revert boosted gain flag to original --- variants/heltec_v4/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_v4/platformio.ini b/variants/heltec_v4/platformio.ini index 9ab3e1625..258a99673 100644 --- a/variants/heltec_v4/platformio.ini +++ b/variants/heltec_v4/platformio.ini @@ -31,7 +31,7 @@ build_flags = -D SX126X_DIO2_AS_RF_SWITCH=true ; GC1109 CTX is controlled by SX1262 DIO2 -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 -; -D SX126X_RX_BOOSTED_GAIN=1 ; Turned off for improved RX + -D SX126X_RX_BOOSTED_GAIN=1 ; In some cases, commenting this out will improve RX -D PIN_GPS_RX=38 -D PIN_GPS_TX=39 -D PIN_GPS_RESET=42 From 3845a1c0219cc4011afa7671040c855eb7eeb44a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Piotr=20Ma=C5=82ek?= Date: Tue, 27 Jan 2026 16:29:31 +0100 Subject: [PATCH 03/35] Fix incorrect INA260 address in debug message --- src/helpers/sensors/EnvironmentSensorManager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 8471d80db..a75d378c8 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -284,7 +284,7 @@ bool EnvironmentSensorManager::begin() { INA260_initialized = true; } else { INA260_initialized = false; - MESH_DEBUG_PRINTLN("INA260 was not found at I2C address %02X", TELEM_INA219_ADDRESS); + MESH_DEBUG_PRINTLN("INA260 was not found at I2C address %02X", TELEM_INA260_ADDRESS); } #endif From edeafde51c5992ed67259901af013addd91a7f6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= Date: Tue, 27 Jan 2026 19:36:12 +0000 Subject: [PATCH 04/35] Fix: Correct validation logic in isValidName function --- src/helpers/CommonCLI.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 42198b498..10ab86691 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -16,7 +16,7 @@ static uint32_t _atoi(const char* sp) { static bool isValidName(const char *n) { while (*n) { - if (*n == '[' || *n == ']' || *n == '/' || *n == '\\' || *n == ':' || *n == ',' || *n == '?' || *n == '*') return false; + if (*n == '[' || *n == ']' || *n == '\\' || *n == ':' || *n == ',' || *n == '?' || *n == '*') return false; n++; } return true; From dd2a9044f3c0a3e608eefc8325a2ea511973ba55 Mon Sep 17 00:00:00 2001 From: Max Litruv Boonzaayer Date: Thu, 29 Jan 2026 08:02:26 +1100 Subject: [PATCH 05/35] Refactor display scaling definitions for HELTEC_VISION_MASTER_T190 --- src/helpers/ui/ST7789Display.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/helpers/ui/ST7789Display.cpp b/src/helpers/ui/ST7789Display.cpp index 7ea351879..f7d20b8ab 100644 --- a/src/helpers/ui/ST7789Display.cpp +++ b/src/helpers/ui/ST7789Display.cpp @@ -10,8 +10,13 @@ #define Y_OFFSET 1 // Vertical offset to prevent top row cutoff #endif -#define SCALE_X 1.875f // 240 / 128 -#define SCALE_Y 2.109375f // 135 / 64 +#ifdef HELTEC_VISION_MASTER_T190 + #define SCALE_X 2.5f // 320 / 128 + #define SCALE_Y 2.65625f // 170 / 64 +#else + #define SCALE_X 1.875f // 240 / 128 + #define SCALE_Y 2.109375f // 135 / 64 +#endif bool ST7789Display::begin() { if(!_isOn) { From f7e54ea7971121ab86501962f3e283889fafcf52 Mon Sep 17 00:00:00 2001 From: Steven Linn Date: Wed, 28 Jan 2026 13:24:22 -0700 Subject: [PATCH 06/35] Add LilyGO T-Beam 1W Support --- boards/t_beam_1w.json | 50 ++++++ variants/lilygo_tbeam_1w/TBeam1WBoard.cpp | 71 ++++++++ variants/lilygo_tbeam_1w/TBeam1WBoard.h | 45 ++++++ variants/lilygo_tbeam_1w/pins_arduino.h | 26 +++ variants/lilygo_tbeam_1w/platformio.ini | 189 ++++++++++++++++++++++ variants/lilygo_tbeam_1w/target.cpp | 64 ++++++++ variants/lilygo_tbeam_1w/target.h | 27 ++++ variants/lilygo_tbeam_1w/variant.h | 96 +++++++++++ 8 files changed, 568 insertions(+) create mode 100644 boards/t_beam_1w.json create mode 100644 variants/lilygo_tbeam_1w/TBeam1WBoard.cpp create mode 100644 variants/lilygo_tbeam_1w/TBeam1WBoard.h create mode 100644 variants/lilygo_tbeam_1w/pins_arduino.h create mode 100644 variants/lilygo_tbeam_1w/platformio.ini create mode 100644 variants/lilygo_tbeam_1w/target.cpp create mode 100644 variants/lilygo_tbeam_1w/target.h create mode 100644 variants/lilygo_tbeam_1w/variant.h diff --git a/boards/t_beam_1w.json b/boards/t_beam_1w.json new file mode 100644 index 000000000..2f1159aa1 --- /dev/null +++ b/boards/t_beam_1w.json @@ -0,0 +1,50 @@ +{ + "build": { + "arduino": { + "ldscript": "esp32s3_out.ld", + "memory_type": "qio_opi" + }, + "core": "esp32", + "extra_flags": [ + "-DBOARD_HAS_PSRAM", + "-DLILYGO_TBEAM_1W", + "-DARDUINO_USB_CDC_ON_BOOT=1", + "-DARDUINO_USB_MODE=0", + "-DARDUINO_RUNNING_CORE=1", + "-DARDUINO_EVENT_RUNNING_CORE=1" + ], + "f_cpu": "240000000L", + "f_flash": "80000000L", + "flash_mode": "qio", + "psram_type": "opi", + "hwids": [ + [ + "0x303A", + "0x1001" + ] + ], + "mcu": "esp32s3", + "variant": "lilygo_tbeam_1w" + }, + "connectivity": [ + "wifi", + "bluetooth", + "lora" + ], + "debug": { + "openocd_target": "esp32s3.cfg" + }, + "frameworks": [ + "arduino" + ], + "name": "LilyGo TBeam-1W", + "upload": { + "flash_size": "16MB", + "maximum_ram_size": 327680, + "maximum_size": 16777216, + "require_upload_port": true, + "speed": 921600 + }, + "url": "http://www.lilygo.cn/", + "vendor": "LilyGo" +} diff --git a/variants/lilygo_tbeam_1w/TBeam1WBoard.cpp b/variants/lilygo_tbeam_1w/TBeam1WBoard.cpp new file mode 100644 index 000000000..1719d7333 --- /dev/null +++ b/variants/lilygo_tbeam_1w/TBeam1WBoard.cpp @@ -0,0 +1,71 @@ +#include "TBeam1WBoard.h" + +void TBeam1WBoard::begin() { + ESP32Board::begin(); + + // Power on radio module (must be done before radio init) + pinMode(SX126X_POWER_EN, OUTPUT); + digitalWrite(SX126X_POWER_EN, HIGH); + radio_powered = true; + delay(10); // Allow radio to power up + + // RF switch RXEN pin handled by RadioLib via setRfSwitchPins() + + // Initialize LED + pinMode(LED_PIN, OUTPUT); + digitalWrite(LED_PIN, LOW); + + // Initialize fan control (on by default - 1W PA can overheat) + pinMode(FAN_CTRL_PIN, OUTPUT); + digitalWrite(FAN_CTRL_PIN, HIGH); +} + +void TBeam1WBoard::onBeforeTransmit() { + // RF switching handled by RadioLib via SX126X_DIO2_AS_RF_SWITCH and setRfSwitchPins() + digitalWrite(LED_PIN, HIGH); // TX LED on +} + +void TBeam1WBoard::onAfterTransmit() { + digitalWrite(LED_PIN, LOW); // TX LED off +} + +uint16_t TBeam1WBoard::getBattMilliVolts() { + // T-Beam 1W uses 7.4V battery with voltage divider + // ADC reads through divider - adjust multiplier based on actual divider ratio + analogReadResolution(12); + uint32_t raw = 0; + for (int i = 0; i < 8; i++) { + raw += analogRead(BATTERY_PIN); + } + raw = raw / 8; + // Assuming voltage divider ratio from ADC_MULTIPLIER + // 3.3V reference, 12-bit ADC (4095 max) + return static_cast((raw * 3300 * ADC_MULTIPLIER) / 4095); +} + +const char* TBeam1WBoard::getManufacturerName() const { + return "LilyGo T-Beam 1W"; +} + +void TBeam1WBoard::powerOff() { + // Turn off radio LNA (CTRL pin must be LOW when not receiving) + digitalWrite(SX126X_RXEN, LOW); + + // Turn off radio power + digitalWrite(SX126X_POWER_EN, LOW); + radio_powered = false; + + // Turn off LED and fan + digitalWrite(LED_PIN, LOW); + digitalWrite(FAN_CTRL_PIN, LOW); + + ESP32Board::powerOff(); +} + +void TBeam1WBoard::setFanEnabled(bool enabled) { + digitalWrite(FAN_CTRL_PIN, enabled ? HIGH : LOW); +} + +bool TBeam1WBoard::isFanEnabled() const { + return digitalRead(FAN_CTRL_PIN) == HIGH; +} diff --git a/variants/lilygo_tbeam_1w/TBeam1WBoard.h b/variants/lilygo_tbeam_1w/TBeam1WBoard.h new file mode 100644 index 000000000..d999dfd4c --- /dev/null +++ b/variants/lilygo_tbeam_1w/TBeam1WBoard.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include "variant.h" + +// LilyGo T-Beam 1W with SX1262 + external PA (XY16P35 module) +// +// Power architecture (LDO is separate chip on T-Beam board, not inside XY16P35): +// +// VCC (+4.0~+8.0V) ──┬──────────────────► XY16P35 VCC pin 5 (PA direct) +// (USB or Battery) │ +// │ ┌───────────┐ +// └──►│ LDO Chip │──► +3.3V ──► XY16P35 (SX1262 + LNA) +// │ EN=GPIO40 │ +// └───────────┘ +// LDO_EN (GPIO 40): H @ +1.2V~VIN, active high, not floating +// +// Control signals: +// - LDO_EN (GPIO 40): HIGH enables LDO → powers SX1262 + LNA +// - TCXO_EN (DIO3): HIGH enables TCXO (set to 1.8V per Meshtastic) +// - CTL (GPIO 21): HIGH=RX (LNA on), LOW=TX (LNA off) +// - DIO2: AUTO via SX126X_DIO2_AS_RF_SWITCH (TX path) +// +// Power notes: +// - PA needs VCC 4.0-8.0V for full 32dBm output +// - USB-C (3.9-6V) marginal; 7.4V battery recommended +// - Battery must support 2A+ discharge for high-power TX + +class TBeam1WBoard : public ESP32Board { +private: + bool radio_powered = false; + +public: + void begin(); + void onBeforeTransmit() override; + void onAfterTransmit() override; + uint16_t getBattMilliVolts() override; + const char* getManufacturerName() const override; + void powerOff() override; + + // Fan control methods + void setFanEnabled(bool enabled); + bool isFanEnabled() const; +}; diff --git a/variants/lilygo_tbeam_1w/pins_arduino.h b/variants/lilygo_tbeam_1w/pins_arduino.h new file mode 100644 index 000000000..c6f596f43 --- /dev/null +++ b/variants/lilygo_tbeam_1w/pins_arduino.h @@ -0,0 +1,26 @@ +#ifndef Pins_Arduino_h +#define Pins_Arduino_h + +#include + +#define USB_VID 0x303a +#define USB_PID 0x1001 + +// Serial (USB CDC) +static const uint8_t TX = 43; +static const uint8_t RX = 44; + +// I2C for OLED and sensors +static const uint8_t SDA = 8; +static const uint8_t SCL = 9; + +// Default SPI mapped to Radio/SD +static const uint8_t SS = 15; // LoRa CS +static const uint8_t MOSI = 11; +static const uint8_t MISO = 12; +static const uint8_t SCK = 13; + +// SD Card CS +#define SDCARD_CS 10 + +#endif /* Pins_Arduino_h */ diff --git a/variants/lilygo_tbeam_1w/platformio.ini b/variants/lilygo_tbeam_1w/platformio.ini new file mode 100644 index 000000000..4b72b5e73 --- /dev/null +++ b/variants/lilygo_tbeam_1w/platformio.ini @@ -0,0 +1,189 @@ +[LilyGo_TBeam_1W] +extends = esp32_base +board = t_beam_1w +build_flags = + ${esp32_base.build_flags} + -I variants/lilygo_tbeam_1w + -D TBEAM_1W + + ; Radio - SX1262 with high-power PA (32dBm max output) + ; Note: Set SX1262 output to 22dBm max, external PA provides additional gain + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D P_LORA_DIO_1=1 + -D P_LORA_NSS=15 + -D P_LORA_RESET=3 + -D P_LORA_BUSY=38 + -D P_LORA_SCLK=13 + -D P_LORA_MISO=12 + -D P_LORA_MOSI=11 + + ; RF switch configuration: + ; DIO2 controls TX path (PA enable) via SX126X_DIO2_AS_RF_SWITCH + ; GPIO21 controls RX path (LNA enable) via SX126X_RXEN + ; Truth table: DIO2=1,RXEN=0 → TX | DIO2=0,RXEN=1 → RX + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_RXEN=21 + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + + ; TX power: 22dBm to SX1262, PA module adds ~10dB for 32dBm total + -D LORA_TX_POWER=22 + + ; Display - SH1106 OLED at 0x3C + -D DISPLAY_CLASS=SH1106Display + + ; I2C pins + -D PIN_BOARD_SDA=8 + -D PIN_BOARD_SCL=9 + + ; GPS - L76K module + ; GNSS_TXD (IO5) = GPS transmits → MCU RX + ; GNSS_RXD (IO6) = GPS receives → MCU TX + -D PIN_GPS_TX=5 + -D PIN_GPS_RX=6 + -D PIN_GPS_EN=16 + -D ENV_INCLUDE_GPS=1 + + ; User interface + -D PIN_USER_BTN=17 + +build_src_filter = ${esp32_base.build_src_filter} + +<../variants/lilygo_tbeam_1w> + + + + + + + +lib_deps = + ${esp32_base.lib_deps} + adafruit/Adafruit SH110X @ ~2.1.13 + stevemarple/MicroNMEA @ ~2.0.6 + +; === LILYGO T-Beam 1W Repeater === +[env:LilyGo_TBeam_1W_repeater] +extends = LilyGo_TBeam_1W +build_flags = + ${LilyGo_TBeam_1W.build_flags} + -D ADVERT_NAME='"T-Beam 1W Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 + -D PERSISTANT_GPS=1 + -D ENV_SKIP_GPS_DETECT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${LilyGo_TBeam_1W.build_src_filter} + +<../examples/simple_repeater> +lib_deps = + ${LilyGo_TBeam_1W.lib_deps} + ${esp32_ota.lib_deps} + +; === LILYGO T-Beam 1W Room Server === +[env:LilyGo_TBeam_1W_room_server] +extends = LilyGo_TBeam_1W +build_flags = + ${LilyGo_TBeam_1W.build_flags} + -D ADVERT_NAME='"T-Beam 1W Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' + -D PERSISTANT_GPS=1 + -D ENV_SKIP_GPS_DETECT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${LilyGo_TBeam_1W.build_src_filter} + +<../examples/simple_room_server> +lib_deps = + ${LilyGo_TBeam_1W.lib_deps} + ${esp32_ota.lib_deps} + +; === LILYGO T-Beam 1W Companion Radio (USB) === +[env:LilyGo_TBeam_1W_companion_radio_usb] +extends = LilyGo_TBeam_1W +build_flags = + ${LilyGo_TBeam_1W.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D PERSISTANT_GPS=1 + -D ENV_SKIP_GPS_DETECT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${LilyGo_TBeam_1W.build_src_filter} + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${LilyGo_TBeam_1W.lib_deps} + densaugeo/base64 @ ~1.4.0 + +; === LILYGO T-Beam 1W Companion Radio (BLE) === +[env:LilyGo_TBeam_1W_companion_radio_ble] +extends = LilyGo_TBeam_1W +build_flags = + ${LilyGo_TBeam_1W.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D BLE_PIN_CODE=123456 + -D OFFLINE_QUEUE_SIZE=256 + -D PERSISTANT_GPS=1 + -D ENV_SKIP_GPS_DETECT=1 +; -D BLE_DEBUG_LOGGING=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${LilyGo_TBeam_1W.build_src_filter} + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${LilyGo_TBeam_1W.lib_deps} + densaugeo/base64 @ ~1.4.0 + +; === LILYGO T-Beam 1W Companion Radio (WiFi) === +[env:LilyGo_TBeam_1W_companion_radio_wifi] +extends = LilyGo_TBeam_1W +build_flags = + ${LilyGo_TBeam_1W.build_flags} + -I examples/companion_radio/ui-new + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D WIFI_DEBUG_LOGGING=1 + -D WIFI_SSID='"myssid"' + -D WIFI_PWD='"mypwd"' + -D PERSISTANT_GPS=1 + -D ENV_SKIP_GPS_DETECT=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${LilyGo_TBeam_1W.build_src_filter} + + + +<../examples/companion_radio/*.cpp> + +<../examples/companion_radio/ui-new/*.cpp> +lib_deps = + ${LilyGo_TBeam_1W.lib_deps} + densaugeo/base64 @ ~1.4.0 + +; === LILYGO T-Beam 1W Repeater with ESPNow Bridge === +[env:LilyGo_TBeam_1W_repeater_bridge_espnow] +extends = LilyGo_TBeam_1W +build_flags = + ${LilyGo_TBeam_1W.build_flags} + -D ADVERT_NAME='"T-Beam 1W ESPNow Bridge"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 + -D WITH_ESPNOW_BRIDGE=1 + -D PERSISTANT_GPS=1 + -D ENV_SKIP_GPS_DETECT=1 +; -D BRIDGE_DEBUG=1 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${LilyGo_TBeam_1W.build_src_filter} + + + +<../examples/simple_repeater> +lib_deps = + ${LilyGo_TBeam_1W.lib_deps} + ${esp32_ota.lib_deps} diff --git a/variants/lilygo_tbeam_1w/target.cpp b/variants/lilygo_tbeam_1w/target.cpp new file mode 100644 index 000000000..fcdb42ed8 --- /dev/null +++ b/variants/lilygo_tbeam_1w/target.cpp @@ -0,0 +1,64 @@ +#include +#include "target.h" + +TBeam1WBoard board; + +#ifdef DISPLAY_CLASS + DISPLAY_CLASS display; + MomentaryButton user_btn(PIN_USER_BTN, 1000, true); +#endif + +static SPIClass spi; + +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); + +#if ENV_INCLUDE_GPS + #include + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#else + EnvironmentSensorManager sensors; +#endif + +bool radio_init() { + fallback_clock.begin(); + rtc_clock.begin(Wire); + + // Initialize SPI for radio + spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + + // GPS serial initialized by EnvironmentSensorManager::begin() + + bool success = radio.std_init(&spi); + if (success) { + // T-Beam 1W has external PA requiring longer ramp time (>800us recommended) + // RADIOLIB_SX126X_PA_RAMP_800U = 0x05 + radio.setTxParams(LORA_TX_POWER, RADIOLIB_SX126X_PA_RAMP_800U); + } + return success; +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); +} diff --git a/variants/lilygo_tbeam_1w/target.h b/variants/lilygo_tbeam_1w/target.h new file mode 100644 index 000000000..2c3e8970a --- /dev/null +++ b/variants/lilygo_tbeam_1w/target.h @@ -0,0 +1,27 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include "TBeam1WBoard.h" + +#ifdef DISPLAY_CLASS + #include + #include + extern DISPLAY_CLASS display; + extern MomentaryButton user_btn; +#endif + +extern TBeam1WBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern EnvironmentSensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_tbeam_1w/variant.h b/variants/lilygo_tbeam_1w/variant.h new file mode 100644 index 000000000..c05b16966 --- /dev/null +++ b/variants/lilygo_tbeam_1w/variant.h @@ -0,0 +1,96 @@ +// LilyGo T-Beam-1W variant.h +// Configuration based on Meshtastic PR #8967 and LilyGO documentation + +#pragma once + +// I2C for OLED display (SH1106 at 0x3C) +#define I2C_SDA 8 +#define I2C_SCL 9 + +// GPS - Quectel L76K +// GNSS_TXD (IO5) = GPS transmits → MCU RX (setPins rxPin) +// GNSS_RXD (IO6) = GPS receives → MCU TX (setPins txPin) +#define PIN_GPS_TX 5 // MCU receives from GPS TX +#define PIN_GPS_RX 6 // MCU transmits to GPS RX +#define PIN_GPS_PPS 7 // GPS PPS output +#define PIN_GPS_EN 16 // GPS wake-up/enable (GPS_EN_PIN in LilyGO code) +#define HAS_GPS 1 +#define GPS_BAUDRATE 9600 + +// Buttons +#define BUTTON_PIN 0 // BUTTON 1 (boot) +#define BUTTON_PIN_ALT 17 // BUTTON 2 + +// SPI (shared by LoRa and SD) +#define SPI_MOSI 11 +#define SPI_SCK 13 +#define SPI_MISO 12 +#define SPI_CS 10 + +// SD Card +#define HAS_SDCARD +#define SDCARD_USE_SPI1 +#define SDCARD_CS SPI_CS + +// LoRa Radio - SX1262 with 1W PA +#define USE_SX1262 + +#define LORA_SCK SPI_SCK +#define LORA_MISO SPI_MISO +#define LORA_MOSI SPI_MOSI +#define LORA_CS 15 +#define LORA_RESET 3 +#define LORA_DIO1 1 +#define LORA_BUSY 38 + +// CRITICAL: Radio power enable - MUST be HIGH before lora.begin()! +// GPIO 40 powers the SX1262 + PA module via LDO +#define SX126X_POWER_EN 40 + +#ifdef USE_SX1262 +#define SX126X_CS LORA_CS +#define SX126X_DIO1 LORA_DIO1 +#define SX126X_BUSY LORA_BUSY +#define SX126X_RESET LORA_RESET + +// RF switching configuration for 1W PA module +// DIO2 controls PA (via SX126X_DIO2_AS_RF_SWITCH) +// CTRL PIN (GPIO 21) controls LNA - must be HIGH during RX +// Truth table: DIO2=1,CTRL=0 -> TX (PA on, LNA off) +// DIO2=0,CTRL=1 -> RX (PA off, LNA on) +#define SX126X_DIO2_AS_RF_SWITCH +#define SX126X_RXEN 21 // LNA enable - HIGH during RX + +// TCXO voltage - required for radio init +#define SX126X_DIO3_TCXO_VOLTAGE 1.8 + +#define SX126X_MAX_POWER 22 +#endif + +// LED +#define LED_PIN 18 +#define LED_STATE_ON 1 // HIGH = ON + +// Battery ADC +#define BATTERY_PIN 4 +#define ADC_CHANNEL ADC1_GPIO4_CHANNEL +#define BATTERY_SENSE_SAMPLES 30 +#define ADC_MULTIPLIER 3.0 + +// NTC temperature sensor +#define NTC_PIN 14 + +// Fan control +#define FAN_CTRL_PIN 41 + +// PA Ramp Time - T-Beam 1W requires >800us stabilization (default is 200us) +// Value 0x05 = RADIOLIB_SX126X_PA_RAMP_800U +#define SX126X_PA_RAMP_US 0x05 + +// Display - SH1106 OLED (128x64) +#define USE_SH1106 +#define OLED_WIDTH 128 +#define OLED_HEIGHT 64 + +// 32768 Hz crystal present +#define HAS_32768HZ 1 From 44e7c092c8bef63eede999481ede41f4c728a737 Mon Sep 17 00:00:00 2001 From: Steven Linn Date: Wed, 28 Jan 2026 14:23:36 -0700 Subject: [PATCH 07/35] Add battery min/max voltage parameter support --- examples/companion_radio/ui-new/UITask.cpp | 10 ++++++++-- examples/companion_radio/ui-orig/UITask.cpp | 10 ++++++++-- variants/lilygo_tbeam_1w/platformio.ini | 4 ++++ 3 files changed, 20 insertions(+), 4 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 8077627f8..0690b45ac 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -103,8 +103,14 @@ class HomeScreen : public UIScreen { void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts) { // Convert millivolts to percentage - const int minMilliVolts = 3000; // Minimum voltage (e.g., 3.0V) - const int maxMilliVolts = 4200; // Maximum voltage (e.g., 4.2V) +#ifndef BATT_MIN_MILLIVOLTS + #define BATT_MIN_MILLIVOLTS 3000 +#endif +#ifndef BATT_MAX_MILLIVOLTS + #define BATT_MAX_MILLIVOLTS 4200 +#endif + const int minMilliVolts = BATT_MIN_MILLIVOLTS; + const int maxMilliVolts = BATT_MAX_MILLIVOLTS; int batteryPercentage = ((batteryMilliVolts - minMilliVolts) * 100) / (maxMilliVolts - minMilliVolts); if (batteryPercentage < 0) batteryPercentage = 0; // Clamp to 0% if (batteryPercentage > 100) batteryPercentage = 100; // Clamp to 100% diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 39cbf23ad..3ad36fb00 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -149,8 +149,14 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i void UITask::renderBatteryIndicator(uint16_t batteryMilliVolts) { // Convert millivolts to percentage - const int minMilliVolts = 3000; // Minimum voltage (e.g., 3.0V) - const int maxMilliVolts = 4200; // Maximum voltage (e.g., 4.2V) +#ifndef BATT_MIN_MILLIVOLTS + #define BATT_MIN_MILLIVOLTS 3000 +#endif +#ifndef BATT_MAX_MILLIVOLTS + #define BATT_MAX_MILLIVOLTS 4200 +#endif + const int minMilliVolts = BATT_MIN_MILLIVOLTS; + const int maxMilliVolts = BATT_MAX_MILLIVOLTS; int batteryPercentage = ((batteryMilliVolts - minMilliVolts) * 100) / (maxMilliVolts - minMilliVolts); if (batteryPercentage < 0) batteryPercentage = 0; // Clamp to 0% if (batteryPercentage > 100) batteryPercentage = 100; // Clamp to 100% diff --git a/variants/lilygo_tbeam_1w/platformio.ini b/variants/lilygo_tbeam_1w/platformio.ini index 4b72b5e73..618a32a87 100644 --- a/variants/lilygo_tbeam_1w/platformio.ini +++ b/variants/lilygo_tbeam_1w/platformio.ini @@ -31,6 +31,10 @@ build_flags = ; TX power: 22dBm to SX1262, PA module adds ~10dB for 32dBm total -D LORA_TX_POWER=22 + ; Battery - 2S 7.4V LiPo (6.0V min, 8.4V max) + -D BATT_MIN_MILLIVOLTS=6000 + -D BATT_MAX_MILLIVOLTS=8400 + ; Display - SH1106 OLED at 0x3C -D DISPLAY_CLASS=SH1106Display From a9a8299e14172769dcc304d6d64fe203acaa01ce Mon Sep 17 00:00:00 2001 From: Steven Linn Date: Wed, 28 Jan 2026 14:24:53 -0700 Subject: [PATCH 08/35] Set LilyGO T-Beam 1W to use TX0 3.0V (within reference +2.85V~+3.15V) --- variants/lilygo_tbeam_1w/platformio.ini | 2 +- variants/lilygo_tbeam_1w/variant.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/variants/lilygo_tbeam_1w/platformio.ini b/variants/lilygo_tbeam_1w/platformio.ini index 618a32a87..cf17ae8bd 100644 --- a/variants/lilygo_tbeam_1w/platformio.ini +++ b/variants/lilygo_tbeam_1w/platformio.ini @@ -24,7 +24,7 @@ build_flags = ; Truth table: DIO2=1,RXEN=0 → TX | DIO2=0,RXEN=1 → RX -D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_RXEN=21 - -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_DIO3_TCXO_VOLTAGE=3.0 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 diff --git a/variants/lilygo_tbeam_1w/variant.h b/variants/lilygo_tbeam_1w/variant.h index c05b16966..f6807e56b 100644 --- a/variants/lilygo_tbeam_1w/variant.h +++ b/variants/lilygo_tbeam_1w/variant.h @@ -62,7 +62,7 @@ #define SX126X_RXEN 21 // LNA enable - HIGH during RX // TCXO voltage - required for radio init -#define SX126X_DIO3_TCXO_VOLTAGE 1.8 +#define SX126X_DIO3_TCXO_VOLTAGE 3.0 #define SX126X_MAX_POWER 22 #endif From 3a7ccc085d5dab694a0eeeb61b5bf341f56ab958 Mon Sep 17 00:00:00 2001 From: Rastislav Vysoky Date: Thu, 29 Jan 2026 15:32:51 +0100 Subject: [PATCH 09/35] fixed build errors and typos/inconsistencies --- variants/thinknode_m3/ThinknodeM3Board.cpp | 22 +++++++++--- variants/thinknode_m3/ThinknodeM3Board.h | 42 ++++++++++------------ variants/thinknode_m3/target.cpp | 16 ++++----- variants/thinknode_m3/target.h | 4 +-- variants/thinknode_m6/ThinkNodeM6Board.h | 13 ++++--- 5 files changed, 56 insertions(+), 41 deletions(-) diff --git a/variants/thinknode_m3/ThinknodeM3Board.cpp b/variants/thinknode_m3/ThinknodeM3Board.cpp index d7ecd62d5..ac513ade5 100644 --- a/variants/thinknode_m3/ThinknodeM3Board.cpp +++ b/variants/thinknode_m3/ThinknodeM3Board.cpp @@ -1,14 +1,28 @@ #include -#include "ThinknodeM3Board.h" +#include "ThinkNodeM3Board.h" #include #include -void ThinknodeM3Board::begin() { - Nrf52BoardDCDC::begin(); +void ThinkNodeM3Board::begin() { + NRF52Board::begin(); btn_prev_state = HIGH; Wire.begin(); delay(10); // give sx1262 some time to power up -} \ No newline at end of file +} + +uint16_t ThinkNodeM3Board::getBattMilliVolts() { + int adcvalue = 0; + + analogReference(AR_INTERNAL_2_4); + analogReadResolution(ADC_RESOLUTION); + delay(10); + + // ADC range is 0..2400mV and resolution is 12-bit (0..4095) + adcvalue = analogRead(PIN_VBAT_READ); + // Convert the raw value to compensated mv, taking the resistor- + // divider into account (providing the actual LIPO voltage) + return (uint16_t)((float)adcvalue * ADC_FACTOR); +} diff --git a/variants/thinknode_m3/ThinknodeM3Board.h b/variants/thinknode_m3/ThinknodeM3Board.h index 626940875..1435d31d4 100644 --- a/variants/thinknode_m3/ThinknodeM3Board.h +++ b/variants/thinknode_m3/ThinknodeM3Board.h @@ -6,38 +6,26 @@ #define ADC_FACTOR ((1000.0*ADC_MULTIPLIER*AREF_VOLTAGE)/ADC_MAX) -class ThinknodeM3Board : public Nrf52BoardDCDC { +class ThinkNodeM3Board : public NRF52BoardDCDC { protected: +#if NRF52_POWER_MANAGEMENT + void initiateShutdown(uint8_t reason) override; +#endif uint8_t btn_prev_state; public: + ThinkNodeM3Board() : NRF52Board("THINKNODE_M3_OTA") {} void begin(); - - uint16_t getBattMilliVolts() override { - int adcvalue = 0; - - analogReference(AR_INTERNAL_2_4); - analogReadResolution(ADC_RESOLUTION); - delay(10); - - // ADC range is 0..2400mV and resolution is 12-bit (0..4095) - adcvalue = analogRead(PIN_VBAT_READ); - // Convert the raw value to compensated mv, taking the resistor- - // divider into account (providing the actual LIPO voltage) - return (uint16_t)((float)adcvalue * ADC_FACTOR); - } + uint16_t getBattMilliVolts() override; #if defined(P_LORA_TX_LED) -#if !defined(P_LORA_TX_LED_ON) -#define P_LORA_TX_LED_ON HIGH -#endif void onBeforeTransmit() override { - digitalWrite(P_LORA_TX_LED, P_LORA_TX_LED_ON); // turn TX LED on + digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on } void onAfterTransmit() override { - digitalWrite(P_LORA_TX_LED, !P_LORA_TX_LED_ON); // turn TX LED off + digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off } - #endif +#endif const char* getManufacturerName() const override { return "Elecrow ThinkNode M3"; @@ -54,5 +42,13 @@ class ThinknodeM3Board : public Nrf52BoardDCDC { return 0; } - void powerOff() override { sd_power_system_off(); } -}; \ No newline at end of file + void powerOff() override { + // turn off all leds, sd_power_system_off will not do this for us + #ifdef P_LORA_TX_LED + digitalWrite(P_LORA_TX_LED, LOW); + #endif + + // power off board + sd_power_system_off(); + } +}; diff --git a/variants/thinknode_m3/target.cpp b/variants/thinknode_m3/target.cpp index c6708e4d1..91d186dc1 100644 --- a/variants/thinknode_m3/target.cpp +++ b/variants/thinknode_m3/target.cpp @@ -2,7 +2,7 @@ #include "target.h" #include -ThinknodeM3Board board; +ThinkNodeM3Board board; RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); @@ -30,26 +30,26 @@ static const uint32_t rfswitch_dios[Module::RFSWITCH_MAX_PINS] = { RADIOLIB_LR11X0_DIO5, RADIOLIB_LR11X0_DIO6, RADIOLIB_NC, - RADIOLIB_NC, + RADIOLIB_NC, RADIOLIB_NC }; static const Module::RfSwitchMode_t rfswitch_table[] = { - // mode DIO5 DIO6 - { LR11x0::MODE_STBY, {LOW , LOW }}, + // mode DIO5 DIO6 + { LR11x0::MODE_STBY, {LOW , LOW }}, { LR11x0::MODE_RX, {HIGH, LOW }}, { LR11x0::MODE_TX, {HIGH, HIGH }}, { LR11x0::MODE_TX_HP, {LOW , HIGH }}, - { LR11x0::MODE_TX_HF, {LOW , LOW }}, + { LR11x0::MODE_TX_HF, {LOW , LOW }}, { LR11x0::MODE_GNSS, {LOW , LOW }}, - { LR11x0::MODE_WIFI, {LOW , LOW }}, + { LR11x0::MODE_WIFI, {LOW , LOW }}, END_OF_MODE_TABLE, }; #endif bool radio_init() { rtc_clock.begin(Wire); - + #ifdef LR11X0_DIO3_TCXO_VOLTAGE float tcxo = LR11X0_DIO3_TCXO_VOLTAGE; #else @@ -64,7 +64,7 @@ bool radio_init() { Serial.println(status); return false; // fail } - + radio.setCRC(2); radio.explicitHeader(); diff --git a/variants/thinknode_m3/target.h b/variants/thinknode_m3/target.h index f60a85b03..23e995814 100644 --- a/variants/thinknode_m3/target.h +++ b/variants/thinknode_m3/target.h @@ -3,7 +3,7 @@ #define RADIOLIB_STATIC_ONLY 1 #include #include -#include "ThinknodeM3Board.h" +#include "ThinkNodeM3Board.h" #include #include #include @@ -17,7 +17,7 @@ extern NullDisplayDriver display; #endif -extern ThinknodeM3Board board; +extern ThinkNodeM3Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; extern EnvironmentSensorManager sensors; diff --git a/variants/thinknode_m6/ThinkNodeM6Board.h b/variants/thinknode_m6/ThinkNodeM6Board.h index c03e1fbc6..32baa2a0a 100644 --- a/variants/thinknode_m6/ThinkNodeM6Board.h +++ b/variants/thinknode_m6/ThinkNodeM6Board.h @@ -12,9 +12,14 @@ #define PIN_VBAT_READ BATTERY_PIN #define REAL_VBAT_MV_PER_LSB (VBAT_DIVIDER_COMP * VBAT_MV_PER_LSB) -class ThinkNodeM6Board : public Nrf52BoardOTA { +class ThinkNodeM6Board : public NRF52BoardDCDC { +protected: +#if NRF52_POWER_MANAGEMENT + void initiateShutdown(uint8_t reason) override; +#endif + public: - ThinkNodeM6Board() : NRF52BoardOTA("THINKNODE_M1_OTA") {} + ThinkNodeM6Board() : NRF52Board("THINKNODE_M6_OTA") {} void begin(); uint16_t getBattMilliVolts() override; @@ -25,10 +30,10 @@ class ThinkNodeM6Board : public Nrf52BoardOTA { void onAfterTransmit() override { digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off } - #endif +#endif const char* getManufacturerName() const override { - return "Elecrow ThinkNode-M6"; + return "Elecrow ThinkNode M6"; } void powerOff() override { From 2a321b53ebfeea2d0b2a9160f944564633b8f9aa Mon Sep 17 00:00:00 2001 From: Rastislav Vysoky Date: Thu, 29 Jan 2026 16:00:19 +0100 Subject: [PATCH 10/35] renamed board files --- .../thinknode_m3/{ThinknodeM3Board.cpp => ThinkNodeM3Board.cpp} | 0 variants/thinknode_m3/{ThinknodeM3Board.h => ThinkNodeM3Board.h} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename variants/thinknode_m3/{ThinknodeM3Board.cpp => ThinkNodeM3Board.cpp} (100%) rename variants/thinknode_m3/{ThinknodeM3Board.h => ThinkNodeM3Board.h} (100%) diff --git a/variants/thinknode_m3/ThinknodeM3Board.cpp b/variants/thinknode_m3/ThinkNodeM3Board.cpp similarity index 100% rename from variants/thinknode_m3/ThinknodeM3Board.cpp rename to variants/thinknode_m3/ThinkNodeM3Board.cpp diff --git a/variants/thinknode_m3/ThinknodeM3Board.h b/variants/thinknode_m3/ThinkNodeM3Board.h similarity index 100% rename from variants/thinknode_m3/ThinknodeM3Board.h rename to variants/thinknode_m3/ThinkNodeM3Board.h From c345f1da8e201bcac4aec02a56529192d15000ec Mon Sep 17 00:00:00 2001 From: Rastislav Vysoky Date: Fri, 30 Jan 2026 00:12:04 +0100 Subject: [PATCH 11/35] Revert "Remove _serial->isConnected() logic from buzzer notifications" --- examples/companion_radio/MyMesh.cpp | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 2dad7866a..e0537707a 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -330,10 +330,11 @@ void MyMesh::onDiscoveredContact(ContactInfo &contact, bool is_new, uint8_t path memcpy(&out_frame[1], contact.id.pub_key, PUB_KEY_SIZE); _serial->writeFrame(out_frame, 1 + PUB_KEY_SIZE); } - } + } else { #ifdef DISPLAY_CLASS - if (_ui && !_prefs.buzzer_quiet) _ui->notify(UIEventType::newContactMessage); //buzz if enabled + if (_ui) _ui->notify(UIEventType::newContactMessage); #endif + } // add inbound-path to mem cache if (path && path_len <= sizeof(AdvertPath::path)) { // check path is valid @@ -440,7 +441,9 @@ void MyMesh::queueMessage(const ContactInfo &from, uint8_t txt_type, mesh::Packe bool should_display = txt_type == TXT_TYPE_PLAIN || txt_type == TXT_TYPE_SIGNED_PLAIN; if (should_display && _ui) { _ui->newMsg(path_len, from.name, text, offline_queue_len); - if (!_prefs.buzzer_quiet) _ui->notify(UIEventType::contactMessage); //buzz if enabled + if (!_serial->isConnected()) { + _ui->notify(UIEventType::contactMessage); + } } #endif } @@ -525,8 +528,11 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe uint8_t frame[1]; frame[0] = PUSH_CODE_MSG_WAITING; // send push 'tickle' _serial->writeFrame(frame, 1); + } else { +#ifdef DISPLAY_CLASS + if (_ui) _ui->notify(UIEventType::channelMessage); +#endif } - #ifdef DISPLAY_CLASS // Get the channel name from the channel index const char *channel_name = "Unknown"; @@ -534,10 +540,7 @@ void MyMesh::onChannelMessageRecv(const mesh::GroupChannel &channel, mesh::Packe if (getChannel(channel_idx, channel_details)) { channel_name = channel_details.name; } - if (_ui) { - _ui->newMsg(path_len, channel_name, text, offline_queue_len); - if (!_prefs.buzzer_quiet) _ui->notify(UIEventType::channelMessage); //buzz if enabled - } + if (_ui) _ui->newMsg(path_len, channel_name, text, offline_queue_len); #endif } @@ -796,7 +799,6 @@ MyMesh::MyMesh(mesh::Radio &radio, mesh::RNG &rng, mesh::RTCClock &rtc, SimpleMe _prefs.bw = LORA_BW; _prefs.cr = LORA_CR; _prefs.tx_power_dbm = LORA_TX_POWER; - _prefs.buzzer_quiet = 0; _prefs.gps_enabled = 0; // GPS disabled by default _prefs.gps_interval = 0; // No automatic GPS updates by default //_prefs.rx_delay_base = 10.0f; enable once new algo fixed @@ -836,7 +838,6 @@ void MyMesh::begin(bool has_display) { _prefs.sf = constrain(_prefs.sf, 5, 12); _prefs.cr = constrain(_prefs.cr, 5, 8); _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); - _prefs.buzzer_quiet = constrain(_prefs.buzzer_quiet, 0, 1); // Ensure boolean 0 or 1 _prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1 _prefs.gps_interval = constrain(_prefs.gps_interval, 0, 86400); // Max 24 hours From c7eea3915d5d23e8cbe5271d3ae4ccc11f4bc68b Mon Sep 17 00:00:00 2001 From: taco Date: Fri, 30 Jan 2026 15:07:40 +1100 Subject: [PATCH 12/35] fix: remove esp_wifi.h from esp32board.h saves ~500 bytes of dram and allows Tbeam to compile again --- examples/companion_radio/main.cpp | 1 + src/helpers/ESP32Board.cpp | 1 + src/helpers/ESP32Board.h | 12 ++++++------ 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/examples/companion_radio/main.cpp b/examples/companion_radio/main.cpp index 7e636acee..eff9efca4 100644 --- a/examples/companion_radio/main.cpp +++ b/examples/companion_radio/main.cpp @@ -194,6 +194,7 @@ void setup() { ); #ifdef WIFI_SSID + board.setInhibitSleep(true); // prevent sleep when WiFi is active WiFi.begin(WIFI_SSID, WIFI_PWD); serial_interface.begin(TCP_PORT); #elif defined(BLE_PIN_CODE) diff --git a/src/helpers/ESP32Board.cpp b/src/helpers/ESP32Board.cpp index 4dce467cd..e0ca1d0ee 100644 --- a/src/helpers/ESP32Board.cpp +++ b/src/helpers/ESP32Board.cpp @@ -11,6 +11,7 @@ #include bool ESP32Board::startOTAUpdate(const char* id, char reply[]) { + inhibit_sleep = true; // prevent sleep during OTA WiFi.softAP("MeshCore-OTA", NULL); sprintf(reply, "Started: http://%s/update", WiFi.softAPIP().toString().c_str()); diff --git a/src/helpers/ESP32Board.h b/src/helpers/ESP32Board.h index 01b4c980c..bade3e898 100644 --- a/src/helpers/ESP32Board.h +++ b/src/helpers/ESP32Board.h @@ -8,12 +8,12 @@ #include #include #include -#include "esp_wifi.h" #include "driver/rtc_io.h" class ESP32Board : public mesh::MainBoard { protected: uint8_t startup_reason; + bool inhibit_sleep = false; public: void begin() { @@ -72,11 +72,7 @@ class ESP32Board : public mesh::MainBoard { } void sleep(uint32_t secs) override { - // To check for WiFi status to see if there is active OTA - wifi_mode_t mode; - esp_err_t err = esp_wifi_get_mode(&mode); - - if (err != ESP_OK) { // WiFi is off ~ No active OTA, safe to go to sleep + if (!inhibit_sleep) { enterLightSleep(secs); // To wake up after "secs" seconds or when receiving a LoRa packet } } @@ -126,6 +122,10 @@ class ESP32Board : public mesh::MainBoard { } bool startOTAUpdate(const char* id, char reply[]) override; + + void setInhibitSleep(bool inhibit) { + inhibit_sleep = inhibit; + } }; class ESP32RTCClock : public mesh::RTCClock { From 019bbf74d336995653aa97cb15d2d5a7b3d612e9 Mon Sep 17 00:00:00 2001 From: agessaman Date: Thu, 29 Jan 2026 20:44:11 -0800 Subject: [PATCH 13/35] Add recv_errors to CMD_GET_STATS STATS_TYPE_PACKETS response Append uint32_t recv_errors (RadioLib receive/CRC errors) to packet stats binary frame. Frame size 26 -> 30 bytes. Update stats_binary_frames.md and Python/TypeScript parsing examples for backward compatibility (accept >=26). --- docs/stats_binary_frames.md | 26 +++++++++++++++++++++----- examples/companion_radio/MyMesh.cpp | 2 ++ 2 files changed, 23 insertions(+), 5 deletions(-) diff --git a/docs/stats_binary_frames.md b/docs/stats_binary_frames.md index 1b409912e..f3b17da96 100644 --- a/docs/stats_binary_frames.md +++ b/docs/stats_binary_frames.md @@ -94,7 +94,7 @@ struct StatsRadio { ## RESP_CODE_STATS + STATS_TYPE_PACKETS (24, 2) -**Total Frame Size:** 26 bytes +**Total Frame Size:** 26 bytes (legacy) or 30 bytes (includes `recv_errors`) | Offset | Size | Type | Field Name | Description | Range/Notes | |--------|------|------|------------|-------------|-------------| @@ -106,12 +106,14 @@ struct StatsRadio { | 14 | 4 | uint32_t | direct_tx | Packets sent via direct routing | 0 - 4,294,967,295 | | 18 | 4 | uint32_t | flood_rx | Packets received via flood routing | 0 - 4,294,967,295 | | 22 | 4 | uint32_t | direct_rx | Packets received via direct routing | 0 - 4,294,967,295 | +| 26 | 4 | uint32_t | recv_errors | Receive/CRC errors (RadioLib); present only in 30-byte frame | 0 - 4,294,967,295 | ### Notes - Counters are cumulative from boot and may wrap. - `recv = flood_rx + direct_rx` - `sent = flood_tx + direct_tx` +- Clients should accept frame length ≥ 26; if length ≥ 30, parse `recv_errors` at offset 26. ### Example Structure (C/C++) @@ -125,6 +127,7 @@ struct StatsPackets { uint32_t direct_tx; uint32_t flood_rx; uint32_t direct_rx; + uint32_t recv_errors; // present when frame size is 30 } __attribute__((packed)); ``` @@ -183,11 +186,12 @@ def parse_stats_radio(frame): } def parse_stats_packets(frame): - """Parse RESP_CODE_STATS + STATS_TYPE_PACKETS frame (26 bytes)""" + """Parse RESP_CODE_STATS + STATS_TYPE_PACKETS frame (26 or 30 bytes)""" + assert len(frame) >= 26, "STATS_TYPE_PACKETS frame too short" response_code, stats_type, recv, sent, flood_tx, direct_tx, flood_rx, direct_rx = \ - struct.unpack('= 30: + (recv_errors,) = struct.unpack('= 30) { + result.recv_errors = view.getUint32(26, true); + } + return result; } ``` diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 2dad7866a..cfe3b77d7 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1688,12 +1688,14 @@ void MyMesh::handleCmdFrame(size_t len) { uint32_t n_sent_direct = getNumSentDirect(); uint32_t n_recv_flood = getNumRecvFlood(); uint32_t n_recv_direct = getNumRecvDirect(); + uint32_t n_recv_errors = radio_driver.getPacketsRecvErrors(); memcpy(&out_frame[i], &recv, 4); i += 4; memcpy(&out_frame[i], &sent, 4); i += 4; memcpy(&out_frame[i], &n_sent_flood, 4); i += 4; memcpy(&out_frame[i], &n_sent_direct, 4); i += 4; memcpy(&out_frame[i], &n_recv_flood, 4); i += 4; memcpy(&out_frame[i], &n_recv_direct, 4); i += 4; + memcpy(&out_frame[i], &n_recv_errors, 4); i += 4; _serial->writeFrame(out_frame, i); } else { writeErrFrame(ERR_CODE_ILLEGAL_ARG); // invalid stats sub-type From c786cfe613b37506dc48caac9273171d8a4df5b1 Mon Sep 17 00:00:00 2001 From: ViezeVingertjes Date: Sat, 31 Jan 2026 10:22:32 +0100 Subject: [PATCH 14/35] Add KISS Modem firmware --- README.md | 2 + docs/kiss_modem_protocol.md | 110 +++++++++ examples/kiss_modem/KissModem.cpp | 362 ++++++++++++++++++++++++++++++ examples/kiss_modem/KissModem.h | 124 ++++++++++ examples/kiss_modem/main.cpp | 108 +++++++++ 5 files changed, 706 insertions(+) create mode 100644 docs/kiss_modem_protocol.md create mode 100644 examples/kiss_modem/KissModem.cpp create mode 100644 examples/kiss_modem/KissModem.h create mode 100644 examples/kiss_modem/main.cpp diff --git a/README.md b/README.md index d3bcbbef9..9d47bffe3 100644 --- a/README.md +++ b/README.md @@ -39,9 +39,11 @@ For developers; - Clone and open the MeshCore repository in Visual Studio Code. - See the example applications you can modify and run: - [Companion Radio](./examples/companion_radio) - For use with an external chat app, over BLE, USB or WiFi. + - [KISS Modem](./examples/kiss_modem) - Serial KISS protocol bridge for host applications. ([protocol docs](./docs/kiss_modem_protocol.md)) - [Simple Repeater](./examples/simple_repeater) - Extends network coverage by relaying messages. - [Simple Room Server](./examples/simple_room_server) - A simple BBS server for shared Posts. - [Simple Secure Chat](./examples/simple_secure_chat) - Secure terminal based text communication between devices. + - [Simple Sensor](./examples/simple_sensor) - Remote sensor node with telemetry and alerting. The Simple Secure Chat example can be interacted with through the Serial Monitor in Visual Studio Code, or with a Serial USB Terminal on Android. diff --git a/docs/kiss_modem_protocol.md b/docs/kiss_modem_protocol.md new file mode 100644 index 000000000..f85bfe6c1 --- /dev/null +++ b/docs/kiss_modem_protocol.md @@ -0,0 +1,110 @@ +# MeshCore KISS Modem Protocol + +Serial protocol for the KISS modem firmware. Enables sending/receiving MeshCore packets over LoRa and cryptographic operations using the modem's identity. + +## Serial Configuration + +115200 baud, 8N1, no flow control. + +## Frame Format + +Standard KISS framing with byte stuffing. + +| Byte | Name | Description | +|------|------|-------------| +| `0xC0` | FEND | Frame delimiter | +| `0xDB` | FESC | Escape character | +| `0xDC` | TFEND | Escaped FEND (FESC + TFEND = 0xC0) | +| `0xDD` | TFESC | Escaped FESC (FESC + TFESC = 0xDB) | + +``` +┌──────┬─────────┬──────────────┬──────┐ +│ FEND │ Command │ Data (escaped)│ FEND │ +│ 0xC0 │ 1 byte │ 0-510 bytes │ 0xC0 │ +└──────┴─────────┴──────────────┴──────┘ +``` + +Maximum unescaped frame size: 512 bytes. + +## Commands + +### Request Commands (Host → Modem) + +| Command | Value | Data | +|---------|-------|------| +| `CMD_DATA` | `0x00` | Packet (2-255 bytes) | +| `CMD_GET_IDENTITY` | `0x01` | - | +| `CMD_GET_RANDOM` | `0x02` | Length (1 byte, 1-64) | +| `CMD_VERIFY_SIGNATURE` | `0x03` | PubKey (32) + Signature (64) + Data | +| `CMD_SIGN_DATA` | `0x04` | Data to sign | +| `CMD_ENCRYPT_DATA` | `0x05` | Key (32) + Plaintext | +| `CMD_DECRYPT_DATA` | `0x06` | Key (32) + MAC (2) + Ciphertext | +| `CMD_KEY_EXCHANGE` | `0x07` | Remote PubKey (32) | +| `CMD_HASH` | `0x08` | Data to hash | +| `CMD_SET_RADIO` | `0x09` | Freq (4) + BW (4) + SF (1) + CR (1) | +| `CMD_SET_TX_POWER` | `0x0A` | Power dBm (1) | +| `CMD_SET_SYNC_WORD` | `0x0B` | Sync word (1) | +| `CMD_GET_RADIO` | `0x0C` | - | +| `CMD_GET_TX_POWER` | `0x0D` | - | +| `CMD_GET_SYNC_WORD` | `0x0E` | - | +| `CMD_GET_VERSION` | `0x0F` | - | + +### Response Commands (Modem → Host) + +| Command | Value | Data | +|---------|-------|------| +| `CMD_DATA` | `0x00` | SNR (1) + RSSI (1) + Packet | +| `RESP_IDENTITY` | `0x11` | PubKey (32) | +| `RESP_RANDOM` | `0x12` | Random bytes (1-64) | +| `RESP_VERIFY` | `0x13` | Result (1): 0x00=invalid, 0x01=valid | +| `RESP_SIGNATURE` | `0x14` | Signature (64) | +| `RESP_ENCRYPTED` | `0x15` | MAC (2) + Ciphertext | +| `RESP_DECRYPTED` | `0x16` | Plaintext | +| `RESP_SHARED_SECRET` | `0x17` | Shared secret (32) | +| `RESP_HASH` | `0x18` | SHA-256 hash (32) | +| `RESP_OK` | `0x19` | - | +| `RESP_RADIO` | `0x1A` | Freq (4) + BW (4) + SF (1) + CR (1) | +| `RESP_TX_POWER` | `0x1B` | Power dBm (1) | +| `RESP_SYNC_WORD` | `0x1C` | Sync word (1) | +| `RESP_VERSION` | `0x1D` | Version (1) + Reserved (1) | +| `RESP_ERROR` | `0x1E` | Error code (1) | +| `RESP_TX_DONE` | `0x1F` | Result (1): 0x00=failed, 0x01=success | + +## Error Codes + +| Code | Value | Description | +|------|-------|-------------| +| `ERR_INVALID_LENGTH` | `0x01` | Request data too short | +| `ERR_INVALID_PARAM` | `0x02` | Invalid parameter value | +| `ERR_NO_CALLBACK` | `0x03` | Radio callback not set | +| `ERR_MAC_FAILED` | `0x04` | MAC verification failed | +| `ERR_UNKNOWN_CMD` | `0x05` | Unknown command | +| `ERR_ENCRYPT_FAILED` | `0x06` | Encryption failed | + +## Data Formats + +### Radio Parameters (CMD_SET_RADIO / RESP_RADIO) + +All values little-endian. + +| Field | Size | Description | +|-------|------|-------------| +| Frequency | 4 bytes | Hz (e.g., 869618000) | +| Bandwidth | 4 bytes | Hz (e.g., 62500) | +| SF | 1 byte | Spreading factor (5-12) | +| CR | 1 byte | Coding rate (5-8) | + +### Received Packet (CMD_DATA response) + +| Field | Size | Description | +|-------|------|-------------| +| SNR | 1 byte | Signal-to-noise × 4, signed | +| RSSI | 1 byte | Signal strength dBm, signed | +| Packet | variable | Raw MeshCore packet | + +## Notes + +- Modem generates identity on first boot (stored in flash) +- SNR values multiplied by 4 for 0.25 dB precision +- Wait for `RESP_TX_DONE` before sending next packet +- See [packet_structure.md](./packet_structure.md) for packet format diff --git a/examples/kiss_modem/KissModem.cpp b/examples/kiss_modem/KissModem.cpp new file mode 100644 index 000000000..4e227d7f7 --- /dev/null +++ b/examples/kiss_modem/KissModem.cpp @@ -0,0 +1,362 @@ +#include "KissModem.h" + +KissModem::KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& rng) + : _serial(serial), _identity(identity), _rng(rng) { + _rx_len = 0; + _rx_escaped = false; + _rx_active = false; + _has_pending_tx = false; + _pending_tx_len = 0; + _setRadioCallback = nullptr; + _setTxPowerCallback = nullptr; + _setSyncWordCallback = nullptr; + _config = {0, 0, 0, 0, 0, 0x12}; +} + +void KissModem::begin() { + _rx_len = 0; + _rx_escaped = false; + _rx_active = false; + _has_pending_tx = false; +} + +void KissModem::writeByte(uint8_t b) { + if (b == KISS_FEND) { + _serial.write(KISS_FESC); + _serial.write(KISS_TFEND); + } else if (b == KISS_FESC) { + _serial.write(KISS_FESC); + _serial.write(KISS_TFESC); + } else { + _serial.write(b); + } +} + +void KissModem::writeFrame(uint8_t cmd, const uint8_t* data, uint16_t len) { + _serial.write(KISS_FEND); + writeByte(cmd); + for (uint16_t i = 0; i < len; i++) { + writeByte(data[i]); + } + _serial.write(KISS_FEND); +} + +void KissModem::writeErrorFrame(uint8_t error_code) { + writeFrame(RESP_ERROR, &error_code, 1); +} + +void KissModem::loop() { + while (_serial.available()) { + uint8_t b = _serial.read(); + + if (b == KISS_FEND) { + if (_rx_active && _rx_len > 0) { + processFrame(); + } + _rx_len = 0; + _rx_escaped = false; + _rx_active = true; + continue; + } + + if (!_rx_active) continue; + + if (b == KISS_FESC) { + _rx_escaped = true; + continue; + } + + if (_rx_escaped) { + _rx_escaped = false; + if (b == KISS_TFEND) b = KISS_FEND; + else if (b == KISS_TFESC) b = KISS_FESC; + } + + if (_rx_len < KISS_MAX_FRAME_SIZE) { + _rx_buf[_rx_len++] = b; + } + } +} + +void KissModem::processFrame() { + if (_rx_len < 1) return; + + uint8_t cmd = _rx_buf[0]; + const uint8_t* data = &_rx_buf[1]; + uint16_t data_len = _rx_len - 1; + + switch (cmd) { + case CMD_DATA: + if (data_len < 2) { + writeErrorFrame(ERR_INVALID_LENGTH); + } else if (data_len > KISS_MAX_PACKET_SIZE) { + writeErrorFrame(ERR_INVALID_LENGTH); + } else { + memcpy(_pending_tx, data, data_len); + _pending_tx_len = data_len; + _has_pending_tx = true; + } + break; + case CMD_GET_IDENTITY: + handleGetIdentity(); + break; + case CMD_GET_RANDOM: + handleGetRandom(data, data_len); + break; + case CMD_VERIFY_SIGNATURE: + handleVerifySignature(data, data_len); + break; + case CMD_SIGN_DATA: + handleSignData(data, data_len); + break; + case CMD_ENCRYPT_DATA: + handleEncryptData(data, data_len); + break; + case CMD_DECRYPT_DATA: + handleDecryptData(data, data_len); + break; + case CMD_KEY_EXCHANGE: + handleKeyExchange(data, data_len); + break; + case CMD_HASH: + handleHash(data, data_len); + break; + case CMD_SET_RADIO: + handleSetRadio(data, data_len); + break; + case CMD_SET_TX_POWER: + handleSetTxPower(data, data_len); + break; + case CMD_SET_SYNC_WORD: + handleSetSyncWord(data, data_len); + break; + case CMD_GET_RADIO: + handleGetRadio(); + break; + case CMD_GET_TX_POWER: + handleGetTxPower(); + break; + case CMD_GET_SYNC_WORD: + handleGetSyncWord(); + break; + case CMD_GET_VERSION: + handleGetVersion(); + break; + default: + writeErrorFrame(ERR_UNKNOWN_CMD); + break; + } +} + +void KissModem::handleGetIdentity() { + writeFrame(RESP_IDENTITY, _identity.pub_key, PUB_KEY_SIZE); +} + +void KissModem::handleGetRandom(const uint8_t* data, uint16_t len) { + if (len < 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + + uint8_t requested = data[0]; + if (requested < 1 || requested > 64) { + writeErrorFrame(ERR_INVALID_PARAM); + return; + } + + uint8_t buf[64]; + _rng.random(buf, requested); + writeFrame(RESP_RANDOM, buf, requested); +} + +void KissModem::handleVerifySignature(const uint8_t* data, uint16_t len) { + if (len < PUB_KEY_SIZE + SIGNATURE_SIZE + 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + + mesh::Identity signer(data); + const uint8_t* signature = data + PUB_KEY_SIZE; + const uint8_t* msg = data + PUB_KEY_SIZE + SIGNATURE_SIZE; + uint16_t msg_len = len - PUB_KEY_SIZE - SIGNATURE_SIZE; + + uint8_t result = signer.verify(signature, msg, msg_len) ? 0x01 : 0x00; + writeFrame(RESP_VERIFY, &result, 1); +} + +void KissModem::handleSignData(const uint8_t* data, uint16_t len) { + if (len < 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + + uint8_t signature[SIGNATURE_SIZE]; + _identity.sign(signature, data, len); + writeFrame(RESP_SIGNATURE, signature, SIGNATURE_SIZE); +} + +void KissModem::handleEncryptData(const uint8_t* data, uint16_t len) { + if (len < PUB_KEY_SIZE + 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + + const uint8_t* key = data; + const uint8_t* plaintext = data + PUB_KEY_SIZE; + uint16_t plaintext_len = len - PUB_KEY_SIZE; + + uint8_t buf[KISS_MAX_FRAME_SIZE]; + int encrypted_len = mesh::Utils::encryptThenMAC(key, buf, plaintext, plaintext_len); + + if (encrypted_len > 0) { + writeFrame(RESP_ENCRYPTED, buf, encrypted_len); + } else { + writeErrorFrame(ERR_ENCRYPT_FAILED); + } +} + +void KissModem::handleDecryptData(const uint8_t* data, uint16_t len) { + if (len < PUB_KEY_SIZE + CIPHER_MAC_SIZE + 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + + const uint8_t* key = data; + const uint8_t* ciphertext = data + PUB_KEY_SIZE; + uint16_t ciphertext_len = len - PUB_KEY_SIZE; + + uint8_t buf[KISS_MAX_FRAME_SIZE]; + int decrypted_len = mesh::Utils::MACThenDecrypt(key, buf, ciphertext, ciphertext_len); + + if (decrypted_len > 0) { + writeFrame(RESP_DECRYPTED, buf, decrypted_len); + } else { + writeErrorFrame(ERR_MAC_FAILED); + } +} + +void KissModem::handleKeyExchange(const uint8_t* data, uint16_t len) { + if (len < PUB_KEY_SIZE) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + + uint8_t shared_secret[PUB_KEY_SIZE]; + _identity.calcSharedSecret(shared_secret, data); + writeFrame(RESP_SHARED_SECRET, shared_secret, PUB_KEY_SIZE); +} + +void KissModem::handleHash(const uint8_t* data, uint16_t len) { + if (len < 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + + uint8_t hash[32]; + mesh::Utils::sha256(hash, 32, data, len); + writeFrame(RESP_HASH, hash, 32); +} + +bool KissModem::getPacketToSend(uint8_t* packet, uint16_t* len) { + if (!_has_pending_tx) return false; + + memcpy(packet, _pending_tx, _pending_tx_len); + *len = _pending_tx_len; + _has_pending_tx = false; + return true; +} + +void KissModem::onPacketReceived(int8_t snr, int8_t rssi, const uint8_t* packet, uint16_t len) { + uint8_t buf[2 + KISS_MAX_PACKET_SIZE]; + buf[0] = (uint8_t)snr; + buf[1] = (uint8_t)rssi; + memcpy(&buf[2], packet, len); + writeFrame(CMD_DATA, buf, 2 + len); +} + +void KissModem::handleSetRadio(const uint8_t* data, uint16_t len) { + if (len < 10) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + if (!_setRadioCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + uint32_t freq_hz, bw_hz; + memcpy(&freq_hz, data, 4); + memcpy(&bw_hz, data + 4, 4); + uint8_t sf = data[8]; + uint8_t cr = data[9]; + + _config.freq_hz = freq_hz; + _config.bw_hz = bw_hz; + _config.sf = sf; + _config.cr = cr; + + float freq = freq_hz / 1000000.0f; + float bw = bw_hz / 1000.0f; + + _setRadioCallback(freq, bw, sf, cr); + writeFrame(RESP_OK, nullptr, 0); +} + +void KissModem::handleSetTxPower(const uint8_t* data, uint16_t len) { + if (len < 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + if (!_setTxPowerCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + _config.tx_power = data[0]; + _setTxPowerCallback(data[0]); + writeFrame(RESP_OK, nullptr, 0); +} + +void KissModem::handleSetSyncWord(const uint8_t* data, uint16_t len) { + if (len < 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + if (!_setSyncWordCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + _config.sync_word = data[0]; + _setSyncWordCallback(data[0]); + writeFrame(RESP_OK, nullptr, 0); +} + +void KissModem::handleGetRadio() { + uint8_t buf[10]; + memcpy(buf, &_config.freq_hz, 4); + memcpy(buf + 4, &_config.bw_hz, 4); + buf[8] = _config.sf; + buf[9] = _config.cr; + writeFrame(RESP_RADIO, buf, 10); +} + +void KissModem::handleGetTxPower() { + writeFrame(RESP_TX_POWER, &_config.tx_power, 1); +} + +void KissModem::handleGetSyncWord() { + writeFrame(RESP_SYNC_WORD, &_config.sync_word, 1); +} + +void KissModem::handleGetVersion() { + uint8_t buf[2]; + buf[0] = KISS_FIRMWARE_VERSION; + buf[1] = 0; + writeFrame(RESP_VERSION, buf, 2); +} + +void KissModem::onTxComplete(bool success) { + uint8_t result = success ? 0x01 : 0x00; + writeFrame(RESP_TX_DONE, &result, 1); +} diff --git a/examples/kiss_modem/KissModem.h b/examples/kiss_modem/KissModem.h new file mode 100644 index 000000000..34d9577f5 --- /dev/null +++ b/examples/kiss_modem/KissModem.h @@ -0,0 +1,124 @@ +#pragma once + +#include +#include +#include + +#define KISS_FEND 0xC0 +#define KISS_FESC 0xDB +#define KISS_TFEND 0xDC +#define KISS_TFESC 0xDD + +#define KISS_MAX_FRAME_SIZE 512 +#define KISS_MAX_PACKET_SIZE 255 + +#define CMD_DATA 0x00 +#define CMD_GET_IDENTITY 0x01 +#define CMD_GET_RANDOM 0x02 +#define CMD_VERIFY_SIGNATURE 0x03 +#define CMD_SIGN_DATA 0x04 +#define CMD_ENCRYPT_DATA 0x05 +#define CMD_DECRYPT_DATA 0x06 +#define CMD_KEY_EXCHANGE 0x07 +#define CMD_HASH 0x08 +#define CMD_SET_RADIO 0x09 +#define CMD_SET_TX_POWER 0x0A +#define CMD_SET_SYNC_WORD 0x0B +#define CMD_GET_RADIO 0x0C +#define CMD_GET_TX_POWER 0x0D +#define CMD_GET_SYNC_WORD 0x0E +#define CMD_GET_VERSION 0x0F + +#define RESP_IDENTITY 0x11 +#define RESP_RANDOM 0x12 +#define RESP_VERIFY 0x13 +#define RESP_SIGNATURE 0x14 +#define RESP_ENCRYPTED 0x15 +#define RESP_DECRYPTED 0x16 +#define RESP_SHARED_SECRET 0x17 +#define RESP_HASH 0x18 +#define RESP_OK 0x19 +#define RESP_RADIO 0x1A +#define RESP_TX_POWER 0x1B +#define RESP_SYNC_WORD 0x1C +#define RESP_VERSION 0x1D +#define RESP_ERROR 0x1E +#define RESP_TX_DONE 0x1F + +#define ERR_INVALID_LENGTH 0x01 +#define ERR_INVALID_PARAM 0x02 +#define ERR_NO_CALLBACK 0x03 +#define ERR_MAC_FAILED 0x04 +#define ERR_UNKNOWN_CMD 0x05 +#define ERR_ENCRYPT_FAILED 0x06 + +#define KISS_FIRMWARE_VERSION 1 + +typedef void (*SetRadioCallback)(float freq, float bw, uint8_t sf, uint8_t cr); +typedef void (*SetTxPowerCallback)(uint8_t power); +typedef void (*SetSyncWordCallback)(uint8_t syncWord); + +struct RadioConfig { + uint32_t freq_hz; + uint32_t bw_hz; + uint8_t sf; + uint8_t cr; + uint8_t tx_power; + uint8_t sync_word; +}; + +class KissModem { + Stream& _serial; + mesh::LocalIdentity& _identity; + mesh::RNG& _rng; + + uint8_t _rx_buf[KISS_MAX_FRAME_SIZE]; + uint16_t _rx_len; + bool _rx_escaped; + bool _rx_active; + + uint8_t _pending_tx[KISS_MAX_PACKET_SIZE]; + uint16_t _pending_tx_len; + bool _has_pending_tx; + + SetRadioCallback _setRadioCallback; + SetTxPowerCallback _setTxPowerCallback; + SetSyncWordCallback _setSyncWordCallback; + + RadioConfig _config; + + void writeByte(uint8_t b); + void writeFrame(uint8_t cmd, const uint8_t* data, uint16_t len); + void writeErrorFrame(uint8_t error_code); + void processFrame(); + + void handleGetIdentity(); + void handleGetRandom(const uint8_t* data, uint16_t len); + void handleVerifySignature(const uint8_t* data, uint16_t len); + void handleSignData(const uint8_t* data, uint16_t len); + void handleEncryptData(const uint8_t* data, uint16_t len); + void handleDecryptData(const uint8_t* data, uint16_t len); + void handleKeyExchange(const uint8_t* data, uint16_t len); + void handleHash(const uint8_t* data, uint16_t len); + void handleSetRadio(const uint8_t* data, uint16_t len); + void handleSetTxPower(const uint8_t* data, uint16_t len); + void handleSetSyncWord(const uint8_t* data, uint16_t len); + void handleGetRadio(); + void handleGetTxPower(); + void handleGetSyncWord(); + void handleGetVersion(); + +public: + KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& rng); + + void begin(); + void loop(); + + void setRadioCallback(SetRadioCallback cb) { _setRadioCallback = cb; } + void setTxPowerCallback(SetTxPowerCallback cb) { _setTxPowerCallback = cb; } + void setSyncWordCallback(SetSyncWordCallback cb) { _setSyncWordCallback = cb; } + + bool getPacketToSend(uint8_t* packet, uint16_t* len); + void onPacketReceived(int8_t snr, int8_t rssi, const uint8_t* packet, uint16_t len); + void onTxComplete(bool success); +}; diff --git a/examples/kiss_modem/main.cpp b/examples/kiss_modem/main.cpp new file mode 100644 index 000000000..2f843a991 --- /dev/null +++ b/examples/kiss_modem/main.cpp @@ -0,0 +1,108 @@ +#include +#include +#include +#include +#include "KissModem.h" + +#if defined(NRF52_PLATFORM) + #include +#elif defined(RP2040_PLATFORM) + #include +#elif defined(ESP32) + #include +#endif + +StdRNG rng; +mesh::LocalIdentity identity; +KissModem* modem; + +void halt() { + while (1) ; +} + +void loadOrCreateIdentity() { +#if defined(NRF52_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 (!store.load("_main", identity)) { + identity = radio_new_identity(); + while (identity.pub_key[0] == 0x00 || identity.pub_key[0] == 0xFF) { + identity = radio_new_identity(); + } + store.save("_main", identity); + } +} + +void onSetRadio(float freq, float bw, uint8_t sf, uint8_t cr) { + radio_set_params(freq, bw, sf, cr); +} + +void onSetTxPower(uint8_t power) { + radio_set_tx_power(power); +} + +void onSetSyncWord(uint8_t sync_word) { + radio_set_sync_word(sync_word); +} + +void setup() { + board.begin(); + + if (!radio_init()) { + halt(); + } + + radio_driver.begin(); + + rng.begin(radio_get_rng_seed()); + loadOrCreateIdentity(); + + Serial.begin(115200); + uint32_t start = millis(); + while (!Serial && millis() - start < 3000) delay(10); + delay(100); + + modem = new KissModem(Serial, identity, rng); + modem->setRadioCallback(onSetRadio); + modem->setTxPowerCallback(onSetTxPower); + modem->setSyncWordCallback(onSetSyncWord); + modem->begin(); +} + +void loop() { + modem->loop(); + + uint8_t packet[KISS_MAX_PACKET_SIZE]; + uint16_t len; + + if (modem->getPacketToSend(packet, &len)) { + radio_driver.startSendRaw(packet, len); + while (!radio_driver.isSendComplete()) { + delay(1); + } + radio_driver.onSendFinished(); + modem->onTxComplete(true); + } + + uint8_t rx_buf[256]; + int rx_len = radio_driver.recvRaw(rx_buf, sizeof(rx_buf)); + + if (rx_len > 0) { + 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); + } + + radio_driver.loop(); +} From c5b1d30280c837214f18db2e19bfcae9151568a1 Mon Sep 17 00:00:00 2001 From: taco Date: Sat, 31 Jan 2026 23:48:28 +1100 Subject: [PATCH 15/35] t114: remove extra DCDC enable --- variants/heltec_t114/T114Board.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/variants/heltec_t114/T114Board.cpp b/variants/heltec_t114/T114Board.cpp index 2a36bd903..c03d39afb 100644 --- a/variants/heltec_t114/T114Board.cpp +++ b/variants/heltec_t114/T114Board.cpp @@ -34,7 +34,6 @@ void T114Board::initiateShutdown(uint8_t reason) { void T114Board::begin() { NRF52Board::begin(); - NRF_POWER->DCDCEN = 1; pinMode(PIN_VBAT_READ, INPUT); From e6e1b810f874491b1e7cf96869f5076069ddc6fa Mon Sep 17 00:00:00 2001 From: taco Date: Tue, 27 Jan 2026 17:51:30 +1100 Subject: [PATCH 16/35] add DataStore::deleteBlobByKey() --- examples/companion_radio/DataStore.cpp | 16 ++++++++++++++++ examples/companion_radio/DataStore.h | 1 + examples/companion_radio/MyMesh.cpp | 2 ++ 3 files changed, 19 insertions(+) diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index f61f53aee..6cc776717 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -560,6 +560,9 @@ bool DataStore::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src } return false; // error } +bool DataStore::deleteBlobByKey(const uint8_t key[], int key_len) { + return true; // this is just a stub on NRF52/STM32 platforms +} #else uint8_t DataStore::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { char path[64]; @@ -598,4 +601,17 @@ bool DataStore::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src } return false; // error } + +bool DataStore::deleteBlobByKey(const uint8_t key[], int key_len) { + char path[64]; + char fname[18]; + + if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) + mesh::Utils::toHex(fname, key, key_len); + sprintf(path, "/bl/%s", fname); + + _fs->remove(path); + + return true; // return true even if file did not exist +} #endif diff --git a/examples/companion_radio/DataStore.h b/examples/companion_radio/DataStore.h index 625809429..58b4d5d28 100644 --- a/examples/companion_radio/DataStore.h +++ b/examples/companion_radio/DataStore.h @@ -42,6 +42,7 @@ class DataStore { void migrateToSecondaryFS(); uint8_t getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]); bool putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], uint8_t len); + bool deleteBlobByKey(const uint8_t key[], int key_len); File openRead(const char* filename); File openRead(FILESYSTEM* fs, const char* filename); bool removeFile(const char* filename); diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 1e4115dad..9bb747e79 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -307,6 +307,7 @@ bool MyMesh::shouldOverwriteWhenFull() const { } void MyMesh::onContactOverwrite(const uint8_t* pub_key) { + _store->deleteBlobByKey(pub_key, PUB_KEY_SIZE); // delete from storage if (_serial->isConnected()) { out_frame[0] = PUSH_CODE_CONTACT_DELETED; memcpy(&out_frame[1], pub_key, PUB_KEY_SIZE); @@ -1124,6 +1125,7 @@ void MyMesh::handleCmdFrame(size_t len) { uint8_t *pub_key = &cmd_frame[1]; ContactInfo *recipient = lookupContactByPubKey(pub_key, PUB_KEY_SIZE); if (recipient && removeContact(*recipient)) { + _store->deleteBlobByKey(pub_key, PUB_KEY_SIZE); dirty_contacts_expiry = futureMillis(LAZY_CONTACTS_WRITE_DELAY); writeOKFrame(); } else { From 31ba971c60e7367de3265a0f006edacbc2ebbe4c Mon Sep 17 00:00:00 2001 From: taco Date: Tue, 27 Jan 2026 17:53:05 +1100 Subject: [PATCH 17/35] only store advblob when adding/updating contacts --- src/helpers/BaseChatMesh.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/helpers/BaseChatMesh.cpp b/src/helpers/BaseChatMesh.cpp index aebfc1b64..6de7469d0 100644 --- a/src/helpers/BaseChatMesh.cpp +++ b/src/helpers/BaseChatMesh.cpp @@ -131,7 +131,6 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, plen = packet->writeTo(temp_buf); packet->header = save; } - putBlobByKey(id.pub_key, PUB_KEY_SIZE, temp_buf, plen); bool is_new = false; // true = not in contacts[], false = exists in contacts[] if (from == NULL) { @@ -157,6 +156,7 @@ void BaseChatMesh::onAdvertRecv(mesh::Packet* packet, const mesh::Identity& id, from->shared_secret_valid = false; } // update + putBlobByKey(id.pub_key, PUB_KEY_SIZE, temp_buf, plen); StrHelper::strncpy(from->name, parser.getName(), sizeof(from->name)); from->type = parser.getType(); if (parser.hasLatLon()) { From 8d5eaf500d8e744d204339be078f10074213d9e2 Mon Sep 17 00:00:00 2001 From: taco Date: Tue, 27 Jan 2026 19:31:07 +1100 Subject: [PATCH 18/35] add makeBlobPath inline helper for esp32 --- examples/companion_radio/DataStore.cpp | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/examples/companion_radio/DataStore.cpp b/examples/companion_radio/DataStore.cpp index 6cc776717..c0f2c0212 100644 --- a/examples/companion_radio/DataStore.cpp +++ b/examples/companion_radio/DataStore.cpp @@ -564,13 +564,16 @@ bool DataStore::deleteBlobByKey(const uint8_t key[], int key_len) { return true; // this is just a stub on NRF52/STM32 platforms } #else -uint8_t DataStore::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { - char path[64]; +inline void makeBlobPath(const uint8_t key[], int key_len, char* path, size_t path_size) { char fname[18]; - if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) mesh::Utils::toHex(fname, key, key_len); sprintf(path, "/bl/%s", fname); +} + +uint8_t DataStore::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_buf[]) { + char path[64]; + makeBlobPath(key, key_len, path, sizeof(path)); if (_fs->exists(path)) { File f = openRead(_fs, path); @@ -585,11 +588,7 @@ uint8_t DataStore::getBlobByKey(const uint8_t key[], int key_len, uint8_t dest_b bool DataStore::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src_buf[], uint8_t len) { char path[64]; - char fname[18]; - - if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) - mesh::Utils::toHex(fname, key, key_len); - sprintf(path, "/bl/%s", fname); + makeBlobPath(key, key_len, path, sizeof(path)); File f = openWrite(_fs, path); if (f) { @@ -604,11 +603,7 @@ bool DataStore::putBlobByKey(const uint8_t key[], int key_len, const uint8_t src bool DataStore::deleteBlobByKey(const uint8_t key[], int key_len) { char path[64]; - char fname[18]; - - if (key_len > 8) key_len = 8; // just use first 8 bytes (prefix) - mesh::Utils::toHex(fname, key, key_len); - sprintf(path, "/bl/%s", fname); + makeBlobPath(key, key_len, path, sizeof(path)); _fs->remove(path); From b5248faec4872a52001ee1ed425492db043ee943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= Date: Sat, 31 Jan 2026 13:45:58 +0000 Subject: [PATCH 19/35] Revert "Merge pull request #1428 from etienn01/update-t114-i2c" This reverts commit 616eb57b163f2123727347ab0425e1ad4fbca564, reversing changes made to 537acd7ea144ee077595c1171cd96770eb924b67. This patch needs to be reverted because it boot freezes t114 433Mhz variant. --- variants/heltec_t114/variant.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/variants/heltec_t114/variant.h b/variants/heltec_t114/variant.h index ac9dbbe6e..aa7f40222 100644 --- a/variants/heltec_t114/variant.h +++ b/variants/heltec_t114/variant.h @@ -58,8 +58,8 @@ //////////////////////////////////////////////////////////////////////////////// // I2C pin definition -#define PIN_WIRE_SDA (16) // P0.16 -#define PIN_WIRE_SCL (13) // P0.13 +#define PIN_WIRE_SDA (26) // P0.26 +#define PIN_WIRE_SCL (27) // P0.27 //////////////////////////////////////////////////////////////////////////////// // SPI pin definition From 1bcb52bab318926b014d0a46d98ebc2f35ff5e3f Mon Sep 17 00:00:00 2001 From: ViezeVingertjes Date: Sat, 31 Jan 2026 15:05:25 +0100 Subject: [PATCH 20/35] Add new commands and responses for RSSI, channel status, airtime, noise floor, statistics, battery, and sensors. --- docs/kiss_modem_protocol.md | 74 +++++++++++++---- examples/kiss_modem/KissModem.cpp | 128 ++++++++++++++++++++++++++++++ examples/kiss_modem/KissModem.h | 78 ++++++++++++++---- examples/kiss_modem/main.cpp | 46 +++++++++++ 4 files changed, 294 insertions(+), 32 deletions(-) diff --git a/docs/kiss_modem_protocol.md b/docs/kiss_modem_protocol.md index f85bfe6c1..e80c3b29b 100644 --- a/docs/kiss_modem_protocol.md +++ b/docs/kiss_modem_protocol.md @@ -48,27 +48,43 @@ Maximum unescaped frame size: 512 bytes. | `CMD_GET_TX_POWER` | `0x0D` | - | | `CMD_GET_SYNC_WORD` | `0x0E` | - | | `CMD_GET_VERSION` | `0x0F` | - | +| `CMD_GET_CURRENT_RSSI` | `0x10` | - | +| `CMD_IS_CHANNEL_BUSY` | `0x11` | - | +| `CMD_GET_AIRTIME` | `0x12` | Packet length (1) | +| `CMD_GET_NOISE_FLOOR` | `0x13` | - | +| `CMD_GET_STATS` | `0x14` | - | +| `CMD_GET_BATTERY` | `0x15` | - | +| `CMD_PING` | `0x16` | - | +| `CMD_GET_SENSORS` | `0x17` | Permissions (1) | ### Response Commands (Modem → Host) | Command | Value | Data | |---------|-------|------| | `CMD_DATA` | `0x00` | SNR (1) + RSSI (1) + Packet | -| `RESP_IDENTITY` | `0x11` | PubKey (32) | -| `RESP_RANDOM` | `0x12` | Random bytes (1-64) | -| `RESP_VERIFY` | `0x13` | Result (1): 0x00=invalid, 0x01=valid | -| `RESP_SIGNATURE` | `0x14` | Signature (64) | -| `RESP_ENCRYPTED` | `0x15` | MAC (2) + Ciphertext | -| `RESP_DECRYPTED` | `0x16` | Plaintext | -| `RESP_SHARED_SECRET` | `0x17` | Shared secret (32) | -| `RESP_HASH` | `0x18` | SHA-256 hash (32) | -| `RESP_OK` | `0x19` | - | -| `RESP_RADIO` | `0x1A` | Freq (4) + BW (4) + SF (1) + CR (1) | -| `RESP_TX_POWER` | `0x1B` | Power dBm (1) | -| `RESP_SYNC_WORD` | `0x1C` | Sync word (1) | -| `RESP_VERSION` | `0x1D` | Version (1) + Reserved (1) | -| `RESP_ERROR` | `0x1E` | Error code (1) | -| `RESP_TX_DONE` | `0x1F` | Result (1): 0x00=failed, 0x01=success | +| `RESP_IDENTITY` | `0x21` | PubKey (32) | +| `RESP_RANDOM` | `0x22` | Random bytes (1-64) | +| `RESP_VERIFY` | `0x23` | Result (1): 0x00=invalid, 0x01=valid | +| `RESP_SIGNATURE` | `0x24` | Signature (64) | +| `RESP_ENCRYPTED` | `0x25` | MAC (2) + Ciphertext | +| `RESP_DECRYPTED` | `0x26` | Plaintext | +| `RESP_SHARED_SECRET` | `0x27` | Shared secret (32) | +| `RESP_HASH` | `0x28` | SHA-256 hash (32) | +| `RESP_OK` | `0x29` | - | +| `RESP_RADIO` | `0x2A` | Freq (4) + BW (4) + SF (1) + CR (1) | +| `RESP_TX_POWER` | `0x2B` | Power dBm (1) | +| `RESP_SYNC_WORD` | `0x2C` | Sync word (1) | +| `RESP_VERSION` | `0x2D` | Version (1) + Reserved (1) | +| `RESP_ERROR` | `0x2E` | Error code (1) | +| `RESP_TX_DONE` | `0x2F` | Result (1): 0x00=failed, 0x01=success | +| `RESP_CURRENT_RSSI` | `0x30` | RSSI dBm (1, signed) | +| `RESP_CHANNEL_BUSY` | `0x31` | Result (1): 0x00=clear, 0x01=busy | +| `RESP_AIRTIME` | `0x32` | Milliseconds (4) | +| `RESP_NOISE_FLOOR` | `0x33` | dBm (2, signed) | +| `RESP_STATS` | `0x34` | RX (4) + TX (4) + Errors (4) | +| `RESP_BATTERY` | `0x35` | Millivolts (2) | +| `RESP_PONG` | `0x36` | - | +| `RESP_SENSORS` | `0x37` | CayenneLPP payload | ## Error Codes @@ -76,10 +92,11 @@ Maximum unescaped frame size: 512 bytes. |------|-------|-------------| | `ERR_INVALID_LENGTH` | `0x01` | Request data too short | | `ERR_INVALID_PARAM` | `0x02` | Invalid parameter value | -| `ERR_NO_CALLBACK` | `0x03` | Radio callback not set | +| `ERR_NO_CALLBACK` | `0x03` | Feature not available | | `ERR_MAC_FAILED` | `0x04` | MAC verification failed | | `ERR_UNKNOWN_CMD` | `0x05` | Unknown command | | `ERR_ENCRYPT_FAILED` | `0x06` | Encryption failed | +| `ERR_TX_PENDING` | `0x07` | TX already pending | ## Data Formats @@ -102,9 +119,34 @@ All values little-endian. | RSSI | 1 byte | Signal strength dBm, signed | | Packet | variable | Raw MeshCore packet | +### Stats (RESP_STATS) + +All values little-endian. + +| Field | Size | Description | +|-------|------|-------------| +| RX | 4 bytes | Packets received | +| TX | 4 bytes | Packets transmitted | +| Errors | 4 bytes | Receive errors | + +### Sensor Permissions (CMD_GET_SENSORS) + +| Bit | Value | Description | +|-----|-------|-------------| +| 0 | `0x01` | Base (battery) | +| 1 | `0x02` | Location (GPS) | +| 2 | `0x04` | Environment (temp, humidity, pressure) | + +Use `0x07` for all permissions. + +### Sensor Data (RESP_SENSORS) + +Data returned in CayenneLPP format. See [CayenneLPP documentation](https://docs.mydevices.com/docs/lorawan/cayenne-lpp) for parsing. + ## Notes - Modem generates identity on first boot (stored in flash) - SNR values multiplied by 4 for 0.25 dB precision - Wait for `RESP_TX_DONE` before sending next packet +- Sending `CMD_DATA` while TX is pending returns `ERR_TX_PENDING` - See [packet_structure.md](./packet_structure.md) for packet format diff --git a/examples/kiss_modem/KissModem.cpp b/examples/kiss_modem/KissModem.cpp index 4e227d7f7..c6e2f2bdc 100644 --- a/examples/kiss_modem/KissModem.cpp +++ b/examples/kiss_modem/KissModem.cpp @@ -10,6 +10,13 @@ KissModem::KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& r _setRadioCallback = nullptr; _setTxPowerCallback = nullptr; _setSyncWordCallback = nullptr; + _getCurrentRssiCallback = nullptr; + _isChannelBusyCallback = nullptr; + _getAirtimeCallback = nullptr; + _getNoiseFloorCallback = nullptr; + _getStatsCallback = nullptr; + _getBatteryCallback = nullptr; + _getSensorsCallback = nullptr; _config = {0, 0, 0, 0, 0, 0x12}; } @@ -91,6 +98,8 @@ void KissModem::processFrame() { writeErrorFrame(ERR_INVALID_LENGTH); } else if (data_len > KISS_MAX_PACKET_SIZE) { writeErrorFrame(ERR_INVALID_LENGTH); + } else if (_has_pending_tx) { + writeErrorFrame(ERR_TX_PENDING); } else { memcpy(_pending_tx, data, data_len); _pending_tx_len = data_len; @@ -142,6 +151,30 @@ void KissModem::processFrame() { case CMD_GET_VERSION: handleGetVersion(); break; + case CMD_GET_CURRENT_RSSI: + handleGetCurrentRssi(); + break; + case CMD_IS_CHANNEL_BUSY: + handleIsChannelBusy(); + break; + case CMD_GET_AIRTIME: + handleGetAirtime(data, data_len); + break; + case CMD_GET_NOISE_FLOOR: + handleGetNoiseFloor(); + break; + case CMD_GET_STATS: + handleGetStats(); + break; + case CMD_GET_BATTERY: + handleGetBattery(); + break; + case CMD_PING: + handlePing(); + break; + case CMD_GET_SENSORS: + handleGetSensors(data, data_len); + break; default: writeErrorFrame(ERR_UNKNOWN_CMD); break; @@ -360,3 +393,98 @@ void KissModem::onTxComplete(bool success) { uint8_t result = success ? 0x01 : 0x00; writeFrame(RESP_TX_DONE, &result, 1); } + +void KissModem::handleGetCurrentRssi() { + if (!_getCurrentRssiCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + float rssi = _getCurrentRssiCallback(); + int8_t rssi_byte = (int8_t)rssi; + writeFrame(RESP_CURRENT_RSSI, (uint8_t*)&rssi_byte, 1); +} + +void KissModem::handleIsChannelBusy() { + if (!_isChannelBusyCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + uint8_t busy = _isChannelBusyCallback() ? 0x01 : 0x00; + writeFrame(RESP_CHANNEL_BUSY, &busy, 1); +} + +void KissModem::handleGetAirtime(const uint8_t* data, uint16_t len) { + if (len < 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + if (!_getAirtimeCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + uint8_t packet_len = data[0]; + uint32_t airtime = _getAirtimeCallback(packet_len); + writeFrame(RESP_AIRTIME, (uint8_t*)&airtime, 4); +} + +void KissModem::handleGetNoiseFloor() { + if (!_getNoiseFloorCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + int16_t noise_floor = _getNoiseFloorCallback(); + writeFrame(RESP_NOISE_FLOOR, (uint8_t*)&noise_floor, 2); +} + +void KissModem::handleGetStats() { + if (!_getStatsCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + uint32_t rx, tx, errors; + _getStatsCallback(&rx, &tx, &errors); + uint8_t buf[12]; + memcpy(buf, &rx, 4); + memcpy(buf + 4, &tx, 4); + memcpy(buf + 8, &errors, 4); + writeFrame(RESP_STATS, buf, 12); +} + +void KissModem::handleGetBattery() { + if (!_getBatteryCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + uint16_t mv = _getBatteryCallback(); + writeFrame(RESP_BATTERY, (uint8_t*)&mv, 2); +} + +void KissModem::handlePing() { + writeFrame(RESP_PONG, nullptr, 0); +} + +void KissModem::handleGetSensors(const uint8_t* data, uint16_t len) { + if (len < 1) { + writeErrorFrame(ERR_INVALID_LENGTH); + return; + } + if (!_getSensorsCallback) { + writeErrorFrame(ERR_NO_CALLBACK); + return; + } + + uint8_t permissions = data[0]; + uint8_t buf[255]; + uint8_t result_len = _getSensorsCallback(permissions, buf, 255); + if (result_len > 0) { + writeFrame(RESP_SENSORS, buf, result_len); + } else { + writeFrame(RESP_SENSORS, nullptr, 0); + } +} diff --git a/examples/kiss_modem/KissModem.h b/examples/kiss_modem/KissModem.h index 34d9577f5..e223d92d1 100644 --- a/examples/kiss_modem/KissModem.h +++ b/examples/kiss_modem/KissModem.h @@ -28,22 +28,38 @@ #define CMD_GET_TX_POWER 0x0D #define CMD_GET_SYNC_WORD 0x0E #define CMD_GET_VERSION 0x0F +#define CMD_GET_CURRENT_RSSI 0x10 +#define CMD_IS_CHANNEL_BUSY 0x11 +#define CMD_GET_AIRTIME 0x12 +#define CMD_GET_NOISE_FLOOR 0x13 +#define CMD_GET_STATS 0x14 +#define CMD_GET_BATTERY 0x15 +#define CMD_PING 0x16 +#define CMD_GET_SENSORS 0x17 -#define RESP_IDENTITY 0x11 -#define RESP_RANDOM 0x12 -#define RESP_VERIFY 0x13 -#define RESP_SIGNATURE 0x14 -#define RESP_ENCRYPTED 0x15 -#define RESP_DECRYPTED 0x16 -#define RESP_SHARED_SECRET 0x17 -#define RESP_HASH 0x18 -#define RESP_OK 0x19 -#define RESP_RADIO 0x1A -#define RESP_TX_POWER 0x1B -#define RESP_SYNC_WORD 0x1C -#define RESP_VERSION 0x1D -#define RESP_ERROR 0x1E -#define RESP_TX_DONE 0x1F +#define RESP_IDENTITY 0x21 +#define RESP_RANDOM 0x22 +#define RESP_VERIFY 0x23 +#define RESP_SIGNATURE 0x24 +#define RESP_ENCRYPTED 0x25 +#define RESP_DECRYPTED 0x26 +#define RESP_SHARED_SECRET 0x27 +#define RESP_HASH 0x28 +#define RESP_OK 0x29 +#define RESP_RADIO 0x2A +#define RESP_TX_POWER 0x2B +#define RESP_SYNC_WORD 0x2C +#define RESP_VERSION 0x2D +#define RESP_ERROR 0x2E +#define RESP_TX_DONE 0x2F +#define RESP_CURRENT_RSSI 0x30 +#define RESP_CHANNEL_BUSY 0x31 +#define RESP_AIRTIME 0x32 +#define RESP_NOISE_FLOOR 0x33 +#define RESP_STATS 0x34 +#define RESP_BATTERY 0x35 +#define RESP_PONG 0x36 +#define RESP_SENSORS 0x37 #define ERR_INVALID_LENGTH 0x01 #define ERR_INVALID_PARAM 0x02 @@ -51,12 +67,20 @@ #define ERR_MAC_FAILED 0x04 #define ERR_UNKNOWN_CMD 0x05 #define ERR_ENCRYPT_FAILED 0x06 +#define ERR_TX_PENDING 0x07 -#define KISS_FIRMWARE_VERSION 1 +#define KISS_FIRMWARE_VERSION 2 typedef void (*SetRadioCallback)(float freq, float bw, uint8_t sf, uint8_t cr); typedef void (*SetTxPowerCallback)(uint8_t power); typedef void (*SetSyncWordCallback)(uint8_t syncWord); +typedef float (*GetCurrentRssiCallback)(); +typedef bool (*IsChannelBusyCallback)(); +typedef uint32_t (*GetAirtimeCallback)(uint8_t len); +typedef int16_t (*GetNoiseFloorCallback)(); +typedef void (*GetStatsCallback)(uint32_t* rx, uint32_t* tx, uint32_t* errors); +typedef uint16_t (*GetBatteryCallback)(); +typedef uint8_t (*GetSensorsCallback)(uint8_t permissions, uint8_t* buffer, uint8_t max_len); struct RadioConfig { uint32_t freq_hz; @@ -84,6 +108,13 @@ class KissModem { SetRadioCallback _setRadioCallback; SetTxPowerCallback _setTxPowerCallback; SetSyncWordCallback _setSyncWordCallback; + GetCurrentRssiCallback _getCurrentRssiCallback; + IsChannelBusyCallback _isChannelBusyCallback; + GetAirtimeCallback _getAirtimeCallback; + GetNoiseFloorCallback _getNoiseFloorCallback; + GetStatsCallback _getStatsCallback; + GetBatteryCallback _getBatteryCallback; + GetSensorsCallback _getSensorsCallback; RadioConfig _config; @@ -107,6 +138,14 @@ class KissModem { void handleGetTxPower(); void handleGetSyncWord(); void handleGetVersion(); + void handleGetCurrentRssi(); + void handleIsChannelBusy(); + void handleGetAirtime(const uint8_t* data, uint16_t len); + void handleGetNoiseFloor(); + void handleGetStats(); + void handleGetBattery(); + void handlePing(); + void handleGetSensors(const uint8_t* data, uint16_t len); public: KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& rng); @@ -117,6 +156,13 @@ class KissModem { void setRadioCallback(SetRadioCallback cb) { _setRadioCallback = cb; } void setTxPowerCallback(SetTxPowerCallback cb) { _setTxPowerCallback = cb; } void setSyncWordCallback(SetSyncWordCallback cb) { _setSyncWordCallback = cb; } + void setGetCurrentRssiCallback(GetCurrentRssiCallback cb) { _getCurrentRssiCallback = cb; } + void setIsChannelBusyCallback(IsChannelBusyCallback cb) { _isChannelBusyCallback = cb; } + void setGetAirtimeCallback(GetAirtimeCallback cb) { _getAirtimeCallback = cb; } + void setGetNoiseFloorCallback(GetNoiseFloorCallback cb) { _getNoiseFloorCallback = cb; } + void setGetStatsCallback(GetStatsCallback cb) { _getStatsCallback = cb; } + void setGetBatteryCallback(GetBatteryCallback cb) { _getBatteryCallback = cb; } + void setGetSensorsCallback(GetSensorsCallback cb) { _getSensorsCallback = cb; } bool getPacketToSend(uint8_t* packet, uint16_t* len); void onPacketReceived(int8_t snr, int8_t rssi, const uint8_t* packet, uint16_t len); diff --git a/examples/kiss_modem/main.cpp b/examples/kiss_modem/main.cpp index 2f843a991..0a54c9d35 100644 --- a/examples/kiss_modem/main.cpp +++ b/examples/kiss_modem/main.cpp @@ -2,6 +2,7 @@ #include #include #include +#include #include "KissModem.h" #if defined(NRF52_PLATFORM) @@ -56,6 +57,42 @@ void onSetSyncWord(uint8_t sync_word) { radio_set_sync_word(sync_word); } +float onGetCurrentRssi() { + return radio_driver.getCurrentRSSI(); +} + +bool onIsChannelBusy() { + return radio_driver.isReceiving(); +} + +uint32_t onGetAirtime(uint8_t len) { + return radio_driver.getEstAirtimeFor(len); +} + +int16_t onGetNoiseFloor() { + return radio_driver.getNoiseFloor(); +} + +void onGetStats(uint32_t* rx, uint32_t* tx, uint32_t* errors) { + *rx = radio_driver.getPacketsRecv(); + *tx = radio_driver.getPacketsSent(); + *errors = radio_driver.getPacketsRecvErrors(); +} + +uint16_t onGetBattery() { + return board.getBattMilliVolts(); +} + +uint8_t onGetSensors(uint8_t permissions, uint8_t* buffer, uint8_t max_len) { + CayenneLPP telemetry(max_len); + if (sensors.querySensors(permissions, telemetry)) { + uint8_t len = telemetry.getSize(); + memcpy(buffer, telemetry.getBuffer(), len); + return len; + } + return 0; +} + void setup() { board.begin(); @@ -73,10 +110,19 @@ void setup() { while (!Serial && millis() - start < 3000) delay(10); delay(100); + sensors.begin(); + modem = new KissModem(Serial, identity, rng); modem->setRadioCallback(onSetRadio); modem->setTxPowerCallback(onSetTxPower); modem->setSyncWordCallback(onSetSyncWord); + modem->setGetCurrentRssiCallback(onGetCurrentRssi); + modem->setIsChannelBusyCallback(onIsChannelBusy); + modem->setGetAirtimeCallback(onGetAirtime); + modem->setGetNoiseFloorCallback(onGetNoiseFloor); + modem->setGetStatsCallback(onGetStats); + modem->setGetBatteryCallback(onGetBattery); + modem->setGetSensorsCallback(onGetSensors); modem->begin(); } From 240b5ea1e33fdc44808c87a268e4295cfa474ded Mon Sep 17 00:00:00 2001 From: ViezeVingertjes Date: Sat, 31 Jan 2026 15:08:25 +0100 Subject: [PATCH 21/35] Refactor KissModem to integrate radio and sensor management directly, removing callback dependencies. --- examples/kiss_modem/KissModem.cpp | 49 +++++++------------------------ examples/kiss_modem/KissModem.h | 25 +++++----------- examples/kiss_modem/main.cpp | 34 +-------------------- 3 files changed, 20 insertions(+), 88 deletions(-) diff --git a/examples/kiss_modem/KissModem.cpp b/examples/kiss_modem/KissModem.cpp index c6e2f2bdc..d11e8217d 100644 --- a/examples/kiss_modem/KissModem.cpp +++ b/examples/kiss_modem/KissModem.cpp @@ -1,7 +1,9 @@ #include "KissModem.h" +#include -KissModem::KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& rng) - : _serial(serial), _identity(identity), _rng(rng) { +KissModem::KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& rng, + mesh::Radio& radio, mesh::MainBoard& board, SensorManager& sensors) + : _serial(serial), _identity(identity), _rng(rng), _radio(radio), _board(board), _sensors(sensors) { _rx_len = 0; _rx_escaped = false; _rx_active = false; @@ -11,12 +13,7 @@ KissModem::KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& r _setTxPowerCallback = nullptr; _setSyncWordCallback = nullptr; _getCurrentRssiCallback = nullptr; - _isChannelBusyCallback = nullptr; - _getAirtimeCallback = nullptr; - _getNoiseFloorCallback = nullptr; _getStatsCallback = nullptr; - _getBatteryCallback = nullptr; - _getSensorsCallback = nullptr; _config = {0, 0, 0, 0, 0, 0x12}; } @@ -406,12 +403,7 @@ void KissModem::handleGetCurrentRssi() { } void KissModem::handleIsChannelBusy() { - if (!_isChannelBusyCallback) { - writeErrorFrame(ERR_NO_CALLBACK); - return; - } - - uint8_t busy = _isChannelBusyCallback() ? 0x01 : 0x00; + uint8_t busy = _radio.isReceiving() ? 0x01 : 0x00; writeFrame(RESP_CHANNEL_BUSY, &busy, 1); } @@ -420,23 +412,14 @@ void KissModem::handleGetAirtime(const uint8_t* data, uint16_t len) { writeErrorFrame(ERR_INVALID_LENGTH); return; } - if (!_getAirtimeCallback) { - writeErrorFrame(ERR_NO_CALLBACK); - return; - } uint8_t packet_len = data[0]; - uint32_t airtime = _getAirtimeCallback(packet_len); + uint32_t airtime = _radio.getEstAirtimeFor(packet_len); writeFrame(RESP_AIRTIME, (uint8_t*)&airtime, 4); } void KissModem::handleGetNoiseFloor() { - if (!_getNoiseFloorCallback) { - writeErrorFrame(ERR_NO_CALLBACK); - return; - } - - int16_t noise_floor = _getNoiseFloorCallback(); + int16_t noise_floor = _radio.getNoiseFloor(); writeFrame(RESP_NOISE_FLOOR, (uint8_t*)&noise_floor, 2); } @@ -456,12 +439,7 @@ void KissModem::handleGetStats() { } void KissModem::handleGetBattery() { - if (!_getBatteryCallback) { - writeErrorFrame(ERR_NO_CALLBACK); - return; - } - - uint16_t mv = _getBatteryCallback(); + uint16_t mv = _board.getBattMilliVolts(); writeFrame(RESP_BATTERY, (uint8_t*)&mv, 2); } @@ -474,16 +452,11 @@ void KissModem::handleGetSensors(const uint8_t* data, uint16_t len) { writeErrorFrame(ERR_INVALID_LENGTH); return; } - if (!_getSensorsCallback) { - writeErrorFrame(ERR_NO_CALLBACK); - return; - } uint8_t permissions = data[0]; - uint8_t buf[255]; - uint8_t result_len = _getSensorsCallback(permissions, buf, 255); - if (result_len > 0) { - writeFrame(RESP_SENSORS, buf, result_len); + CayenneLPP telemetry(255); + if (_sensors.querySensors(permissions, telemetry)) { + writeFrame(RESP_SENSORS, telemetry.getBuffer(), telemetry.getSize()); } else { writeFrame(RESP_SENSORS, nullptr, 0); } diff --git a/examples/kiss_modem/KissModem.h b/examples/kiss_modem/KissModem.h index e223d92d1..bc7560f48 100644 --- a/examples/kiss_modem/KissModem.h +++ b/examples/kiss_modem/KissModem.h @@ -3,6 +3,8 @@ #include #include #include +#include +#include #define KISS_FEND 0xC0 #define KISS_FESC 0xDB @@ -69,18 +71,13 @@ #define ERR_ENCRYPT_FAILED 0x06 #define ERR_TX_PENDING 0x07 -#define KISS_FIRMWARE_VERSION 2 +#define KISS_FIRMWARE_VERSION 1 typedef void (*SetRadioCallback)(float freq, float bw, uint8_t sf, uint8_t cr); typedef void (*SetTxPowerCallback)(uint8_t power); typedef void (*SetSyncWordCallback)(uint8_t syncWord); typedef float (*GetCurrentRssiCallback)(); -typedef bool (*IsChannelBusyCallback)(); -typedef uint32_t (*GetAirtimeCallback)(uint8_t len); -typedef int16_t (*GetNoiseFloorCallback)(); typedef void (*GetStatsCallback)(uint32_t* rx, uint32_t* tx, uint32_t* errors); -typedef uint16_t (*GetBatteryCallback)(); -typedef uint8_t (*GetSensorsCallback)(uint8_t permissions, uint8_t* buffer, uint8_t max_len); struct RadioConfig { uint32_t freq_hz; @@ -95,6 +92,9 @@ class KissModem { Stream& _serial; mesh::LocalIdentity& _identity; mesh::RNG& _rng; + mesh::Radio& _radio; + mesh::MainBoard& _board; + SensorManager& _sensors; uint8_t _rx_buf[KISS_MAX_FRAME_SIZE]; uint16_t _rx_len; @@ -109,12 +109,7 @@ class KissModem { SetTxPowerCallback _setTxPowerCallback; SetSyncWordCallback _setSyncWordCallback; GetCurrentRssiCallback _getCurrentRssiCallback; - IsChannelBusyCallback _isChannelBusyCallback; - GetAirtimeCallback _getAirtimeCallback; - GetNoiseFloorCallback _getNoiseFloorCallback; GetStatsCallback _getStatsCallback; - GetBatteryCallback _getBatteryCallback; - GetSensorsCallback _getSensorsCallback; RadioConfig _config; @@ -148,7 +143,8 @@ class KissModem { void handleGetSensors(const uint8_t* data, uint16_t len); public: - KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& rng); + KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& rng, + mesh::Radio& radio, mesh::MainBoard& board, SensorManager& sensors); void begin(); void loop(); @@ -157,12 +153,7 @@ class KissModem { void setTxPowerCallback(SetTxPowerCallback cb) { _setTxPowerCallback = cb; } void setSyncWordCallback(SetSyncWordCallback cb) { _setSyncWordCallback = cb; } void setGetCurrentRssiCallback(GetCurrentRssiCallback cb) { _getCurrentRssiCallback = cb; } - void setIsChannelBusyCallback(IsChannelBusyCallback cb) { _isChannelBusyCallback = cb; } - void setGetAirtimeCallback(GetAirtimeCallback cb) { _getAirtimeCallback = cb; } - void setGetNoiseFloorCallback(GetNoiseFloorCallback cb) { _getNoiseFloorCallback = cb; } void setGetStatsCallback(GetStatsCallback cb) { _getStatsCallback = cb; } - void setGetBatteryCallback(GetBatteryCallback cb) { _getBatteryCallback = cb; } - void setGetSensorsCallback(GetSensorsCallback cb) { _getSensorsCallback = cb; } bool getPacketToSend(uint8_t* packet, uint16_t* len); void onPacketReceived(int8_t snr, int8_t rssi, const uint8_t* packet, uint16_t len); diff --git a/examples/kiss_modem/main.cpp b/examples/kiss_modem/main.cpp index 0a54c9d35..e81161bf3 100644 --- a/examples/kiss_modem/main.cpp +++ b/examples/kiss_modem/main.cpp @@ -2,7 +2,6 @@ #include #include #include -#include #include "KissModem.h" #if defined(NRF52_PLATFORM) @@ -61,38 +60,12 @@ float onGetCurrentRssi() { return radio_driver.getCurrentRSSI(); } -bool onIsChannelBusy() { - return radio_driver.isReceiving(); -} - -uint32_t onGetAirtime(uint8_t len) { - return radio_driver.getEstAirtimeFor(len); -} - -int16_t onGetNoiseFloor() { - return radio_driver.getNoiseFloor(); -} - void onGetStats(uint32_t* rx, uint32_t* tx, uint32_t* errors) { *rx = radio_driver.getPacketsRecv(); *tx = radio_driver.getPacketsSent(); *errors = radio_driver.getPacketsRecvErrors(); } -uint16_t onGetBattery() { - return board.getBattMilliVolts(); -} - -uint8_t onGetSensors(uint8_t permissions, uint8_t* buffer, uint8_t max_len) { - CayenneLPP telemetry(max_len); - if (sensors.querySensors(permissions, telemetry)) { - uint8_t len = telemetry.getSize(); - memcpy(buffer, telemetry.getBuffer(), len); - return len; - } - return 0; -} - void setup() { board.begin(); @@ -112,17 +85,12 @@ void setup() { sensors.begin(); - modem = new KissModem(Serial, identity, rng); + modem = new KissModem(Serial, identity, rng, radio_driver, board, sensors); modem->setRadioCallback(onSetRadio); modem->setTxPowerCallback(onSetTxPower); modem->setSyncWordCallback(onSetSyncWord); modem->setGetCurrentRssiCallback(onGetCurrentRssi); - modem->setIsChannelBusyCallback(onIsChannelBusy); - modem->setGetAirtimeCallback(onGetAirtime); - modem->setGetNoiseFloorCallback(onGetNoiseFloor); modem->setGetStatsCallback(onGetStats); - modem->setGetBatteryCallback(onGetBattery); - modem->setGetSensorsCallback(onGetSensors); modem->begin(); } From a342ab8437e19ea792e51e46cd14c333c1c8b609 Mon Sep 17 00:00:00 2001 From: taco Date: Sun, 1 Feb 2026 14:46:55 +1100 Subject: [PATCH 22/35] nrf52: allow repeater to sleep when idle --- examples/simple_repeater/main.cpp | 9 ++++++--- src/helpers/NRF52Board.cpp | 26 ++++++++++++++++++++++++++ src/helpers/NRF52Board.h | 1 + 3 files changed, 33 insertions(+), 3 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index d55d61186..eb4b5b098 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -127,14 +127,17 @@ void loop() { #endif rtc_clock.tick(); - if (the_mesh.getNodePrefs()->powersaving_enabled && // To check if power saving is enabled - the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep - if (!the_mesh.hasPendingWork()) { // No pending work. Safe to sleep + if (the_mesh.getNodePrefs()->powersaving_enabled && !the_mesh.hasPendingWork()) { + #if defined(NRF52_PLATFORM) + board.sleep(1800); // nrf ignores seconds param, sleeps whenever possible + #else + if (the_mesh.millisHasNowPassed(lastActive + nextSleepinSecs * 1000)) { // To check if it is time to sleep board.sleep(1800); // To sleep. Wake up after 30 minutes or when receiving a LoRa packet lastActive = millis(); nextSleepinSecs = 5; // Default: To work for 5s and sleep again } else { nextSleepinSecs += 5; // When there is pending work, to work another 5s } + #endif } } diff --git a/src/helpers/NRF52Board.cpp b/src/helpers/NRF52Board.cpp index 6915c8563..1db858f50 100644 --- a/src/helpers/NRF52Board.cpp +++ b/src/helpers/NRF52Board.cpp @@ -251,6 +251,32 @@ void NRF52BoardDCDC::begin() { } } +void NRF52Board::sleep(uint32_t secs) { + // Clear FPU interrupt flags to avoid insomnia + // see errata 87 for details https://docs.nordicsemi.com/bundle/errata_nRF52840_Rev3/page/ERR/nRF52840/Rev3/latest/anomaly_840_87.html + #if (__FPU_USED == 1) + __set_FPSCR(__get_FPSCR() & ~(0x0000009F)); + (void) __get_FPSCR(); + NVIC_ClearPendingIRQ(FPU_IRQn); + #endif + + // On nRF52, we use event-driven sleep instead of timed sleep + // The 'secs' parameter is ignored - we wake on any interrupt + uint8_t sd_enabled = 0; + sd_softdevice_is_enabled(&sd_enabled); + + if (sd_enabled) { + // first call processes pending softdevice events, second call sleeps. + sd_app_evt_wait(); + sd_app_evt_wait(); + } else { + // softdevice is disabled, use raw WFE + __SEV(); + __WFE(); + __WFE(); + } +} + // Temperature from NRF52 MCU float NRF52Board::getMCUTemperature() { NRF_TEMP->TASKS_START = 1; // Start temperature measurement diff --git a/src/helpers/NRF52Board.h b/src/helpers/NRF52Board.h index 1c70d8f05..0332af078 100644 --- a/src/helpers/NRF52Board.h +++ b/src/helpers/NRF52Board.h @@ -51,6 +51,7 @@ class NRF52Board : public mesh::MainBoard { virtual float getMCUTemperature() override; virtual void reboot() override { NVIC_SystemReset(); } virtual bool startOTAUpdate(const char *id, char reply[]) override; + virtual void sleep(uint32_t secs) override; #ifdef NRF52_POWER_MANAGEMENT bool isExternalPowered() override; From 223930765cbb0dabcd171444f54db6f6d6771cf1 Mon Sep 17 00:00:00 2001 From: Jan Pinkas Date: Sun, 1 Feb 2026 09:00:01 +0100 Subject: [PATCH 23/35] Enable I2C sensors and EnvironmentSensorManager for Heltec T114 --- variants/heltec_t114/platformio.ini | 5 +++ variants/heltec_t114/target.cpp | 67 +++-------------------------- variants/heltec_t114/target.h | 18 ++------ 3 files changed, 14 insertions(+), 76 deletions(-) diff --git a/variants/heltec_t114/platformio.ini b/variants/heltec_t114/platformio.ini index 20f5e8fec..dd1f8bb3c 100644 --- a/variants/heltec_t114/platformio.ini +++ b/variants/heltec_t114/platformio.ini @@ -6,6 +6,7 @@ extends = nrf52_base board = heltec_t114 board_build.ldscript = boards/nrf52840_s140_v6.ld build_flags = ${nrf52_base.build_flags} + ${sensor_base.build_flags} -I lib/nrf52/s140_nrf52_6.1.1_API/include -I lib/nrf52/s140_nrf52_6.1.1_API/include/nrf52 -I variants/heltec_t114 @@ -35,11 +36,15 @@ build_flags = ${nrf52_base.build_flags} -D PIN_GPS_EN=21 -D PIN_GPS_RESET=38 -D PIN_GPS_RESET_ACTIVE=LOW + -D PIN_BOARD_SDA=16 + -D PIN_BOARD_SCL=13 build_src_filter = ${nrf52_base.build_src_filter} + + + +<../variants/heltec_t114> lib_deps = ${nrf52_base.lib_deps} + ${sensor_base.lib_deps} stevemarple/MicroNMEA @ ^2.0.6 adafruit/Adafruit GFX Library @ ^1.12.1 debug_tool = jlink diff --git a/variants/heltec_t114/target.cpp b/variants/heltec_t114/target.cpp index c3341103a..23b9b667b 100644 --- a/variants/heltec_t114/target.cpp +++ b/variants/heltec_t114/target.cpp @@ -45,26 +45,12 @@ mesh::LocalIdentity radio_new_identity() { return mesh::LocalIdentity(&rng); // create new random identity } -void T114SensorManager::start_gps() { - if (!gps_active) { - gps_active = true; - _location->begin(); - } -} - -void T114SensorManager::stop_gps() { - if (gps_active) { - gps_active = false; - _location->stop(); - } -} - bool T114SensorManager::begin() { Serial1.begin(9600); // Try to detect if GPS is physically connected to determine if we should expose the setting - pinMode(GPS_EN, OUTPUT); - digitalWrite(GPS_EN, HIGH); // Power on GPS + pinMode(PIN_GPS_EN, OUTPUT); + digitalWrite(PIN_GPS_EN, HIGH); // Power on GPS // Give GPS a moment to power up and send data delay(1500); @@ -77,57 +63,16 @@ bool T114SensorManager::begin() { } else { MESH_DEBUG_PRINTLN("No GPS detected"); } - digitalWrite(GPS_EN, LOW); // Power off GPS until the setting is changed + digitalWrite(PIN_GPS_EN, LOW); // Power off GPS until the setting is changed - return true; + return EnvironmentSensorManager::begin(); } bool T114SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { + EnvironmentSensorManager::querySensors(requester_permissions, telemetry); + if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); } return true; } - -void T114SensorManager::loop() { - static long next_gps_update = 0; - - _location->loop(); - - if (millis() > next_gps_update) { - if (_location->isValid()) { - node_lat = ((double)_location->getLatitude())/1000000.; - node_lon = ((double)_location->getLongitude())/1000000.; - node_altitude = ((double)_location->getAltitude()) / 1000.0; - MESH_DEBUG_PRINTLN("lat %f lon %f", node_lat, node_lon); - } - next_gps_update = millis() + 1000; - } -} - -int T114SensorManager::getNumSettings() const { - return gps_detected ? 1 : 0; // only show GPS setting if GPS is detected -} - -const char* T114SensorManager::getSettingName(int i) const { - return (gps_detected && i == 0) ? "gps" : NULL; -} - -const char* T114SensorManager::getSettingValue(int i) const { - if (gps_detected && i == 0) { - return gps_active ? "1" : "0"; - } - return NULL; -} - -bool T114SensorManager::setSettingValue(const char* name, const char* value) { - if (gps_detected && strcmp(name, "gps") == 0) { - if (strcmp(value, "0") == 0) { - stop_gps(); - } else { - start_gps(); - } - return true; - } - return false; // not supported -} diff --git a/variants/heltec_t114/target.h b/variants/heltec_t114/target.h index 6306cd699..24de81eee 100644 --- a/variants/heltec_t114/target.h +++ b/variants/heltec_t114/target.h @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #ifdef DISPLAY_CLASS @@ -18,23 +18,11 @@ #endif #endif -class T114SensorManager : public SensorManager { - bool gps_active = false; - bool gps_detected = false; - LocationProvider* _location; - - void start_gps(); - void stop_gps(); +class T114SensorManager : public EnvironmentSensorManager { public: - T114SensorManager(LocationProvider &location): _location(&location) { } + T114SensorManager(LocationProvider &location): EnvironmentSensorManager(location) { } bool begin() override; bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; - void loop() override; - LocationProvider* getLocationProvider() override { return gps_detected ? _location : NULL; } - int getNumSettings() const override; - const char* getSettingName(int i) const override; - const char* getSettingValue(int i) const override; - bool setSettingValue(const char* name, const char* value) override; }; extern T114Board board; From f0ba14ff7580fd8dfc866ec0490606485390cb3c Mon Sep 17 00:00:00 2001 From: ViezeVingertjes Date: Mon, 2 Feb 2026 18:05:26 +0100 Subject: [PATCH 24/35] Remove sync word handling from KissModem. --- examples/kiss_modem/KissModem.cpp | 28 +--------------------------- examples/kiss_modem/KissModem.h | 9 --------- examples/kiss_modem/main.cpp | 5 ----- 3 files changed, 1 insertion(+), 41 deletions(-) diff --git a/examples/kiss_modem/KissModem.cpp b/examples/kiss_modem/KissModem.cpp index d11e8217d..d9c71bf85 100644 --- a/examples/kiss_modem/KissModem.cpp +++ b/examples/kiss_modem/KissModem.cpp @@ -11,10 +11,9 @@ KissModem::KissModem(Stream& serial, mesh::LocalIdentity& identity, mesh::RNG& r _pending_tx_len = 0; _setRadioCallback = nullptr; _setTxPowerCallback = nullptr; - _setSyncWordCallback = nullptr; _getCurrentRssiCallback = nullptr; _getStatsCallback = nullptr; - _config = {0, 0, 0, 0, 0, 0x12}; + _config = {0, 0, 0, 0, 0}; } void KissModem::begin() { @@ -133,18 +132,12 @@ void KissModem::processFrame() { case CMD_SET_TX_POWER: handleSetTxPower(data, data_len); break; - case CMD_SET_SYNC_WORD: - handleSetSyncWord(data, data_len); - break; case CMD_GET_RADIO: handleGetRadio(); break; case CMD_GET_TX_POWER: handleGetTxPower(); break; - case CMD_GET_SYNC_WORD: - handleGetSyncWord(); - break; case CMD_GET_VERSION: handleGetVersion(); break; @@ -347,21 +340,6 @@ void KissModem::handleSetTxPower(const uint8_t* data, uint16_t len) { writeFrame(RESP_OK, nullptr, 0); } -void KissModem::handleSetSyncWord(const uint8_t* data, uint16_t len) { - if (len < 1) { - writeErrorFrame(ERR_INVALID_LENGTH); - return; - } - if (!_setSyncWordCallback) { - writeErrorFrame(ERR_NO_CALLBACK); - return; - } - - _config.sync_word = data[0]; - _setSyncWordCallback(data[0]); - writeFrame(RESP_OK, nullptr, 0); -} - void KissModem::handleGetRadio() { uint8_t buf[10]; memcpy(buf, &_config.freq_hz, 4); @@ -375,10 +353,6 @@ void KissModem::handleGetTxPower() { writeFrame(RESP_TX_POWER, &_config.tx_power, 1); } -void KissModem::handleGetSyncWord() { - writeFrame(RESP_SYNC_WORD, &_config.sync_word, 1); -} - void KissModem::handleGetVersion() { uint8_t buf[2]; buf[0] = KISS_FIRMWARE_VERSION; diff --git a/examples/kiss_modem/KissModem.h b/examples/kiss_modem/KissModem.h index bc7560f48..170bb0c2a 100644 --- a/examples/kiss_modem/KissModem.h +++ b/examples/kiss_modem/KissModem.h @@ -25,10 +25,8 @@ #define CMD_HASH 0x08 #define CMD_SET_RADIO 0x09 #define CMD_SET_TX_POWER 0x0A -#define CMD_SET_SYNC_WORD 0x0B #define CMD_GET_RADIO 0x0C #define CMD_GET_TX_POWER 0x0D -#define CMD_GET_SYNC_WORD 0x0E #define CMD_GET_VERSION 0x0F #define CMD_GET_CURRENT_RSSI 0x10 #define CMD_IS_CHANNEL_BUSY 0x11 @@ -50,7 +48,6 @@ #define RESP_OK 0x29 #define RESP_RADIO 0x2A #define RESP_TX_POWER 0x2B -#define RESP_SYNC_WORD 0x2C #define RESP_VERSION 0x2D #define RESP_ERROR 0x2E #define RESP_TX_DONE 0x2F @@ -75,7 +72,6 @@ typedef void (*SetRadioCallback)(float freq, float bw, uint8_t sf, uint8_t cr); typedef void (*SetTxPowerCallback)(uint8_t power); -typedef void (*SetSyncWordCallback)(uint8_t syncWord); typedef float (*GetCurrentRssiCallback)(); typedef void (*GetStatsCallback)(uint32_t* rx, uint32_t* tx, uint32_t* errors); @@ -85,7 +81,6 @@ struct RadioConfig { uint8_t sf; uint8_t cr; uint8_t tx_power; - uint8_t sync_word; }; class KissModem { @@ -107,7 +102,6 @@ class KissModem { SetRadioCallback _setRadioCallback; SetTxPowerCallback _setTxPowerCallback; - SetSyncWordCallback _setSyncWordCallback; GetCurrentRssiCallback _getCurrentRssiCallback; GetStatsCallback _getStatsCallback; @@ -128,10 +122,8 @@ class KissModem { void handleHash(const uint8_t* data, uint16_t len); void handleSetRadio(const uint8_t* data, uint16_t len); void handleSetTxPower(const uint8_t* data, uint16_t len); - void handleSetSyncWord(const uint8_t* data, uint16_t len); void handleGetRadio(); void handleGetTxPower(); - void handleGetSyncWord(); void handleGetVersion(); void handleGetCurrentRssi(); void handleIsChannelBusy(); @@ -151,7 +143,6 @@ class KissModem { void setRadioCallback(SetRadioCallback cb) { _setRadioCallback = cb; } void setTxPowerCallback(SetTxPowerCallback cb) { _setTxPowerCallback = cb; } - void setSyncWordCallback(SetSyncWordCallback cb) { _setSyncWordCallback = cb; } void setGetCurrentRssiCallback(GetCurrentRssiCallback cb) { _getCurrentRssiCallback = cb; } void setGetStatsCallback(GetStatsCallback cb) { _getStatsCallback = cb; } diff --git a/examples/kiss_modem/main.cpp b/examples/kiss_modem/main.cpp index e81161bf3..959222b9f 100644 --- a/examples/kiss_modem/main.cpp +++ b/examples/kiss_modem/main.cpp @@ -52,10 +52,6 @@ void onSetTxPower(uint8_t power) { radio_set_tx_power(power); } -void onSetSyncWord(uint8_t sync_word) { - radio_set_sync_word(sync_word); -} - float onGetCurrentRssi() { return radio_driver.getCurrentRSSI(); } @@ -88,7 +84,6 @@ void setup() { modem = new KissModem(Serial, identity, rng, radio_driver, board, sensors); modem->setRadioCallback(onSetRadio); modem->setTxPowerCallback(onSetTxPower); - modem->setSyncWordCallback(onSetSyncWord); modem->setGetCurrentRssiCallback(onGetCurrentRssi); modem->setGetStatsCallback(onGetStats); modem->begin(); From 84e68cf4cb2dc06f83c861863621e0749ff18700 Mon Sep 17 00:00:00 2001 From: Rastislav Vysoky Date: Mon, 2 Feb 2026 22:58:55 +0100 Subject: [PATCH 25/35] initial port of M5Stack Unit C6L, update pioarduino to newer bugfix release --- platformio.ini | 6 +- variants/m5stack_unit_c6l/UnitC6LBoard.cpp | 49 ++++++++++ variants/m5stack_unit_c6l/UnitC6LBoard.h | 15 +++ variants/m5stack_unit_c6l/platformio.ini | 104 +++++++++++++++++++++ variants/m5stack_unit_c6l/target.h | 21 +++++ 5 files changed, 192 insertions(+), 3 deletions(-) create mode 100644 variants/m5stack_unit_c6l/UnitC6LBoard.cpp create mode 100644 variants/m5stack_unit_c6l/UnitC6LBoard.h create mode 100644 variants/m5stack_unit_c6l/platformio.ini create mode 100644 variants/m5stack_unit_c6l/target.h diff --git a/platformio.ini b/platformio.ini index 743e357af..69883271d 100644 --- a/platformio.ini +++ b/platformio.ini @@ -68,10 +68,10 @@ lib_deps = file://arch/esp32/AsyncElegantOTA ; esp32c6 uses arduino framework 3.x -; WARNING: experimental. pioarduino on esp32c6 needs work - it's not considered stable and has issues. +; WARNING: experimental. May not work as stable as other platforms. [esp32c6_base] extends = esp32_base -platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.12/platform-espressif32.zip +platform = https://github.com/pioarduino/platform-espressif32/releases/download/53.03.13-1/platform-espressif32.zip ; ----------------- NRF52 --------------------- @@ -80,7 +80,7 @@ extends = arduino_base platform = nordicnrf52 platform_packages = framework-arduinoadafruitnrf52 @ 1.10700.0 -extra_scripts = +extra_scripts = create-uf2.py arch/nrf52/extra_scripts/patch_bluefruit.py build_flags = ${arduino_base.build_flags} diff --git a/variants/m5stack_unit_c6l/UnitC6LBoard.cpp b/variants/m5stack_unit_c6l/UnitC6LBoard.cpp new file mode 100644 index 000000000..6538ef484 --- /dev/null +++ b/variants/m5stack_unit_c6l/UnitC6LBoard.cpp @@ -0,0 +1,49 @@ +#include +#include "target.h" + +UnitC6LBoard board; + +#if defined(P_LORA_SCLK) + static SPIClass spi(0); + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi); +#else + RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); +#endif + +WRAPPER_CLASS radio_driver(radio, board); + +ESP32RTCClock fallback_clock; +AutoDiscoverRTCClock rtc_clock(fallback_clock); +SensorManager sensors; + +bool radio_init() { + fallback_clock.begin(); + rtc_clock.begin(Wire); + +#if defined(P_LORA_SCLK) + spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); + return radio.std_init(&spi); +#else + return radio.std_init(); +#endif +} + +uint32_t radio_get_rng_seed() { + return radio.random(0x7FFFFFFF); +} + +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { + radio.setFrequency(freq); + radio.setSpreadingFactor(sf); + radio.setBandwidth(bw); + radio.setCodingRate(cr); +} + +void radio_set_tx_power(uint8_t dbm) { + radio.setOutputPower(dbm); +} + +mesh::LocalIdentity radio_new_identity() { + RadioNoiseListener rng(radio); + return mesh::LocalIdentity(&rng); // create new random identity +} diff --git a/variants/m5stack_unit_c6l/UnitC6LBoard.h b/variants/m5stack_unit_c6l/UnitC6LBoard.h new file mode 100644 index 000000000..a4ea3ee6e --- /dev/null +++ b/variants/m5stack_unit_c6l/UnitC6LBoard.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +class UnitC6LBoard : public ESP32Board { +public: + void begin() { + ESP32Board::begin(); + } + + const char* getManufacturerName() const override { + return "Unit C6L"; + } +}; diff --git a/variants/m5stack_unit_c6l/platformio.ini b/variants/m5stack_unit_c6l/platformio.ini new file mode 100644 index 000000000..bbfdb4a11 --- /dev/null +++ b/variants/m5stack_unit_c6l/platformio.ini @@ -0,0 +1,104 @@ +[M5Stack_Unit_C6L] +extends = esp32c6_base +board = esp32-c6-devkitm-1 +board_build.partitions = min_spiffs.csv ; get around 4mb flash limit +build_flags = + ${esp32c6_base.build_flags} + ${sensor_base.build_flags} + -I variants/M5Stack_Unit_C6L + -D P_LORA_TX_LED=15 + -D P_LORA_SCLK=20 + -D P_LORA_MISO=22 + -D P_LORA_MOSI=21 + -D P_LORA_NSS=23 + -D P_LORA_DIO_1=7 + -D P_LORA_BUSY=19 + -D P_LORA_RESET=-1 + -D PIN_BUZZER=11 + -D PIN_BOARD_SDA=16 + -D PIN_BOARD_SCL=17 + -D SX126X_RXEN=5 + -D SX126X_DIO2_AS_RF_SWITCH=true + -D SX126X_DIO3_TCXO_VOLTAGE=1.8 + -D SX126X_CURRENT_LIMIT=140 + -D SX126X_RX_BOOSTED_GAIN=1 + -D RADIO_CLASS=CustomSX1262 + -D WRAPPER_CLASS=CustomSX1262Wrapper + -D LORA_TX_POWER=22 + -D DISABLE_WIFI_OTA=1 + -D GPS_RX=4 + -D GPS_TX=5 +build_src_filter = ${esp32c6_base.build_src_filter} + +<../variants/m5stack_unit_c6l> + + +lib_deps = + ${esp32c6_base.lib_deps} + ${sensor_base.lib_deps} + +[env:M5Stack_Unit_C6L_repeater] +extends = M5Stack_Unit_C6L +build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} + +<../examples/simple_repeater/*.cpp> +build_flags = + ${M5Stack_Unit_C6L.build_flags} + -D ADVERT_NAME='"Unit C6L Repeater"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D MAX_NEIGHBOURS=50 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${M5Stack_Unit_C6L.lib_deps} +; ${esp32_ota.lib_deps} + +[env:M5Stack_Unit_C6L_room_server] +extends = M5Stack_Unit_C6L +build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} + +<../examples/simple_room_server> +build_flags = + ${M5Stack_Unit_C6L.build_flags} + -D ADVERT_NAME='"Unit C6L Room"' + -D ADVERT_LAT=0.0 + -D ADVERT_LON=0.0 + -D ADMIN_PASSWORD='"password"' + -D ROOM_PASSWORD='"hello"' +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +lib_deps = + ${M5Stack_Unit_C6L.lib_deps} +; ${esp32_ota.lib_deps} + +[env:M5Stack_Unit_C6L_companion_radio_ble] +extends = M5Stack_Unit_C6L +build_flags = ${M5Stack_Unit_C6L.build_flags} + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D BLE_PIN_CODE=123456 + -D BLE_DEBUG_LOGGING=1 + -D OFFLINE_QUEUE_SIZE=256 +; -D MESH_PACKET_LOGGING=1 +; -D MESH_DEBUG=1 +build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} + + + - + +<../examples/companion_radio/*.cpp> +lib_deps = + ${M5Stack_Unit_C6L.lib_deps} + densaugeo/base64 @ ~1.4.0 + end2endzone/NonBlockingRTTTL@^1.3.0 + +[env:M5Stack_Unit_C6L_companion_radio_usb] +extends = M5Stack_Unit_C6L +build_flags = ${M5Stack_Unit_C6L.build_flags} + -D MAX_CONTACTS=350 + -D MAX_GROUP_CHANNELS=40 + -D OFFLINE_QUEUE_SIZE=256 +build_src_filter = ${M5Stack_Unit_C6L.build_src_filter} + + + - + +<../examples/companion_radio/*.cpp> +lib_deps = + ${M5Stack_Unit_C6L.lib_deps} + densaugeo/base64 @ ~1.4.0 + end2endzone/NonBlockingRTTTL@^1.3.0 diff --git a/variants/m5stack_unit_c6l/target.h b/variants/m5stack_unit_c6l/target.h new file mode 100644 index 000000000..1f4e9ae32 --- /dev/null +++ b/variants/m5stack_unit_c6l/target.h @@ -0,0 +1,21 @@ +#pragma once + +#define RADIOLIB_STATIC_ONLY 1 +#include +#include +#include +#include +#include +#include +#include + +extern UnitC6LBoard board; +extern WRAPPER_CLASS radio_driver; +extern AutoDiscoverRTCClock rtc_clock; +extern SensorManager sensors; + +bool radio_init(); +uint32_t radio_get_rng_seed(); +void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); +void radio_set_tx_power(uint8_t dbm); +mesh::LocalIdentity radio_new_identity(); From 598489be471e978ea76d6f759f6367124a0b335a Mon Sep 17 00:00:00 2001 From: taco Date: Mon, 26 Jan 2026 16:41:08 +1100 Subject: [PATCH 26/35] refactor ui with ring buffer and display most recent --- examples/companion_radio/ui-new/UITask.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 0690b45ac..ae2d93753 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -458,15 +458,17 @@ class MsgPreviewScreen : public UIScreen { }; #define MAX_UNREAD_MSGS 32 int num_unread; + int head = MAX_UNREAD_MSGS - 1; // index of latest unread message MsgEntry unread[MAX_UNREAD_MSGS]; public: MsgPreviewScreen(UITask* task, mesh::RTCClock* rtc) : _task(task), _rtc(rtc) { num_unread = 0; } void addPreview(uint8_t path_len, const char* from_name, const char* msg) { - if (num_unread >= MAX_UNREAD_MSGS) return; // full + head = (head + 1) % MAX_UNREAD_MSGS; + if (num_unread < MAX_UNREAD_MSGS) num_unread++; - auto p = &unread[num_unread++]; + auto p = &unread[head]; p->timestamp = _rtc->getCurrentTime(); if (path_len == 0xFF) { sprintf(p->origin, "(D) %s:", from_name); @@ -484,7 +486,7 @@ class MsgPreviewScreen : public UIScreen { sprintf(tmp, "Unread: %d", num_unread); display.print(tmp); - auto p = &unread[0]; + auto p = &unread[head]; int secs = _rtc->getCurrentTime() - p->timestamp; if (secs < 60) { @@ -520,14 +522,10 @@ class MsgPreviewScreen : public UIScreen { bool handleInput(char c) override { if (c == KEY_NEXT || c == KEY_RIGHT) { + head = (head + MAX_UNREAD_MSGS - 1) % MAX_UNREAD_MSGS; num_unread--; if (num_unread == 0) { _task->gotoHomeScreen(); - } else { - // delete first/curr item from unread queue - for (int i = 0; i < num_unread; i++) { - unread[i] = unread[i + 1]; - } } return true; } From 0fb570338f57b6b2fdb5426f92e6e61c58e9db38 Mon Sep 17 00:00:00 2001 From: agessaman Date: Tue, 3 Feb 2026 20:58:37 -0800 Subject: [PATCH 27/35] fix(kiss): periodic noise floor calibration and AGC reset - Trigger noise floor calibration every 2s and AGC reset every 30s in main loop. - Reorder loop to match Dispatcher: calibrate + radio.loop() before AGC reset and recvRaw() so RSSI is never sampled right after startReceive(). - Update protocol doc with calibration intervals and typical noise floor range. - Variant platformio.ini updates (heltec_v3, rak4631). --- docs/kiss_modem_protocol.md | 20 ++++++++++++++++---- examples/kiss_modem/main.cpp | 23 +++++++++++++++++++---- variants/heltec_v3/platformio.ini | 9 +++++++++ variants/rak4631/platformio.ini | 11 ++++++++++- 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/docs/kiss_modem_protocol.md b/docs/kiss_modem_protocol.md index e80c3b29b..067e15397 100644 --- a/docs/kiss_modem_protocol.md +++ b/docs/kiss_modem_protocol.md @@ -28,6 +28,8 @@ Maximum unescaped frame size: 512 bytes. ## Commands +Command and response codes below are taken from `examples/kiss_modem/KissModem.h` and the switch in `KissModem::processFrame()`. + ### Request Commands (Host → Modem) | Command | Value | Data | @@ -43,10 +45,10 @@ Maximum unescaped frame size: 512 bytes. | `CMD_HASH` | `0x08` | Data to hash | | `CMD_SET_RADIO` | `0x09` | Freq (4) + BW (4) + SF (1) + CR (1) | | `CMD_SET_TX_POWER` | `0x0A` | Power dBm (1) | -| `CMD_SET_SYNC_WORD` | `0x0B` | Sync word (1) | +| *reserved* | `0x0B` | *(not implemented)* | | `CMD_GET_RADIO` | `0x0C` | - | | `CMD_GET_TX_POWER` | `0x0D` | - | -| `CMD_GET_SYNC_WORD` | `0x0E` | - | +| *reserved* | `0x0E` | *(not implemented)* | | `CMD_GET_VERSION` | `0x0F` | - | | `CMD_GET_CURRENT_RSSI` | `0x10` | - | | `CMD_IS_CHANNEL_BUSY` | `0x11` | - | @@ -73,7 +75,7 @@ Maximum unescaped frame size: 512 bytes. | `RESP_OK` | `0x29` | - | | `RESP_RADIO` | `0x2A` | Freq (4) + BW (4) + SF (1) + CR (1) | | `RESP_TX_POWER` | `0x2B` | Power dBm (1) | -| `RESP_SYNC_WORD` | `0x2C` | Sync word (1) | +| *reserved* | `0x2C` | *(not implemented)* | | `RESP_VERSION` | `0x2D` | Version (1) + Reserved (1) | | `RESP_ERROR` | `0x2E` | Error code (1) | | `RESP_TX_DONE` | `0x2F` | Result (1): 0x00=failed, 0x01=success | @@ -119,9 +121,19 @@ All values little-endian. | RSSI | 1 byte | Signal strength dBm, signed | | Packet | variable | Raw MeshCore packet | +### Noise Floor (RESP_NOISE_FLOOR) + +Response to `CMD_GET_NOISE_FLOOR` (0x13). Little-endian. + +| Field | Size | Description | +|--------------|------|--------------------------------| +| Noise floor | 2 | int16_t, dBm (signed), e.g. -120 | + +The modem recalibrates the noise floor periodically (every 2 s) from RX samples when idle. The receiver AGC is also reset periodically (every 30 s) so RSSI and noise floor do not drift to the minimum (-120). Typical range after calibration is about -120 to -90 dBm. Values may be 0 or briefly stale until the radio has been in receive mode long enough to collect 64 samples. + ### Stats (RESP_STATS) -All values little-endian. +Response to `CMD_GET_STATS` (0x14). All values little-endian. | Field | Size | Description | |-------|------|-------------| diff --git a/examples/kiss_modem/main.cpp b/examples/kiss_modem/main.cpp index 959222b9f..13855309b 100644 --- a/examples/kiss_modem/main.cpp +++ b/examples/kiss_modem/main.cpp @@ -12,9 +12,14 @@ #include #endif +#define NOISE_FLOOR_CALIB_INTERVAL_MS 2000 // match Dispatcher default +#define AGC_RESET_INTERVAL_MS 30000 // periodic RX restart so AGC doesn't drift (repeater uses same via prefs) + 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) ; @@ -94,7 +99,16 @@ void loop() { uint8_t packet[KISS_MAX_PACKET_SIZE]; uint16_t len; - + + // Match Dispatcher order: noise floor calib + loop() first, so we never sample RSSI in the same + // iteration as startReceive() (AGC reset -> recvRaw below). Sampling right after startReceive() + // can yield settling/cold RSSI and drive the floor toward -120. + if ((uint32_t)(millis() - next_noise_floor_calib_ms) >= NOISE_FLOOR_CALIB_INTERVAL_MS) { + radio_driver.triggerNoiseFloorCalibrate(0); // 0 = no interference threshold (KISS has no prefs) + next_noise_floor_calib_ms = millis(); + } + radio_driver.loop(); + if (modem->getPacketToSend(packet, &len)) { radio_driver.startSendRaw(packet, len); while (!radio_driver.isSendComplete()) { @@ -104,14 +118,15 @@ void loop() { modem->onTxComplete(true); } + if ((uint32_t)(millis() - next_agc_reset_ms) >= AGC_RESET_INTERVAL_MS) { + radio_driver.resetAGC(); // next recvRaw() will startReceive() and reset AGC so RSSI/noise floor don't stick at -120 + 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) { 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); } - - radio_driver.loop(); } diff --git a/variants/heltec_v3/platformio.ini b/variants/heltec_v3/platformio.ini index 6b61eff5d..4d299104e 100644 --- a/variants/heltec_v3/platformio.ini +++ b/variants/heltec_v3/platformio.ini @@ -367,3 +367,12 @@ build_src_filter = ${Heltec_lora32_v3.build_src_filter} lib_deps = ${Heltec_lora32_v3.lib_deps} ${esp32_ota.lib_deps} + +[env:Heltec_v3_kiss_modem] +extends = Heltec_lora32_v3 +build_flags = + ${Heltec_lora32_v3.build_flags} +build_src_filter = ${Heltec_lora32_v3.build_src_filter} + +<../examples/kiss_modem/> +lib_deps = + ${Heltec_lora32_v3.lib_deps} \ No newline at end of file diff --git a/variants/rak4631/platformio.ini b/variants/rak4631/platformio.ini index 9a9ab2dd3..737ef5652 100644 --- a/variants/rak4631/platformio.ini +++ b/variants/rak4631/platformio.ini @@ -183,4 +183,13 @@ build_flags = -D MESH_DEBUG=1 build_src_filter = ${rak4631.build_src_filter} + - +<../examples/simple_sensor> \ No newline at end of file + +<../examples/simple_sensor> + +[env:RAK_4631_kiss_modem] +extends = rak4631 +build_flags = + ${rak4631.build_flags} +build_src_filter = ${rak4631.build_src_filter} + +<../examples/kiss_modem/> +lib_deps = + ${rak4631.lib_deps} \ No newline at end of file From 5cb26b91f6b35ebb452887fa458513790052ff57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= Date: Thu, 5 Feb 2026 13:35:04 +0000 Subject: [PATCH 28/35] Refactor Heltec T114 sensor management --- examples/simple_repeater/main.cpp | 7 ++++ variants/heltec_t114/platformio.ini | 12 +++--- variants/heltec_t114/target.cpp | 62 +++++++++++------------------ variants/heltec_t114/target.h | 17 +++----- variants/heltec_t114/variant.h | 9 +++-- 5 files changed, 48 insertions(+), 59 deletions(-) diff --git a/examples/simple_repeater/main.cpp b/examples/simple_repeater/main.cpp index d55d61186..c053b68bd 100644 --- a/examples/simple_repeater/main.cpp +++ b/examples/simple_repeater/main.cpp @@ -29,6 +29,12 @@ void setup() { board.begin(); +#if defined(MESH_DEBUG) && defined(NRF52_PLATFORM) + // give some extra time for serial to settle so + // boot debug messages can be seen on terminal + delay(5000); +#endif + // For power saving lastActive = millis(); // mark last active time since boot @@ -42,6 +48,7 @@ void setup() { #endif if (!radio_init()) { + MESH_DEBUG_PRINTLN("Radio init failed!"); halt(); } diff --git a/variants/heltec_t114/platformio.ini b/variants/heltec_t114/platformio.ini index dd1f8bb3c..b985030f7 100644 --- a/variants/heltec_t114/platformio.ini +++ b/variants/heltec_t114/platformio.ini @@ -29,15 +29,13 @@ build_flags = ${nrf52_base.build_flags} -D SX126X_DIO3_TCXO_VOLTAGE=1.8 -D SX126X_CURRENT_LIMIT=140 -D SX126X_RX_BOOSTED_GAIN=1 - -D DISPLAY_CLASS=NullDisplayDriver - -D ST7789 -D PIN_GPS_RX=39 -D PIN_GPS_TX=37 -D PIN_GPS_EN=21 -D PIN_GPS_RESET=38 -D PIN_GPS_RESET_ACTIVE=LOW - -D PIN_BOARD_SDA=16 - -D PIN_BOARD_SCL=13 + -D ENV_PIN_SDA=PIN_WIRE1_SDA + -D ENV_PIN_SCL=PIN_WIRE1_SCL build_src_filter = ${nrf52_base.build_src_filter} + + @@ -45,8 +43,6 @@ build_src_filter = ${nrf52_base.build_src_filter} lib_deps = ${nrf52_base.lib_deps} ${sensor_base.lib_deps} - stevemarple/MicroNMEA @ ^2.0.6 - adafruit/Adafruit GFX Library @ ^1.12.1 debug_tool = jlink upload_protocol = nrfutil @@ -105,6 +101,7 @@ board_upload.maximum_size = 712704 build_flags = ${Heltec_t114.build_flags} -I examples/companion_radio/ui-new + -D DISPLAY_CLASS=NullDisplayDriver -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 -D BLE_PIN_CODE=123456 @@ -127,6 +124,7 @@ board_upload.maximum_size = 712704 build_flags = ${Heltec_t114.build_flags} -I examples/companion_radio/ui-new + -D DISPLAY_CLASS=NullDisplayDriver -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 ; -D BLE_PIN_CODE=123456 @@ -149,6 +147,7 @@ extends = Heltec_t114 board = heltec_t114 board_build.ldscript = boards/nrf52840_s140_v6.ld build_flags = ${Heltec_t114.build_flags} + -D ST7789 -D HELTEC_T114_WITH_DISPLAY -D DISPLAY_CLASS=ST7789Display build_src_filter = ${Heltec_t114.build_src_filter} @@ -158,6 +157,7 @@ build_src_filter = ${Heltec_t114.build_src_filter} + lib_deps = ${Heltec_t114.lib_deps} + adafruit/Adafruit SSD1306 @ ^2.5.13 debug_tool = jlink upload_protocol = nrfutil diff --git a/variants/heltec_t114/target.cpp b/variants/heltec_t114/target.cpp index 23b9b667b..cd280ddab 100644 --- a/variants/heltec_t114/target.cpp +++ b/variants/heltec_t114/target.cpp @@ -1,28 +1,46 @@ -#include #include "target.h" + +#include #include + +#ifdef ENV_INCLUDE_GPS #include +#endif T114Board board; +#if defined(P_LORA_SCLK) RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); +#else +RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY); +#endif WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); -T114SensorManager sensors = T114SensorManager(nmea); + +#if ENV_INCLUDE_GPS +#include +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#else +EnvironmentSensorManager sensors; +#endif #ifdef DISPLAY_CLASS - DISPLAY_CLASS display; - MomentaryButton user_btn(PIN_USER_BTN, 1000, true); +DISPLAY_CLASS display; +MomentaryButton user_btn(PIN_USER_BTN, 1000, true); #endif bool radio_init() { rtc_clock.begin(Wire); +#if defined(P_LORA_SCLK) return radio.std_init(&SPI); +#else + return radio.std_init(); +#endif } uint32_t radio_get_rng_seed() { @@ -42,37 +60,5 @@ void radio_set_tx_power(uint8_t dbm) { mesh::LocalIdentity radio_new_identity() { RadioNoiseListener rng(radio); - return mesh::LocalIdentity(&rng); // create new random identity -} - -bool T114SensorManager::begin() { - Serial1.begin(9600); - - // Try to detect if GPS is physically connected to determine if we should expose the setting - pinMode(PIN_GPS_EN, OUTPUT); - digitalWrite(PIN_GPS_EN, HIGH); // Power on GPS - - // Give GPS a moment to power up and send data - delay(1500); - - // We'll consider GPS detected if we see any data on Serial1 - gps_detected = (Serial1.available() > 0); - - if (gps_detected) { - MESH_DEBUG_PRINTLN("GPS detected"); - } else { - MESH_DEBUG_PRINTLN("No GPS detected"); - } - digitalWrite(PIN_GPS_EN, LOW); // Power off GPS until the setting is changed - - return EnvironmentSensorManager::begin(); -} - -bool T114SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) { - EnvironmentSensorManager::querySensors(requester_permissions, telemetry); - - if (requester_permissions & TELEM_PERM_LOCATION) { // does requester have permission? - telemetry.addGPS(TELEM_CHANNEL_SELF, node_lat, node_lon, node_altitude); - } - return true; + return mesh::LocalIdentity(&rng); // create new random identity } diff --git a/variants/heltec_t114/target.h b/variants/heltec_t114/target.h index 24de81eee..94f990ecc 100644 --- a/variants/heltec_t114/target.h +++ b/variants/heltec_t114/target.h @@ -2,10 +2,10 @@ #define RADIOLIB_STATIC_ONLY 1 #include -#include #include -#include #include +#include +#include #include #include @@ -18,21 +18,14 @@ #endif #endif -class T114SensorManager : public EnvironmentSensorManager { -public: - T114SensorManager(LocationProvider &location): EnvironmentSensorManager(location) { } - bool begin() override; - bool querySensors(uint8_t requester_permissions, CayenneLPP& telemetry) override; -}; - extern T114Board board; extern WRAPPER_CLASS radio_driver; extern AutoDiscoverRTCClock rtc_clock; -extern T114SensorManager sensors; +extern EnvironmentSensorManager sensors; #ifdef DISPLAY_CLASS - extern DISPLAY_CLASS display; - extern MomentaryButton user_btn; +extern DISPLAY_CLASS display; +extern MomentaryButton user_btn; #endif bool radio_init(); diff --git a/variants/heltec_t114/variant.h b/variants/heltec_t114/variant.h index aa7f40222..bfb4484d1 100644 --- a/variants/heltec_t114/variant.h +++ b/variants/heltec_t114/variant.h @@ -14,7 +14,7 @@ #define USE_LFXO // 32.768 kHz crystal oscillator #define VARIANT_MCK (64000000ul) -#define WIRE_INTERFACES_COUNT (1) +#define WIRE_INTERFACES_COUNT (2) //////////////////////////////////////////////////////////////////////////////// // Power @@ -58,8 +58,11 @@ //////////////////////////////////////////////////////////////////////////////// // I2C pin definition -#define PIN_WIRE_SDA (26) // P0.26 -#define PIN_WIRE_SCL (27) // P0.27 +#define PIN_WIRE_SDA (26) // P0.26 +#define PIN_WIRE_SCL (27) // P0.27 + +#define PIN_WIRE1_SDA (7) // P0.8 +#define PIN_WIRE1_SCL (8) // P0.7 //////////////////////////////////////////////////////////////////////////////// // SPI pin definition From c0b81b9ad867dd0b018c4a513b0424995226fb97 Mon Sep 17 00:00:00 2001 From: Adam Gessaman Date: Thu, 5 Feb 2026 09:46:30 -0800 Subject: [PATCH 29/35] Clean up comments on kiss noise floor changes. --- docs/kiss_modem_protocol.md | 4 +--- examples/kiss_modem/main.cpp | 12 +++++------- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/docs/kiss_modem_protocol.md b/docs/kiss_modem_protocol.md index 067e15397..00b0bf90f 100644 --- a/docs/kiss_modem_protocol.md +++ b/docs/kiss_modem_protocol.md @@ -28,8 +28,6 @@ Maximum unescaped frame size: 512 bytes. ## Commands -Command and response codes below are taken from `examples/kiss_modem/KissModem.h` and the switch in `KissModem::processFrame()`. - ### Request Commands (Host → Modem) | Command | Value | Data | @@ -129,7 +127,7 @@ Response to `CMD_GET_NOISE_FLOOR` (0x13). Little-endian. |--------------|------|--------------------------------| | Noise floor | 2 | int16_t, dBm (signed), e.g. -120 | -The modem recalibrates the noise floor periodically (every 2 s) from RX samples when idle. The receiver AGC is also reset periodically (every 30 s) so RSSI and noise floor do not drift to the minimum (-120). Typical range after calibration is about -120 to -90 dBm. Values may be 0 or briefly stale until the radio has been in receive mode long enough to collect 64 samples. +The modem recalibrates the noise floor every two seconds with an AGC reset every 30 seconds. ### Stats (RESP_STATS) diff --git a/examples/kiss_modem/main.cpp b/examples/kiss_modem/main.cpp index 13855309b..3a610460d 100644 --- a/examples/kiss_modem/main.cpp +++ b/examples/kiss_modem/main.cpp @@ -12,8 +12,8 @@ #include #endif -#define NOISE_FLOOR_CALIB_INTERVAL_MS 2000 // match Dispatcher default -#define AGC_RESET_INTERVAL_MS 30000 // periodic RX restart so AGC doesn't drift (repeater uses same via prefs) +#define NOISE_FLOOR_CALIB_INTERVAL_MS 2000 +#define AGC_RESET_INTERVAL_MS 30000 StdRNG rng; mesh::LocalIdentity identity; @@ -100,11 +100,9 @@ void loop() { uint8_t packet[KISS_MAX_PACKET_SIZE]; uint16_t len; - // Match Dispatcher order: noise floor calib + loop() first, so we never sample RSSI in the same - // iteration as startReceive() (AGC reset -> recvRaw below). Sampling right after startReceive() - // can yield settling/cold RSSI and drive the floor toward -120. + // trigger noise floor calibration if ((uint32_t)(millis() - next_noise_floor_calib_ms) >= NOISE_FLOOR_CALIB_INTERVAL_MS) { - radio_driver.triggerNoiseFloorCalibrate(0); // 0 = no interference threshold (KISS has no prefs) + radio_driver.triggerNoiseFloorCalibrate(0); next_noise_floor_calib_ms = millis(); } radio_driver.loop(); @@ -119,7 +117,7 @@ void loop() { } if ((uint32_t)(millis() - next_agc_reset_ms) >= AGC_RESET_INTERVAL_MS) { - radio_driver.resetAGC(); // next recvRaw() will startReceive() and reset AGC so RSSI/noise floor don't stick at -120 + radio_driver.resetAGC(); next_agc_reset_ms = millis(); } uint8_t rx_buf[256]; From d0720c63c2cfa687f7d3a525f4c7a8c5152e44d6 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Sat, 3 Jan 2026 20:35:14 +0100 Subject: [PATCH 30/35] Allow negative tx power Like SX1262 allows -9 dBm lowest, some allow lower but that probably isn't useful --- examples/companion_radio/MyMesh.cpp | 2 +- examples/companion_radio/NodePrefs.h | 2 +- examples/simple_repeater/MyMesh.cpp | 2 +- examples/simple_repeater/MyMesh.h | 2 +- examples/simple_room_server/MyMesh.cpp | 2 +- examples/simple_room_server/MyMesh.h | 2 +- examples/simple_secure_chat/main.cpp | 4 ++-- examples/simple_sensor/SensorMesh.cpp | 2 +- examples/simple_sensor/SensorMesh.h | 2 +- src/helpers/CommonCLI.cpp | 4 ++-- src/helpers/CommonCLI.h | 4 ++-- variants/ebyte_eora_s3/target.cpp | 2 +- variants/ebyte_eora_s3/target.h | 2 +- variants/generic-e22/target.cpp | 2 +- variants/generic-e22/target.h | 2 +- variants/generic_espnow/target.cpp | 2 +- variants/generic_espnow/target.h | 2 +- variants/heltec_ct62/target.cpp | 2 +- variants/heltec_ct62/target.h | 2 +- variants/heltec_e213/target.cpp | 2 +- variants/heltec_e213/target.h | 2 +- variants/heltec_e290/target.cpp | 2 +- variants/heltec_e290/target.h | 2 +- variants/heltec_mesh_solar/target.cpp | 2 +- variants/heltec_mesh_solar/target.h | 2 +- variants/heltec_t114/target.cpp | 2 +- variants/heltec_t114/target.h | 2 +- variants/heltec_t190/target.cpp | 2 +- variants/heltec_t190/target.h | 2 +- variants/heltec_tracker/target.cpp | 2 +- variants/heltec_tracker/target.h | 2 +- variants/heltec_tracker_v2/target.cpp | 2 +- variants/heltec_tracker_v2/target.h | 2 +- variants/heltec_v2/target.cpp | 2 +- variants/heltec_v2/target.h | 2 +- variants/heltec_v3/target.cpp | 2 +- variants/heltec_v3/target.h | 2 +- variants/heltec_v4/target.cpp | 2 +- variants/heltec_v4/target.h | 2 +- variants/heltec_wireless_paper/target.cpp | 2 +- variants/heltec_wireless_paper/target.h | 2 +- variants/ikoka_handheld_nrf/target.cpp | 2 +- variants/ikoka_handheld_nrf/target.h | 2 +- variants/ikoka_nano_nrf/target.cpp | 2 +- variants/ikoka_nano_nrf/target.h | 2 +- variants/ikoka_stick_nrf/target.cpp | 2 +- variants/ikoka_stick_nrf/target.h | 2 +- variants/keepteen_lt1/target.cpp | 2 +- variants/keepteen_lt1/target.h | 2 +- variants/lilygo_t3s3/target.cpp | 2 +- variants/lilygo_t3s3/target.h | 2 +- variants/lilygo_t3s3_sx1276/target.cpp | 2 +- variants/lilygo_t3s3_sx1276/target.h | 2 +- variants/lilygo_tbeam_1w/target.cpp | 2 +- variants/lilygo_tbeam_1w/target.h | 2 +- variants/lilygo_tbeam_SX1262/target.cpp | 2 +- variants/lilygo_tbeam_SX1262/target.h | 2 +- variants/lilygo_tbeam_SX1276/target.cpp | 2 +- variants/lilygo_tbeam_SX1276/target.h | 2 +- variants/lilygo_tbeam_supreme_SX1262/target.cpp | 2 +- variants/lilygo_tbeam_supreme_SX1262/target.h | 2 +- variants/lilygo_tdeck/target.cpp | 2 +- variants/lilygo_tdeck/target.h | 2 +- variants/lilygo_techo/target.cpp | 2 +- variants/lilygo_techo/target.h | 2 +- variants/lilygo_techo_lite/target.cpp | 2 +- variants/lilygo_techo_lite/target.h | 2 +- variants/lilygo_tlora_c6/target.cpp | 2 +- variants/lilygo_tlora_c6/target.h | 2 +- variants/lilygo_tlora_v2_1/target.cpp | 2 +- variants/lilygo_tlora_v2_1/target.h | 2 +- variants/mesh_pocket/target.cpp | 2 +- variants/mesh_pocket/target.h | 2 +- variants/meshadventurer/target.cpp | 2 +- variants/meshadventurer/target.h | 2 +- variants/meshtiny/target.cpp | 2 +- variants/meshtiny/target.h | 2 +- variants/minewsemi_me25ls01/target.cpp | 2 +- variants/minewsemi_me25ls01/target.h | 2 +- variants/nano_g2_ultra/target.cpp | 2 +- variants/nano_g2_ultra/target.h | 2 +- variants/nibble_screen_connect/target.cpp | 2 +- variants/nibble_screen_connect/target.h | 2 +- variants/promicro/target.cpp | 2 +- variants/promicro/target.h | 2 +- variants/rak11310/target.cpp | 2 +- variants/rak11310/target.h | 2 +- variants/rak3112/target.cpp | 2 +- variants/rak3112/target.h | 2 +- variants/rak3401/target.cpp | 2 +- variants/rak3401/target.h | 2 +- variants/rak3x72/target.cpp | 2 +- variants/rak3x72/target.h | 2 +- variants/rak4631/target.cpp | 2 +- variants/rak4631/target.h | 2 +- variants/rak_wismesh_tag/target.cpp | 2 +- variants/rak_wismesh_tag/target.h | 2 +- variants/rpi_picow/target.cpp | 2 +- variants/rpi_picow/target.h | 2 +- variants/sensecap_indicator-espnow/target.cpp | 2 +- variants/sensecap_indicator-espnow/target.h | 2 +- variants/sensecap_solar/target.cpp | 2 +- variants/sensecap_solar/target.h | 2 +- variants/station_g2/target.cpp | 2 +- variants/station_g2/target.h | 2 +- variants/t1000-e/target.cpp | 2 +- variants/t1000-e/target.h | 2 +- variants/tenstar_c3/target.cpp | 2 +- variants/tenstar_c3/target.h | 2 +- variants/thinknode_m1/target.cpp | 2 +- variants/thinknode_m1/target.h | 2 +- variants/thinknode_m2/target.cpp | 2 +- variants/thinknode_m2/target.h | 2 +- variants/thinknode_m3/target.cpp | 2 +- variants/thinknode_m3/target.h | 2 +- variants/thinknode_m5/target.cpp | 2 +- variants/thinknode_m5/target.h | 2 +- variants/thinknode_m6/target.cpp | 2 +- variants/thinknode_m6/target.h | 2 +- variants/tiny_relay/target.cpp | 2 +- variants/tiny_relay/target.h | 2 +- variants/waveshare_rp2040_lora/target.cpp | 2 +- variants/waveshare_rp2040_lora/target.h | 2 +- variants/wio-e5-dev/target.cpp | 2 +- variants/wio-e5-dev/target.h | 2 +- variants/wio-e5-mini/target.cpp | 2 +- variants/wio-e5-mini/target.h | 2 +- variants/wio-tracker-l1/target.cpp | 2 +- variants/wio-tracker-l1/target.h | 2 +- variants/wio_wm1110/target.cpp | 2 +- variants/wio_wm1110/target.h | 2 +- variants/xiao_c3/target.cpp | 2 +- variants/xiao_c3/target.h | 2 +- variants/xiao_c6/XiaoC6Board.cpp | 2 +- variants/xiao_c6/target.h | 2 +- variants/xiao_nrf52/target.cpp | 2 +- variants/xiao_nrf52/target.h | 2 +- variants/xiao_rp2040/target.cpp | 2 +- variants/xiao_rp2040/target.h | 2 +- variants/xiao_s3_wio/target.cpp | 2 +- variants/xiao_s3_wio/target.h | 2 +- 141 files changed, 144 insertions(+), 144 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index 9bb747e79..f8e90be5e 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -838,7 +838,7 @@ void MyMesh::begin(bool has_display) { _prefs.bw = constrain(_prefs.bw, 7.8f, 500.0f); _prefs.sf = constrain(_prefs.sf, 5, 12); _prefs.cr = constrain(_prefs.cr, 5, 8); - _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, 1, MAX_LORA_TX_POWER); + _prefs.tx_power_dbm = constrain(_prefs.tx_power_dbm, -9, MAX_LORA_TX_POWER); _prefs.gps_enabled = constrain(_prefs.gps_enabled, 0, 1); // Ensure boolean 0 or 1 _prefs.gps_interval = constrain(_prefs.gps_interval, 0, 86400); // Max 24 hours diff --git a/examples/companion_radio/NodePrefs.h b/examples/companion_radio/NodePrefs.h index 62cd41642..d7ddd92a5 100644 --- a/examples/companion_radio/NodePrefs.h +++ b/examples/companion_radio/NodePrefs.h @@ -17,7 +17,7 @@ struct NodePrefs { // persisted to file uint8_t multi_acks; uint8_t manual_add_contacts; float bw; - uint8_t tx_power_dbm; + int8_t tx_power_dbm; uint8_t telemetry_mode_base; uint8_t telemetry_mode_loc; uint8_t telemetry_mode_env; diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 6d957cc09..8220ef0db 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -899,7 +899,7 @@ void MyMesh::dumpLogFile() { } } -void MyMesh::setTxPower(uint8_t power_dbm) { +void MyMesh::setTxPower(int8_t power_dbm) { radio_set_tx_power(power_dbm); } diff --git a/examples/simple_repeater/MyMesh.h b/examples/simple_repeater/MyMesh.h index 0d5cd28a3..7a51b4a97 100644 --- a/examples/simple_repeater/MyMesh.h +++ b/examples/simple_repeater/MyMesh.h @@ -198,7 +198,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { } void dumpLogFile() override; - void setTxPower(uint8_t power_dbm) override; + void setTxPower(int8_t power_dbm) override; void formatNeighborsReply(char *reply) override; void removeNeighbor(const uint8_t* pubkey, int key_len) override; void formatStatsReply(char *reply) override; diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 22a3d208b..598b14de6 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -719,7 +719,7 @@ void MyMesh::dumpLogFile() { } } -void MyMesh::setTxPower(uint8_t power_dbm) { +void MyMesh::setTxPower(int8_t power_dbm) { radio_set_tx_power(power_dbm); } diff --git a/examples/simple_room_server/MyMesh.h b/examples/simple_room_server/MyMesh.h index f470e55eb..b4529e776 100644 --- a/examples/simple_room_server/MyMesh.h +++ b/examples/simple_room_server/MyMesh.h @@ -188,7 +188,7 @@ class MyMesh : public mesh::Mesh, public CommonCLICallbacks { } void dumpLogFile() override; - void setTxPower(uint8_t power_dbm) override; + void setTxPower(int8_t power_dbm) override; void formatNeighborsReply(char *reply) override { strcpy(reply, "not supported"); diff --git a/examples/simple_secure_chat/main.cpp b/examples/simple_secure_chat/main.cpp index 018ec2a20..a389ec74b 100644 --- a/examples/simple_secure_chat/main.cpp +++ b/examples/simple_secure_chat/main.cpp @@ -66,7 +66,7 @@ struct NodePrefs { // persisted to file char node_name[32]; double node_lat, node_lon; float freq; - uint8_t tx_power_dbm; + int8_t tx_power_dbm; uint8_t unused[3]; }; @@ -290,7 +290,7 @@ class MyMesh : public BaseChatMesh, ContactVisitor { } float getFreqPref() const { return _prefs.freq; } - uint8_t getTxPowerPref() const { return _prefs.tx_power_dbm; } + int8_t getTxPowerPref() const { return _prefs.tx_power_dbm; } void begin(FILESYSTEM& fs) { _fs = &fs; diff --git a/examples/simple_sensor/SensorMesh.cpp b/examples/simple_sensor/SensorMesh.cpp index 8e27323ed..f05fb245c 100644 --- a/examples/simple_sensor/SensorMesh.cpp +++ b/examples/simple_sensor/SensorMesh.cpp @@ -815,7 +815,7 @@ void SensorMesh::updateFloodAdvertTimer() { } } -void SensorMesh::setTxPower(uint8_t power_dbm) { +void SensorMesh::setTxPower(int8_t power_dbm) { radio_set_tx_power(power_dbm); } diff --git a/examples/simple_sensor/SensorMesh.h b/examples/simple_sensor/SensorMesh.h index ed3523458..4bc0d784e 100644 --- a/examples/simple_sensor/SensorMesh.h +++ b/examples/simple_sensor/SensorMesh.h @@ -66,7 +66,7 @@ class SensorMesh : public mesh::Mesh, public CommonCLICallbacks { void setLoggingOn(bool enable) override { } void eraseLogFile() override { } void dumpLogFile() override { } - void setTxPower(uint8_t power_dbm) override; + void setTxPower(int8_t power_dbm) override; void formatNeighborsReply(char *reply) override { strcpy(reply, "not supported"); } diff --git a/src/helpers/CommonCLI.cpp b/src/helpers/CommonCLI.cpp index 10ab86691..6dcf7018e 100644 --- a/src/helpers/CommonCLI.cpp +++ b/src/helpers/CommonCLI.cpp @@ -92,7 +92,7 @@ void CommonCLI::loadPrefsInt(FILESYSTEM* fs, const char* filename) { _prefs->bw = constrain(_prefs->bw, 7.8f, 500.0f); _prefs->sf = constrain(_prefs->sf, 5, 12); _prefs->cr = constrain(_prefs->cr, 5, 8); - _prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, 1, 30); + _prefs->tx_power_dbm = constrain(_prefs->tx_power_dbm, -9, 30); _prefs->multi_acks = constrain(_prefs->multi_acks, 0, 1); _prefs->adc_multiplier = constrain(_prefs->adc_multiplier, 0.0f, 10.0f); @@ -326,7 +326,7 @@ void CommonCLI::handleCommand(uint32_t sender_timestamp, const char* command, ch } *reply = 0; // set null terminator } else if (memcmp(config, "tx", 2) == 0 && (config[2] == 0 || config[2] == ' ')) { - sprintf(reply, "> %d", (uint32_t) _prefs->tx_power_dbm); + sprintf(reply, "> %d", (int32_t) _prefs->tx_power_dbm); } else if (memcmp(config, "freq", 4) == 0) { sprintf(reply, "> %s", StrHelper::ftoa(_prefs->freq)); } else if (memcmp(config, "public.key", 10) == 0) { diff --git a/src/helpers/CommonCLI.h b/src/helpers/CommonCLI.h index 8661d1e6d..146e1c6e2 100644 --- a/src/helpers/CommonCLI.h +++ b/src/helpers/CommonCLI.h @@ -19,7 +19,7 @@ struct NodePrefs { // persisted to file double node_lat, node_lon; char password[16]; float freq; - uint8_t tx_power_dbm; + int8_t tx_power_dbm; uint8_t disable_fwd; uint8_t advert_interval; // minutes / 2 uint8_t flood_advert_interval; // hours @@ -67,7 +67,7 @@ class CommonCLICallbacks { virtual void setLoggingOn(bool enable) = 0; virtual void eraseLogFile() = 0; virtual void dumpLogFile() = 0; - virtual void setTxPower(uint8_t power_dbm) = 0; + virtual void setTxPower(int8_t power_dbm) = 0; virtual void formatNeighborsReply(char *reply) = 0; virtual void removeNeighbor(const uint8_t* pubkey, int key_len) { // no op by default diff --git a/variants/ebyte_eora_s3/target.cpp b/variants/ebyte_eora_s3/target.cpp index 647f59972..501f560be 100644 --- a/variants/ebyte_eora_s3/target.cpp +++ b/variants/ebyte_eora_s3/target.cpp @@ -75,7 +75,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/ebyte_eora_s3/target.h b/variants/ebyte_eora_s3/target.h index f184c7575..892c3de3f 100644 --- a/variants/ebyte_eora_s3/target.h +++ b/variants/ebyte_eora_s3/target.h @@ -25,5 +25,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/generic-e22/target.cpp b/variants/generic-e22/target.cpp index e02537798..f76bb979a 100644 --- a/variants/generic-e22/target.cpp +++ b/variants/generic-e22/target.cpp @@ -38,7 +38,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/generic-e22/target.h b/variants/generic-e22/target.h index 442706f33..5ad13054f 100644 --- a/variants/generic-e22/target.h +++ b/variants/generic-e22/target.h @@ -17,5 +17,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/generic_espnow/target.cpp b/variants/generic_espnow/target.cpp index 6b5d4e444..f42085c04 100644 --- a/variants/generic_espnow/target.cpp +++ b/variants/generic_espnow/target.cpp @@ -25,7 +25,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { // no-op } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio_driver.setTxPower(dbm); } diff --git a/variants/generic_espnow/target.h b/variants/generic_espnow/target.h index 99b6f5778..1ebd0837b 100644 --- a/variants/generic_espnow/target.h +++ b/variants/generic_espnow/target.h @@ -12,5 +12,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/heltec_ct62/target.cpp b/variants/heltec_ct62/target.cpp index a8c15f5ff..5cc621a13 100644 --- a/variants/heltec_ct62/target.cpp +++ b/variants/heltec_ct62/target.cpp @@ -27,7 +27,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_ct62/target.h b/variants/heltec_ct62/target.h index 9639ab2df..34130ae77 100644 --- a/variants/heltec_ct62/target.h +++ b/variants/heltec_ct62/target.h @@ -16,5 +16,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/heltec_e213/target.cpp b/variants/heltec_e213/target.cpp index 23561850e..c9233431c 100644 --- a/variants/heltec_e213/target.cpp +++ b/variants/heltec_e213/target.cpp @@ -44,7 +44,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_e213/target.h b/variants/heltec_e213/target.h index 9ecdc212a..14969c0f4 100644 --- a/variants/heltec_e213/target.h +++ b/variants/heltec_e213/target.h @@ -25,5 +25,5 @@ extern MomentaryButton user_btn; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/heltec_e290/target.cpp b/variants/heltec_e290/target.cpp index 92b02092e..b0c9630cf 100644 --- a/variants/heltec_e290/target.cpp +++ b/variants/heltec_e290/target.cpp @@ -44,7 +44,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_e290/target.h b/variants/heltec_e290/target.h index 607701127..5d423fc0d 100644 --- a/variants/heltec_e290/target.h +++ b/variants/heltec_e290/target.h @@ -25,5 +25,5 @@ extern MomentaryButton user_btn; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index ad79f7171..9852b68f8 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -34,7 +34,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_mesh_solar/target.h b/variants/heltec_mesh_solar/target.h index e301a2735..f1921abfa 100644 --- a/variants/heltec_mesh_solar/target.h +++ b/variants/heltec_mesh_solar/target.h @@ -42,5 +42,5 @@ extern SolarSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/heltec_t114/target.cpp b/variants/heltec_t114/target.cpp index c3341103a..160d00b6a 100644 --- a/variants/heltec_t114/target.cpp +++ b/variants/heltec_t114/target.cpp @@ -36,7 +36,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_t114/target.h b/variants/heltec_t114/target.h index 6306cd699..187675e97 100644 --- a/variants/heltec_t114/target.h +++ b/variants/heltec_t114/target.h @@ -50,5 +50,5 @@ extern T114SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/heltec_t190/target.cpp b/variants/heltec_t190/target.cpp index b93575943..d22f8b8cf 100644 --- a/variants/heltec_t190/target.cpp +++ b/variants/heltec_t190/target.cpp @@ -44,7 +44,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_t190/target.h b/variants/heltec_t190/target.h index 8a5fc716f..83e035707 100644 --- a/variants/heltec_t190/target.h +++ b/variants/heltec_t190/target.h @@ -25,5 +25,5 @@ extern MomentaryButton user_btn; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/heltec_tracker/target.cpp b/variants/heltec_tracker/target.cpp index 5ba9a8fb4..25c2634bb 100644 --- a/variants/heltec_tracker/target.cpp +++ b/variants/heltec_tracker/target.cpp @@ -47,7 +47,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_tracker/target.h b/variants/heltec_tracker/target.h index 23fab16e1..5296fb2c2 100644 --- a/variants/heltec_tracker/target.h +++ b/variants/heltec_tracker/target.h @@ -43,5 +43,5 @@ extern HWTSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/heltec_tracker_v2/target.cpp b/variants/heltec_tracker_v2/target.cpp index da397fb74..c2e26b20d 100644 --- a/variants/heltec_tracker_v2/target.cpp +++ b/variants/heltec_tracker_v2/target.cpp @@ -50,7 +50,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_tracker_v2/target.h b/variants/heltec_tracker_v2/target.h index 190404ef9..5b799e780 100644 --- a/variants/heltec_tracker_v2/target.h +++ b/variants/heltec_tracker_v2/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/heltec_v2/target.cpp b/variants/heltec_v2/target.cpp index df71d3f4b..c5a047528 100644 --- a/variants/heltec_v2/target.cpp +++ b/variants/heltec_v2/target.cpp @@ -43,7 +43,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_v2/target.h b/variants/heltec_v2/target.h index 48d750be4..788dac723 100644 --- a/variants/heltec_v2/target.h +++ b/variants/heltec_v2/target.h @@ -25,5 +25,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/heltec_v3/target.cpp b/variants/heltec_v3/target.cpp index 78b881972..cdd2535e8 100644 --- a/variants/heltec_v3/target.cpp +++ b/variants/heltec_v3/target.cpp @@ -50,7 +50,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_v3/target.h b/variants/heltec_v3/target.h index 739aecfe0..21a209f99 100644 --- a/variants/heltec_v3/target.h +++ b/variants/heltec_v3/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/heltec_v4/target.cpp b/variants/heltec_v4/target.cpp index 0d2bd4976..f971cc608 100644 --- a/variants/heltec_v4/target.cpp +++ b/variants/heltec_v4/target.cpp @@ -50,7 +50,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_v4/target.h b/variants/heltec_v4/target.h index 00d2adab6..5016588d1 100644 --- a/variants/heltec_v4/target.h +++ b/variants/heltec_v4/target.h @@ -30,5 +30,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/heltec_wireless_paper/target.cpp b/variants/heltec_wireless_paper/target.cpp index dd2d51c0f..06f548fc0 100644 --- a/variants/heltec_wireless_paper/target.cpp +++ b/variants/heltec_wireless_paper/target.cpp @@ -43,7 +43,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/heltec_wireless_paper/target.h b/variants/heltec_wireless_paper/target.h index b89c486fb..65739e773 100644 --- a/variants/heltec_wireless_paper/target.h +++ b/variants/heltec_wireless_paper/target.h @@ -25,5 +25,5 @@ extern MomentaryButton user_btn; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/ikoka_handheld_nrf/target.cpp b/variants/ikoka_handheld_nrf/target.cpp index efa6669f1..48244e172 100644 --- a/variants/ikoka_handheld_nrf/target.cpp +++ b/variants/ikoka_handheld_nrf/target.cpp @@ -36,7 +36,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/ikoka_handheld_nrf/target.h b/variants/ikoka_handheld_nrf/target.h index a28ca81a5..d4af956e1 100644 --- a/variants/ikoka_handheld_nrf/target.h +++ b/variants/ikoka_handheld_nrf/target.h @@ -25,5 +25,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/ikoka_nano_nrf/target.cpp b/variants/ikoka_nano_nrf/target.cpp index aed591823..be20cfb43 100644 --- a/variants/ikoka_nano_nrf/target.cpp +++ b/variants/ikoka_nano_nrf/target.cpp @@ -34,7 +34,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/ikoka_nano_nrf/target.h b/variants/ikoka_nano_nrf/target.h index 9b4e908ec..7949ab638 100644 --- a/variants/ikoka_nano_nrf/target.h +++ b/variants/ikoka_nano_nrf/target.h @@ -24,5 +24,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/ikoka_stick_nrf/target.cpp b/variants/ikoka_stick_nrf/target.cpp index bd803399b..4f6befc60 100644 --- a/variants/ikoka_stick_nrf/target.cpp +++ b/variants/ikoka_stick_nrf/target.cpp @@ -34,7 +34,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/ikoka_stick_nrf/target.h b/variants/ikoka_stick_nrf/target.h index c276e89f2..fab825926 100644 --- a/variants/ikoka_stick_nrf/target.h +++ b/variants/ikoka_stick_nrf/target.h @@ -24,5 +24,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/keepteen_lt1/target.cpp b/variants/keepteen_lt1/target.cpp index e72abf08b..e2e183a70 100644 --- a/variants/keepteen_lt1/target.cpp +++ b/variants/keepteen_lt1/target.cpp @@ -40,7 +40,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/keepteen_lt1/target.h b/variants/keepteen_lt1/target.h index 0f1aa756c..f2468d34e 100644 --- a/variants/keepteen_lt1/target.h +++ b/variants/keepteen_lt1/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_t3s3/target.cpp b/variants/lilygo_t3s3/target.cpp index 1c7b3b094..284811881 100644 --- a/variants/lilygo_t3s3/target.cpp +++ b/variants/lilygo_t3s3/target.cpp @@ -38,7 +38,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_t3s3/target.h b/variants/lilygo_t3s3/target.h index f184c7575..892c3de3f 100644 --- a/variants/lilygo_t3s3/target.h +++ b/variants/lilygo_t3s3/target.h @@ -25,5 +25,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_t3s3_sx1276/target.cpp b/variants/lilygo_t3s3_sx1276/target.cpp index 042ff2062..e7fe07a0c 100644 --- a/variants/lilygo_t3s3_sx1276/target.cpp +++ b/variants/lilygo_t3s3_sx1276/target.cpp @@ -44,7 +44,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_t3s3_sx1276/target.h b/variants/lilygo_t3s3_sx1276/target.h index 98a0fe359..2df4b3edb 100644 --- a/variants/lilygo_t3s3_sx1276/target.h +++ b/variants/lilygo_t3s3_sx1276/target.h @@ -25,5 +25,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/lilygo_tbeam_1w/target.cpp b/variants/lilygo_tbeam_1w/target.cpp index fcdb42ed8..8cb6bdfa3 100644 --- a/variants/lilygo_tbeam_1w/target.cpp +++ b/variants/lilygo_tbeam_1w/target.cpp @@ -54,7 +54,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_tbeam_1w/target.h b/variants/lilygo_tbeam_1w/target.h index 2c3e8970a..99a750317 100644 --- a/variants/lilygo_tbeam_1w/target.h +++ b/variants/lilygo_tbeam_1w/target.h @@ -23,5 +23,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_tbeam_SX1262/target.cpp b/variants/lilygo_tbeam_SX1262/target.cpp index a8caecb36..f85049d7c 100644 --- a/variants/lilygo_tbeam_SX1262/target.cpp +++ b/variants/lilygo_tbeam_SX1262/target.cpp @@ -45,7 +45,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_tbeam_SX1262/target.h b/variants/lilygo_tbeam_SX1262/target.h index 5f33abb87..e5b3e445e 100644 --- a/variants/lilygo_tbeam_SX1262/target.h +++ b/variants/lilygo_tbeam_SX1262/target.h @@ -25,5 +25,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_tbeam_SX1276/target.cpp b/variants/lilygo_tbeam_SX1276/target.cpp index 0a7517a21..5fe82e111 100644 --- a/variants/lilygo_tbeam_SX1276/target.cpp +++ b/variants/lilygo_tbeam_SX1276/target.cpp @@ -50,7 +50,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_tbeam_SX1276/target.h b/variants/lilygo_tbeam_SX1276/target.h index b382b652d..cd4480dce 100644 --- a/variants/lilygo_tbeam_SX1276/target.h +++ b/variants/lilygo_tbeam_SX1276/target.h @@ -25,5 +25,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp index 8ad306f1b..6fec6f583 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.cpp +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -42,7 +42,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.h b/variants/lilygo_tbeam_supreme_SX1262/target.h index c6ffa0a66..200a56905 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.h +++ b/variants/lilygo_tbeam_supreme_SX1262/target.h @@ -23,5 +23,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/lilygo_tdeck/target.cpp b/variants/lilygo_tdeck/target.cpp index 50ffa7359..731ecfd86 100644 --- a/variants/lilygo_tdeck/target.cpp +++ b/variants/lilygo_tdeck/target.cpp @@ -45,7 +45,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_tdeck/target.h b/variants/lilygo_tdeck/target.h index 4640925f1..c31d0d0ff 100644 --- a/variants/lilygo_tdeck/target.h +++ b/variants/lilygo_tdeck/target.h @@ -27,5 +27,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/lilygo_techo/target.cpp b/variants/lilygo_techo/target.cpp index 2ebc0641f..12d222ff7 100644 --- a/variants/lilygo_techo/target.cpp +++ b/variants/lilygo_techo/target.cpp @@ -42,7 +42,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_techo/target.h b/variants/lilygo_techo/target.h index 2b6ed45fc..d978d5224 100644 --- a/variants/lilygo_techo/target.h +++ b/variants/lilygo_techo/target.h @@ -27,5 +27,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_techo_lite/target.cpp b/variants/lilygo_techo_lite/target.cpp index 6979e3478..40a94526e 100644 --- a/variants/lilygo_techo_lite/target.cpp +++ b/variants/lilygo_techo_lite/target.cpp @@ -41,7 +41,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_techo_lite/target.h b/variants/lilygo_techo_lite/target.h index 2b6ed45fc..d978d5224 100644 --- a/variants/lilygo_techo_lite/target.h +++ b/variants/lilygo_techo_lite/target.h @@ -27,5 +27,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_tlora_c6/target.cpp b/variants/lilygo_tlora_c6/target.cpp index e12c58b5a..3566fbe48 100644 --- a/variants/lilygo_tlora_c6/target.cpp +++ b/variants/lilygo_tlora_c6/target.cpp @@ -38,7 +38,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_tlora_c6/target.h b/variants/lilygo_tlora_c6/target.h index c26d59586..1cb52fbc7 100644 --- a/variants/lilygo_tlora_c6/target.h +++ b/variants/lilygo_tlora_c6/target.h @@ -16,5 +16,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/lilygo_tlora_v2_1/target.cpp b/variants/lilygo_tlora_v2_1/target.cpp index 65a78c194..ead62e797 100644 --- a/variants/lilygo_tlora_v2_1/target.cpp +++ b/variants/lilygo_tlora_v2_1/target.cpp @@ -39,7 +39,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/lilygo_tlora_v2_1/target.h b/variants/lilygo_tlora_v2_1/target.h index 326a0dee7..cb7d861dd 100644 --- a/variants/lilygo_tlora_v2_1/target.h +++ b/variants/lilygo_tlora_v2_1/target.h @@ -25,5 +25,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/mesh_pocket/target.cpp b/variants/mesh_pocket/target.cpp index a7f6c7fb1..6fabb3174 100644 --- a/variants/mesh_pocket/target.cpp +++ b/variants/mesh_pocket/target.cpp @@ -34,7 +34,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/mesh_pocket/target.h b/variants/mesh_pocket/target.h index 2aa956693..6ab5d9c2f 100644 --- a/variants/mesh_pocket/target.h +++ b/variants/mesh_pocket/target.h @@ -26,7 +26,7 @@ extern AutoDiscoverRTCClock rtc_clock; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); extern SensorManager sensors; diff --git a/variants/meshadventurer/target.cpp b/variants/meshadventurer/target.cpp index 0e3b03f2b..0edd44030 100644 --- a/variants/meshadventurer/target.cpp +++ b/variants/meshadventurer/target.cpp @@ -41,7 +41,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/meshadventurer/target.h b/variants/meshadventurer/target.h index 31bc40663..9d1ffca8d 100644 --- a/variants/meshadventurer/target.h +++ b/variants/meshadventurer/target.h @@ -45,5 +45,5 @@ extern MASensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/meshtiny/target.cpp b/variants/meshtiny/target.cpp index 5fc60eae4..9188db174 100644 --- a/variants/meshtiny/target.cpp +++ b/variants/meshtiny/target.cpp @@ -37,7 +37,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/meshtiny/target.h b/variants/meshtiny/target.h index 8ee3ee86e..31f8505d6 100644 --- a/variants/meshtiny/target.h +++ b/variants/meshtiny/target.h @@ -29,5 +29,5 @@ extern MomentaryButton back_btn; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/minewsemi_me25ls01/target.cpp b/variants/minewsemi_me25ls01/target.cpp index 13306762a..fcec19419 100644 --- a/variants/minewsemi_me25ls01/target.cpp +++ b/variants/minewsemi_me25ls01/target.cpp @@ -88,7 +88,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/minewsemi_me25ls01/target.h b/variants/minewsemi_me25ls01/target.h index a5da58234..ea7383e25 100644 --- a/variants/minewsemi_me25ls01/target.h +++ b/variants/minewsemi_me25ls01/target.h @@ -25,5 +25,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/nano_g2_ultra/target.cpp b/variants/nano_g2_ultra/target.cpp index 81e7744fc..aad10c505 100644 --- a/variants/nano_g2_ultra/target.cpp +++ b/variants/nano_g2_ultra/target.cpp @@ -36,7 +36,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/nano_g2_ultra/target.h b/variants/nano_g2_ultra/target.h index 3e58b9007..6e3541275 100644 --- a/variants/nano_g2_ultra/target.h +++ b/variants/nano_g2_ultra/target.h @@ -45,5 +45,5 @@ extern MomentaryButton user_btn; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/nibble_screen_connect/target.cpp b/variants/nibble_screen_connect/target.cpp index 1980e0394..6edaaad7a 100644 --- a/variants/nibble_screen_connect/target.cpp +++ b/variants/nibble_screen_connect/target.cpp @@ -38,7 +38,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/nibble_screen_connect/target.h b/variants/nibble_screen_connect/target.h index 66e69901a..f31efb8da 100644 --- a/variants/nibble_screen_connect/target.h +++ b/variants/nibble_screen_connect/target.h @@ -25,6 +25,6 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/promicro/target.cpp b/variants/promicro/target.cpp index b26320e47..61eab91c2 100644 --- a/variants/promicro/target.cpp +++ b/variants/promicro/target.cpp @@ -40,7 +40,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/promicro/target.h b/variants/promicro/target.h index 38c4b4e88..d379927ec 100644 --- a/variants/promicro/target.h +++ b/variants/promicro/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rak11310/target.cpp b/variants/rak11310/target.cpp index dba5bff2c..67432998a 100644 --- a/variants/rak11310/target.cpp +++ b/variants/rak11310/target.cpp @@ -29,7 +29,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/rak11310/target.h b/variants/rak11310/target.h index fe45c3f2c..7c25cd901 100644 --- a/variants/rak11310/target.h +++ b/variants/rak11310/target.h @@ -16,5 +16,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rak3112/target.cpp b/variants/rak3112/target.cpp index 634573b81..6cddfce51 100644 --- a/variants/rak3112/target.cpp +++ b/variants/rak3112/target.cpp @@ -50,7 +50,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/rak3112/target.h b/variants/rak3112/target.h index eae90900d..e7d85de9b 100644 --- a/variants/rak3112/target.h +++ b/variants/rak3112/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rak3401/target.cpp b/variants/rak3401/target.cpp index 52f3a3d59..ec4fc28c0 100644 --- a/variants/rak3401/target.cpp +++ b/variants/rak3401/target.cpp @@ -48,7 +48,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/rak3401/target.h b/variants/rak3401/target.h index 32f17cd1d..bb7f5dc49 100644 --- a/variants/rak3401/target.h +++ b/variants/rak3401/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rak3x72/target.cpp b/variants/rak3x72/target.cpp index 446783aa4..48e7f4228 100644 --- a/variants/rak3x72/target.cpp +++ b/variants/rak3x72/target.cpp @@ -66,7 +66,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/rak3x72/target.h b/variants/rak3x72/target.h index e0c1441e7..3ba1cf421 100644 --- a/variants/rak3x72/target.h +++ b/variants/rak3x72/target.h @@ -52,5 +52,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rak4631/target.cpp b/variants/rak4631/target.cpp index bc7465fda..ea6a2bd4a 100644 --- a/variants/rak4631/target.cpp +++ b/variants/rak4631/target.cpp @@ -48,7 +48,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/rak4631/target.h b/variants/rak4631/target.h index aa6be664b..eeb3e0947 100644 --- a/variants/rak4631/target.h +++ b/variants/rak4631/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rak_wismesh_tag/target.cpp b/variants/rak_wismesh_tag/target.cpp index 2bd30864b..9646375e6 100644 --- a/variants/rak_wismesh_tag/target.cpp +++ b/variants/rak_wismesh_tag/target.cpp @@ -44,7 +44,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/rak_wismesh_tag/target.h b/variants/rak_wismesh_tag/target.h index 150d08319..a51b30924 100644 --- a/variants/rak_wismesh_tag/target.h +++ b/variants/rak_wismesh_tag/target.h @@ -23,5 +23,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/rpi_picow/target.cpp b/variants/rpi_picow/target.cpp index abb1485df..e3d4bf090 100644 --- a/variants/rpi_picow/target.cpp +++ b/variants/rpi_picow/target.cpp @@ -29,7 +29,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/rpi_picow/target.h b/variants/rpi_picow/target.h index 17dbb35fd..706578a40 100644 --- a/variants/rpi_picow/target.h +++ b/variants/rpi_picow/target.h @@ -16,5 +16,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/sensecap_indicator-espnow/target.cpp b/variants/sensecap_indicator-espnow/target.cpp index efdaac610..6674c180d 100644 --- a/variants/sensecap_indicator-espnow/target.cpp +++ b/variants/sensecap_indicator-espnow/target.cpp @@ -37,7 +37,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { // no-op } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio_driver.setTxPower(dbm); } diff --git a/variants/sensecap_indicator-espnow/target.h b/variants/sensecap_indicator-espnow/target.h index bb78e9233..a56dec7bd 100644 --- a/variants/sensecap_indicator-espnow/target.h +++ b/variants/sensecap_indicator-espnow/target.h @@ -25,5 +25,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/sensecap_solar/target.cpp b/variants/sensecap_solar/target.cpp index 6bd7d31a7..2c2ff0dc7 100644 --- a/variants/sensecap_solar/target.cpp +++ b/variants/sensecap_solar/target.cpp @@ -29,7 +29,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/sensecap_solar/target.h b/variants/sensecap_solar/target.h index 90d60ba52..f4a988013 100644 --- a/variants/sensecap_solar/target.h +++ b/variants/sensecap_solar/target.h @@ -17,5 +17,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/station_g2/target.cpp b/variants/station_g2/target.cpp index 3f0c1404d..026b25de7 100644 --- a/variants/station_g2/target.cpp +++ b/variants/station_g2/target.cpp @@ -51,7 +51,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/station_g2/target.h b/variants/station_g2/target.h index 2bf7016d4..01428d586 100644 --- a/variants/station_g2/target.h +++ b/variants/station_g2/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index 82d958b5d..da8fa48bb 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -85,7 +85,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/t1000-e/target.h b/variants/t1000-e/target.h index 27351b945..d4e3c02c5 100644 --- a/variants/t1000-e/target.h +++ b/variants/t1000-e/target.h @@ -43,5 +43,5 @@ extern T1000SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/tenstar_c3/target.cpp b/variants/tenstar_c3/target.cpp index a29780f09..d4f189b52 100644 --- a/variants/tenstar_c3/target.cpp +++ b/variants/tenstar_c3/target.cpp @@ -38,7 +38,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/tenstar_c3/target.h b/variants/tenstar_c3/target.h index fa29e52bd..e503564b3 100644 --- a/variants/tenstar_c3/target.h +++ b/variants/tenstar_c3/target.h @@ -17,5 +17,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/thinknode_m1/target.cpp b/variants/thinknode_m1/target.cpp index c3b1abc21..ec2438d40 100644 --- a/variants/thinknode_m1/target.cpp +++ b/variants/thinknode_m1/target.cpp @@ -35,7 +35,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/thinknode_m1/target.h b/variants/thinknode_m1/target.h index 8425369d8..92661d096 100644 --- a/variants/thinknode_m1/target.h +++ b/variants/thinknode_m1/target.h @@ -45,5 +45,5 @@ extern ThinkNodeM1SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/thinknode_m2/target.cpp b/variants/thinknode_m2/target.cpp index cb3c1624d..e7e36d05f 100644 --- a/variants/thinknode_m2/target.cpp +++ b/variants/thinknode_m2/target.cpp @@ -46,7 +46,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/thinknode_m2/target.h b/variants/thinknode_m2/target.h index b05def8aa..77ebbfde8 100644 --- a/variants/thinknode_m2/target.h +++ b/variants/thinknode_m2/target.h @@ -26,7 +26,7 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/thinknode_m3/target.cpp b/variants/thinknode_m3/target.cpp index 91d186dc1..ca2b0aa06 100644 --- a/variants/thinknode_m3/target.cpp +++ b/variants/thinknode_m3/target.cpp @@ -89,7 +89,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/thinknode_m3/target.h b/variants/thinknode_m3/target.h index 23e995814..4124761cf 100644 --- a/variants/thinknode_m3/target.h +++ b/variants/thinknode_m3/target.h @@ -25,5 +25,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/thinknode_m5/target.cpp b/variants/thinknode_m5/target.cpp index 8208d2c43..a7a049ef4 100644 --- a/variants/thinknode_m5/target.cpp +++ b/variants/thinknode_m5/target.cpp @@ -53,7 +53,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/thinknode_m5/target.h b/variants/thinknode_m5/target.h index 2af42095c..a228cc9f5 100644 --- a/variants/thinknode_m5/target.h +++ b/variants/thinknode_m5/target.h @@ -29,7 +29,7 @@ extern PCA9557 expander; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); \ No newline at end of file diff --git a/variants/thinknode_m6/target.cpp b/variants/thinknode_m6/target.cpp index c14dd300f..36ca86180 100644 --- a/variants/thinknode_m6/target.cpp +++ b/variants/thinknode_m6/target.cpp @@ -39,7 +39,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/thinknode_m6/target.h b/variants/thinknode_m6/target.h index 38b1fed1b..fb129988f 100644 --- a/variants/thinknode_m6/target.h +++ b/variants/thinknode_m6/target.h @@ -27,5 +27,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/tiny_relay/target.cpp b/variants/tiny_relay/target.cpp index f738ac179..313dfaa94 100644 --- a/variants/tiny_relay/target.cpp +++ b/variants/tiny_relay/target.cpp @@ -70,7 +70,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/tiny_relay/target.h b/variants/tiny_relay/target.h index 82747cdcc..d15837121 100644 --- a/variants/tiny_relay/target.h +++ b/variants/tiny_relay/target.h @@ -55,5 +55,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/waveshare_rp2040_lora/target.cpp b/variants/waveshare_rp2040_lora/target.cpp index 7bc1d0430..a9121b0c3 100644 --- a/variants/waveshare_rp2040_lora/target.cpp +++ b/variants/waveshare_rp2040_lora/target.cpp @@ -39,7 +39,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/waveshare_rp2040_lora/target.h b/variants/waveshare_rp2040_lora/target.h index aed558939..fe1903de1 100644 --- a/variants/waveshare_rp2040_lora/target.h +++ b/variants/waveshare_rp2040_lora/target.h @@ -17,5 +17,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/wio-e5-dev/target.cpp b/variants/wio-e5-dev/target.cpp index 42e900e40..3e59b6cee 100644 --- a/variants/wio-e5-dev/target.cpp +++ b/variants/wio-e5-dev/target.cpp @@ -63,7 +63,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/wio-e5-dev/target.h b/variants/wio-e5-dev/target.h index 5fdd0abaf..1d1fc5cb9 100644 --- a/variants/wio-e5-dev/target.h +++ b/variants/wio-e5-dev/target.h @@ -29,5 +29,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/wio-e5-mini/target.cpp b/variants/wio-e5-mini/target.cpp index 0e2358b82..2e95ad6d1 100644 --- a/variants/wio-e5-mini/target.cpp +++ b/variants/wio-e5-mini/target.cpp @@ -61,7 +61,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/wio-e5-mini/target.h b/variants/wio-e5-mini/target.h index 921c38d34..a4e5fb60c 100644 --- a/variants/wio-e5-mini/target.h +++ b/variants/wio-e5-mini/target.h @@ -60,5 +60,5 @@ extern WIOE5SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/wio-tracker-l1/target.cpp b/variants/wio-tracker-l1/target.cpp index 64866de00..4575a76c8 100644 --- a/variants/wio-tracker-l1/target.cpp +++ b/variants/wio-tracker-l1/target.cpp @@ -44,7 +44,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/wio-tracker-l1/target.h b/variants/wio-tracker-l1/target.h index 97e575d89..e23476473 100644 --- a/variants/wio-tracker-l1/target.h +++ b/variants/wio-tracker-l1/target.h @@ -33,5 +33,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/wio_wm1110/target.cpp b/variants/wio_wm1110/target.cpp index c659d708b..457d5bda2 100644 --- a/variants/wio_wm1110/target.cpp +++ b/variants/wio_wm1110/target.cpp @@ -81,7 +81,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/wio_wm1110/target.h b/variants/wio_wm1110/target.h index 9bd4a22b8..8712a0ef0 100644 --- a/variants/wio_wm1110/target.h +++ b/variants/wio_wm1110/target.h @@ -16,6 +16,6 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/xiao_c3/target.cpp b/variants/xiao_c3/target.cpp index fe3f7196a..f8ee3d92c 100644 --- a/variants/xiao_c3/target.cpp +++ b/variants/xiao_c3/target.cpp @@ -46,7 +46,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/xiao_c3/target.h b/variants/xiao_c3/target.h index a7ef44218..57e3b81ca 100644 --- a/variants/xiao_c3/target.h +++ b/variants/xiao_c3/target.h @@ -16,5 +16,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/xiao_c6/XiaoC6Board.cpp b/variants/xiao_c6/XiaoC6Board.cpp index 555fed629..5710c4ccb 100644 --- a/variants/xiao_c6/XiaoC6Board.cpp +++ b/variants/xiao_c6/XiaoC6Board.cpp @@ -39,7 +39,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/xiao_c6/target.h b/variants/xiao_c6/target.h index 0fbb0bb2e..28b465383 100644 --- a/variants/xiao_c6/target.h +++ b/variants/xiao_c6/target.h @@ -17,5 +17,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/xiao_nrf52/target.cpp b/variants/xiao_nrf52/target.cpp index c9c02d215..a8f4162ea 100644 --- a/variants/xiao_nrf52/target.cpp +++ b/variants/xiao_nrf52/target.cpp @@ -34,7 +34,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/xiao_nrf52/target.h b/variants/xiao_nrf52/target.h index e1ea2a6b8..f4076c349 100644 --- a/variants/xiao_nrf52/target.h +++ b/variants/xiao_nrf52/target.h @@ -22,5 +22,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/xiao_rp2040/target.cpp b/variants/xiao_rp2040/target.cpp index b7c199758..6c9a91434 100644 --- a/variants/xiao_rp2040/target.cpp +++ b/variants/xiao_rp2040/target.cpp @@ -39,7 +39,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/xiao_rp2040/target.h b/variants/xiao_rp2040/target.h index 33b3766c2..528c44414 100644 --- a/variants/xiao_rp2040/target.h +++ b/variants/xiao_rp2040/target.h @@ -17,5 +17,5 @@ extern SensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); diff --git a/variants/xiao_s3_wio/target.cpp b/variants/xiao_s3_wio/target.cpp index 26cd27ac2..50981ab64 100644 --- a/variants/xiao_s3_wio/target.cpp +++ b/variants/xiao_s3_wio/target.cpp @@ -46,7 +46,7 @@ void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr) { radio.setCodingRate(cr); } -void radio_set_tx_power(uint8_t dbm) { +void radio_set_tx_power(int8_t dbm) { radio.setOutputPower(dbm); } diff --git a/variants/xiao_s3_wio/target.h b/variants/xiao_s3_wio/target.h index c3227368c..fffd16833 100644 --- a/variants/xiao_s3_wio/target.h +++ b/variants/xiao_s3_wio/target.h @@ -26,5 +26,5 @@ extern EnvironmentSensorManager sensors; bool radio_init(); uint32_t radio_get_rng_seed(); void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr); -void radio_set_tx_power(uint8_t dbm); +void radio_set_tx_power(int8_t dbm); mesh::LocalIdentity radio_new_identity(); From c4c287d01bd67dbc65028f21ca0892b89228bf21 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Sat, 7 Feb 2026 15:39:24 +0100 Subject: [PATCH 31/35] Bridge always has work (prevents sleep) --- examples/simple_repeater/MyMesh.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 6d957cc09..40b54555a 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -1219,5 +1219,8 @@ void MyMesh::loop() { // To check if there is pending work bool MyMesh::hasPendingWork() const { +#if defined(WITH_BRIDGE) + if (bridge.isRunning()) return true; // bridge needs WiFi radio, can't sleep +#endif return _mgr->getOutboundCount(0xFFFFFFFF) > 0; } From e8646f5ede777bc883079eec42d6989aa14b8f7a Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Sat, 7 Feb 2026 16:58:06 +0100 Subject: [PATCH 32/35] Parse as signed int --- examples/companion_radio/MyMesh.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index f8e90be5e..967160915 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1228,10 +1228,11 @@ void MyMesh::handleCmdFrame(size_t len) { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } } else if (cmd_frame[0] == CMD_SET_RADIO_TX_POWER) { - if (cmd_frame[1] > MAX_LORA_TX_POWER) { + int8_t power = (int8_t)cmd_frame[1]; + if (power < -9 || power > MAX_LORA_TX_POWER) { writeErrFrame(ERR_CODE_ILLEGAL_ARG); } else { - _prefs.tx_power_dbm = cmd_frame[1]; + _prefs.tx_power_dbm = power; savePrefs(); radio_set_tx_power(_prefs.tx_power_dbm); writeOKFrame(); From fcfbb458f82a5ca5f49a8225ebede2f84ec7a240 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Br=C3=A1zio?= Date: Sat, 7 Feb 2026 21:26:28 +0000 Subject: [PATCH 33/35] Refactor environment names and build flags for RAK variants --- variants/rak11310/platformio.ini | 15 +++++++------ variants/rak3112/platformio.ini | 37 ++++++++------------------------ variants/rak3401/platformio.ini | 1 - variants/rak3x72/platformio.ini | 7 +++--- 4 files changed, 21 insertions(+), 39 deletions(-) diff --git a/variants/rak11310/platformio.ini b/variants/rak11310/platformio.ini index df99ea843..950b46efa 100644 --- a/variants/rak11310/platformio.ini +++ b/variants/rak11310/platformio.ini @@ -7,6 +7,7 @@ board = rakwireless_rak11300 board_build.filesystem_size = 0.5m build_flags = ${rp2040_base.build_flags} -I variants/rak11310 + -D RAK_11310 -D ARDUINO_RAKWIRELESS_RAK11300=1 -D SX126X_CURRENT_LIMIT=140 -D RADIO_CLASS=CustomSX1262 @@ -34,7 +35,7 @@ build_src_filter = ${rp2040_base.build_src_filter} +<../variants/rak11310> lib_deps = ${rp2040_base.lib_deps} -[env:rak11310_repeater] +[env:RAK_11310_repeater] extends = rak11310 build_flags = ${rak11310.build_flags} -D ADVERT_NAME='"RAK11310 Repeater"' @@ -47,7 +48,7 @@ build_flags = ${rak11310.build_flags} build_src_filter = ${rak11310.build_src_filter} +<../examples/simple_repeater> -[env:rak11310_repeater_bridge_rs232] +[env:RAK_11310_repeater_bridge_rs232] extends = rak11310 build_flags = ${rak11310.build_flags} -D ADVERT_NAME='"RS232 Bridge"' @@ -65,7 +66,7 @@ build_src_filter = ${rak11310.build_src_filter} + +<../examples/simple_repeater> -[env:rak11310_room_server] +[env:RAK_11310_room_server] extends = rak11310 build_flags = ${rak11310.build_flags} -D ADVERT_NAME='"RAK11310 Room"' @@ -78,7 +79,7 @@ build_flags = ${rak11310.build_flags} build_src_filter = ${rak11310.build_src_filter} +<../examples/simple_room_server> -[env:rak11310_companion_radio_usb] +[env:RAK_11310_companion_radio_usb] extends = rak11310 build_flags = ${rak11310.build_flags} -D MAX_CONTACTS=100 @@ -90,7 +91,7 @@ build_src_filter = ${rak11310.build_src_filter} lib_deps = ${rak11310.lib_deps} densaugeo/base64 @ ~1.4.0 -; [env:rak11310_companion_radio_ble] +; [env:RAK_11310_companion_radio_ble] ; extends = rak11310 ; build_flags = ${rak11310.build_flags} ; -D MAX_CONTACTS=100 @@ -104,7 +105,7 @@ lib_deps = ${rak11310.lib_deps} ; lib_deps = ${rak11310.lib_deps} ; densaugeo/base64 @ ~1.4.0 -; [env:rak11310_companion_radio_wifi] +; [env:RAK_11310_companion_radio_wifi] ; extends = rak11310 ; build_flags = ${rak11310.build_flags} ; -D MAX_CONTACTS=100 @@ -119,7 +120,7 @@ lib_deps = ${rak11310.lib_deps} ; lib_deps = ${rak11310.lib_deps} ; densaugeo/base64 @ ~1.4.0 -[env:rak11310_terminal_chat] +[env:RAK_11310_terminal_chat] extends = rak11310 build_flags = ${rak11310.build_flags} -D MAX_CONTACTS=100 diff --git a/variants/rak3112/platformio.ini b/variants/rak3112/platformio.ini index 29ebdff27..bc43ee04d 100644 --- a/variants/rak3112/platformio.ini +++ b/variants/rak3112/platformio.ini @@ -36,11 +36,10 @@ lib_deps = ${esp32_base.lib_deps} ${sensor_base.lib_deps} -[env:RAK3112_repeater] +[env:RAK_3112_repeater] extends = rak3112 build_flags = ${rak3112.build_flags} - -D DISPLAY_CLASS=SSD1306Display -D ADVERT_NAME='"RAK3112 Repeater"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 @@ -49,18 +48,16 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak3112.build_src_filter} - + +<../examples/simple_repeater> lib_deps = ${rak3112.lib_deps} ${esp32_ota.lib_deps} bakercp/CRC32 @ ^2.0.0 -[env:RAK3112_repeater_bridge_rs232] +[env:RAK_3112_repeater_bridge_rs232] extends = rak3112 build_flags = ${rak3112.build_flags} - -D DISPLAY_CLASS=SSD1306Display -D ADVERT_NAME='"RS232 Bridge"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 @@ -74,17 +71,15 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${rak3112.build_src_filter} + - + +<../examples/simple_repeater> lib_deps = ${rak3112.lib_deps} ${esp32_ota.lib_deps} -[env:RAK3112_repeater_bridge_espnow] +[env:RAK_3112_repeater_bridge_espnow] extends = rak3112 build_flags = ${rak3112.build_flags} - -D DISPLAY_CLASS=SSD1306Display -D ADVERT_NAME='"ESPNow Bridge"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 @@ -96,17 +91,15 @@ build_flags = ; -D MESH_DEBUG=1 build_src_filter = ${rak3112.build_src_filter} + - + +<../examples/simple_repeater> lib_deps = ${rak3112.lib_deps} ${esp32_ota.lib_deps} -[env:RAK3112_room_server] +[env:RAK_3112_room_server] extends = rak3112 build_flags = ${rak3112.build_flags} - -D DISPLAY_CLASS=SSD1306Display -D ADVERT_NAME='"RAK3112 Room"' -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 @@ -115,13 +108,12 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak3112.build_src_filter} - + +<../examples/simple_room_server> lib_deps = ${rak3112.lib_deps} ${esp32_ota.lib_deps} -[env:RAK3112_terminal_chat] +[env:RAK_3112_terminal_chat] extends = rak3112 build_flags = ${rak3112.build_flags} @@ -135,33 +127,29 @@ lib_deps = ${rak3112.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:RAK3112_companion_radio_usb] +[env:RAK_3112_companion_radio_usb] extends = rak3112 build_flags = ${rak3112.build_flags} -I examples/companion_radio/ui-new -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 - -D DISPLAY_CLASS=SSD1306Display ; NOTE: DO NOT ENABLE --> -D MESH_PACKET_LOGGING=1 ; NOTE: DO NOT ENABLE --> -D MESH_DEBUG=1 build_src_filter = ${rak3112.build_src_filter} - + - + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> lib_deps = ${rak3112.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:RAK3112_companion_radio_ble] +[env:RAK_3112_companion_radio_ble] extends = rak3112 build_flags = ${rak3112.build_flags} -I examples/companion_radio/ui-new -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 - -D DISPLAY_CLASS=SSD1306Display -D BLE_PIN_CODE=123456 ; dynamic, random PIN -D AUTO_SHUTDOWN_MILLIVOLTS=3400 -D BLE_DEBUG_LOGGING=1 @@ -169,8 +157,6 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak3112.build_src_filter} - + - + + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> @@ -178,14 +164,13 @@ lib_deps = ${rak3112.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:RAK3112_companion_radio_wifi] +[env:RAK_3112_companion_radio_wifi] extends = rak3112 build_flags = ${rak3112.build_flags} -I examples/companion_radio/ui-new -D MAX_CONTACTS=350 -D MAX_GROUP_CHANNELS=40 - -D DISPLAY_CLASS=SSD1306Display -D WIFI_DEBUG_LOGGING=1 -D WIFI_SSID='"myssid"' -D WIFI_PWD='"mypwd"' @@ -193,8 +178,6 @@ build_flags = ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak3112.build_src_filter} - + - + + +<../examples/companion_radio/*.cpp> +<../examples/companion_radio/ui-new/*.cpp> @@ -202,7 +185,7 @@ lib_deps = ${rak3112.lib_deps} densaugeo/base64 @ ~1.4.0 -[env:RAK3112_sensor] +[env:RAK_3112_sensor] extends = rak3112 build_flags = ${rak3112.build_flags} @@ -212,11 +195,9 @@ build_flags = -D ADMIN_PASSWORD='"password"' -D ENV_PIN_SDA=33 -D ENV_PIN_SCL=34 - -D DISPLAY_CLASS=SSD1306Display ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 build_src_filter = ${rak3112.build_src_filter} - + +<../examples/simple_sensor> lib_deps = ${rak3112.lib_deps} diff --git a/variants/rak3401/platformio.ini b/variants/rak3401/platformio.ini index 30d35d0b4..7467ceb9c 100644 --- a/variants/rak3401/platformio.ini +++ b/variants/rak3401/platformio.ini @@ -6,7 +6,6 @@ build_flags = ${nrf52_base.build_flags} ${sensor_base.build_flags} -I variants/rak3401 -D RAK_3401 - -D RAK13302 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper -D LORA_TX_POWER=22 diff --git a/variants/rak3x72/platformio.ini b/variants/rak3x72/platformio.ini index a62600894..12ea413ab 100644 --- a/variants/rak3x72/platformio.ini +++ b/variants/rak3x72/platformio.ini @@ -3,6 +3,7 @@ extends = stm32_base board = rak3172 board_upload.maximum_size = 229376 ; 32kb for FS build_flags = ${stm32_base.build_flags} + -D RAK_3X72 -D RADIO_CLASS=CustomSTM32WLx -D WRAPPER_CLASS=CustomSTM32WLxWrapper -D SPI_INTERFACES_COUNT=0 @@ -13,7 +14,7 @@ build_flags = ${stm32_base.build_flags} build_src_filter = ${stm32_base.build_src_filter} +<../variants/rak3x72> -[env:rak3x72_repeater] +[env:RAK_3x72_repeater] extends = rak3x72 build_flags = ${rak3x72.build_flags} -D ADVERT_NAME='"RAK3x72 Repeater"' @@ -22,7 +23,7 @@ build_flags = ${rak3x72.build_flags} build_src_filter = ${rak3x72.build_src_filter} +<../examples/simple_repeater/*.cpp> -[env:rak3x72_sensor] +[env:RAK_3x72_sensor] extends = rak3x72 build_flags = ${rak3x72.build_flags} -D ADVERT_NAME='"RAK3x72 Sensor"' @@ -30,7 +31,7 @@ build_flags = ${rak3x72.build_flags} build_src_filter = ${rak3x72.build_src_filter} +<../examples/simple_sensor> -[env:rak3x72_companion_radio_usb] +[env:RAK_3x72_companion_radio_usb] extends = rak3x72 build_flags = ${rak3x72.build_flags} ; -D FORMAT_FS=true From 31a2e74ada0b644ad955b19b872ddf662849fbbc Mon Sep 17 00:00:00 2001 From: Thane Gill Date: Sat, 7 Feb 2026 16:56:20 -0800 Subject: [PATCH 34/35] Correct manufacturer name 'Elecrow ThinkNode M5' --- variants/thinknode_m5/ThinknodeM5Board.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/thinknode_m5/ThinknodeM5Board.cpp b/variants/thinknode_m5/ThinknodeM5Board.cpp index 5adc8c005..c4de538c5 100644 --- a/variants/thinknode_m5/ThinknodeM5Board.cpp +++ b/variants/thinknode_m5/ThinknodeM5Board.cpp @@ -43,5 +43,5 @@ void ThinknodeM5Board::begin() { } const char* ThinknodeM5Board::getManufacturerName() const { - return "Elecrow ThinkNode M2"; + return "Elecrow ThinkNode M5"; } From d5b17b1ce245f912639862af105ed5a0fef03596 Mon Sep 17 00:00:00 2001 From: overkillfpv Date: Mon, 9 Feb 2026 23:04:30 +1100 Subject: [PATCH 35/35] changed preambles to 32 --- src/helpers/esp32/TBeamBoard.cpp | 4 ++-- src/helpers/radiolib/CustomLLCC68.h | 4 ++-- src/helpers/radiolib/CustomLR1110Wrapper.h | 2 +- src/helpers/radiolib/CustomSX1262.h | 4 ++-- src/helpers/radiolib/CustomSX1268.h | 4 ++-- src/helpers/radiolib/CustomSX1276.h | 2 +- variants/ebyte_eora_s3/target.cpp | 2 +- variants/minewsemi_me25ls01/target.cpp | 2 +- variants/rak3x72/target.cpp | 2 +- variants/t1000-e/target.cpp | 2 +- variants/thinknode_m3/target.cpp | 2 +- variants/tiny_relay/target.cpp | 2 +- variants/wio-e5-dev/target.cpp | 2 +- variants/wio-e5-mini/target.cpp | 2 +- variants/wio_wm1110/target.cpp | 2 +- 15 files changed, 19 insertions(+), 19 deletions(-) diff --git a/src/helpers/esp32/TBeamBoard.cpp b/src/helpers/esp32/TBeamBoard.cpp index 5f708d71d..7dcfa8f77 100644 --- a/src/helpers/esp32/TBeamBoard.cpp +++ b/src/helpers/esp32/TBeamBoard.cpp @@ -299,7 +299,7 @@ bool TBeamBoard::power_init() // switch(i){ // case 0: // CustomSX1262 radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi); -// int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); +// int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32); // if (status != RADIOLIB_ERR_NONE) { // Serial.print("ERROR: SX1262 not found: "); // Serial.println(status); @@ -320,7 +320,7 @@ bool TBeamBoard::power_init() // } // case 1: // SX1276 radio = new Module(P_LORA_NSS, P_LORA_DIO_0, P_LORA_RESET, P_LORA_DIO_1, spi); -// int status1 = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8); +// int status1 = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32); // if (status1 != RADIOLIB_ERR_NONE) { // Serial.print("ERROR: SX1272 not found: "); // Serial.println(status1); diff --git a/src/helpers/radiolib/CustomLLCC68.h b/src/helpers/radiolib/CustomLLCC68.h index c239cc412..374fac6b5 100644 --- a/src/helpers/radiolib/CustomLLCC68.h +++ b/src/helpers/radiolib/CustomLLCC68.h @@ -42,12 +42,12 @@ class CustomLLCC68 : public LLCC68 { if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif #endif - int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) { #define SX126X_DIO3_TCXO_VOLTAGE (0.0f); tcxo = SX126X_DIO3_TCXO_VOLTAGE; - status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); } if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/src/helpers/radiolib/CustomLR1110Wrapper.h b/src/helpers/radiolib/CustomLR1110Wrapper.h index 947bb51dd..0f5d5bfe8 100644 --- a/src/helpers/radiolib/CustomLR1110Wrapper.h +++ b/src/helpers/radiolib/CustomLR1110Wrapper.h @@ -17,7 +17,7 @@ class CustomLR1110Wrapper : public RadioLibWrapper { void onSendFinished() override { RadioLibWrapper::onSendFinished(); - _radio->setPreambleLength(16); // overcomes weird issues with small and big pkts + _radio->setPreambleLength(32); // overcomes weird issues with small and big pkts } float getLastRSSI() const override { return ((CustomLR1110 *)_radio)->getRSSI(); } diff --git a/src/helpers/radiolib/CustomSX1262.h b/src/helpers/radiolib/CustomSX1262.h index be6812c6f..fd8e5e848 100644 --- a/src/helpers/radiolib/CustomSX1262.h +++ b/src/helpers/radiolib/CustomSX1262.h @@ -42,12 +42,12 @@ class CustomSX1262 : public SX1262 { if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif #endif - int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) { #define SX126X_DIO3_TCXO_VOLTAGE (0.0f); tcxo = SX126X_DIO3_TCXO_VOLTAGE; - status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); } if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/src/helpers/radiolib/CustomSX1268.h b/src/helpers/radiolib/CustomSX1268.h index 1e2e26204..83d3b749b 100644 --- a/src/helpers/radiolib/CustomSX1268.h +++ b/src/helpers/radiolib/CustomSX1268.h @@ -42,12 +42,12 @@ class CustomSX1268 : public SX1268 { if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif #endif - int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f if (status == RADIOLIB_ERR_SPI_CMD_FAILED || status == RADIOLIB_ERR_SPI_CMD_INVALID) { #define SX126X_DIO3_TCXO_VOLTAGE (0.0f); tcxo = SX126X_DIO3_TCXO_VOLTAGE; - status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); } if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/src/helpers/radiolib/CustomSX1276.h b/src/helpers/radiolib/CustomSX1276.h index bee252743..4da5711c6 100644 --- a/src/helpers/radiolib/CustomSX1276.h +++ b/src/helpers/radiolib/CustomSX1276.h @@ -39,7 +39,7 @@ class CustomSX1276 : public SX1276 { if (spi) spi->begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif #endif - int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16); + int status = begin(LORA_FREQ, LORA_BW, LORA_SF, cr, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32); // if radio init fails with -707/-706, try again with tcxo voltage set to 0.0f if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/ebyte_eora_s3/target.cpp b/variants/ebyte_eora_s3/target.cpp index 501f560be..48a5f64c0 100644 --- a/variants/ebyte_eora_s3/target.cpp +++ b/variants/ebyte_eora_s3/target.cpp @@ -38,7 +38,7 @@ bool radio_init() { #if defined(P_LORA_SCLK) spi.begin(P_LORA_SCLK, P_LORA_MISO, P_LORA_MOSI); #endif - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 8, tcxo); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); Serial.println(status); diff --git a/variants/minewsemi_me25ls01/target.cpp b/variants/minewsemi_me25ls01/target.cpp index fcec19419..25d10f253 100644 --- a/variants/minewsemi_me25ls01/target.cpp +++ b/variants/minewsemi_me25ls01/target.cpp @@ -58,7 +58,7 @@ bool radio_init() { SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); SPI.begin(); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); Serial.println(status); diff --git a/variants/rak3x72/target.cpp b/variants/rak3x72/target.cpp index 48e7f4228..4988ac0dc 100644 --- a/variants/rak3x72/target.cpp +++ b/variants/rak3x72/target.cpp @@ -38,7 +38,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, STM32WL_TCXO_VOLTAGE, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, STM32WL_TCXO_VOLTAGE, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index da8fa48bb..b3818cb99 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -54,7 +54,7 @@ bool radio_init() { SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); SPI.begin(); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); Serial.println(status); diff --git a/variants/thinknode_m3/target.cpp b/variants/thinknode_m3/target.cpp index ca2b0aa06..81a60531f 100644 --- a/variants/thinknode_m3/target.cpp +++ b/variants/thinknode_m3/target.cpp @@ -58,7 +58,7 @@ bool radio_init() { SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); SPI.begin(); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); Serial.println(status); diff --git a/variants/tiny_relay/target.cpp b/variants/tiny_relay/target.cpp index 313dfaa94..9e15a7596 100644 --- a/variants/tiny_relay/target.cpp +++ b/variants/tiny_relay/target.cpp @@ -39,7 +39,7 @@ bool radio_init() radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, STM32WL_TCXO_VOLTAGE, 0); if (status != RADIOLIB_ERR_NONE) { diff --git a/variants/wio-e5-dev/target.cpp b/variants/wio-e5-dev/target.cpp index 3e59b6cee..2471aa160 100644 --- a/variants/wio-e5-dev/target.cpp +++ b/variants/wio-e5-dev/target.cpp @@ -35,7 +35,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, 1.7, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, 1.7, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/wio-e5-mini/target.cpp b/variants/wio-e5-mini/target.cpp index 2e95ad6d1..2f5bc4c15 100644 --- a/variants/wio-e5-mini/target.cpp +++ b/variants/wio-e5-mini/target.cpp @@ -33,7 +33,7 @@ bool radio_init() { radio.setRfSwitchTable(rfswitch_pins, rfswitch_table); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, 1.7, 0); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_SX126X_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, 1.7, 0); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); diff --git a/variants/wio_wm1110/target.cpp b/variants/wio_wm1110/target.cpp index 457d5bda2..e532157cd 100644 --- a/variants/wio_wm1110/target.cpp +++ b/variants/wio_wm1110/target.cpp @@ -49,7 +49,7 @@ bool radio_init() { SPI.setPins(P_LORA_MISO, P_LORA_SCLK, P_LORA_MOSI); SPI.begin(); - int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 16, tcxo); + int status = radio.begin(LORA_FREQ, LORA_BW, LORA_SF, LORA_CR, RADIOLIB_LR11X0_LORA_SYNC_WORD_PRIVATE, LORA_TX_POWER, 32, tcxo); if (status != RADIOLIB_ERR_NONE) { Serial.print("ERROR: radio init failed: "); Serial.println(status);