The 7.7k-line qemu-wasm patch was really a fork, so vendor it as a submodule (pinned at the xteink QEMU fork) and build it directly. Removes the clone/commit-check/patch/reset machinery, the redundant web-dev/patch targets, and 0002-qemu-wasm.patch. Editing third_party/qemu now recompiles incrementally via plain `make web`. Native build keeps 0001-xteink-machine.patch.
4.2 KiB
xteink-web-emulator
An offline, in-browser emulator for the xteink X3/X4 (ESP32-C3 + e-ink):
upload a firmware .bin, run the real machine code client-side, see the screen,
press buttons, mount a virtual SD — no server, no proprietary engine.
Status: native and WebAssembly builds provide one xteink machine that
selects X3 or X4 at launch. Unmodified
canonical firmware
auto-detects the selected variant: X3 boots with its UC8253 display and SD card;
X4 reaches its SSD1677 driver through a blank protocol stub. A basic static
browser UI now loads local firmware, renders the panel, and drives the physical
buttons. See ROADMAP.md for architecture and plan.
Quick start (native QEMU)
git clone --recursive https://github.com/crosspoint-reader/crosspoint-reader ../crosspoint-reader
# Build ../crosspoint-reader's PlatformIO `default` environment first.
nix develop
make qemu # clone espressif/qemu @ pinned commit, apply patch, build
make firmware sdimage # 16 MB flash.bin + FAT32 sd.img from the PlatformIO build
make run # X3 (default)
make run VARIANT=x4 # X4 detection + blank SSD1677 stub
Point at a firmware build with make firmware FIRMWARE_DIR=/path/to/.pio/build/gh_release.
make qemu is a long compile on modest hardware — set JOBS to taste.
WebAssembly build
Podman or Docker is required. The QEMU source is the third_party/qemu
submodule, so initialize it first:
git submodule update --init third_party/qemu
The build is limited to riscv32-softmmu and the X3/X4 device graph;
networking, audio, virtfs, tools, docs, and unrelated boards are disabled.
make qemu-wasm
# dist/wasm/qemu-system-riscv32.{js,wasm,worker.js} + esp32c3-rom.bin
The build runs Node smoke checks when Node is available.
Browser interface
make web
# Open http://127.0.0.1:8000/web/
Choose a CrossPoint firmware .bin — either the ~5 MB release app image (it is
merged in-browser with the bundled bootloader and partition table into a 16 MB
flash) or a full 16 MB image — select X3 or X4, and boot. The controls
map to the device's ADC button ladders and active-low Power GPIO. make web
serves the required COOP/COEP headers for Emscripten pthreads; a generic static
server without those headers will not work.
Real firmware boots in WASM and drives the X3 panel (528×792). The browser SD
uses QEMU's directory-backed FAT provider: the guest sees a writable, ephemeral
32 GiB FAT32 card while memory use scales with actual files instead of logical
capacity. It starts with Test/example.txt; inspect it in the Files tab. The
Debug tab reports committed WASM heap, visible MEMFS data, SD file bytes, and
browser JS heap where supported. X4 remains a white display stub.
Contents
qemu/patches/0001-xteink-machine.patch— thexteink,variant=x3|x4machine and its device models (I²C fingerprints, ADC, GPIO, SPI2, X3 UC8253, X4 panel stub, SD-over-SPI fix), applied onto the pinned espressif/qemu commit byscripts/build-qemu.sh.third_party/qemu— submodule of the xteink QEMU fork (espressif/qemu + the machine models + the wasm32 TCG backend), built for the browser byscripts/build-qemu-wasm.sh. Edit it in place;make webrecompiles incrementally.qemu/wasm/Dockerfileis the pinned Emscripten dependency environment.flake.nix— the espressif-qemu release binary as the fast generic baseline (nix run .#run-upstream -- flash.bin), plus a devShell with QEMU's full build environment.Makefile—qemu,firmware,sdimage,run,chip.scripts/mksd.sh— build the FAT32 SD backing image (local-disk impl of the SD block interface).chip/eink-x3.chip.c— the reverse-engineered X3 e-ink protocol, first written as a Wokwi chip and now the reference for the QEMU display device.make -C chip testruns its host self-check.
Why not Wokwi
Wokwi runs any bin in a browser and we had the e-ink chip working — but its simulation engine is proprietary and gated behind a license/service, so it can't be self-hosted or run airgapped. QEMU is the open path; the e-ink protocol work carried straight over.