diff --git a/README.md b/README.md index 5836a37c..88ab5a1e 100644 --- a/README.md +++ b/README.md @@ -14,36 +14,72 @@ Every star counts and helps make this project better! You can also support the p ## Screenshots -![Arduino Emulator - Editor and Simulator](doc/img1.png) +![Raspberry Pi Pico ADC simulation with Serial Monitor](doc/img1.png) -Arduino emulator with Monaco code editor and visual simulator with wokwi-elements +Raspberry Pi Pico simulation — ADC read test with two potentiometers, Serial Monitor showing live output, and compilation console at the bottom. -![Arduino Emulator - Component Properties and Wire Editing](doc/img2.png) +![ILI9341 TFT display simulation on Arduino Uno](doc/img2.png) -Interactive component properties dialog and segment-based wire editing +Arduino Uno driving an ILI9341 240×320 TFT display via SPI — rendering a real-time graphics demo using Adafruit_GFX + Adafruit_ILI9341. + +![Library Manager with full library list](doc/img3.png) + +Library Manager loads the full Arduino library index on open — browse and install libraries without typing first. + +![Component Picker with 48 components](doc/img4.png) + +Component Picker showing 48 available components with visual previews, search, and category filters (Boards, Displays, Input, Motors, Output, Passive, Sensors). ## Features ### Code Editing - **Monaco Editor** — Full C++ editor with syntax highlighting, autocomplete, minimap, and dark theme -- **Arduino compilation** via `arduino-cli` backend — compile sketches to `.hex` files +- **Arduino compilation** via `arduino-cli` backend — compile sketches to `.hex` / `.uf2` files - **Compile / Run / Stop / Reset** toolbar buttons with status messages +- **Compilation console** — resizable output panel at the bottom of the editor showing full compiler output, warnings, and errors -### AVR8 Simulation (avr8js) +### Multi-Board Support +- **Arduino Uno** (ATmega328p) — full AVR8 emulation via avr8js +- **Raspberry Pi Pico** (RP2040) — full RP2040 emulation via rp2040js, compiled with arduino-pico core +- Board selector in the toolbar — switch boards without restarting + +### AVR8 Simulation (Arduino Uno) - **Real ATmega328p emulation** at 16 MHz using avr8js - **Intel HEX parser** with checksum verification - **Full GPIO support** — PORTB (pins 8-13), PORTC (A0-A5), PORTD (pins 0-7) -- **Timer0 peripheral** support -- **USART (Serial)** support +- **Timer0/Timer1/Timer2** peripheral support (enables `millis()`, `delay()`, PWM via `analogWrite()`) +- **USART (Serial)** — full transmit and receive support +- **ADC** — `analogRead()` on pins A0-A5, voltage injection from UI components +- **SPI** — hardware SPI peripheral (enables ILI9341, SD card, etc.) +- **I2C (TWI)** — hardware I2C with virtual device bus (DS1307, temp sensor, EEPROM) - **~60 FPS simulation loop** with `requestAnimationFrame` (~267k cycles/frame) - **Speed control** — adjustable from 0.1x to 10x -- **Single-step debugging** API -- **External pin state injection** for input components (buttons, potentiometers) +- **PWM monitoring** — reads OCR registers each frame to drive PWM-capable components + +### RP2040 Simulation (Raspberry Pi Pico) +- **Real RP2040 emulation** via rp2040js at 133 MHz +- **UART0** serial output captured and displayed in Serial Monitor +- **ADC** — 12-bit, 3.3V reference on GPIO 26-29 (A0-A3) +- **I2C** bus with virtual device support +- Automatic `#define Serial Serial1` injection at compile time to route serial output to emulated UART + +### Serial Monitor +- **Live serial output** — displays characters as the sketch sends them via `Serial.print()` +- **Baud rate indicator** — automatically detects the speed set by `Serial.begin()` reading hardware registers in real time — no manual configuration needed +- **Send data** to the Arduino RX pin from the UI +- **Line ending selector** — None, Newline, Carriage Return, or Both +- **Autoscroll** with toggle +- **Resizable panel** — drag the handle to adjust height + +### ILI9341 TFT Display Simulation +- **Full SPI command decoding** — CASET, PASET, RAMWR, SWRESET, DISPON, MADCTL, and more +- **RGB-565 pixel rendering** directly to an HTML Canvas element in real time +- **240×320 resolution** with full framebuffer support +- Compatible with Adafruit_GFX + Adafruit_ILI9341 libraries ### Component System (48+ Components) - **48 electronic components** auto-discovered from wokwi-elements source code -- **Component picker modal** with search bar, category filtering, and live wokwi-element previews as thumbnails -- **9 component categories**: Boards (4), Sensors (6), Displays (3), Input (5), Output (5), Motors (2), Passive (4), Other (19) +- **Component picker modal** with search bar, category filtering (Boards, Displays, Input, Motors, Output, Passive, Sensors), and live wokwi-element previews as thumbnails - **Dynamic component rendering** from build-time metadata (TypeScript AST parser extracts `@customElement` tags, `@property` decorators, and pin counts) - **Drag-and-drop repositioning** on the simulation canvas - **Component rotation** in 90° increments @@ -54,27 +90,38 @@ Interactive component properties dialog and segment-based wire editing ### Part Simulation Behaviors - **LED** — pin state drives LED on/off -- **RGB LED** — digital HIGH/LOW mapped to individual R/G/B channels -- **Pushbutton** — press/release events inject active-LOW pin state into simulation -- **Potentiometer** — reads element value (0-1023), converts to voltage, injects into ADC channel -- **LCD 1602 & LCD 2004** — Full HD44780 controller emulation: - - 4-bit mode protocol (high nibble first, then low nibble) - - DDRAM with proper line address mapping - - Commands: Clear Display, Return Home, Entry Mode Set, Display On/Off, Cursor/Display Shift, Function Set - - Initialization sequence handling - - Enable pin falling-edge detection for data latching +- **RGB LED** — digital HIGH/LOW and PWM (`analogWrite`) mapped to R/G/B channels +- **Pushbutton / 6mm pushbutton** — press/release events inject active-LOW pin state +- **Slide switch** — toggle between HIGH and LOW +- **DIP Switch 8** — 8 independent toggles, each driving its own pin +- **Potentiometer** — reads slider value (0-1023), converts to voltage (5V for AVR, 3.3V for RP2040), injects into ADC +- **Slide potentiometer** — same as rotary, with configurable min/max range +- **Analog joystick** — two ADC axes (VRX/VRY) + button press +- **Photoresistor sensor** — injects mid-range voltage on AO pin; reacts to element input events +- **Servo** — reads Timer1 OCR1A/ICR1 registers to calculate pulse width and maps to 0-180° angle +- **Buzzer** — Web Audio API tone generation, frequency derived from Timer2 OCR2A/TCCR2B registers +- **LED Bar Graph** — 10 individual LEDs driven by pins A1-A10 +- **7-Segment Display** — segments A-G + DP driven by individual pins +- **LCD 1602 & LCD 2004** — full HD44780 controller emulation in 4-bit mode (RS, E, D4-D7 pins) +- **ILI9341 TFT** — full SPI display simulation (see above) ### Wire System - **Wire creation** — click a pin to start, click another pin to connect - **Real-time preview** — dashed green wire with L-shaped orthogonal routing while creating - **Orthogonal wire rendering** — no diagonal paths - **Segment-based wire editing** — hover to highlight, drag segments perpendicular to their orientation -- **Smooth dragging** with `requestAnimationFrame` - **8 signal-type wire colors**: Red (VCC), Black (GND), Blue (Analog), Green (Digital), Purple (PWM), Gold (I2C), Orange (SPI), Cyan (USART) - **Automatic overlap offset** — parallel wires are offset symmetrically (6px spacing) - **Auto-update positions** — wire endpoints recalculate when components move - **Grid snapping** (20px grid) +### Library Manager +- **Loads full library index on open** — no need to type first; shows spinner while fetching +- **Live search with debounce** — filter while typing (400ms delay) +- **Install libraries** directly from the UI via arduino-cli +- **Installed tab** — see all installed libraries with versions +- **Cross-reference** — installed libraries show "INSTALLED" badge in search results + ### Example Projects - **8 built-in example projects** with full code, components, and wire definitions: @@ -92,10 +139,16 @@ Interactive component properties dialog and segment-based wire editing - **Examples gallery** with category and difficulty filters - **One-click loading** — loads code, components, and wires into the editor and simulator +### UI / Layout +- **Resizable panels** — drag the vertical divider between editor and simulator +- **Resizable bottom panels** — Serial Monitor and compilation console share the same draggable handle; both start at the same height (200px) +- **Compilation console at the bottom** — output appears below the code editor, not between the toolbar and the code +- **Serial Monitor** opens automatically when simulation starts + ### Wokwi Libraries (Local Clones) - **wokwi-elements** — 48+ electronic web components (Lit-based Web Components) - **avr8js** — AVR8 CPU emulator -- **rp2040js** — RP2040 emulator (cloned, for future use) +- **rp2040js** — RP2040 emulator - **Build-time metadata generation** — TypeScript AST parser reads wokwi-elements source to generate component metadata automatically ## Prerequisites @@ -131,6 +184,11 @@ arduino-cli core update-index arduino-cli core install arduino:avr ``` +**For Raspberry Pi Pico support:** +```bash +arduino-cli core install rp2040:rp2040 +``` + ## Installation ### Option A: Docker (Recommended) @@ -214,14 +272,15 @@ The frontend will be available at: ## Usage 1. Open http://localhost:5173 in your browser -2. Write Arduino code in the editor (a Blink example is loaded by default) -3. Click **Compile** to compile the code via the backend -4. Click **Run** to start real AVR8 CPU simulation -5. Watch LEDs, LCDs, and other components react in real time -6. Click on components to view properties or assign pin mappings -7. Double-click components to open the pin selector +2. Select a board (Arduino Uno or Raspberry Pi Pico) from the toolbar +3. Write Arduino code in the editor (a Blink example is loaded by default) +4. Click **Compile** to compile the code via the backend +5. Click **Run** to start simulation — the Serial Monitor opens automatically +6. Watch LEDs, LCDs, TFT displays, and other components react in real time +7. Click components to view properties or assign pin mappings 8. Click pins to create wires connecting components -9. Browse **Examples** to load pre-built projects (Blink, Traffic Light, Simon Says, LCD, etc.) +9. Use the **Library Manager** to install Arduino libraries +10. Browse **Examples** to load pre-built projects ## Project Structure @@ -232,17 +291,16 @@ openwokwi/ │ │ ├── components/ │ │ │ ├── ComponentPickerModal.tsx # Component search & picker │ │ │ ├── DynamicComponent.tsx # Generic wokwi component renderer -│ │ │ ├── components-wokwi/ # Legacy React wrappers -│ │ │ ├── editor/ # Monaco Editor + toolbar -│ │ │ ├── examples/ # Examples gallery -│ │ │ └── simulator/ # Canvas, wires, pins, dialogs +│ │ │ ├── editor/ # Monaco Editor + toolbar + compilation console +│ │ │ └── simulator/ # Canvas, wires, pins, Serial Monitor, dialogs │ │ ├── simulation/ │ │ │ ├── AVRSimulator.ts # AVR8 CPU emulator wrapper -│ │ │ ├── PinManager.ts # Pin-to-component mapping -│ │ │ └── parts/ # Part behaviors (LED, LCD, etc.) +│ │ │ ├── RP2040Simulator.ts # RP2040 emulator wrapper +│ │ │ ├── PinManager.ts # Pin-to-component mapping + PWM +│ │ │ └── parts/ # Part behaviors (LED, LCD, ILI9341, servo, buzzer...) │ │ ├── store/ # Zustand state management │ │ ├── services/ # API clients & ComponentRegistry -│ │ ├── types/ # TypeScript types (wires, components) +│ │ ├── types/ # TypeScript types (wires, components, metadata) │ │ ├── utils/ # Hex parser, wire routing, pin calc │ │ └── pages/ # EditorPage, ExamplesPage │ └── public/ @@ -251,14 +309,14 @@ openwokwi/ ├── backend/ # FastAPI + Python │ └── app/ │ ├── main.py # Entry point, CORS config -│ ├── api/routes/compile.py # POST /api/compile, GET /api/compile/boards +│ ├── api/routes/compile.py # POST /api/compile +│ ├── api/routes/libraries.py # Library search, install, list │ └── services/arduino_cli.py # arduino-cli subprocess wrapper │ ├── wokwi-libs/ # Cloned Wokwi repositories │ ├── wokwi-elements/ # 48+ Web Components (Lit) │ ├── avr8js/ # AVR8 CPU Emulator -│ ├── rp2040js/ # RP2040 Emulator (future) -│ └── wokwi-features/ # Features and documentation +│ └── rp2040js/ # RP2040 Emulator │ ├── scripts/ │ └── generate-component-metadata.ts # AST parser for component discovery @@ -266,8 +324,10 @@ openwokwi/ ├── doc/ │ ├── ARCHITECTURE.md # Detailed architecture documentation │ ├── WOKWI_LIBS.md # Wokwi integration documentation -│ ├── SETUP_COMPLETE.md # Project status overview -│ └── examples/ # Example screenshots +│ ├── img1.png # Screenshot: RP2040 + Serial Monitor +│ ├── img2.png # Screenshot: ILI9341 TFT simulation +│ ├── img3.png # Screenshot: Library Manager +│ └── img4.png # Screenshot: Component Picker │ ├── CLAUDE.md # AI assistant guidance └── update-wokwi-libs.bat # Update local Wokwi libraries @@ -282,7 +342,6 @@ openwokwi/ - **Monaco Editor** — Code editor (VS Code engine) - **Zustand** 5 — State management - **React Router** 7 — Client-side routing -- **Axios** — HTTP client ### Backend - **FastAPI** — Python web framework @@ -291,17 +350,16 @@ openwokwi/ ### Simulation & Components - **avr8js** — Real AVR8 ATmega328p emulator (local clone) +- **rp2040js** — RP2040 emulator (local clone) - **wokwi-elements** — 48+ electronic web components built with Lit (local clone) -- **rp2040js** — RP2040 emulator (local clone, for future use) ## Planned Features -- **Serial Monitor** — UI for reading USART output from the simulation - **Project Persistence** — Save/load projects with SQLite - **Undo/Redo** — Edit history for code and circuit changes -- **Multi-board Support** — Runtime board switching (Mega, Nano, ESP32) - **Wire Validation** — Electrical validation and error highlighting - **Export/Import** — Share projects as files +- **More boards** — ESP32, Arduino Mega, Arduino Nano ## Update Wokwi Libraries @@ -337,9 +395,9 @@ See [WOKWI_LIBS.md](doc/WOKWI_LIBS.md) for more details about Wokwi integration. - Check CORS logs in browser console ### Compilation errors -- Check backend console for arduino-cli logs +- Check the compilation console output at the bottom of the editor - Make sure Arduino code is valid -- Verify you have the `arduino:avr` core installed +- Verify you have the correct core installed (`arduino:avr` for Uno, `rp2040:rp2040` for Pico) ### LED doesn't blink - Check port listeners are firing (browser console logs) @@ -349,6 +407,10 @@ See [WOKWI_LIBS.md](doc/WOKWI_LIBS.md) for more details about Wokwi integration. - Ensure `avrInstruction()` is being called in the execution loop - Check hex file was loaded correctly +### Serial Monitor shows nothing +- Make sure your sketch calls `Serial.begin()` before `Serial.print()` +- Check the baud rate indicator appears in the Serial Monitor header after the simulation starts + ## Contributing This is an open-source project. Suggestions, bug reports, and pull requests are welcome! @@ -362,6 +424,6 @@ MIT - [Wokwi](https://wokwi.com) — Project inspiration - [avr8js](https://github.com/wokwi/avr8js) — AVR8 emulator - [wokwi-elements](https://github.com/wokwi/wokwi-elements) — Electronic web components +- [rp2040js](https://github.com/wokwi/rp2040js) — RP2040 emulator - [arduino-cli](https://github.com/arduino/arduino-cli) — Arduino compiler - [Monaco Editor](https://microsoft.github.io/monaco-editor/) — Code editor - diff --git a/doc/img1.png b/doc/img1.png index 84918b57..731c8da3 100644 Binary files a/doc/img1.png and b/doc/img1.png differ diff --git a/doc/img2.png b/doc/img2.png index 956663df..b4fadabf 100644 Binary files a/doc/img2.png and b/doc/img2.png differ diff --git a/doc/img3.png b/doc/img3.png new file mode 100644 index 00000000..489a3fc3 Binary files /dev/null and b/doc/img3.png differ diff --git a/doc/img4.png b/doc/img4.png new file mode 100644 index 00000000..870e8af0 Binary files /dev/null and b/doc/img4.png differ diff --git a/frontend/src/utils/wireOffsetCalculator.ts b/frontend/src/utils/wireOffsetCalculator.ts index ec65898f..a9a55fa7 100644 --- a/frontend/src/utils/wireOffsetCalculator.ts +++ b/frontend/src/utils/wireOffsetCalculator.ts @@ -218,44 +218,76 @@ export function calculateWireOffsets(wires: Wire[]): Map { } /** - * Apply offset to wire points (perpendicular to wire direction) + * Apply offset to wire points (perpendicular to wire direction). + * + * Instead of moving the endpoints (which would visually disconnect the wire from its + * pins), we keep the true pin positions fixed and insert short stub segments that + * travel from each pin to the offset path, forming an L-shaped attachment at both ends. + * + * Example (horizontal wire, offset = +6): + * Before: pin ────────────────── pin + * After: pin (stub) + * │ ──────────────── │ + * (stub) pin */ export function applyOffsetToWire(wire: Wire, offset: number): Wire { if (offset === 0) return wire; - // Clone the wire - const offsetWire: Wire = { - ...wire, - start: { ...wire.start }, - end: { ...wire.end }, - controlPoints: wire.controlPoints ? [...wire.controlPoints] : [], - }; + // Determine primary direction from the first segment of the path + const firstControlOrEnd = + wire.controlPoints && wire.controlPoints.length > 0 + ? wire.controlPoints[0] + : wire.end; - // Apply offset to start and end points - // Determine primary direction (first segment) - const firstPoint = offsetWire.start; - const secondPoint = offsetWire.controlPoints && offsetWire.controlPoints.length > 0 - ? offsetWire.controlPoints[0] - : offsetWire.end; + const isHorizontalFirst = + Math.abs(firstControlOrEnd.x - wire.start.x) >= + Math.abs(firstControlOrEnd.y - wire.start.y); - const isVertical = Math.abs(secondPoint.x - firstPoint.x) < Math.abs(secondPoint.y - firstPoint.y); + // True pin positions (never moved) + const pinStart = { x: wire.start.x, y: wire.start.y }; + const pinEnd = { x: wire.end.x, y: wire.end.y }; - // Apply offset perpendicular to direction - if (isVertical) { - // Vertical wire: offset in X - offsetWire.start.x += offset; - offsetWire.end.x += offset; - offsetWire.controlPoints?.forEach(point => { - point.x += offset; - }); - } else { - // Horizontal wire: offset in Y - offsetWire.start.y += offset; - offsetWire.end.y += offset; - offsetWire.controlPoints?.forEach(point => { - point.y += offset; - }); + // Offset intermediate points perpendicular to the primary direction + const shiftedControlPoints = (wire.controlPoints || []).map(cp => ({ + ...cp, + x: isHorizontalFirst ? cp.x : cp.x + offset, + y: isHorizontalFirst ? cp.y + offset : cp.y, + })); + + // Compute where the offset path actually starts/ends + // (the point on the parallel track immediately after the pin stub) + const offsetStart = isHorizontalFirst + ? { x: pinStart.x, y: pinStart.y + offset } + : { x: pinStart.x + offset, y: pinStart.y }; + + const offsetEnd = isHorizontalFirst + ? { x: pinEnd.x, y: pinEnd.y + offset } + : { x: pinEnd.x + offset, y: pinEnd.y }; + + // Build new control points: + // stub from pinStart → offsetStart, then the shifted intermediates, then stub from offsetEnd → pinEnd + // We only need to add extra stubs when they are non-zero length. + const newControlPoints: typeof wire.controlPoints = []; + + // Leading stub end-point (where the offset path begins) + if (offsetStart.x !== pinStart.x || offsetStart.y !== pinStart.y) { + newControlPoints.push({ id: `${wire.id}-stub-s`, ...offsetStart }); } - return offsetWire; + // Shifted original control points + for (const cp of shiftedControlPoints) { + newControlPoints.push(cp); + } + + // Trailing stub start-point (where the offset path rejoins the pin) + if (offsetEnd.x !== pinEnd.x || offsetEnd.y !== pinEnd.y) { + newControlPoints.push({ id: `${wire.id}-stub-e`, ...offsetEnd }); + } + + return { + ...wire, + start: { ...wire.start, x: pinStart.x, y: pinStart.y }, + end: { ...wire.end, x: pinEnd.x, y: pinEnd.y }, + controlPoints: newControlPoints, + }; }