jrote1 is fitting a battery-backed DS3231 to the T-Deck's I2C bus so the device keeps time across a full power-off without needing GPS or Wi-Fi. The RTC adapter already had the hard parts, refusing an untrustworthy read and revalidating every write, so this teaches it a third chip rather than adding a second path. Three things differ from the soldered PCF parts and all three are handled by normalising into the existing decoder rather than duplicating its rules: - It lives at 0x68 rather than 0x51. That is also what makes it safe to add: it cannot be mistaken for either chip an existing board carries. - Day-of-week and day-of-month are swapped in its calendar block. - It reports "my time is not trustworthy" as OSF in a status register instead of in bit 7 of seconds, so that bit is folded into the one the decoder already refuses on. A module whose backup cell went flat is therefore rejected the same way a powered-off M9 is, rather than having its frozen calendar believed. 0x68 is a busy address, so identification requires a positive DS3231 trait rather than an ACK: its temperature register pair, whose low byte is a quarter degree in the top two bits and zero elsewhere, with a high byte in a range a working chip could be at. A module that has never been set by us can also arrive in 12-hour mode, which is converted rather than decoded as if it were 24-hour. Transparent when no module is fitted, which is nearly every T-Deck: reads come from the software clock, writes stop there, and the probe logs that nothing answered. CAP_HARDWARE_RTC stays 0 for the board, since this is an aftermarket addition rather than something a T-Deck has, so the cold-boot network time sync stays on offer for everyone else. Unverified on hardware: neither of us has the module wired yet. The host tests for the shared decoder still pass. Built on all nine S3 envs and both ESP32-P4 targets. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
70 lines
2.6 KiB
C++
70 lines
2.6 KiB
C++
#include <Arduino.h>
|
|
#include "target.h"
|
|
#include <helpers/HardwareRtcClock.h>
|
|
|
|
TDeckBoard board;
|
|
|
|
#if defined(P_LORA_SCLK)
|
|
static SPIClass spi;
|
|
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY, spi);
|
|
#else
|
|
RADIO_CLASS radio = new Module(P_LORA_NSS, P_LORA_DIO_1, P_LORA_RESET, P_LORA_BUSY);
|
|
#endif
|
|
|
|
WRAPPER_CLASS radio_driver(radio, board);
|
|
|
|
SPIClass* tdeckSharedSPI() {
|
|
#if defined(P_LORA_SCLK)
|
|
return &spi; // already begun (SCLK/MISO/MOSI) by radio.std_init
|
|
#else
|
|
return nullptr;
|
|
#endif
|
|
}
|
|
|
|
ESP32RTCClock fallback_clock;
|
|
// The T-Deck ships with no battery-backed clock, but a DS3231 module on the I2C
|
|
// bus is a common self-fit (#378). The adapter is transparent when nothing is
|
|
// there: reads come from the software clock and writes stop at it, so a board
|
|
// without the module behaves exactly as before.
|
|
HardwareRtcClock hw_rtc(fallback_clock);
|
|
ClockFloorRTC rtc_clock(hw_rtc);
|
|
MicroNMEALocationProvider gps(Serial1, &rtc_clock);
|
|
EnvironmentSensorManager sensors(gps);
|
|
|
|
#ifdef DISPLAY_CLASS
|
|
DISPLAY_CLASS display;
|
|
MomentaryButton user_btn(PIN_USER_BTN, 1000, true);
|
|
#endif
|
|
|
|
bool radio_init() {
|
|
fallback_clock.begin();
|
|
Wire.begin(18, 8);
|
|
// A DS3231 fitted to this bus, if there is one. This is NOT the generic
|
|
// address probe the comment below warns about: it is a declared chip type at
|
|
// its own address with a positive identity proof, and a bus with nothing at
|
|
// 0x68 simply logs and carries on. CAP_HARDWARE_RTC stays 0 for the board,
|
|
// since the module is an aftermarket addition rather than something a T-Deck
|
|
// has, which keeps the cold-boot network time sync on offer for everyone else.
|
|
hw_rtc.begin(Wire, HardwareRtcClock::Chip::DS3231);
|
|
rtc_clock.noteHardwareClock(hw_rtc.present());
|
|
if (hw_rtc.adopted()) rtc_clock.noteHardwareTime();
|
|
// NO generic rtc_clock.begin(Wire) here (issue #383). This board has no declared
|
|
// battery-backed clock, and the call was doubly wrong: it ran BEFORE the bus
|
|
// was even begun, so "the probe found nothing" was never evidence of anything.
|
|
// A board either drives a documented chip through HardwareRtcClock (see the
|
|
// Pager and the M9) or has none — "the generic probe happened to be quiet" is
|
|
// not a capability test. CAP_HARDWARE_RTC is 0 here, which is what makes the
|
|
// opt-in cold-boot network time sync worth offering on this board.
|
|
|
|
#if defined(P_LORA_SCLK)
|
|
return radio.std_init(&spi);
|
|
#else
|
|
return radio.std_init();
|
|
#endif
|
|
}
|
|
|
|
mesh::LocalIdentity radio_new_identity() {
|
|
RadioNoiseListener rng(radio);
|
|
return mesh::LocalIdentity(&rng); // create new random identity
|
|
}
|