implementing low battery brownout protection to prevent contacts file corruption caused by low voltage reboot loop; board goes to sleep at 2800mv

This commit is contained in:
pelgraine
2026-03-01 23:28:49 +11:00
parent 4646fd6bd9
commit 4bb721e060
5 changed files with 61 additions and 4 deletions
+32
View File
@@ -303,6 +303,38 @@ void DataStore::loadContacts(DataStoreHost* host) {
File file = openRead(fs, "/contacts3");
if (file) {
// --- Truncation guard ---
// If the file is smaller than one full contact record (152 bytes),
// it was truncated by a crash/brown-out. Discard it and try the
// .tmp backup if available.
size_t fsize = file.size();
if (fsize > 0 && fsize < 152) {
Serial.printf("DataStore: contacts3 truncated (%d bytes < 152), discarding\n", (int)fsize);
file.close();
fs->remove("/contacts3");
if (fs->exists("/contacts3.tmp")) {
File tmp = openRead(fs, "/contacts3.tmp");
if (tmp && tmp.size() >= 152) {
Serial.println("DataStore: recovering from .tmp after truncation");
tmp.close();
fs->rename("/contacts3.tmp", "/contacts3");
file = openRead(fs, "/contacts3");
if (!file) return; // give up
} else {
if (tmp) tmp.close();
Serial.println("DataStore: no valid contacts backup — starting fresh");
return;
}
} else {
Serial.println("DataStore: no .tmp backup — starting fresh");
return;
}
} else if (fsize == 0) {
// Empty file — nothing to load
file.close();
return;
}
bool full = false;
while (!full) {
ContactInfo c;
+7 -4
View File
@@ -1289,10 +1289,11 @@ if (curr) curr->poll();
if (millis() > next_batt_chck) {
uint16_t milliVolts = getBattMilliVolts();
if (milliVolts > 0 && milliVolts < AUTO_SHUTDOWN_MILLIVOLTS) {
_low_batt_count++;
if (_low_batt_count >= 3) { // 3 consecutive low readings (~24s) to avoid transient sags
// show low battery shutdown alert
// we should only do this for eink displays, which will persist after power loss
#if defined(THINKNODE_M1) || defined(LILYGO_TECHO)
// show low battery shutdown alert on e-ink (persists after power loss)
#if defined(THINKNODE_M1) || defined(LILYGO_TECHO) || defined(LilyGo_TDeck_Pro)
if (_display != NULL) {
_display->startFrame();
_display->setTextSize(2);
@@ -1304,7 +1305,9 @@ if (curr) curr->poll();
#endif
shutdown();
}
} else {
_low_batt_count = 0;
}
next_batt_chck = millis() + 8000;
}
+1
View File
@@ -54,6 +54,7 @@ class UITask : public AbstractUITask {
unsigned long _alert_expiry;
int _msgcount;
unsigned long ui_started_at, next_batt_chck;
uint8_t _low_batt_count = 0; // Consecutive low-voltage readings for debounce
int next_backlight_btn_check = 0;
#ifdef PIN_STATUS_LED
int led_state = 0;