hwinfo_get_reset_cause() reads a latched register. It was read inline in
main_companion.cpp and cleared there, so the repeater, room server and
observer never read it and never cleared it: their flags carried into the next
boot, and whichever role read first defined what any later reader would see.
helpers/boot_info.c reads it once in a SYS_INIT at POST_KERNEL, logs it,
stores it and clears the register. That runs before main() on every role.
zephcore_boot_reset_cause() hands out the stored copy and reports false where
the platform has no support, which a caller can distinguish from a cause of 0.
The clear's return is discarded deliberately: ESP32 has no
hwinfo_clear_reset_cause() implementation, so the weak stub returns -ENOSYS.
The capture is still correct there; only the next boot's reading is not.
Logging in boot_info_init() rather than only in the consuming role matters
because the clear now happens everywhere. Without it a repeater that rebooted
on WATCHDOG or LOCKUP would have the evidence cleared and recorded nowhere,
where before it survived in the register for whoever read it over SWD.
main_companion.cpp reads the stored copy and renders through a table with one
row per RESET_* bit, so a cause with no label is no longer logged as bare hex.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
main_repeater.cpp and main_room_server.cpp applied the GPS duty interval
~55 lines before data_store.loadPrefs() ran, so getNodePrefs()->gps_interval
still held the initNodePrefs() value of 300 s.
That 300 is the *companion* default. loadPrefs() is not a pure read on these
roles: its first-boot path is the only place the 48 h repeater/room-server
default is established, and it persists that to flash so later code can treat
flash as authoritative. A stored value is likewise only in the struct after
loadPrefs() returns. Reading gps_interval before that call therefore cannot
see either the role default or the operator's setting -- only the companion
constant.
Two consequences, on every boot:
- A stock GPS-equipped repeater duty-cycled its GPS every 5 minutes instead
of every 48 hours, ~576x more wakeups than intended. On battery nodes this
is a straight power regression.
- Any operator value never reached the hardware. "set gps duty 0" (always-on)
persisted to flash correctly, and `get gps duty` reports the manager's
now-effective value, so it answered 300 -- readable as a stale default
rather than as the setting being ignored.
The GPS manager itself is correct: gps_start_acquiring(), the fix-done
callback, gps_enable() and the fresh-fix request all guard standby on
gps_duty_cycling(), so the always-on invariant holds once the manager is
actually told the interval is zero.
Same ordering class as the two bugs already documented in these files -- radio
frequency binding and the LED master switch -- where CLI readback looked right
and the hardware disagreed. main_companion.cpp has always had the correct
order (loadPrefs() at 1461, gps_set_poll_interval_sec() at 1616) and is
unaffected.
Move the interval and the mode switch that starts acquisition to just after
loadPrefs(). Callback registration stays where it was: it has no prefs
dependency and must precede acquisition.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>