Commit Graph

65 Commits

Author SHA1 Message Date
David Montero Crespo 06d6e0afbb fix(simulator): circuitVerifier worst-case GPIO + LED NaN guard
Two related correctness fixes that make the simulator's realism
match what users actually see.

1. circuitVerifier was running pre-flight against the IDLE circuit
   (every pin LOW). A Blink sketch is going to write pin 13 HIGH
   eventually — at which point a missing series resistor produces a
   ~500 mA spike through the diode. But because pre-flight ran with
   pin 13 LOW the led-overcurrent rule never fired, and the user
   sailed through Run only to see the LED stay mysteriously dark on
   the canvas.

   The verifier now forces every digital pin connected to a load to
   HIGH = vcc, the worst case any well-defined sketch will eventually
   impose. The existing rules (led-overcurrent, resistor-overpower,
   short-circuit) now fire correctly and the existing
   CircuitVerificationModal blocks Run until the user adds a proper
   current limiter or chooses Run Anyway.

   Pins that are inputs-only (a pull-up + button) get over-driven
   here too, but the rules tolerate that — a pull-up at 5 V draws
   ~0.5 mA, well below all thresholds. A circuit that would actually
   fault under HIGH is flagged.

2. LED simulator was crashing visually on non-finite ngspice branch
   currents. A degenerate diode (no series R) makes ngspice return
   NaN, which fell through 'raw !== undefined && current > 1e-6' as
   false and never triggered the digital fallback. Now we check
   Number.isFinite(raw) before trusting it — non-finite returns
   route to the digital fallback so the LED at least lights visually
   when its driver pin is HIGH (the user still sees the verifier
   warning that the real-world circuit is wrong, but Run Anyway is
   not a black screen).
2026-05-18 00:00:45 -03:00
David Montero Crespo c39a00c07c fix(ili9341): debounce flush instead of rAF — paint on frame boundary
rp2040js runs at ~50% real time, so a TFT frame burst (fillRect sky +
fillRect floor + many drawFastVLine for walls + HUD) often takes longer
than 16 ms to drain through the SPI pipeline. Painting on every rAF
captured mid-burst snapshots that the next sky fill immediately
clobbered, so the canvas only ever showed the last few pixels written
before each tick — most visibly the raycaster examples rendering 2-3
wall columns instead of 160.

Strategy: each SPI pixel write resets a 16 ms idle timer. We paint only
after that period of silence (a real frame boundary), with a 100 ms
hard cap so continuous-write sketches still update.

Also adds test/pico_doom_demo/raycaster-perf.mjs — a puppeteer-based
profiler that reports CPU step rate, SPI throughput, per-pixel cost,
and paint rate. Run with the dev backend + frontend up:

  node test/pico_doom_demo/raycaster-perf.mjs

After the fix the Doom raycaster paints at the sketch's natural 10 FPS
with full frames (was 29 fps of mid-burst snapshots).
2026-05-16 00:48:38 -03:00
davidmonterocrespo24 8bde313a91 test(sim): Phase 1d-tests J + C — vitest.config.ts + components-metadata integrity
J: vitest.config.ts split out from inline `test:` block in
vite.config.ts.  CI workflows can now reference vitest.config.ts
directly; test settings no longer pulled into vite build deps.
Settings: testTimeout 30s, hookTimeout 30s, forks pool with
singleFork:false (per-file worker isolation for the
NgSpiceNodeAdapter singleton), coverage excludes
`src/simulation/spice/wasm/**` (irrelevant lcov bytes).

C: components-metadata-integrity.test.ts — 11 sub-tests, all live
checks against the real `public/components-metadata.json` + every
examples-*.ts source-of-truth + the live PartSimulationRegistry:
  • Shape per entry: id / tagName / name / category / pinCount
  • IDs unique
  • tagName matches wokwi/velxio prefix
  • Thumbnail is an SVG
  • properties[] + defaultValues{} shape
  • Every metadataId referenced from gallery exists in metadata
    (instr-* filtered — instruments aren't canvas-rendered)
  • PartSimulationRegistry registrations cross-checked vs metadata
    (informational — some runtime-only parts have no metadata entry
    by design: custom-chip, raspberry-pi-3, 74hc595 internals)
  • Orphan-entries report: surfaces metadata entries no example or
    part-sim uses (informational, doesn't fail)

The orphan report flags 58 dead-ish metadata entries (preset
variants like resistor-220, individual epaper sizes, etc.) for
later cleanup conversation.  Not an error.

`PartSimulationRegistry.listRegisteredParts()` exposed for the test
to enumerate without duplicating the list.

1472 tests pass (was 1461 — +11 new metadata sub-tests).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 22:58:12 +02:00
davidmonterocrespo24 5ae9fbb615 feat(sim): Phase 5 — migrate RGB LED + buzzer handlers to PinResolver
RGB LED: each of R/G/B channels prefers the resolver subscription so
the LED works correctly when fed through a P-MOSFET high-side switch
or a BJT driver.  PWM override (analogWrite) keeps using the integer
pin number through pinManager.onPwmChange — duty cycle handling isn't
yet exposed on PinResolver.

Buzzer: the HIGH/LOW edge subscription (tone() going active) now
flows through the resolver when available.  Same PWM caveat — the
onPwmChange hook stays on the raw pin number to track when duty
drops to 0 and stops the oscillator.

Both fall back to pinManager.onPinChange when the resolver isn't
provided (tests / Phase-0-less builds).

Phase 5 progress: 19 of ~22 handlers migrated. Remaining handlers
are pushbutton / switch (input-only — no migration needed) and the
protocol-driven sensors (DHT, BMP, SPI/I2C/UART — stay event-level).
This is effectively the migration plateau.

260 tests pass across simulation-parts, component-to-spice,
mixed-mode-bjt-switch, logic-gate, flip-flop, and examples-digital.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:25:40 +02:00
davidmonterocrespo24 bffa8fd814 feat(sim): Phase 5 — migrate 74HC595 shift register to PinResolver
Five control pins (DS / SHCP / STCP / MR / OE) now subscribe through
PinResolver when available.  Rising-edge detection on SHCP / STCP
keeps working — resolver.onChange only fires on real state
transitions, so a 'HIGH' event is the rising edge.

Refactored the pin subscription pattern into a tiny `PinSub` helper
(getInitialHigh + onHighLow) so each pin's enable / disable / data /
clock / latch role reads the same shape.  Falls back to the legacy
pinManager.onPinChange path when the resolver isn't provided.

Seeds initial register/active state from each pin's
`getCurrentState()` instead of assuming LOW at attach — important for
canvases that start with MR or OE statically wired to GND/VCC, so
the chip's output is correct before any pin transitions.

Phase 5 progress: 17 of ~22 handlers migrated. Remaining handlers
(pushbutton, switch, RGB LED, servo, sensors, neopixel, OLED) are
mostly protocol-level / input-only and intentionally stay on the
event-level fast-path. The output-style migration plateau is
essentially reached.

131 tests pass across simulation-parts + examples-digital.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:23:10 +02:00
davidmonterocrespo24 dceb6a8c40 feat(sim): Phase 5 — migrate every logic-gate handler to PinResolver
twoInputGate (AND/NAND/OR/NOR/XOR/XNOR), nInputGate (3/4-input AND/OR/
NAND/NOR), edgeTriggeredFF (D/T/JK), and the standalone NOT gate all
now prefer PinResolver input subscriptions. Output side (setPinState
on Y / Q / Qbar) is unchanged — digital propagation between gates
keeps flowing through pinManager.

Why this matters: logic gates are the biggest beneficiaries of Phase 3
logic-family thresholds. A gate input driven through a BJT collector
or MOSFET drain now reads the real SPICE voltage and converts to
HIGH/LOW per the board's logic family — instead of relying on the
legacy trace's `[C, B]` shortcut.

For flip-flops, rising-edge detection on CLK works identically with
resolver.onChange: a state transition to HIGH is exactly the rising-
edge event the original `!prevClk && s` was watching for.

All migrated handlers fall back to the legacy pinManager.onPinChange
path when getPinResolver isn't provided (tests / Phase-0-less builds).

Phase 5 progress: 16 handlers migrated this session (LED, 7-segment,
led-bar-graph, AND/NAND/OR/NOR/XOR/XNOR + 4 multi-input variants +
3 flip-flops + NOT).  Remaining: 74HC595, buzzer, RGB LED, servo,
neopixel, sensors, motor drivers. Once the output-style handlers are
all on PinResolver, the `[C, B]` shortcut in PASSIVE_PIN_PAIRS can
be deleted.

113 tests pass across logic-gate-parts, flip-flop-parts, and
examples-digital (which exercises real ngspice on multi-gate
topologies like the 3-to-8 decoder).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 18:19:00 +02:00
davidmonterocrespo24 29bb8af6f6 feat(sim): Phase 5 — migrate led-bar-graph handler to PinResolver
Same backwards-compatible pattern as LED and 7-segment migrations.
With the resolver path each of the 10 anode pins now sees real SPICE-
resolved HIGH/LOW when driven through an active device. Legacy
pinManager.onPinChange path is kept as the fallback.

Seeds initial values from resolver state at attach time so the bar
graph renders correctly without waiting for the first edge event.

Phase 5 progress: 3 of ~12 handlers migrated (LED, 7-segment,
led-bar-graph). Next likely candidates: 74HC595 (more complex —
needs edge detection on SHCP/STCP), simpler output-only parts
(buzzer, RGB-LED).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:40:31 +02:00
davidmonterocrespo24 73478b7433 feat(sim): Phase 5 — migrate 7-segment handler to PinResolver
The 7-segment display was the canary case for the original problem:
multiplexed displays with BJTs driving digit-select pins (COM/DIG)
required the `[C, B]` shortcut in PASSIVE_PIN_PAIRS to even discover
that the COM was wired to an Arduino pin. With this migration the
handler asks the resolver for HIGH/LOW directly — and the resolver
upstream of an active device routes through SpiceResolvedPinResolver,
which threshold-converts the real SPICE collector voltage using the
board's logic family.

Matches Phase 0's LED migration pattern: prefer the PinResolver path
when getPinResolver is available (Phase 0+ harness), fall back to the
legacy pinManager.onPinChange + getArduinoPinHelper for tests / builds
without it.  Backwards-compatible — both digit-select (COM.1/COM.2 on
1-digit, DIG1..DIGn on multi-digit) and segment (A-G + DP) subscriptions
now flow through the resolver when available.

Seeds initial state from resolver.getCurrentState() so static-wire
topologies (e.g. COM directly to GND) work at sim-start without an
explicit edge event.

Phase 5 progress: 2 of ~12 *Parts handlers migrated (LED, 7-segment).
Remaining handlers (pushbutton, switch, 74HC595, etc.) follow the
same pattern.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 17:39:16 +02:00
davidmonterocrespo24 e10492c6e6 feat(sim): introduce PinResolver abstraction (Phase 0 of mixed-mode rewrite)
Decouple per-component handlers from direct pinManager.onPinChange +
getArduinoPinHelper subscriptions by introducing a small PinResolver
interface. The Phase 0 default impl is functionally identical to the
legacy path — it just routes through PinResolver instead of being
inlined in every handler. Zero behavior change.

The point is to make Phase 1 possible: swap the default impl for a
SPICE-resolved version that watches node voltages and threshold-
converts to digital events, without rewriting every handler.

Files:
  - simulation/PinResolver.ts (new) — interface + default factory
  - parts/PartSimulationRegistry.ts — additive 5th arg to
    attachEvents (getPinResolver?), legacy 4-arg signatures keep
    working unchanged
  - components/DynamicComponent.tsx — assembles the PinResolver from
    the wire-trace logic + PinManager subscriptions + board Vcc
    lookup, passes it as the 5th arg to attachEvents
  - parts/BasicParts.ts — LED handler migrated as proof of concept
    (resolver-first path, legacy 4-arg path kept as fallback for
    tests / unmigrated harnesses)
  - __tests__/pin-resolver.test.ts (new) — 8 unit tests covering
    FLOATING / GND / HIGH / LOW / GPIO subscriptions / unsubscribe

Vitest: 8/8 pin-resolver tests pass. 1300+ existing tests still pass;
the one pre-existing flake (spice-rectifier-live-repro timing out >60s)
is unrelated to this commit — verified by running the test on plain
HEAD without these changes (same timeout).

See project/sim-mixedmode/phase-00-pin-resolver.md (in the velxio-prod
repo) for full phase context.
2026-05-15 15:50:09 +02:00
David Montero Crespo a91b857d8c fix(ili9341): rotation 3 was mirrored — use explicit per-rotation map
The MADCTL handler in 6edc715 applied MX/MY/MV as three independent
flags, then mirrored physX/physY post-swap. That double-applies the
mirror for setRotation(3) (which Adafruit sends as MX|MY|MV|BGR=0xE8):
expected formula for rotation 3 is

  physX = 239 - curY
  physY = curX

but the flag-by-flag approach computed

  physX = 239 - curY      (correct by coincidence)
  physY = 319 - curX      (mirrored — should be just curX)

so every landscape-rot-3 sketch rendered horizontally flipped. The
user's Pico Doom title screen looked mirrored even after the previous
fix landed.

Replaced with an explicit per-rotation table derived from
Adafruit_ILI9341's setRotation() source:

  rot 0  MX|BGR        : (curX, curY)
  rot 1  MV|BGR        : (curY, 319 - curX)
  rot 2  MY|BGR        : (239 - curX, 319 - curY)
  rot 3  MX|MY|MV|BGR  : (239 - curY, curX)

Selects the case based on (madMV, madMX, madMY) bits, which is
straightforward because Adafruit only emits these 4 specific values.
Other drivers that set arbitrary MADCTL combinations (e.g. with the ML
or MH bits) still fall through to the closest of the four — good
enough for the screens we actually run.

Build verified (vite OSS+pro, 285 SEO pages).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-15 01:32:37 -03:00
davidmonterocrespo24 76e0d77975 fix(sim/7segment): multiplex-aware driver — track COM/DIG pins, latch segments per digit
The simulator's 7-segment part used to write segments straight into
element.values[0..7] regardless of how many digits the display has and
without considering the COM/DIG select pins.  That meant:

  - Multi-digit displays (digits=2/3/4) only ever lit digit 0; the
    other digits stayed dark even when their DIGn pin was driven.
  - For 1-digit displays multiplexed via shared A-G bus + per-display
    COM.1 transistor (the canonical Arduino clock pattern), all four
    displays showed the same rapidly-changing segment pattern and
    rendered as flickering gibberish because COM.1/COM.2 were ignored.

This rewrites the part:

  - Per-element state: live segments[] (Arduino-driven A..DP), per-
    digit latched digitValues[][], and digitEnabled[] flags.
  - Subscribes to the right digit-select pins for the digit count
    (COM.1/COM.2 for digits=1, DIG1..DIGn for digits=2/3/4).
  - On segment-pin change: writes to segments[] AND mirrors into
    every currently-enabled digit's latched slot.
  - On digit-pin LOW->HIGH (= enable, transistor-driver convention):
    latches the live segments[] into that digit's slot so the first
    refresh after enabling reflects the current pattern.
  - When NO digit-select pin is wired to an Arduino pin (pure direct
    drive, COM tied to GND): all digits default to enabled so segment
    writes propagate immediately — preserves the old behaviour for
    the simplest single-digit case.
  - Rebuilds element.values as a flat array of length digits*8 (the
    shape wokwi-7segment-element expects: indices d*8..d*8+7 = digit
    d's A..DP).

Result: multiplexed 4-digit clocks built with 4 separate 1-digit
7segments + transistors actually render the four digits as the user
intended.  Direct-drive single-digit displays still work unchanged.
2026-05-15 06:08:38 +02:00
David Montero Crespo 6edc715e8d fix(ili9341): handle MADCTL so landscape (setRotation 1/3) renders
The ILI9341 emulator hardcoded SCREEN_W=240 SCREEN_H=320 and silently
ignored every command except CASET/PASET/RAMWR/SWRESET. The block
comment even bragged about it ("All others are silently accepted —
init sequences, DISPON, MADCTL…").

That's fine for portrait sketches, but every landscape demo —
including the new Pico Doom raycaster — calls tft.setRotation(1) or
setRotation(3). Adafruit_ILI9341 translates those into MADCTL 0x36
with the MV (row/column exchange) bit set, then issues CASET windows
with X∈[0..319] and PASET windows with Y∈[0..239]. The emulator's
bounds check `curX > colEnd` would let curX reach 319, but the
buffer write `id.data[(curY*240 + curX)*4]` would land in a slot
that belongs to a different row — and worse, the SCREEN_W=240
ceiling silently truncated everything past column 239. Net result:
black screen for any rotated sketch.

Fix: parse MADCTL (0x36) and treat CASET/PASET as LOGICAL coordinates.
At pixel-write time, remap (curX, curY) → physical (px, py) using the
MV/MX/MY bits, then write into the still-physical 240×320 imageData.
SWRESET resets MADCTL back to portrait defaults (matches the
datasheet's reset semantics).

  MADCTL bit  Mask    Meaning
  D7 MY       0x80    row mirror
  D6 MX       0x40    column mirror
  D5 MV       0x20    swap X/Y (landscape)

Verified by rebuilding (vite OSS+pro). The fix is data-flow only —
no API change, no new dependency. Pico Doom should now actually
render its title screen + raycast frames in /examples on the
raspberry-pi-pico board.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-14 23:19:03 -03:00
David Montero Crespo 71616e580d Add end-to-end tests for ESP32 I2C functionality and circuit verification
- Implemented `i2c-esp32-real-firmware.test.ts` to test ESP32 I2C communication via backend and WebSocket.
- Created `load-example-transitions.test.ts` to ensure proper loading of examples between board-less and board-based contexts.
- Added `CircuitVerificationModal.tsx` to display circuit verification results before running simulations.
- Developed `circuitVerifier.ts` to perform pre-flight checks for circuit safety, identifying potential issues like short circuits and component overloads.
- Introduced minimal ESP32 I2C master sketch `esp32_i2c_writer.ino` for testing I2C transactions.
2026-05-12 16:55:15 -03:00
David Montero Crespo a097601a73 Add HD44780Decoder and various I2C sketches
- Implement HD44780Decoder for decoding I2C commands to HD44780-compatible LCDs.
- Add bmp280_bridge_reader.ino to read BMP280 chip_id and status registers via I2C.
- Create i2c_scanner_multi.ino to scan I2C addresses and report responding devices.
- Introduce lcd_i2c_hello.ino to demonstrate basic LCD functionality with I2C.
- Implement pcf8574_bidirectional.ino to test bidirectional communication with PCF8574.
- Add pico_i2c_master_reader.ino for reading BMP280 from a Raspberry Pi Pico.
- Create rtc_lcd_clock.ino to display time from a DS1307 RTC on an I2C LCD.
2026-05-12 14:26:33 -03:00
David Montero Crespo 8b1433deae refactor(spi): unify SPI bus interface across all simulators
Previous fix added an ESP32-specific code path inside ili9341Simulation
to subscribe to the QEMU worker's spi_event stream. That made the LCD
work on ESP32-CAM but left the underlying issue unsolved: every other
SPI part (custom chips, future SD-card emulators, the SSD168x ePaper
already in the codebase) would also need its own per-board branching.

The right shape: every simulator exposes a `.spi` member matching the
SAME SpiBusLike interface, and SPI parts hook .spi.onByte without
caring which board they're attached to. AVRSimulator already had
this — now everything else does too.

  frontend/src/simulation/SpiBus.ts (new)
    Defines the contract — `onByte: (mosi) => void | null` plus
    optional `completeTransfer(miso)`. Documents the single-listener
    semantics that AVR has had since day one.

  frontend/src/store/useSimulatorStore.ts
    Esp32BridgeShim gets a lazy `.spi` getter that wraps
    bridge.onSpiByte (the per-byte WS event from the QEMU worker).
    completeTransfer is a no-op because the worker drives MISO via
    its own _spi_response global. Covers ESP32 (Xtensa), ESP32-S3,
    ESP32-CAM, ESP32-C3 — every kind that routes through Esp32Bridge.

  frontend/src/simulation/RP2040Simulator.ts
    Adds a lazy `.spi` getter that re-routes rp2040.spi[0].onTransmit
    through the adapter. Default loopback (the prior behaviour) is
    preserved when no part has accessed `.spi` yet — only consumers
    that opt in see their handler invoked. Covers Pico and Pico W.

  frontend/src/simulation/parts/ComplexParts.ts
    ili9341Simulation no longer has an ESP32 special case. Single
    code path: `simulator.spi.onByte = handler`. Works on AVR,
    RP2040, all ESP32 variants. Same pattern is now available to
    every future SPI part — ssd1306, sd-card, oled, etc.

The Esp32Bridge.ts spi_event field-name fix from 6afa62e (msg.data.event
instead of the non-existent msg.data.data) stays in place — that's what
makes the per-byte stream actually arrive in the bridge.

Verified: ILI9341 + ESP32-CAM gallery example renders the live webcam
preview after a hard refresh. The same simulation code works on Arduino
Uno + ILI9341 (the existing ili9341-test-sketch in example_zip).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 22:36:29 -03:00
David Montero Crespo 6afa62ea17 fix(ili9341): add ESP32 SPI byte routing so the LCD renders on ESP32-CAM
The ILI9341 part simulation only hooked AVR's SPI peripheral. For
ESP32 the simulator is Esp32BridgeShim (no .spi member), so
attachEvents bailed early and the LCD stayed black even though the
firmware was driving SPI traffic correctly.

The QEMU worker already emits per-byte spi_event WS messages
(see backend/app/services/esp32_worker.py::_on_spi_event), and the
Esp32Bridge already had an onSpiEvent hook — but the bridge was
reading msg.data.data (a non-existent field) instead of decoding
the worker's {bus, event, response} format. Fixed.

Two changes:

1. Esp32Bridge.ts: decode the spi_event payload correctly. The
   worker encodes byte transfers as `mosi << 8` (op = low byte = 0x00)
   and CS-line changes as `((cs<<1)|level) << 8 | 0x01` (op == 0x01).
   Added onSpiByte (per-byte) and onSpiCsChange callbacks alongside
   the existing onSpiEvent for backwards compat.

2. ComplexParts.ts ili9341Simulation: detect Esp32BridgeShim via
   `getBridge()` duck-type check. When present, subscribe to
   bridge.onSpiByte and feed bytes into the same processCommand /
   processData pipeline used by the AVR path. DC tracking via
   pinManager.onPinChange already works for ESP32 because the bridge
   fires triggerPinChange on every gpio_change WS event.

Verified end-to-end: ESP32-CAM + ILI9341 example in the gallery now
renders the live webcam preview to the simulated TFT (160×120 RGB565
centered in the 320×240 panel) at ~3-4 fps.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-02 22:31:24 -03:00
David Montero Crespo 2e4c470f75 feat: add support for UC8159c (ACeP 7-colour) display
- Implement UC8159cDecoder for handling 7-colour ACeP panels.
- Introduce painting functions for UC8159c frames in EPaperPart.
- Update EPaperPart to handle both SSD168x and UC8159c frame types.
- Add integration tests for EPaperPart and UC8159cDecoder.
- Create example sketch for 5.65" ACeP 7-colour panel.
- Enhance error handling in test cases for library dependencies.
2026-04-30 00:27:40 -03:00
David Montero Crespo bcc7129aa3 feat: Add support for SSD168x ePaper panels
- Introduced EPaperPanels.ts to define configurations for various ePaper panels including dimensions, refresh rates, and controller details.
- Implemented SSD168xDecoder.ts to handle the decoding of SPI commands for the SSD168x family of ePaper displays.
- Created EPaperPart.ts to manage the simulation of ePaper panels, integrating with the existing simulator architecture and handling events.
- Added example sketches for 2.13", 2.9", 4.2", and 7.5" ePaper displays, demonstrating basic functionality and text rendering.
- Ensured compatibility with AVR, RP2040, and ESP32 platforms, with appropriate pin configurations for each.
2026-04-29 22:23:00 -03:00
David Montero Crespo 7f2014bef7 Add ESP32 chip demos and comprehensive tests for I2C, SPI, and UART interactions
- Implemented `esp32_spi_chip_demo.ino` to demonstrate SPI communication with a 74HC595 shift register.
- Created `esp32_uart_chip_demo.ino` for UART loopback testing with ROT13 transformation.
- Added Python tests for compiling chips and sketches, ensuring valid WASM output and successful compilation for various board families.
- Developed end-to-end tests for ESP32 with custom chips using I2C and SPI, validating synchronous communication through the backend.
- Introduced GPIO bridge tests to verify serial communication and GPIO state changes.
- Ensured all tests validate the expected behavior of the custom chips and their interaction with the ESP32 firmware.
2026-04-28 19:24:39 -03:00
davidmonterocrespo24 7e026179aa feat(photodiode): add lux control in sensor panel and property dialog
The SPICE emitter already reads properties.lux (default 500, 100 nA/lux)
but the UI had no way to set it — the static dialog rejected the "range"
control type and there was no entry in SENSOR_CONTROLS for the live panel.

- Add photodiode entry in SENSOR_CONTROLS (slider 0-1000 lux)
- Register a minimal PartSimulationRegistry handler that forwards slider
  values via emitPropertyChange so the netlist memo invalidates
- Switch the photodiode lux control from "range" to "number" so the
  static ComponentPropertyDialog renders an editable input
2026-04-24 16:42:36 +02:00
David Montero Crespo 692af00258 style: update ESLint rules and clean up code formatting across multiple files 2026-04-21 17:14:27 -03:00
David Montero Crespo 212ecd1bcb refactor: rename components and update prefixes to 'velxio-' for consistency
- Modified the index file to reflect the new naming convention for Velxio components.
- Changed JSX declarations to use 'velxio-' prefix for various components.
- Updated component overrides to replace 'wokwi-' with 'velxio-' for logic gates and other components.
- Adjusted SVG generation script to use 'velxio-' prefix for BMP280 and Raspberry Pi components.
- Marked submodules as dirty in QEMU and RP2040 libraries.
- Added .prettierignore and .prettierrc.json for consistent code formatting.
- Introduced InstrumentComponent with support for Voltmeter and Ammeter, including pin information handling.
2026-04-21 16:45:45 -03:00
David Montero Crespo b152cb1919 Refactor property synchronization in simulation parts; introduce emitPropertyChange event
- Replaced syncStoreProperty function with emitPropertyChange to decouple parts from Zustand store.
- Updated relay component mapping to ensure proper handling of coil and contact states.
- Added new test cases for half-wave rectifier and relay-controlled LED to ensure correct functionality.
- Introduced InlineComponentSVGs for schematic-style icons of various components.
- Updated submodule references for qemu-lcgamboa, rp2040js, and wokwi-elements to indicate dirty state.
2026-04-21 10:56:20 -03:00
David Montero Crespo 9cc9cfebd6 Add end-to-end tests for ammeter, voltmeter, and capacitor charging behavior
- Implement `ammeter-waveform.test.ts` to validate AC readings from a sine wave source.
- Create `capacitor-charge-transient.test.ts` to test the charging response of an RC circuit driven by a microcontroller pin.
- Introduce `esp32-rectifier-integration.test.ts` for testing rectifier behavior using QEMU and ESP32.
- Add helper functions in `esp32RectifierE2E.ts` for the rectifier test harness.
- Develop `voltmeter-waveform.test.ts` to ensure correct AC and DC readings from a sine wave source.
- Implement unit tests for waveform statistics in `waveform-stats.test.ts` to validate RMS, mean, peak, and interpolation functions.
- Create `waveformStats.ts` to provide statistical functions for time-domain waveform analysis.
2026-04-21 02:17:30 -03:00
David Montero Crespo 137f9ab0a0 Add tests for serial batching and spice rectifier functionality
- Implement `serial-batching.test.ts` to verify the behavior of `createSerialBatcher`, ensuring it coalesces multiple appends into a single flush, preserves byte order, and groups by board.
- Create `spice-rectifier-integration.test.ts` to test the end-to-end functionality of the Half-Wave Rectifier example, covering the entire simulation pipeline from input building to circuit solving.
- Add `spice-rectifier-live-repro.test.ts` to reproduce a live-app failure scenario, tracing through each layer of the simulation to identify potential failure points.
- Introduce `spice-signal-generator-tran.test.ts` to validate the behavior of the signal generator and ensure correct analysis type switching based on circuit components.
- Establish `serialBatcher.ts` to implement a batching mechanism for USART output, reducing the frequency of store updates and preventing React's maximum update depth error.
2026-04-20 23:56:42 -03:00
David Montero Crespo dcb8a92b79 feat: enhance electrical simulation and testing framework
- Decoupled electrical simulation from the simulator store, ensuring SPICE is always active for accurate circuit analysis.
- Removed feature flag for electrical simulation, simplifying the state management.
- Preloaded SPICE engine at app start to eliminate latency during the first solve.
- Added comprehensive tests for MOSFET PWM LED behavior and NPN transistor switch functionality, ensuring correct current flow and response to pin states.
- Implemented diagnostics for floating input nodes in RC low-pass filter circuits, addressing singular matrix issues in SPICE simulations.
- Introduced active semiconductor metadata registry for better component management and simulation fidelity.
- Updated Vite configuration to force re-bundling of local wokwi-elements after component additions.
2026-04-20 16:38:31 -03:00
David Montero Crespo 04d14a74b2 feat: always-on SPICE mode, full board ADC integration, LED brightness from current
Electrical simulation is now active by default (mode='spice' instead of
'off') — users no longer need to toggle the mode on manually. The engine
lazy-loads on first solve, so there is no startup cost penalty.

Changes:
- useElectricalStore: default mode = 'spice' when ELECTRICAL_SIM_ENABLED
- subscribeToStore: ADC_PIN_MAP expanded to all 18 board types (Uno, Nano,
  Mega with 16 ADC channels, ATtiny85, RP2040 GP26-29, ESP32/S3/C3 GPIO
  ADCs). Voltages from SPICE solutions now inject into MCU ADC peripherals
  for all boards.
- BasicParts LED: reads branchCurrents from useElectricalStore when SPICE
  is active. Brightness = clamp(|I_led| / 20mA, 0, 1) instead of boolean.
  Subscribes to store changes to update in real time.
- ElectricalOverlay: shows per-wire voltage labels (gold monospace on dark
  pill) using buildWireNetMap() which replicates the NetlistBuilder's
  Union-Find to map wireId -> netName -> nodeVoltage. Summary pill shows
  net count + solve time.
- NetlistBuilder: new export buildWireNetMap() for lightweight wire-to-net
  resolution without running ngspice.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:59:22 -03:00
David Montero Crespo 36543e2479 feat: expand SPICE component catalog (fases 9 + 10)
Adds 44 SPICE mappers, 58 custom metadata entries, and 12 visual
Web Components covering logic gates, transistors, op-amps, regulators,
sources, electromechanical parts and integrated-circuit packaging.

Fase 9 — component catalog expansion
------------------------------------
- 7 logic gates (AND/OR/NAND/NOR/XOR/XNOR + NOT) as SPICE B-sources
- 8 multi-input gates (AND/OR/NAND/NOR with 3 and 4 inputs)
- 9 transistors: 5 BJTs (incl. PNP 2N3906/BC557) + 4 MOSFETs (incl.
  P-channel IRF9540/FQP27P06). NMOS refactored from Level=3 W=0.1
  (hangs ngspice) to Level=1 with sane W/L
- 5 op-amps: LM358, LM741, TL072, LM324 with per-chip saturation
  rails + opamp-ideal
- 4 linear regulators (7805, 7812, 7905, LM317) with dropout
- 3 batteries (9V, AA, coin-cell) with realistic ESR
- Signal generator (sine / square / DC)
- 2 Schottky diodes (1N5817, 1N5819) + photodiode (lux-driven
  current source)

Fase 10 — electromechanical + ICs
---------------------------------
- Relay (SPDT): coil + L + S-switch with native hysteresis +
  flyback diode, inverted-control trick for the NC contact
- Optocouplers 4N25 and PC817 (LED + CCCS with CTR=0.5 / 1.0)
- 7 74HC ICs as DIP-14 packages emitting 4 or 6 B-sources per
  component (first mapper pattern emitting multiple device cards)
- 3 flip-flops (D, T, JK) — digital-sim only (edge detection is
  not representable in ngspice .op)
- L293D dual H-bridge motor driver

Infrastructure
--------------
- scripts/component-overrides.json gains a _customComponents[] array
  that lets new Velxio-only parts survive metadata regeneration
  (previously applyOverrides() could only patch wokwi-elements
  components that had already been scanned)
- scripts/generate-component-metadata.ts injects custom entries
  before the patch loop
- New ComponentCategory values: 'logic', 'analog', 'electromech'
- frontend/src/components/DynamicComponent.tsx PASSIVE tracing
  extended from just ['resistor','resistor-us'] to 9 two-terminal
  passives with per-part pin name maps
- New CI workflow test-circuit.yml runs the sandbox on push/PR
- frontend-tests.yml regenerates metadata and fails if committed
  JSON is stale
- Documented 2 new ngspice gotchas in circuit-emulation-gotchas.md:
  unicode in netlist titles silently hangs the parser, and
  MOSFET Level=3 + W=0.1m causes .op to hang
- 164/164 sandbox tests passing in ~9 s (was 88 pre-fase-9)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-15 22:41:26 -03:00
David Montero Crespo ca6520e48d feat: Update I2C event handling and improve MPU-6050 slave emulation; enhance README and tests 2026-04-08 00:02:54 -03:00
David Montero Crespo 689f8e71db feat: Add I2C slave emulation for MPU-6050 and BMP280 sensors
- Implemented _MPU6050Slave and _BMP280Slave classes for I2C communication.
- Enhanced main function to register these sensors and handle I2C events.
- Updated sensor management to support MPU-6050, BMP280, DS1307, DS3231, SSD1306, and PCF8574.
- Added frontend examples for BMP280 weather station and SSD1306 OLED display.
- Modified Esp32Bridge to handle new I2C transaction events.
- Updated ProtocolParts to support ESP32 path for I2C devices.
- Enhanced useSimulatorStore to manage I2C transaction listeners.
2026-04-07 15:43:09 -03:00
David Montero Crespo a3db014d2d feat: multi-arch Docker (amd64+arm64) and fix LED ground check
Docker multi-arch:
- Dockerfile downloads arch-specific QEMU .so via TARGETARCH
- docker-publish.yml adds setup-qemu-action and platforms: linux/amd64,linux/arm64
- qemu-lcgamboa submodule updated (matrix build for both architectures)

LED fix:
- LEDs now require cathode wired to GND (or LOW GPIO) to light up
- Previously LEDs turned on with anode HIGH regardless of cathode connection
- Updated tests to verify anode+cathode behavior
2026-04-07 03:58:52 -03:00
David Montero Crespo 97f8f6cd52 feat: add protocol selection and editable properties in component dialogs 2026-04-07 03:58:17 -03:00
David Montero Crespo 0290b24a47 feat: remove unnecessary logging and diagnostic dumps in ESP32 worker; update WS2812 event handling in simulator store 2026-03-24 14:38:08 -03:00
David Montero Crespo 01f75cf313 feat: implement eager scan for LEDC GPIO mapping and add tests for race condition fix 2026-03-24 13:54:44 -03:00
David Montero Crespo aa6522fd60 feat: Enhance DHT22 sync handling, improve ADC support for ESP32, and update component metadata 2026-03-23 10:37:06 -03:00
David Montero Crespo 083d8d69a8 feat: Add HC-SR04 sensor support and enhance DHT22 response timing in simulation 2026-03-22 18:39:09 -03:00
David Montero Crespo 6a55f58e46 feat: Implement generic sensor registration for ESP32 and RP2040
- Added board-agnostic sensor registration methods in RP2040Simulator.
- Enhanced ComplexParts to handle LEDC PWM duty updates for ESP32.
- Updated ProtocolParts to check if the simulator handles sensor protocols natively, delegating to backend if applicable.
- Introduced pre-registration of sensors in useSimulatorStore for ESP32 to prevent race conditions.
- Added tests for ESP32 DHT22 sensor registration flow, ensuring proper delegation and fallback mechanisms.
- Created tests for ESP32 Servo and Potentiometer interactions, verifying PWM subscriptions and ADC handling.
2026-03-22 18:03:17 -03:00
David Montero Crespo f5257009cd feat: implement DHT22 sensor support with attach, update, and detach functionality in ESP32 simulation 2026-03-22 15:17:44 -03:00
David Montero Crespo 84370e6f8d feat: enhance simulator interfaces and add ESP32 bridge shim for improved component interaction 2026-03-22 02:25:58 -03:00
David Montero Crespo ee7281383c feat: remove unnecessary logging and streamline potentiometer and servo simulations 2026-03-21 17:20:48 -03:00
David Montero Crespo aac3465d49 feat: update component metadata timestamp and enhance RP2040 simulator for accurate PIO stepping and servo calibration 2026-03-21 17:12:06 -03:00
David Montero Crespo 43f13e1bc2 feat: implement synchronous PIO stepping and enhance servo pulse width measurement 2026-03-21 16:41:20 -03:00
David Montero Crespo b900f960ad feat: update pin mappings and descriptions for Raspberry Pi Pico examples 2026-03-21 14:02:46 -03:00
David Montero Crespo dc5dfb8635 feat: enhance simulation accuracy and component interactions across various modules 2026-03-20 17:11:12 -03:00
David Montero Crespo f6fdae6b0e feat: enhance DHT22 and HC-SR04 simulations with cycle-accurate pin changes 2026-03-19 08:22:36 -03:00
David Montero Crespo 8ba11800e1 feat: add SensorControlPanel for interactive sensor controls
- Implemented SensorControlPanel component to allow real-time adjustments of sensor values during simulation.
- Introduced SensorUpdateRegistry for communication between UI and simulation.
- Added configuration for various sensors including sliders and buttons for user interaction.
- Enhanced existing sensor parts to support updates from SensorControlPanel.
- Created CSS styles for the SensorControlPanel layout and controls.
2026-03-19 01:52:46 -03:00
David Montero Crespo d35ad2d2f7 Refactor code structure for improved readability and maintainability 2026-03-16 18:31:46 -03:00
David Montero Crespo bc31ee76c1 feat: enhance oscilloscope and simulator functionality
- Added `onPinStateChange` method to `ChipParts` for handling pin state changes in 7-segment displays.
- Updated `useOscilloscopeStore` to allow independent monitoring of multiple boards by adding `boardId` to channels and modifying `addChannel` method.
- Modified `getOscilloscopeCallback` in `useSimulatorStore` to filter channels based on `boardId` and pin number.
- Adjusted component and board position calculations in `useSimulatorStore` to account for wrapper offsets.
- Updated submodule references for `qemu-lcgamboa`, `rp2040js`, and `wokwi-elements` to indicate dirty states.
2026-03-16 10:31:02 -03:00
David Montero Crespo b0b3a8763d V1 feat: Enhance ESP32 emulation support and logging
- Added detailed logging for GPIO changes, system events, and errors in simulation websocket.
- Improved ESP32 firmware handling by merging individual binaries into a single 4MB flash image.
- Updated ESP32 bridge to handle serial output and GPIO changes with appropriate logging.
- Introduced integration test for ESP32 emulation, covering compilation, WebSocket connection, and event handling.
- Enhanced examples to include ESP32 projects and updated the examples gallery to reflect new board types.
- Refactored simulator store to manage ESP32 bridge and simulator instances more effectively.
- Updated requirements to include esptool for ESP32 firmware management.
2026-03-14 16:57:22 -03:00
David Montero Crespo b89f85e5f7 Merge branch 'feat/raspberryPi_emuation' of https://github.com/davidmonterocrespo24/wokwi_clon into feat/raspberryPi_emuation 2026-03-12 08:26:56 -03:00