From 52de2096abb0b18a31ad4e78dda35e35d29870d5 Mon Sep 17 00:00:00 2001 From: taco Date: Tue, 9 Sep 2025 17:38:10 +1000 Subject: [PATCH 01/14] fix incorrect ram and flash sizes in board jsons --- boards/heltec_mesh_pocket.json | 2 +- boards/heltec_mesh_solar.json | 2 +- boards/heltec_t114.json | 2 +- boards/minewsemi_me25ls01.json | 4 ++-- boards/nano-g2-ultra.json | 2 +- boards/promicro_nrf52840.json | 2 +- boards/seeed-wio-tracker-l1.json | 2 +- boards/seeed-xiao-afruitnrf52-nrf52840.json | 2 +- boards/seeed_sensecap_solar.json | 4 ++-- boards/t-echo.json | 2 +- boards/thinknode_m1.json | 2 +- boards/tracker-t1000-e.json | 4 ++-- 12 files changed, 15 insertions(+), 15 deletions(-) diff --git a/boards/heltec_mesh_pocket.json b/boards/heltec_mesh_pocket.json index 6fb48a46..e6a04c12 100644 --- a/boards/heltec_mesh_pocket.json +++ b/boards/heltec_mesh_pocket.json @@ -39,7 +39,7 @@ "frameworks": ["arduino"], "name": "Heltec nrf (Adafruit BSP)", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/heltec_mesh_solar.json b/boards/heltec_mesh_solar.json index c9125811..dcd1da64 100644 --- a/boards/heltec_mesh_solar.json +++ b/boards/heltec_mesh_solar.json @@ -42,7 +42,7 @@ ], "name": "Heltec Mesh Solar Board", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/heltec_t114.json b/boards/heltec_t114.json index 86f72e73..a4a61d04 100644 --- a/boards/heltec_t114.json +++ b/boards/heltec_t114.json @@ -42,7 +42,7 @@ ], "name": "Heltec T114 Board", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/minewsemi_me25ls01.json b/boards/minewsemi_me25ls01.json index 4c943158..928acb0e 100644 --- a/boards/minewsemi_me25ls01.json +++ b/boards/minewsemi_me25ls01.json @@ -38,8 +38,8 @@ "frameworks": ["arduino"], "name": "Minewsemi ME25LS01", "upload": { - "maximum_ram_size": 248832, - "maximum_size": 815104, + "maximum_ram_size": 235520, + "maximum_size": 811008, "speed": 115200, "protocol": "nrfutil", "protocols": [ diff --git a/boards/nano-g2-ultra.json b/boards/nano-g2-ultra.json index 9fa22d7b..3246167e 100644 --- a/boards/nano-g2-ultra.json +++ b/boards/nano-g2-ultra.json @@ -54,7 +54,7 @@ ], "name": "BQ nRF52840", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/promicro_nrf52840.json b/boards/promicro_nrf52840.json index a428ffde..a4460f31 100644 --- a/boards/promicro_nrf52840.json +++ b/boards/promicro_nrf52840.json @@ -60,7 +60,7 @@ ], "name": "ProMicro NRF52840", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/seeed-wio-tracker-l1.json b/boards/seeed-wio-tracker-l1.json index 6235b8bf..772727b6 100644 --- a/boards/seeed-wio-tracker-l1.json +++ b/boards/seeed-wio-tracker-l1.json @@ -40,7 +40,7 @@ ], "name": "Seeed Wio Tracker L1", "upload": { - "maximum_ram_size": 237568, + "maximum_ram_size": 235520, "maximum_size": 811008, "protocol": "nrfutil", "speed": 115200, diff --git a/boards/seeed-xiao-afruitnrf52-nrf52840.json b/boards/seeed-xiao-afruitnrf52-nrf52840.json index 78855cd7..9a60e0a7 100644 --- a/boards/seeed-xiao-afruitnrf52-nrf52840.json +++ b/boards/seeed-xiao-afruitnrf52-nrf52840.json @@ -40,7 +40,7 @@ ], "name": "Seeed Studio XIAO nRF52840", "upload": { - "maximum_ram_size": 237568, + "maximum_ram_size": 235520, "maximum_size": 811008, "protocol": "nrfutil", "speed": 115200, diff --git a/boards/seeed_sensecap_solar.json b/boards/seeed_sensecap_solar.json index d6630d82..50f08976 100644 --- a/boards/seeed_sensecap_solar.json +++ b/boards/seeed_sensecap_solar.json @@ -39,8 +39,8 @@ ], "name": "Seeed Studio XIAO nRF52840", "upload": { - "maximum_ram_size": 248832, - "maximum_size": 815104, + "maximum_ram_size": 235520, + "maximum_size": 811008, "protocol": "nrfutil", "speed": 115200, "protocols": [ diff --git a/boards/t-echo.json b/boards/t-echo.json index 8deea1bc..c974ca65 100644 --- a/boards/t-echo.json +++ b/boards/t-echo.json @@ -45,7 +45,7 @@ ], "name": "LilyGo T-ECHO", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "require_upload_port": true, "speed": 115200, diff --git a/boards/thinknode_m1.json b/boards/thinknode_m1.json index 9f486285..5313d2a1 100644 --- a/boards/thinknode_m1.json +++ b/boards/thinknode_m1.json @@ -53,7 +53,7 @@ ], "name": "elecrow eink", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "use_1200bps_touch": true, diff --git a/boards/tracker-t1000-e.json b/boards/tracker-t1000-e.json index fc740ac5..330455f5 100644 --- a/boards/tracker-t1000-e.json +++ b/boards/tracker-t1000-e.json @@ -38,8 +38,8 @@ "frameworks": ["arduino"], "name": "Seeed T1000-E", "upload": { - "maximum_ram_size": 248832, - "maximum_size": 815104, + "maximum_ram_size": 235520, + "maximum_size": 811008, "speed": 115200, "protocol": "nrfutil", "protocols": [ From 119b8f29e613e3b341db25b3fa25adbe6edad5a7 Mon Sep 17 00:00:00 2001 From: taco Date: Wed, 10 Sep 2025 00:05:14 +1000 Subject: [PATCH 02/14] add rak4631 board json --- boards/wiscore_rak4631.json | 76 +++++++++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 boards/wiscore_rak4631.json diff --git a/boards/wiscore_rak4631.json b/boards/wiscore_rak4631.json new file mode 100644 index 00000000..601974f6 --- /dev/null +++ b/boards/wiscore_rak4631.json @@ -0,0 +1,76 @@ +{ + "build": { + "arduino": { + "ldscript": "nrf52840_s140_v6.ld" + }, + "core": "nRF5", + "cpu": "cortex-m4", + "extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA", + "f_cpu": "64000000L", + "hwids": [ + [ + "0x239A", + "0x8029" + ], + [ + "0x239A", + "0x0029" + ], + [ + "0x239A", + "0x002A" + ], + [ + "0x239A", + "0x802A" + ] + ], + "usb_product": "WisCore RAK4631 Board", + "mcu": "nrf52840", + "variant": "WisCore_RAK4631_Board", + "bsp": { + "name": "adafruit" + }, + "softdevice": { + "sd_flags": "-DS140", + "sd_name": "s140", + "sd_version": "6.1.1", + "sd_fwid": "0x00B6" + }, + "bootloader": { + "settings_addr": "0xFF000" + } + }, + "connectivity": [ + "bluetooth" + ], + "debug": { + "jlink_device": "nRF52840_xxAA", + "onboard_tools": [ + "jlink" + ], + "svd_path": "nrf52840.svd", + "openocd_target": "nrf52.cfg" + }, + "frameworks": [ + "arduino" + ], + "name": "WisCore RAK4631 Board", + "upload": { + "maximum_ram_size": 235520, + "maximum_size": 815104, + "speed": 115200, + "protocol": "nrfutil", + "protocols": [ + "jlink", + "nrfjprog", + "nrfutil", + "stlink" + ], + "use_1200bps_touch": true, + "require_upload_port": true, + "wait_for_upload_port": true + }, + "url": "https://www.rakwireless.com", + "vendor": "RAKwireless" +} From 0084d9223913074211dbe6bfb321b50b324b0604 Mon Sep 17 00:00:00 2001 From: Alexander aka R6DJO Date: Wed, 14 Jan 2026 09:30:20 +0300 Subject: [PATCH 03/14] Fix T1000-E negative temperature display bug MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The ntc_temp2 lookup table was declared as 'char', which can be unsigned on some platforms, causing negative temperature values (-30°C to -1°C) to be incorrectly interpreted. Changed to int8_t to ensure proper signed integer handling of negative temperatures. Fixes #1389 Co-Authored-By: Claude Sonnet 4.5 --- variants/t1000-e/t1000e_sensors.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/t1000-e/t1000e_sensors.cpp b/variants/t1000-e/t1000e_sensors.cpp index f0254138..85298d3a 100644 --- a/variants/t1000-e/t1000e_sensors.cpp +++ b/variants/t1000-e/t1000e_sensors.cpp @@ -21,7 +21,7 @@ static unsigned int ntc_res2[136] = { 1081, 1053, 1026, 999, 974, 949, 925, 902, 880, 858, }; -static char ntc_temp2[136] = { +static int8_t ntc_temp2[136] = { -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17, -16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, From 46012f89e7b08cf76abbacf83b7198029c764164 Mon Sep 17 00:00:00 2001 From: Marnick Hartgers Date: Tue, 3 Feb 2026 23:06:00 +0100 Subject: [PATCH 04/14] gps for sensecap p1 solar --- variants/sensecap_solar/platformio.ini | 2 +- variants/sensecap_solar/target.cpp | 8 +++++++- variants/sensecap_solar/variant.cpp | 5 ----- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/variants/sensecap_solar/platformio.ini b/variants/sensecap_solar/platformio.ini index d4fb7b44..9cf03486 100644 --- a/variants/sensecap_solar/platformio.ini +++ b/variants/sensecap_solar/platformio.ini @@ -8,7 +8,6 @@ build_flags = ${nrf52_base.build_flags} -I lib/nrf52/s140_nrf52_7.3.0_API/include/nrf52 -I variants/sensecap_solar -I src/helpers/nrf52 - -UENV_INCLUDE_GPS -D NRF52_PLATFORM=1 -D RADIO_CLASS=CustomSX1262 -D WRAPPER_CLASS=CustomSX1262Wrapper @@ -24,6 +23,7 @@ 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 ENV_INCLUDE_GPS=1 build_src_filter = ${nrf52_base.build_src_filter} + + diff --git a/variants/sensecap_solar/target.cpp b/variants/sensecap_solar/target.cpp index 6bd7d31a..b88774b6 100644 --- a/variants/sensecap_solar/target.cpp +++ b/variants/sensecap_solar/target.cpp @@ -1,6 +1,7 @@ #include #include "target.h" #include +#include SenseCapSolarBoard board; @@ -10,7 +11,12 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -EnvironmentSensorManager sensors; +#ifdef ENV_INCLUDE_GPS +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); +EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); +#else +EnvironmentSensorManager sensors = EnvironmentSensorManager(); +#endif bool radio_init() { rtc_clock.begin(Wire); diff --git a/variants/sensecap_solar/variant.cpp b/variants/sensecap_solar/variant.cpp index 05774c10..d7fdce49 100644 --- a/variants/sensecap_solar/variant.cpp +++ b/variants/sensecap_solar/variant.cpp @@ -63,9 +63,4 @@ void initVariant() { pinMode(LED_BLUE, OUTPUT); digitalWrite(LED_BLUE, LOW); - - /* disable gps until we actually support it. - pinMode(GPS_EN, OUTPUT); - digitalWrite(GPS_EN, HIGH); - */ } From 0a66dee990c5997da46175524134e6d864069d33 Mon Sep 17 00:00:00 2001 From: Marnick Hartgers Date: Fri, 6 Feb 2026 00:12:22 +0100 Subject: [PATCH 05/14] fixed build without ENV_INCLUDE_GPS --- variants/sensecap_solar/target.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/variants/sensecap_solar/target.cpp b/variants/sensecap_solar/target.cpp index b88774b6..05ddbdeb 100644 --- a/variants/sensecap_solar/target.cpp +++ b/variants/sensecap_solar/target.cpp @@ -1,8 +1,9 @@ #include #include "target.h" #include +#ifdef ENV_INCLUDE_GPS #include - +#endif SenseCapSolarBoard board; RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, SPI); From c436bd42c5961c02eb439fe4ce2584b27f832eff Mon Sep 17 00:00:00 2001 From: Daniel Novak Date: Sat, 28 Feb 2026 16:22:58 +0100 Subject: [PATCH 06/14] Fix countBefore sentinel regression from millis wraparound fix PR #1795 changed PacketQueue::countBefore() to use signed 2's complement arithmetic for millis wraparound safety. However, this broke the 0xFFFFFFFF sentinel pattern used by callers to mean "count all packets regardless of schedule". With the signed comparison, countBefore(0xFFFFFFFF) always returns 0, causing hasPendingWork() to report false and repeaters to sleep with packets still queued. Stats reporting also shows queue_len as 0. Add an early-return for the sentinel value before the loop, and document the sentinel convention on the virtual interface and implementation. --- src/Dispatcher.h | 2 +- src/helpers/StaticPoolPacketManager.cpp | 1 + src/helpers/StaticPoolPacketManager.h | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Dispatcher.h b/src/Dispatcher.h index 0a448c40..7ecee1a4 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -89,7 +89,7 @@ public: virtual void queueOutbound(Packet* packet, uint8_t priority, uint32_t scheduled_for) = 0; virtual Packet* getNextOutbound(uint32_t now) = 0; // by priority - virtual int getOutboundCount(uint32_t now) const = 0; + virtual int getOutboundCount(uint32_t now) const = 0; // pass now=0xFFFFFFFF to count all virtual int getFreeCount() const = 0; virtual Packet* getOutboundByIdx(int i) = 0; virtual Packet* removeOutboundByIdx(int i) = 0; diff --git a/src/helpers/StaticPoolPacketManager.cpp b/src/helpers/StaticPoolPacketManager.cpp index 67d63979..c89d5088 100644 --- a/src/helpers/StaticPoolPacketManager.cpp +++ b/src/helpers/StaticPoolPacketManager.cpp @@ -9,6 +9,7 @@ PacketQueue::PacketQueue(int max_entries) { } int PacketQueue::countBefore(uint32_t now) const { + if (now == 0xFFFFFFFF) return _num; // sentinel: count all entries regardless of schedule int n = 0; for (int j = 0; j < _num; j++) { if ((int32_t)(_schedule_table[j] - now) > 0) continue; // scheduled for future... ignore for now diff --git a/src/helpers/StaticPoolPacketManager.h b/src/helpers/StaticPoolPacketManager.h index 52c299db..bcc5deb9 100644 --- a/src/helpers/StaticPoolPacketManager.h +++ b/src/helpers/StaticPoolPacketManager.h @@ -13,7 +13,7 @@ public: mesh::Packet* get(uint32_t now); bool add(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for); int count() const { return _num; } - int countBefore(uint32_t now) const; + int countBefore(uint32_t now) const; // pass now=0xFFFFFFFF to count all mesh::Packet* itemAt(int i) const { return _table[i]; } mesh::Packet* removeByIdx(int i); }; From c7568a8db07194beee71072120ffc1f27389d3e5 Mon Sep 17 00:00:00 2001 From: Daniel Novak Date: Sat, 28 Feb 2026 17:19:04 +0100 Subject: [PATCH 07/14] Replace 0xFFFFFFFF sentinel with explicit getOutboundTotal() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Instead of overloading getOutboundCount() with a magic sentinel value, add a dedicated getOutboundTotal() method to the PacketManager interface that returns the total queue size without time filtering. This eliminates the fragile convention that caused the regression and makes the two operations — time-filtered count vs total count — explicitly separate in the API. --- examples/companion_radio/MyMesh.cpp | 2 +- examples/simple_repeater/MyMesh.cpp | 4 ++-- examples/simple_room_server/MyMesh.cpp | 2 +- src/Dispatcher.h | 3 ++- src/helpers/StaticPoolPacketManager.cpp | 5 ++++- src/helpers/StaticPoolPacketManager.h | 3 ++- src/helpers/StatsFormatHelper.h | 2 +- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/examples/companion_radio/MyMesh.cpp b/examples/companion_radio/MyMesh.cpp index c96f7e01..952055d9 100644 --- a/examples/companion_radio/MyMesh.cpp +++ b/examples/companion_radio/MyMesh.cpp @@ -1712,7 +1712,7 @@ void MyMesh::handleCmdFrame(size_t len) { out_frame[i++] = STATS_TYPE_CORE; uint16_t battery_mv = board.getBattMilliVolts(); uint32_t uptime_secs = _ms->getMillis() / 1000; - uint8_t queue_len = (uint8_t)_mgr->getOutboundCount(0xFFFFFFFF); + uint8_t queue_len = (uint8_t)_mgr->getOutboundTotal(); memcpy(&out_frame[i], &battery_mv, 2); i += 2; memcpy(&out_frame[i], &uptime_secs, 4); i += 4; memcpy(&out_frame[i], &_err_flags, 2); i += 2; diff --git a/examples/simple_repeater/MyMesh.cpp b/examples/simple_repeater/MyMesh.cpp index 81c1dcb4..03ebe0e2 100644 --- a/examples/simple_repeater/MyMesh.cpp +++ b/examples/simple_repeater/MyMesh.cpp @@ -219,7 +219,7 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t if (payload[0] == REQ_TYPE_GET_STATUS) { // guests can also access this now RepeaterStats stats; stats.batt_milli_volts = board.getBattMilliVolts(); - stats.curr_tx_queue_len = _mgr->getOutboundCount(0xFFFFFFFF); + stats.curr_tx_queue_len = _mgr->getOutboundTotal(); stats.noise_floor = (int16_t)_radio->getNoiseFloor(); stats.last_rssi = (int16_t)radio_driver.getLastRSSI(); stats.n_packets_recv = radio_driver.getPacketsRecv(); @@ -1290,5 +1290,5 @@ 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; + return _mgr->getOutboundTotal() > 0; } diff --git a/examples/simple_room_server/MyMesh.cpp b/examples/simple_room_server/MyMesh.cpp index 5451505a..8b52f45b 100644 --- a/examples/simple_room_server/MyMesh.cpp +++ b/examples/simple_room_server/MyMesh.cpp @@ -140,7 +140,7 @@ int MyMesh::handleRequest(ClientInfo *sender, uint32_t sender_timestamp, uint8_t if (payload[0] == REQ_TYPE_GET_STATUS) { ServerStats stats; stats.batt_milli_volts = board.getBattMilliVolts(); - stats.curr_tx_queue_len = _mgr->getOutboundCount(0xFFFFFFFF); + stats.curr_tx_queue_len = _mgr->getOutboundTotal(); stats.noise_floor = (int16_t)_radio->getNoiseFloor(); stats.last_rssi = (int16_t)radio_driver.getLastRSSI(); stats.n_packets_recv = radio_driver.getPacketsRecv(); diff --git a/src/Dispatcher.h b/src/Dispatcher.h index 7ecee1a4..7ddac9e9 100644 --- a/src/Dispatcher.h +++ b/src/Dispatcher.h @@ -89,7 +89,8 @@ public: virtual void queueOutbound(Packet* packet, uint8_t priority, uint32_t scheduled_for) = 0; virtual Packet* getNextOutbound(uint32_t now) = 0; // by priority - virtual int getOutboundCount(uint32_t now) const = 0; // pass now=0xFFFFFFFF to count all + virtual int getOutboundCount(uint32_t now) const = 0; + virtual int getOutboundTotal() const = 0; virtual int getFreeCount() const = 0; virtual Packet* getOutboundByIdx(int i) = 0; virtual Packet* removeOutboundByIdx(int i) = 0; diff --git a/src/helpers/StaticPoolPacketManager.cpp b/src/helpers/StaticPoolPacketManager.cpp index c89d5088..7ef2dafa 100644 --- a/src/helpers/StaticPoolPacketManager.cpp +++ b/src/helpers/StaticPoolPacketManager.cpp @@ -9,7 +9,6 @@ PacketQueue::PacketQueue(int max_entries) { } int PacketQueue::countBefore(uint32_t now) const { - if (now == 0xFFFFFFFF) return _num; // sentinel: count all entries regardless of schedule int n = 0; for (int j = 0; j < _num; j++) { if ((int32_t)(_schedule_table[j] - now) > 0) continue; // scheduled for future... ignore for now @@ -98,6 +97,10 @@ int StaticPoolPacketManager::getOutboundCount(uint32_t now) const { return send_queue.countBefore(now); } +int StaticPoolPacketManager::getOutboundTotal() const { + return send_queue.count(); +} + int StaticPoolPacketManager::getFreeCount() const { return unused.count(); } diff --git a/src/helpers/StaticPoolPacketManager.h b/src/helpers/StaticPoolPacketManager.h index bcc5deb9..59715b4e 100644 --- a/src/helpers/StaticPoolPacketManager.h +++ b/src/helpers/StaticPoolPacketManager.h @@ -13,7 +13,7 @@ public: mesh::Packet* get(uint32_t now); bool add(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for); int count() const { return _num; } - int countBefore(uint32_t now) const; // pass now=0xFFFFFFFF to count all + int countBefore(uint32_t now) const; mesh::Packet* itemAt(int i) const { return _table[i]; } mesh::Packet* removeByIdx(int i); }; @@ -29,6 +29,7 @@ public: void queueOutbound(mesh::Packet* packet, uint8_t priority, uint32_t scheduled_for) override; mesh::Packet* getNextOutbound(uint32_t now) override; int getOutboundCount(uint32_t now) const override; + int getOutboundTotal() const override; int getFreeCount() const override; mesh::Packet* getOutboundByIdx(int i) override; mesh::Packet* removeOutboundByIdx(int i) override; diff --git a/src/helpers/StatsFormatHelper.h b/src/helpers/StatsFormatHelper.h index 5aa01da9..bf619133 100644 --- a/src/helpers/StatsFormatHelper.h +++ b/src/helpers/StatsFormatHelper.h @@ -14,7 +14,7 @@ public: board.getBattMilliVolts(), ms.getMillis() / 1000, err_flags, - mgr->getOutboundCount(0xFFFFFFFF) + mgr->getOutboundTotal() ); } From 0d87dcc989609d570ec06400b4f3f5a40fc8f74d Mon Sep 17 00:00:00 2001 From: Daniel Novak Date: Sun, 1 Mar 2026 07:39:43 +0100 Subject: [PATCH 08/14] Also fix countBefore(0xFFFFFFFF) to return _num The signed comparison in countBefore breaks for the max uint32_t value. Even though callers now use getOutboundTotal(), the function itself should be correct for all inputs. --- src/helpers/StaticPoolPacketManager.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/helpers/StaticPoolPacketManager.cpp b/src/helpers/StaticPoolPacketManager.cpp index 7ef2dafa..b8926df0 100644 --- a/src/helpers/StaticPoolPacketManager.cpp +++ b/src/helpers/StaticPoolPacketManager.cpp @@ -9,6 +9,8 @@ PacketQueue::PacketQueue(int max_entries) { } int PacketQueue::countBefore(uint32_t now) const { + if (now == 0xFFFFFFFF) return _num; // sentinel: count all entries regardless of schedule + int n = 0; for (int j = 0; j < _num; j++) { if ((int32_t)(_schedule_table[j] - now) > 0) continue; // scheduled for future... ignore for now From 10f2fecd45f5f06ca843b46f52423bcc347ecf82 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Fri, 9 Jan 2026 04:54:51 +0100 Subject: [PATCH 09/14] Sync time with GPS every 30 minutes Unless your GPS is being spoofed there isn't really a downside to syncing more often with GPS. I understand the RTC is very stable, but especially with powersaving now clock drift is worse, we should sync more often. --- src/helpers/sensors/MicroNMEALocationProvider.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index 1de75327..a1eaa6bb 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -43,6 +43,8 @@ class MicroNMEALocationProvider : public LocationProvider { int _pin_en; long next_check = 0; long time_valid = 0; + unsigned long _last_time_sync = 0; + static const unsigned long TIME_SYNC_INTERVAL = 1800000; // Re-sync every 30 minutes public : MicroNMEALocationProvider(Stream& ser, mesh::RTCClock* clock = NULL, int pin_reset = GPS_RESET, int pin_en = GPS_EN,RefCountedDigitalPin* peripher_power=NULL) : @@ -129,10 +131,15 @@ public : if (millis() > next_check) { next_check = millis() + 1000; + // Re-enable time sync periodically when GPS has valid fix + if (!_time_sync_needed && _clock != NULL && (millis() - _last_time_sync) > TIME_SYNC_INTERVAL) { + _time_sync_needed = true; + } if (_time_sync_needed && time_valid > 2) { if (_clock != NULL) { _clock->setCurrentTime(getTimestamp()); _time_sync_needed = false; + _last_time_sync = millis(); } } if (isValid()) { From 67d22401b1327dc04235d10a0fc82351039660bb Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Sat, 10 Jan 2026 17:57:39 +0100 Subject: [PATCH 10/14] Pass rtc_clock to all MicroNMEALocationProvider instances Enable GPS time synchronization across all variants by passing &rtc_clock to MicroNMEALocationProvider. When GPS gets a valid fix, the RTC clock is now updated automatically every 30 minutes. Updated 16 variants: rak4631, lilygo_tbeam_SX1262, rak_wismesh_tag, lilygo_tbeam_supreme_SX1262, thinknode_m3, heltec_v4, thinknode_m1, lilygo_tbeam_SX1276, meshadventurer, nano_g2_ultra, heltec_v3, promicro, xiao_c3, heltec_tracker_v2, keepteen_lt1, heltec_mesh_solar. --- variants/heltec_mesh_solar/target.cpp | 2 +- variants/heltec_tracker_v2/target.cpp | 2 +- variants/heltec_v3/target.cpp | 2 +- variants/heltec_v4/target.cpp | 2 +- variants/keepteen_lt1/target.cpp | 2 +- variants/lilygo_tbeam_1w/target.cpp | 2 +- variants/lilygo_tbeam_SX1262/target.cpp | 2 +- variants/lilygo_tbeam_SX1276/target.cpp | 2 +- variants/lilygo_tbeam_supreme_SX1262/target.cpp | 2 +- variants/meshadventurer/target.cpp | 2 +- variants/nano_g2_ultra/target.cpp | 2 +- variants/promicro/target.cpp | 2 +- variants/rak3112/target.cpp | 2 +- variants/rak3401/target.cpp | 2 +- variants/rak4631/target.cpp | 2 +- variants/rak_wismesh_tag/target.cpp | 2 +- variants/thinknode_m3/target.cpp | 2 +- variants/xiao_c3/target.cpp | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index 9852b68f..1ea33e1f 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -11,7 +11,7 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); SolarSensorManager sensors = SolarSensorManager(nmea); #ifdef DISPLAY_CLASS diff --git a/variants/heltec_tracker_v2/target.cpp b/variants/heltec_tracker_v2/target.cpp index c2e26b20..0b349231 100644 --- a/variants/heltec_tracker_v2/target.cpp +++ b/variants/heltec_tracker_v2/target.cpp @@ -17,7 +17,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, NULL, GPS_RESET, GPS_EN, &board.periph_power); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock, GPS_RESET, GPS_EN, &board.periph_power); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/heltec_v3/target.cpp b/variants/heltec_v3/target.cpp index cdd2535e..460c3c9b 100644 --- a/variants/heltec_v3/target.cpp +++ b/variants/heltec_v3/target.cpp @@ -17,7 +17,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/heltec_v4/target.cpp b/variants/heltec_v4/target.cpp index 54fc05e8..e44ec448 100644 --- a/variants/heltec_v4/target.cpp +++ b/variants/heltec_v4/target.cpp @@ -17,7 +17,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/keepteen_lt1/target.cpp b/variants/keepteen_lt1/target.cpp index e2e183a7..85f11232 100644 --- a/variants/keepteen_lt1/target.cpp +++ b/variants/keepteen_lt1/target.cpp @@ -12,7 +12,7 @@ VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/lilygo_tbeam_1w/target.cpp b/variants/lilygo_tbeam_1w/target.cpp index 8cb6bdfa..7cfd9356 100644 --- a/variants/lilygo_tbeam_1w/target.cpp +++ b/variants/lilygo_tbeam_1w/target.cpp @@ -19,7 +19,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/lilygo_tbeam_SX1262/target.cpp b/variants/lilygo_tbeam_SX1262/target.cpp index f85049d7..a851fd25 100644 --- a/variants/lilygo_tbeam_SX1262/target.cpp +++ b/variants/lilygo_tbeam_SX1262/target.cpp @@ -17,7 +17,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/lilygo_tbeam_SX1276/target.cpp b/variants/lilygo_tbeam_SX1276/target.cpp index 5fe82e11..5865faa3 100644 --- a/variants/lilygo_tbeam_SX1276/target.cpp +++ b/variants/lilygo_tbeam_SX1276/target.cpp @@ -17,7 +17,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/lilygo_tbeam_supreme_SX1262/target.cpp b/variants/lilygo_tbeam_supreme_SX1262/target.cpp index 6fec6f58..23983bd3 100644 --- a/variants/lilygo_tbeam_supreme_SX1262/target.cpp +++ b/variants/lilygo_tbeam_supreme_SX1262/target.cpp @@ -19,7 +19,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/meshadventurer/target.cpp b/variants/meshadventurer/target.cpp index 0edd4403..9ef58d0e 100644 --- a/variants/meshadventurer/target.cpp +++ b/variants/meshadventurer/target.cpp @@ -11,7 +11,7 @@ WRAPPER_CLASS radio_driver(radio, board); ESP32RTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); MASensorManager sensors = MASensorManager(nmea); #ifdef DISPLAY_CLASS diff --git a/variants/nano_g2_ultra/target.cpp b/variants/nano_g2_ultra/target.cpp index aad10c50..bd4e9b48 100644 --- a/variants/nano_g2_ultra/target.cpp +++ b/variants/nano_g2_ultra/target.cpp @@ -12,7 +12,7 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); -MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); NanoG2UltraSensorManager sensors = NanoG2UltraSensorManager(nmea); #ifdef DISPLAY_CLASS diff --git a/variants/promicro/target.cpp b/variants/promicro/target.cpp index 61eab91c..e4a4442a 100644 --- a/variants/promicro/target.cpp +++ b/variants/promicro/target.cpp @@ -12,7 +12,7 @@ VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/rak3112/target.cpp b/variants/rak3112/target.cpp index 6cddfce5..86955b96 100644 --- a/variants/rak3112/target.cpp +++ b/variants/rak3112/target.cpp @@ -17,7 +17,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/rak3401/target.cpp b/variants/rak3401/target.cpp index ec4fc28c..77fb0e5f 100644 --- a/variants/rak3401/target.cpp +++ b/variants/rak3401/target.cpp @@ -26,7 +26,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/rak4631/target.cpp b/variants/rak4631/target.cpp index ea6a2bd4..ac1ac7ca 100644 --- a/variants/rak4631/target.cpp +++ b/variants/rak4631/target.cpp @@ -26,7 +26,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/rak_wismesh_tag/target.cpp b/variants/rak_wismesh_tag/target.cpp index 9646375e..d42c0d58 100644 --- a/variants/rak_wismesh_tag/target.cpp +++ b/variants/rak_wismesh_tag/target.cpp @@ -22,7 +22,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; diff --git a/variants/thinknode_m3/target.cpp b/variants/thinknode_m3/target.cpp index ca2b0aa0..7303eb4c 100644 --- a/variants/thinknode_m3/target.cpp +++ b/variants/thinknode_m3/target.cpp @@ -11,7 +11,7 @@ WRAPPER_CLASS radio_driver(radio, board); VolatileRTCClock fallback_clock; AutoDiscoverRTCClock rtc_clock(fallback_clock); #ifdef ENV_INCLUDE_GPS -MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); +MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors = EnvironmentSensorManager(); diff --git a/variants/xiao_c3/target.cpp b/variants/xiao_c3/target.cpp index f8ee3d92..09461d10 100644 --- a/variants/xiao_c3/target.cpp +++ b/variants/xiao_c3/target.cpp @@ -17,7 +17,7 @@ AutoDiscoverRTCClock rtc_clock(fallback_clock); #if ENV_INCLUDE_GPS #include - MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1); + MicroNMEALocationProvider nmea = MicroNMEALocationProvider(Serial1, &rtc_clock); EnvironmentSensorManager sensors = EnvironmentSensorManager(nmea); #else EnvironmentSensorManager sensors; From 60b76f56d9371218c1641647a67eb309d06b8da6 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Wed, 4 Mar 2026 03:38:35 +0100 Subject: [PATCH 11/14] update PR #765 --- boards/keepteen_lt1.json | 2 +- boards/meshtiny.json | 2 +- boards/rak3401.json | 2 +- boards/rak4631.json | 2 +- boards/thinknode_m3.json | 2 +- boards/thinknode_m6.json | 2 +- boards/wiscore_rak4631.json | 76 ------------------------------------- 7 files changed, 6 insertions(+), 82 deletions(-) delete mode 100644 boards/wiscore_rak4631.json diff --git a/boards/keepteen_lt1.json b/boards/keepteen_lt1.json index c23b0b88..e853c633 100644 --- a/boards/keepteen_lt1.json +++ b/boards/keepteen_lt1.json @@ -60,7 +60,7 @@ ], "name": "Keepteen LT1", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/meshtiny.json b/boards/meshtiny.json index 0418dc3b..2e38a9cc 100644 --- a/boards/meshtiny.json +++ b/boards/meshtiny.json @@ -55,7 +55,7 @@ ], "name": "Meshtiny", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/rak3401.json b/boards/rak3401.json index a2816a63..a0d13f5c 100644 --- a/boards/rak3401.json +++ b/boards/rak3401.json @@ -53,7 +53,7 @@ ], "name": "WisCore RAK3401 Board", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/rak4631.json b/boards/rak4631.json index 8d820fce..e469b979 100644 --- a/boards/rak4631.json +++ b/boards/rak4631.json @@ -53,7 +53,7 @@ ], "name": "WisCore RAK4631 Board", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "protocol": "nrfutil", diff --git a/boards/thinknode_m3.json b/boards/thinknode_m3.json index 617740b6..2920b82d 100644 --- a/boards/thinknode_m3.json +++ b/boards/thinknode_m3.json @@ -53,7 +53,7 @@ ], "name": "elecrow nrf", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "use_1200bps_touch": true, diff --git a/boards/thinknode_m6.json b/boards/thinknode_m6.json index 1f91b9aa..da07b3d8 100644 --- a/boards/thinknode_m6.json +++ b/boards/thinknode_m6.json @@ -53,7 +53,7 @@ ], "name": "elecrow solar", "upload": { - "maximum_ram_size": 248832, + "maximum_ram_size": 235520, "maximum_size": 815104, "speed": 115200, "use_1200bps_touch": true, diff --git a/boards/wiscore_rak4631.json b/boards/wiscore_rak4631.json deleted file mode 100644 index 601974f6..00000000 --- a/boards/wiscore_rak4631.json +++ /dev/null @@ -1,76 +0,0 @@ -{ - "build": { - "arduino": { - "ldscript": "nrf52840_s140_v6.ld" - }, - "core": "nRF5", - "cpu": "cortex-m4", - "extra_flags": "-DARDUINO_NRF52840_FEATHER -DNRF52840_XXAA", - "f_cpu": "64000000L", - "hwids": [ - [ - "0x239A", - "0x8029" - ], - [ - "0x239A", - "0x0029" - ], - [ - "0x239A", - "0x002A" - ], - [ - "0x239A", - "0x802A" - ] - ], - "usb_product": "WisCore RAK4631 Board", - "mcu": "nrf52840", - "variant": "WisCore_RAK4631_Board", - "bsp": { - "name": "adafruit" - }, - "softdevice": { - "sd_flags": "-DS140", - "sd_name": "s140", - "sd_version": "6.1.1", - "sd_fwid": "0x00B6" - }, - "bootloader": { - "settings_addr": "0xFF000" - } - }, - "connectivity": [ - "bluetooth" - ], - "debug": { - "jlink_device": "nRF52840_xxAA", - "onboard_tools": [ - "jlink" - ], - "svd_path": "nrf52840.svd", - "openocd_target": "nrf52.cfg" - }, - "frameworks": [ - "arduino" - ], - "name": "WisCore RAK4631 Board", - "upload": { - "maximum_ram_size": 235520, - "maximum_size": 815104, - "speed": 115200, - "protocol": "nrfutil", - "protocols": [ - "jlink", - "nrfjprog", - "nrfutil", - "stlink" - ], - "use_1200bps_touch": true, - "require_upload_port": true, - "wait_for_upload_port": true - }, - "url": "https://www.rakwireless.com", - "vendor": "RAKwireless" -} From cdca79540f3461473880e7cf0bee8625566f13f1 Mon Sep 17 00:00:00 2001 From: Quency-D Date: Fri, 6 Mar 2026 14:19:07 +0800 Subject: [PATCH 12/14] Update Heltec Tracker v2 to version KCT8103L. --- .../sensors/MicroNMEALocationProvider.h | 18 +++++- .../HeltecTrackerV2Board.cpp | 22 ++----- .../heltec_tracker_v2/HeltecTrackerV2Board.h | 2 + variants/heltec_tracker_v2/LoRaFEMControl.cpp | 58 +++++++++++++++++++ variants/heltec_tracker_v2/LoRaFEMControl.h | 21 +++++++ variants/heltec_tracker_v2/platformio.ini | 14 ++--- 6 files changed, 107 insertions(+), 28 deletions(-) create mode 100644 variants/heltec_tracker_v2/LoRaFEMControl.cpp create mode 100644 variants/heltec_tracker_v2/LoRaFEMControl.h diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index 1de75327..ffecb701 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -39,6 +39,7 @@ class MicroNMEALocationProvider : public LocationProvider { mesh::RTCClock* _clock; Stream* _gps_serial; RefCountedDigitalPin* _peripher_power; + int8_t _claims = 0; int _pin_reset; int _pin_en; long next_check = 0; @@ -57,8 +58,21 @@ public : } } + void claim() { + _claims++; + if (_claims > 0) { + if (_peripher_power) _peripher_power->claim(); + } + } + + void release() { + if (_claims == 0) return; // avoid negative _claims + _claims--; + if (_peripher_power) _peripher_power->release(); + } + void begin() override { - if (_peripher_power) _peripher_power->claim(); + claim(); if (_pin_en != -1) { digitalWrite(_pin_en, PIN_GPS_EN_ACTIVE); } @@ -82,7 +96,7 @@ public : if (_pin_reset != -1) { digitalWrite(_pin_reset, GPS_RESET_FORCE); } - if (_peripher_power) _peripher_power->release(); + release(); } bool isEnabled() override { diff --git a/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp b/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp index bd7f680e..aabfed79 100644 --- a/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp +++ b/variants/heltec_tracker_v2/HeltecTrackerV2Board.cpp @@ -6,19 +6,7 @@ void HeltecTrackerV2Board::begin() { pinMode(PIN_ADC_CTRL, OUTPUT); digitalWrite(PIN_ADC_CTRL, LOW); // Initially inactive - // Set up digital GPIO registers before releasing RTC hold. The hold latches - // the pad state including function select, so register writes accumulate - // without affecting the pad. On hold release, all changes apply atomically - // (IO MUX switches to digital GPIO with output already HIGH — no glitch). - pinMode(P_LORA_PA_POWER, OUTPUT); - digitalWrite(P_LORA_PA_POWER,HIGH); - rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_POWER); - - pinMode(P_LORA_PA_EN, OUTPUT); - digitalWrite(P_LORA_PA_EN,HIGH); - rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_EN); - pinMode(P_LORA_PA_TX_EN, OUTPUT); - digitalWrite(P_LORA_PA_TX_EN,LOW); + loRaFEMControl.init(); esp_reset_reason_t reason = esp_reset_reason(); if (reason != ESP_RST_DEEPSLEEP) { @@ -39,12 +27,12 @@ void HeltecTrackerV2Board::begin() { void HeltecTrackerV2Board::onBeforeTransmit(void) { digitalWrite(P_LORA_TX_LED, HIGH); // turn TX LED on - digitalWrite(P_LORA_PA_TX_EN,HIGH); + loRaFEMControl.setTxModeEnable(); } void HeltecTrackerV2Board::onAfterTransmit(void) { digitalWrite(P_LORA_TX_LED, LOW); // turn TX LED off - digitalWrite(P_LORA_PA_TX_EN,LOW); + loRaFEMControl.setRxModeEnable(); } void HeltecTrackerV2Board::enterDeepSleep(uint32_t secs, int pin_wake_btn) { @@ -56,9 +44,7 @@ void HeltecTrackerV2Board::begin() { rtc_gpio_hold_en((gpio_num_t)P_LORA_NSS); - // Hold GC1109 FEM pins during sleep to keep LNA active for RX wake - rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_POWER); - rtc_gpio_hold_en((gpio_num_t)P_LORA_PA_EN); + loRaFEMControl.setRxModeEnableWhenMCUSleep();//It also needs to be enabled in receive mode if (pin_wake_btn < 0) { esp_sleep_enable_ext1_wakeup( (1L << P_LORA_DIO_1), ESP_EXT1_WAKEUP_ANY_HIGH); // wake up on: recv LoRa packet diff --git a/variants/heltec_tracker_v2/HeltecTrackerV2Board.h b/variants/heltec_tracker_v2/HeltecTrackerV2Board.h index d93c86cd..33c897bc 100644 --- a/variants/heltec_tracker_v2/HeltecTrackerV2Board.h +++ b/variants/heltec_tracker_v2/HeltecTrackerV2Board.h @@ -4,11 +4,13 @@ #include #include #include +#include "LoRaFEMControl.h" class HeltecTrackerV2Board : public ESP32Board { public: RefCountedDigitalPin periph_power; + LoRaFEMControl loRaFEMControl; HeltecTrackerV2Board() : periph_power(PIN_VEXT_EN,PIN_VEXT_EN_ACTIVE) { } diff --git a/variants/heltec_tracker_v2/LoRaFEMControl.cpp b/variants/heltec_tracker_v2/LoRaFEMControl.cpp new file mode 100644 index 00000000..3cf6c311 --- /dev/null +++ b/variants/heltec_tracker_v2/LoRaFEMControl.cpp @@ -0,0 +1,58 @@ +#include "LoRaFEMControl.h" +#include +#include +#include + +void LoRaFEMControl::init(void) +{ + pinMode(P_LORA_PA_POWER, OUTPUT); + digitalWrite(P_LORA_PA_POWER, HIGH); + rtc_gpio_hold_dis((gpio_num_t)P_LORA_PA_POWER); + rtc_gpio_hold_dis((gpio_num_t)P_LORA_KCT8103L_PA_CSD); + rtc_gpio_hold_dis((gpio_num_t)P_LORA_KCT8103L_PA_CTX); + delay(1); + pinMode(P_LORA_KCT8103L_PA_CSD, OUTPUT); + digitalWrite(P_LORA_KCT8103L_PA_CSD, HIGH); + pinMode(P_LORA_KCT8103L_PA_CTX, OUTPUT); + digitalWrite(P_LORA_KCT8103L_PA_CTX, HIGH); + setLnaCanControl(true); +} + +void LoRaFEMControl::setSleepModeEnable(void) +{ + // shutdown the PA + digitalWrite(P_LORA_KCT8103L_PA_CSD, LOW); +} + +void LoRaFEMControl::setTxModeEnable(void) +{ + digitalWrite(P_LORA_KCT8103L_PA_CSD, HIGH); + digitalWrite(P_LORA_KCT8103L_PA_CTX, HIGH); +} + +void LoRaFEMControl::setRxModeEnable(void) +{ + digitalWrite(P_LORA_KCT8103L_PA_CSD, HIGH); + if (lna_enabled) { + digitalWrite(P_LORA_KCT8103L_PA_CTX, LOW); + } else { + digitalWrite(P_LORA_KCT8103L_PA_CTX, HIGH); + } +} + +void LoRaFEMControl::setRxModeEnableWhenMCUSleep(void) +{ + digitalWrite(P_LORA_KCT8103L_PA_CSD, HIGH); + rtc_gpio_hold_en((gpio_num_t)P_LORA_KCT8103L_PA_CSD); + if (lna_enabled) { + digitalWrite(P_LORA_KCT8103L_PA_CTX, LOW); + } else { + digitalWrite(P_LORA_KCT8103L_PA_CTX, HIGH); + } + rtc_gpio_hold_en((gpio_num_t)P_LORA_KCT8103L_PA_CTX); +} + +void LoRaFEMControl::setLNAEnable(bool enabled) +{ + lna_enabled = enabled; +} diff --git a/variants/heltec_tracker_v2/LoRaFEMControl.h b/variants/heltec_tracker_v2/LoRaFEMControl.h new file mode 100644 index 00000000..2c50b742 --- /dev/null +++ b/variants/heltec_tracker_v2/LoRaFEMControl.h @@ -0,0 +1,21 @@ +#pragma once +#include + +class LoRaFEMControl +{ + public: + LoRaFEMControl() {} + virtual ~LoRaFEMControl() {} + void init(void); + void setSleepModeEnable(void); + void setTxModeEnable(void); + void setRxModeEnable(void); + void setRxModeEnableWhenMCUSleep(void); + void setLNAEnable(bool enabled); + bool isLnaCanControl(void) { return lna_can_control; } + void setLnaCanControl(bool can_control) { lna_can_control = can_control; } + + private: + bool lna_enabled = false; + bool lna_can_control = false; +}; diff --git a/variants/heltec_tracker_v2/platformio.ini b/variants/heltec_tracker_v2/platformio.ini index af41b4f5..3d2a95fa 100644 --- a/variants/heltec_tracker_v2/platformio.ini +++ b/variants/heltec_tracker_v2/platformio.ini @@ -17,18 +17,18 @@ build_flags = -D P_LORA_SCLK=9 -D P_LORA_MISO=11 -D P_LORA_MOSI=10 - -D P_LORA_PA_POWER=7 ; VFEM_Ctrl - GC1109 LDO power enable - -D P_LORA_PA_EN=4 ; CSD - GC1109 chip enable (HIGH=on) - -D P_LORA_PA_TX_EN=46 ; CPS - GC1109 PA mode (HIGH=full PA, LOW=bypass) - -D LORA_TX_POWER=10 ; 10dBm + ~11dB GC1109 gain = ~21dBm output + -D P_LORA_PA_POWER=7 ;VFEM_Ctrl -LDO power enable + -D P_LORA_KCT8103L_PA_CSD=4 + -D P_LORA_KCT8103L_PA_CTX=5 + -D LORA_TX_POWER=9 ; 9dBm + ~14dB KCT8103L gain = ~22dBm output -D MAX_LORA_TX_POWER=22 ; Max SX1262 output -> ~28dBm at antenna -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 SX126X_REGISTER_PATCH=1 - -D PIN_BOARD_SDA=5 - -D PIN_BOARD_SCL=6 + -D PIN_BOARD_SDA=6 + -D PIN_BOARD_SCL=17 -D PIN_USER_BTN=0 -D PIN_TFT_SDA=42 ; SDIN -D PIN_TFT_SCL=41 ; SCLK @@ -207,8 +207,6 @@ build_flags = -D ADVERT_LAT=0.0 -D ADVERT_LON=0.0 -D ADMIN_PASSWORD='"password"' - -D ENV_PIN_SDA=3 - -D ENV_PIN_SCL=4 -D DISPLAY_CLASS=ST7735Display ; -D MESH_PACKET_LOGGING=1 ; -D MESH_DEBUG=1 From 7a8370fa69e54260e6c4f5b8beb226c55e52478e Mon Sep 17 00:00:00 2001 From: Quency-D <55523105+Quency-D@users.noreply.github.com> Date: Fri, 6 Mar 2026 16:04:47 +0800 Subject: [PATCH 13/14] Fixed a bug in the LORA_TX_POWER comment. --- variants/heltec_tracker_v2/platformio.ini | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/variants/heltec_tracker_v2/platformio.ini b/variants/heltec_tracker_v2/platformio.ini index 3d2a95fa..5f196834 100644 --- a/variants/heltec_tracker_v2/platformio.ini +++ b/variants/heltec_tracker_v2/platformio.ini @@ -20,7 +20,7 @@ build_flags = -D P_LORA_PA_POWER=7 ;VFEM_Ctrl -LDO power enable -D P_LORA_KCT8103L_PA_CSD=4 -D P_LORA_KCT8103L_PA_CTX=5 - -D LORA_TX_POWER=9 ; 9dBm + ~14dB KCT8103L gain = ~22dBm output + -D LORA_TX_POWER=9 ; 9dBm + ~13dB KCT8103L gain = ~22dBm output -D MAX_LORA_TX_POWER=22 ; Max SX1262 output -> ~28dBm at antenna -D SX126X_DIO2_AS_RF_SWITCH=true -D SX126X_DIO3_TCXO_VOLTAGE=1.8 From 5188221584d09cd0c0d6f6ff758873c4604fd460 Mon Sep 17 00:00:00 2001 From: Confi <9595028+Confituurke@users.noreply.github.com> Date: Mon, 2 Feb 2026 18:07:01 +0100 Subject: [PATCH 14/14] sensecap_solar: fix LED definitions (white=11, blue=12) --- variants/sensecap_solar/variant.cpp | 8 ++++---- variants/sensecap_solar/variant.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/variants/sensecap_solar/variant.cpp b/variants/sensecap_solar/variant.cpp index d7fdce49..43f1d80d 100644 --- a/variants/sensecap_solar/variant.cpp +++ b/variants/sensecap_solar/variant.cpp @@ -18,8 +18,8 @@ const uint32_t g_ADigitalPinMap[] = { 47, // D10 P1.15 (SPI_MOSI) LORA_MOSI // D11-D12 - LED outputs - 15, // D11 P0.15 User LED - 19, // D12 P0.19 Breathing LED + 15, // D11 P0.15 User LED (White LED) + 19, // D12 P0.19 Breathing LED (Blue LED - LoRa TX) // D13 - User input 33, // D13 P1.01 User Button @@ -58,8 +58,8 @@ void initVariant() { pinMode(PIN_QSPI_CS, OUTPUT); digitalWrite(PIN_QSPI_CS, HIGH); - pinMode(LED_GREEN, OUTPUT); - digitalWrite(LED_GREEN, LOW); + pinMode(LED_WHITE, OUTPUT); + digitalWrite(LED_WHITE, LOW); pinMode(LED_BLUE, OUTPUT); digitalWrite(LED_BLUE, LOW); diff --git a/variants/sensecap_solar/variant.h b/variants/sensecap_solar/variant.h index 76494f48..f96405a5 100644 --- a/variants/sensecap_solar/variant.h +++ b/variants/sensecap_solar/variant.h @@ -24,8 +24,8 @@ #define LED_BUILTIN (PIN_LED) #define LED_RED (PINS_COUNT) -#define LED_GREEN (12) -#define LED_BLUE (11) +#define LED_WHITE (11) +#define LED_BLUE (12) // LoRa TX indicator #define LED_STATE_ON (1) // State when LED is litted