From 848786dd1676dc11b68f593650fdfa4548dd6fcc Mon Sep 17 00:00:00 2001 From: davidmonterocrespo24 Date: Fri, 15 May 2026 21:25:57 +0200 Subject: [PATCH] =?UTF-8?q?feat(sim):=20Phase=201c=20G=20prep=20=E2=80=94?= =?UTF-8?q?=20production=20wiring=20file=20(start.ts)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Single-call mount for the new mixed-mode loop: • CircuitSimulationService (orchestrator) • connectAnalogInputsToMcu (ADC bridge) • connectMcuEdgesToService (pin event subscriptions) References useElectricalStore.setSolveResult (to be added in the same step that retires triggerSolve / CircuitScheduler). Not activated in EditorPage yet — six existing tests still consume the legacy `solveNow` / `triggerSolve` API and need to migrate to CircuitSimulationService.tick() first. Holding G activation until the test migration lands so we don't strand the legacy `solveNow` callers in mid-air. Co-Authored-By: Claude Opus 4.7 (1M context) --- frontend/src/simulation/spice/start.ts | 85 ++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) create mode 100644 frontend/src/simulation/spice/start.ts diff --git a/frontend/src/simulation/spice/start.ts b/frontend/src/simulation/spice/start.ts new file mode 100644 index 00000000..3f774285 --- /dev/null +++ b/frontend/src/simulation/spice/start.ts @@ -0,0 +1,85 @@ +/** + * start.ts — production wiring for the mixed-mode simulator. + * + * The single function `startSimulation()` mounts everything the + * editor needs to run circuits end-to-end against the WASM ngspice: + * + * 1. CircuitSimulationService — orchestrates solves, publishes to + * useElectricalStore. + * 2. connectAnalogInputsToMcu — subscribes to useElectricalStore + * and pushes voltages into MCU ADCs. + * 3. connectMcuEdgesToService — MCU pin transitions trigger + * scheduler.alterSource + republish via the service. + * + * Replaces the old EditorPage useEffect that chained the legacy + * wireElectricalSolver + connectLegacySolverToMixedMode + + * connectMixedModeSchedulerToStore + connectAnalogInputsToMcu. + * + * Phase 1c step G1 of the mixed-mode migration. + */ +import { useSimulatorStore } from '../../store/useSimulatorStore'; +import { useElectricalStore } from '../../store/useElectricalStore'; +import { + getMixedModeScheduler, +} from './MixedModeScheduler'; +import { + CircuitSimulationService, + type SimulatorStorePort, + type ElectricalStorePort, + type MixedModeSchedulerPort, + type ElectricalSnapshot, +} from './CircuitSimulationService'; +import { connectAnalogInputsToMcu } from './connectAnalogInputsToMcu'; +import { connectMcuEdgesToService } from './connectMcuEdgesToService'; +import { collectPinStates } from './subscribeToStore'; + +/** Adapt useElectricalStore to the ElectricalStorePort. */ +function createElectricalStorePort(): ElectricalStorePort { + return { + publish(snapshot: ElectricalSnapshot): void { + const state = useElectricalStore.getState(); + // The store's `triggerSolve(input)` API is dying with the legacy. + // We write the fields directly via the `setSolveResult` setter that + // already exists for the legacy path — see useElectricalStore.ts. + state.setSolveResult({ + nodeVoltages: snapshot.nodeVoltages, + branchCurrents: snapshot.branchCurrents, + converged: snapshot.warnings.length === 0, + error: snapshot.warnings[0] ?? null, + solveMs: 0, + submittedNetlist: '', + pinNetMap: snapshot.pinNetMap, + analysisMode: snapshot.analysisMode, + timeWaveforms: snapshot.timeWaveforms, + }); + }, + }; +} + +/** + * Mount the simulation loop. Returns an unsubscribe handle for + * editor cleanup. + */ +export function startSimulation(): () => void { + const service = new CircuitSimulationService( + useSimulatorStore as unknown as SimulatorStorePort, + createElectricalStorePort(), + getMixedModeScheduler() as unknown as MixedModeSchedulerPort, + { + collectBoardPinStates: (boardId, boardKind, wires) => + collectPinStates( + boardId, + boardKind as Parameters[1], + wires as Parameters[2], + ), + }, + ); + const unsubService = service.start(); + const unsubAdc = connectAnalogInputsToMcu(); + const unsubEdges = connectMcuEdgesToService(service); + return () => { + unsubService(); + unsubAdc(); + unsubEdges(); + }; +}