Skip to content

sensors: fix millis() rollover that stalls GPS time-sync on long-uptime nodes - #2937

Merged
ripplebiz merged 1 commit into
meshcore-dev:devfrom
benskigomez:fix/gps-timesync-millis-overflow
Jul 13, 2026
Merged

sensors: fix millis() rollover that stalls GPS time-sync on long-uptime nodes#2937
ripplebiz merged 1 commit into
meshcore-dev:devfrom
benskigomez:fix/gps-timesync-millis-overflow

Conversation

@benskigomez

Copy link
Copy Markdown

Problem

MicroNMEALocationProvider and EnvironmentSensorManager store a future millis()
deadline in a signed long and compare it with a naive millis() > deadline:

long next_check = 0;
...
if (millis() > next_check) {
    next_check = millis() + 1000;
    // re-arm 30-min time-sync + set RTC from GPS here
}

millis() is uint32_t. After the ~24.8-day sign flip the stored deadline sits above
the wrapped millis(), so millis() > next_check stays false and the whole block never
runs again. Because both the periodic re-arm and the actual _clock->setCurrentTime()
live inside that block, GPS→RTC time-sync (manual and automatic) stops permanently until
reboot — matching the "ran for weeks then the clock drifted / node fell off the map"
reports in #2786 (this is distinct from, and complementary to, the missing-clock-in-
constructor cause some boards also have). The same pattern in
EnvironmentSensorManager::loop() (next_gps_update) freezes the location cache refresh.

Fix

Use the wrap-safe signed-difference compare already used by Dispatcher::millisHasNowPassed
((long)(millis() - deadline) > 0) and make the deadlines unsigned long:

  • src/helpers/sensors/MicroNMEALocationProvider.h: next_check
  • src/helpers/sensors/EnvironmentSensorManager.cpp: next_gps_update

Valid for all intervals well under 2^31 ms (here 1 s), on every platform.

Two tiny cleanups ride along in the same file: reorder the MicroNMEALocationProvider
constructor init-list to declaration order (silences -Wreorder), and drop the always-true
if (_claims > 0) guard in claim() (it always runs right after _claims++).

No functional change beyond fixing the rollover; no API/ABI surface touched (all changed
symbols are private/local).

next_check and next_gps_update stored a future millis() value in a signed
long and compared with a naive '>'. After the ~24.8-day millis() sign flip
the deadline sits above the wrapped millis(), so the block never runs again
and GPS->RTC time-sync (and the location cache refresh) stall permanently
until reboot. Switch to unsigned deadlines with the wrap-safe signed-
difference compare '(long)(millis() - deadline) > 0', matching the idiom in
Dispatcher::millisHasNowPassed.

Also: reorder the MicroNMEALocationProvider ctor init-list to declaration
order (silences -Wreorder) and drop the always-true 'if (_claims > 0)' guard
in claim() (claim() always runs after _claims++, so it is >= 1).
@ripplebiz
ripplebiz merged commit 4f12dc0 into meshcore-dev:dev Jul 13, 2026
12 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants