Skip to content

rtc: write the RTC time only for years 2000-2099 (iteration branch) - #54

Closed
ptr727 wants to merge 16 commits into
devfrom
work/rtc-year-range
Closed

ptr727 wants to merge 16 commits into
devfrom
work/rtc-year-range

Conversation

@ptr727

@ptr727 ptr727 commented Oct 7, 2026

Copy link
Copy Markdown
Owner

Iteration branch for the cut-down replacement of liquidraver#103, per the maintainer's review (liquidraver#103 (comment)). It starts from #50's head (the A0h version coordinated with Zephyr and MeshCore) and cuts it to the 2000-2099 write range. Never merged; the clean branch rtc-year-range carries the upstream commit.

🤖 Generated with Claude Code

ptr727 and others added 16 commits October 6, 2026 08:51
The RV3028 time write set year 00h, burst-wrote 00h-05h, then wrote the
real year, so a write cut short left year 2000 and the next boot took no
time from it. That split the write into three accesses against the
manual's one-access rule (Application Manual Rev 1.4, 4.5), relying on
the Seconds write restarting the prescaler, and used a real date as the
"not set" mark.

The write now sets 06h to A0h, which is not BCD, then writes all seven
registers 00h-06h in one burst, year last. The chip keeps each byte as
it is acknowledged, so a write cut short still leaves the mark. On read
at an rv3028-eeprom-config descriptor, a year of A0h-FEh reads as "time
not yet set": a New Year counts a left mark on (A0h to A1h, A9h to B0h)
and never into BCD. FFh stays a failed read, since a read cut short
returns 1s and the year is the last byte. The BSF bracket and the 5 s
retry around the write are unchanged, and so is the 2025 floor, so a
power-on-reset chip reading 2000-01-01 still gives no time.

The same write order and year handling are used by Zephyr and MeshCore
for the RV3028; the three are kept consistent in behaviour.

Link: zephyrproject-rtos/zephyr#121389
Link: meshcore-dev/MeshCore#3421
Link: liquidraver#98

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The binding still described the old write order (year 00h first, the
real year last).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review: a write cut on the A0h byte itself leaves the old year and
the old, intact time, so the docs now say "cut after the mark". The read
comment no longer says a counted-on mark never reaches BCD, since only
A0h, A9h and FFh were rolled over. The header lines the first edit left
as fragments are rewrapped, and so is the binding text.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review: a counted-on mark skips xAh-xFh, and another tool can
write any of them, so the header no longer calls the whole range the
mark. The behaviour is unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The year register holds two BCD digits and no century, and the save
encoded y % 100. So a time before 2000 was stored as a year near the
end of the century: a CLI `time 900000000` (1998), accepted by a node
whose clock had no time yet, was written as year 98 and restored at the
next boot as 2098, past the 2025 floor. A year from 2100 was stored as
2100-2106 minus a century, which the floor did reject. On the RV3028,
BCD-encoding 2100 as a three-digit year would also equal the A0h mark,
which is why Zephyr and MeshCore bound the write to 2000-2099 too.

rtc_time_block() now fails outside 2000-2099, and the save writes
nothing then, for every chip. At an rv3028-eeprom-config descriptor it
writes the A0h mark instead and drops any pending retry, so the next
boot takes no time rather than the older time the chip still holds. A
retry whose run-on time crosses 2099 does the same. Other chips keep
their older time.

Local review: the docs now say a write cut between the mark and the
year byte gives no time, rather than any cut after the mark, and that
a mark gives no time rather than always logging "time not yet set",
since a set power-loss flag or a switchover logs first.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review of the range check: the refusal ignored whether its A0h
write landed, logged "year marked unset" either way and had already
dropped any pending retry, so a failed mark left the chip's older time
for the next boot to restore. The mark is now checked and, if it fails,
repeated every 5 s up to the same 13 attempts, sharing the time write's
repeat state; a newer save replaces it either way. The header says only
a time within 2000-2099 is saved, and the 2000-2099 reason is ZephCore's
two-digit year, since the DS3231 and PCF8563 have a century bit that
ZephCore does not use.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review: the mark was confirmed by its acknowledgement alone,
without the BSF clear-before / check-after a time write gets, so a
switchover during it (5.10) could leave the byte unstored while the log
said "year marked unset". It now takes the same bracket, and a failure
is repeated. A repeat that switches from writing the time to marking
restarts the try count, so the final warning counts mark attempts only.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review of fdf2332: restarting the try count when a repeat switched
from writing the time to marking let one save repeat up to 23 times,
against the documented 13 attempts, and its final log overstated the
mark attempts by one. The count now runs across both, and the final log
says "save not confirmed" rather than naming one kind.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review: the DS3231 and PCF8563 have a century bit, which ZephCore
writes as 0 and masks off on read, so the limit is the encoding rather
than every chip.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Upstream's "comment diet vol.2" (9d6b21a) cut the RTC header contracts to
a few sentences each, which conflicted with this branch's paragraphs. The
header keeps upstream's text, plus one sentence each for the A0h mark on
read and the 2000-2099 write range with its A0h mark. This branch's own
new comments in ZephyrRTCDiscover.c are trimmed to the same density.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review: the trimmed rv3028_write_time() comment said a write cut
before the year byte leaves the mark, which a cut on the A0h byte itself
does not (ed8802f had this right), and the trimmed header called the
whole A0h-FEh range the mark a cut write leaves (b9fb124 had narrowed
it). The time block comment again names the two-digit year as ZephCore's
encoding.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… range

Local review: "the A0h mark, or a New Year's count on from it" is false
for the xAh-xFh values in the range, which a count from A0h never
reaches; the code and header now state the rule alone. The Kconfig help
and ARCHITECTURE.md said every sync writes the RTC, which a time outside
2000-2099 no longer does.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review: ARCHITECTURE.md said an out-of-range time is not written,
but at an RV3028 with rv3028-eeprom-config its year is marked instead.
A year of FFh reaching the A0h-FEh check has passed the BSF-checked
read, so it is a stored value, not a cut read; the comment no longer
gives a reason. A Kconfig help line the last edit left long is wrapped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
liquidraver#103 review (comment 6037017924): drop the A0h year
mark, the one-burst write, rv3028_mark_year(), s_save_mark and the A0h
read branch. The RV3028 write is dev's again (year 00h, 00h-05h, then
the year): ZephCore's 2025 restore floor already rejects the year 2000 a
cut write leaves.

A time outside 2000-2099 is now not written for every chip,
rv3028-eeprom-config included, and the chip keeps the time it has. The
RV3028 retry stops if its run-on time leaves the range.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Local review: the rv3028-eeprom-config text ("written on each sync")
and the header's file summary still said every sync is written back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI lite review requested due to automatic review settings October 7, 2026 14:38
@coderabbitai

coderabbitai Bot commented Oct 7, 2026

Copy link
Copy Markdown

Important

  • 🔍 Trigger review

This repository does not receive automatic reviews because it has fewer than 10 stars.

⚙️ Run configuration
  • Configuration used: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 61fefc26-719e-4d3a-8244-669037eac9db
  • Autopilot · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Unresolved RV3028 retry, stale-time invalidation, and protocol implementation issues block approval.

Review effort: Lite
Findings: 3 Medium severity

Open (3)
What changed in this PR

Restricts RTC persistence to years 2000–2099 and updates related documentation.

Changes:

  • Adds year-range validation for RTC writes.
  • Updates configuration, API, binding, and architecture documentation.
  • RV3028 retry cancellation and A0h invalidation handling remain unresolved.
File Summary
zephcore/​Kconfig Documents the supported RTC range.
zephcore/​dts/​bindings/​rtc/​zephcore,rtc-i2c.yaml Documents RTC persistence behavior; A0h protocol remains incomplete.
zephcore/​adapters/​clock/​ZephyrRTCDiscover.h Updates the RTC save contract.
zephcore/​adapters/​clock/​ZephyrRTCDiscover.c Enforces the year range; retry and invalidation handling need changes.
docs/​ARCHITECTURE.md Documents range-limited RTC persistence.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +686 to +688
if (!rtc_time_block(d, epoch, blk)) {
LOG_WRN("RTC %s: time outside 2000-2099 not written", d->name);
return;
Comment on lines +686 to +689
if (!rtc_time_block(d, epoch, blk)) {
LOG_WRN("RTC %s: time outside 2000-2099 not written", d->name);
return;
}
Comment on lines +85 to +88
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
@ptr727

ptr727 commented Oct 8, 2026

Copy link
Copy Markdown
Owner Author

Upstream merged the squashed version as liquidraver#105. Closing this iteration PR unmerged, as the upstream workflow does.

@ptr727 ptr727 closed this Oct 8, 2026
@ptr727
ptr727 deleted the work/rtc-year-range branch October 8, 2026 20:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants