velxio/test/autosearch/07_multi_board_support.md

133 lines
7.4 KiB
Markdown

# Multi-board support — Custom Chips
> Validado el 2026-04-28. Fuente: `test/test_custom_chips_boards/` (24 tests pytest:
> compile + sketch + GPIO bridge + I2C + UART + SPI E2E),
> `test/test_chip_backend_runtime/` (11 tests pytest: runtime aislado),
> `test/test_custom_chips/` (70 tests vitest sandbox).
## Resumen ejecutivo
| Capa | Estado |
|---|---|
| Compilación de chips (`/api/compile-chip`) | ✅ funciona — 11/11 chips de la galería pasan |
| Compilación de sketches (`/api/compile`) | ✅ funciona en AVR (Uno/Nano/Mega), RP2040 Pi Pico, ESP32 |
| Runtime AVR (avr8js, browser) | ✅ GPIO+I2C+SPI+UART (sandbox 70/70) |
| Runtime ESP32 QEMU (lcgamboa, backend WASM-in-process) | ✅ GPIO + I2C + UART + SPI + pin_watch + timers (E2E con sketches reales) |
| Runtime RP2040 (rp2040js, browser) | ✅ GPIO + I2C + SPI + USART expuestos |
| Runtime ESP32-C3 (RV32IMC, browser) | ⚠️ Solo GPIO — peripherals stub |
| Runtime Raspberry Pi 3 (QEMU, backend) | ⚠️ Solo GPIO + Serial via WS |
| Runtime ATtiny85 (avr8js, browser) | ⚠️ Solo GPIO — chip no tiene TWI/SPI/USART |
## Matriz detallada
| Board kind | Simulator class | pinManager | i2cBus | spi | usart | Custom chip funciona |
|---|---|:---:|:---:|:---:|:---:|---|
| `arduino-uno` | `AVRSimulator` | ✅ | ✅ | ✅ | ✅ | **GPIO + I2C + SPI + UART** |
| `arduino-nano` | `AVRSimulator` | ✅ | ✅ | ✅ | ✅ | **GPIO + I2C + SPI + UART** |
| `arduino-mega` | `AVRSimulator` | ✅ | ✅ | ✅ | ✅ | **GPIO + I2C + SPI + UART** |
| `attiny85` | `AVRSimulator` | ✅ | ❌ | ❌ | ❌ | Solo GPIO |
| `raspberry-pi-pico` | `RP2040Simulator` | ✅ | ✅ | ✅ | ✅ | **GPIO + I2C + SPI + UART** |
| `pi-pico-w` | `RP2040Simulator` | ✅ | ✅ | ✅ | ✅ | **GPIO + I2C + SPI + UART** |
| `nano-rp2040` | `RP2040Simulator` | ✅ | ✅ | ✅ | ✅ | **GPIO + I2C + SPI + UART** |
| `esp32` y variants | `Esp32Bridge` (QEMU) | ✅ vía shim | **✅ backend WASM** | **✅ backend WASM** | **✅ backend WASM (UART0)** | **GPIO + I2C + SPI + UART + pin_watch + timers** |
| `esp32-s3` | `Esp32Bridge` | ✅ vía shim | **✅ backend WASM** | **✅ backend WASM** | **✅ backend WASM** | **GPIO + I2C + SPI + UART** |
| `esp32-cam` | `Esp32Bridge` | ✅ vía shim | **✅ backend WASM** | **✅ backend WASM** | **✅ backend WASM** | **GPIO + I2C + SPI + UART** |
| `esp32-c3` | `Esp32C3Simulator` | ✅ | ❌ | ❌ | ❌ | Solo GPIO |
| `xiao-esp32-c3` | `Esp32C3Simulator` | ✅ | ❌ | ❌ | ❌ | Solo GPIO |
| `arduino-nano-esp32` | `Esp32Bridge` | ✅ vía shim | **✅ backend WASM** | **✅ backend WASM** | **✅ backend WASM** | **GPIO + I2C + SPI + UART** |
| `raspberry-pi-3` | `RaspberryPi3Bridge` (QEMU) | ✅ vía shim | ❌ | ❌ | ❌ | GPIO + Serial vía WS |
## Componentes de display soportados
| Componente | AVR | RP2040 | ESP32 | Path |
|---|:---:|:---:|:---:|---|
| `wokwi-ssd1306` (I2C OLED) | ✅ | ✅ | ⚠️ I2C sink only (no canvas) | `simulator.addI2CDevice` (browser) |
| `wokwi-ili9341` (SPI TFT) | ✅ | ✅ | ❌ | `spi.onByte` (browser) |
| `wokwi-lcd2004` (parallel LCD) | ✅ | ✅ | ❌ | parallel pin monitor |
| **`epaper-ssd168x` (5 variants)** | **✅ ≤2.13"** | **✅** | **✅** | Browser decoder for AVR/RP2040; backend `Ssd168xEpaperSlave` for ESP32 — emits `epaper_update` WS events. See [`docs/wiki/epaper-emulation.md`](../../docs/wiki/epaper-emulation.md). |
**Nota ESP32**: el chip's `.wasm` corre en el proceso del worker QEMU (vía
[`wasmtime`](https://wasmtime.dev/)), así que **todas** las callbacks
(I2C / SPI / UART / pin_watch / timers) responden a QEMU **sincrónicamente**
misma fidelidad que los slaves Python hardcodeados (`MPU6050Slave`, etc) y
sin round-trip por WebSocket. Ver
[`docs/wiki/custom-chips-esp32-backend-runtime.md`](../../docs/wiki/custom-chips-esp32-backend-runtime.md)
para la arquitectura completa, incluyendo el reference de op codes picsimlab.
## Cómo se validó cada uno
### AVR (Uno/Nano/Mega)
- 70 tests en `test/test_custom_chips/test/` con `avr8js` real cargando `.hex` real
de un sketch Arduino (incluye el sketch I2C `i2c_eeprom_demo.ino` compilado con
`arduino-cli`).
- Chip 24C01 contesta correctamente al `Wire.h` del sketch — full I2C E2E.
### ESP32 (lcgamboa QEMU + backend WASM runtime)
- `test/test_custom_chips_boards/test_esp32_gpio_bridge.py` (2 tests) — GPIO + serial
round-trip básico, sin WASM.
- `test/test_custom_chips_boards/test_esp32_chip_i2c.py` (1 test) — sketch ESP32 con
`Wire.h` ↔ chip 24C01 EEPROM. Valida pointer write, data write, pointer reset,
read 4 bytes round-trip.
- `test/test_custom_chips_boards/test_esp32_chip_uart.py` (1 test) — sketch envía
"Hello", chip ROT13 transforma byte a byte, sketch lee bytes transformados.
- `test/test_custom_chips_boards/test_esp32_chip_spi.py` (1 test) — sketch hace
`SPI.transfer(0xA5)` + RCLK pulse, chip 74HC595 latch a 8 GPIO outputs, sketch
lee `Q=10100101` LSB-first. Valida la cadena completa: SPI byte → on_done →
pin_watch en RCLK → vx_pin_write → `qemu_picsimlab_set_pin``digitalRead`.
- `test/test_chip_backend_runtime/test_wasm_runtime.py` (11 tests) — runtime
Python aislado (sin QEMU): inverter, EEPROM 24C01 + pointer wrap, EEPROM 24LC256,
GPIO output, UART ROT13, SPI shift register, timer plumbing, pin_watch edge.
### Compilación multi-board
- `test_multi_board_sketch_compile.py` compila un blink simple en 5 boards
representativos (Uno, Nano, Mega, Pi Pico, ESP32). Todos pasan en ~90 s.
## Gaps documentados (follow-ups)
### Alta prioridad
1. **ESP32-C3 — exponer USART/I2C/SPI MMIO**. El simulator JS hoy hace stubs;
habría que rutear las MMIO regions a un bus equivalente al del AVR. Alternativa:
replicar el patrón ESP32 — el lcgamboa fork ya tiene `esp32c3_picsimlab.c`
con los mismos hooks `picsimlab_i2c_event`/`spi_event`/`uart_tx_event` y los
eventos picsimlab tienen el mismo encoding, así que el `WasmChipRuntime`
funciona tal cual. Falta agregar el branch `custom-chip` en el worker C3.
### Baja prioridad
- **ATtiny85 — añadir USI** (peripheral 2-wire). Avr8js puede no soportarlo;
validar primero.
- **Raspberry Pi 3 — bridge a I2C real del kernel** dentro del QEMU. Más
complejo, depende del firmware.
- **ESP32 framebuffer/display** — chips con `vx_framebuffer_init` hoy emiten
`chip_warning`; falta forwardear pixel updates al canvas del frontend vía
WebSocket (async, no en hot path).
- **ESP32 `vx_pin_dac_write`** — hook a `qemu_picsimlab_set_apin` (~30 min).
## Cómo correr la validación localmente
```bash
# 1. Backend (con lcgamboa lib disponible — ver paso 0 abajo si falta)
cd backend && uvicorn app.main:app --port 8765
# 2. Suite multi-board pytest
cd .. && VELXIO_BACKEND_URL=http://127.0.0.1:8765 \
python -m pytest test/test_custom_chips_boards/ -v
# 3. Sandbox AVR (browser-side via avr8js + Vitest)
cd test/test_custom_chips && npm test
```
### Paso 0 — Cómo conseguir libqemu-xtensa.dll/.so en dev local
El `Dockerfile.standalone` la trae como parte del build. Si tenés un container
de Velxio corriendo:
```bash
# Windows / dev local
docker cp velxio-dev:/app/app/services/libqemu-xtensa.dll backend/app/services/
docker cp velxio-dev:/app/app/services/esp32-v3-rom.bin backend/app/services/
docker cp velxio-dev:/app/app/services/esp32-v3-rom-app.bin backend/app/services/
```
(Análogo en Linux con `.so`.) El backend la detecta en `LIB_PATH` y enruta
ESP32 a través de la C library en lugar del subprocess fallback.