Skip to content

[Bug]: RTC time overwritten with uptime on platforms without hardware RTC #9828

Description

@duraseb

Category

Other

Hardware

Raspberry Pi Pico (W)

Is this bug report about any UI component firmware like InkHUD or Meshtatic UI (MUI)?

  • Meshtastic UI aka MUI colorTFT
  • InkHUD ePaper
  • OLED slide UI on any display

Firmware Version

2.7.20

Description

Since PR #9493 (200e79e80 — "You get an RTC, and you get an RTC!"), platforms without a hardware RTC (e.g., RP2040) lose their network-derived time immediately after it is set.

Root Cause

PR #9493 removed the #if HAS_RTC guard around readFromRTC() in perhapsSetRTC() (RTC.cpp, line ~283):

// Before #9493:
#if HAS_RTC
        readFromRTC();
#endif

// After #9493:
        readFromRTC();

On platforms without a hardware RTC, readFromRTC() falls into the #else branch which calls gettimeofday(). On RP2040, gettimeofday() returns uptime (seconds since boot), not wall-clock time, because there is no settimeofday() call for RP2040 in perhapsSetRTC() (only ESP32 has one).

This causes the following sequence:

  1. perhapsSetRTC() correctly sets zeroOffsetSecs to the network time (e.g., 1772717422)
  2. perhapsSetRTC() calls readFromRTC()
  3. readFromRTC() calls gettimeofday() which returns uptime (e.g., 21)
  4. readFromRTC() unconditionally overwrites zeroOffsetSecs = 21
  5. getTime() now returns uptime instead of wall-clock time for the rest of the session

Impact

  • getTime() returns uptime seconds (~21) instead of epoch time (~1.7 billion)
  • getValidTime(RTCQualityFromNet) returns tiny values, causing rx_time on all received packets to be uptime-based
  • NodeDB::updateFrom() sets last_heard to uptime values for newly heard nodes
  • Nodes loaded from flash have real timestamps, so newly heard nodes appear "oldest" and get immediately evicted from the nodeDB when it is full
  • Rapid nodeDB churn: 222 evictions observed in a single ~3 hour session on a node with MAX_NUM_NODES=100

Affected Platforms

Any platform without a hardware RTC where gettimeofday() does not reflect time set via the internal zeroOffsetSecs mechanism. Confirmed on RP2040.

Fix

Add the same currentQuality == RTCQualityNone guard that all hardware RTC branches already use in readFromRTC():

// In readFromRTC(), the #else branch (platforms without hardware RTC):
    if (!gettimeofday(&tv, NULL)) {
        uint32_t now = millis();
        uint32_t printableEpoch = tv.tv_sec;
        LOG_DEBUG("Read RTC time as %ld", printableEpoch);
        if (currentQuality == RTCQualityNone) {  // <-- add this guard
            timeStartMsec = now;
            zeroOffsetSecs = tv.tv_sec;
        }
        return RTCSetResultSuccess;
    }

This matches the existing pattern in the RV3028, PCF8563/PCF85063, and RX8130CE branches which all check if (currentQuality == RTCQualityNone) before overwriting the time.

Introduced In

Relevant log output

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingfirst-contributionhelp wantedWe'd welcome help on this issuetriagedReviewed by the team, has enough information and ready to work on now.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions