diff --git a/PROVIDER_CATALOG.md b/PROVIDER_CATALOG.md index a606db4..f9839bf 100644 --- a/PROVIDER_CATALOG.md +++ b/PROVIDER_CATALOG.md @@ -47,14 +47,13 @@ renamed. Names must match MeshCore's canonical `config.json` mismatches. Notes on the mapping: -- **ESP32 offers `flash-wipe` only — because of an offset mismatch, not flashability.** - Our `-update.bin` (the MCUboot-signed app) *is* serial-flashable, but only at ZephCore's - app-slot offset `0x20000` (`slot0_partition: partition@20000` in every ESP32 overlay; - MCUboot itself owns `0x0`–`0x20000`). Mesh America's `flash-update` hardcodes `0x10000` - (MeshCore's slot layout) and the catalog schema has no offset override, so it would write - the app inside our MCUboot partition and the board wouldn't boot. `flash-wipe` (full merged - image at `0x0`) is offset-independent and always works. Enabling `flash-update` would mean - moving our MCUboot partition to `0x10000` to match MeshCore — out of scope. +- **ESP32 offers both `flash-wipe` and `flash-update`.** `flash-wipe` = the `-merged.bin` + (MCUboot + app) written at `0x0`. `flash-update` = the `-update.bin` (MCUboot-signed app) + written at `0x10000`. As of 2026-07-09 ZephCore's ESP32 app slot is at `0x10000` (see + `boards/esp32//partitions.overlay`), matching Mesh America's fixed flash-update + offset — so app-only updates that keep settings now work. `build.sh` ships `-update.bin` + for both ESP32 companion and repeater roles. **Classic-ESP32 (T-Beam)** uses simple boot + (no MCUboot), produces no `-update.bin`, and is naturally flash-wipe-only. - **Companion firmware** is one image serving BLE + USB; it's listed under both `companionBle` and `companionUsb` (same file). Native-Linux companions use a custom `companionTcp` role. diff --git a/build.sh b/build.sh index 1949834..a7006b7 100644 --- a/build.sh +++ b/build.sh @@ -205,14 +205,20 @@ print(str(size // 1048576) + "MB") # MCUboot/sysbuild boards: only the merged (MCUboot + signed app) # image is bootable on a bare/existing chip at 0x0. The signed app # alone requires MCUboot already present and must land at 0x10000 — - # publishing it standalone as a "plain .bin" bricks boards when - # flashed the same way as classic-ESP32's self-contained zephyr.bin - # (see GH #42). Don't ship it. + # never publish it as a bootable "plain .bin" (bricks boards when + # flashed like classic-ESP32's self-contained zephyr.bin, see GH #42). python -m esptool --chip "$chip" merge-bin \ --output firmware/"$board_clean_for_path"-companion-"$COMMIT_HASH"-merged.bin \ --flash-mode dio --flash-freq 40m --flash-size "$FLASH_SIZE" \ 0x00000 build/mcuboot/zephyr/zephyr.bin \ 0x10000 build/zephcore/zephyr/zephyr.signed.bin + + # Signed app image (slot0 @ 0x10000). App-only update payload: used by + # the Mesh America configurator's "flash-update" (esptool writes it at + # 0x10000 over an existing MCUboot) and as a WiFi-OTA payload. NOT + # bootable standalone — never flash at 0x0 (see GH #42). + cp build/zephcore/zephyr/zephyr.signed.bin \ + firmware/"$board_clean_for_path"-companion-"$COMMIT_HASH"-update.bin fi if [[ $2 == "repeaters" ]]; then @@ -258,9 +264,11 @@ print(str(size // 1048576) + "MB") 0x00000 build/mcuboot/zephyr/zephyr.bin \ 0x10000 build/zephcore/zephyr/zephyr.signed.bin - # Signed app image for WiFi OTA: uploaded to MCUboot slot1 via the - # repeater's /update page. NOT bootable standalone — never flash this - # at 0x0 (see GH #42). It is ONLY valid as an OTA payload. + # Signed app image (slot0 @ 0x10000). App-only update payload: the + # Mesh America configurator's "flash-update" (esptool writes it at + # 0x10000 over an existing MCUboot) and the WiFi-OTA payload uploaded + # to slot1 via the repeater's /update page. NOT bootable standalone — + # never flash this at 0x0 (see GH #42). cp build/zephcore/zephyr/zephyr.signed.bin \ firmware/"$board_clean_for_path"-repeater-"$COMMIT_HASH"-update.bin fi diff --git a/gen_provider_catalog.py b/gen_provider_catalog.py index bf47b3c..16e3d69 100644 --- a/gen_provider_catalog.py +++ b/gen_provider_catalog.py @@ -163,6 +163,13 @@ def files_for(assets, board, token): merged = find_file(assets, stem, token, variant, r"-merged\.bin") if merged: out.append(("flash-wipe", merged, "Full install (bootloader + firmware)")) + # App-only update, written at 0x10000 over an existing MCUboot. Our slot0 + # is at 0x10000 (matches Mesh America's fixed flash-update offset), so this + # is valid. Classic-ESP32 (simple boot, no MCUboot) has no -update.bin and + # is naturally skipped by the presence check. + update = find_file(assets, stem, token, variant, r"-update\.bin") + if update: + out.append(("flash-update", update, "Update (app only; keeps settings)")) elif kind == "linux": elf = find_file(assets, stem, token, variant, r"") if elf: