Files
twislaandClaude Opus 5.5 7b5df713ad
CI / build (pull_request) Successful in 1m38s
Site / build (pull_request) Successful in 10s
Shell: only its own replies, Apps by their names, and rm as Unix has it (#67)
The Shell shows the replies to its own commands and nothing else. The
console knows who each line is printed for (Console::As, Console::origin):
a command run from the Shell prints as the Shell's, and what answers it
later from another task carries that along (ls, tasks, du, cp, update
check, sd list, screenshot, gemini get). Ctrl+b shows everything instead.
This replaces the ten-second window, which was a guess.

An App's name with a capital opens it (Notes, Irc, Wifi, Gnss, Gemini, Lora,
Storage, Shell, System, Settings), from the Shell and from the consoles.

rm needs -r for a folder, here and over the consoles. In the Shell a file,
or a folder with something in it, is asked about unless -f; an empty folder
with -r goes without a word.

The Shell now hands its line to the main loop to run: run from inside the
key handler, rm on a folder overflowed the loop's stack and crashed the
device. `info` says which App is in front.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
2026-10-07 11:35:29 +02:00

8.1 KiB

+++ title = "Drive the UI from your desk" description = "Press keys, take screenshots, fake inputs and test the awkward paths (updates, crashes, fixed IPs, crowded folders) without touching the device." weight = 4 [extra] tag = "Console" +++

Everything the keyboard can do, a command can do, and everything on the screen can be looked at remotely. That makes the Cardputer testable like a web page: act, look, repeat.

Keys

key up|down|left|right|select|back|home|del|tab|space|help
key a        # any single character: it is typed

Two things to know before you use them:

  1. A name key does not know is select. key sleect presses Enter. A single character is typed as that character; anything else that is not a known name is treated as Enter. Check what you type.
  2. A key that wakes a dark screen only wakes it. The device's power policy swallows the key press that turns the screen back on, as it does for the real keyboard: the first key after the screen went off does nothing else. Send key back (harmless) first, or keep the screen on with the normal and short commands below.

