mirror of
https://github.com/pelgraine/Meck.git
synced 2026-05-07 22:04:49 +02:00
ui fixes including discover screen; clock fix
This commit is contained in:
@@ -614,6 +614,25 @@ MyMesh the_mesh(radio_driver, fast_rng, rtc_clock, tables, store
|
||||
return KEY_ENTER; // file list: open
|
||||
}
|
||||
|
||||
// Discovery screen: long press = rescan
|
||||
if (ui_task.isOnDiscoveryScreen()) {
|
||||
return 'f';
|
||||
}
|
||||
|
||||
// Contacts screen: long press = open repeater admin (if on a repeater contact)
|
||||
if (ui_task.isOnContactsScreen()) {
|
||||
ContactsScreen* cs = (ContactsScreen*)ui_task.getContactsScreen();
|
||||
if (cs) {
|
||||
int idx = cs->getSelectedContactIdx();
|
||||
ContactInfo ci;
|
||||
if (the_mesh.getContactByIdx(idx, ci) && ci.type == ADV_TYPE_REPEATER) {
|
||||
ui_task.gotoRepeaterAdmin(idx);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return KEY_ENTER; // non-repeater: normal select
|
||||
}
|
||||
|
||||
// Default: enter/select (settings toggle, etc.)
|
||||
return KEY_ENTER;
|
||||
}
|
||||
@@ -959,9 +978,10 @@ void setup() {
|
||||
#endif
|
||||
|
||||
// Initialize GT911 touch (T5S3 E-Paper Pro)
|
||||
// Wire is already initialized by T5S3Board::begin(). The 4-arg begin() re-calls
|
||||
// Wire.begin() which logs "bus already initialized" — cosmetic only, not harmful.
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
gt911Touch.setPins(GT911_PIN_RST, GT911_PIN_INT);
|
||||
pinMode(GT911_PIN_INT, INPUT_PULLUP); // Ensure INT pin has pullup for clean transitions
|
||||
if (gt911Touch.begin(Wire, GT911_SLAVE_ADDRESS_L, GT911_PIN_SDA, GT911_PIN_SCL)) {
|
||||
gt911Ready = true;
|
||||
Serial.println("setup() - GT911 touch initialized");
|
||||
@@ -970,8 +990,17 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
// SD card is already initialized (early init above).
|
||||
// RTC diagnostic — verify the auto-discovered RTC is working
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
{
|
||||
uint32_t rtcTime = rtc_clock.getCurrentTime();
|
||||
Serial.printf("setup() - RTC time: %lu (valid=%s)\n", rtcTime,
|
||||
rtcTime > 1700000000 ? "YES" : "NO");
|
||||
if (rtcTime < 1700000000) {
|
||||
Serial.println("setup() - RTC has no valid time (will be set by companion app)");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// Now set up SD-dependent features: message history + text reader.
|
||||
// ---------------------------------------------------------------------------
|
||||
#if defined(LilyGo_TDeck_Pro) && defined(HAS_SDCARD)
|
||||
|
||||
@@ -957,7 +957,7 @@ public:
|
||||
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.setTextSize(0);
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Select Boot: Home");
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Select boot: home");
|
||||
#else
|
||||
// Left side: abbreviated controls
|
||||
if (_replySelectMode) {
|
||||
|
||||
@@ -303,7 +303,7 @@ public:
|
||||
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.setTextSize(0);
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Select Boot: Home");
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Select boot: home");
|
||||
#else
|
||||
// Left: Q:Bk
|
||||
display.setCursor(0, footerY);
|
||||
|
||||
@@ -79,7 +79,11 @@ public:
|
||||
display.print(active ? "Listening for adverts..." : "No nodes found");
|
||||
if (!active) {
|
||||
display.setCursor(4, 38);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.print("Long press: Rescan");
|
||||
#else
|
||||
display.print("F: Scan again Q: Back");
|
||||
#endif
|
||||
}
|
||||
} else {
|
||||
// Center visible window around selected item
|
||||
@@ -158,6 +162,17 @@ public:
|
||||
display.setColor(DisplayDriver::YELLOW);
|
||||
|
||||
display.setCursor(0, footerY);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.print("Swipe:Scroll");
|
||||
|
||||
const char* mid = "Tap:Add";
|
||||
display.setCursor((display.width() - display.getTextWidth(mid)) / 2, footerY);
|
||||
display.print(mid);
|
||||
|
||||
const char* right = "Hold:Rescan";
|
||||
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
|
||||
display.print(right);
|
||||
#else
|
||||
display.print("Q:Back");
|
||||
|
||||
const char* mid = "Ent:Add";
|
||||
@@ -167,6 +182,7 @@ public:
|
||||
const char* right = "F:Rescan";
|
||||
display.setCursor(display.width() - display.getTextWidth(right) - 2, footerY);
|
||||
display.print(right);
|
||||
#endif
|
||||
|
||||
// Faster refresh while actively scanning
|
||||
return active ? 1000 : 5000;
|
||||
|
||||
@@ -1008,17 +1008,17 @@ public:
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.setTextSize(0);
|
||||
if (_editMode == EDIT_NONE) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Select Hold: Edit Boot: Home");
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Select Hold: Edit boot: home");
|
||||
} else if (_editMode == EDIT_NUMBER) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe Up/Down: Adjust Tap: OK Boot: Cancel");
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe Up/Down: Adjust Tap: OK boot: cancel");
|
||||
} else if (_editMode == EDIT_PICKER) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe Left/Right: Choose Tap: OK");
|
||||
} else if (_editMode == EDIT_CONFIRM) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Tap: Confirm Boot: Cancel");
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Tap: Confirm boot: cancel");
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
} else if (_editMode == EDIT_WIFI) {
|
||||
if (_wifiPhase == WIFI_PHASE_SELECT) {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Pick Tap: Select Boot: Back");
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Pick Tap: Select boot: back");
|
||||
} else {
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Please wait...");
|
||||
}
|
||||
|
||||
@@ -926,7 +926,7 @@ private:
|
||||
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.setTextSize(0);
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Open Boot: Home");
|
||||
display.drawTextCentered(display.width() / 2, footerY, "Swipe: Scroll Tap: Open boot: home");
|
||||
#else
|
||||
display.setCursor(0, footerY);
|
||||
display.print("Q:Back W/S:Nav");
|
||||
@@ -960,6 +960,7 @@ private:
|
||||
display.setCursor(0, y);
|
||||
// Print line with UTF-8 decoding: multi-byte sequences are decoded
|
||||
// to Unicode codepoints, then mapped to CP437 for the built-in font.
|
||||
bool lineHasContent = false;
|
||||
char charStr[2] = {0, 0};
|
||||
int j = pos;
|
||||
while (j < wrap.lineEnd && j < _pageBufLen) {
|
||||
@@ -975,6 +976,7 @@ private:
|
||||
// Plain ASCII — print directly
|
||||
charStr[0] = (char)b;
|
||||
display.print(charStr);
|
||||
lineHasContent = true;
|
||||
j++;
|
||||
} else if (b >= 0xC0) {
|
||||
// UTF-8 lead byte — decode full sequence and map to CP437
|
||||
@@ -984,6 +986,7 @@ private:
|
||||
if (glyph) {
|
||||
charStr[0] = (char)glyph;
|
||||
display.print(charStr);
|
||||
lineHasContent = true;
|
||||
}
|
||||
// If unmappable (glyph==0), just skip the character
|
||||
} else {
|
||||
@@ -991,11 +994,20 @@ private:
|
||||
// Treat as CP437 pass-through (e.g. from EPUB numeric entity decoding).
|
||||
charStr[0] = (char)b;
|
||||
display.print(charStr);
|
||||
lineHasContent = true;
|
||||
j++;
|
||||
}
|
||||
}
|
||||
|
||||
y += _lineHeight;
|
||||
// Blank lines (paragraph breaks) get reduced height for compact layout.
|
||||
// Full _lineHeight for blank lines wastes too much space — on T5S3 each
|
||||
// blank line is ~34px, making paragraph gaps 7-8× the normal line spacing.
|
||||
// Using 40% height gives a visible paragraph break without wasting space.
|
||||
if (lineHasContent) {
|
||||
y += _lineHeight;
|
||||
} else {
|
||||
y += max(2, _lineHeight * 2 / 5); // ~40% height for blank lines
|
||||
}
|
||||
lineCount++;
|
||||
pos = wrap.nextStart;
|
||||
if (pos >= _pageBufLen) break;
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
#if UI_HAS_JOYSTICK
|
||||
#define PRESS_LABEL "press Enter"
|
||||
#elif defined(LilyGo_T5S3_EPaper_Pro)
|
||||
#define PRESS_LABEL "hold Boot btn"
|
||||
#define PRESS_LABEL "hold boot btn"
|
||||
#else
|
||||
#define PRESS_LABEL "long press"
|
||||
#endif
|
||||
@@ -159,9 +159,11 @@ void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts,
|
||||
int totalWidth = iconWidth + 2 + 2 + textWidth + 2;
|
||||
int iconX = display.width() - totalWidth;
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
int iconY = 4; // Shift down to match header text offset
|
||||
int iconY = 6; // Align with FreeSans12pt text baseline
|
||||
int textY = 1; // Percentage text — setCursor adds +5 → baseline at (6)*scale_y
|
||||
#else
|
||||
int iconY = 0; // vertically align with node name text
|
||||
int iconY = 0; // vertically align with node name text
|
||||
int textY = iconY - 3; // offset up to vertically center with icon
|
||||
#endif
|
||||
|
||||
if (outIconX) *outIconX = iconX;
|
||||
@@ -179,7 +181,6 @@ void renderBatteryIndicator(DisplayDriver& display, uint16_t batteryMilliVolts,
|
||||
// draw percentage text after the battery cap, offset upward to center with icon
|
||||
// (setCursor adds +5 internally for baseline, so compensate for the tiny font)
|
||||
int textX = iconX + iconWidth + 2 + 2; // after cap + gap
|
||||
int textY = iconY - 3; // offset up to vertically center with icon
|
||||
display.setCursor(textX, textY);
|
||||
display.print(pctStr);
|
||||
display.setTextSize(1); // restore default text size
|
||||
@@ -490,23 +491,39 @@ public:
|
||||
#ifdef BLE_PIN_CODE
|
||||
} else if (_page == HomePage::BLUETOOTH) {
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.drawXbm((display.width() - 32) / 2, 28,
|
||||
#else
|
||||
display.drawXbm((display.width() - 32) / 2, 18,
|
||||
#endif
|
||||
_task->isSerialEnabled() ? bluetooth_on : bluetooth_off,
|
||||
32, 32);
|
||||
if (_task->hasConnection()) {
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
display.setTextSize(1);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.drawTextCentered(display.width() / 2, 64, "< Connected >");
|
||||
#else
|
||||
display.drawTextCentered(display.width() / 2, 53, "< Connected >");
|
||||
#endif
|
||||
} else if (_task->isSerialEnabled() && the_mesh.getBLEPin() != 0) {
|
||||
display.setColor(DisplayDriver::RED);
|
||||
display.setTextSize(2);
|
||||
sprintf(tmp, "Pin:%d", the_mesh.getBLEPin());
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.drawTextCentered(display.width() / 2, 64, tmp);
|
||||
#else
|
||||
display.drawTextCentered(display.width() / 2, 53, tmp);
|
||||
#endif
|
||||
}
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
display.setTextSize(1);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.drawTextCentered(display.width() / 2, 80, "toggle: " PRESS_LABEL);
|
||||
#else
|
||||
display.drawTextCentered(display.width() / 2, 72, "toggle: " PRESS_LABEL);
|
||||
#endif
|
||||
#endif
|
||||
#ifdef MECK_WIFI_COMPANION
|
||||
} else if (_page == HomePage::WIFI_STATUS) {
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
@@ -547,8 +564,16 @@ public:
|
||||
#endif
|
||||
} else if (_page == HomePage::ADVERT) {
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.drawXbm((display.width() - 32) / 2, 28, advert_icon, 32, 32);
|
||||
#else
|
||||
display.drawXbm((display.width() - 32) / 2, 18, advert_icon, 32, 32);
|
||||
#endif
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.drawTextCentered(display.width() / 2, 64, "advert: " PRESS_LABEL);
|
||||
#else
|
||||
display.drawTextCentered(display.width() / 2, 64 - 11, "advert: " PRESS_LABEL);
|
||||
#endif
|
||||
#if ENV_INCLUDE_GPS == 1
|
||||
} else if (_page == HomePage::GPS) {
|
||||
extern GPSStreamCounter gpsStream;
|
||||
@@ -773,10 +798,21 @@ public:
|
||||
display.setColor(DisplayDriver::GREEN);
|
||||
display.setTextSize(1);
|
||||
if (_shutdown_init) {
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
board.setBacklight(false); // Turn off backlight on hibernate
|
||||
#endif
|
||||
display.drawTextCentered(display.width() / 2, 34, "hibernating...");
|
||||
} else {
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.drawXbm((display.width() - 32) / 2, 28, power_icon, 32, 32);
|
||||
#else
|
||||
display.drawXbm((display.width() - 32) / 2, 18, power_icon, 32, 32);
|
||||
#endif
|
||||
#if defined(LilyGo_T5S3_EPaper_Pro)
|
||||
display.drawTextCentered(display.width() / 2, 64, "hibernate:" PRESS_LABEL);
|
||||
#else
|
||||
display.drawTextCentered(display.width() / 2, 64 - 11, "hibernate:" PRESS_LABEL);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
return _editing_utc ? 700 : 5000; // match e-ink refresh cycle while editing UTC
|
||||
@@ -1490,7 +1526,7 @@ char UITask::handleTripleClick(char c) {
|
||||
if (board.isBacklightOn()) {
|
||||
board.setBacklight(false); // If already on, turn off
|
||||
} else {
|
||||
board.setBacklightBrightness(40);
|
||||
board.setBacklightBrightness(4);
|
||||
board.setBacklight(true);
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -0,0 +1,209 @@
|
||||
#pragma once
|
||||
// =============================================================================
|
||||
// PCF85063Clock — PCF8563/BM8563 RTC driver for T5S3 E-Paper Pro
|
||||
//
|
||||
// Time registers at 0x02–0x08 (PCF8563 layout):
|
||||
// 0x02 Seconds, 0x03 Minutes, 0x04 Hours,
|
||||
// 0x05 Days, 0x06 Weekdays, 0x07 Months, 0x08 Years
|
||||
// =============================================================================
|
||||
|
||||
#include <Arduino.h>
|
||||
#include <Wire.h>
|
||||
#include <MeshCore.h>
|
||||
|
||||
#define PCF8563_ADDR 0x51
|
||||
#define PCF8563_REG_SECONDS 0x02
|
||||
|
||||
// Reject timestamps outside 2024–2036 (blocks MeshCore contacts garbage)
|
||||
#define EPOCH_MIN_SANE 1704067200UL
|
||||
#define EPOCH_MAX_SANE 2082758400UL
|
||||
|
||||
class PCF85063Clock : public mesh::RTCClock {
|
||||
public:
|
||||
PCF85063Clock() : _wire(nullptr), _millis_offset(0),
|
||||
_has_hw_time(false), _time_set_this_session(false) {}
|
||||
|
||||
bool begin(TwoWire& wire) {
|
||||
_wire = &wire;
|
||||
|
||||
_wire->beginTransmission(PCF8563_ADDR);
|
||||
if (_wire->endTransmission() != 0) {
|
||||
Serial.println("[RTC] PCF8563 not found");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Repair any corrupted registers from prior wrong-offset writes
|
||||
repairRegisters();
|
||||
|
||||
uint32_t t = readHardwareTime();
|
||||
if (t > EPOCH_MIN_SANE && t < EPOCH_MAX_SANE) {
|
||||
_has_hw_time = true;
|
||||
_millis_offset = t - (millis() / 1000);
|
||||
Serial.printf("[RTC] PCF8563 OK, time=%lu\n", t);
|
||||
} else {
|
||||
_has_hw_time = false;
|
||||
Serial.printf("[RTC] PCF8563 no valid time (%lu), awaiting BLE sync\n", t);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32_t getCurrentTime() override {
|
||||
if (_time_set_this_session) {
|
||||
return _millis_offset + (millis() / 1000);
|
||||
}
|
||||
if (_has_hw_time && _wire) {
|
||||
uint32_t t = readHardwareTime();
|
||||
if (t > EPOCH_MIN_SANE && t < EPOCH_MAX_SANE) {
|
||||
_millis_offset = t - (millis() / 1000);
|
||||
return t;
|
||||
}
|
||||
_has_hw_time = false;
|
||||
}
|
||||
return _millis_offset + (millis() / 1000);
|
||||
}
|
||||
|
||||
void setCurrentTime(uint32_t time) override {
|
||||
if (time < EPOCH_MIN_SANE || time > EPOCH_MAX_SANE) {
|
||||
Serial.printf("[RTC] setCurrentTime(%lu) REJECTED\n", time);
|
||||
return;
|
||||
}
|
||||
_millis_offset = time - (millis() / 1000);
|
||||
_time_set_this_session = true;
|
||||
Serial.printf("[RTC] setCurrentTime(%lu) OK\n", time);
|
||||
if (_wire) writeHardwareTime(time);
|
||||
}
|
||||
|
||||
private:
|
||||
TwoWire* _wire;
|
||||
uint32_t _millis_offset;
|
||||
bool _has_hw_time;
|
||||
bool _time_set_this_session;
|
||||
|
||||
// ---- Register helpers ----
|
||||
void writeReg(uint8_t reg, uint8_t val) {
|
||||
_wire->beginTransmission(PCF8563_ADDR);
|
||||
_wire->write(reg);
|
||||
_wire->write(val);
|
||||
_wire->endTransmission();
|
||||
}
|
||||
|
||||
uint8_t readReg(uint8_t reg) {
|
||||
_wire->beginTransmission(PCF8563_ADDR);
|
||||
_wire->write(reg);
|
||||
if (_wire->endTransmission(false) != 0) return 0xFF;
|
||||
if (_wire->requestFrom((uint8_t)PCF8563_ADDR, (uint8_t)1) != 1) return 0xFF;
|
||||
return _wire->read();
|
||||
}
|
||||
|
||||
// ---- Fix registers corrupted by prior PCF85063A-mode writes ----
|
||||
void repairRegisters() {
|
||||
uint8_t hours = readReg(0x04) & 0x3F;
|
||||
if (bcd2dec(hours) > 23) {
|
||||
Serial.printf("[RTC] Repairing hours (0x%02X→0x00)\n", hours);
|
||||
writeReg(0x04, 0x00);
|
||||
}
|
||||
uint8_t days = readReg(0x05) & 0x3F;
|
||||
if (bcd2dec(days) == 0 || bcd2dec(days) > 31) {
|
||||
Serial.printf("[RTC] Repairing days (0x%02X→0x01)\n", days);
|
||||
writeReg(0x05, 0x01);
|
||||
}
|
||||
uint8_t month = readReg(0x07) & 0x1F;
|
||||
if (bcd2dec(month) == 0 || bcd2dec(month) > 12) {
|
||||
Serial.printf("[RTC] Repairing month (0x%02X→0x01)\n", month);
|
||||
writeReg(0x07, 0x01);
|
||||
}
|
||||
}
|
||||
|
||||
// ---- BCD ----
|
||||
static uint8_t bcd2dec(uint8_t bcd) { return ((bcd >> 4) * 10) + (bcd & 0x0F); }
|
||||
static uint8_t dec2bcd(uint8_t dec) { return ((dec / 10) << 4) | (dec % 10); }
|
||||
|
||||
// ---- Date helpers ----
|
||||
static bool isLeap(int y) { return (y%4==0 && y%100!=0) || y%400==0; }
|
||||
static int daysInMonth(int m, int y) {
|
||||
static const uint8_t d[] = {31,28,31,30,31,30,31,31,30,31,30,31};
|
||||
return (m==2 && isLeap(y)) ? 29 : d[m-1];
|
||||
}
|
||||
|
||||
static uint32_t toEpoch(int yr, int mo, int dy, int h, int mi, int s) {
|
||||
uint32_t days = 0;
|
||||
for (int y = 1970; y < yr; y++) days += isLeap(y) ? 366 : 365;
|
||||
for (int m = 1; m < mo; m++) days += daysInMonth(m, yr);
|
||||
days += (dy - 1);
|
||||
return days * 86400UL + h * 3600UL + mi * 60UL + s;
|
||||
}
|
||||
|
||||
static void fromEpoch(uint32_t ep, int& yr, int& mo, int& dy, int& h, int& mi, int& s) {
|
||||
s = ep % 60; ep /= 60;
|
||||
mi = ep % 60; ep /= 60;
|
||||
h = ep % 24; ep /= 24;
|
||||
yr = 1970;
|
||||
while (true) { int d = isLeap(yr)?366:365; if (ep<(uint32_t)d) break; ep-=d; yr++; }
|
||||
mo = 1;
|
||||
while (true) { int d = daysInMonth(mo,yr); if (ep<(uint32_t)d) break; ep-=d; mo++; }
|
||||
dy = ep + 1;
|
||||
}
|
||||
|
||||
// ---- Read time (burst from 0x02) ----
|
||||
uint32_t readHardwareTime() {
|
||||
_wire->beginTransmission(PCF8563_ADDR);
|
||||
_wire->write(PCF8563_REG_SECONDS);
|
||||
if (_wire->endTransmission(false) != 0) return 0;
|
||||
if (_wire->requestFrom((uint8_t)PCF8563_ADDR, (uint8_t)7) != 7) return 0;
|
||||
|
||||
uint8_t raw[7];
|
||||
for (int i = 0; i < 7; i++) raw[i] = _wire->read();
|
||||
|
||||
if (raw[0] & 0x80) {
|
||||
Serial.println("[RTC] OS flag set — clearing");
|
||||
writeReg(PCF8563_REG_SECONDS, raw[0] & 0x7F);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int second = bcd2dec(raw[0] & 0x7F);
|
||||
int minute = bcd2dec(raw[1] & 0x7F);
|
||||
int hour = bcd2dec(raw[2] & 0x3F);
|
||||
int day = bcd2dec(raw[3] & 0x3F);
|
||||
int month = bcd2dec(raw[5] & 0x1F);
|
||||
int year = 2000 + bcd2dec(raw[6]);
|
||||
|
||||
if (month<1 || month>12 || day<1 || day>31 || hour>23 || minute>59 || second>59)
|
||||
return 0;
|
||||
|
||||
return toEpoch(year, month, day, hour, minute, second);
|
||||
}
|
||||
|
||||
// ---- Write time (burst to 0x02) ----
|
||||
void writeHardwareTime(uint32_t epoch) {
|
||||
int year, month, day, hour, minute, second;
|
||||
fromEpoch(epoch, year, month, day, hour, minute, second);
|
||||
|
||||
static const int dow[] = {0,3,2,5,0,3,5,1,4,6,2,4};
|
||||
int y = year; if (month < 3) y--;
|
||||
int wday = (y + y/4 - y/100 + y/400 + dow[month-1] + day) % 7;
|
||||
int yr = year - 2000;
|
||||
|
||||
// Stop clock
|
||||
writeReg(0x00, 0x20);
|
||||
delay(5);
|
||||
|
||||
// Burst write
|
||||
_wire->beginTransmission(PCF8563_ADDR);
|
||||
_wire->write(PCF8563_REG_SECONDS);
|
||||
_wire->write(dec2bcd(second) & 0x7F);
|
||||
_wire->write(dec2bcd(minute));
|
||||
_wire->write(dec2bcd(hour));
|
||||
_wire->write(dec2bcd(day));
|
||||
_wire->write(dec2bcd(wday));
|
||||
_wire->write(dec2bcd(month));
|
||||
_wire->write(dec2bcd(yr));
|
||||
_wire->endTransmission();
|
||||
delay(5);
|
||||
|
||||
// Restart clock
|
||||
writeReg(0x00, 0x00);
|
||||
|
||||
Serial.printf("[RTC] Wrote %04d-%02d-%02d %02d:%02d:%02d\n",
|
||||
year, month, day, hour, minute, second);
|
||||
}
|
||||
};
|
||||
@@ -15,8 +15,7 @@ T5S3Board board;
|
||||
|
||||
WRAPPER_CLASS radio_driver(radio, board);
|
||||
|
||||
ESP32RTCClock fallback_clock;
|
||||
AutoDiscoverRTCClock rtc_clock(fallback_clock);
|
||||
PCF85063Clock rtc_clock;
|
||||
|
||||
// No GPS on H752-B
|
||||
#if HAS_GPS
|
||||
@@ -39,13 +38,10 @@ bool radio_init() {
|
||||
// NOTE: board.begin() is called by main.cpp setup() before radio_init()
|
||||
// I2C is already initialized there with correct pins
|
||||
|
||||
fallback_clock.begin();
|
||||
MESH_DEBUG_PRINTLN("radio_init() - fallback_clock started");
|
||||
|
||||
// Use existing Wire for RTC discovery
|
||||
// AutoDiscoverRTCClock will find PCF85063 at 0x51 if present
|
||||
// PCF85063 hardware RTC — reads correct registers (0x04–0x0A)
|
||||
// Unlike AutoDiscoverRTCClock which uses RTClib's PCF8563 driver (wrong registers)
|
||||
rtc_clock.begin(Wire);
|
||||
MESH_DEBUG_PRINTLN("radio_init() - rtc_clock started");
|
||||
MESH_DEBUG_PRINTLN("radio_init() - PCF85063 RTC started");
|
||||
|
||||
#if defined(P_LORA_SCLK)
|
||||
MESH_DEBUG_PRINTLN("radio_init() - initializing LoRa SPI (SCLK=%d, MISO=%d, MOSI=%d, NSS=%d)...",
|
||||
@@ -92,4 +88,4 @@ mesh::LocalIdentity radio_new_identity() {
|
||||
|
||||
void radio_reset_agc() {
|
||||
radio.setRxBoostedGainMode(true);
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <helpers/radiolib/RadioLibWrappers.h>
|
||||
#include <helpers/radiolib/CustomSX1262Wrapper.h>
|
||||
#include <T5S3Board.h>
|
||||
#include <helpers/AutoDiscoverRTCClock.h>
|
||||
#include "PCF85063Clock.h"
|
||||
|
||||
// Display support — FastEPDDisplay for parallel e-ink (not GxEPD2)
|
||||
#ifdef DISPLAY_CLASS
|
||||
@@ -28,7 +28,7 @@
|
||||
|
||||
extern T5S3Board board;
|
||||
extern WRAPPER_CLASS radio_driver;
|
||||
extern AutoDiscoverRTCClock rtc_clock;
|
||||
extern PCF85063Clock rtc_clock;
|
||||
|
||||
#if HAS_GPS
|
||||
extern GPSStreamCounter gpsStream;
|
||||
@@ -47,4 +47,4 @@ uint32_t radio_get_rng_seed();
|
||||
void radio_set_params(float freq, float bw, uint8_t sf, uint8_t cr);
|
||||
void radio_set_tx_power(uint8_t dbm);
|
||||
mesh::LocalIdentity radio_new_identity();
|
||||
void radio_reset_agc();
|
||||
void radio_reset_agc();
|
||||
Reference in New Issue
Block a user