cardputer-adv-debug (-DRORO_DEBUG, version +debug) adds a Debug Console: after a token line, a client gets the last 6 KB of console output, live lines (ESP-IDF logs included) and the serial commands. The socket task only queues lines; the main loop runs them. Release builds compile none of it. The token lives in ~/.config/roro9stack/debug-token, created by _docker.sh and passed into the container. All output now goes through `console`, which never waits for USB: a host that was attached but not reading stalled the main loop up to 2 s per line. New commands everywhere: info (slots with their versions from NVS, since the framework stamps its own into each image), tasks, reboot, boot other, log level, help. scripts/rdbg.py is the client; flash.sh --debug builds it; CI builds both variants. ADR 0004. Verified on the device: USB-flashed, then updated over Wi-Fi to a Debug Build that confirmed on Probation; both slots hold Debug Builds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
roro9stack
A multi-app firmware for the M5Stack Cardputer ADV with the Cap LoRa-1262. It's a Meshtastic-compatible mesh messenger, plus Wi-Fi tools, IRC, GNSS and more. Licensed GPL-3.0.
- Domain language: CONTEXT.md
- Decisions: docs/adr/
- Milestones: docs/milestones/
Requirements
Only Docker is needed. PlatformIO and the ESP32 toolchain run inside a container, and are cached in the roro9stack-pio Docker volume. The first build downloads about 1 GB and takes a few minutes.
Build and test (local CI)
scripts/ci.sh
This runs the host-side unit tests (test/, native environment), then builds the firmware. The output is .pio/build/cardputer-adv/firmware.factory.bin.
Flash
-
Connect the Cardputer by USB-C.
-
Run:
scripts/flash.sh # auto-detects the port; or: scripts/flash.sh /dev/ttyACM1This uploads the firmware, then opens the serial monitor. Quit the monitor with
Ctrl+C.
If the upload can't connect, put the device in download mode: hold G0 (the button next to the screen) while plugging in USB, or while pressing reset. Then retry.
If you get "permission denied" on the port, your user needs access to the serial device. Run this once, then log out and back in:
sudo usermod -aG dialout "$USER"
Firmware Updates over Wi-Fi (OTA)
Once the Cardputer runs an OTA-capable firmware (flashed once over USB), updates can go over Wi-Fi:
scripts/ota_keygen.sh # once: creates the signing key (see ADR 0003)
scripts/flash.sh --ota 10.39.39.12 # build, sign and push; or set RORO_OTA_HOST
The device shows the push address in Settings → Firmware. It installs a correctly signed update right away, restarts (waiting up to 60 s if you're typing), and runs the new firmware on Probation. If the new firmware crashes, or can't reconnect Wi-Fi within 3 minutes, it rolls back to the previous one and says so.
To install from the SD card instead, copy the .ota file from .pio/build/cardputer-adv/ into /updates on the card, then use Settings → Firmware. With the Cardputer on USB, the card can stay in: scripts/sd_put.sh <file.ota> sends it over the serial console into /updates (about 30 s for 1.6 MB, checked with SHA-256 before it's renamed into place; SD_PUT_DEBUG=1 shows the console while it runs).
The private key lives in ~/.config/roro9stack/ota-key.pem and must never be committed. If it's lost, generate a new pair and flash once over USB.
Development aids
scripts/serial_log.sh [seconds] [command…] records the serial output, and can send commands to the firmware first. For example, scripts/serial_log.sh 30 short sleep:12 burst sets short screen timeouts, waits 12 s, then sends a burst of Toasts.
| Command | Effect |
|---|---|
burst |
Publishes 5 Notifications at once |
key up|down|left|right|select|back|home, or key <char> |
Injects a key press |
sound on / sound off |
Toggles the Sound setting (beep + LED) |
short / normal |
Screen timeouts 5 s / 10 s, or 30 s / 60 s |
wifi add <ssid><TAB><password> |
Adds a Saved Network (so credentials stay out of the repo) |
log <text> |
Appends a line to a test IRC Log (/irc/dev/#test/<date>.log) |
sd list |
Lists the files of each Storage Clean-up category |
cat <path> |
Prints the first ~1.2 KB of a file on the SD card |
irc start |
Starts the IRC Service (normally done by opening the IRC App) |
irc say <buffer> <text> |
Types into a Buffer, commands included (irc say 0 /join #test) |
irc dump |
Prints IRC status, memory, and the last lines of each Buffer |
wifi status |
Prints Wi-Fi state, network, signal, clock and free heap |
info |
Firmware, uptime, last start reason, memory, Wi-Fi, and both app slots with their versions and OTA states |
tasks |
FreeRTOS tasks: state, priority, lowest free stack, CPU share |
reboot / boot other |
Restart, or restart into the other app slot (a manual Rollback) |
log level <0-5> |
ESP-IDF log level |
help |
Lists the commands |
scripts/flash.sh stops a running serial log first, since it would hold the port.
Debug Builds and the Debug Console
scripts/flash.sh --debug (USB) or scripts/flash.sh --debug --ota <ip> (Wi-Fi) installs a Debug Build: the same firmware plus the Debug Console on TCP 2323 (ADR 0004). Then, with RORO_OTA_HOST set to the device's IP:
scripts/rdbg.py # interactive: the console backlog, live lines, and commands
scripts/rdbg.py info # one command and its reply
scripts/rdbg.py -b tasks # the same, after the backlog (boot messages and so on)
Every command above works there too. The token is in ~/.config/roro9stack/debug-token, made by the first build; keep developing on Debug Builds, so the firmware a Rollback returns to always has the console.