diff --git a/src/helpers/AutoDiscoverRTCClock.cpp b/src/helpers/AutoDiscoverRTCClock.cpp index 49a72893d..53afcfcaa 100644 --- a/src/helpers/AutoDiscoverRTCClock.cpp +++ b/src/helpers/AutoDiscoverRTCClock.cpp @@ -26,6 +26,17 @@ bool AutoDiscoverRTCClock::i2c_probe(TwoWire& wire, uint8_t addr) { return (error == 0); } +void AutoDiscoverRTCClock::syncSystemClock() { + uint32_t hw_time = getCurrentTime(); + if (hw_time <= 1704067200UL) return; // DS3231 not set or lost power (before 2024-01-01) + + uint32_t sys_time = _fallback->getCurrentTime(); + int32_t drift = (int32_t)(hw_time - sys_time); + if (drift > 2 || drift < -2) { + _fallback->setCurrentTime(hw_time); + } +} + void AutoDiscoverRTCClock::begin(TwoWire& wire) { if (i2c_probe(wire, DS3231_ADDRESS)) { ds3231_success = rtc_3231.begin(&wire); @@ -49,6 +60,12 @@ void AutoDiscoverRTCClock::begin(TwoWire& wire) { rtc_8130_success = true; MESH_DEBUG_PRINTLN("RX8130CE: Initialized"); } + + _has_hw_rtc = ds3231_success || rv3028_success || rtc_8563_success || rtc_8130_success; + if (_has_hw_rtc) { + syncSystemClock(); + _last_sync_ms = millis(); + } } uint32_t AutoDiscoverRTCClock::getCurrentTime() { diff --git a/src/helpers/AutoDiscoverRTCClock.h b/src/helpers/AutoDiscoverRTCClock.h index 11364cd81..21b2ef6e7 100644 --- a/src/helpers/AutoDiscoverRTCClock.h +++ b/src/helpers/AutoDiscoverRTCClock.h @@ -4,12 +4,20 @@ #include #include +#ifndef RTC_RESYNC_INTERVAL_MS + #define RTC_RESYNC_INTERVAL_MS 3600000UL // re-sync system clock from hardware RTC once per hour +#endif + class AutoDiscoverRTCClock : public mesh::RTCClock { mesh::RTCClock* _fallback; + bool _has_hw_rtc; + unsigned long _last_sync_ms; bool i2c_probe(TwoWire& wire, uint8_t addr); + void syncSystemClock(); public: - AutoDiscoverRTCClock(mesh::RTCClock& fallback) : _fallback(&fallback) { } + AutoDiscoverRTCClock(mesh::RTCClock& fallback) + : _fallback(&fallback), _has_hw_rtc(false), _last_sync_ms(0) { } void begin(TwoWire& wire); uint32_t getCurrentTime() override; @@ -17,5 +25,12 @@ public: void tick() override { _fallback->tick(); // is typically VolatileRTCClock, which now needs tick() + if (_has_hw_rtc) { + unsigned long now = millis(); + if ((unsigned long)(now - _last_sync_ms) >= RTC_RESYNC_INTERVAL_MS) { + syncSystemClock(); + _last_sync_ms = now; + } + } } };