mirror of
https://github.com/liquidraver/ZephCore.git
synced 2026-10-15 03:49:55 +00:00
rtc: clear the RV3028 12-hour bit at boot
ZephCore assumed 24-hour mode. If other firmware had left an RV3028 in 12-hour mode, the boot read masked the hours with 0x3F and could restore a time up to twelve hours off, and each save's 24-hour hours byte meant a different hour to the chip. A new optional twelve-hour-bit = [register mask] names the bit, set on the two RV3028 nodes to Control 2 12_24. Once the chip is cleanly identified at boot, rtc_probe() clears a set bit and re-reads the time block; the chip converts its own hours, as MeshCore relies on. If the register cannot be read, reads FFh, or the clear or re-read fails, no time is taken from the chip. DS3231/DS1307 are unchanged: a save's hours byte already selects 24-hour mode there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5.5
parent
290b0c26b0
commit
db69172c66
@@ -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; 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.
|
||||
**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. An RV-3028 cleanly identified in 12-hour mode has its `twelve-hour-bit` cleared first, so the chip converts its own hours. No time is taken from a cleanly identified RV-3028 whose `twelve-hour-bit` register cannot be read or reads FFh, or whose clear or re-read fails. 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
|
||||
|
||||
@@ -40,6 +40,8 @@ struct rtc_desc {
|
||||
uint8_t status_mask; /* "time unreliable" bit within status_reg */
|
||||
const uint8_t *zero; /* 7 bytes of bits the data sheet shows as 0, or NULL */
|
||||
bool week_one_hot; /* weekday as one bit per day, not 0-6 */
|
||||
uint8_t h12_reg; /* register of the 12-hour bit */
|
||||
uint8_t h12_mask; /* 12-hour bit, or 0 if none */
|
||||
#if RTC_RV3028_CFG
|
||||
const uint8_t *cfg; /* rv3028-eeprom-config triplets, or NULL */
|
||||
uint8_t cfg_len;
|
||||
@@ -79,6 +81,10 @@ DT_FOREACH_STATUS_OKAY(RTC_COMPAT, RTC_CFG_ARRAY)
|
||||
#define RTC_CFG_FIELDS(node)
|
||||
#endif
|
||||
|
||||
#define RTC_H12(node, i) \
|
||||
COND_CODE_1(DT_NODE_HAS_PROP(node, twelve_hour_bit), \
|
||||
(DT_PROP_BY_IDX(node, twelve_hour_bit, i)), (0))
|
||||
|
||||
#define RTC_DESC_ENTRY(node) \
|
||||
{ \
|
||||
.bus = DEVICE_DT_GET(DT_BUS(node)), \
|
||||
@@ -91,6 +97,8 @@ DT_FOREACH_STATUS_OKAY(RTC_COMPAT, RTC_CFG_ARRAY)
|
||||
DT_NODE_HAS_PROP(node, zero_mask), \
|
||||
(RTC_ZERO_NAME(node)), (NULL)), \
|
||||
.week_one_hot = DT_PROP(node, weekday_one_hot), \
|
||||
.h12_reg = (uint8_t)RTC_H12(node, 0), \
|
||||
.h12_mask = (uint8_t)RTC_H12(node, 1), \
|
||||
RTC_CFG_FIELDS(node) \
|
||||
.name = DT_NODE_FULL_NAME(node), \
|
||||
},
|
||||
@@ -224,6 +232,30 @@ static enum rtc_verdict rtc_identify(const struct rtc_desc *d, uint8_t blk[7])
|
||||
return RTC_FOUND;
|
||||
}
|
||||
|
||||
/* Clear a set 12-hour bit and re-read blk; the chip converts its hours
|
||||
* itself. False on a failed or FFh read of the bit, or a failed clear or
|
||||
* re-read. */
|
||||
static bool rtc_clear_12h(const struct rtc_desc *d, uint8_t blk[7])
|
||||
{
|
||||
uint8_t r;
|
||||
|
||||
if (d->h12_mask == 0) {
|
||||
return true;
|
||||
}
|
||||
if (i2c_reg_read_byte(d->bus, d->addr, d->h12_reg, &r) != 0 || r == 0xFF) {
|
||||
return false;
|
||||
}
|
||||
if (!(r & d->h12_mask)) {
|
||||
return true;
|
||||
}
|
||||
if (i2c_reg_write_byte(d->bus, d->addr, d->h12_reg, r & ~d->h12_mask) != 0 ||
|
||||
i2c_burst_read(d->bus, d->addr, d->time_reg, blk, 7) != 0) {
|
||||
return false;
|
||||
}
|
||||
LOG_INF("%s: 12-hour mode cleared", d->name);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* 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])
|
||||
@@ -584,6 +616,9 @@ static bool rtc_probe(uint32_t *epoch_out)
|
||||
if (v == RTC_ABSENT) {
|
||||
continue;
|
||||
}
|
||||
if (v == RTC_FOUND && !rtc_clear_12h(d, blk)) {
|
||||
v = RTC_FOUND_GARBLED;
|
||||
}
|
||||
|
||||
#if RTC_RV3028_CFG
|
||||
/* Only a clean identification is configured: the store writes to
|
||||
|
||||
@@ -28,7 +28,9 @@ extern "C" {
|
||||
* sane time (year >= 2025 and its power-loss flag clear): store its Unix
|
||||
* epoch in *epoch_out and return true. The first chip found (valid time or
|
||||
* not) is remembered as the write-back target. Returns false if none is
|
||||
* present or none holds a trustworthy time.
|
||||
* present or none holds a trustworthy time. On a clean identification, a set
|
||||
* twelve-hour-bit is cleared before the time is taken. No time is taken if its
|
||||
* register cannot be read or reads FFh, or if the clear or the re-read fails.
|
||||
*
|
||||
* A descriptor with rv3028-eeprom-config also has that config stored in the
|
||||
* chip's EEPROM, retried on the system work queue if it fails.
|
||||
|
||||
@@ -65,6 +65,7 @@ rtc_rv3028: rtc-rv3028@52 {
|
||||
date-index = <4>;
|
||||
status-reg = <0x0e> /* status */
|
||||
status-mask = <0x01> /* PORF — power-on reset */
|
||||
twelve-hour-bit = [10 02]; /* Control 2 12_24, p. 24 */
|
||||
/* RV-3028-C7 Application Manual Rev. 1.4, 3.2, p. 12 */
|
||||
zero-mask = [80 80 c0 f8 c0 e0 00];
|
||||
};
|
||||
|
||||
@@ -228,6 +228,7 @@
|
||||
date-index = <4>;
|
||||
status-reg = <0x0e>; /* status */
|
||||
status-mask = <0x01>; /* PORF — power-on reset */
|
||||
twelve-hour-bit = [10 02]; /* Control 2 12_24, p. 24 */
|
||||
/* RV-3028-C7 Application Manual Rev. 1.4, 3.2, p. 12 */
|
||||
zero-mask = [80 80 c0 f8 c0 e0 00];
|
||||
/* The RAK12002's backup is a supercapacitor. As the RV-3028-C7
|
||||
|
||||
@@ -62,6 +62,16 @@ properties:
|
||||
bit 6) rather than a number 0-6. Set it for a chip whose data sheet
|
||||
says so, such as the RX8130CE.
|
||||
|
||||
twelve-hour-bit:
|
||||
type: uint8-array
|
||||
description: >
|
||||
[register mask]: a bit outside the time block that reads set in
|
||||
12-hour mode, where clearing it makes the chip convert its own
|
||||
hours to 24-hour, such as the RV3028's Control 2 12_24. Once the
|
||||
chip is cleanly identified, a set bit is cleared before a time is
|
||||
taken from it. No time is taken if the register cannot be read or
|
||||
reads FFh, or if the write or the re-read fails.
|
||||
|
||||
rv3028-eeprom-config:
|
||||
type: uint8-array
|
||||
description: >
|
||||
@@ -80,7 +90,8 @@ properties:
|
||||
it, off once the store has disabled it, until a retry or that
|
||||
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
|
||||
identify it cleanly, or whose 12-hour clear failed, waits for those
|
||||
retries. The time is read at
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user