- 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.
140 lines
7.6 KiB
Markdown
140 lines
7.6 KiB
Markdown
**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).
|