diff --git a/.pi/skills/test-xteink-firmware/SKILL.md b/.pi/skills/test-xteink-firmware/SKILL.md new file mode 100644 index 0000000000..dff77f99e8 --- /dev/null +++ b/.pi/skills/test-xteink-firmware/SKILL.md @@ -0,0 +1,105 @@ +--- +name: test-xteink-firmware +description: "Build and interactively test Xteink ESP32-C3 firmware in the native emulator. Use when validating firmware UI, buttons, screenshots, serial output, SD behavior, or networking." +--- + +# Test Xteink Firmware + +## Overview + +Build firmware for an Xteink device, boot it in the native emulator, and validate behavior through serial logs, physical controls, screenshots, SD state, and network access. + +## Prerequisites + +Point `XTEINK_QEMU_REPO` at a prepared QEMU checkout containing `dist/qemu-native`: + +```sh +export XTEINK_QEMU_REPO=${XTEINK_QEMU_REPO:-../qemu} +export XTEINK_EMU_STATE=/tmp/xteink-firmware-$UID +export XTEINK_EMU_SD=/tmp/xteink-firmware-$UID.img +``` + +The emulator exits with setup instructions when its native QEMU distribution is missing. + +## Workflow + +1. Inspect the firmware project and use its documented build command. Locate the resulting ESP32-C3 application binary; for PlatformIO this is commonly: + + ```sh + pio run + export XTEINK_FIRMWARE=.pio/build/default/firmware.bin + ``` + +2. Create a persistent FAT32 SD image once, unless the test requires a fresh card: + + ```sh + truncate -s 64M "$XTEINK_EMU_SD" + mkfs.fat -F 32 "$XTEINK_EMU_SD" + ``` + +3. Start a clean emulator process while preserving SD contents: + + ```sh + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-emu.py" stop \ + --state-dir "$XTEINK_EMU_STATE" || true + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-emu.py" start \ + --state-dir "$XTEINK_EMU_STATE" \ + --firmware "$XTEINK_FIRMWARE" \ + --sdcard "$XTEINK_EMU_SD" + ``` + + `start` simulates a two-second power-button hold for cold boot. Override `--power-hold-ms` when testing power behavior. + +4. Observe serial behavior with either a persistent regex cursor or the raw log: + + ```sh + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-emu.py" wait \ + --state-dir "$XTEINK_EMU_STATE" --timeout 30 --match 'pattern' + tail -f "$XTEINK_EMU_STATE/serial.log" + ``` + +5. Drive the physical controls: + + ```sh + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-emu.py" button \ + --state-dir "$XTEINK_EMU_STATE" bottom-2 + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-emu.py" button \ + --state-dir "$XTEINK_EMU_STATE" power --down + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-emu.py" button \ + --state-dir "$XTEINK_EMU_STATE" power --up + ``` + + Available buttons are `left`, `right`, `bottom-1` through `bottom-4`, and `power`. Use the labels rendered by the current screen as the authoritative mapping. Allow the e-ink panel to refresh after state-changing input. + +6. Capture and inspect the screen after meaningful transitions: + + ```sh + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-emu.py" screenshot \ + --state-dir "$XTEINK_EMU_STATE" --output /tmp/xteink-screen.png + ``` + +7. Enter text when the firmware's on-screen keyboard is focused: + + ```sh + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-type-keyboard.py" \ + "$XTEINK_EMU_STATE" normal 'Example' + uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-type-keyboard.py" \ + "$XTEINK_EMU_STATE" url 'https://example.com' + ``` + +8. For network tests, connect the firmware to the single open Wi-Fi network named `qemu`, then validate the feature's observable result. + +## Diagnose Failures + +- Firmware serial output: `$XTEINK_EMU_STATE/serial.log` +- Emulator output: `$XTEINK_EMU_STATE/qemu.log` +- Assembled flash image: `$XTEINK_EMU_STATE/flash.bin` +- Resolve crash addresses against the exact ELF produced with the tested binary, using the project's RISC-V `addr2line` tool. +- Preserve the SD image when reproducing persistence bugs; replace it when testing first-boot behavior. + +## Cleanup + +```sh +uv run --script "$XTEINK_QEMU_REPO/scripts/xteink-emu.py" stop \ + --state-dir "$XTEINK_EMU_STATE" +```