velxio/backend/app/services
David Montero 8c58d2a1a7 fix(epaper/esp32): preserve PartSimulationRegistry sensors in setSensors + correct BUSY polarity per controller family
Two intertwined bugs were leaving every ESP32 ePaper example broken
end-to-end.  Only the 5.65" UC8159c panel surfaced the failure
audibly ("Busy Timeout!" repeating in serial), because its inverted
busy polarity caused the firmware to hang inside `_waitBusy()`.  The
SSD168x ePaper examples APPEARED to run cleanly but never actually
rendered anything to the panel — the canvas stayed at the idle paper
colour because the same registration path was broken.

Root cause #1 — `setSensors` was a full REPLACE, not a merge.
  `Esp32Bridge.setSensors(sensors)` did `this._pendingSensors =
  sensors`.  At `startBoard()` time the store iterates components,
  resolves wires for any entry in `SENSOR_COMPONENT_MAP` (DHT22 /
  HC-SR04 / I²C sensors) and calls `setSensors(...)` with that list.
  ePaper components live in `PartSimulationRegistry` (not in the
  sensor map) and are registered via `sendSensorAttach()` AT
  COMPONENT-MOUNT TIME — well before `startBoard()` runs.  Full-replace
  semantics blew that registration away on every Run click, so the
  worker never instantiated an `Ssd168xEpaperSlave` / `Uc8159cEpaperSlave`,
  no SPI bytes were decoded, no frames were latched, and BUSY was
  never driven.

  Fix: upsert by `pin` so pre-existing registrations from
  PartSimulationRegistry handlers are preserved alongside the
  startBoard-resolved sensors.  Confirmed via a WebSocket spy that the
  `start_esp32` payload now carries the ePaper sensor entry.

Root cause #2 — BUSY polarity was hard-coded for SSD168x only.
  Verified against upstream GxEPD2 source:
    * SSD168x family — constructor passes `_busy_level = HIGH`
                       → BUSY=HIGH means busy, LOW means ready.
    * UC8159c family — constructor passes `_busy_level = LOW`
                       → BUSY=LOW  means busy, HIGH means ready.
  The worker only drove BUSY after a frame flush (and at the wrong
  polarity for UC8159c), so the firmware's first `_waitBusy()` inside
  `_PowerOn()` / `_InitDisplay()` — which fires BEFORE any frame —
  blocked for the full 25 s `_busy_timeout`.

  Fix: read `controller_family` from the registration payload, pick the
  per-family idle level, and (a) seed the pin to IDLE at registration so
  the first `_waitBusy()` sees "ready" immediately, (b) use that
  polarity (idle vs. busy) when pulsing on frame flush.

Verified on https://velxio.dev/example/epaper-5in65-7c-esp32-rainbow:
the serial timeline now reads `_InitDisplay reset : 1566` /
`_PowerOn : 148` / `_PowerOff : 183` / `frame done` (all sub-2 ms
busy-waits, no timeouts).  Sensor registration confirmed via the
`start_esp32` payload carrying the `epaper-ssd168x` entry.
2026-05-22 23:32:33 +02:00
..
boot_images feat(pi): Phase 3.3 — Pi Zero / Pi 1 / Pi 2 armhf simulators 2026-05-18 23:23:48 +02:00
esp-idf-template fix(esp32/ledc): translate ledcWrite(pin,duty) → ledcWrite(channel,duty) 2026-05-22 16:14:55 +02:00
picow_net Implement TCP and UDP NAT services for chip-initiated connections 2026-04-29 08:43:41 -03:00
__init__.py
arduino_cli.py fix(arduino-cli): pin ATTinyCore to 1.4.1 (azduino.com micronucleus host unreachable) 2026-05-22 15:15:53 +02:00
asm8080.py feat(chips): programmable retro CPU chips with external ROM 2026-05-18 23:38:18 -03:00
asmz80.py feat(chips): programmable Z80 chip + Larson scanner example 2026-05-19 00:21:08 -03:00
c_compile.py feat(chips): C-to-Z80 compile via SDCC + LED chaser example 2026-05-19 00:31:10 -03:00
chip_compile.py Add ESP32 chip demos and comprehensive tests for I2C, SPI, and UART interactions 2026-04-28 19:24:39 -03:00
esp32_flash_image.py fix(esp32): trim flash image before serializing, pad on QEMU attach 2026-05-08 14:36:34 -03:00
esp32_i2c_slaves.py feat(i2c): cross-board bridging across all velxio boards (AVR/RP2040/ESP32 xtensa+riscv) 2026-05-12 17:51:39 -03:00
esp32_lib_bridge.py feat(compile): ESP-IDF compile options + request dedup 2026-05-18 21:50:45 -03:00
esp32_lib_manager.py refactor(esp32): retire ledc_update + broadcastPwm + channelGpioMemo 2026-05-19 04:05:34 +02:00
esp32_signals.py fix(esp32): LEDC signal IDs are 71-86 per ESP32 TRM, not 72-87 2026-05-17 05:42:52 +02:00
esp32_spi_slaves.py feat: add support for UC8159c (ACeP 7-colour) display 2026-04-30 00:27:40 -03:00
esp32_worker.py fix(epaper/esp32): preserve PartSimulationRegistry sensors in setSensors + correct BUSY polarity per controller family 2026-05-22 23:32:33 +02:00
esp_qemu_manager.py
espidf_compiler.py fix(espidf): treat C++ stdlib headers as built-in in user_libs bundler 2026-05-22 18:48:14 +02:00
gpio_shim.py
picow_net_bridge.py Implement TCP and UDP NAT services for chip-initiated connections 2026-04-29 08:43:41 -03:00
qemu_manager.py feat(pi): Phase 3.3 — Pi Zero / Pi 1 / Pi 2 armhf simulators 2026-05-18 23:23:48 +02:00
rom_compile.py feat(chips): C-to-Z80 compile via SDCC + LED chaser example 2026-05-19 00:31:10 -03:00
signal_router.py feat(esp32): SignalRouter — model the GPIO Matrix as first-class 2026-05-17 05:00:53 +02:00
wasm_chip_runtime.py Add ESP32 chip demos and comprehensive tests for I2C, SPI, and UART interactions 2026-04-28 19:24:39 -03:00
wasm_chip_slave.py Add ESP32 chip demos and comprehensive tests for I2C, SPI, and UART interactions 2026-04-28 19:24:39 -03:00
wifi_status_parser.py