From 8cc9a8bbb06d6929e3242c22a88c0ce3a6c7cf10 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 c0610b7f8a..772d2c61ac 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 b2d4c7ce52f24c0d4199678d6e59c5b5966a8ff3 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 28591cc1a5..c7c0306d3f 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); @@ -766,7 +766,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); @@ -792,10 +792,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; @@ -820,7 +820,7 @@ void UITask::loop() { _auto_off = millis() + AUTO_OFF_MILLIS; } #endif - if (millis() > _auto_off) { + if (millis_passed(_auto_off)) { _display->turnOff(); } #endif @@ -831,7 +831,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) { if(!board.isExternalPowered()) { diff --git a/examples/companion_radio/ui-orig/UITask.cpp b/examples/companion_radio/ui-orig/UITask.cpp index 34a7342bba..209e12196a 100644 --- a/examples/companion_radio/ui-orig/UITask.cpp +++ b/examples/companion_radio/ui-orig/UITask.cpp @@ -337,7 +337,7 @@ 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(); @@ -353,7 +353,7 @@ void UITask::loop() { _auto_off = millis() + AUTO_OFF_MILLIS; } #endif - 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 05d863fc4d..7024aebf75 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 @@ -47,7 +48,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; @@ -95,7 +96,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? @@ -113,14 +114,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 fb66b81919..36504ba608 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 @@ -47,7 +48,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; @@ -95,7 +96,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? @@ -113,14 +114,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 68a80607d0..50e543e135 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 @@ -47,7 +48,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; @@ -95,7 +96,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? @@ -113,14 +114,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 e6f3270be1..906f35ebd4 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 af09eff624..51e5bb2dce 100644 --- a/src/helpers/sensors/EnvironmentSensorManager.cpp +++ b/src/helpers/sensors/EnvironmentSensorManager.cpp @@ -1,4 +1,5 @@ #include "EnvironmentSensorManager.h" +#include #include @@ -893,7 +894,7 @@ void EnvironmentSensorManager::loop() { if (gps_active) { _location->loop(); } - if ((long)(millis() - next_gps_update) > 0) { + 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 6b06259b96..5d962f6804 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 @@ -141,7 +142,7 @@ public : if (!isValid()) time_valid = 0; - if ((long)(millis() - next_check) > 0) { + 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 94e2684c12..acbf239f02 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -70,7 +70,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 f44b363b13647b3ff715bc1bb961fb562ac6aac3 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 +- 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 +++--- 10 files changed, 18 insertions(+), 17 deletions(-) diff --git a/examples/companion_radio/ui-new/UITask.cpp b/examples/companion_radio/ui-new/UITask.cpp index c7c0306d3f..d649a1565f 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 209e12196a..eed1fcf661 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 beee32126f..9ff54e2e44 100644 --- a/src/helpers/NRF52Board.cpp +++ b/src/helpers/NRF52Board.cpp @@ -282,7 +282,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/variants/heltec_mesh_solar/target.cpp b/variants/heltec_mesh_solar/target.cpp index acbf239f02..59f2a71fa0 100644 --- a/variants/heltec_mesh_solar/target.cpp +++ b/variants/heltec_mesh_solar/target.cpp @@ -66,7 +66,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 a1972062195b3071a1a957bf6181b2ce880929d3 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; }