mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-09-26 13:48:01 +00:00
tanmatsu: move identity + prefs to the SD card; open-probe the prefs load chain
The P4's internal FFat 'locfd' has a broken FAT metadata layer: open/ read/write work but f_stat/exists()/size() return garbage - and WHICH garbage shifts with the build. At -Og the exists()-gated identity and NodePrefs loads worked by luck; the -Os switch flipped the lie and the device booted with a fresh identity and default name, and profile changes never survived a reboot (the loads failed, not the saves). Chat history was unaffected because it already lives on SD_MMC. - DataStore::useSdMmcStorage(): full-store adoption of the card (/meshcomod root, identity store included), mirroring the T-Deck's useSdStorage(). The old card-root contacts3/channels2/adv_blobs from the secondary-FS era are renamed under /meshcomod. - Tanmatsu boot: one-time rescue of identity + prefs off FFat by OPEN and READ probing (never exists()/size() on that FS), then adopt the card. FFat remains the no-card fallback only. - DataStore::loadPrefs() probes candidates by opening and reading a byte instead of exists() - truthful on the P4, identical elsewhere. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
d20241627c
commit
76cd025bf5
+49
-3
@@ -5,6 +5,9 @@
|
||||
#include <SD.h>
|
||||
#include "helpers/esp32/WdtHeavyGuard.h" // suspend core-0 idle WDT during the (SPIFFS-GC-prone) contact write
|
||||
#endif
|
||||
#if defined(HAS_TANMATSU)
|
||||
#include <SD_MMC.h>
|
||||
#endif
|
||||
|
||||
#if defined(EXTRAFS) || defined(QSPIFLASH)
|
||||
#define MAX_BLOBRECS 100
|
||||
@@ -240,16 +243,29 @@ bool DataStore::saveMainIdentity(const mesh::LocalIdentity &identity) {
|
||||
}
|
||||
|
||||
void DataStore::loadPrefs(NodePrefs& prefs, double& node_lat, double& node_lon) {
|
||||
if (_fs->exists(_rp("/new_prefs"))) {
|
||||
// Probe by OPENING, never exists(): on the Tanmatsu's internal FFat the FAT
|
||||
// metadata layer lies (f_stat garbage — the tile cache hit the same thing),
|
||||
// and WHICH lie you get shifts with the build (the -Og to -Os switch turned
|
||||
// "loaded fine by luck" into "no prefs found -> default name every boot").
|
||||
// open()+read is truthful there, and identical in behavior everywhere else.
|
||||
auto probe = [this](const char* nm) -> bool {
|
||||
File f = openRead(nm);
|
||||
if (!f) return false;
|
||||
uint8_t b;
|
||||
const bool ok = f.read(&b, 1) == 1; // size() lies on the P4's FFat too — actually read
|
||||
f.close();
|
||||
return ok;
|
||||
};
|
||||
if (probe("/new_prefs")) {
|
||||
loadPrefsInt("/new_prefs", prefs, node_lat, node_lon); // new filename
|
||||
} else if (_fs->exists(_rp("/new_prefs.tmp"))) {
|
||||
} else if (probe("/new_prefs.tmp")) {
|
||||
// Main file gone but a staged copy exists: a reboot landed between the temp
|
||||
// write and the swap (or the swap was torn). Recover from it — this is the
|
||||
// "device booted with the default name once" failure mode.
|
||||
MESH_DEBUG_PRINTLN("DataStore: /new_prefs missing, recovering from .tmp");
|
||||
loadPrefsInt("/new_prefs.tmp", prefs, node_lat, node_lon);
|
||||
savePrefs(prefs, node_lat, node_lon); // re-establish the main file
|
||||
} else if (_fs->exists(_rp("/node_prefs"))) {
|
||||
} else if (probe("/node_prefs")) {
|
||||
loadPrefsInt("/node_prefs", prefs, node_lat, node_lon);
|
||||
savePrefs(prefs, node_lat, node_lon); // save to new filename
|
||||
_fs->remove(_rp("/node_prefs")); // remove old
|
||||
@@ -818,3 +834,33 @@ bool DataStore::useSdStorage() {
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(HAS_TANMATSU)
|
||||
// Tanmatsu: same full-store adoption as useSdStorage(), but on the SD_MMC slot.
|
||||
// The internal FFat 'locfd' has a broken FAT metadata layer (f_stat/exists lie —
|
||||
// see the tile-cache notes), and the exists()-gated identity + prefs loads that
|
||||
// "worked" at -Og read different garbage at -Os and came up empty: fresh node
|
||||
// identity, default name, profile changes gone every reboot. The card's FAT
|
||||
// metadata is truthful, so identity/prefs move there with everything else.
|
||||
// The caller migrates any FFat-resident files first (open()-probed, never
|
||||
// exists() on FFat).
|
||||
bool DataStore::useSdMmcStorage() {
|
||||
if (!SD_MMC.exists("/meshcomod")) SD_MMC.mkdir("/meshcomod");
|
||||
if (!SD_MMC.exists("/meshcomod/bl")) SD_MMC.mkdir("/meshcomod/bl");
|
||||
if (!SD_MMC.exists("/meshcomod/identity")) SD_MMC.mkdir("/meshcomod/identity");
|
||||
// The old secondary-FS layout kept contacts/channels/blobs at the CARD ROOT;
|
||||
// pull them under /meshcomod so the rooted store keeps reading them.
|
||||
static const char* k_move[] = { "/contacts3", "/channels2", "/adv_blobs" };
|
||||
for (const char* nm : k_move) {
|
||||
char dst[40];
|
||||
snprintf(dst, sizeof dst, "/meshcomod%s", nm);
|
||||
if (SD_MMC.exists(nm) && !SD_MMC.exists(dst)) SD_MMC.rename(nm, dst);
|
||||
}
|
||||
strncpy(_root, "/meshcomod", sizeof(_root) - 1);
|
||||
_root[sizeof(_root) - 1] = '\0';
|
||||
_fs = &SD_MMC;
|
||||
_fsExtra = nullptr;
|
||||
identity_store.use(SD_MMC, "/meshcomod/identity");
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -42,6 +42,12 @@ public:
|
||||
// contacts, channels, blobs). Call after the SD card is mounted. Returns false
|
||||
// if the dir can't be created. No-op on non-ESP32.
|
||||
bool useSdStorage();
|
||||
#endif
|
||||
#if defined(HAS_TANMATSU)
|
||||
// Full-store adoption of the SD_MMC card (Tanmatsu): identity + prefs move off
|
||||
// the broken-metadata internal FFat (its exists()/f_stat lie, which made the
|
||||
// gated loads come up empty). Caller migrates FFat-resident files first.
|
||||
bool useSdMmcStorage();
|
||||
#endif
|
||||
FILESYSTEM* getPrimaryFS() const { return _fs; }
|
||||
FILESYSTEM* getSecondaryFS() const { return _fsExtra; }
|
||||
|
||||
+37
-4
@@ -375,12 +375,45 @@ static void wadameshSetup() {
|
||||
printf("[storage] persistence disabled this boot (DataStore opens fail gracefully)\n");
|
||||
}
|
||||
// The internal FFat 'locfd' on this P4 has a broken FAT metadata layer (see the tile-cache notes):
|
||||
// it keeps rarely-written data (identity/prefs) but LOSES the frequently-rewritten contacts + chat on
|
||||
// reboot. So route contacts/channels (and chat history, see uiDataFsReady) to the microSD card, which
|
||||
// is reliable FAT. Identity/NodePrefs stay on FFat — they persist there and survive a card-less boot.
|
||||
// open/read/write work but f_stat/exists()/size() return garbage — and WHICH garbage shifts with
|
||||
// the build (-Og "worked by luck"; -Os made the exists()-gated identity + prefs loads come up
|
||||
// empty: fresh node identity, default name, profile changes lost every reboot). The card's FAT
|
||||
// metadata is truthful, so the WHOLE store lives there now; FFat remains only the no-card fallback.
|
||||
g_sd_ok = SD_MMC.begin("/sdcard", false /*1-bit*/) && SD_MMC.cardType() != CARD_NONE;
|
||||
printf("[storage] SD_MMC.begin = %s\n", g_sd_ok ? "OK" : "no card");
|
||||
if (g_sd_ok) store.setSecondaryFS(&SD_MMC); // contacts + channels -> SD; identity/prefs stay on FFat
|
||||
if (g_sd_ok) {
|
||||
SD_MMC.mkdir("/meshcomod");
|
||||
SD_MMC.mkdir("/meshcomod/identity");
|
||||
SD_MMC.mkdir("/meshcomod/bl");
|
||||
if (g_fs_ok) {
|
||||
// One-time rescue of identity + prefs off FFat: probe by OPEN + READ (never
|
||||
// exists()/size() on this FS). Files the card already holds win — SD metadata
|
||||
// is honest, so exists() is safe THERE.
|
||||
static const char* k_mig[] = { "/new_prefs", "/new_prefs.tmp", "/node_prefs",
|
||||
"/identity/_main.id" };
|
||||
for (const char* nm : k_mig) {
|
||||
char dst[48];
|
||||
snprintf(dst, sizeof dst, "/meshcomod%s", nm);
|
||||
if (SD_MMC.exists(dst)) continue;
|
||||
File s = FFat.open(nm, FILE_READ);
|
||||
if (!s) continue;
|
||||
uint8_t buf[512];
|
||||
size_t n = s.read(buf, sizeof buf);
|
||||
if (n == 0) { s.close(); continue; } // ghost/empty entry — nothing to keep
|
||||
File d = SD_MMC.open(dst, FILE_WRITE);
|
||||
if (!d) { s.close(); continue; }
|
||||
size_t total = 0;
|
||||
do { d.write(buf, n); total += n; n = s.read(buf, sizeof buf); } while (n > 0);
|
||||
d.close();
|
||||
s.close();
|
||||
printf("[storage] migrated %s -> SD:/meshcomod (%u B)\n", nm, (unsigned)total);
|
||||
}
|
||||
}
|
||||
store.useSdMmcStorage(); // identity/prefs/contacts/channels all on the card
|
||||
}
|
||||
// No card: FFat stays the store, as before — identity/prefs loads there depend
|
||||
// on the broken metadata layer and may be unreliable, but it is the only
|
||||
// persistent option on a card-less unit.
|
||||
store.begin();
|
||||
|
||||
bootLog("Mesh stack");
|
||||
|
||||
Reference in New Issue
Block a user