mirror of
https://github.com/ALLFATHER-BV/wadamesh.git
synced 2026-09-26 18:07:56 +00:00
touch: drop the V4 memory/store diagnostics + fix a swallowed hex escape
The RAM investigation and the language-download debugging left Serial probes across three files: the BOOTMEM/MESHMEM/MEMPROBE macros and their 48 call sites, plus the [STORE]/[APPCAT]/[LANGDL]/[LANGSEL] traces. They have served their purpose and were flooding the companion USB-CDC, so they all go. Two locals in the .lang installer (wr, wr3) existed only to feed a trace and go with it; the control-write repair path that actually rebuilds /lang stays. Separately, the map tile-cache help text read "256\xC3\x97256": the 256 after the multiplication sign is all hex digits, so the compiler folded it into the escape and emitted one out-of-range byte instead of "256x256". Breaking the literal after the escape terminates it. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f3d238c47a
commit
e0663eb9ee
@@ -3257,15 +3257,8 @@ void MyMesh::popChannelScope() {
|
||||
_chan_scope_pushed = false;
|
||||
}
|
||||
|
||||
#define MESHMEM(tag) do { \
|
||||
multi_heap_info_t _h{}; heap_caps_get_info(&_h, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); \
|
||||
Serial.printf("[MESHMEM] %-12s free=%6u psram=%7u\n", tag, \
|
||||
(unsigned)_h.total_free_bytes, (unsigned)ESP.getFreePsram()); Serial.flush(); } while (0)
|
||||
|
||||
void MyMesh::begin(bool has_display) {
|
||||
MESHMEM("enter");
|
||||
BaseChatMesh::begin();
|
||||
MESHMEM("post-base");
|
||||
|
||||
if (!_store->loadMainIdentity(self_id)) {
|
||||
self_id = radio_new_identity(); // create new random identity
|
||||
@@ -3288,9 +3281,7 @@ void MyMesh::begin(bool has_display) {
|
||||
#endif
|
||||
|
||||
// load persisted prefs
|
||||
MESHMEM("pre-prefs");
|
||||
_store->loadPrefs(_prefs, sensors.node_lat, sensors.node_lon);
|
||||
MESHMEM("post-prefs");
|
||||
|
||||
// sanitise bad pref values
|
||||
_prefs.rx_delay_base = constrain(_prefs.rx_delay_base, 0, 20.0f);
|
||||
@@ -3332,13 +3323,10 @@ void MyMesh::begin(bool has_display) {
|
||||
#endif
|
||||
|
||||
resetContacts();
|
||||
MESHMEM("pre-contacts");
|
||||
_store->loadContacts(this);
|
||||
MESHMEM("post-contacts");
|
||||
bootstrapRTCfromContacts();
|
||||
addChannel("Public", PUBLIC_GROUP_PSK); // pre-configure Andy's public channel
|
||||
_store->loadChannels(this);
|
||||
MESHMEM("post-channels");
|
||||
|
||||
applyRadioFromPrefs(); // freq/bw/sf/cr + TX power + RX-boost (shared with the live UI apply)
|
||||
#if defined(DISPLAY_CLASS)
|
||||
|
||||
@@ -276,15 +276,6 @@ void meshcomodClearSdMigLatch() {
|
||||
#endif
|
||||
|
||||
|
||||
// Boot memory trace: 175 KB of internal RAM is gone before the UI starts, and
|
||||
// nothing said where. Print free/largest at each init step so the consumer
|
||||
// names itself instead of being guessed at.
|
||||
#define BOOTMEM(tag) do { \
|
||||
multi_heap_info_t _h{}; heap_caps_get_info(&_h, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); \
|
||||
Serial.printf("[BOOTMEM] %-12s free=%6u largest=%6u psram=%7u\n", tag, \
|
||||
(unsigned)_h.total_free_bytes, (unsigned)_h.largest_free_block, \
|
||||
(unsigned)ESP.getFreePsram()); Serial.flush(); } while (0)
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
#if defined(HAS_RAK_TAP_V2)
|
||||
@@ -293,7 +284,6 @@ void setup() {
|
||||
delay(200);
|
||||
#endif
|
||||
Serial.println("[BOOT] setup start");
|
||||
BOOTMEM("setup-start");
|
||||
// The SDK ships CONFIG_SPIRAM_MALLOC_ALWAYSINTERNAL=4096: every allocation
|
||||
// under 4 KB is forced into internal DRAM even when PSRAM is free. On the V4
|
||||
// that is why internal sat at ~99% while 800+ KB of PSRAM went unused. Lower
|
||||
@@ -301,7 +291,6 @@ void setup() {
|
||||
// genuinely needs internal/DMA memory asks for it by capability and is
|
||||
// unaffected. Tunable — raise it if something misbehaves.
|
||||
heap_caps_malloc_extmem_enable(256);
|
||||
BOOTMEM("post-extmem");
|
||||
|
||||
// Widen the task-watchdog grace period. The ~5 s default trips during a legitimate-but-slow flash
|
||||
// burst — a SPIFFS garbage-collect, or a bulk save (DataStore issues ~12 flash ops per contact,
|
||||
@@ -344,7 +333,6 @@ void setup() {
|
||||
|
||||
board.begin();
|
||||
Serial.println("[BOOT] board ok");
|
||||
BOOTMEM("post-board");
|
||||
|
||||
#if defined(HAS_RAK_TAP_V2)
|
||||
// Quick PSRAM sanity check — silent crash before SPIFFS could be bad PSRAM config
|
||||
@@ -392,9 +380,7 @@ void setup() {
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOTMEM("pre-radio");
|
||||
if (!radio_init()) { halt(); }
|
||||
BOOTMEM("post-radio");
|
||||
Serial.println("[BOOT] radio ok");
|
||||
|
||||
fast_rng.begin(radio_driver.getRngSeed());
|
||||
@@ -440,10 +426,7 @@ void setup() {
|
||||
ExtraFS.begin();
|
||||
#endif
|
||||
#endif
|
||||
BOOTMEM("pre-store");
|
||||
store.begin();
|
||||
BOOTMEM("post-store");
|
||||
BOOTMEM("pre-mesh");
|
||||
the_mesh.begin(
|
||||
#ifdef DISPLAY_CLASS
|
||||
disp != NULL
|
||||
@@ -457,15 +440,10 @@ void setup() {
|
||||
#else
|
||||
serial_interface.begin(Serial);
|
||||
#endif
|
||||
BOOTMEM("pre-iface");
|
||||
the_mesh.startInterface(serial_interface);
|
||||
BOOTMEM("post-iface");
|
||||
#elif defined(RP2040_PLATFORM)
|
||||
LittleFS.begin();
|
||||
BOOTMEM("pre-store");
|
||||
store.begin();
|
||||
BOOTMEM("post-store");
|
||||
BOOTMEM("pre-mesh");
|
||||
the_mesh.begin(
|
||||
#ifdef DISPLAY_CLASS
|
||||
disp != NULL
|
||||
@@ -488,18 +466,14 @@ void setup() {
|
||||
#else
|
||||
serial_interface.begin(Serial);
|
||||
#endif
|
||||
BOOTMEM("pre-iface");
|
||||
the_mesh.startInterface(serial_interface);
|
||||
BOOTMEM("post-iface");
|
||||
#elif defined(ESP32)
|
||||
// Storage selection. SPIFFS by default; use the SD card under /meshcomod when
|
||||
// SPIFFS is unavailable (e.g. installed under Launcher) OR the user opted in
|
||||
// ("Store data on SD"). The SD shares the LoRa SPI bus, already brought up by
|
||||
// radio_init() above, so SD.begin's spi.begin is a no-op. Graceful: any SD
|
||||
// failure falls back to SPIFFS so the device always boots.
|
||||
BOOTMEM("pre-spiffs");
|
||||
bool spiffs_ok = SPIFFS.begin(false); // try first WITHOUT auto-format
|
||||
BOOTMEM("post-spiffs");
|
||||
bool sd_storage = false;
|
||||
#if defined(HAS_TDECK_GT911) || defined(HELTEC_LORA_V4_R8) || defined(TLORA_PAGER)
|
||||
{
|
||||
@@ -668,14 +642,11 @@ void setup() {
|
||||
Serial.println("[BOOT] touchPrefsReload ok"); Serial.flush();
|
||||
#endif
|
||||
#endif
|
||||
BOOTMEM("pre-store");
|
||||
store.begin();
|
||||
BOOTMEM("post-store");
|
||||
#if defined(HAS_RAK_TAP_V2)
|
||||
Serial.println("[BOOT] store ok"); Serial.flush();
|
||||
Serial.println("[BOOT] calling mesh.begin..."); Serial.flush();
|
||||
#endif
|
||||
BOOTMEM("pre-mesh");
|
||||
the_mesh.begin(
|
||||
#ifdef DISPLAY_CLASS
|
||||
disp != NULL
|
||||
@@ -697,17 +668,13 @@ void setup() {
|
||||
#endif
|
||||
|
||||
#if defined(WIFI_SSID) || defined(MULTI_TRANSPORT_COMPANION)
|
||||
BOOTMEM("pre-wifi-cfg");
|
||||
wifiConfigBegin();
|
||||
BOOTMEM("post-wifi-cfg");
|
||||
Serial.println("[BOOT] wifiConfig ok");
|
||||
#endif
|
||||
|
||||
#ifdef MULTI_TRANSPORT_COMPANION
|
||||
board.setInhibitSleep(true);
|
||||
BOOTMEM("pre-iface-srv");
|
||||
serial_interface.begin(Serial, TCP_PORT, WS_PORT);
|
||||
BOOTMEM("post-iface-srv");
|
||||
Serial.println("[BOOT] serial_interface ok");
|
||||
serial_interface.setBroadcastResponses(true); // RX log, channel messages, etc. go to all clients (USB + TCP + WS [+ BLE]), not only last sender
|
||||
/* Pick BLE vs WiFi at boot. The ESP32-S3 doesn't have enough internal heap
|
||||
@@ -794,9 +761,7 @@ void setup() {
|
||||
#else
|
||||
serial_interface.begin(Serial);
|
||||
#endif
|
||||
BOOTMEM("pre-iface");
|
||||
the_mesh.startInterface(serial_interface);
|
||||
BOOTMEM("post-iface");
|
||||
#else
|
||||
#error "need to define filesystem"
|
||||
#endif
|
||||
|
||||
+7
-40
@@ -1330,12 +1330,6 @@ static void statusBarSetTall(bool tall) {
|
||||
|
||||
void reserveTileFetchStack(); // fwd: claim the worker stack before Wi-Fi eats the heap
|
||||
|
||||
#define MEMPROBE(tag) do { \
|
||||
multi_heap_info_t _hi{}; heap_caps_get_info(&_hi, MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT); \
|
||||
Serial.printf("[MEM] %-14s free=%6u largest=%6u psram=%7u\n", tag, \
|
||||
(unsigned)_hi.total_free_bytes, (unsigned)_hi.largest_free_block, \
|
||||
(unsigned)ESP.getFreePsram()); } while (0)
|
||||
|
||||
// ---- AppPage: the shared full-screen app-page chrome (see AppPage.h) --------------
|
||||
// Thin wrappers over the machinery just above, exported so the self-contained app
|
||||
// modules (SnakeGame) build the same page as the in-file tool
|
||||
@@ -24361,9 +24355,8 @@ static void luaStoreFetchCatalogWorker(WiFiClient& client, HTTPClient& http) {
|
||||
s_luacat_buf = (char*)heap_caps_malloc(kLuaCatBufMax, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (!s_luacat_buf) { return; }
|
||||
s_luacat_buf[0] = 0;
|
||||
int cn = luaStoreHttpGet(client, http, "http://firmware.wadamesh.com/apps/apps.json",
|
||||
s_luacat_buf, kLuaCatBufMax);
|
||||
Serial.printf("[APPCAT] n=%d wifi=%d\n", cn, (int)WiFi.status());
|
||||
luaStoreHttpGet(client, http, "http://firmware.wadamesh.com/apps/apps.json",
|
||||
s_luacat_buf, kLuaCatBufMax);
|
||||
}
|
||||
|
||||
// Download <id>.lua + <id>.json (immutable per-version path) into /apps/.
|
||||
@@ -24483,7 +24476,6 @@ static bool luaStoreLangDownloadWorker(WiFiClient& client, HTTPClient& http,
|
||||
snprintf(url, sizeof url, "http://firmware.wadamesh.com/apps/lang/%s.lang", code);
|
||||
int n = luaStoreHttpGet(client, http, url, buf, kCap);
|
||||
bool ok = false;
|
||||
size_t wr = 0;
|
||||
bool opened = false;
|
||||
if (n > 16) {
|
||||
// Write to a TEMP file, verify every byte landed, then rename over the real
|
||||
@@ -24499,7 +24491,7 @@ static bool luaStoreLangDownloadWorker(WiFiClient& client, HTTPClient& http,
|
||||
File f = fs->open(tmp, "w");
|
||||
opened = (bool)f;
|
||||
if (f) {
|
||||
wr = langWriteAll(f, (const uint8_t*)buf, (size_t)n);
|
||||
langWriteAll(f, (const uint8_t*)buf, (size_t)n);
|
||||
f.close();
|
||||
ok = langVerifyInstall(fs, tmp, path, (size_t)n);
|
||||
}
|
||||
@@ -24515,7 +24507,6 @@ static bool luaStoreLangDownloadWorker(WiFiClient& client, HTTPClient& http,
|
||||
File cf = fs->open(ctl, "w");
|
||||
if (cf) { wr2 = langWriteAll(cf, (const uint8_t*)buf, (size_t)n); cf.close(); }
|
||||
fs->remove(ctl);
|
||||
size_t wr3 = 0;
|
||||
if (wr2 == (size_t)n) {
|
||||
// Healthy elsewhere -> nuke and recreate the /lang directory.
|
||||
char ldir[48];
|
||||
@@ -24536,17 +24527,12 @@ static bool luaStoreLangDownloadWorker(WiFiClient& client, HTTPClient& http,
|
||||
fs->rmdir(ldir);
|
||||
fs->mkdir(ldir);
|
||||
File rf = fs->open(tmp, "w");
|
||||
if (rf) { wr3 = langWriteAll(rf, (const uint8_t*)buf, (size_t)n); rf.close(); }
|
||||
if (rf) { langWriteAll(rf, (const uint8_t*)buf, (size_t)n); rf.close(); }
|
||||
ok = langVerifyInstall(fs, tmp, path, (size_t)n);
|
||||
if (!ok) fs->remove(tmp);
|
||||
}
|
||||
Serial.printf("[LANGDL] repair ctl=%u relang=%u ok=%d\n", (unsigned)wr2, (unsigned)wr3, (int)ok);
|
||||
}
|
||||
}
|
||||
char root[16];
|
||||
luaHostAppPath(root, sizeof root, ""); // "" = internal flash, "/meshcomod" = SD
|
||||
Serial.printf("[LANGDL] %s n=%d root=%s open=%d wr=%u ok=%d\n",
|
||||
url, n, root[0] ? root : "(internal)", (int)opened, (unsigned)wr, (int)ok);
|
||||
heap_caps_free(buf);
|
||||
return ok;
|
||||
}
|
||||
@@ -24910,7 +24896,6 @@ static void tileFetchTaskFn(void* arg) {
|
||||
// Lua app store: catalog fetch + app install (LUA_APPS.md Phase 2).
|
||||
if (s_luacat_request) {
|
||||
s_luacat_request = false;
|
||||
Serial.println("[APPCAT] worker picked up the request");
|
||||
luaStoreFetchCatalogWorker(client, http);
|
||||
s_luacat_done = true;
|
||||
continue;
|
||||
@@ -26904,7 +26889,9 @@ static void mapOptInfoCb(lv_event_t* e) {
|
||||
if (!credits) return; // OOM only: skip the credits text
|
||||
snprintf(credits, CREDITS_SZ, "%s%s", attrib,
|
||||
"How tiles work:\n"
|
||||
"The map is built from 256\xC3\x97256 \"slippy\" tiles. Only the tiles for the "
|
||||
// NOTE: the literal break after \x97 is REQUIRED — "\xC3\x97256" would parse the
|
||||
// trailing 256 as part of the hex escape (all hex digits) and emit one garbage byte.
|
||||
"The map is built from 256\xC3\x97" "256 \"slippy\" tiles. Only the tiles for the "
|
||||
"area you're viewing are fetched \xE2\x80\x94 there is no bulk pre-download.\n\n"
|
||||
"Because this device can't do HTTPS (not enough heap after Wi-Fi starts) "
|
||||
"and decodes JPEG far more cheaply than PNG, tiles come from the wadamesh "
|
||||
@@ -37907,13 +37894,7 @@ static void openLuaStorePage() {
|
||||
s_luacat_done = false;
|
||||
s_luacat_request = true;
|
||||
}
|
||||
MEMPROBE("store-open");
|
||||
const bool worker_up = ensureTileFetchTaskRunning();
|
||||
Serial.printf("[STORE] open: worker=%d spawn_ok=%d wifi=%d free_int=%u largest=%u free_psram=%u\n",
|
||||
(int)worker_up, (int)s_tile_fetch_spawn_ok, (int)WiFi.status(),
|
||||
(unsigned)ESP.getFreeHeap(),
|
||||
(unsigned)heap_caps_get_largest_free_block(MALLOC_CAP_INTERNAL | MALLOC_CAP_8BIT),
|
||||
(unsigned)ESP.getFreePsram());
|
||||
// The net worker needs an 8 KB contiguous internal block. When memory is too
|
||||
// tight to start it, nothing will ever service the request — so fail visibly
|
||||
// instead of spinning on "Loading catalog..." forever.
|
||||
@@ -42059,18 +42040,13 @@ static void buildUiTree() {
|
||||
}
|
||||
|
||||
// ---- Build tab contents ----
|
||||
MEMPROBE("pre-home");
|
||||
makeHome(tab_home);
|
||||
MEMPROBE("tab-home");
|
||||
|
||||
g_lv.dm.channel_mode = false;
|
||||
g_lv.ch.channel_mode = true;
|
||||
makeChatList(tab_chats, g_lv.dm, false, true);
|
||||
MEMPROBE("tab-chats");
|
||||
makeContactsTab(tab_contacts);
|
||||
MEMPROBE("tab-contacts");
|
||||
makeMapTab(tab_map);
|
||||
MEMPROBE("tab-map");
|
||||
#if defined(HAS_EXPANSION_KIT)
|
||||
if (tab_sensors) makeSensorsTab(tab_sensors);
|
||||
#endif
|
||||
@@ -42136,13 +42112,8 @@ static void buildUiTree() {
|
||||
// Create full-screen detail overlays (hidden until a thread is tapped)
|
||||
makeChatDetail(g_lv.dm);
|
||||
makeChatDetail(g_lv.ch);
|
||||
MEMPROBE("tab-chatdetail");
|
||||
|
||||
MEMPROBE("pre-settings");
|
||||
MEMPROBE("pre-settings");
|
||||
makeSettings(tab_settings);
|
||||
MEMPROBE("tab-settings");
|
||||
MEMPROBE("post-UI-build");
|
||||
|
||||
#if defined(HAS_TANMATSU)
|
||||
navBuildTabKeyHints(); // coloured △□○♣◇ shapes on the tab bar = the physical F-keys
|
||||
@@ -45997,8 +45968,6 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
// largest block, so the worker could never start and tiles, the update
|
||||
// check and the app catalog were all silently dead.
|
||||
reserveTileFetchStack();
|
||||
MEMPROBE("post-reserve");
|
||||
MEMPROBE("pre-lv_init");
|
||||
lv_init();
|
||||
initTouchFontFallbacks();
|
||||
#if CAP_ROUND_CORNERS
|
||||
@@ -46236,9 +46205,7 @@ void UITask::begin(DisplayDriver* display, SensorManager* sensors, NodePrefs* no
|
||||
// when the base orientation is portrait. In hardware landscape the LVGL
|
||||
// rotation is left at NONE so it never software-rotates on top of the panel.
|
||||
g_lv.disp_drv.sw_rotate = 1;
|
||||
MEMPROBE("pre-disp_reg");
|
||||
lv_disp_drv_register(&g_lv.disp_drv);
|
||||
MEMPROBE("post-disp_reg");
|
||||
#if defined(HAS_TANMATSU)
|
||||
// Apply the 270° software rotation now that the driver is registered: logical surface
|
||||
// becomes 800x480 and lv_disp_get_hor/ver_res report landscape for every layout query.
|
||||
|
||||
Reference in New Issue
Block a user