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).
This commit is contained in:
David Montero Crespo 2026-07-29 20:55:05 +02:00
parent 3f867f7234
commit a0ba1fbd28
2 changed files with 40 additions and 1 deletions

View File

@ -756,7 +756,11 @@ export function notifyBoardReady(_boardId: string, wires: readonly Wire[]): void
*/ */
export function reensureSerialHooks(boardId: string): void { export function reensureSerialHooks(boardId: string): void {
const entry = boards.get(boardId); 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. */ /** For tests: reset all internal state. */

View File

@ -1215,6 +1215,11 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
try { existingShim.clearAllProxies(); } catch { /* ignore */ } try { existingShim.clearAllProxies(); } catch { /* ignore */ }
} }
simulatorMap.set(id, shim); 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( const initialSim = createSimulator(
@ -1382,6 +1387,11 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
// Shim so PartSimulationRegistry parts (I2C displays, sensors, SPI // Shim so PartSimulationRegistry parts (I2C displays, sensors, SPI
// panels) attach to this STM32 the same way they do on ESP32. // panels) attach to this STM32 the same way they do on ESP32.
simulatorMap.set(id, new Stm32BridgeShim(bridge, pm)); 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 { } else {
const sim = createSimulator( const sim = createSimulator(
boardKind, boardKind,
@ -1400,6 +1410,11 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
); );
// Cross-board routing now handled by Interconnect (see bind below). // Cross-board routing now handled by Interconnect (see bind below).
simulatorMap.set(id, sim); 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. // ── Attach a PIO bus peripheral if a factory supports this board.
// The pro overlay registers a CYW43 WiFi peripheral for 'pi-pico-w' // The pro overlay registers a CYW43 WiFi peripheral for 'pi-pico-w'
@ -2400,6 +2415,11 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
const shim = new Esp32BridgeShim(bridge, pm); const shim = new Esp32BridgeShim(bridge, pm);
shim.onSerialData = serialCallback; shim.onSerialData = serialCallback;
simulatorMap.set(boardId, shim); 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) => ({ set((s) => ({
boardType: type, boardType: type,
@ -2434,6 +2454,11 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
getOscilloscopeCallback(boardId), getOscilloscopeCallback(boardId),
); );
simulatorMap.set(boardId, sim); 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) => ({ set((s) => ({
boardType: type, boardType: type,
@ -2513,6 +2538,11 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
const shim = new Esp32BridgeShim(bridge, pm); const shim = new Esp32BridgeShim(bridge, pm);
shim.onSerialData = serialCallback; shim.onSerialData = serialCallback;
simulatorMap.set(boardId, shim); 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 }); set({ simulator: shim as any, serialOutput: '', serialBaudRate: 0 });
} else { } else {
const sim = createSimulator( const sim = createSimulator(
@ -2529,6 +2559,11 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
getOscilloscopeCallback(boardId), getOscilloscopeCallback(boardId),
); );
simulatorMap.set(boardId, sim); 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 }); set({ simulator: sim, serialOutput: '', serialBaudRate: 0 });
} }
console.log(`Simulator initialized: ${boardType}`); console.log(`Simulator initialized: ${boardType}`);