From f9053d0afb8c2ac36909439a4f4efe13a8334b8b Mon Sep 17 00:00:00 2001 From: "Michael A. Cojocari" Date: Fri, 21 Aug 2026 15:10:49 -0400 Subject: [PATCH 1/5] fix(touch): finish the CAP_SD gating for "Save update bin to SD" (#289) e2d07d8 moved this feature off a board-name list and onto CAP_SD && CAP_OTA, which is the right gate. It changed two of the six #if regions the feature is spread across. The other four still carried the old three-board list, so the T-Lora Pager (CAP_SD=1, not on that list) got the button and the state without the worker behind it. The result is not a build failure, which is why "all 8 S3 boards build" did not catch it: sdFwWorkerRun's only caller sits behind the same gate that excluded the worker, so nothing link-errors. It fails at runtime instead. Pressing the button sets s_sdfw_request and starts the 400 ms poll timer, nothing ever services the request, so s_sdfw_state stays 1 and the row sits at "Saving to SD... 0%" forever. Then closeSettingsCategory -- also still on the old list -- does not null s_sdfw_status_lbl when the sheet is freed, and the timer keeps calling lv_label_set_text on the dead object. Open About, tap the button, leave settings, and it is a use-after-free every 400 ms. Verified by building the pager before and after: on the unfixed tree sdFwWorkerRun's strings ("can't create /BINS", "SD open failed") are absent from firmware.elf while the button is present; after, both are in. All six regions are now character-for-character identical, with a comment at the worker saying so and why a partial widening still compiles. Pager, T-Deck and ThinkNode M9 all build. Co-Authored-By: Claude Opus 5 --- src/ui-touch/UITask.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index 40cd65a1..1c95f311 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -26272,11 +26272,19 @@ static void otaWorkerRun(WiFiClient& client, HTTPClient& http) { s_ota_state = 2; // success -> the UI poll timer reboots into the new slot } -#if defined(HAS_TDECK_GT911) || defined(HAS_THINKNODE_M9) || defined(HELTEC_LORA_V4_R8) +#if CAP_SD && defined(ESP32) && defined(MULTI_TRANSPORT_COMPANION) && CAP_OTA // Stream the app-only bin for the active update channel onto the SD card // (/BINS/wadamesh-beta_-.bin) so the Launcher can flash it — // the no-A/B-slot counterpart to otaWorkerRun above. Same immutable versioned // URL, same worker, but the bytes go to SD instead of the spare OTA slot. +// +// This feature is spread over SIX #if regions (state+callbacks, this worker, +// the tile-worker dispatch below, the About button, the settings-close teardown, +// and the sdHealthTick bail-out). They are character-for-character identical on +// purpose. A board admitted to some but not all of them still COMPILES — the +// worker's only caller sits behind the same gate, so nothing link-errors — and +// then hangs at "Saving to SD… 0%" with a poll timer writing to a label the +// teardown never nulled. Change all six or none. static void sdFwWorkerRun(WiFiClient& client, HTTPClient& http) { s_sdfw_pct = 0; if (SD.cardType() == CARD_NONE) { snprintf(s_sdfw_msg, sizeof s_sdfw_msg, "no SD card"); s_sdfw_state = 3; return; } @@ -26533,7 +26541,7 @@ static void tileFetchTaskFn(void* arg) { otaWorkerRun(client, http); continue; } -#if defined(HAS_TDECK_GT911) || defined(HAS_THINKNODE_M9) || defined(HELTEC_LORA_V4_R8) +#if CAP_SD && defined(ESP32) && defined(MULTI_TRANSPORT_COMPANION) && CAP_OTA // SD firmware download for Launcher installs (user-initiated from About). if (s_sdfw_request) { s_sdfw_request = false; @@ -31015,7 +31023,7 @@ static void closeSettingsCategory() { hideKb(); if (s_settings_open_cat == CAT_ABOUT) { // null the live-label ptrs (freed with the sheet) s_sysinfo_lbl = nullptr; s_sysinfo_rest_lbl = nullptr; s_update_about_lbl = nullptr; s_ota_status_lbl = nullptr; -#if (defined(HAS_TDECK_GT911) || defined(HAS_THINKNODE_M9) || defined(HELTEC_LORA_V4_R8)) && defined(ESP32) && defined(MULTI_TRANSPORT_COMPANION) && CAP_OTA +#if CAP_SD && defined(ESP32) && defined(MULTI_TRANSPORT_COMPANION) && CAP_OTA s_sdfw_status_lbl = nullptr; #endif s_ota_btn = nullptr; s_ota_btn_lbl = nullptr; @@ -51214,8 +51222,8 @@ static void sdHealthTick() { return; } #endif -#if (defined(HAS_TDECK_GT911) || defined(HAS_THINKNODE_M9) || defined(HELTEC_LORA_V4_R8)) && defined(ESP32) && defined(MULTI_TRANSPORT_COMPANION) && CAP_OTA - if (s_sdfw_request) return; // worker streaming a firmware download to /BINS (T-Deck only) +#if CAP_SD && defined(ESP32) && defined(MULTI_TRANSPORT_COMPANION) && CAP_OTA + if (s_sdfw_request) return; // worker streaming a firmware download to /BINS #endif // Probe when some SD user flagged a failure (rate-limited to 1/5 s), and // also on a slow 30 s background cadence — a card yanked while nothing is From 4b9c9f1f24fbbe47a60c7ebfda048af97d43f8b5 Mon Sep 17 00:00:00 2001 From: "Michael A. Cojocari" Date: Fri, 21 Aug 2026 15:19:56 -0400 Subject: [PATCH 2/5] docs: the Pager is an LCD on the beta channel, and so are two of its neighbours (#289) e2d07d8 added the four missing boards to the support matrix, which was the right call -- the docs were listing five of ten. Three details in it do not match what we actually publish. The T-Lora Pager's display is listed as AMOLED. It is a 2.33" IPS ST7796U LCD at 480x222 (TLORA_PAGER_PORT.md's hardware table, and the ST7796LCDDisplay driver it boots). The AMOLED is the T-Display P4, one row down. The Pager, the Heltec V4-R8 and the T-Display P4 are all marked Stable. All three install from latest-beta on the site and all three carry data-dl-betaonly there; only the T-Deck and the Heltec V4 + TFT are on the stable feed. Marking a board Stable in DEVICES.md while the install button pulls a beta build tells a user the wrong thing about what they are getting. All three now say "Beta (new in beta_45)", which is the release the three of them debuted in. Also adds the per-board feature note the Pager was missing: the two radio SKUs and what happens if you flash the wrong one, and the microSD behaviour (detected-but-unreadable cards offer a retry; formatting stays a host-side job). The V4-R8, T-Display P4 and Attaky rows still have no feature note. Left for someone who has the hardware. Co-Authored-By: Claude Opus 5 --- DEVICES.md | 15 ++++++++++++--- README.md | 6 +++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/DEVICES.md b/DEVICES.md index 2b75e334..a863ef68 100644 --- a/DEVICES.md +++ b/DEVICES.md @@ -13,9 +13,9 @@ USB) and the [GitHub releases](https://github.com/ALLFATHER-BV/wadamesh/releases | Tanmatsu | ESP32-P4 + ESP32-C6, SX1262 | 4" 800x480, 69-key keyboard (no touch) | Tanmatsu app store on the device (runs under the badge.team launcher, not web-flashable) | Store tracks the test channel | Fully supported; LoRa + Wi-Fi + Bluetooth simultaneously, standalone and companion in one | | Elecrow ThinkNode M9 | ESP32-S3, LR1110 | 2.4" 240x320 (no touch), I2C QWERTY + d-pad | Web flasher | Beta (new in beta_38) | Hardware-complete community port by ded (#138): GPS, microSD, buzzer, lock screen, d-pad navigation | | RAK WisMesh Tap V2 (RAK3312) | ESP32-S3, SX1262 | Touch display (LovyanGFX, 30+ fps) | Web flasher | Beta (new in beta_38) | Early community port by Ethac.chen (#136); core mesh, chat and map working | -| LilyGo T-Lora Pager | ESP32-S3, LR1121 or SX1262 | 2.33" AMOLED (no touch), QWERTY + rotary encoder | Web flasher (pick the build matching your radio) | Stable | Fully supported; keyboard-first navigation, microSD, map tile packs | -| Heltec V4-R8 + Expansion Kit V2 | ESP32-S3 (8 MB octal PSRAM), SX1262 | 2.4" touch (CHSC6x) | Web flasher | Stable | As the V4 plus microSD and the Expansion Kit sensors; buzzer supported | -| LilyGo T-Display P4 | ESP32-P4 + ESP32-C6, SX1262 | AMOLED or TFT-LCD, touch | Web flasher (AMOLED) or the .bin for the LCD SKU | Stable | Two screen SKUs; fuel-gauge battery reporting, full TX power | +| LilyGo T-Lora Pager | ESP32-S3, LR1121 or SX1262 | 2.33" IPS LCD, 480x222 (no touch), QWERTY + rotary encoder | Web flasher (pick the build matching your radio) | Beta (new in beta_45) | Fully supported; keyboard-first navigation, microSD, map tile packs | +| Heltec V4-R8 + Expansion Kit V2 | ESP32-S3 (8 MB octal PSRAM), SX1262 | 2.4" touch (CHSC6x) | Web flasher | Beta (new in beta_45) | As the V4 plus microSD and the Expansion Kit sensors; buzzer supported | +| LilyGo T-Display P4 | ESP32-P4 + ESP32-C6, SX1262 | AMOLED or TFT-LCD, touch | Web flasher (AMOLED) or the .bin for the LCD SKU | Beta (new in beta_45) | Two screen SKUs; fuel-gauge battery reporting, full TX power | | Attaky Mesh Series | ESP32-S3, SX1262 | Touch display | Web flasher | Beta (new in beta_47) | Community port by attakygit (#158/#169); detachable keyboard supported | ## Feature notes per board @@ -30,6 +30,15 @@ USB) and the [GitHub releases](https://github.com/ALLFATHER-BV/wadamesh/releases keys mapped to tabs, ALT accent picker, UI scaling (Normal/Large/Huge), microSD for all persistent data. Ships through the Tanmatsu launcher store, updates arrive as store updates. +- **T-Lora Pager**: no touchscreen at all — the QWERTY keyboard and the rotary + encoder drive everything (Alt+turn free-scrolls a page; see + [TLORA_PAGER_SHORTCUTS.md](TLORA_PAGER_SHORTCUTS.md) for the full key map). + GPS, microSD, keyboard backlight, lock screen and notification sound through + the onboard codec and amp all work. Two builds, one per radio: LR1121 and + SX1262 — flashing the wrong one leaves you with no radio, so check the label + on your unit. A card the Pager detects but cannot read shows up in File + Manager greyed, and tapping it retries the mount; formatting is deliberately + left to a computer (FAT32) rather than done on-device. - **ThinkNode M9**: keyboard plus d-pad navigation (no touch), same feature set as the other boards where the hardware allows. Every key and mode is covered in the [keyboard & d-pad guide](THINKNODE_M9_SHORTCUTS.md). New in beta_38; diff --git a/README.md b/README.md index 95510e01..60ea0cd9 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,9 @@ per-board status. - Tanmatsu (ESP32-P4) — built from `tanmatsu/` (ESP-IDF), ships via the Tanmatsu app store — [sideload guide](TANMATSU_SIDELOAD.md) for running your own build - Elecrow ThinkNode M9 — env `ThinkNode_M9_companion_radio_touch` (beta) — [keyboard & d-pad guide](THINKNODE_M9_SHORTCUTS.md) - RAK WisMesh Tap V2 (RAK3312) — env `rak_tap_v2_companion_radio_touch` (beta) -- LilyGo T-Lora Pager — envs `tlora_pager_lr1121_companion_radio_touch` / `tlora_pager_sx1262_companion_radio_touch` (stable) — [keyboard shortcuts](TLORA_PAGER_SHORTCUTS.md) -- Heltec V4-R8 + Expansion Kit V2 — env `heltec_v4_r8_tft_companion_radio_usb_tcp_touch` (stable) -- LilyGo T-Display P4 — built from `tdisplay_p4/` (ESP-IDF); AMOLED by default, `WADA_P4_LCD=1` for the TFT-LCD SKU +- LilyGo T-Lora Pager — envs `tlora_pager_lr1121_companion_radio_touch` / `tlora_pager_sx1262_companion_radio_touch` (beta) — [keyboard shortcuts](TLORA_PAGER_SHORTCUTS.md) +- Heltec V4-R8 + Expansion Kit V2 — env `heltec_v4_r8_tft_companion_radio_usb_tcp_touch` (beta) +- LilyGo T-Display P4 — built from `tdisplay_p4/` (ESP-IDF); AMOLED by default, `WADA_P4_LCD=1` for the TFT-LCD SKU (beta) - Attaky Mesh Series — env `attaky_mesh_series_companion_radio_touch` (beta) ## Architecture From d7b981bc620cffdfcf6487306c62b7ea21ca6cc7 Mon Sep 17 00:00:00 2001 From: "Michael A. Cojocari" Date: Fri, 21 Aug 2026 15:39:01 -0400 Subject: [PATCH 3/5] fix(touch): stop telling three boards to flash from a Launcher they do not have Gating "Save update bin to SD" on CAP_SD gave it to the Pager, the ThinkNode M9 and the Heltec V4-R8 as well as the T-Deck. The two strings it shows still name bmorcelli's Launcher -- "For Launcher installs: ..." on the button, and "Saved: %s\nFlash it from the Launcher." when it finishes -- which is the T-Deck's update path and means nothing on the other three. Those users get told to open something that does not exist on their device. The obvious fix is to reword the strings, and that is the trap: both are translated in all 13 .lang files, TR() looks rows up by their English text, and editing the English orphans every translation of them silently. So the T-Deck keeps its strings byte-identical and the other boards get their own keys, chosen at compile time. Two new keys, added to all 13 files with English on both sides, which is this repo's convention for a row awaiting a translator (see 4709c81). i18n-audit: 13/13 languages, 952 keys, nothing missing. audit-lang: no UNSAFE format mismatches, which matters here because SDFW_SAVED_FMT is handed to snprintf as the format string. T-Deck (the #if arm), Pager, M9 and V4-R8 (the #else arm) all build. Co-Authored-By: Claude Opus 5 --- deploy/apps/lang/bg.lang | 2 ++ deploy/apps/lang/de.lang | 2 ++ deploy/apps/lang/el.lang | 2 ++ deploy/apps/lang/es.lang | 2 ++ deploy/apps/lang/fr.lang | 2 ++ deploy/apps/lang/hu.lang | 2 ++ deploy/apps/lang/it.lang | 2 ++ deploy/apps/lang/nl.lang | 2 ++ deploy/apps/lang/pt-br.lang | 2 ++ deploy/apps/lang/ro.lang | 2 ++ deploy/apps/lang/ru.lang | 2 ++ deploy/apps/lang/sr.lang | 2 ++ deploy/apps/lang/uk.lang | 2 ++ src/ui-touch/UITask.cpp | 19 +++++++++++++++++-- 14 files changed, 43 insertions(+), 2 deletions(-) diff --git a/deploy/apps/lang/bg.lang b/deploy/apps/lang/bg.lang index 21885b15..8a4950ed 100644 --- a/deploy/apps/lang/bg.lang +++ b/deploy/apps/lang/bg.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Запазено — рестарт Saved — reconnecting… Запазено — повторно свързване… Saved: %s\nFlash it from the Launcher. Запазено: %s\nФлашнете го от Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Запис на SD… %d%% Saving to SD… 0% Запис на SD… 0% Scan to open on phone Сканирай, за да отвориш на телефона diff --git a/deploy/apps/lang/de.lang b/deploy/apps/lang/de.lang index 1e1f8180..9b1ce841 100644 --- a/deploy/apps/lang/de.lang +++ b/deploy/apps/lang/de.lang @@ -722,6 +722,8 @@ Saved — applying… Gespeichert – wird angewendet … Saved — rebooting Gespeichert — Neustart Saved — reconnecting… Gespeichert — verbinde neu… Saved: %s\nFlash it from the Launcher. Gespeichert: %s\nFlashe es über den Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Speichern auf SD… %d%% Saving to SD… 0% Speichern auf SD… 0% Scan to open on phone Scannen, um am Handy zu öffnen diff --git a/deploy/apps/lang/el.lang b/deploy/apps/lang/el.lang index 3ce37421..5d74319a 100644 --- a/deploy/apps/lang/el.lang +++ b/deploy/apps/lang/el.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Αποθηκεύτηκε — επανεκκίνηση Saved — reconnecting… Αποθηκεύτηκε — επανασύνδεση… Saved: %s\nFlash it from the Launcher. Αποθηκεύτηκε: %s\nΕγκαταστήστε το από τον Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Αποθήκευση στην SD… %d%% Saving to SD… 0% Αποθήκευση στην SD… 0% Scan to open on phone Σαρώστε για άνοιγμα στο κινητό diff --git a/deploy/apps/lang/es.lang b/deploy/apps/lang/es.lang index a2a1efa0..4303baa0 100644 --- a/deploy/apps/lang/es.lang +++ b/deploy/apps/lang/es.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Guardado — reiniciando Saved — reconnecting… Guardado — reconectando… Saved: %s\nFlash it from the Launcher. Guardado: %s\nFlashéalo desde el Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Guardando en SD… %d%% Saving to SD… 0% Guardando en SD… 0% Scan to open on phone Escanea para abrir en el móvil diff --git a/deploy/apps/lang/fr.lang b/deploy/apps/lang/fr.lang index 8c1378bd..f3c9280d 100644 --- a/deploy/apps/lang/fr.lang +++ b/deploy/apps/lang/fr.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Enregistré — redémarrage Saved — reconnecting… Enregistré — reconnexion… Saved: %s\nFlash it from the Launcher. Enregistré : %s\nFlashez-le depuis le Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Enregistrement sur SD… %d%% Saving to SD… 0% Enregistrement sur SD… 0% Scan to open on phone Scannez pour ouvrir sur le téléphone diff --git a/deploy/apps/lang/hu.lang b/deploy/apps/lang/hu.lang index bc46a26e..0f344fb7 100644 --- a/deploy/apps/lang/hu.lang +++ b/deploy/apps/lang/hu.lang @@ -733,6 +733,8 @@ Saved — applying… Mentve — alkalmazás folyamatban… Saved — rebooting Mentve — újraindítás Saved — reconnecting… Mentve — újracsatlakozás… Saved: %s\nFlash it from the Launcher. Mentett: %s\nFlash-eld a Launcher-ből. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Mentés SD-kártyára… %d%% Saving to SD… 0% Mentés SD-kártyára… 0% Scan to open on phone Olvasd be a telefonos megnyitáshoz diff --git a/deploy/apps/lang/it.lang b/deploy/apps/lang/it.lang index 2d651989..bc1ea47a 100644 --- a/deploy/apps/lang/it.lang +++ b/deploy/apps/lang/it.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Salvato — riavvio Saved — reconnecting… Salvato — riconnessione… Saved: %s\nFlash it from the Launcher. Salvato: %s\nFlashalo dal Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Salvataggio su SD… %d%% Saving to SD… 0% Salvataggio su SD… 0% Scan to open on phone Scansiona per aprire sul telefono diff --git a/deploy/apps/lang/nl.lang b/deploy/apps/lang/nl.lang index 762d5045..7240e4c2 100644 --- a/deploy/apps/lang/nl.lang +++ b/deploy/apps/lang/nl.lang @@ -722,6 +722,8 @@ Saved — applying… Opgeslagen — wordt toegepast… Saved — rebooting Opgeslagen — opnieuw opstarten Saved — reconnecting… Opgeslagen — opnieuw verbinden… Saved: %s\nFlash it from the Launcher. Opgeslagen: %s\nFlash het vanuit de Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Opslaan naar SD… %d%% Saving to SD… 0% Opslaan naar SD… 0% Scan to open on phone Scan om op je telefoon te openen diff --git a/deploy/apps/lang/pt-br.lang b/deploy/apps/lang/pt-br.lang index 7f974d1a..a53d5819 100644 --- a/deploy/apps/lang/pt-br.lang +++ b/deploy/apps/lang/pt-br.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Salvo — reiniciando Saved — reconnecting… Salvo — reconectando… Saved: %s\nFlash it from the Launcher. Salvo: %s\nInstale pelo Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Salvando no SD… %d%% Saving to SD… 0% Salvando no SD… 0% Scan to open on phone Escaneie para abrir no celular diff --git a/deploy/apps/lang/ro.lang b/deploy/apps/lang/ro.lang index ff7c8d2a..86d4772b 100644 --- a/deploy/apps/lang/ro.lang +++ b/deploy/apps/lang/ro.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Salvat — se reporneşte Saved — reconnecting… Salvat — se reconectează… Saved: %s\nFlash it from the Launcher. Salvat: %s\nInstalează-l din Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Se salvează pe SD… %d%% Saving to SD… 0% Se salvează pe SD… 0% Scan to open on phone Scanează pentru a deschide pe telefon diff --git a/deploy/apps/lang/ru.lang b/deploy/apps/lang/ru.lang index 2fbddc2a..78e21c51 100644 --- a/deploy/apps/lang/ru.lang +++ b/deploy/apps/lang/ru.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Сохранено — перезагрузка Saved — reconnecting… Сохранено — переподключение… Saved: %s\nFlash it from the Launcher. Сохранено: %s\nПрошейте из Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Сохранение на SD… %d%% Saving to SD… 0% Сохранение на SD… 0% Scan to open on phone Отсканируйте, чтобы открыть на телефоне diff --git a/deploy/apps/lang/sr.lang b/deploy/apps/lang/sr.lang index 377722d0..c379e9f9 100644 --- a/deploy/apps/lang/sr.lang +++ b/deploy/apps/lang/sr.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Сачувано — рестарт Saved — reconnecting… Сачувано — поновно повезивање… Saved: %s\nFlash it from the Launcher. Сачувано: %s\nФлешујте га из Launcher-а. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Чување на SD… %d%% Saving to SD… 0% Чување на SD… 0% Scan to open on phone Скенирај да отвориш на телефону diff --git a/deploy/apps/lang/uk.lang b/deploy/apps/lang/uk.lang index 2605f078..074a4641 100644 --- a/deploy/apps/lang/uk.lang +++ b/deploy/apps/lang/uk.lang @@ -722,6 +722,8 @@ Saved — applying… Saved — rebooting Збережено — перезавантаження Saved — reconnecting… Збережено — перепідключення… Saved: %s\nFlash it from the Launcher. Збережено: %s\nПрошийте з Launcher. +Saved: %s\nReady for offline flashing. Saved: %s\nReady for offline flashing. +Saves the latest firmware of the selected channel to the SD card (BINS folder). Saves the latest firmware of the selected channel to the SD card (BINS folder). Saving to SD… %d%% Збереження на SD… %d%% Saving to SD… 0% Збереження на SD… 0% Scan to open on phone Відскануйте, щоб відкрити на телефоні diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index 1c95f311..36a48443 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -5377,6 +5377,21 @@ static void otaButtonRefreshState() { // the ACTIVE update channel (stable, or beta when "Get test builds" is on) // into /BINS/wadamesh-beta_-.bin on the SD card. The download // streams on the tile worker; this UI side mirrors the OTA poll pattern. +// Wording is board-conditional and the two sets are SEPARATE TR() keys on purpose. +// Only the T-Deck has bmorcelli's Launcher; now that this feature is gated on +// CAP_SD it also compiles for the Pager, the ThinkNode M9 and the Heltec V4-R8, +// where "flash it from the Launcher" names something the user does not have. The +// T-Deck strings must stay byte-identical: they are translated in all 13 .lang +// files, and editing the English key orphans every translation of it (audit with +// scripts/build/audit-lang.py). +#if defined(HAS_TDECK_GT911) + #define SDFW_SAVED_FMT TR("Saved: %s\nFlash it from the Launcher.") + #define SDFW_HINT_TEXT TR("For Launcher installs: saves the latest firmware of the selected channel to the SD card (BINS folder).") +#else + #define SDFW_SAVED_FMT TR("Saved: %s\nReady for offline flashing.") + #define SDFW_HINT_TEXT TR("Saves the latest firmware of the selected channel to the SD card (BINS folder).") +#endif + static volatile bool s_sdfw_request = false; // UI -> worker static volatile int s_sdfw_state = 0; // 0 idle, 1 running, 2 ok, 3 error static volatile int s_sdfw_pct = 0; @@ -5400,7 +5415,7 @@ static void sdFwPollTimerCb(lv_timer_t* t) { if (st == 2) { if (s_sdfw_status_lbl) { char b[112]; - snprintf(b, sizeof b, TR("Saved: %s\nFlash it from the Launcher."), s_sdfw_msg); + snprintf(b, sizeof b, SDFW_SAVED_FMT, s_sdfw_msg); lv_label_set_text(s_sdfw_status_lbl, b); } if (g_lv.task) g_lv.task->showAlert(TR("Update bin saved to SD"), 3000); @@ -30965,7 +30980,7 @@ static void settingsCatBuild(int cat) { lv_obj_set_width(s_sdfw_status_lbl, lblw); lv_obj_set_style_text_font(s_sdfw_status_lbl, &g_font_12, LV_PART_MAIN); lv_obj_set_style_text_color(s_sdfw_status_lbl, lv_color_hex(COLOR_SUB), LV_PART_MAIN); - lv_label_set_text(s_sdfw_status_lbl, TR("For Launcher installs: saves the latest firmware of the selected channel to the SD card (BINS folder).")); + lv_label_set_text(s_sdfw_status_lbl, SDFW_HINT_TEXT); } #endif } From 62d7a170344e65a67eb25f3ed3ec5292f9594b53 Mon Sep 17 00:00:00 2001 From: "Michael A. Cojocari" Date: Fri, 21 Aug 2026 15:41:44 -0400 Subject: [PATCH 4/5] feat(touch): give the Pager a way back from an unreadable SD card (#289) The Pager's File Manager only drew an SD row when the card mounted. A card the board can see but cannot read -- exFAT out of the box, or a damaged FAT -- produced no row at all, so the user could not tell "no card" from "card the firmware refuses", and had no way to retry short of a reboot. The Pager is the board that can actually tell those apart: it has a card-detect line on the expander (XL9555 ch10), which the T-Deck does not. So a detected but unmounted card now draws greyed as "SD card (unreadable - tap to retry)", and tapping it clears the mount backoff and retries. An absent card still draws nothing, which is the existing deliberate behaviour. The retry is the same single 4 MHz attempt fmSdTryMount() already makes. No retry ladder, no teardown of the live shared display/radio bus -- both of which that function's comment forbids on this board, and both of which were learned the hard way in M7. In-app formatting stays off for the Pager. That was already true but read as an oversight, so the reasoning now sits on the format-helper guard: f_mkfs needs an SD.end() + sdcard_init/uninit lifecycle teardown on that shared bus; with no touchscreen the T-Deck's hold-to-format gesture maps to holding ENTER, which is an undiscoverable way to erase a card on a device where ENTER is how you move; and it has never been run on Pager hardware. Formatting on a computer costs 30 seconds and carries none of that. The Arduino SD library never calls spi->begin()/end(), so it is probably safe -- "probably" is not enough for a one-way whole-card erase. Two new strings, added to all 13 .lang files with English on both sides. i18n-audit: 954 keys, nothing missing. Pager and T-Deck build. Co-Authored-By: Claude Opus 5 --- deploy/apps/lang/bg.lang | 2 ++ deploy/apps/lang/de.lang | 2 ++ deploy/apps/lang/el.lang | 2 ++ deploy/apps/lang/es.lang | 2 ++ deploy/apps/lang/fr.lang | 2 ++ deploy/apps/lang/hu.lang | 2 ++ deploy/apps/lang/it.lang | 2 ++ deploy/apps/lang/nl.lang | 2 ++ deploy/apps/lang/pt-br.lang | 2 ++ deploy/apps/lang/ro.lang | 2 ++ deploy/apps/lang/ru.lang | 2 ++ deploy/apps/lang/sr.lang | 2 ++ deploy/apps/lang/uk.lang | 2 ++ src/ui-touch/UITask.cpp | 52 +++++++++++++++++++++++++++++++++++-- 14 files changed, 76 insertions(+), 2 deletions(-) diff --git a/deploy/apps/lang/bg.lang b/deploy/apps/lang/bg.lang index 8a4950ed..7014a05e 100644 --- a/deploy/apps/lang/bg.lang +++ b/deploy/apps/lang/bg.lang @@ -683,6 +683,7 @@ Run setup again Стартирай настройката отново SD card %s SD карта %s SD card %s (hold: format) SD карта %s (задръж: формат) SD card (tap to mount) SD карта (докоснете за монтиране) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted SD картата е поставена SD card lost - reinsert to recover SD картата е изгубена - поставете я отново SD card remounted SD картата е монтирана отново @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD форматирана - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB използвани diff --git a/deploy/apps/lang/de.lang b/deploy/apps/lang/de.lang index 9b1ce841..7032f47b 100644 --- a/deploy/apps/lang/de.lang +++ b/deploy/apps/lang/de.lang @@ -683,6 +683,7 @@ Run setup again Setup erneut ausführen SD card %s SD-Karte %s SD card %s (hold: format) SD-Karte %s (halten: formatieren) SD card (tap to mount) SD-Karte (zum Einbinden tippen) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted SD-Karte eingelegt SD card lost - reinsert to recover SD-Karte verloren - neu einstecken SD card remounted SD-Karte neu eingebunden @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD formatiert - %s (MESHCOMOD) SD is busy - close tools and retry SD ist belegt – Tools schließen und erneut versuchen SD removed - card-backed data cannot be saved SD entfernt – Kartendaten können nicht gespeichert werden SD stayed busy - format cancelled, retry SD blieb belegt – Formatierung abgebrochen, erneut versuchen +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB belegt diff --git a/deploy/apps/lang/el.lang b/deploy/apps/lang/el.lang index 5d74319a..779a0900 100644 --- a/deploy/apps/lang/el.lang +++ b/deploy/apps/lang/el.lang @@ -683,6 +683,7 @@ Run setup again Εκτέλεση ρύθμισης ξανά SD card %s Κάρτα SD %s SD card %s (hold: format) Κάρτα SD %s (κράτημα: διαμόρφωση) SD card (tap to mount) Κάρτα SD (πατήστε για προσάρτηση) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted Η κάρτα SD εισήχθη SD card lost - reinsert to recover Η κάρτα SD χάθηκε - επανατοποθετήστε SD card remounted Η κάρτα SD επανασυνδέθηκε @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD διαμορφώθηκε - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB σε χρήση diff --git a/deploy/apps/lang/es.lang b/deploy/apps/lang/es.lang index 4303baa0..ee930fb6 100644 --- a/deploy/apps/lang/es.lang +++ b/deploy/apps/lang/es.lang @@ -683,6 +683,7 @@ Run setup again Ejecutar configuración de nuevo SD card %s Tarjeta SD %s SD card %s (hold: format) Tarjeta SD %s (mantener: formatear) SD card (tap to mount) Tarjeta SD (toca para montar) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted Tarjeta SD insertada SD card lost - reinsert to recover Tarjeta SD perdida - reinsértala SD card remounted Tarjeta SD remontada @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD formateada - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB usados diff --git a/deploy/apps/lang/fr.lang b/deploy/apps/lang/fr.lang index f3c9280d..78457bf3 100644 --- a/deploy/apps/lang/fr.lang +++ b/deploy/apps/lang/fr.lang @@ -683,6 +683,7 @@ Run setup again Relancer la configuration SD card %s Carte SD %s SD card %s (hold: format) Carte SD %s (maintenir : formater) SD card (tap to mount) Carte SD (toucher pour monter) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted Carte SD insérée SD card lost - reinsert to recover Carte SD perdue - réinsérez-la SD card remounted Carte SD remontée @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD formatée - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u Ko utilisés diff --git a/deploy/apps/lang/hu.lang b/deploy/apps/lang/hu.lang index 0f344fb7..6c3b8b77 100644 --- a/deploy/apps/lang/hu.lang +++ b/deploy/apps/lang/hu.lang @@ -692,6 +692,7 @@ Run setup again Futtassa újra a beállítást SD card %s SD-kártya %s SD card %s (hold: format) SD-kártya %s (tartás: formázás) SD card (tap to mount) SD-kártya (érintésre csatlakoztatható) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted SD-kártya behelyezve SD card lost - reinsert to recover SD-kártya elveszett - helyezze be újra a helyreállításhoz SD card remounted SD kártya újracsatolva @@ -704,6 +705,7 @@ SD formatted - %s (MESHCOMOD) SD formázás - %s (MESHCOMOD) SD is busy - close tools and retry Az SD-kártya foglalt – zárd be az eszközöket, majd próbáld újra. SD removed - card-backed data cannot be saved SD-kártya eltávolítva – az SD-kártyán tárolt adatok nem menthetők. SD stayed busy - format cancelled, retry Az SD-kártya továbbra is foglalt – a formázás megszakítva, próbáld újra. +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB felhasználva diff --git a/deploy/apps/lang/it.lang b/deploy/apps/lang/it.lang index bc1ea47a..51637080 100644 --- a/deploy/apps/lang/it.lang +++ b/deploy/apps/lang/it.lang @@ -683,6 +683,7 @@ Run setup again Esegui di nuovo la configurazione SD card %s Scheda SD %s SD card %s (hold: format) Scheda SD %s (tieni: formatta) SD card (tap to mount) Scheda SD (tocca per montare) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted Scheda SD inserita SD card lost - reinsert to recover Scheda SD persa - reinserirla SD card remounted Scheda SD rimontata @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD formattata - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB usati diff --git a/deploy/apps/lang/nl.lang b/deploy/apps/lang/nl.lang index 7240e4c2..0489fa0b 100644 --- a/deploy/apps/lang/nl.lang +++ b/deploy/apps/lang/nl.lang @@ -683,6 +683,7 @@ Run setup again Setup opnieuw uitvoeren SD card %s SD-kaart %s SD card %s (hold: format) SD-kaart %s (vasthouden: formatteren) SD card (tap to mount) SD-kaart (tik om te koppelen) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted SD-kaart geplaatst SD card lost - reinsert to recover SD-kaart verloren - plaats opnieuw SD card remounted SD-kaart opnieuw gekoppeld @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD geformatteerd - %s (MESHCOMOD) SD is busy - close tools and retry SD is bezig - sluit tools en probeer opnieuw SD removed - card-backed data cannot be saved SD verwijderd - kaartgegevens kunnen niet worden opgeslagen SD stayed busy - format cancelled, retry SD bleef bezig - formatteren geannuleerd, opnieuw proberen +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB gebruikt diff --git a/deploy/apps/lang/pt-br.lang b/deploy/apps/lang/pt-br.lang index a53d5819..3f17a643 100644 --- a/deploy/apps/lang/pt-br.lang +++ b/deploy/apps/lang/pt-br.lang @@ -683,6 +683,7 @@ Run setup again Executar configuração de novo SD card %s Cartão SD %s SD card %s (hold: format) Cartão SD %s (segure: formatar) SD card (tap to mount) Cartão SD (toque para montar) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted Cartão SD inserido SD card lost - reinsert to recover Cartão SD perdido - reinsira-o SD card remounted Cartão SD remontado @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD formatado - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB usados diff --git a/deploy/apps/lang/ro.lang b/deploy/apps/lang/ro.lang index 86d4772b..e07a9074 100644 --- a/deploy/apps/lang/ro.lang +++ b/deploy/apps/lang/ro.lang @@ -683,6 +683,7 @@ Run setup again Rulează configurarea din nou SD card %s Card SD %s SD card %s (hold: format) Card SD %s (ţine: formatare) SD card (tap to mount) Card SD (atinge pentru montare) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted Card SD introdus SD card lost - reinsert to recover Card SD pierdut - reintrodu-l pentru recuperare SD card remounted Card SD remontat @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD formatat - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB folosiţi diff --git a/deploy/apps/lang/ru.lang b/deploy/apps/lang/ru.lang index 78e21c51..1fd0bd30 100644 --- a/deploy/apps/lang/ru.lang +++ b/deploy/apps/lang/ru.lang @@ -683,6 +683,7 @@ Run setup again Запустить настройку снова SD card %s SD-карта %s SD card %s (hold: format) SD-карта %s (удерж.: формат.) SD card (tap to mount) SD-карта (нажмите для монтирования) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted SD-карта вставлена SD card lost - reinsert to recover SD-карта потеряна - переставьте её SD card remounted SD-карта перемонтирована @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD отформатирована - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u КБ занято diff --git a/deploy/apps/lang/sr.lang b/deploy/apps/lang/sr.lang index c379e9f9..77960dab 100644 --- a/deploy/apps/lang/sr.lang +++ b/deploy/apps/lang/sr.lang @@ -683,6 +683,7 @@ Run setup again Поново покрени подешавање SD card %s SD картица %s SD card %s (hold: format) SD картица %s (држи: формат) SD card (tap to mount) SD картица (додирни за монтирање) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted SD картица убачена SD card lost - reinsert to recover SD картица изгубљена - убаците поново SD card remounted SD картица поново монтирана @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD форматирана - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u KB заузето diff --git a/deploy/apps/lang/uk.lang b/deploy/apps/lang/uk.lang index 074a4641..f8a482b4 100644 --- a/deploy/apps/lang/uk.lang +++ b/deploy/apps/lang/uk.lang @@ -683,6 +683,7 @@ Run setup again Запустити налаштування знову SD card %s SD-картка %s SD card %s (hold: format) SD-картка %s (утрим.: формат.) SD card (tap to mount) SD-картка (торкніться для монтування) +SD card (unreadable - tap to retry) SD card (unreadable - tap to retry) SD card inserted SD-картку вставлено SD card lost - reinsert to recover SD-картку втрачено - вставте знову SD card remounted SD-картку перемонтовано @@ -695,6 +696,7 @@ SD formatted - %s (MESHCOMOD) SD відформатовано - %s (MESHCOMOD) SD is busy - close tools and retry SD removed - card-backed data cannot be saved SD stayed busy - format cancelled, retry +SD unreadable - format it as FAT32 on a computer SD unreadable - format it as FAT32 on a computer SF SF SF / CR / TX / AF SF / CR / TX / AF SPIFFS %u/%u KB used SPIFFS %u/%u КБ використано diff --git a/src/ui-touch/UITask.cpp b/src/ui-touch/UITask.cpp index 36a48443..0d4022c4 100644 --- a/src/ui-touch/UITask.cpp +++ b/src/ui-touch/UITask.cpp @@ -92,7 +92,9 @@ #endif #elif defined(TLORA_PAGER) #include // microSD (CS=21) on the shared radio/display SPI bus -- - // storage + file manager/WAV access; formatting stays disabled + // storage + file manager/WAV access. No sd_diskio.h/f_mkfs + // here: formatting is deliberately off on this board (the + // reasons are on the format-helper guard in the file manager). #define PIN_SD_CS PAGER_PIN_SD_CS // from TLoraPagerBoard.h, already visible via // MyMesh.h -> target.h -> TLoraPagerBoard.h above #include // pager ES8311 codec (notification tones + WAV playback) @@ -19995,6 +19997,27 @@ static void fmSdClickCb(lv_event_t* e) { if (s_sd_mounted) fmOpenStorage(&SD, "SD", "/"); } +#if defined(TLORA_PAGER) +// Recovery entry for a card the Pager can SEE (card-detect asserted) but cannot +// mount: exFAT/NTFS, or a damaged FAT. Without this the roots page renders no SD +// row at all (fmShowRoots below), so there is no way to tell "no card" from "card +// the firmware won't take", and no way to retry without a reboot. +// +// Deliberately NON-destructive. It clears the mount backoff and makes exactly the +// one vendor-compatible 4 MHz attempt fmSdTryMount() already makes — it does not +// add a retry ladder and never tears down the live shared display/radio bus. If +// that attempt fails the card needs formatting, and on this board that is a +// deliberate host-side task: see the format-helper guard below for why the in-app +// formatter stays off for the Pager. +static void fmSdPagerRetryMountCb(lv_event_t* e) { + if (lv_event_get_code(e) != LV_EVENT_CLICKED) return; + s_sd_retry_after_ms = 0; // explicit user retry — bypass the backoff + if (fmSdTryMount() && s_sd_mounted) { fmShowRoots(); return; } + if (g_lv.task) + g_lv.task->showAlert(TR("SD unreadable - format it as FAT32 on a computer"), 3600); +} +#endif + #endif // HAS_TDECK_GT911 || TLORA_PAGER || HAS_THINKNODE_M9 || HELTEC_LORA_V4_R8 (microSD mount helpers; the busy overlays below are generic LVGL) // Full-screen "busy" notice (copy/move/format). Pure LVGL — used by the generic paste path too. @@ -20022,6 +20045,24 @@ static void fmHideFormatOverlay() { if (s_fm_fmt_overlay) { popupClose(&s_fm_fmt_overlay); } } +// TLORA_PAGER is deliberately NOT in this list — the in-app formatter is omitted +// on the Pager, not merely unimplemented. Three reasons, in order of weight: +// 1. f_mkfs needs SD.end() + sdcard_init/uninit around it. That is a card and +// diskio lifecycle teardown on a bus the display AND the radio are actively +// driving, and this board's mount path is explicitly documented (fmSdTryMount +// above) to make ONE 4 MHz attempt and never tear the live shared bus down. +// The Arduino SD library never touches the SPI peripheral itself, so this is +// very likely fine — but "very likely" is not a basis for a one-way, whole-card +// erase, and it has never been run on Pager hardware. +// 2. There is no touchscreen, so the T-Deck's tap-to-open / hold-to-format split +// does not map. The nearest equivalent is holding ENTER on the focused row — +// an undiscoverable gesture that destroys the card, on a device where the +// encoder and ENTER are the only ways to move at all. +// 3. The recoverable case is already covered non-destructively: +// fmSdPagerRetryMountCb above surfaces a detected-but-unmountable card and +// retries the mount, and the alert it raises on failure points at the host. +// Formatting a card on a computer is a 30-second task with no such risk. Revisit +// only with a Pager in hand and a card that is safe to lose. #if defined(HAS_TDECK_GT911) || defined(HAS_THINKNODE_M9) || defined(HELTEC_LORA_V4_R8) // SD format helpers resume (Arduino SD, T-Deck + M9 + V4-R8) // Confirm callback: paint the formatting notice, then defer the (blocking) // f_mkfs to UITask::loop so the notice is on-screen before the loop freezes. @@ -21312,7 +21353,7 @@ static void fmShowRoots() { fmStyleRow(sd, COLOR_SUB); lv_obj_add_event_cb(sd, fmSdMountOrFormatCb, LV_EVENT_CLICKED, nullptr); } -#elif defined(TLORA_PAGER) // microSD row — browse only this pass, no format (see fmSdTryMount()) +#elif defined(TLORA_PAGER) // microSD row — browse + mount recovery, no in-app format // The card-detect line makes "not present" unambiguous, unlike the T-Deck (no detect // pin at all) -- so unlike its always-shown "tap to mount/format" fallback row, a bare // pager just shows no SD row at all rather than a row that can never succeed. @@ -21324,6 +21365,13 @@ static void fmShowRoots() { lv_obj_t* sd = lv_list_add_btn(s_fm_list, LV_SYMBOL_SD_CARD, sdl); fmStyleRow(sd, COLOR_TEXT); lv_obj_add_event_cb(sd, fmSdClickCb, LV_EVENT_SHORT_CLICKED, nullptr); + } else if (board.sdCardPresent()) { + // Detected but not mounted. Surfacing it (greyed) is the whole recovery path + // on this board: it distinguishes "card the firmware won't take" from the + // absent case above, and gives a retry that bypasses the mount backoff. + lv_obj_t* sd = lv_list_add_btn(s_fm_list, LV_SYMBOL_SD_CARD, TR("SD card (unreadable - tap to retry)")); + fmStyleRow(sd, COLOR_SUB); + lv_obj_add_event_cb(sd, fmSdPagerRetryMountCb, LV_EVENT_CLICKED, nullptr); } #endif #if defined(HAS_TANMATSU) || defined(HAS_TDISPLAY_P4) From 72fb10254fc063f525e5c304289f1e84d111c6c5 Mon Sep 17 00:00:00 2001 From: "Michael A. Cojocari" Date: Fri, 21 Aug 2026 15:43:24 -0400 Subject: [PATCH 5/5] docs: pager cards on the standalone flasher page, and what that page actually is (#289) Last item on oumike's list. deploy/flasher/ carried two manifests and no pager, so the board was missing from the standalone install page. It now has a card per radio variant, both pointing at latest-beta -- the pager is a beta-feed board, so latest/ is the wrong pointer for it, unlike the two stable boards already there. Each card names its radio and says so again in the body, because flashing an LR1121 build onto an SX1262 unit leaves the user with a device whose radio does not come up, and the two SKUs look identical. version is set to "beta" rather than a tag. These manifests point at a rolling feed, so any tag hardcoded here is wrong the moment the next build ships -- which is what happened to the two existing files, both still claiming beta_1. Worth fixing those separately or dropping the local copies entirely. Which leads to the caveat, now written down in deploy/README.md: no deploy script publishes deploy/flasher/. deploy-site.sh ships deploy/site/ only, and flasher.wadamesh.com 301s to the apex, so the page users actually reach is deploy/site/index.html -- which has covered every board for a while. The README also had the redirect backwards, claiming the apex redirects to the flasher. So this is parity for a directory that may be dead. Kaj reached the same conclusion independently in e2d07d8 and left it alone; the files are cheap and the ticket asked for them, but the real decision is wire it up or delete it, and that is now stated where someone will find it. Also refreshes TLORA_PAGER_PORT.md, which still listed the release pipeline as TODO (both envs have been in release.sh and gen-flasher-meta.py for a while) and still described CAP_SD/CAP_FILESYSTEM as 0 by design in four places, along with a deferred-SD list that has almost entirely landed. Only lock-screen wallpaper SD scanning is genuinely still T-Deck/M9-only. Adds a dated status section at the top; the milestone narrative below it is kept, since the war stories are why several non-obvious things are the way they are. Co-Authored-By: Claude Opus 5 --- TLORA_PAGER_PORT.md | 158 ++++++++++++++---- deploy/README.md | 21 ++- deploy/flasher/index.html | 22 ++- .../flasher/manifest-tlora-pager-lr1121.json | 13 ++ .../flasher/manifest-tlora-pager-sx1262.json | 13 ++ 5 files changed, 186 insertions(+), 41 deletions(-) create mode 100644 deploy/flasher/manifest-tlora-pager-lr1121.json create mode 100644 deploy/flasher/manifest-tlora-pager-sx1262.json diff --git a/TLORA_PAGER_PORT.md b/TLORA_PAGER_PORT.md index 17157513..08c1d8e7 100644 --- a/TLORA_PAGER_PORT.md +++ b/TLORA_PAGER_PORT.md @@ -5,6 +5,60 @@ Goal: run the **full** wadamesh UI + functionality on the **LilyGo T-LoRa Pager* existing boards so a UI change ships everywhere at once. This file is the running plan/status — update it as we go. +## Current status (2026-08-20) + +**The port has shipped.** Both radio variants debuted on the beta channel in +**beta_45** (community PR #149, @codemonkeybr) and are installable from +wadamesh.com; `README.md` and `DEVICES.md` list the pager as a supported beta +board rather than a request. Milestones ⓪-⑦, ⑨ and ⑩ are done. Only ⑦b (the +USB companion gate) and ⑧ (the on-device UI pass) are still open. + +Done since the milestone history below was written, and re-verified against the +code on 2026-08-20: + +- **microSD is fully wired.** `CAP_SD`/`CAP_FILESYSTEM` are **1** — the staged + per-call-site widening finished, so DataStore contacts/channels routing, the + 5000-message history ring, map-tile SD packs, settings/crash export and the + About-page `/BINS` firmware export all work. See risk 1h for what that + replaced. +- **Release pipeline complete** — both envs in `release.sh`, both flasher + manifests generated, `FIRMWARE_OTA_ENV` set on each (worklist ⑨). +- **SD recovery without formatting**: a detected-but-unmountable card now shows + a greyed tap-to-retry row. In-app format remains deliberately omitted on this + board; the reasoning lives on the format-helper guard in `UITask.cpp`. +- **"Save update bin to SD" reaches the pager** via `CAP_SD && CAP_OTA` + (upstream e2d07d8) rather than a board-name list. Note that feature is spread + over six `#if` regions: e2d07d8 converted two, which left the pager with the + button but no worker — a hang plus a use-after-free on the status label, and + it still compiled. All six are now identical; do not widen them piecemeal. + +Still open, in priority order: + +1. **⑧'s actual stated scope — the 222 px vertical-layout audit and the + screen-by-screen focus-nav coverage pass — has still never been started** + (risk 8). Everything that landed under M8 was reactive bug-fixing from + user-reported issues. This remains the single biggest item in the port. +2. **USB companion device-profile frame is still untested** (⑦b). Remove the + temporary `[DISP]` register readback in `ST7796LCDDisplay::begin()` once it + passes. +3. Lock-screen wallpaper SD scanning is still T-Deck/M9-only (risk 1h). +4. `deploy/flasher/` now carries pager cards + manifests for parity, but **no + deploy script publishes that directory** (`deploy-site.sh` ships + `deploy/site/` only) and `flasher.wadamesh.com` 301s to the apex. Decide + whether to wire it into a deploy target or retire it. + +Risk 11 (keyboard/encoder scroll not repainting) is **accepted as +workaround-final**: the Alt+turn free-scroll gesture is the intended fix for +this hardware. + +--- + +## Milestone history + +The narrative below is kept as the port's working record — the war stories are +why several non-obvious things are the way they are. Where it conflicts with +the section above, the section above is current. + Status: **M7's UI portion DONE — boot logo, full LVGL UI, QWERTY keyboard nav and rotary encoder all VERIFIED WORKING on real hardware (2026-07-07)**, after root-causing the intermittent black screen to the ST7796 @@ -30,7 +84,8 @@ milestone: the radio-settings blur-autosave lag (risk 12), the encoder not scrolling open dropdowns (fixed 2026-07-08, commit `4bbfcb5`), the keyboard backlight never being wired up (risk 9, fixed 2026-07-10), and microSD file manager + WAV-picker support (risk 1h, fixed 2026-07-10, scoped — DataStore -SD routing/chat-history/tiles/wallpaper/backup remain deferred). An +SD routing/chat-history/tiles/backup were still deferred at the time and have +all since landed; only wallpaper scanning is left, see risk 1h). An unread-message LED notification was investigated and explicitly decided against (risk 13) — this board has no onboard LED at all. Risk 11 (keyboard/encoder-driven scroll not repainting) was **ACCEPTED as @@ -601,7 +656,7 @@ existing boards. Notes: **Gate:** all three envs build — verified. - [x] ⑥ **UITask wiring**: `device_caps.h` got its `TLORA_PAGER` cap block (no touch, no rotate, no large-screen, GPS 1, OTA 1, lock-screen 1; `CAP_SD`/ - `CAP_FILESYSTEM` corrected to 0 — see below) plus widened `CAP_KEYBOARD`/ + `CAP_FILESYSTEM` set to 0 at the time — both are 1 today, see risk 1h) plus widened `CAP_KEYBOARD`/ `CAP_KEYPAD_NAV` derivations to recognize `HAS_PAGER_KEYBOARD`/ `TLORA_PAGER`. `UITask.cpp` changes, all pager-gated: KEYPAD indev registered by widening the Tanmatsu branch's `#if` to @@ -624,9 +679,10 @@ existing boards. Notes: vs. the milestone doc's assumptions, all found by compiling rather than assumed — see risks 1h/1i/1j: - `CAP_SD`/`CAP_FILESYSTEM` looked right from the hardware (real microSD - slot) but the actual mount code is hardcoded to `HAS_TDECK_GT911`, not - truly `CAP_SD`-generic — set back to 0, real support is unscheduled - follow-up. + slot) but the mount code was hardcoded to `HAS_TDECK_GT911`, not truly + `CAP_SD`-generic — set back to 0 for this milestone. *(Superseded: the + call sites were widened over the following passes and both macros are 1 + today — risk 1h.)* - `navMaybeRebuild()` (populates the LVGL focus group every screen) wasn't reachable on the pager's own cap combination — added a `#elif defined(TLORA_PAGER)` arm; without it the KEYPAD indev would have @@ -653,11 +709,23 @@ existing boards. Notes: above): still untested. **SD storage: DONE** — real mount, browse, read/write/delete, and insert/remove detection all confirmed on hardware (risk 1h). (DataStore/NVS-level SD use — routing contacts/channels to the - card — is a separate, still-deferred feature, not part of this bring-up - gate.) Remove the temporary `[DISP]` register readback in + card — was a separate feature outside this bring-up gate; it has since + landed, see risk 1h.) Remove the temporary `[DISP]` register readback in `ST7796LCDDisplay::begin()` once the USB piece passes. - [~] ⑧ **On-device UI pass** — ACTIVE: nav-coverage audit screen by screen (every interactive control reachable via focus group — the Tanmatsu work paved this), chat layout at 222 px, map pan via encoder/keys, fonts legibility at 480-wide, plus fixing any weird UI/keyboard behaviors surfaced by manual testing (human provides photos/repro steps). -- [ ] ⑨ **Release pipeline**: add the env:binname pair to `release.sh` `ENVS`, flasher manifest (`deploy/flasher/manifest-tlora-pager.json`), OTA env name via `FIRMWARE_OTA_ENV`. Separate PR. +- [x] ⑨ **Release pipeline** — DONE (verified against the scripts 2026-08-20). + Both envs are in `scripts/release.sh`'s `ENVS` + (`tlora_pager_lr1121_...:wadamesh-tlora-pager-lr1121`, + `tlora_pager_sx1262_...:wadamesh-tlora-pager-sx1262`); both manifests are + generated by `scripts/build/gen-flasher-meta.py` + (`manifest-tlora-pager-{lr1121,sx1262}.json`); both envs set + `FIRMWARE_OTA_ENV`. The install page (`deploy/site/index.html`, which + `flasher.wadamesh.com` 301s to) carries an install button + .bin download for + each variant off the beta feed. Shipped to users in **beta_45**. + One leftover, not user-facing: the legacy static `deploy/flasher/index.html` + still lists only the T-Deck and Heltec V4 cards and has no pager manifests + next to it. That page is no longer the install path — decide whether to add + the two cards for parity or retire the directory. - [x] ⑩ (Optional, cheap) `tlora_pager_sx1262_...` env for SX1262-variant owners — **DONE, hardware-verified 2026-07-13** (`tlora_pager_sx1262_companion_radio_touch`, all 4 envs green; see `TLORA_PAGER_PORT_MILESTONES.md`'s Milestone 10 for the full writeup, including the `target.h` missing-include bug found + fixed). Radio gate (M7 step 3) confirmed on real hardware: user sent + received messages on public, a custom `#` channel, and DM. ## UI-changes inventory (what actually changes in `src/ui-touch/`) @@ -673,9 +741,11 @@ existing boards. Notes: | `navMaybeRebuild()` reachability | Added `#elif defined(TLORA_PAGER)` arm — was unreachable, would've left focus group permanently empty | small | done (bug fix) | | Vertical budget | Audit `STATUSBAR_H`, `TABBAR_H`, `CHAT_KB_H`, modal/chat height helpers for 222 px | **the real work** | deferred to M8 on-device (risk 8) | | Focus-nav coverage | Screen-by-screen pass that every control is in `s_nav_group` | medium, on-device | deferred to M8 | -| device_caps.h | New `CAP_*` block: no touch, hw keyboard, encoder, 480×222, GPS, OTA, lock-screen; SD/filesystem left 0 by design — real SD support added via widened individual call sites instead (see risk 1h) | trivial | done | +| device_caps.h | New `CAP_*` block: no touch, hw keyboard, encoder, 480×222, GPS, OTA, lock-screen. `CAP_SD`/`CAP_FILESYSTEM` were 0 while SD support was staged in per call site, and are now **1** (see risk 1h) | trivial | done | | Keyboard backlight (`pagerKeyboardSetBacklight()`) | `updatePagerKbBacklight()` tick + Settings → Keyboard cycle row (off/on/auto) | small | done (risk 9) | -| microSD (file manager + WAV picker) | `fmSdTryMount()`/`fmShowRoots()`/`fmIsAudio()` etc. widened to `\|\| defined(TLORA_PAGER)`; DataStore SD routing, chat-history cap, tile/wallpaper/backup SD use still deferred | medium | done, scoped (risk 1h) | +| microSD (file manager + WAV picker) | `fmSdTryMount()`/`fmShowRoots()`/`fmIsAudio()` etc. widened to `\|\| defined(TLORA_PAGER)`; DataStore routing, 5000-msg history, tiles and backup export all landed later. Only wallpaper SD scanning is still T-Deck/M9-only | medium | done (risk 1h) | +| microSD recovery row | `fmSdPagerRetryMountCb` — a detected-but-unmountable card renders greyed with a tap-to-retry that clears the mount backoff. No in-app format on this board, by decision | small | done | +| Save update bin to SD | About-page `/BINS` firmware export widened to the pager (`sdFwWorkerRun`); board-specific wording kept as separate TR() keys so the T-Deck's translated Launcher strings are not orphaned | small | done | | Chat bubble Enter/Backspace (`handleHwKey()` ~28808) | Enter on a focused bubble opens the Ack/Mention/Copy/Info/Block menu (`navEnterBubble()`); Backspace jumps to the newest message when the scroll-to-bottom button is showing | small | done | | Shift/Caps (`PagerKeyboard.cpp`) | Held Shift = momentary uppercase; held Alt+Shift = chord (see below for what it does) | small | done | | Accent-variant popup keyboard nav | Fn+Space arms it; encoder walks variants; encoder click/Enter confirms; Backspace cancels (`s_accentnav_active`/`accentNavRestyle()`/`accentNavConfirm()`) | medium | done | @@ -776,29 +846,51 @@ MQTT, OTA) is resolution-agnostic or already keyed off caps. page-scroll backward/up instead. Fixed by negating once in `PagerEncoder.cpp`'s `pagerEncoderReadDelta()` (the driver, not UI code) so every consumer inherits the corrected sense from one place. -1h. **`CAP_SD`/`CAP_FILESYSTEM` are 0 for the pager despite real microSD - hardware — a latent gap in `device_caps.h`'s own abstraction, not a pager - bug.** **File manager browsing + WAV notification-sound picker RESOLVED - 2026-07-10** (commits `8c7fb6a`/`1514e76`), scoped deliberately: `CAP_SD` - turned out to gate ~37 call sites (file manager, WAV picker, DataStore - contacts/channels routing, tile-cache SD fallback, wallpaper scanning, - settings backup, screenshots), so flipping the macro itself would have - silently turned on ~30 unvetted, T-Deck-only-tested features at once. - Instead `CAP_SD`/`CAP_FILESYSTEM` stay 0 by design, and only the ~7 - specific call sites needed for browsing + WAV picking were widened with - `|| defined(TLORA_PAGER)` — see those commits for the full categorized - site list. Added `pagerSdCardPresent()` (XL9555 `PAGER_EXPAND_SD_DET`, - confirmed-inverted polarity) and a pager `sdSharedSPI()` (reuses - `TFT_eSPI::getSPIinstance()`, the same bus the radio already shares). - Format support is explicitly out of scope (no `f_mkfs`/`sd_diskio.h` pulled - in) — the pager's SD row is tap-to-open only. Hardware-verified: mount, - browse, read/write/delete, insert/remove detection, and picking a WAV from - SD as a notification sound all confirmed on real hardware. **Still not - done** (unscheduled follow-up, deliberately deferred): DataStore - contacts/channels routing to SD (`setSecondaryFS`, what Tanmatsu/T-Deck - do to dodge SPIFFS GC stalls), the `MAX_UI_MESSAGES_SD` chat-history cap - bump, map-tile SD fallback/offline tile packs, lock-screen wallpaper SD - scanning, and settings/telemetry backup export-import to SD. +1h. **microSD — RESOLVED; `CAP_SD`/`CAP_FILESYSTEM` are now 1.** They were 0 + from M6 onward, which looked wrong against the hardware (there is a real + slot) but was deliberate: `CAP_SD` gates ~37 call sites (file manager, WAV + picker, DataStore contacts/channels routing, tile-cache SD fallback, + wallpaper scanning, settings backup, screenshots), so flipping the macro in + one go would have switched on ~30 unvetted, T-Deck-only-tested features at + once. The support was staged in instead, a group at a time: + - **File manager browsing + WAV notification-sound picker** — 2026-07-10 + (commits `8c7fb6a`/`1514e76`), the first ~7 sites, widened with + `|| defined(TLORA_PAGER)`. Added `pagerSdCardPresent()` (XL9555 + `PAGER_EXPAND_SD_DET`, confirmed-inverted polarity) and a pager + `sdSharedSPI()` (reuses `TFT_eSPI::getSPIinstance()`, the same bus the + radio already shares). Hardware-verified: mount, browse, + read/write/delete, insert/remove detection, and picking a WAV off the card + as a notification sound. + - **The rest** — verified in code 2026-08-20: DataStore contacts/channels + routing (`src/main.cpp`'s `setSecondaryFS`/`useSdStorage` blocks admit + `TLORA_PAGER`), the `MAX_UI_MESSAGES_SD` 5000-message history ring + (`uiDataFsIsSdCard()` admits the pager), map-tile SD fallback and offline + packs (the Map "tiles from SD" toggle; the tile-cache fix shipped in + beta_46), settings backup export/import plus crash-dump export + (`doExportBackupFile`), and firmware export to `/BINS` via About → "Save + update bin to SD". + + With those vetted, both macros were flipped to 1 and `device_caps.h` + describes the hardware again. Cleanup left over: the belt-and-braces + `#if CAP_SD || defined(TLORA_PAGER)` at several sites is now redundant and + can be collapsed to plain `CAP_SD`. + + **In-app format stays deliberately out of scope** on this board (no + `f_mkfs`/`sd_diskio.h` pulled in). The full reasoning now lives on the + format-helper guard in `UITask.cpp` so it is found from the code, not only + here: `f_mkfs` needs an `SD.end()` + `sdcard_init`/`uninit` lifecycle + teardown on the live shared display/radio bus; there is no touchscreen, so + the T-Deck's hold-to-format gesture does not map; and it has never been run + on pager hardware. The *recoverable* case is covered non-destructively + instead — a card the expander's SD_DET sees but that will not mount renders + a greyed **"SD card (unreadable - tap to retry)"** row + (`fmSdPagerRetryMountCb`) which clears the mount backoff and retries the + single 4 MHz attempt, then points the user at formatting on a computer. + + **Still not done**: lock-screen wallpaper SD scanning — that picker block is + still `HAS_TDECK_GT911 || HAS_THINKNODE_M9`, so the pager keeps its baked + 480x222 wallpaper (`lockscreen_wallpaper_pager_rgb565.h`) with no way to + choose one off the card. 1i. **`navMaybeRebuild()` was unreachable for the pager in the first M6 pass.** It's only called under `#if defined(HAS_TANMATSU) ... #elif CAP_TRACKBALL ...`, neither of which the pager's cap combination matches diff --git a/deploy/README.md b/deploy/README.md index 1534d0ce..988d321a 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -5,8 +5,8 @@ Distribution stack for wadamesh: a **VPS nginx origin behind Cloudflare**. ``` tiles.wadamesh.com →CF (HTTP, edge-cached) → nginx → OpenStreetMap / OpenTopoMap firmware.wadamesh.com →CF (cache bins) → nginx → /srv/wadamesh/firmware -flasher.wadamesh.com →CF (HTTPS) → web flasher (TODO — see below) -wadamesh.com →CF (HTTPS) → landing page (later) +flasher.wadamesh.com →CF (HTTPS) → 301 → wadamesh.com +wadamesh.com →CF (HTTPS) → nginx → /srv/wadamesh/site ``` **Map tile styles.** The default `/{z}/{x}/{y}.jpg` route serves **OpenStreetMap** @@ -67,11 +67,18 @@ highest `beta_`, and (once OTA-over-Wi-Fi is re-enabled) pulls ## Done -- **Web flasher** ✅ at `flasher.wadamesh.com` — `deploy/flasher/` (esp-web-tools / - Web Serial, board picker, manifests pointing at the rolling `/latest/` merged - bins; `release.sh` refreshes `/latest/` each publish). -- **Apex** `wadamesh.com` 301-redirects to the flasher — **activate by pointing - the `wadamesh.com` A record at the VPS** in Cloudflare (it's still on the parking IP). +- **Web flasher** ✅ — the guided install page at `wadamesh.com`, served from + `deploy/site/` and published by `scripts/deploy-site.sh` (esp-web-tools / Web + Serial, per-board install buttons + .bin downloads, manifests generated per + release by `scripts/build/gen-flasher-meta.py` into the `/latest/` and + `/latest-beta/` feeds that `release.sh` refreshes each publish). +- **`flasher.wadamesh.com` 301-redirects to the apex** (see + `deploy/nginx/flasher.wadamesh.com.conf`) — it is an alias, not its own page. +- **`deploy/flasher/`** is the original standalone flasher page. **No deploy + script publishes it** — `deploy-site.sh` ships `deploy/site/` only — so it is + effectively an offline/local copy kept in parity by hand. Retire it or wire it + into a deploy target; until then, treat `deploy/site/index.html` as the only + install page users can reach. ## TODO before public launch diff --git a/deploy/flasher/index.html b/deploy/flasher/index.html index d5ad86ff..19f7ce5b 100644 --- a/deploy/flasher/index.html +++ b/deploy/flasher/index.html @@ -47,6 +47,10 @@ .note b{color:var(--ink)} a{color:var(--teal-ink)} footer{color:var(--mut);font-size:.85rem;padding:0 20px 40px;text-align:center} + .card h2 .beta{display:inline-block;margin-left:8px;padding:1px 7px;border-radius:999px;font-size:.7rem; + font-weight:700;letter-spacing:.04em;text-transform:uppercase;color:#8a5a12;background:#fdf0d8; + border:1px solid #f0d6a8;vertical-align:middle} + .card .warn{color:#b4631a;font-size:.85rem} .unsupported{display:none;color:#b4631a} body.no-serial .unsupported{display:block} body.no-serial esp-web-install-button{display:none} @@ -86,11 +90,27 @@ Use Chrome or Edge on desktop (Web Serial). +
+

T-LoRa Pager Beta LR1121

+

ESP32-S3 QWERTY + rotary encoder, no touchscreen.

+

Only for units with the LR1121 radio — SX1262 units need the other Pager card.

+ + Use Chrome or Edge on desktop (Web Serial). +
+
+

T-LoRa Pager Beta SX1262

+

ESP32-S3 QWERTY + rotary encoder, no touchscreen.

+

Only for units with the SX1262 radio — LR1121 units need the other Pager card.

+ + Use Chrome or Edge on desktop (Web Serial). +
How it works: plug the device in over USB, click Connect, pick the serial port, and let it flash — a clean full install. On a T-Deck, hold the trackball while tapping reset if it - doesn't enter download mode on its own. Works in Chrome / Edge on desktop. Want the guided + doesn't enter download mode on its own. The T-LoRa Pager ships with either an LR1121 or an SX1262 + radio — check yours and pick the matching card, since the wrong build leaves the radio dead; both + install from the beta channel. Works in Chrome / Edge on desktop. Want the guided version (incl. running under bmorcelli's Launcher)? See wadamesh.com.
diff --git a/deploy/flasher/manifest-tlora-pager-lr1121.json b/deploy/flasher/manifest-tlora-pager-lr1121.json new file mode 100644 index 00000000..fca81268 --- /dev/null +++ b/deploy/flasher/manifest-tlora-pager-lr1121.json @@ -0,0 +1,13 @@ +{ + "name": "wadamesh — LilyGo T-LoRa Pager (LR1121)", + "version": "beta", + "new_install_prompt_erase": true, + "builds": [ + { + "chipFamily": "ESP32-S3", + "parts": [ + { "path": "https://firmware.wadamesh.com/latest-beta/wadamesh-tlora-pager-lr1121-merged.bin", "offset": 0 } + ] + } + ] +} diff --git a/deploy/flasher/manifest-tlora-pager-sx1262.json b/deploy/flasher/manifest-tlora-pager-sx1262.json new file mode 100644 index 00000000..e214ded0 --- /dev/null +++ b/deploy/flasher/manifest-tlora-pager-sx1262.json @@ -0,0 +1,13 @@ +{ + "name": "wadamesh — LilyGo T-LoRa Pager (SX1262)", + "version": "beta", + "new_install_prompt_erase": true, + "builds": [ + { + "chipFamily": "ESP32-S3", + "parts": [ + { "path": "https://firmware.wadamesh.com/latest-beta/wadamesh-tlora-pager-sx1262-merged.bin", "offset": 0 } + ] + } + ] +}