Trim task stacks and buffers by measurement: +15 KB with IRC up

Peak stack use was measured through each task's worst case (an
ECDSA-checked install over Wi-Fi and from SD, get/put, a core dump
fetch, an IRC TLS handshake); stacks are now peak plus about 2 KB: loop
8 -> 6 KB, update 8 -> 5, storage 10 -> 6, irc 8 -> 6. The Debug Build's
console ring goes 6 -> 4 KB, serial TX 2 -> 1 KB, the GNSS UART buffer
1 KB -> 512 B.

On the device, with IRC on TLS: 46 KB free (was 31), an 18 KB low (was
9.4). The re-run of every worst case left at least 1.6 KB of stack free
in each task.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
2026-10-04 23:02:35 +02:00
co-authored by Claude Opus 5.5
parent 578a39d3c1
commit db265fb757
9 changed files with 14 additions and 11 deletions
@@ -1,6 +1,6 @@
# A Debug Console over Wi-Fi, in Debug Builds only
The goal of Firmware Updates is to manage the device without a cable, and that includes finding out what went wrong. So a **Debug Build** (`cardputer-adv-debug`, `-DRORO_DEBUG`, version suffix `+debug`) adds a **Debug Console** on TCP 2323: the serial console, over Wi-Fi. A client sends a token as its first line, then gets the last 6 KB of console output (boot messages included), every new line live, and runs the same commands as the serial port, plus a few that only make sense remotely. ESP-IDF's own log lines are teed into it.
The goal of Firmware Updates is to manage the device without a cable, and that includes finding out what went wrong. So a **Debug Build** (`cardputer-adv-debug`, `-DRORO_DEBUG`, version suffix `+debug`) adds a **Debug Console** on TCP 2323: the serial console, over Wi-Fi. A client sends a token as its first line, then gets the last 4 KB of console output (boot messages included), every new line live, and runs the same commands as the serial port, plus a few that only make sense remotely. ESP-IDF's own log lines are teed into it.
It's compiled out of release builds entirely, rather than switched off by a setting. A console that runs commands is a remote control: in a release build, nothing listens.
@@ -9,7 +9,7 @@ It's compiled out of release builds entirely, rather than switched off by a sett
- **Console, not Serial.** All human-readable output goes through `console`, which writes to the USB port and, in a Debug Build, to a ring buffer the Debug Console drains. Writes never wait for USB: a host that's attached but not reading used to stall the main loop for up to 2 s per line.
- **Commands run on the main loop.** The socket lives on the Debug Console's own task, which only queues command lines. The main loop runs them, as it does serial commands, so they touch Apps and Services from the one task allowed to.
- **The token** is 128 random bits in `~/.config/roro9stack/debug-token`, made by the first build and passed into the container. It's never committed; a Debug Build refuses to compile without one. Like the OTA key, it guards against the network, not against someone holding the device.
- **One client at a time**, to keep memory flat (about 6 KB for the ring, 6 KB of task stack).
- **One client at a time**, to keep memory flat (4 KB for the ring since M2, 6 KB of task stack).
- **Binary commands are answered on the console's own task**, not queued: `get`/`put` (SD card files, run as one Storage Service job each so card access stays on the storage task, with TCP doing the flow control), `screenshot` (the 32 KB RGB332 frame the UI composes into, read as it stands, so it may tear), `coredump get` and `reset`. These keep working when the main loop is stuck. A failed `put` closes the connection, so the rest of the file is never read as commands.
## Keep a Debug Build in the fallback slot
+2 -2
View File
@@ -1,12 +1,12 @@
# M2 — GNSS
**Status:** steps 1–6 done on the device (branch `m2`). Open: the heap floor (below).
**Status:** steps 1–6 done on the device (branch `m2`). Open: the heap floor during a TLS handshake (below).
## Measured
- **Cold start** (`$PCAS10,2`) to a 3D Fix, by a window: **73 s**, 5 satellites used of 8 in view. A restart of the ESP32 alone keeps the receiver's Fix (the Cap stays powered).
- By a window: 3D Fix from GPS, GLONASS, Galileo and BeiDou, up to 14 of 17 satellites used, HDOP 1.0–1.3.
- **Heap, Debug Build, GNSS on:** 82 KB free with Wi-Fi up; with IRC on TLS, **33 KB free and a 12.6 KB low** during the handshake. The floor is 40 KB, and v0.2.1 (before OTA) measured a 79 KB low. Not a GNSS cost: the OTA and Debug Build work added the `update` (8 KB) and `debug` (6 KB) task stacks, the 6 KB console ring, a larger `storage` stack (10 KB, for SD signature checks), 4 KB of serial buffers, mDNS and two TCP servers. To decide before M2 closes.
- **Heap, Debug Build, GNSS on:** with IRC on TLS, first 33 KB free and a 12.6 KB low (floor 40 KB; v0.2.1 had a 79 KB low). Not a GNSS cost: the OTA and Debug Build work added task stacks, a console ring, serial buffers, mDNS and two TCP servers. **Trimmed by measurement:** each task's peak stack was measured through its worst case (an ECDSA-checked install over Wi-Fi and from SD, get/put, a core dump fetch, an IRC TLS handshake), then stacks were set to peak plus about 2 KB: loop 8→6 KB, update 8→5, storage 10→6, irc 8→6; the console ring 6→4 KB, serial TX 2→1 KB, GNSS UART 1 KB→512 B. **After:** 46 KB free with IRC connected, an 18 KB low. The steady state clears the floor; the TLS handshake peak doesn't yet. Next candidates: mbedTLS dynamic buffers (custom sdkconfig), one network task for the update and debug listeners, mDNS on demand.
**Goal:** the device knows where it is and what time it is without a network: a GNSS Service in the background, a GNSS App with the position and a sky view of the satellites, the clock set from satellites when there's no NTP, and Tracks recorded to the SD card.