Fn combinations, modifiers and the compose key have no command: the arrows are key up|down|left|right, and key back is the back key (` on the device). Text is typed one character at a time.

key help opens the help panel (Fn+h on the device): the keys of the screen that is showing. A screenshot of it is the quickest way to learn what a screen accepts, and it is how every screen's list was checked. Any key but the arrows closes it.

Open an App by its name

Notes        # an App's name, with a capital: opens it
Shell        # Irc Wifi Gnss Gemini Lora Storage Notes Shell System Settings
info         # ...and `app: Notes` says which App is in front

Far better than key home, some key down and key select: it doesn't depend on where the Launcher's selection was.

Look before you press

Take a screenshot before any key that deletes, renames or installs. A blind sequence of key commands goes wrong the moment the screen is not where you think it is, and the screen is often not where you think it is: a Toast, a dialog that has not closed, a different App. A sequence that was meant to open a note once renamed real data instead.

scripts/rdbg.py key home          # to the Launcher
scripts/rdbg.py screenshot a.png  # look: is it the Launcher?
scripts/rdbg.py key down
scripts/rdbg.py key select
scripts/rdbg.py screenshot b.png  # look again before the next destructive step
  • Check the App in front before typing anything. info prints app: <name>. A crash restarts the device into the Launcher, and a script that goes on typing is typing somewhere else: one of this project's own test scripts sent a word to an IRC channel that way.
  • Prefer reading a state to assuming it: info, ls <folder>, cat <file>, irc dump, gnss status, lora status, wifi status, update status.
  • Test on a scratch folder on the card, not on your real files.
  • For anything that deletes (rm, a delete dialog), ls first and ls after.

Keep the screen on, and make timeouts short

short     # screen dims after 5 s, turns off after 10 s: to test the screen policy
normal    # back to 30 s and 60 s
burst     # five Toasts at once: to test notifications
sound on | sound off

Fake the inputs

Each of these puts something in, without the outside world:

Command What it does
lora inject <hex> [rssi] [snr] A packet into the LoRa Scanner as if the radio had received it. Nothing is sent
irc say <buffer> <text> Types into an IRC buffer, commands included: irc say 0 /join #test
log <text> Adds a line to a test IRC log
gnss send <sentence> Sends an NMEA sentence to the GNSS receiver (the checksum is added), to configure it
gemini get <url> Fetches a page and reports header, size, certificate and heap use, without the App
gemini trust <host> <port> <sha256> Pins a certificate by hand
sd fill <folder> <count> Makes that many small files in a folder, to test a crowded one (the Storage App shows the first 256)
wifi add <ssid><TAB><password> Adds a Saved Network, so credentials stay out of the repository

Test the update path

An update that goes wrong is the case you most want to rehearse, and the firmware can make it go wrong on purpose:

update status                       # what the device runs, what failed here before, the daily check, heap
update check | update list          # look at the server: the latest release, or the last ten
update pretend v0.9.0               # take the running version to be v0.9.0: the latest release now counts as "new"
update damage cut 50000             # the next download is cut after 50000 bytes
update damage flip 100000           # ...or has the byte at offset 100000 damaged
update install v0.11.0              # try the install
update probe git.twis.la            # is that server's certificate accepted? (the two ISRG roots only)
update daily                        # forget today's daily check: it runs again at the next tick
update pretend off                  # back to the real version
  • A damaged download must be refused cleanly: the Update Service checks the signature after the first 160 bytes and the image hash at the end, so a cut or a flipped byte must end in a refusal with nothing switched. Check info afterwards: both slots, and update: confirmed.
  • An undamaged install really installs the release, into the other slot, and the device restarts into it. Your build stays in the slot it was in until the next update overwrites it, and the console's setting and token are untouched: the release has the console too.
  • The server is read by the device itself, with Wi-Fi up; the download is one TLS connection, about 52 KB of heap at its peak, so IRC steps aside (see the memory limit). status: heap in the stream shows it happen.

For crashes during Probation, see Crashes and Safe Mode.

Test a network change without losing the console

The Debug Console runs over the Wi-Fi you are about to change, which is the usual way to lock yourself out. A trial IP setting takes care of it:

wifi ip MyNet 10.39.39.50/24 10.39.39.1 try 60     # use this address for 60 s...
wifi ip keep                                       # ...and keep it, if you could still reach the device

If you do not send wifi ip keep in time, the device goes back to the previous setting by itself, and the console comes back with it.

Measure

info       # firmware, uptime, last start reason, heap now/lowest/largest block, chip temperature, Wi-Fi, SD faults, both app slots
tasks      # each task over the next second: state, priority, least free stack, CPU share; each core's load; main-loop passes
net        # bytes each network service has read and written since start

tasks takes a second to answer. A low number in the stack column is a risk (the System App shows it in the warning colour under 512 bytes). loop spin on|off makes the main loop spin without resting, to compare load and radio noise. And the status: heap line every 10 seconds in the stream is the cheapest memory trace there is: watch it while you do the thing you suspect.

task             st   pri  stack   cpu% core
loopTask         R      1   1828    1.3 1
wifi             B     23   4072    0.7 0
debug            B      1   3088    0.5 -1
...
load: core 0 2 %, core 1 1 %
loop: 50 passes in the last second, chip 35.3 C

The System App shows the same, live, on the device.

Radio experiments

lora preset <name> and lora custom <MHz> <BW kHz> <SF> <CR> <sync hex> [preamble] change what the receiver listens to (receive only: the radio never transmits), lora sweep on [from] [to] [step] takes a survey, and lora noise test [gnss|quiet] runs a Sweep under one changed condition at a time, with Wi-Fi off for a moment, to find what raises the noise floor. lora probe finds the radio and reports its chip, oscillator, antenna switch, interrupt line and noise floor. Details in the command reference.