From f9e2e26a7052e0f608e2f0c969f5822afe9fd925 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Sun, 8 Mar 2026 14:28:16 +0100 Subject: [PATCH 1/4] Fix timewrap bug --- src/Dispatcher.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Dispatcher.cpp b/src/Dispatcher.cpp index 9d7a11131d..b0f9491c9d 100644 --- a/src/Dispatcher.cpp +++ b/src/Dispatcher.cpp @@ -20,7 +20,16 @@ void Dispatcher::begin() { n_sent_flood = n_sent_direct = 0; n_recv_flood = n_recv_direct = 0; _err_flags = 0; - radio_nonrx_start = _ms->getMillis(); + + unsigned long now = _ms->getMillis(); + radio_nonrx_start = now; + // Initialize timers to "just passed" so millisHasNowPassed() returns true + // immediately. Using 0 breaks when millis is in the upper half of uint32 + // range (near the 49-day wrap), because the signed comparison trick + // interprets 0 as a future timestamp. + next_tx_time = now; + next_floor_calib_time = now; + next_agc_reset_time = now; duty_cycle_window_ms = getDutyCycleWindowMs(); float duty_cycle = 1.0f / (1.0f + getAirtimeBudgetFactor()); From c17542498257b0dc304c3307d596b53e3840bf0d Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Sun, 8 Mar 2026 14:38:34 +0100 Subject: [PATCH 2/4] Add wrap-safe millis_passed() helper and use that --- examples/companion_radio/ui-new/UITask.cpp | 14 +++++++------- examples/companion_radio/ui-orig/UITask.cpp | 4 ++-- examples/simple_repeater/UITask.cpp | 9 +++++---- examples/simple_room_server/UITask.cpp | 9 +++++---- examples/simple_sensor/UITask.cpp | 9 +++++---- src/helpers/ArduinoHelpers.h | 6 ++++++ src/helpers/esp32/SerialBLEInterface.cpp | 7 ++++--- src/helpers/radiolib/CustomSX1276.h | 3 ++- src/helpers/sensors/EnvironmentSensorManager.cpp | 3 ++- src/helpers/sensors/MicroNMEALocationProvider.h | 3 ++- variants/heltec_mesh_solar/target.cpp | 2 +- variants/heltec_tracker/target.cpp | 3 ++- variants/meshadventurer/target.cpp | 3 ++- variants/nano_g2_ultra/target.cpp | 2 +- variants/t1000-e/target.cpp | 3 ++- variants/thinknode_m1/target.cpp | 2 +- 16 files changed, 49 insertions(+), 33 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index 6f363d7f96..b717211e28 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -77,7 +77,7 @@ class SplashScreen : public UIScreen { } void poll() override { - if (millis() >= dismiss_after) { + if (millis_passed(dismiss_after)) { _task->gotoHomeScreen(); } } @@ -156,7 +156,7 @@ class HomeScreen : public UIScreen { int next_sensors_refresh = 0; void refresh_sensors() { - if (millis() > next_sensors_refresh) { + if (millis_passed(next_sensors_refresh)) { sensors_lpp.reset(); sensors_nb = 0; sensors_lpp.addVoltage(TELEM_CHANNEL_SELF, (float)board.getBattMilliVolts() / 1000.0f); @@ -764,7 +764,7 @@ void UITask::loop() { } #endif #if defined(BACKLIGHT_BTN) - if (millis() > next_backlight_btn_check) { + if (millis_passed(next_backlight_btn_check)) { bool touch_state = digitalRead(PIN_BUTTON2); #if defined(DISP_BACKLIGHT) digitalWrite(DISP_BACKLIGHT, !touch_state); @@ -790,10 +790,10 @@ void UITask::loop() { if (curr) curr->poll(); if (_display != NULL && _display->isOn()) { - if (millis() >= _next_refresh && curr) { + if (millis_passed(_next_refresh) && curr) { _display->startFrame(); int delay_millis = curr->render(*_display); - if (millis() < _alert_expiry) { // render alert popup + if (!millis_passed(_alert_expiry)) { // render alert popup _display->setTextSize(1); int y = _display->height() / 3; int p = _display->height() / 32; @@ -809,7 +809,7 @@ void UITask::loop() { _display->endFrame(); } #if AUTO_OFF_MILLIS > 0 - if (millis() > _auto_off) { + if (millis_passed(_auto_off)) { _display->turnOff(); } #endif @@ -820,7 +820,7 @@ void UITask::loop() { #endif #ifdef AUTO_SHUTDOWN_MILLIVOLTS - if (millis() > next_batt_chck) { + if (millis_passed(next_batt_chck)) { uint16_t milliVolts = getBattMilliVolts(); if (milliVolts > 0 && milliVolts < AUTO_SHUTDOWN_MILLIVOLTS) { diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 12a374d91d..8c340ed13d 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -335,14 +335,14 @@ void UITask::loop() { _need_refresh = true; _firstBoot = false; } - if (millis() >= _next_refresh && _need_refresh) { + if (millis_passed(_next_refresh) && _need_refresh) { _display->startFrame(); renderCurrScreen(); _display->endFrame(); _next_refresh = millis() + 1000; // refresh every second } - if (millis() > _auto_off) { + if (millis_passed(_auto_off)) { _display->turnOff(); } } diff --git a/examples/simple_repeater/UITask.cpp b/examples/simple_repeater/UITask.cpp index 6a85143887..a16e79794d 100644 --- a/examples/simple_repeater/UITask.cpp +++ b/examples/simple_repeater/UITask.cpp @@ -1,6 +1,7 @@ #include "UITask.h" #include #include +#include #ifndef USER_BTN_PRESSED #define USER_BTN_PRESSED LOW @@ -46,7 +47,7 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi void UITask::renderCurrScreen() { char tmp[80]; - if (millis() < BOOT_SCREEN_MILLIS) { // boot screen + if (!millis_passed(BOOT_SCREEN_MILLIS)) { // boot screen // meshcore logo _display->setColor(DisplayDriver::BLUE); int logoWidth = 128; @@ -94,7 +95,7 @@ void UITask::renderCurrScreen() { void UITask::loop() { #ifdef PIN_USER_BTN - if (millis() >= _next_read) { + if (millis_passed(_next_read)) { int btnState = digitalRead(PIN_USER_BTN); if (btnState != _prevBtnState) { if (btnState == USER_BTN_PRESSED) { // pressed? @@ -112,14 +113,14 @@ void UITask::loop() { #endif if (_display->isOn()) { - if (millis() >= _next_refresh) { + if (millis_passed(_next_refresh)) { _display->startFrame(); renderCurrScreen(); _display->endFrame(); _next_refresh = millis() + 1000; // refresh every second } - if (millis() > _auto_off) { + if (millis_passed(_auto_off)) { _display->turnOff(); } } diff --git a/examples/simple_room_server/UITask.cpp b/examples/simple_room_server/UITask.cpp index 640a1d2d10..054dec1975 100644 --- a/examples/simple_room_server/UITask.cpp +++ b/examples/simple_room_server/UITask.cpp @@ -1,6 +1,7 @@ #include "UITask.h" #include #include +#include #ifndef USER_BTN_PRESSED #define USER_BTN_PRESSED LOW @@ -46,7 +47,7 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi void UITask::renderCurrScreen() { char tmp[80]; - if (millis() < BOOT_SCREEN_MILLIS) { // boot screen + if (!millis_passed(BOOT_SCREEN_MILLIS)) { // boot screen // meshcore logo _display->setColor(DisplayDriver::BLUE); int logoWidth = 128; @@ -94,7 +95,7 @@ void UITask::renderCurrScreen() { void UITask::loop() { #ifdef PIN_USER_BTN - if (millis() >= _next_read) { + if (millis_passed(_next_read)) { int btnState = digitalRead(PIN_USER_BTN); if (btnState != _prevBtnState) { if (btnState == USER_BTN_PRESSED) { // pressed? @@ -112,14 +113,14 @@ void UITask::loop() { #endif if (_display->isOn()) { - if (millis() >= _next_refresh) { + if (millis_passed(_next_refresh)) { _display->startFrame(); renderCurrScreen(); _display->endFrame(); _next_refresh = millis() + 1000; // refresh every second } - if (millis() > _auto_off) { + if (millis_passed(_auto_off)) { _display->turnOff(); } } diff --git a/examples/simple_sensor/UITask.cpp b/examples/simple_sensor/UITask.cpp index 757ea1dc60..20923eee91 100644 --- a/examples/simple_sensor/UITask.cpp +++ b/examples/simple_sensor/UITask.cpp @@ -1,6 +1,7 @@ #include "UITask.h" #include #include +#include #ifndef USER_BTN_PRESSED #define USER_BTN_PRESSED LOW @@ -46,7 +47,7 @@ void UITask::begin(NodePrefs* node_prefs, const char* build_date, const char* fi void UITask::renderCurrScreen() { char tmp[80]; - if (millis() < BOOT_SCREEN_MILLIS) { // boot screen + if (!millis_passed(BOOT_SCREEN_MILLIS)) { // boot screen // meshcore logo _display->setColor(DisplayDriver::BLUE); int logoWidth = 128; @@ -94,7 +95,7 @@ void UITask::renderCurrScreen() { void UITask::loop() { #ifdef PIN_USER_BTN - if (millis() >= _next_read) { + if (millis_passed(_next_read)) { int btnState = digitalRead(PIN_USER_BTN); if (btnState != _prevBtnState) { if (btnState == USER_BTN_PRESSED) { // pressed? @@ -112,14 +113,14 @@ void UITask::loop() { #endif if (_display->isOn()) { - if (millis() >= _next_refresh) { + if (millis_passed(_next_refresh)) { _display->startFrame(); renderCurrScreen(); _display->endFrame(); _next_refresh = millis() + 1000; // refresh every second } - if (millis() > _auto_off) { + if (millis_passed(_auto_off)) { _display->turnOff(); } } diff --git a/src/helpers/ArduinoHelpers.h b/src/helpers/ArduinoHelpers.h index 97596daa31..e5bb15daf5 100644 --- a/src/helpers/ArduinoHelpers.h +++ b/src/helpers/ArduinoHelpers.h @@ -24,6 +24,12 @@ class ArduinoMillis : public mesh::MillisecondClock { unsigned long getMillis() override { return millis(); } }; +// Wrap-safe millis deadline check. Handles the 49-day millis() overflow +// using signed comparison (2's complement). Use instead of millis() >= target. +inline bool millis_passed(unsigned long target) { + return (long)(millis() - target) > 0; +} + class StdRNG : public mesh::RNG { public: void begin(long seed) { randomSeed(seed); } diff --git a/src/helpers/esp32/SerialBLEInterface.cpp b/src/helpers/esp32/SerialBLEInterface.cpp index dcfa0e1e34..f02840ac6a 100644 --- a/src/helpers/esp32/SerialBLEInterface.cpp +++ b/src/helpers/esp32/SerialBLEInterface.cpp @@ -1,5 +1,6 @@ #include "SerialBLEInterface.h" #include "esp_mac.h" +#include // See the following for generating UUIDs: // https://www.uuidgenerator.net/ @@ -183,12 +184,12 @@ size_t SerialBLEInterface::writeFrame(const uint8_t src[], size_t len) { #define BLE_WRITE_MIN_INTERVAL 60 bool SerialBLEInterface::isWriteBusy() const { - return millis() < _last_write + BLE_WRITE_MIN_INTERVAL; // still too soon to start another write? + return !millis_passed(_last_write + BLE_WRITE_MIN_INTERVAL); // still too soon to start another write? } size_t SerialBLEInterface::checkRecvFrame(uint8_t dest[]) { if (send_queue_len > 0 // first, check send queue - && millis() >= _last_write + BLE_WRITE_MIN_INTERVAL // space the writes apart + && millis_passed(_last_write + BLE_WRITE_MIN_INTERVAL) // space the writes apart ) { _last_write = millis(); pTxCharacteristic->setValue(send_queue[0].buf, send_queue[0].len); @@ -238,7 +239,7 @@ size_t SerialBLEInterface::checkRecvFrame(uint8_t dest[]) { oldDeviceConnected = deviceConnected; } - if (adv_restart_time && millis() >= adv_restart_time) { + if (adv_restart_time && millis_passed(adv_restart_time)) { if (pServer->getConnectedCount() == 0) { BLE_DEBUG_PRINTLN("SerialBLEInterface -> re-starting advertising"); pServer->getAdvertising()->start(); // re-Start advertising diff --git a/src/helpers/radiolib/CustomSX1276.h b/src/helpers/radiolib/CustomSX1276.h index bee2527431..087a6784d1 100644 --- a/src/helpers/radiolib/CustomSX1276.h +++ b/src/helpers/radiolib/CustomSX1276.h @@ -1,6 +1,7 @@ #pragma once #include +#include #define RH_RF95_MODEM_STATUS_CLEAR 0x10 #define RH_RF95_MODEM_STATUS_HEADER_INFO_VALID 0x08 @@ -79,7 +80,7 @@ class CustomSX1276 : public SX1276 { // wait for channel activity detected or timeout unsigned long timeout = millis() + 16; - while(!this->mod->hal->digitalRead(this->mod->getIrq()) && millis() < timeout) { + while(!this->mod->hal->digitalRead(this->mod->getIrq()) && !millis_passed(timeout)) { this->mod->hal->yield(); if(this->mod->hal->digitalRead(this->mod->getGpio())) { return(RADIOLIB_PREAMBLE_DETECTED); diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index b5e23b3fe8..7a8bc80409 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -1,4 +1,5 @@ #include "EnvironmentSensorManager.h" +#include #include @@ -806,7 +807,7 @@ void EnvironmentSensorManager::loop() { if (gps_active) { _location->loop(); } - if (millis() > next_gps_update) { + if (millis_passed(next_gps_update)) { if(gps_active){ #ifdef RAK_WISBLOCK_GPS diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index eec466d3aa..c8f5b12737 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -4,6 +4,7 @@ #include #include #include +#include #ifndef GPS_EN #ifdef PIN_GPS_EN @@ -143,7 +144,7 @@ public : if (!isValid()) time_valid = 0; - if (millis() > next_check) { + if (millis_passed(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) { diff --git a/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index d140864cd1..533c4da697 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -69,7 +69,7 @@ void SolarSensorManager::loop() { _location->loop(); - if (millis() > next_gps_update) { + if (millis_passed(next_gps_update)) { if (_location->isValid()) { node_lat = ((double)_location->getLatitude())/1000000.; node_lon = ((double)_location->getLongitude())/1000000.; diff --git a/variants/heltec_tracker/target.cpp b/variants/heltec_tracker/target.cpp index f32c41ff47..cca1ecc146 100644 --- a/variants/heltec_tracker/target.cpp +++ b/variants/heltec_tracker/target.cpp @@ -1,6 +1,7 @@ #include #include "target.h" +#include #include HeltecV3Board board; @@ -75,7 +76,7 @@ void HWTSensorManager::loop() { _location->loop(); - if (millis() > next_gps_update) { + if (millis_passed(next_gps_update)) { if (gps_active && _location->isValid()) { node_lat = ((double)_location->getLatitude())/1000000.; node_lon = ((double)_location->getLongitude())/1000000.; diff --git a/variants/meshadventurer/target.cpp b/variants/meshadventurer/target.cpp index 8795a4cbe7..63d910c437 100644 --- a/variants/meshadventurer/target.cpp +++ b/variants/meshadventurer/target.cpp @@ -1,6 +1,7 @@ #include #include "target.h" +#include #include MeshadventurerBoard board; @@ -67,7 +68,7 @@ bool MASensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& te void MASensorManager::loop() { static long next_gps_update = 0; _location->loop(); - if(millis() > next_gps_update && gps_active) { + if(millis_passed(next_gps_update) && gps_active) { if(_location->isValid()) { node_lat = ((double)_location->getLatitude()) / 1000000.; node_lon = ((double)_location->getLongitude()) / 1000000.; diff --git a/variants/nano_g2_ultra/target.cpp b/variants/nano_g2_ultra/target.cpp index 69a2772ccb..f535385a09 100644 --- a/variants/nano_g2_ultra/target.cpp +++ b/variants/nano_g2_ultra/target.cpp @@ -81,7 +81,7 @@ void NanoG2UltraSensorManager::loop() { _location->loop(); - if (millis() > next_gps_update) { + if (millis_passed(next_gps_update)) { if (_location->isValid()) { node_lat = ((double)_location->getLatitude()) / 1000000.; node_lon = ((double)_location->getLongitude()) / 1000000.; diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index 4253282708..eeef1aa697 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -1,6 +1,7 @@ #include #include "t1000e_sensors.h" #include "target.h" +#include #include T1000eBoard board; @@ -151,7 +152,7 @@ void T1000SensorManager::loop() { _nmea->loop(); - if (millis() > next_gps_update) { + if (millis_passed(next_gps_update)) { if (gps_active && _nmea->isValid()) { node_lat = ((double)_nmea->getLatitude())/1000000.; node_lon = ((double)_nmea->getLongitude())/1000000.; diff --git a/variants/thinknode_m1/target.cpp b/variants/thinknode_m1/target.cpp index 69306fc0e1..dd03b07f8f 100644 --- a/variants/thinknode_m1/target.cpp +++ b/variants/thinknode_m1/target.cpp @@ -98,7 +98,7 @@ void ThinkNodeM1SensorManager::loop() { _location->loop(); - if (millis() > next_gps_update) { + if (millis_passed(next_gps_update)) { if (_location->isValid()) { node_lat = ((double)_location->getLatitude())/1000000.; node_lon = ((double)_location->getLongitude())/1000000.; From da6cf357dfaa2162f297f70eea01185c62b83ece Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Sun, 8 Mar 2026 15:02:03 +0100 Subject: [PATCH 3/4] minor type nit fixes --- examples/companion_radio/ui-new/UITask.cpp | 7 ++++--- examples/companion_radio/ui-new/UITask.h | 4 ++-- examples/companion_radio/ui-orig/UITask.cpp | 6 +++--- src/helpers/NRF52Board.cpp | 2 +- src/helpers/sensors/EnvironmentSensorManager.cpp | 2 +- src/helpers/sensors/MicroNMEALocationProvider.h | 2 +- variants/heltec_mesh_solar/target.cpp | 2 +- variants/heltec_tracker/target.cpp | 2 +- variants/meshadventurer/target.cpp | 2 +- variants/nano_g2_ultra/target.cpp | 2 +- variants/t1000-e/target.cpp | 2 +- variants/thinknode_m1/target.cpp | 6 +++--- 12 files changed, 20 insertions(+), 19 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index b717211e28..c3f9cc0dfe 100644 --- a/examples/companion_radio/ui-new/UITask.cpp +++ b/examples/companion_radio/ui-new/UITask.cpp @@ -153,7 +153,8 @@ class HomeScreen : public UIScreen { int sensors_nb = 0; bool sensors_scroll = false; int sensors_scroll_offset = 0; - int next_sensors_refresh = 0; + unsigned long next_sensors_refresh = 0; + void refresh_sensors() { if (millis_passed(next_sensors_refresh)) { @@ -652,8 +653,8 @@ void UITask::newMsg(uint8_t path_len, const char* from_name, const char* text, i void UITask::userLedHandler() { #ifdef PIN_STATUS_LED - int cur_time = millis(); - if (cur_time > next_led_change) { + unsigned long cur_time = millis(); + if (millis_passed(next_led_change)) { if (led_state == 0) { led_state = 1; if (_msgcount > 0) { diff --git a/examples/companion_radio/ui-new/UITask.h b/examples/companion_radio/ui-new/UITask.h index a77ad6e7ec..e0aebd6698 100644 --- a/examples/companion_radio/ui-new/UITask.h +++ b/examples/companion_radio/ui-new/UITask.h @@ -37,10 +37,10 @@ class UITask : public AbstractUITask { unsigned long _alert_expiry; int _msgcount; unsigned long ui_started_at, next_batt_chck; - int next_backlight_btn_check = 0; + unsigned long next_backlight_btn_check = 0; #ifdef PIN_STATUS_LED int led_state = 0; - int next_led_change = 0; + unsigned long next_led_change = 0; int last_led_increment = 0; #endif diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 8c340ed13d..6136dbd905 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -264,11 +264,11 @@ void UITask::renderCurrScreen() { void UITask::userLedHandler() { #ifdef PIN_STATUS_LED static int state = 0; - static int next_change = 0; + static unsigned long next_change = 0; static int last_increment = 0; - int cur_time = millis(); - if (cur_time > next_change) { + unsigned long cur_time = millis(); + if (millis_passed(next_change)) { if (state == 0) { state = 1; if (_msgcount > 0) { diff --git a/src/helpers/NRF52Board.cpp b/src/helpers/NRF52Board.cpp index 2c8753d464..7bcd8f0f81 100644 --- a/src/helpers/NRF52Board.cpp +++ b/src/helpers/NRF52Board.cpp @@ -281,7 +281,7 @@ void NRF52Board::sleep(uint32_t secs) { float NRF52Board::getMCUTemperature() { NRF_TEMP->TASKS_START = 1; // Start temperature measurement - long startTime = millis(); + unsigned long startTime = millis(); while (NRF_TEMP->EVENTS_DATARDY == 0) { // Wait for completion. Should complete in 50us if(millis() - startTime > 5) { // To wait 5ms just in case NRF_TEMP->TASKS_STOP = 1; diff --git a/src/helpers/sensors/EnvironmentSensorManager.cpp b/src/helpers/sensors/EnvironmentSensorManager.cpp index 7a8bc80409..0a30c0e8b7 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -801,7 +801,7 @@ void EnvironmentSensorManager::stop_gps() { } void EnvironmentSensorManager::loop() { - static long next_gps_update = 0; + static unsigned long next_gps_update = 0; #if ENV_INCLUDE_GPS if (gps_active) { diff --git a/src/helpers/sensors/MicroNMEALocationProvider.h b/src/helpers/sensors/MicroNMEALocationProvider.h index c8f5b12737..17c293ac7d 100644 --- a/src/helpers/sensors/MicroNMEALocationProvider.h +++ b/src/helpers/sensors/MicroNMEALocationProvider.h @@ -43,7 +43,7 @@ class MicroNMEALocationProvider : public LocationProvider { int8_t _claims = 0; int _pin_reset; int _pin_en; - long next_check = 0; + unsigned 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 diff --git a/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index 533c4da697..19ab711681 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -65,7 +65,7 @@ bool SolarSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& } void SolarSensorManager::loop() { - static long next_gps_update = 0; + static unsigned long next_gps_update = 0; _location->loop(); diff --git a/variants/heltec_tracker/target.cpp b/variants/heltec_tracker/target.cpp index cca1ecc146..a85772eb4a 100644 --- a/variants/heltec_tracker/target.cpp +++ b/variants/heltec_tracker/target.cpp @@ -72,7 +72,7 @@ bool HWTSensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& t } void HWTSensorManager::loop() { - static long next_gps_update = 0; + static unsigned long next_gps_update = 0; _location->loop(); diff --git a/variants/meshadventurer/target.cpp b/variants/meshadventurer/target.cpp index 63d910c437..5e9cc346e3 100644 --- a/variants/meshadventurer/target.cpp +++ b/variants/meshadventurer/target.cpp @@ -66,7 +66,7 @@ bool MASensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& te } void MASensorManager::loop() { - static long next_gps_update = 0; + static unsigned long next_gps_update = 0; _location->loop(); if(millis_passed(next_gps_update) && gps_active) { if(_location->isValid()) { diff --git a/variants/nano_g2_ultra/target.cpp b/variants/nano_g2_ultra/target.cpp index f535385a09..8813449287 100644 --- a/variants/nano_g2_ultra/target.cpp +++ b/variants/nano_g2_ultra/target.cpp @@ -73,7 +73,7 @@ bool NanoG2UltraSensorManager::querySensors(uint8_t requester_permissions, Cayen } void NanoG2UltraSensorManager::loop() { - static long next_gps_update = 0; + static unsigned long next_gps_update = 0; if (!gps_active) { return; // GPS is not active, skip further processing diff --git a/variants/t1000-e/target.cpp b/variants/t1000-e/target.cpp index eeef1aa697..7e8f7500d5 100644 --- a/variants/t1000-e/target.cpp +++ b/variants/t1000-e/target.cpp @@ -148,7 +148,7 @@ bool T1000SensorManager::querySensors(uint8_t requester_permissions, CayenneLPP& } void T1000SensorManager::loop() { - static long next_gps_update = 0; + static unsigned long next_gps_update = 0; _nmea->loop(); diff --git a/variants/thinknode_m1/target.cpp b/variants/thinknode_m1/target.cpp index dd03b07f8f..d151df3208 100644 --- a/variants/thinknode_m1/target.cpp +++ b/variants/thinknode_m1/target.cpp @@ -69,11 +69,11 @@ bool ThinkNodeM1SensorManager::querySensors(uint8_t requester_permissions, Cayen } void ThinkNodeM1SensorManager::loop() { - static long next_gps_update = 0; - static long last_switch_check = 0; + static unsigned long next_gps_update = 0; + static unsigned long last_switch_check = 0; // Check GPS switch state every second - if (millis() - last_switch_check > 1000) { + if (millis_passed(last_switch_check + 1000)) { bool current_switch_state = digitalRead(PIN_GPS_SWITCH); // Detect switch state change From 571c1b89ba0b723412f6d9205d1c2a797aead680 Mon Sep 17 00:00:00 2001 From: Wessel Nieboer Date: Mon, 9 Mar 2026 14:50:58 +0100 Subject: [PATCH 4/4] Upgrade to Doxygen comment --- src/helpers/ArduinoHelpers.h | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/helpers/ArduinoHelpers.h b/src/helpers/ArduinoHelpers.h index e5bb15daf5..4e80f5c122 100644 --- a/src/helpers/ArduinoHelpers.h +++ b/src/helpers/ArduinoHelpers.h @@ -24,8 +24,13 @@ class ArduinoMillis : public mesh::MillisecondClock { unsigned long getMillis() override { return millis(); } }; -// Wrap-safe millis deadline check. Handles the 49-day millis() overflow -// using signed comparison (2's complement). Use instead of millis() >= target. +/** + * \brief Wrap-safe millis deadline check, handling the 49-day millis() overflow. + * \param target The deadline timestamp obtained from millis() + delay. + * \returns true when the deadline has passed. + * \note Use this instead of \c millis()>=target which fails near the 32-bit wrap. + * Works via signed subtraction (2's complement). + */ inline bool millis_passed(unsigned long target) { return (long)(millis() - target) > 0; }