The documentation had kept up feature page by feature page and nowhere else. Now also: - the home page's App cards (notes of any size, pictures, sharing) and its note (the Shell, the VPN, the screenshot key); - the guide: VPN in the Status Bar and in Settings, the three keys that work everywhere, screenshots of the Shell, a picture, sharing, the VPN page and the help panel; - three how-tos: move files with your phone, set up the VPN, take a screenshot; where the files are and what things cost in memory; - the FAQ: screenshots, and what listens on the network; - the README's opening: what the firmware does today; - the glossary: Tunnel, Sharing, Screenshot; - every milestone's status line, with the version each thing shipped in. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
4.2 KiB
+++ 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.
Without a PC, the device does both by itself now: Fn + p saves a screenshot to the card (how-to), and w in the Storage App serves the card to a browser (how-to). What follows is the scripted way, with checksums.
get: card to PC
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
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 answersput: ready <size>orput: 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
.partfile, 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, orput: 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
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 and the devlog, were taken this way.
- With a number, it saves to the card instead:
screenshot 5(orscreenshot 0) writes a PNG to/screenshotson the SD card after that many seconds, as the Shell does. A barescreenshotover 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.
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.
reset: restart now
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.)