Public Access
/dev/ has Debug Builds and the Debug Console (builds and the token, the console and its protocol, files and screenshots, driving the UI, crashes and Safe Mode, the command reference), Build, test and release (including how an update works), the architecture decisions and the milestone plans. Generated from the repository by site/tools/gen_dev_docs.py: the ADRs, the milestones, the README's sections, and the command reference, read from the firmware's own `help` text. The pages are committed (Zola cannot read outside its folder); the Site workflow checks they are current, and now also runs when src/main.cpp changes. M0, M1 and CONTEXT.md are not published. README: the gnss commands that the table lacked. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
42 lines
3.0 KiB
Markdown
42 lines
3.0 KiB
Markdown
+++
|
|
title = "Firmware Updates over Wi-Fi and from the SD card"
|
|
description = "Install new firmware without a USB cable. Push it from the PC over Wi-Fi, or drop it on the SD card. Unsigned images are refused, and a broken update rolls back by itself."
|
|
weight = 10
|
|
|
|
[extra]
|
|
docs = true
|
|
source = "docs/milestones/OTA.md"
|
|
tag = "OTA"
|
|
+++
|
|
**Goal:** install new firmware without a USB cable. Push it from the PC over Wi-Fi, or drop it on the SD card. Unsigned images are refused, and a broken update rolls back by itself.
|
|
|
|
## Decisions (design round 2026-10-03)
|
|
|
|
| # | Decision |
|
|
|---|---|
|
|
| Q52 | Two sources: **push over Wi-Fi** from the PC, and **from the SD card**. Pulling from Gitea releases is deferred. |
|
|
| Q53 | **Signed Update Files** (ECDSA P-256 over SHA-256). The private key stays in `~/.config/roro9stack/`, and the firmware embeds the public key (ADR 0003). |
|
|
| Q54 | The device **always listens** for pushes on the LAN while Wi-Fi is Connected. *Revised in M2:* it was announced over mDNS as `roro9stack-<id>.local`; mDNS was removed to save RAM (it never crossed the dev box's routed network anyway). Pushes go to the IP shown in Settings → Firmware. |
|
|
| Q55 | New firmware runs on **Probation**. It's confirmed once booted, UI drawn, Services started, 30 s without a crash, and Wi-Fi connected (if configured). Otherwise **Rollback**. A Toast reports either outcome. |
|
|
| Q56 | **Downgrades are allowed**, with "older than the installed version" shown. |
|
|
| Q57 | A valid push **installs right away**: progress screen, then reboot. The reboot waits for Text Entry to end, 60 s at most. |
|
|
|
|
## Done when
|
|
|
|
- `scripts/ota_keygen.sh` creates the key pair once. The public key is committed; the private key never is.
|
|
- `scripts/flash.sh --ota` builds, signs and pushes to `roro9stack-<id>.local`. The device shows progress, reboots, and a Toast confirms the new version.
|
|
- An Update File with a bad signature, a truncated or corrupted image, or no signature is refused, and the device keeps running.
|
|
- Settings → About → **Update from SD** lists the `.ota` files in `/updates` and installs one.
|
|
- A firmware that crashes during Probation rolls back to the previous version, and says so after the reboot.
|
|
|
|
## Work breakdown
|
|
|
|
1. **Update File format** (host-tested): header (magic, format, version, image size, SHA-256), signature, image. A streaming parser that hashes as it goes and decides accept / refuse / downgrade. The signature verifier sits behind an interface, so tests can inject one.
|
|
2. **PC side:** key generation, `make_ota.py` (wraps `firmware.bin` into a signed `.ota`), and the push client. `flash.sh --ota` ties them together.
|
|
3. **Device:** the Update Service.
|
|
- A listener on TCP 3232 plus mDNS.
|
|
- Writes the image to the inactive app slot, with the ECDSA check through mbedTLS.
|
|
- A progress screen, and a reboot that waits out Text Entry.
|
|
4. **Probation and Rollback:** the health checks, confirming the image, and detecting a rollback after reboot to report it.
|
|
5. **Update from SD:** the same parser, fed from the Storage Service's task (all card access stays there).
|