Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
.DS_Store
Thumbs.db
*.bak
*.hex
*.swp
*~
*.log
Expand Down Expand Up @@ -42,8 +43,8 @@ yarn-error.log*
/playwright-report/
/screenshots/

# Old archive folder (legacy, use /docs/archive instead)
/archive/
# archive folder
**/archive/

##################################
# 4. COMPILER & TYPESCRIPT #
Expand Down
4 changes: 3 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@
},
"/bin/ls": true,
"/usr/bin/git": true,
"test": true
"test": true,
"clear": true,
"printf": true
},
}
243 changes: 151 additions & 92 deletions client/src/components/features/parser-output.tsx

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions client/src/hooks/use-compile-and-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,17 @@ export function useCompileAndRun(params: CompileAndRunParams): UseCompileAndRunR
if (!params.ensureBackendConnected("Simulation starten")) return;
params.setDebugMessages([]);

// Reset I/O registry so old entries don't persist across recompilations
params.resetPinUI();
const freshPins: IOPinRecord[] = [];
for (let i = 0; i <= 13; i++) {
freshPins.push({ pin: String(i), defined: false, usedAt: [] });
}
for (let i = 0; i <= 5; i++) {
freshPins.push({ pin: `A${i}`, defined: false, usedAt: [] });
}
params.setIoRegistry(freshPins);

let mainSketchCode: string = "";
if (params.editorRef.current) {
try {
Expand Down Expand Up @@ -647,6 +658,7 @@ export function useCompileAndRun(params: CompileAndRunParams): UseCompileAndRunR
params.ensureBackendConnected,
params.resetPinUI,
params.setDebugMessages,
params.setIoRegistry,
params.setIsModified,
startSimulationInternal,
params.tabs,
Expand Down
12 changes: 4 additions & 8 deletions client/src/hooks/use-simulation-store.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { useSyncExternalStore } from "react";
import { telemetryStore } from "./use-telemetry-store";

type PinMode = "INPUT" | "OUTPUT" | "INPUT_PULLUP";
export type PinStateType = "mode" | "value" | "pwm";
Expand Down Expand Up @@ -229,14 +230,9 @@ if (typeof window !== "undefined") {
resetAllStores: async () => {
// Reset simulation store
simulationStore.resetToInitial();

// Reset telemetry store (lazy import to avoid circular dependencies)
try {
const { telemetryStore } = await import('./use-telemetry-store');
telemetryStore.resetToInitial();
} catch (err) {
console.warn('[SIM_DEBUG] Could not reset telemetry store:', err);
}

// Reset telemetry store
telemetryStore.resetToInitial();
},
};
}
Expand Down
28 changes: 27 additions & 1 deletion client/src/hooks/useWebSocketHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,7 +216,33 @@ export function useWebSocketHandler(params: UseWebSocketHandlerParams) {
}
case "io_registry": {
const { registry, baudrate } = message as any;
setIoRegistry(registry);

// Merge runtime registry with static registry (preserve static usedAt with line numbers)
setIoRegistry((prevRegistry) => {
const merged = new Map<string, IOPinRecord>();

// Start with previous registry (contains static analysis with line numbers)
for (const rec of prevRegistry) {
merged.set(rec.pin, { ...rec });
}

// Update with runtime pinMode/defined state
for (const runtimeRec of registry) {
const current = merged.get(runtimeRec.pin);
if (current) {
// Update pinMode and defined state from runtime
if (runtimeRec.defined !== undefined) current.defined = runtimeRec.defined;
if (runtimeRec.pinMode !== undefined) current.pinMode = runtimeRec.pinMode;
if (runtimeRec.hasConflict !== undefined) current.hasConflict = runtimeRec.hasConflict;
// Keep static usedAt (with line numbers), don't overwrite with runtime (line: 0)
} else {
// Add new pin from runtime (shouldn't normally happen with static parsing)
merged.set(runtimeRec.pin, { ...runtimeRec });
}
}

return Array.from(merged.values());
});

if (typeof baudrate === "number" && baudrate > 0) {
setBaudRate(baudrate);
Expand Down
44 changes: 44 additions & 0 deletions client/src/pages/arduino-simulator.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ const LoadingPlaceholder = () => (

// Logger import
import { Logger } from "@shared/logger";
import { CodeParser } from "@shared/code-parser";
const logger = new Logger("ArduinoSimulator");

export default function ArduinoSimulator() {
Expand Down Expand Up @@ -692,6 +693,49 @@ export default function ArduinoSimulator() {
});
}, [detectedPinModes, simulationStatus]);

// Static IO analysis: populate ioRegistry from source code (always active, even during simulation)
useEffect(() => {
if (!code.trim()) return;
try {
const parser = new CodeParser();
const staticRegistry = parser.buildStaticIORegistry(code);

// If simulation is running, merge with current registry to preserve runtime updates
if (simulationStatus === "running") {
setIoRegistry((prevRegistry) => {
const merged = new Map<string, IOPinRecord>();

// Start with static registry (has line numbers from source code)
for (const rec of staticRegistry) {
merged.set(rec.pin, { ...rec });
}

// Overlay runtime pinMode/defined state from previous registry
for (const prevRec of prevRegistry) {
const current = merged.get(prevRec.pin);
if (current) {
// Keep runtime pinMode if it differs from static (e.g., user interactions)
if (prevRec.defined && prevRec.pinMode !== current.pinMode) {
current.pinMode = prevRec.pinMode;
current.defined = prevRec.defined;
}
} else {
// Add pins that are only in runtime (shouldn't normally happen)
merged.set(prevRec.pin, { ...prevRec });
}
}

return Array.from(merged.values());
});
} else {
// Simulation not running: use pure static registry
setIoRegistry(staticRegistry);
}
} catch {
// ignore parse errors — don't crash the UI
}
}, [code, simulationStatus]);

// When simulation stops, flush any pending incomplete lines to make them visible
useEffect(() => {
if (simulationStatus === "stopped" && serialOutput.length > 0) {
Expand Down
Loading
Loading