mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-10-06 03:27:23 +00:00
touch: beta_46 — control-center redesign, Do Not Disturb, contact safety + board fixes
- Contact-loss fix (microSD devices): atomic temp+swap saveContacts, unified robust boot SD-mount ladder, and a storage-truth line in the Store-on-SD setting. - Heltec V4-R8: route MISO for the shared FSPI bus so the microSD mounts; wake-from-sleep freeze fixed (panel sleep goes through LovyanGFX's own bus, not the HSPI shim). - Do Not Disturb (originally PR #156 by Tesso Codemonkey / @codemonkeybr): scheduled sound-silencing window in Settings > Sound + a status-bar bell. - Control-center redesign: round icon-only chips that spread to fill each row (T-Deck 2x4, V4 portrait 2 rows), frosted-glass panel, real lock glyph + dynamic bell/bell-slash DND chip + keyboard icon+word chip (new cc_icons_16 FontAwesome font), per-chip confirmation toasts, press-grow clip fix, and a V4-portrait status-bar BLE/clock overlap fix. - LilyGo T-Pager: map tile cache falls back to the microSD under the launcher (fixes the "storage error / reflash the tiles partition" dead-end). Co-Authored-By: Tesso Codemonkey <798026+codemonkeybr@users.noreply.github.com> Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Tesso Codemonkey
Claude Opus 4.8
parent
36e49d4d9e
commit
041dd60b8d
+52
-4
@@ -420,6 +420,23 @@ bool DataStore::savePrefs(const NodePrefs& _prefs, double node_lat, double node_
|
||||
}
|
||||
|
||||
void DataStore::loadContacts(DataStoreHost* host) {
|
||||
#if defined(ESP32)
|
||||
// Recover an atomic-save swap interrupted by power loss: if the live file is gone but the
|
||||
// fully-written temp survives, adopt it. A temp alongside an intact live file is a stale
|
||||
// leftover (save crashed after writing temp but before the swap) — keep live, drop temp.
|
||||
{
|
||||
FILESYSTEM* cfs = _getContactsChannelsFS();
|
||||
char live[80], tmp[80];
|
||||
if (_root[0]) { snprintf(live, sizeof live, "%s/contacts3", _root);
|
||||
snprintf(tmp, sizeof tmp, "%s/contacts3.tmp", _root); }
|
||||
else { strncpy(live, "/contacts3", sizeof live);
|
||||
strncpy(tmp, "/contacts3.tmp", sizeof tmp); }
|
||||
if (cfs->exists(tmp)) {
|
||||
if (!cfs->exists(live)) cfs->rename(tmp, live); // interrupted swap -> recover the temp
|
||||
else cfs->remove(tmp); // stale temp -> the live file wins
|
||||
}
|
||||
}
|
||||
#endif
|
||||
File file = openRead(_getContactsChannelsFS(), "/contacts3");
|
||||
if (file) {
|
||||
bool full = false;
|
||||
@@ -462,8 +479,21 @@ void DataStore::saveContacts(DataStoreHost* host, bool (*filter)(const ContactIn
|
||||
// (FAT has no such GC); it matters most for card-less SPIFFS devices.
|
||||
WdtHeavyGuard _wdt;
|
||||
#endif
|
||||
File file = openWrite(_getContactsChannelsFS(), "/contacts3");
|
||||
#if defined(ESP32)
|
||||
// Write to a TEMP file and swap it in only after it is FULLY written, so a partial
|
||||
// write — a multi-second SPIFFS GC stall or an SD hiccup mid-save — can never truncate
|
||||
// the operator's live contact list. Without this, openWrite("/contacts3") truncates the
|
||||
// real file up front, so any failed write permanently destroyed the list (the "lost all
|
||||
// my repeaters overnight" report). Other platforms keep the direct write (LittleFS, and
|
||||
// untested here). The swap + boot-recovery live after the write loop below.
|
||||
const char* kContactsWriteTarget = "/contacts3.tmp";
|
||||
#else
|
||||
const char* kContactsWriteTarget = "/contacts3";
|
||||
#endif
|
||||
File file = openWrite(_getContactsChannelsFS(), kContactsWriteTarget);
|
||||
bool wrote_ok = false; // true only if every record reached the file
|
||||
if (file) {
|
||||
bool ok = true; // cleared on any short write (partial file)
|
||||
uint32_t idx = 0;
|
||||
ContactInfo c;
|
||||
uint8_t unused = 0;
|
||||
@@ -478,7 +508,6 @@ void DataStore::saveContacts(DataStoreHost* host, bool (*filter)(const ContactIn
|
||||
uint8_t* buf = (uint8_t*)malloc(REC * CHUNK_RECS);
|
||||
if (buf) {
|
||||
size_t fill = 0;
|
||||
bool ok = true;
|
||||
while (ok && host->getContactForSave(idx, c)) {
|
||||
if (filter && !filter(c)) {
|
||||
idx++; // advance to next contact
|
||||
@@ -504,7 +533,7 @@ void DataStore::saveContacts(DataStoreHost* host, bool (*filter)(const ContactIn
|
||||
}
|
||||
idx++; // advance to next contact
|
||||
}
|
||||
if (ok && fill > 0) file.write(buf, fill);
|
||||
if (ok && fill > 0) ok = (file.write(buf, fill) == fill);
|
||||
free(buf);
|
||||
} else {
|
||||
while (host->getContactForSave(idx, c)) {
|
||||
@@ -525,13 +554,32 @@ void DataStore::saveContacts(DataStoreHost* host, bool (*filter)(const ContactIn
|
||||
success = success && (file.write((uint8_t *)&c.gps_lat, 4) == 4);
|
||||
success = success && (file.write((uint8_t *)&c.gps_lon, 4) == 4);
|
||||
|
||||
if (!success) break; // write failed
|
||||
if (!success) { ok = false; break; } // write failed -> keep the live file
|
||||
|
||||
idx++; // advance to next contact
|
||||
}
|
||||
}
|
||||
file.close();
|
||||
wrote_ok = ok;
|
||||
}
|
||||
#if defined(ESP32)
|
||||
// Commit the temp only if it was written IN FULL; otherwise keep the existing live list.
|
||||
// (_rp uses one shared buffer, so build both paths explicitly to avoid clobbering it.)
|
||||
{
|
||||
FILESYSTEM* cfs = _getContactsChannelsFS();
|
||||
char live[80], tmp[80];
|
||||
if (_root[0]) { snprintf(live, sizeof live, "%s/contacts3", _root);
|
||||
snprintf(tmp, sizeof tmp, "%s/contacts3.tmp", _root); }
|
||||
else { strncpy(live, "/contacts3", sizeof live);
|
||||
strncpy(tmp, "/contacts3.tmp", sizeof tmp); }
|
||||
if (wrote_ok) {
|
||||
cfs->remove(live); // FAT/SPIFFS rename won't overwrite an existing target
|
||||
cfs->rename(tmp, live); // if this rename fails, loadContacts recovers the temp at next boot
|
||||
} else {
|
||||
cfs->remove(tmp); // discard the partial temp; the live contact list is untouched
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void DataStore::loadChannels(DataStoreHost* host) {
|
||||
|
||||
Reference in New Issue
Block a user