mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-09-26 20:18:04 +00:00
touch: fix the P4 clock — mirror the mesh RTC into the ESP32 system clock
The UI reads the ESP32 *system* clock for every displayed timestamp (status
bar, chat bubbles) while protocol timestamps come from ClockFloorRTC. On a
board with no RTC chip those are the same clock, so they cannot disagree. The
T-Display P4 (and the ThinkNode M9) carry a PCF8563, and
AutoDiscoverRTCClock::setCurrentTime is an if/else chain: with a chip present
it writes ONLY the chip and never reaches the ESP32RTCClock fallback. So the
system clock kept ESP32RTCClock::begin()'s power-on seed forever.
That seed is 1715770351 == exactly ClockFloorRTC::MIN_VALID_EPOCH, which
explains both halves of the P4 field report:
- the UI showed 15 May 2024 while sent messages carried the correct time
- "Sync clock from system" then poisoned the good clock: it fed that seed
back in as a real set and cleared the MIN check by being precisely equal
to it (the old `t < 100000` guard only caught a clock counting up from 0)
Fixed in the one funnel every time source already goes through:
- ClockFloorRTC::setCurrentTime mirrors every ACCEPTED value into the system
clock, so NTP-via-C6, GPS and the phone app all correct the display too.
Validation runs first, so 1902/2043-class garbage never reaches it either.
- new seedSystemClock(), called at boot right after seedFloor(): a
battery-backed chip already knows the time, so the UI reads correctly with
no network and no GPS fix. After seedFloor, so a dead chip yields the
persisted floor rather than the seed.
- the sync button rejects an untouched seed and now reports honestly instead
of always claiming "Clock synced".
No-op on the seven chipless boards: the fallback already wrote the same value
through settimeofday. GPS re-syncs are rate-capped to ~30 min, so the mirror
adds no measurable work. Builds clean on all 8 S3 envs + the P4 IDF target;
compile-verified only, the P4 is still off the USB bus pending a power cycle.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
d6c0321472
commit
fe87ff02c5
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
// Monotonic clock floor for outgoing protocol timestamps (issue #89 follow-up).
|
||||
//
|
||||
@@ -60,9 +61,43 @@ public:
|
||||
void setCurrentTime(uint32_t time) override {
|
||||
if (time < MIN_VALID_EPOCH || time > MAX_PLAUSIBLE_EPOCH) return; // garbage set — ignore, whatever the source
|
||||
AutoDiscoverRTCClock::setCurrentTime(time);
|
||||
pushSystemClock(time);
|
||||
if (_floor > time + TRUSTED_BACK_CAP) _floor = time;
|
||||
}
|
||||
|
||||
// The UI reads the ESP32 *system* clock for every displayed time (status bar, chat
|
||||
// bubbles, logs — see the note at addMessage()), while protocol timestamps come from
|
||||
// this class. On a board with NO RTC chip they are the same clock: AutoDiscoverRTCClock
|
||||
// falls through to ESP32RTCClock, whose set IS settimeofday(), so the two can never
|
||||
// disagree. With a chip present (the T-Display P4 and the ThinkNode M9 both carry a
|
||||
// PCF8563 at 0x51 and call rtc_clock.begin(); the T-LoRa Pager has one too but
|
||||
// deliberately skips begin(), since its PCF85063A is register-incompatible with the
|
||||
// core's 8563 driver) the base class writes ONLY the chip, so the system clock keeps
|
||||
// ESP32RTCClock::begin()'s power-on seed forever. That seed is
|
||||
// exactly MIN_VALID_EPOCH, which is why the P4 showed 15 May 2024 in the UI while sent
|
||||
// messages carried the correct time — and why "Sync clock from system" then poisoned
|
||||
// the good clock: it fed that seed back in as a real set, clearing the MIN check by
|
||||
// being precisely equal to it.
|
||||
//
|
||||
// So mirror every ACCEPTED value into the system clock. The validation above has
|
||||
// already run, so 1902/2043-class garbage never reaches the display either.
|
||||
static void pushSystemClock(uint32_t t) {
|
||||
struct timeval tv;
|
||||
tv.tv_sec = (time_t)t;
|
||||
tv.tv_usec = 0;
|
||||
settimeofday(&tv, nullptr);
|
||||
}
|
||||
|
||||
// Boot seed. An RTC chip is battery-backed, so it already knows the time while the
|
||||
// system clock is still on the power-on seed — pull it across once so the UI reads
|
||||
// correctly with no network and no GPS fix. Goes through getCurrentTime(), so the
|
||||
// garbage-future hatch and the persisted floor both apply. No-op on the chipless
|
||||
// boards (it reads the system clock and writes the same value back).
|
||||
void seedSystemClock() {
|
||||
const uint32_t t = getCurrentTime();
|
||||
if (t >= MIN_VALID_EPOCH && t <= MAX_PLAUSIBLE_EPOCH) pushSystemClock(t);
|
||||
}
|
||||
|
||||
// Boot-time seed from the persisted floor (only ever raises), and the getter
|
||||
// the persister reads back. Benign u32 races: both cores may touch _floor.
|
||||
// A poisoned persisted value (saved while the hw clock asserted garbage) is refused.
|
||||
|
||||
+20
-6
@@ -8596,8 +8596,8 @@ static void saveExperimentalCb(lv_event_t* e) {
|
||||
|
||||
static void syncClockCb(lv_event_t* e) {
|
||||
if (lv_event_get_code(e) != LV_EVENT_CLICKED || !g_lv.task) return;
|
||||
g_lv.task->setDeviceTimeFromSystemClock();
|
||||
g_lv.task->showAlert(TR("Clock synced"), 900);
|
||||
const bool ok = g_lv.task->setDeviceTimeFromSystemClock();
|
||||
g_lv.task->showAlert(ok ? TR("Clock synced") : TR("No system time yet"), 900);
|
||||
}
|
||||
|
||||
// Chat-save fallback dropdown (Settings -> General): selection index -> number
|
||||
@@ -43667,6 +43667,12 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
// backwards (server replay guards silently drop those). Seed before the UI
|
||||
// generates traffic; written back rate-capped in loop() + on shutdown().
|
||||
rtc_clock.seedFloor(touchPrefsGetClockFloor());
|
||||
// ...then push the resulting time into the ESP32 system clock, which is what every
|
||||
// displayed timestamp reads. On a board with a battery-backed RTC chip (P4) the chip
|
||||
// knows the time but the system clock is still on its power-on seed, so the UI would
|
||||
// otherwise show 15 May 2024 until a network/GPS sync landed. Order matters: after
|
||||
// seedFloor(), so a dead chip still yields the persisted floor instead of the seed.
|
||||
rtc_clock.seedSystemClock();
|
||||
#endif
|
||||
|
||||
// GPS resume: initBasicGPS() always leaves the module stopped at boot, so a
|
||||
@@ -45096,13 +45102,21 @@ bool UITask::setWifiRadio(bool on) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void UITask::setDeviceTimeFromSystemClock() {
|
||||
bool UITask::setDeviceTimeFromSystemClock() {
|
||||
#if defined(ESP32)
|
||||
time_t t = time(nullptr);
|
||||
if (t < 100000) return;
|
||||
the_mesh.getRTCClock()->setCurrentTime((uint32_t)t);
|
||||
const uint32_t t = (uint32_t)time(nullptr);
|
||||
// ESP32RTCClock::begin() seeds the system clock to exactly MIN_VALID_EPOCH on power-on,
|
||||
// so "still at the seed" means never synced. Pushing that into the mesh clock is a
|
||||
// two-year step backwards that setCurrentTime()'s own MIN check cannot catch, because
|
||||
// the value IS the constant it compares against — that is how a P4 (whose RTC chip left
|
||||
// the system clock on the seed) could sync 2024 over a perfectly good clock. The old
|
||||
// `t < 100000` guard only caught a clock counting up from zero, which never happens here.
|
||||
if (t <= ClockFloorRTC::MIN_VALID_EPOCH) return false;
|
||||
the_mesh.getRTCClock()->setCurrentTime(t);
|
||||
return true;
|
||||
#else
|
||||
the_mesh.getRTCClock()->setCurrentTime((uint32_t)(millis() / 1000));
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -464,7 +464,8 @@ public:
|
||||
bool enableBle();
|
||||
void disableBle() { if (_serial) _serial->disableBle(); }
|
||||
int getWsConnectedCount() const { return _serial ? _serial->getWsConnectedCount() : 0; }
|
||||
void setDeviceTimeFromSystemClock();
|
||||
/** Push the ESP32 system clock into the mesh RTC. false = never synced, mesh clock untouched. */
|
||||
bool setDeviceTimeFromSystemClock();
|
||||
/** Mark recent user input — call when touch / hw button is detected. */
|
||||
void noteUserInput();
|
||||
/** Get / set the screen-off-after-idle timeout (0 = never). Persists in NVS. */
|
||||
|
||||
Reference in New Issue
Block a user