From a1137f19299d870992d82e5c3015d3be9ea3907e Mon Sep 17 00:00:00 2001 From: David Montero Date: Thu, 2 Jul 2026 22:33:46 +0200 Subject: [PATCH] fix(sim): re-solve SPICE on ESP32/STM32/Pi output pin edges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit WebSocket-backed boards (ESP32, STM32, Raspberry Pi) reach the electrical simulation only through PinManager.triggerPinChange, which updated the pin state + notified listeners but never requested an electrical re-solve. AVR and RP2040 already resolve at their own toggle sites. As a result an analog part on an MCU-driven net (e.g. a resistor-less LED whose brightness comes from the SPICE solve) stayed at its first solved value until unrelated activity (such as serial output) forced a solve — so an ESP32 blink with no Serial in loop() left the LED stuck on. Request an electrical re-solve after an 'mcu'-sourced pin edge, in one place (triggerPinChange), covering all WS boards. Gated to source==='mcu' so the solver's own input feedback (triggerPinChange with the default 'external' source) can't loop; requestElectricalResolve coalesces overlapping ticks so a per-edge call is cheap. --- frontend/src/simulation/PinManager.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/frontend/src/simulation/PinManager.ts b/frontend/src/simulation/PinManager.ts index c1c72f99..445e72fb 100644 --- a/frontend/src/simulation/PinManager.ts +++ b/frontend/src/simulation/PinManager.ts @@ -16,6 +16,8 @@ * - PWM duty cycle tracking (for servos, RGB LEDs, buzzers) */ +import { requestElectricalResolve } from './spice/electricalResolveHook'; + export type PinState = boolean; export type PinChangeCallback = (pin: number, state: PinState) => void; export type AnalogCallback = (pin: number, voltage: number) => void; @@ -155,6 +157,16 @@ export class PinManager { if (callbacks) { callbacks.forEach((cb) => cb(pin, state)); } + // An MCU output edge changes the circuit: request a SPICE re-solve so the + // analog parts on this net (LED brightness, etc.) update. WS-backed boards + // (ESP32 / STM32 / Raspberry Pi) reach the electrical sim ONLY through here + // — previously they never triggered a re-solve, so a resistor-less LED + // stayed at its first solved brightness until unrelated activity (e.g. + // serial output) forced a solve. AVR / RP2040 already resolve at their own + // toggle sites. Gated to 'mcu' so the solver's own input feedback + // (triggerPinChange with the default 'external' source) can't create a + // solve loop; the hook coalesces overlapping ticks so per-edge is cheap. + if (source === 'mcu') requestElectricalResolve(); } /** Pins the MCU has actively driven this session. */