Files
darceye 7f5f1aaa88 Logic analyzer probe freedoms: passive pads, any-GPIO trigger, 1 h window (0.11.0)
- passive probes (new `static passive = true` device metadata): a pure
  listener never drives an input and claims no pad, so it may clamp onto
  ANY GPIO - including pads other devices own (an LED, an I2C pair, a
  MAX7219 bus) and other analyzers. The runtime's pin-conflict check and
  the wired-AND arbitration skip passive pads; the panel's usedPins
  ignores them, so other devices' pickers never show them as "in use";
  the analyzer's channel grid never disables a GPIO (pads owned elsewhere
  get a dashed "shared" hint). Replaces the analyzer's sharedBus flag.
- trigger on any GPIO: trigCh (channel index) becomes trigPin (GPIO
  number) - the trigger pad gets its own subscription and need not be an
  analysed channel (off-channel triggers land in no lane, channel levels
  still snapshot at capture start). The window dropdown lists every valid
  GPIO. Tooltip documents the gpio_state visibility caveat: a trigger
  fires only when the FIRMWARE drives the pad - pure-input pads (driven
  by our button devices) never toggle the output registers.
- window cap lifted 1 s -> 1 h of guest time (was a conservative guard;
  dense signals still freeze earlier at the 20 000-edge buffer with the
  buffer-full note - the natural limit, since Saleae streams into host
  RAM while we capture into a fixed buffer).
- tests: runtime-level passive sharing (probe onto an LED pad + I2C pair
  + second probe, zero conflicts), off-channel trigger, 1 h clamp,
  trigger cases migrated to trigPin; device bumped to 1.1.0; GUI checked
  (shared chip clickable, 23 trigger options, 5000 ms window accepted).
- docs (both languages): CHANGELOG 0.11.0 + device version table,
  DEVICE-API passive metadata + instrument section, README capability
  row, ROADMAP probe-freedoms bullet, AGENT rule 3.11; version synced to
  0.11.0.
2026-11-02 10:58:17 +08:00

