Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/ARCHITECTURE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
35 changes: 35 additions & 0 deletions zephcore/adapters/clock/ZephyrRTCDiscover.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)), \
Expand All @@ -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), \
},
Expand Down Expand Up @@ -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])
Expand Down Expand Up @@ -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
Expand Down
4 changes: 3 additions & 1 deletion zephcore/adapters/clock/ZephyrRTCDiscover.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions zephcore/boards/common/rtc-i2c.dtsi
Original file line number Diff line number Diff line change
Expand Up @@ -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];
};
Expand Down
1 change: 1 addition & 0 deletions zephcore/boards/nrf52840/rak4631/board.overlay
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
13 changes: 12 additions & 1 deletion zephcore/dts/bindings/rtc/zephcore,rtc-i2c.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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: >
Expand All @@ -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
Expand Down
Loading