Public Access
An App in the Launcher that runs the same commands as USB serial and the Debug Console, trusted like the first. It shows what the console prints while it is open, through a second ring of the console's that exists only meanwhile; Ctrl+b keeps only what follows your own commands. Tab completes a command's name from the firmware's help text, Fn with up and down recalls earlier lines, Alt with up and down scrolls back. `rm` asks first in the Shell, `rm -f` doesn't. Nothing is kept once the App is left. `screenshot [seconds]` saves the screen as a PNG in /screenshots on the card, now or after a pause: written a row at a time, indexed colour with RGB332 as the palette, in one stored deflate block. 487 host tests (11 new: the PNG writer, the Shell's log filter, Tab). Checked on the device over the Debug Console: commands, Tab, history, a screenshot fetched and decoded on the PC, rm with and without the question, a delayed screenshot of another screen. 12 KB of flash; 7 KB of heap while open. Decisions Q204 to Q212 in docs/milestones/S1.md. Safe Mode: #77. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
62 lines
3.9 KiB
Markdown
62 lines
3.9 KiB
Markdown
+++
|
|
title = "Files, screenshots and the SD card"
|
|
description = "Copy files to and from the card, take a screenshot, fetch a core dump and restart the device, all over Wi-Fi, with checksums."
|
|
weight = 3
|
|
[extra]
|
|
tag = "Console"
|
|
+++
|
|
|
|
These are the **binary commands**: a text header line, then raw bytes. The console task answers them itself, so they keep working when the main loop is stuck. `scripts/rdbg.py` handles each one on the PC side; the protocol is given too, for your own tools.
|
|
|
|
## `get`: card to PC
|
|
|
|
```sh
|
|
scripts/rdbg.py get /gnss/tracks/20261004-142530.gpx # saved here, under its own name
|
|
scripts/rdbg.py get /captures/lora/capture.pcap my-capture.pcap
|
|
```
|
|
|
|
The device answers `get: data <size>`, then exactly `<size>` bytes, then `get: end`. A path it cannot open (missing, or a folder) gives `get: error cannot open <path>`. The script prints the size and the speed.
|
|
|
|
## `put`: PC to card
|
|
|
|
```sh
|
|
scripts/rdbg.py put roro9stack-v0.12.0.ota # to /updates/roro9stack-v0.12.0.ota
|
|
scripts/rdbg.py put notes.txt /notes/from-the-pc.txt # to a path you choose
|
|
```
|
|
|
|
The default destination is `/updates/<name>`, so this is also the way to **install an update from the SD card without touching the device**: `put` the `.ota` file, then `scripts/rdbg.py install /updates/<name>`.
|
|
|
|
The device does a few things you want from a file transfer:
|
|
|
|
- the PC sends the **size and the SHA-256** first (`put <path> <size> <sha256>`); the device answers `put: ready <size>` or `put: error <why>` (no card, **not enough space**: it wants the size plus 64 KB free, or a path or size it refuses);
|
|
- it writes to a **temporary `.part` file**, creating missing folders, and only **renames it into place after the whole file has been read back from the card and its SHA-256 matches**: the checksum covers what is on the card, not what arrived;
|
|
- a write the card refuses is **retried up to 3 times**, cutting the file back to the last good byte, and gives up rather than leave a hole in the middle;
|
|
- it ends with `put: done <path> <size> B`, or `put: error <why>` and **a closed connection** (so the rest of the file is never read as commands). A failed transfer leaves nothing on the card.
|
|
|
|
Speed is about 300 KB/s. The same transfer exists over USB serial, for a device with no Wi-Fi: `scripts/sd_put.sh <file> [card path]` (about 30 seconds for 1.6 MB, with the card left in).
|
|
|
|
## `screenshot`: the screen as a PNG
|
|
|
|
```sh
|
|
scripts/rdbg.py screenshot ui.png # 480x270: the 240x135 screen at 2x
|
|
```
|
|
|
|
The device sends `screenshot: rgb332 <width> <height>` and then **one byte per pixel**: the frame the UI composed off-screen, in RGB332 (RRRGGGBB), the way M5GFX stores an 8-bit sprite. The script expands it and doubles it into a PNG.
|
|
|
|
- It is read **as it stands**, while the UI may be drawing, so it can **tear**. It is for looking at, not for pixel-exact comparison.
|
|
- It is the real thing: the screenshots on this site, in the [user guide](/guide/) and the [devlog](/devlog/), were taken this way.
|
|
- **With a number, it saves to the card instead:** `screenshot 5` (or `screenshot 0`) writes a PNG to `/screenshots` on the SD card after that many seconds, as the [Shell](/guide/shell/) does. A bare `screenshot` over the console is the binary one above.
|
|
- Its main use is in a loop: send a key, wait a moment, take a screenshot, look. See [Drive the UI](/dev/debug/drive-the-ui/).
|
|
|
|
## `coredump get`: the crash dump
|
|
|
|
The raw contents of the core dump partition: `coredump: data <size>`, the bytes, `coredump: end`, or `coredump: none`. `scripts/rdbg.py coredump` fetches and decodes it in one go: see [Crashes and Safe Mode](/dev/debug/crashes/).
|
|
|
|
## `reset`: restart now
|
|
|
|
```sh
|
|
scripts/rdbg.py reset
|
|
```
|
|
|
|
The console prints `debug: restarting now` and restarts the chip after a moment. It does not go through the main loop, so it works when the loop is stuck. (The text command `reboot` does go through the main loop: a clean restart. `boot other` restarts into the other app slot: a manual rollback.)
|