Skip to content

Commit b5ebb6f

Browse files
committed
Fix millis() wraparound handling in timer comparisons
Fixes potential scheduler failures after ~49.7 days of continuous uptime when millis() wraps around from 2^32-1 to 0. Changed time comparisons from: if (millis() >= targetTime) to: if ((int32_t)(millis() - targetTime) >= 0) This uses signed subtraction to correctly handle wraparound, matching the approach from MeshCore 1.14 commit 011edd3c. Affected timers: - pendingAdvertTime: scheduled ADVERT beacon after time sync - tempRadioExpireTime: temporary radio parameter expiration - rebootTime: delayed reboot from CLI command Without this fix, scheduled events would get stuck and never trigger after millis() wraparound, as the target time would appear to be in the far future.
1 parent df1ebf1 commit b5ebb6f

2 files changed

Lines changed: 10 additions & 3 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,10 @@ MIT License - See LICENSE file for details.
208208
- Default: 0 (no limit, backward compatible)
209209
- Reduces contact list pollution from distant nodes
210210
- Test script: `tools/test_autoadd_maxhops.py`
211+
- **Bug Fix: millis() Wraparound Handling** - Fixes scheduler issues after ~49.7 days uptime
212+
- Fixed timer comparisons in pendingAdvertTime, tempRadioExpireTime, and rebootTime
213+
- Uses signed subtraction to correctly handle millis() wraparound
214+
- Prevents scheduled tasks from getting stuck when millis() wraps around
211215

212216
### v0.5.2 (2026-02-15)
213217
- **Extended MeshCore CLI** - 23 new commands for full MeshCore standard compatibility

src/main.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2104,7 +2104,8 @@ void healthCheck() {
21042104

21052105
void checkAdvertBeacon() {
21062106
// Check for pending ADVERT after time sync
2107-
if (pendingAdvertTime > 0 && millis() >= pendingAdvertTime) {
2107+
// Use signed subtraction to handle millis() wraparound correctly
2108+
if (pendingAdvertTime > 0 && (int32_t)(millis() - pendingAdvertTime) >= 0) {
21082109
pendingAdvertTime = 0; // Clear pending
21092110
LOG(TAG_ADVERT " Sched ADV post-sync\n\r");
21102111
sendAdvert(true);
@@ -3241,7 +3242,8 @@ void loop() {
32413242
feedWatchdog();
32423243

32433244
// Auto-expire temporary radio settings
3244-
if (tempRadioActive && tempRadioExpireTime > 0 && millis() >= tempRadioExpireTime) {
3245+
// Use signed subtraction to handle millis() wraparound correctly
3246+
if (tempRadioActive && tempRadioExpireTime > 0 && (int32_t)(millis() - tempRadioExpireTime) >= 0) {
32453247
tempRadioActive = false;
32463248
tempRadioExpireTime = 0;
32473249
setupRadio(); startReceive(); calculateTimings();
@@ -3258,7 +3260,8 @@ void loop() {
32583260
}
32593261

32603262
// Handle pending reboot from CLI command
3261-
if (pendingReboot && millis() >= rebootTime) {
3263+
// Use signed subtraction to handle millis() wraparound correctly
3264+
if (pendingReboot && (int32_t)(millis() - rebootTime) >= 0) {
32623265
LOG(TAG_SYSTEM " Rebooting...\n\r");
32633266
delay(100); // Let serial flush
32643267
HW_Reset(0);

0 commit comments

Comments
 (0)