# 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](https://github.com/crosspoint-reader/crosspoint-reader) 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](./ROADMAP.md) for architecture and plan. ## Quick start (native QEMU) ```sh 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: ```sh 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. ```sh 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 ```sh 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` — the `xteink,variant=x3|x4` machine 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 by `scripts/build-qemu.sh`. - `third_party/qemu` — submodule of the [xteink QEMU fork](git@ssh.gitea.va.reichard.io:evan/qemu-xteink.git) (espressif/qemu + the machine models + the wasm32 TCG backend), built for the browser by `scripts/build-qemu-wasm.sh`. Edit it in place; `make web` recompiles incrementally. `qemu/wasm/Dockerfile` is 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 test` runs 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.