mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-23 01:11:23 +00:00
rtc: write the RTC time only for years 2000-2099
ZephCore writes the year as two BCD digits with no century, as y % 100. A time before 2000, accepted by a node whose clock had no time yet, was stored as a year near the end of the century and restored at the next boot above the 2025 floor: `time 900000000` (1998) came back as 2098. rtc_time_block() now fails outside 2000-2099, and zephcore_rtc_save() then logs and writes no time, for every chip; the chip keeps the time it has. An RV3028 write retry stops if its run-on time leaves the range. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a2e8d5f440
commit
9b68b7e1ae
5 files changed
+30
-18
No files matched your search
@@ -860,7 +860,7 @@ Repeaters and room servers default to `CONFIG_ZEPHCORE_REPEATER_GPS_INTERVAL_SEC
|
||||
|
||||
**Telemetry** (`REQ_TYPE_GET_TELEMETRY_DATA`, every role, upstream's shape): battery on channel 1, then `sensors.querySensors()` (`adapters/sensors/ZephyrSensorManager.cpp`): GPS position on channel 1 while the GPS is on and has a fix, each environment sensor and power-monitor channel found at boot on its own channel from 2 up (probe order), board-local analog sensors (T1000-E) on channel 1; then the MCU temperature on channel 1. Servers give guests battery + MCU temperature only and honour the requester's inverse permission mask, as upstream. Encoded by `helpers/compat/CayenneLPP.h`: upstream's library API and wire format, but values round to the nearest step where the library truncates.
|
||||
|
||||
**Clock** (`adapters/clock/ZephyrRTCClock`): `setCurrentTime()` also writes the hardware RTC when the board has one (coalesced on the system work queue), as upstream's `AutoDiscoverRTCClock` writes its chip; `seedCurrentTime()` is the boot restore, not written back. A chip is adopted at boot only once it is identified (`adapters/clock/ZephyrRTCDiscover.c`), because other parts can answer at the same address: a device is passed over when two reads each show a bit set that the chip's data sheet fixes at zero, or a time field out of range, and a time is restored only from a read in which every field is valid. The time is written in each chip's own encoding (the RX8130CE takes a one-hot weekday, `weekday-one-hot` in its descriptor), and an RV-3028 whose descriptor carries `rv3028-eeprom-config` (the RAK12002 on a RAK4631) has that configuration, its backup switchover, stored in the chip's EEPROM. Without a hardware RTC, the last time read is kept in no-init memory (RTC slow memory on ESP32) and restored after a reset that keeps RAM (reboot, crash, watchdog), as upstream's `ESP32RTCClock`; a power cycle starts from 1970 again.
|
||||
**Clock** (`adapters/clock/ZephyrRTCClock`): `setCurrentTime()` also writes the hardware RTC when the board has one (coalesced on the system work queue; a time outside 2000-2099 is not written), as upstream's `AutoDiscoverRTCClock` writes its chip; `seedCurrentTime()` is the boot restore, not written back. A chip is adopted at boot only once it is identified (`adapters/clock/ZephyrRTCDiscover.c`), because other parts can answer at the same address: a device is passed over when two reads each show a bit set that the chip's data sheet fixes at zero, or a time field out of range, and a time is restored only from a read in which every field is valid. The time is written in each chip's own encoding (the RX8130CE takes a one-hot weekday, `weekday-one-hot` in its descriptor), and an RV-3028 whose descriptor carries `rv3028-eeprom-config` (the RAK12002 on a RAK4631) has that configuration, its backup switchover, stored in the chip's EEPROM. Without a hardware RTC, the last time read is kept in no-init memory (RTC slow memory on ESP32) and restored after a reset that keeps RAM (reboot, crash, watchdog), as upstream's `ESP32RTCClock`; a power cycle starts from 1970 again.
|
||||
|
||||
**LED master switch** (`helpers/led_gate.{c,h}`, `set leds on|off`, all roles): one process-wide
|
||||
flag every LED driver consults — heartbeat and unread-message LEDs in `helpers/ui/ui_common.c`, the
|
||||
|
||||
+3
-2
@@ -911,8 +911,9 @@ config ZEPHCORE_RTC_AUTODISCOVER
|
||||
backed RTC opt in by including boards/common/rtc-i2c.dtsi or
|
||||
declaring their own node; if a chip holds a valid time it is
|
||||
restored at boot — shown tagged "L" until the next external sync.
|
||||
On every GPS/app/CLI sync the time is written back so it survives
|
||||
power-off. A node with rv3028-eeprom-config has its time read and
|
||||
On every GPS/app/CLI sync to a time within 2000-2099 the time is
|
||||
written back so it survives power-off. A node with
|
||||
rv3028-eeprom-config has its time read and
|
||||
written with the chip's backup switch flag cleared before and
|
||||
checked after, and, when its chip is the one adopted, a read
|
||||
identifies it, and a checked time read just before the store shows
|
||||
|
||||
@@ -224,8 +224,9 @@ static enum rtc_verdict rtc_identify(const struct rtc_desc *d, uint8_t blk[7])
|
||||
return RTC_FOUND;
|
||||
}
|
||||
|
||||
/* The 7-byte time block for an epoch, in d's register order. */
|
||||
static void rtc_time_block(const struct rtc_desc *d, uint32_t epoch, uint8_t blk[7])
|
||||
/* The 7-byte time block for an epoch, in d's register order. False outside
|
||||
* 2000-2099: the year is written as two BCD digits with no century. */
|
||||
static bool rtc_time_block(const struct rtc_desc *d, uint32_t epoch, uint8_t blk[7])
|
||||
{
|
||||
int y;
|
||||
unsigned m, day;
|
||||
@@ -236,6 +237,9 @@ static void rtc_time_block(const struct rtc_desc *d, uint32_t epoch, uint8_t blk
|
||||
unsigned sec = rem % 60;
|
||||
unsigned dow = (unsigned)(((epoch / 86400) + 4) % 7); /* 1970-01-01 = Thu */
|
||||
|
||||
if (y < 2000 || y > 2099) {
|
||||
return false;
|
||||
}
|
||||
blk[0] = BIN2BCD(sec);
|
||||
blk[1] = BIN2BCD(min);
|
||||
blk[2] = BIN2BCD(hour);
|
||||
@@ -244,6 +248,7 @@ static void rtc_time_block(const struct rtc_desc *d, uint32_t epoch, uint8_t blk
|
||||
blk[d->date_index == 4 ? 3 : 4] = d->week_one_hot ? (uint8_t)BIT(dow) : (uint8_t)dow;
|
||||
blk[5] = BIN2BCD(m);
|
||||
blk[6] = BIN2BCD((unsigned)(y % 100));
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Clear the power-loss flag (for chips whose flag is a separate reg;
|
||||
@@ -537,8 +542,11 @@ static void rv3028_save_retry_fn(struct k_work *work)
|
||||
uint8_t blk[7];
|
||||
|
||||
ARG_UNUSED(work);
|
||||
rtc_time_block(s_active, s_save_epoch +
|
||||
(uint32_t)((k_uptime_get() - s_save_at) / 1000), blk);
|
||||
if (!rtc_time_block(s_active, s_save_epoch +
|
||||
(uint32_t)((k_uptime_get() - s_save_at) / 1000), blk)) {
|
||||
LOG_WRN("RTC %s: time outside 2000-2099 not written", s_active->name);
|
||||
return;
|
||||
}
|
||||
if (!rv3028_steady(s_active, blk, true)) {
|
||||
if (++s_save_tries < RTC_SAVE_RETRIES) {
|
||||
k_work_schedule(&s_save_retry, RTC_SAVE_RETRY);
|
||||
@@ -675,7 +683,10 @@ void zephcore_rtc_save(uint32_t epoch)
|
||||
const struct rtc_desc *d = s_active;
|
||||
uint8_t blk[7];
|
||||
|
||||
rtc_time_block(d, epoch, blk);
|
||||
if (!rtc_time_block(d, epoch, blk)) {
|
||||
LOG_WRN("RTC %s: time outside 2000-2099 not written", d->name);
|
||||
return;
|
||||
}
|
||||
#if RTC_RV3028_CFG
|
||||
if (d->cfg != NULL) {
|
||||
(void)k_work_cancel_delayable(&s_save_retry);
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
*
|
||||
* If a present chip holds a valid time, zephcore_rtc_restore() returns it so
|
||||
* the soft clock can be seeded at boot (shown tagged "L" — local). Every
|
||||
* ZephyrRTCClock::setCurrentTime() writes it back via zephcore_rtc_save(), so
|
||||
* time survives the next power-off.
|
||||
* ZephyrRTCClock::setCurrentTime() within 2000-2099 writes it back via
|
||||
* zephcore_rtc_save(), so time survives the next power-off.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
@@ -40,7 +40,7 @@ bool zephcore_rtc_restore(uint32_t *epoch_out);
|
||||
* power-loss flag. No-op if no RTC was discovered. Intended for real syncs
|
||||
* (GPS/app/CLI), not per-packet clock nudges. Call only from the system work
|
||||
* queue: an unconfirmed write is repeated there and shares state with this
|
||||
* call.
|
||||
* call. A time outside 2000-2099 is not written.
|
||||
*/
|
||||
void zephcore_rtc_save(uint32_t epoch);
|
||||
|
||||
|
||||
@@ -81,10 +81,10 @@ properties:
|
||||
refresh. The store is retried up to 3 times, 10 minutes apart,
|
||||
identifying the chip again first; a boot whose read could not
|
||||
identify it cleanly waits for those retries. The time is read at
|
||||
boot and written on each sync with the chip's backup switch flag
|
||||
cleared before and checked after. A write sets year 00h first and
|
||||
the real year last, so a write cut by a power loss reads as "time
|
||||
not yet set", and a write not confirmed is repeated every 5 s, up
|
||||
to 12 times. Set it only on a board whose backup supply is known:
|
||||
trickle charging suits a supercapacitor or rechargeable cell,
|
||||
never a primary cell.
|
||||
boot and written on each sync within 2000-2099 with the chip's
|
||||
backup switch flag cleared before and checked after. A write sets
|
||||
year 00h first and the real year last, so a write cut by a power
|
||||
loss reads as "time not yet set", and a write not confirmed is
|
||||
repeated every 5 s, up to 12 times. Set it only on a board whose
|
||||
backup supply is known: trickle charging suits a supercapacitor or
|
||||
rechargeable cell, never a primary cell.
|
||||
Reference in new issue
Block a user