140 lines
7.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
**English** | [简体中文](ROADMAP.zh-cn.md)
# Roadmap
## Logic analyzer — shipped in peris 0.10.0, probe freedoms in 0.11.0
- ✅ `logic-analyzer.js`: multi-channel GPIO waveform capture (up to 8
pads, one trigger: channel + edge or Immediate, guest-time window,
auto re-arm). Driven levels 1/0, released pads Z, times in guest µs.
Rides the M4 scheduler (arm 1000 watch, fine lease per `resolution`
preset: 20/100/300); 20 000-edge buffer freezes with an `overflow`
flag. Shared logic in `peris/devices/la-lib.js`.
- ✅ 0.11 probe freedoms: `static passive = true` — a probe listens only,
claims no pad and may clamp onto ANY in-use GPIO (conflict check and
wired-AND skip passive pads; other devices' pickers ignore them; the
channel grid never disables a GPIO). Trigger became `trigPin` (any GPIO,
independently subscribed, off-channel triggers fine); the window cap
lifted to 1 h of guest time (the edge buffer is the natural limit).
- ✅ Floating analyzer window: draggable, resizable, non-modal popup
(fixed position, no backdrop — the page underneath keeps working);
geometry persisted. One `drawWaveform` painter feeds the popup, the
details mini-preview and the row icon; channels picked from a GPIO grid
(occupied pins shown as shared, never disabled). Framework:
`ctx.pinLevel`, `ViewHost.pinInfo`, `View.destroy` (row
removal/rebuild teardown).
- ✅ Saleae-style plot interactions: wheel zoom anchored at the cursor,
drag pan, double-click/F fit; hover measurement shades the pulse and
reads level · width · period · frequency · PWM duty; A/B cursors with
Δt + 1/Δt; lane selection + ‹/›/←/→ edge jumping; lane gutter shows the
right-edge level per channel.
- Tests: readout math + capture state machine units, `sigbus.pinLevel`,
smoke S13 (P4 soft-I2C bus capture). Ideas not in v1: pre-trigger
buffer, incremental edge streaming during a run, protocol decoders on
top of a capture (I2C/NEC annotations) — the frozen buffer already
carries everything a decoder needs.
## MAX7219 display — shipped in peris 0.9.0
- ✅ `max7219.js`: the 8-digit LED driver on a firmware bit-banged
DIN/CLK/LOAD bus (hardware SPI stays invisible — M0). Level-driven shift
engine (MSB-first, words latched on the LOAD rising edge, misaligned
frames dropped and counted, never garbled) + datasheet register model
(Code B decode with independent DP, intensity PWM, scan limit,
shutdown / display test, power-on defaults). 8×8 matrix and 7-segment
Views auto-selected from the decode-mode register; daisy chains share
the three pads. Shared logic in `peris/devices/max7219-lib.js`.
- ✅ Real-firmware integration: smoke S12 boots the gun 0.1.0 release
(ESP32-S3, delay-free bit-bang — edges ~20 instructions apart, the
tightest pulses the M4 scheduler resolves: fine lease at the floor 20,
arm 60) and decodes its `display_init()` with zero drops;
`examples/esp32s3-gun.json` wires the display for the browser.
## M4 · Bit-bang protocol devices + IR — shipped in peris 0.8.0
- ✅ `bitbang-i2c-slave.js`: 24C02 EEPROM and BME280 models behind two
firmware bit-banged GPIOs (SCL/SDA). Level-driven engine (open-drain
model); the slave answers on the SDA input path, which the master sees
while it releases the pad. Shared logic in `peris/devices/i2c-lib.js`
(engine, register models, bit-exact Bosch compensation). Constraint
documented: hardware I2C/SPI buses cannot be tapped (M0) and push-pull
masters that never release SDA cannot be answered; clock stretching not
modelled.
- ✅ `ir-nec.js`: NEC codes captured from firmware **bit-bang** transmissions
(fine-batch edge sampling → burst envelope) and from **RMT** channels
(a 34-word frame fits the post-TX channel RAM; the emulator leaves
`APB_MEM_WADDR` at 0, so mid-TX stitching is out — M4 probe). Decoder is
fully ratio-based: the guest clock runs ~50% of nominal through
`esp_rom_delay_us` (measured), so absolute-µs windows would misjudge.
Shared logic in `peris/devices/nec-lib.js`.
- ✅ High-rate sampling scheduler (`src/core/scheduler.ts`): per-device
leases — a standing arm batch (~1000 instr) while the bus is idle, fine
batches (~300 instr) while a transfer is in flight; leases expire on
deadline or CPU-sleep fast-forward. Worker and tests share
`runtime.batchSize()`.
- ✅ Framework: `sharedBus` device metadata (I2C slaves legally share
SCL/SDA) with wired-AND input arbitration; `cyclesPerUs` on the device
ctx.
- Test firmware P4 (soft-I2C master at ~20 kHz, forced BME280 measurements
with C-side compensation cross-checked bit-exactly by the smoke test,
NEC via both paths) + unit tests `tests/unit/protocol.test.mjs` +
smoke S10/S11.
## M3 · WS2812 addressable LEDs — shipped in peris 0.7.0
- ✅ `ws2812.js`: polls the RMT channel RAM (M0 verified Q3b PASS),
symbols → bitstream → GRB frames; reset-symbol resync + leading-zero
alignment (the M3 probe refined the model: one RMT word per WS2812 bit,
48-word wrap, a zero transmit terminator after the reset — details in
FEASIBILITY.md). Shared logic in `peris/devices/ws2812-lib.js`.
- ✅ Strip / ring / matrix Views; GRB/RGB order, brightness cap and gamma
configurable; smooth frame interpolation like the M2 PWM bulbs
(reusing the `ledc-lib.js` animator).
- ✅ Known limitation, documented and surfaced in the UI: the 48-word
channel RAM keeps only the **last 46 bits** of a frame, so strips longer
than ~2 LEDs show only their tail (same as real C3 hardware); the View
draws unrecoverable LEDs hollow. `CHnSTATUS` gates decoding while a
transmission is in flight.
- Performance: JS decoding measures far below any budget (one 192-byte
read + a 48-word compare per batch); the wasm-helper escape hatch was
not needed. Lifting the 46-bit limit would need the M4 fine-batch
scheduler (sampling the RAM repeatedly *during* a transmission), not
faster decoding.
## M2 · PWM dimmed LED — shipped in peris 0.6.0
- ✅ `pwm-led.js` + `rgb-led.js`: each LEDC channel's `DUTY_R` register is
read every batch for the exact duty cycle, no aliasing (approach verified
in M0: Q2b PASS).
- ✅ Channel→pin mapping: `GPIO_FUNCn_OUT_SEL_CFG` (LEDC ch0–5 = 45–50)
implements auto-discovered wiring that follows firmware rewiring; manual
channel selection also allowed.
- ✅ Breathing effect with smooth rendering: canvas brightness
interpolation (one rAF animator per plugin repaints bulb + row icon).
- Shared logic in `peris/devices/ledc-lib.js`; framework hooks
`Device.onBatch()` + `ctx.mmio` (see DEVICE-API.md).
## M5 · Upstream capability tracking (not under our control)
These need APIs the wasm does not expose today; progress depends on new
esp-emulator releases (upgrade procedure in UPGRADE.md):
| capability | required upstream interface | status |
|---|---|---|
| hardware I2C device models | i2c slave/device bridge API (CLI-only `--i2c-dev`, dumb registers only) | ❌ |
| hardware SPI peripherals (SD card etc.) | spi device bridge | ❌ |
| SPI/RGB565 displays | spi/lcd_cam (the peripheral itself is not emulated) | ❌ |
| real touch peripheral | touch peripheral emulation | ❌ (touch button stands in with GPIO semantics) |
| ADC (potentiometers etc.) | adc emulation | ❌ |
| I2S audio | i2s emulation | ❌ |
| UART1 peripheral | wasm-exposed uart1 (CLI has `--uart1-tcp`) | ❌ |
| state snapshot save/restore | save/load API | ❌ |
## Maintenance items
- ~~`update_esp_emu_browser.bat`~~ — solved differently: `tools/fetch_esp_emu.py`
downloads/unpacks any esp-emulator release (`--version <ver>`), see
UPGRADE.md.
- `src/core/mmio/`: add the C5/C6/H2/P4/S3 address tables (extracted from each
chip's IDF soc headers, same method as M0).