+++ 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 `, then exactly `` bytes, then `get: end`. A path it cannot open (missing, or a folder) gives `get: error cannot open `. 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/`, 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/`. The device does a few things you want from a file transfer: - the PC sends the **size and the SHA-256** first (`put `); the device answers `put: ready ` or `put: error ` (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 B`, or `put: error ` 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 [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 ` 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 `, 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.)