feat: enhance RP2040 and AVR simulators with serial baud rate handling; update editor toolbar and library manager modal for improved state management and UI
parent
4ba2ccb877
commit
9b8747349f
|
|
@ -224,6 +224,13 @@ class ArduinoCLIService:
|
|||
|
||||
# arduino-cli requires sketch name to match directory name
|
||||
sketch_file = sketch_dir / "sketch.ino"
|
||||
|
||||
# For RP2040 boards, redirect Serial (USB CDC) to Serial1 (UART0)
|
||||
# The emulator captures UART0 output, but the arduino-pico core
|
||||
# defaults Serial to USB CDC which isn't emulated.
|
||||
if "rp2040" in board_fqbn:
|
||||
code = "#define Serial Serial1\n" + code
|
||||
|
||||
sketch_file.write_text(code)
|
||||
print(f"Created sketch file: {sketch_file}")
|
||||
|
||||
|
|
|
|||
|
|
@ -3,12 +3,18 @@ import { useEditorStore } from '../../store/useEditorStore';
|
|||
import { useSimulatorStore, BOARD_FQBN, BOARD_LABELS } from '../../store/useSimulatorStore';
|
||||
import { compileCode } from '../../services/compilation';
|
||||
import { LibraryManagerModal } from '../simulator/LibraryManagerModal';
|
||||
import { CompilationConsole } from './CompilationConsole';
|
||||
import { parseCompileResult } from '../../utils/compilationLogger';
|
||||
import type { CompilationLog } from '../../utils/compilationLogger';
|
||||
import './EditorToolbar.css';
|
||||
|
||||
export const EditorToolbar = () => {
|
||||
interface EditorToolbarProps {
|
||||
consoleOpen: boolean;
|
||||
setConsoleOpen: (open: boolean | ((v: boolean) => boolean)) => void;
|
||||
compileLogs: CompilationLog[];
|
||||
setCompileLogs: (logs: CompilationLog[] | ((prev: CompilationLog[]) => CompilationLog[])) => void;
|
||||
}
|
||||
|
||||
export const EditorToolbar = ({ consoleOpen, setConsoleOpen, compileLogs: _compileLogs, setCompileLogs }: EditorToolbarProps) => {
|
||||
const { code } = useEditorStore();
|
||||
const {
|
||||
boardType,
|
||||
|
|
@ -23,12 +29,10 @@ export const EditorToolbar = () => {
|
|||
const [compiling, setCompiling] = useState(false);
|
||||
const [message, setMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
|
||||
const [libManagerOpen, setLibManagerOpen] = useState(false);
|
||||
const [consoleOpen, setConsoleOpen] = useState(false);
|
||||
const [compileLogs, setCompileLogs] = useState<CompilationLog[]>([]);
|
||||
|
||||
const addLog = useCallback((log: CompilationLog) => {
|
||||
setCompileLogs((prev) => [...prev, log]);
|
||||
}, []);
|
||||
setCompileLogs((prev: CompilationLog[]) => [...prev, log]);
|
||||
}, [setCompileLogs]);
|
||||
|
||||
const handleCompile = async () => {
|
||||
setCompiling(true);
|
||||
|
|
@ -45,7 +49,7 @@ export const EditorToolbar = () => {
|
|||
|
||||
// Parse the full result into log entries
|
||||
const resultLogs = parseCompileResult(result, boardLabel);
|
||||
setCompileLogs((prev) => [...prev, ...resultLogs]);
|
||||
setCompileLogs((prev: CompilationLog[]) => [...prev, ...resultLogs]);
|
||||
|
||||
if (result.success) {
|
||||
if (result.hex_content) {
|
||||
|
|
@ -203,18 +207,6 @@ export const EditorToolbar = () => {
|
|||
<div className="toolbar-error-detail">{message.text}</div>
|
||||
)}
|
||||
|
||||
{/* Compilation Console */}
|
||||
{consoleOpen && (
|
||||
<div style={{ height: 200, flexShrink: 0 }}>
|
||||
<CompilationConsole
|
||||
isOpen={consoleOpen}
|
||||
onClose={() => setConsoleOpen(false)}
|
||||
logs={compileLogs}
|
||||
onClear={() => setCompileLogs([])}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<LibraryManagerModal isOpen={libManagerOpen} onClose={() => setLibManagerOpen(false)} />
|
||||
</>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -191,6 +191,12 @@
|
|||
animation: spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.lib-spinner-center {
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
|
|
|
|||
|
|
@ -33,26 +33,29 @@ export const LibraryManagerModal: React.FC<LibraryManagerModalProps> = ({ isOpen
|
|||
}
|
||||
}, []);
|
||||
|
||||
// Fetch installed list when modal opens (to cross-reference in search tab)
|
||||
// Reset state when modal closes
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
fetchInstalled();
|
||||
if (!isOpen) {
|
||||
setSearchQuery('');
|
||||
setSearchResults([]);
|
||||
setStatusMsg(null);
|
||||
}
|
||||
}, [isOpen, fetchInstalled]);
|
||||
}, [isOpen]);
|
||||
|
||||
// Also refresh when switching to the installed tab
|
||||
// Fetch installed list when modal opens or switching to installed tab
|
||||
useEffect(() => {
|
||||
if (isOpen && activeTab === 'installed') {
|
||||
fetchInstalled();
|
||||
}
|
||||
if (isOpen && activeTab === 'installed') fetchInstalled();
|
||||
}, [isOpen, activeTab, fetchInstalled]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!searchQuery.trim()) {
|
||||
setSearchResults([]);
|
||||
return;
|
||||
}
|
||||
if (isOpen) fetchInstalled();
|
||||
}, [isOpen, fetchInstalled]);
|
||||
|
||||
// Search: immediate on open (empty query), debounced when typing
|
||||
useEffect(() => {
|
||||
if (!isOpen) return;
|
||||
if (debounceRef.current) clearTimeout(debounceRef.current);
|
||||
const delay = searchQuery ? 400 : 0;
|
||||
debounceRef.current = setTimeout(async () => {
|
||||
setLoadingSearch(true);
|
||||
setStatusMsg(null);
|
||||
|
|
@ -65,10 +68,10 @@ export const LibraryManagerModal: React.FC<LibraryManagerModalProps> = ({ isOpen
|
|||
} finally {
|
||||
setLoadingSearch(false);
|
||||
}
|
||||
}, 500);
|
||||
}, delay);
|
||||
|
||||
return () => { if (debounceRef.current) clearTimeout(debounceRef.current); };
|
||||
}, [searchQuery]);
|
||||
}, [searchQuery, isOpen]);
|
||||
|
||||
const handleInstall = async (libName: string) => {
|
||||
setInstallingLib(libName);
|
||||
|
|
@ -89,9 +92,6 @@ export const LibraryManagerModal: React.FC<LibraryManagerModalProps> = ({ isOpen
|
|||
};
|
||||
|
||||
const handleClose = () => {
|
||||
setStatusMsg(null);
|
||||
setSearchQuery('');
|
||||
setSearchResults([]);
|
||||
onClose();
|
||||
};
|
||||
|
||||
|
|
@ -193,18 +193,20 @@ export const LibraryManagerModal: React.FC<LibraryManagerModalProps> = ({ isOpen
|
|||
</div>
|
||||
|
||||
<div className="lib-list">
|
||||
{!searchQuery.trim() && (
|
||||
{loadingSearch && (
|
||||
<div className="lib-empty">
|
||||
<p>Type a library name to search</p>
|
||||
<p className="lib-empty-sub">e.g. "ArduinoJson", "Servo", "LiquidCrystal"</p>
|
||||
<svg className="lib-spinner lib-spinner-center" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round">
|
||||
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
||||
</svg>
|
||||
<p className="lib-empty-sub">{searchQuery ? `Searching "${searchQuery}"…` : 'Loading libraries…'}</p>
|
||||
</div>
|
||||
)}
|
||||
{searchQuery.trim() && searchResults.length === 0 && !loadingSearch && (
|
||||
{!loadingSearch && searchResults.length === 0 && (
|
||||
<div className="lib-empty">
|
||||
<p>No libraries found for "{searchQuery}"</p>
|
||||
<p>{searchQuery ? `No libraries found for "${searchQuery}"` : 'No libraries available'}</p>
|
||||
</div>
|
||||
)}
|
||||
{searchResults.map((lib, i) => (
|
||||
{!loadingSearch && searchResults.map((lib, i) => (
|
||||
<div key={i} className="lib-item">
|
||||
<div className="lib-item-info">
|
||||
<div className="lib-item-header">
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import { useSimulatorStore } from '../../store/useSimulatorStore';
|
|||
|
||||
export const SerialMonitor: React.FC = () => {
|
||||
const serialOutput = useSimulatorStore((s) => s.serialOutput);
|
||||
const serialBaudRate = useSimulatorStore((s) => s.serialBaudRate);
|
||||
const running = useSimulatorStore((s) => s.running);
|
||||
const serialWrite = useSimulatorStore((s) => s.serialWrite);
|
||||
const clearSerialOutput = useSimulatorStore((s) => s.clearSerialOutput);
|
||||
|
|
@ -49,6 +50,9 @@ export const SerialMonitor: React.FC = () => {
|
|||
<div style={styles.header}>
|
||||
<span style={styles.title}>Serial Monitor</span>
|
||||
<div style={styles.headerControls}>
|
||||
{serialBaudRate > 0 && (
|
||||
<span style={styles.baudRate}>{serialBaudRate.toLocaleString()} baud</span>
|
||||
)}
|
||||
<label style={styles.autoscrollLabel}>
|
||||
<input
|
||||
type="checkbox"
|
||||
|
|
@ -127,6 +131,15 @@ const styles: Record<string, React.CSSProperties> = {
|
|||
alignItems: 'center',
|
||||
gap: 8,
|
||||
},
|
||||
baudRate: {
|
||||
color: '#569cd6',
|
||||
fontSize: 11,
|
||||
fontFamily: 'monospace',
|
||||
background: '#1e1e1e',
|
||||
border: '1px solid #3a3a3a',
|
||||
borderRadius: 3,
|
||||
padding: '1px 6px',
|
||||
},
|
||||
autoscrollLabel: {
|
||||
color: '#999',
|
||||
fontSize: 11,
|
||||
|
|
|
|||
|
|
@ -6,18 +6,35 @@ import React, { useRef, useState, useCallback } from 'react';
|
|||
import { Link } from 'react-router-dom';
|
||||
import { CodeEditor } from '../components/editor/CodeEditor';
|
||||
import { EditorToolbar } from '../components/editor/EditorToolbar';
|
||||
import { CompilationConsole } from '../components/editor/CompilationConsole';
|
||||
import { SimulatorCanvas } from '../components/simulator/SimulatorCanvas';
|
||||
import { SerialMonitor } from '../components/simulator/SerialMonitor';
|
||||
import { useSimulatorStore } from '../store/useSimulatorStore';
|
||||
import type { CompilationLog } from '../utils/compilationLogger';
|
||||
import '../App.css';
|
||||
|
||||
const BOTTOM_PANEL_MIN = 80;
|
||||
const BOTTOM_PANEL_MAX = 600;
|
||||
const BOTTOM_PANEL_DEFAULT = 200;
|
||||
|
||||
const resizeHandleStyle: React.CSSProperties = {
|
||||
height: 5,
|
||||
flexShrink: 0,
|
||||
cursor: 'row-resize',
|
||||
background: '#2a2d2e',
|
||||
borderTop: '1px solid #3c3c3c',
|
||||
borderBottom: '1px solid #3c3c3c',
|
||||
};
|
||||
|
||||
export const EditorPage: React.FC = () => {
|
||||
const [editorWidthPct, setEditorWidthPct] = useState(45);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const resizingRef = useRef(false);
|
||||
const serialMonitorOpen = useSimulatorStore((s) => s.serialMonitorOpen);
|
||||
const toggleSerialMonitor = useSimulatorStore((s) => s.toggleSerialMonitor);
|
||||
const [serialHeightPct, setSerialHeightPct] = useState(30);
|
||||
const [consoleOpen, setConsoleOpen] = useState(false);
|
||||
const [compileLogs, setCompileLogs] = useState<CompilationLog[]>([]);
|
||||
const [bottomPanelHeight, setBottomPanelHeight] = useState(BOTTOM_PANEL_DEFAULT);
|
||||
|
||||
const handleResizeMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
|
|
@ -44,6 +61,27 @@ export const EditorPage: React.FC = () => {
|
|||
document.addEventListener('mouseup', handleMouseUp);
|
||||
}, []);
|
||||
|
||||
const handleBottomPanelResizeMouseDown = useCallback((e: React.MouseEvent) => {
|
||||
e.preventDefault();
|
||||
const startY = e.clientY;
|
||||
const startHeight = bottomPanelHeight;
|
||||
|
||||
const onMove = (ev: MouseEvent) => {
|
||||
const delta = startY - ev.clientY;
|
||||
setBottomPanelHeight(Math.max(BOTTOM_PANEL_MIN, Math.min(BOTTOM_PANEL_MAX, startHeight + delta)));
|
||||
};
|
||||
const onUp = () => {
|
||||
document.body.style.cursor = '';
|
||||
document.body.style.userSelect = '';
|
||||
document.removeEventListener('mousemove', onMove);
|
||||
document.removeEventListener('mouseup', onUp);
|
||||
};
|
||||
document.body.style.cursor = 'row-resize';
|
||||
document.body.style.userSelect = 'none';
|
||||
document.addEventListener('mousemove', onMove);
|
||||
document.addEventListener('mouseup', onUp);
|
||||
}, [bottomPanelHeight]);
|
||||
|
||||
return (
|
||||
<div className="app">
|
||||
<header className="app-header">
|
||||
|
|
@ -90,11 +128,33 @@ export const EditorPage: React.FC = () => {
|
|||
</header>
|
||||
|
||||
<div className="app-container" ref={containerRef}>
|
||||
<div className="editor-panel" style={{ width: `${editorWidthPct}%` }}>
|
||||
<EditorToolbar />
|
||||
<div className="editor-wrapper">
|
||||
<div className="editor-panel" style={{ width: `${editorWidthPct}%`, display: 'flex', flexDirection: 'column' }}>
|
||||
<EditorToolbar
|
||||
consoleOpen={consoleOpen}
|
||||
setConsoleOpen={setConsoleOpen}
|
||||
compileLogs={compileLogs}
|
||||
setCompileLogs={setCompileLogs}
|
||||
/>
|
||||
<div className="editor-wrapper" style={{ flex: 1, overflow: 'hidden', minHeight: 0 }}>
|
||||
<CodeEditor />
|
||||
</div>
|
||||
{consoleOpen && (
|
||||
<>
|
||||
<div
|
||||
onMouseDown={handleBottomPanelResizeMouseDown}
|
||||
style={resizeHandleStyle}
|
||||
title="Drag to resize"
|
||||
/>
|
||||
<div style={{ height: bottomPanelHeight, flexShrink: 0 }}>
|
||||
<CompilationConsole
|
||||
isOpen={consoleOpen}
|
||||
onClose={() => setConsoleOpen(false)}
|
||||
logs={compileLogs}
|
||||
onClear={() => setCompileLogs([])}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Resize handle */}
|
||||
|
|
@ -103,13 +163,20 @@ export const EditorPage: React.FC = () => {
|
|||
</div>
|
||||
|
||||
<div className="simulator-panel" style={{ width: `${100 - editorWidthPct}%`, display: 'flex', flexDirection: 'column' }}>
|
||||
<div style={{ flex: serialMonitorOpen ? `0 0 ${100 - serialHeightPct}%` : '1 1 auto', overflow: 'hidden', position: 'relative' }}>
|
||||
<div style={{ flex: 1, overflow: 'hidden', position: 'relative', minHeight: 0 }}>
|
||||
<SimulatorCanvas />
|
||||
</div>
|
||||
{serialMonitorOpen && (
|
||||
<div style={{ flex: `0 0 ${serialHeightPct}%`, minHeight: 100, display: 'flex', flexDirection: 'column' }}>
|
||||
<SerialMonitor />
|
||||
</div>
|
||||
<>
|
||||
<div
|
||||
onMouseDown={handleBottomPanelResizeMouseDown}
|
||||
style={resizeHandleStyle}
|
||||
title="Drag to resize"
|
||||
/>
|
||||
<div style={{ height: bottomPanelHeight, flexShrink: 0 }}>
|
||||
<SerialMonitor />
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ export class AVRSimulator {
|
|||
|
||||
/** Serial output buffer — subscribers receive each byte or line */
|
||||
public onSerialData: ((char: string) => void) | null = null;
|
||||
/** Fires whenever the sketch changes Serial baud rate (Serial.begin) */
|
||||
public onBaudRateChange: ((baudRate: number) => void) | null = null;
|
||||
private lastPortBValue = 0;
|
||||
private lastPortCValue = 0;
|
||||
private lastPortDValue = 0;
|
||||
|
|
@ -94,6 +96,11 @@ export class AVRSimulator {
|
|||
this.onSerialData(String.fromCharCode(value));
|
||||
}
|
||||
};
|
||||
this.usart.onConfigurationChange = () => {
|
||||
if (this.onBaudRateChange && this.usart) {
|
||||
this.onBaudRateChange(this.usart.baudRate);
|
||||
}
|
||||
};
|
||||
|
||||
// TWI (I2C)
|
||||
this.twi = new AVRTWI(this.cpu, twiConfig, 16000000);
|
||||
|
|
@ -262,6 +269,11 @@ export class AVRSimulator {
|
|||
this.usart.onByteTransmit = (value: number) => {
|
||||
if (this.onSerialData) this.onSerialData(String.fromCharCode(value));
|
||||
};
|
||||
this.usart.onConfigurationChange = () => {
|
||||
if (this.onBaudRateChange && this.usart) {
|
||||
this.onBaudRateChange(this.usart.baudRate);
|
||||
}
|
||||
};
|
||||
|
||||
this.twi = new AVRTWI(this.cpu, twiConfig, 16000000);
|
||||
this.i2cBus = new I2CBusManager(this.twi);
|
||||
|
|
|
|||
|
|
@ -115,9 +115,16 @@ export class RP2040Simulator {
|
|||
this.rp2040.core.PC = 0x10000000;
|
||||
|
||||
// ── Wire UART0 (default Serial port for Arduino-Pico) ────────────
|
||||
let serialBuffer = '';
|
||||
this.rp2040.uart[0].onByte = (value: number) => {
|
||||
const ch = String.fromCharCode(value);
|
||||
serialBuffer += ch;
|
||||
if (ch === '\n') {
|
||||
console.log('[RP2040 UART0]', serialBuffer.trimEnd());
|
||||
serialBuffer = '';
|
||||
}
|
||||
if (this.onSerialData) {
|
||||
this.onSerialData(String.fromCharCode(value));
|
||||
this.onSerialData(ch);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -22,9 +22,11 @@ function setAdcVoltage(simulator: AnySimulator, pin: number, voltage: number): b
|
|||
const channel = pin - 26;
|
||||
// RP2040 ADC: 12-bit, 3.3V reference
|
||||
const adcValue = Math.round((voltage / 3.3) * 4095);
|
||||
console.log(`[setAdcVoltage] RP2040 ch${channel} = ${adcValue} (${voltage.toFixed(3)}V)`);
|
||||
simulator.setADCValue(channel, adcValue);
|
||||
return true;
|
||||
}
|
||||
console.warn(`[setAdcVoltage] RP2040 pin ${pin} is not an ADC pin (26-29)`);
|
||||
return false;
|
||||
}
|
||||
// AVR: pins 14-19 → ADC channels 0-5
|
||||
|
|
@ -94,15 +96,21 @@ PartSimulationRegistry.register('rgb-led', {
|
|||
PartSimulationRegistry.register('potentiometer', {
|
||||
attachEvents: (element, simulator, getArduinoPinHelper) => {
|
||||
const pin = getArduinoPinHelper('SIG');
|
||||
if (pin === null) return () => { };
|
||||
console.log(`[Potentiometer] attachEvents called, SIG pin resolved to: ${pin}`);
|
||||
if (pin === null) {
|
||||
console.warn('[Potentiometer] No SIG pin found — skipping ADC attachment');
|
||||
return () => { };
|
||||
}
|
||||
|
||||
// Determine reference voltage based on board type
|
||||
const isRP2040 = simulator instanceof RP2040Simulator;
|
||||
const refVoltage = isRP2040 ? 3.3 : 5.0;
|
||||
console.log(`[Potentiometer] Board type: ${isRP2040 ? 'RP2040' : 'AVR'}, refV: ${refVoltage}`);
|
||||
|
||||
const onInput = () => {
|
||||
const raw = parseInt((element as any).value || '0', 10);
|
||||
const volts = (raw / 1023.0) * refVoltage;
|
||||
console.log(`[Potentiometer] pin=${pin}, raw=${raw}, volts=${volts.toFixed(3)}`);
|
||||
if (!setAdcVoltage(simulator, pin, volts)) {
|
||||
console.warn(`[Potentiometer] ADC not available for pin ${pin}`);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ interface SimulatorState {
|
|||
|
||||
// Serial monitor state
|
||||
serialOutput: string;
|
||||
serialBaudRate: number;
|
||||
serialMonitorOpen: boolean;
|
||||
|
||||
// Actions
|
||||
|
|
@ -164,6 +165,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
selectedWireId: null,
|
||||
wireInProgress: null,
|
||||
serialOutput: '',
|
||||
serialBaudRate: 0,
|
||||
serialMonitorOpen: false,
|
||||
|
||||
setBoardType: (type: BoardType) => {
|
||||
|
|
@ -178,7 +180,10 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
simulator.onSerialData = (char: string) => {
|
||||
set((s) => ({ serialOutput: s.serialOutput + char }));
|
||||
};
|
||||
set({ boardType: type, simulator, compiledHex: null, serialOutput: '' });
|
||||
if (simulator instanceof AVRSimulator) {
|
||||
simulator.onBaudRateChange = (baudRate: number) => set({ serialBaudRate: baudRate });
|
||||
}
|
||||
set({ boardType: type, simulator, compiledHex: null, serialOutput: '', serialBaudRate: 0 });
|
||||
console.log(`Board switched to: ${type}`);
|
||||
},
|
||||
|
||||
|
|
@ -191,7 +196,10 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
simulator.onSerialData = (char: string) => {
|
||||
set((s) => ({ serialOutput: s.serialOutput + char }));
|
||||
};
|
||||
set({ simulator, serialOutput: '' });
|
||||
if (simulator instanceof AVRSimulator) {
|
||||
simulator.onBaudRateChange = (baudRate: number) => set({ serialBaudRate: baudRate });
|
||||
}
|
||||
set({ simulator, serialOutput: '', serialBaudRate: 0 });
|
||||
console.log(`Simulator initialized: ${boardType}`);
|
||||
},
|
||||
|
||||
|
|
@ -239,7 +247,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
simulator.addI2CDevice(new I2CMemoryDevice(0x50) as RP2040I2CDevice);
|
||||
}
|
||||
simulator.start();
|
||||
set({ running: true });
|
||||
set({ running: true, serialMonitorOpen: true });
|
||||
}
|
||||
},
|
||||
|
||||
|
|
@ -259,7 +267,10 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
simulator.onSerialData = (char: string) => {
|
||||
set((s) => ({ serialOutput: s.serialOutput + char }));
|
||||
};
|
||||
set({ running: false, serialOutput: '' });
|
||||
if (simulator instanceof AVRSimulator) {
|
||||
simulator.onBaudRateChange = (baudRate: number) => set({ serialBaudRate: baudRate });
|
||||
}
|
||||
set({ running: false, serialOutput: '', serialBaudRate: 0 });
|
||||
}
|
||||
},
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue