diff --git a/docs/index.md b/docs/index.md index 2bc0f937..1373d9bc 100644 --- a/docs/index.md +++ b/docs/index.md @@ -6,7 +6,7 @@ Below are a few quick start guides. - [Frequently Asked Questions](./faq.md) - [CLI Commands](./cli_commands.md) -- [Easy Full-Firmware Update over LoRa](./ota_easy.md) +- [Easy LoRa OTA: ESP32 full images and nRF52 deltas](./ota_easy.md) - [GPS Tracking](./gps_tracking.md) - [Companion Protocol](./companion_protocol.md) - [Packet Format](./packet_format.md) diff --git a/docs/ota_easy.md b/docs/ota_easy.md index 09766e5c..a690cadf 100644 --- a/docs/ota_easy.md +++ b/docs/ota_easy.md @@ -1,7 +1,17 @@ -# Easy full-firmware update over LoRa (ESP32) +# Easy firmware updates over LoRa -This guide shows the shortest manual path for sending a **full firmware image** from a computer to a -MeshCore node over LoRa. It uses this temporary OTA channel: +This guide shows the shortest manual path for sending firmware from a computer to a MeshCore node over +LoRa. Choose the package type for the **destination** node: + +| Destination | Update type | Files needed to build the `.mota` | Installer | +| --- | --- | --- | --- | +| ESP32 | Full firmware | New non-merged application `.bin` | ESP32 A/B firmware slots | +| nRF52 | In-place delta | Exact running `firmware.hex` and new `firmware.hex` | Exact-board OTAFIX bootloader | + +An nRF52 node cannot install an ESP32-style full-image container. It deliberately accepts only an in-place +delta built against its exact running firmware. + +## Temporary OTA channel used in this guide | Setting | Value | | --- | --- | @@ -26,24 +36,17 @@ location and change it when necessary. ## Before you start -You need: +Both paths require: -- A standard, non-logging Keymind OTA build on the source and destination nodes. Logging and MQTT builds do - not include LoRa OTA. Use the WiFi or USB connection to update those. -- An OTA-capable ESP32 destination with an A/B partition table. nRF52 has a single application slot and - cannot install this guide's full-image container; it requires an in-place delta plus the exact matching - OTAFIX bootloader. On RAK4631 repeaters, the OTA target is named - `RAK_4631_repeater_no_external_sensors_lora_ota`; it retains built-in battery monitoring but omits optional - external environmental/GPS sensor packages to fit the safe in-place update limit. -- The new, non-merged `.bin` application firmware for the destination's exact board **and role**. Do not - package an ESP32 `-merged.bin` factory image. +- Standard, non-logging Keymind OTA firmware on the source, destination, and intermediate nodes. Logging + and MQTT builds do not include LoRa OTA; use WiFi or USB to update those. - A source node connected to the computer by USB serial. - Overlapping `tempradio` windows on the source, destination, and every repeater needed between them. LoRa OTA packets are generated, received, and relayed only while `tempradio` is active. If any required window closes, the transfer stops making progress and can resume during a later overlapping window. -## 1. Install `motatool` +## Install `motatool` Install Rust if necessary, then install the standalone packaging and serving tool: @@ -52,7 +55,11 @@ git clone https://github.com/vk496/motatool cargo install --path ./motatool ``` -## 2. Package the full firmware +## ESP32: package a full firmware image + +The destination must be an OTA-capable ESP32 with an A/B partition table. Download or build the new +non-merged `.bin` application for the destination's exact board **and role**. Do not use an ESP32 +`-merged.bin` factory image. Put the application firmware in a working directory, then build a full `.mota` container. For example: @@ -68,7 +75,91 @@ identity trailer so `motatool` and the destination can verify the target, hardwa Do not continue if `motatool verify` reports a failure. -## 3. Start the temporary OTA channel +## nRF52: package an in-place delta + +### 1. Install and check the OTAFIX bootloader + +This is a one-time prerequisite. Install the OTAFIX bootloader built for the destination's **exact board** +from the +[nRF52 OTAFIX in-place-delta repository](https://github.com/mikecarper/Adafruit_nRF52_Bootloader_OTAFIX/tree/feature/ota-delta-apply). +Follow that repository's board-specific installation and erase instructions. If it does not contain the +destination's exact board, this LoRa install path is not yet available for that board; never substitute a +similar board's bootloader. + +Before preparing or downloading a LoRa update, run this on the destination: + +```text +ota self +``` + +Continue only if the reply includes: + +```text +bootloader: apply OK +``` + +The reply also contains the running firmware's `base_hash`. Save it for the package check below. A stock, +legacy, or older OTAFIX bootloader without `.mota` in-place-apply support will report that apply support is +missing, and `ota install` will refuse to reboot into it. + +### 2. Keep the exact current and new application images + +You need the raw `.pio/build//firmware.hex` from the build that is **actually running**, plus +the corresponding `firmware.hex` from the new build. Save the current file before building the new version, +because PlatformIO reuses that path. For example: + +```bash +# Save this immediately after building/flashing the version now running on the node. +cp .pio/build/Heltec_t114_repeater/firmware.hex ./Heltec_t114_repeater-running.hex + +# After checking out and building the new version, save its image separately. +cp .pio/build/Heltec_t114_repeater/firmware.hex ./Heltec_t114_repeater-new.hex +``` + +Replace `Heltec_t114_repeater` with the destination's exact PlatformIO environment. The two images must be +for the same board and role, and both must contain their `EndF` trailers. Do not pass a release `.uf2` or +BLE-DFU `.zip` to `motatool`; those are installation containers rather than raw application images. + +Keeping a file with the same version label is not enough: the base must be byte-for-byte identical to the +running application. The hash check in the next step proves that it is the right file. + +On RAK4631 repeaters, use the +`RAK_4631_repeater_no_external_sensors_lora_ota` environment. It retains built-in battery monitoring but +omits optional external environmental/GPS sensor packages so the delta fits the safe in-place workspace. + +### 3. Build and check the in-place delta + +```bash +mkdir -p ./motas +motatool build \ + --base ./Heltec_t114_repeater-running.hex \ + --fw ./Heltec_t114_repeater-new.hex \ + --patch-type in-place \ + --out-dir ./motas +motatool verify ./motas/*.mota +``` + +`motatool` prints the generated filename. Inspect that file: + +```bash +motatool inspect ./motas/GENERATED_FILENAME.mota +``` + +Check all three of these before serving it: + +- `codec_id` is `2 (detools-in-place)`. +- `base_hash` is the same 8-byte value reported by the destination's `ota self` command. +- The numeric `target_id` exactly matches `target:` in the destination's `ota status`, and the hardware and + firmware version identify the intended board and role. If `inspect` shows `N/A` for the human-readable + target name, the tool's name table is older than that environment; the numeric IDs still must match. + +The default `--inplace-memory 0x98000` and 4096-byte segment size match the supported MeshCore OTAFIX +builds; do not override them for this normal nRF52 flow. Do not continue if verification or any identity +check fails. + +## Transfer and install either package + +### 1. Start the temporary OTA channel On the source node, destination node, and every intermediate repeater, run: @@ -83,7 +174,7 @@ If you administer the destination over LoRa, the controller used to send later ` able to communicate on this temporary channel. For unattended nodes, use synchronized `tempradioat` entries instead of manually starting the windows. Ensure the nodes' clocks are set before using `tempradioat`. -## 4. Serve the update from the computer +### 2. Serve the update from the computer Close any serial terminal using the source node's USB port, find its device name, and start the server: @@ -91,12 +182,12 @@ Close any serial terminal using the source node's USB port, find its device name motatool serve --dir ./motas --serial /dev/ttyACM0 -v ``` -Replace `/dev/ttyACM0` with the source node's serial device. `motatool` attaches the folder to the source -node, and the source advertises the full update over LoRa while its temporary-radio window is active. +Replace `/dev/ttyACM0` with the source node's serial device. `motatool` attaches the folder to the source, +which advertises the update over LoRa while its temporary-radio window is active. Leave this command running until the destination finishes downloading. -## 5. Find and download the update +### 3. Find and download the update On the destination node, check its state and ask for nearby updates: @@ -105,8 +196,9 @@ ota status ota ls ``` -Discovery is asynchronous. Wait a few seconds and run `ota ls` again if the list is initially empty. Find -the entry marked `[yours]` and `full`, then use its displayed number. If it is entry 1, run: +Discovery is asynchronous. Wait a few seconds and run `ota ls` again if the list is initially empty. Select +the entry marked `[yours]`: it should say `full` for the ESP32 path or `delta` for the nRF52 path. If it is +entry 1, run: ```text ota pull 1 flash @@ -119,10 +211,13 @@ ota status ``` The update is ready when the status says `ready to install`. OTA is deliberately the lowest-priority mesh -traffic, so a busy channel can make a full-image transfer take longer than the example window. If necessary, -start another overlapping `tempradio` window; the download resumes rather than starting over. +traffic. At the temporary-radio settings in this guide, allow roughly **one hour** for a typical ESP32 full +image over a quiet, direct link. That is a planning estimate, not an upper bound: repeaters, retries, weak +links, and normal mesh traffic can extend it well past an hour. The 120-minute example window is +intentional. If necessary, start another overlapping `tempradio` window; the download resumes rather than +starting over. -## 6. Verify and install +### 4. Verify and install Once the destination reports `ready to install`, run: @@ -130,8 +225,12 @@ Once the destination reports `ready to install`, run: ota install ``` -The destination verifies the complete firmware again before approving it. If verification succeeds, it -reboots and applies the update. If verification fails, it keeps the current firmware and reports an error. +The destination verifies the complete package again before approving it. ESP32 installs the full image into +its inactive A/B slot. nRF52 checks the base hash and bootloader capability, then reboots into OTAFIX; the +bootloader independently rechecks the package, applies the delta in place, and verifies the resulting image. +Pre-install failures leave the running firmware unchanged and report the reason. If power is lost after an +nRF52 in-place apply has begun, OTAFIX will not boot a partial image; it enters recovery DFU so a known-good +application can be restored. After the node returns, reconnect on its normal radio channel and confirm: @@ -144,11 +243,16 @@ ota status - **Nothing appears in `ota ls`:** confirm that `motatool serve` is still running and every required node has an active `tempradio 909.950,125,5,5,120` window. - **The update is marked `[other hw]`:** it is for a different board or firmware role. Do not install it. +- **An nRF52 node does not list a full update:** this is intentional. nRF52 accepts only an in-place delta. +- **nRF52 reports no bootloader apply support:** install the exact-board in-place-delta OTAFIX bootloader + before trying LoRa OTA. +- **nRF52 reports a base mismatch:** the file passed to `--base` is not the exact application running on + the destination. Rebuild the delta from the correct saved `firmware.hex`. - **The download stalls:** check the source, destination, and intermediate repeaters. Restart matching, overlapping temporary-radio windows if one expired. - **The serial port is busy:** close the serial terminal before starting `motatool serve`. -- **The destination rejects the package:** verify that you used the non-merged application image with the - `EndF` trailer and that `motatool verify` succeeds. +- **The destination rejects the package:** verify the source files, their `EndF` trailers, the package's + target/hardware identity, and the result of `motatool verify`. For additional commands and safety details, see [the full OTA user guide](ota_user_guide.md). For protocol and container internals, see [the OTA protocol specification](ota_protocol.md).