+++ title = "Debug Builds" description = "What a Debug Build is, how to build and flash one, how its token works, and why you should keep one in the fallback slot." weight = 1 [extra] tag = "Start here" +++ ## What it is A Debug Build is built from the same source as a release, with the `cardputer-adv-debug` environment (it `extends` `cardputer-adv` in `platformio.ini`) and `-DRORO_DEBUG`. Differences: - the **Debug Console** on TCP **2323** (next page); - extra commands, only meant for testing: crash on purpose, fake an installed version, damage a download, inject a LoRa packet, fill a folder with files (see the [command reference](/dev/debug/commands/)); - the version ends in **`+debug`** (`scripts/version.py`) wherever the version shows: Settings, `info`, the Update Service. A `+debug` version compares **equal** to its release counterpart, so going between the two is never refused as a downgrade. **It is compiled out of release builds, not switched off by a setting.** A console that runs commands, presses keys and reboots the device is a remote control; in a release build nothing listens and the code is not there. ## Build and flash one Everything runs in Docker (see [Build, test and release](/dev/build/build-and-test/)). Over USB: ```sh scripts/flash.sh --debug # builds cardputer-adv-debug, uploads, opens the serial monitor ``` Once a Debug Build is on the device, every later one can go over Wi-Fi, with no cable: ```sh export RORO_OTA_HOST=10.39.39.12 # the address Settings > Firmware shows scripts/flash.sh --debug --ota # builds, signs and pushes; the device installs and restarts ``` The device's address is on **Settings → Firmware** ("Push to", which also gives port 3232, the update port). The Debug Console is on the same address, port 2323. See [Flash and update](/dev/build/flash/) for the update side. ## The token The console asks for a secret first. It is **128 random bits**, made the first time any build runs (`scripts/_docker.sh`), kept in `~/.config/roro9stack/debug-token` next to the update-signing key, and passed into the build container as `RORO_DEBUG_TOKEN`. `scripts/debug_flags.py` compiles it into the firmware, and **refuses to build a Debug Build without one**, rather than fall back on a default. - It is **never committed.** Releases have no console, so nothing of it is published: CI builds a Debug Build on a pull request to prove it still compiles, but never publishes it, because each one carries its builder's token. - It guards against **the network**, not against someone who holds the device: anyone with USB access can flash anything anyway ([ADR 0003](/dev/decisions/0003-own-signature-check-not-secure-boot/)). - To change it, delete the file and build again; the new token goes into the next Debug Build you flash. ## Keep a Debug Build in the other slot The device has two app slots, so an update never overwrites the running firmware. If a new firmware crashes during [Probation](/dev/build/how-an-update-works/), the device goes **back to the previous one**, whatever that is. As long as you develop on Debug Builds, **the firmware a crash falls back to has the console too**, so a bad update never costs you remote access. Pushing a *release* build over a Debug Build leaves the Debug Build in the other slot until the next update overwrites it. So the habit is: develop on Debug Builds, release by tag, and think twice before pushing a release over the only Debug Build you have. ## Releases and Debug Builds - A Debug Build shows the latest release in Settings → Firmware but **never installs it**: that would replace the console with a release that has none. Update a Debug Build from the PC with `scripts/flash.sh --debug --ota`. - A Debug Build still checks and lists releases, which is useful for testing the update path: `update pretend` makes a released version count as newer (see [Drive the UI](/dev/debug/drive-the-ui/)). - **Safe Mode** (after 3 crashes in a row) keeps the Debug Console running, so a crash loop is something you fix remotely: see [Crashes and Safe Mode](/dev/debug/crashes/). The reasoning is in [ADR 0004](/dev/decisions/0004-debug-console-in-debug-builds/).