From a0ba1fbd28322a2daab1d6facb44090eedd83b5f Mon Sep 17 00:00:00 2001 From: David Montero Crespo Date: Wed, 29 Jul 2026 20:55:05 +0200 Subject: [PATCH] fix(uart): el enganche de serie sobrevive a recrear el simulador El fan-out del Interconnect envuelve el onSerialData de la INSTANCIA y la marca con un flag. Compilar, resetear o cambiar de motor crea una instancia nueva: sin flag y sin envoltorio, asi que la placa dejaba de oirse por el cable a mitad de sesion. Sintoma real: la Pi en modo Linux encendia el LED del Arduino (Pi -> Uno), pero la respuesta del Arduino no volvia nunca (Uno -> Pi), porque el Uno habia recreado su simulador al compilar despues de que se construyeran las rutas. Se vuelve a enganchar en cada simulatorMap.set (siete puntos: AVR, RP2040, RISC-V, ESP32, STM32 y los shims). --- frontend/src/simulation/Interconnect.ts | 6 ++++- frontend/src/store/useSimulatorStore.ts | 35 +++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/frontend/src/simulation/Interconnect.ts b/frontend/src/simulation/Interconnect.ts index 51709cd9..2ef3f857 100644 --- a/frontend/src/simulation/Interconnect.ts +++ b/frontend/src/simulation/Interconnect.ts @@ -756,7 +756,11 @@ export function notifyBoardReady(_boardId: string, wires: readonly Wire[]): void */ export function reensureSerialHooks(boardId: string): void { const entry = boards.get(boardId); - if (entry && entry.serialFanout.size > 0) ensureSerialHook(entry); + if (!entry || entry.serialFanout.size === 0) return; + // The hook lives on the sim/bridge INSTANCE and marks it with a flag. + // A fresh instance carries no flag, so ensureSerialHook installs on it; + // this call is what makes that happen after a compile or a reconnect. + ensureSerialHook(entry); } /** For tests: reset all internal state. */ diff --git a/frontend/src/store/useSimulatorStore.ts b/frontend/src/store/useSimulatorStore.ts index eee8effe..bcbce6cd 100644 --- a/frontend/src/store/useSimulatorStore.ts +++ b/frontend/src/store/useSimulatorStore.ts @@ -1215,6 +1215,11 @@ export const useSimulatorStore = create((set, get) => { try { existingShim.clearAllProxies(); } catch { /* ignore */ } } simulatorMap.set(id, shim); + // The Interconnect's serial fan-out wraps the INSTANCE's + // onSerialData; a fresh simulator (compile, reset, engine + // swap) drops that wrapper, so a wired peer stopped + // hearing this board mid-session. Re-ensure it here. + icReensureSerialHooks(id); } const initialSim = createSimulator( @@ -1382,6 +1387,11 @@ export const useSimulatorStore = create((set, get) => { // Shim so PartSimulationRegistry parts (I2C displays, sensors, SPI // panels) attach to this STM32 the same way they do on ESP32. simulatorMap.set(id, new Stm32BridgeShim(bridge, pm)); + // The Interconnect's serial fan-out wraps the INSTANCE's + // onSerialData; a fresh simulator (compile, reset, engine + // swap) drops that wrapper, so a wired peer stopped + // hearing this board mid-session. Re-ensure it here. + icReensureSerialHooks(id); } else { const sim = createSimulator( boardKind, @@ -1400,6 +1410,11 @@ export const useSimulatorStore = create((set, get) => { ); // Cross-board routing now handled by Interconnect (see bind below). simulatorMap.set(id, sim); + // The Interconnect's serial fan-out wraps the INSTANCE's + // onSerialData; a fresh simulator (compile, reset, engine + // swap) drops that wrapper, so a wired peer stopped + // hearing this board mid-session. Re-ensure it here. + icReensureSerialHooks(id); // ── Attach a PIO bus peripheral if a factory supports this board. // The pro overlay registers a CYW43 WiFi peripheral for 'pi-pico-w' @@ -2400,6 +2415,11 @@ export const useSimulatorStore = create((set, get) => { const shim = new Esp32BridgeShim(bridge, pm); shim.onSerialData = serialCallback; simulatorMap.set(boardId, shim); + // The Interconnect's serial fan-out wraps the INSTANCE's + // onSerialData; a fresh simulator (compile, reset, engine + // swap) drops that wrapper, so a wired peer stopped + // hearing this board mid-session. Re-ensure it here. + icReensureSerialHooks(boardId); set((s) => ({ boardType: type, @@ -2434,6 +2454,11 @@ export const useSimulatorStore = create((set, get) => { getOscilloscopeCallback(boardId), ); simulatorMap.set(boardId, sim); + // The Interconnect's serial fan-out wraps the INSTANCE's + // onSerialData; a fresh simulator (compile, reset, engine + // swap) drops that wrapper, so a wired peer stopped + // hearing this board mid-session. Re-ensure it here. + icReensureSerialHooks(boardId); set((s) => ({ boardType: type, @@ -2513,6 +2538,11 @@ export const useSimulatorStore = create((set, get) => { const shim = new Esp32BridgeShim(bridge, pm); shim.onSerialData = serialCallback; simulatorMap.set(boardId, shim); + // The Interconnect's serial fan-out wraps the INSTANCE's + // onSerialData; a fresh simulator (compile, reset, engine + // swap) drops that wrapper, so a wired peer stopped + // hearing this board mid-session. Re-ensure it here. + icReensureSerialHooks(boardId); set({ simulator: shim as any, serialOutput: '', serialBaudRate: 0 }); } else { const sim = createSimulator( @@ -2529,6 +2559,11 @@ export const useSimulatorStore = create((set, get) => { getOscilloscopeCallback(boardId), ); simulatorMap.set(boardId, sim); + // The Interconnect's serial fan-out wraps the INSTANCE's + // onSerialData; a fresh simulator (compile, reset, engine + // swap) drops that wrapper, so a wired peer stopped + // hearing this board mid-session. Re-ensure it here. + icReensureSerialHooks(boardId); set({ simulator: sim, serialOutput: '', serialBaudRate: 0 }); } console.log(`Simulator initialized: ${boardType}`);