diff --git a/README.md b/README.md index 97e04e1..577fa17 100644 --- a/README.md +++ b/README.md @@ -1,8 +1,8 @@ -# Velxio: Arduino Emulator +# Velxio: Arduino & Embedded Board Emulator **Live at [velxio.dev](https://velxio.dev)** -A fully local, open-source Arduino emulator. Write Arduino code, compile it, and simulate it with real AVR8 CPU emulation and 48+ interactive electronic components — all running in your browser. +A fully local, open-source multi-board emulator. Write Arduino C++ or Python, compile it, and simulate it with real CPU emulation and 48+ interactive electronic components — all running in your browser. [![Live Demo](https://img.shields.io/badge/Live%20Demo-velxio.dev-007acc?style=for-the-badge)](https://velxio.dev) [![Docker Image](https://img.shields.io/badge/Docker-ghcr.io%2Fdavidmonterocrespo24%2Fvelxio-2496ED?style=for-the-badge&logo=docker&logoColor=white)](https://github.com/davidmonterocrespo24/velxio/pkgs/container/velxio) @@ -12,22 +12,21 @@ A fully local, open-source Arduino emulator. Write Arduino code, compile it, and [![Commercial License](https://img.shields.io/badge/Commercial%20License-Available-green?style=for-the-badge)](COMMERCIAL_LICENSE.md) --- -Velxio - Arduino emulator running entirely in the browser | Product Hunt - +[![Product Hunt](https://api.producthunt.com/widgets/embed-image/v1/featured.svg?post_id=1092514&theme=dark&t=1772998619179)](https://www.producthunt.com/products/velxio) --- ## Support the Project -Velxio is free and open-source. Building and maintaining a full Arduino emulator takes a lot of time — if it saves you time or you enjoy the project, sponsoring me directly helps keep development going. +Velxio is free and open-source. Building and maintaining a full multi-board emulator takes a lot of time — if it saves you time or you enjoy the project, sponsoring me directly helps keep development going. | Platform | Link | -|---|---| +| --- | --- | | **GitHub Sponsors** (preferred) | [github.com/sponsors/davidmonterocrespo24](https://github.com/sponsors/davidmonterocrespo24) | | **PayPal** | [paypal.me/odoonext](https://paypal.me/odoonext) | -Your support helps cover server costs, library maintenance, and frees up time to add new boards, components, and features. Thank you! +Your support helps cover server costs, library maintenance, and frees up time to add new boards, components, and features. Thank you! --- @@ -41,7 +40,7 @@ To self-host with Docker (single command): docker run -d -p 3080:80 ghcr.io/davidmonterocrespo24/velxio:master ``` -Then open **http://localhost:3080**. +Then open . --- @@ -65,60 +64,133 @@ Component Picker showing 48 available components with visual previews, search, a --- +## Supported Boards + + + + + + + + + + + + + + + + + + + + +
Raspberry Pi Pico
Raspberry Pi Pico
Raspberry Pi Pico W
Raspberry Pi Pico W
ESP32 DevKit C
ESP32 DevKit C
ESP32-S3
ESP32-S3
ESP32-C3
ESP32-C3
Seeed XIAO ESP32-C3
Seeed XIAO ESP32-C3
ESP32-C3 SuperMini
ESP32-C3 SuperMini
ESP32-CAM
ESP32-CAM
Seeed XIAO ESP32-S3
Seeed XIAO ESP32-S3
Arduino Nano ESP32
Arduino Nano ESP32
Raspberry Pi 3B
Raspberry Pi 3B
Arduino Uno / Nano / Mega
(ATmega328p / 2560)
+ +| Board | CPU | Engine | Language | +| ----- | --- | ------ | -------- | +| Arduino Uno | ATmega328p @ 16 MHz | avr8js (browser) | C++ (Arduino) | +| Arduino Nano | ATmega328p @ 16 MHz | avr8js (browser) | C++ (Arduino) | +| Arduino Mega | ATmega2560 @ 16 MHz | avr8js (browser) | C++ (Arduino) | +| Raspberry Pi Pico | RP2040 @ 125 MHz | rp2040js (browser) | C++ (Arduino) | +| Raspberry Pi Pico W | RP2040 @ 125 MHz | rp2040js (browser) | C++ (Arduino) | +| ESP32 DevKit C | Xtensa LX6 @ 240 MHz | QEMU lcgamboa (backend) | C++ (Arduino) | +| ESP32-S3 | Xtensa LX7 @ 240 MHz | QEMU lcgamboa (backend) | C++ (Arduino) | +| ESP32-CAM | Xtensa LX6 @ 240 MHz | QEMU lcgamboa (backend) | C++ (Arduino) | +| ESP32-C3 | RISC-V RV32IMC @ 160 MHz | RiscVCore.ts (browser) | C++ (Arduino) | +| Seeed XIAO ESP32-C3 | RISC-V RV32IMC @ 160 MHz | RiscVCore.ts (browser) | C++ (Arduino) | +| ESP32-C3 SuperMini | RISC-V RV32IMC @ 160 MHz | RiscVCore.ts (browser) | C++ (Arduino) | +| Seeed XIAO ESP32-S3 | Xtensa LX7 @ 240 MHz | QEMU lcgamboa (backend) | C++ (Arduino) | +| Arduino Nano ESP32 | Xtensa LX6 @ 240 MHz | QEMU lcgamboa (backend) | C++ (Arduino) | +| Raspberry Pi 3B | ARM Cortex-A53 @ 1.2 GHz | QEMU raspi3b (backend) | Python | + +--- + ## Features ### Code Editing -- **Monaco Editor** — Full C++ editor with syntax highlighting, autocomplete, minimap, and dark theme -- **Multi-file workspace** — create, rename, delete, and switch between multiple `.ino` / `.h` / `.cpp` files -- **Arduino compilation** via `arduino-cli` backend — compile sketches to `.hex` / `.uf2` files + +- **Monaco Editor** — Full C++ / Python editor with syntax highlighting, autocomplete, minimap, and dark theme +- **Multi-file workspace** — create, rename, delete, and switch between multiple `.ino` / `.h` / `.cpp` / `.py` files +- **Arduino compilation** via `arduino-cli` backend — compile sketches to `.hex` / `.bin` files - **Compile / Run / Stop / Reset** toolbar buttons with status messages - **Compilation console** — resizable output panel showing full compiler output, warnings, and errors -### Multi-Board Support -- **Arduino Uno** (ATmega328p) — full AVR8 emulation via avr8js -- **Arduino Nano** (ATmega328p) — full AVR8 emulation -- **Arduino Mega** (ATmega2560) — full AVR8 emulation -- **Raspberry Pi Pico** (RP2040) — full RP2040 emulation via rp2040js, compiled with arduino-pico core -- Board selector in the toolbar — switch boards without restarting +### Multi-Board Simulation -### AVR8 Simulation (Arduino Uno / Nano / Mega) -- **Real ATmega328p emulation** at 16 MHz using avr8js -- **Full GPIO support** — PORTB (pins 8-13), PORTC (A0-A5), PORTD (pins 0-7) -- **Timer0/Timer1/Timer2** peripheral support (`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.) +#### AVR8 (Arduino Uno / Nano / Mega) + +- **Real ATmega328p / ATmega2560 emulation** at 16 MHz via avr8js +- **Full GPIO** — PORTB (pins 8–13), PORTC (A0–A5), PORTD (pins 0–7) +- **Timer0/Timer1/Timer2** — `millis()`, `delay()`, PWM via `analogWrite()` +- **USART** — full transmit and receive, auto baud-rate detection +- **ADC** — `analogRead()` on A0–A5, voltage injection from potentiometers on canvas +- **SPI** — hardware SPI peripheral (ILI9341, SD card, etc.) - **I2C (TWI)** — hardware I2C with virtual device bus -- **~60 FPS simulation loop** with `requestAnimationFrame` +- ~60 FPS simulation loop via `requestAnimationFrame` -### RP2040 Simulation (Raspberry Pi Pico) -- **Real RP2040 emulation** via rp2040js at 133 MHz -- **UART0** serial output displayed in Serial Monitor -- **ADC** — 12-bit, 3.3V reference on GPIO 26-29 (A0-A3) +#### RP2040 (Raspberry Pi Pico / Pico W) -### ESP32 Simulation (via lcgamboa QEMU) -- **Real Xtensa LX6 dual-core emulation** via [lcgamboa/qemu](https://github.com/lcgamboa/qemu) fork -- **Full GPIO** — all 40 GPIO pins with direction tracking and state callbacks -- **UART0/1/2** — multi-UART serial with baud-rate detection -- **ADC** — 12-bit, 3.3V reference on all ADC-capable pins (0–3300 mV injection) -- **I2C** — synchronous bus with virtual device response support +- **Real RP2040 emulation** at 125 MHz via rp2040js — ARM Cortex-M0+ +- **All 30 GPIO pins** — input/output, event listeners, pin state injection +- **UART0 + UART1** — serial output in Serial Monitor; Serial input from UI +- **ADC** — 12-bit on GPIO 26–29 (A0–A3) + internal temperature sensor (ch4) +- **I2C0 + I2C1** — master mode with virtual device bus (DS1307, TMP102, EEPROM) +- **SPI0 + SPI1** — loopback default; custom handler supported +- **PWM** — available on any GPIO pin +- **WFI optimization** — `delay()` skips ahead in simulation time instead of busy-waiting +- **Oscilloscope** — GPIO transition timestamps at ~8 ns resolution +- Compiled with the [earlephilhower arduino-pico](https://github.com/earlephilhower/arduino-pico) core + +See [docs/RP2040_EMULATION.md](docs/RP2040_EMULATION.md) for full technical details. + +#### ESP32 / ESP32-S3 (Xtensa QEMU) + +- **Real Xtensa LX6/LX7 dual-core emulation** via [lcgamboa/qemu](https://github.com/lcgamboa/qemu) +- **Full GPIO** — all 40 GPIO pins, direction tracking, state callbacks, GPIO32–39 fix +- **UART0/1/2** — multi-UART serial, baud-rate detection +- **ADC** — 12-bit on all ADC-capable pins (0–3300 mV injection from potentiometers) +- **I2C** — synchronous bus with virtual device response - **SPI** — full-duplex with configurable MISO byte injection -- **RMT / NeoPixel** — hardware RMT decoder with WS2812 24-bit GRB frame decoding -- **LEDC/PWM** — 16-channel duty cycle readout, mapped to LED brightness +- **RMT / NeoPixel** — hardware RMT decoder, WS2812 24-bit GRB frame decoding +- **LEDC/PWM** — 16-channel duty cycle readout, LEDC→GPIO mapping, LED brightness - **WiFi** — SLIRP NAT emulation (`WiFi.begin("PICSimLabWifi", "")`) -- **arduino-esp32 2.0.17 (IDF 4.4.x)** — only compatible version with lcgamboa WiFi emulation -- **Crash detection** — banner notification in UI with dismiss button -- **Fully included in the Docker image** — zero extra setup required +- Requires arduino-esp32 **2.0.17** (IDF 4.4.x) — only version compatible with lcgamboa WiFi -See [docs/ESP32_EMULATION.md](docs/ESP32_EMULATION.md) for the complete installation guide. +See [docs/ESP32_EMULATION.md](docs/ESP32_EMULATION.md) for setup and full technical details. + +#### ESP32-C3 / XIAO-C3 (RISC-V, in-browser) + +- **RV32IMC emulation** in TypeScript — no backend, no QEMU, no WebSocket +- **GPIO 0–21** via W1TS/W1TC MMIO registers +- **UART0** serial output in Serial Monitor +- **Instant startup** — zero latency, works offline +- **CI-testable** — same TypeScript runs in Vitest + +See [docs/RISCV_EMULATION.md](docs/RISCV_EMULATION.md) for full technical details. + +#### Raspberry Pi 3B (QEMU raspi3b) + +- **Full BCM2837 emulation** via `qemu-system-aarch64 -M raspi3b` +- **Boots real Raspberry Pi OS** (Trixie) — runs Python scripts directly +- **RPi.GPIO shim** — drop-in replacement for the GPIO library; sends pin events to the frontend over a text protocol +- **GPIO 0–27** — output and input, event detection, PWM (binary state) +- **Dual serial** — ttyAMA0 for user Serial Monitor, ttyAMA1 for GPIO protocol +- **Virtual File System** — edit Python scripts in the UI, upload to Pi at boot +- **Multi-board serial bridge** — Pi ↔ Arduino serial communication on the same canvas +- **qcow2 overlay** — base SD image never modified; session changes are isolated + +See [docs/RASPBERRYPI3_EMULATION.md](docs/RASPBERRYPI3_EMULATION.md) for full technical details. ### Serial Monitor -- **Live serial output** — characters as the sketch sends them via `Serial.print()` + +- **Live serial output** — characters as the sketch/script sends them - **Auto baud-rate detection** — reads hardware registers, no manual configuration needed -- **Send data** to the Arduino RX pin from the UI +- **Send data** to the RX pin from the UI - **Autoscroll** with toggle ### Component System (48+ Components) + - **48 electronic components** from wokwi-elements - **Component picker** with search, category filters, and live previews - **Drag-and-drop** repositioning on the simulation canvas @@ -126,16 +198,19 @@ See [docs/ESP32_EMULATION.md](docs/ESP32_EMULATION.md) for the complete installa - **Property dialog** — pin roles, Arduino pin assignment, rotate & delete ### Wire System + - **Wire creation** — click a pin to start, click another pin to connect - **Orthogonal routing** — no diagonal paths - **8 signal-type wire colors**: Red (VCC), Black (GND), Blue (Analog), Green (Digital), Purple (PWM), Gold (I2C), Orange (SPI), Cyan (USART) - **Segment-based wire editing** — drag segments perpendicular to their orientation ### Library Manager + - Browse and install the full Arduino library index directly from the UI - Live search, installed tab, version display ### Auth & Project Persistence + - **Email/password** and **Google OAuth** sign-in - **Project save** with name, description, and public/private visibility - **Project URL** — each project gets a permanent URL at `/project/:id` @@ -143,7 +218,8 @@ See [docs/ESP32_EMULATION.md](docs/ESP32_EMULATION.md) for the complete installa - **User profile** at `/:username` showing public projects ### Example Projects -- 8 built-in examples (Blink, Traffic Light, Button Control, Fade LED, Serial Hello World, RGB LED, Simon Says, LCD 20×4) + +- Built-in examples including Blink, Traffic Light, Button Control, Fade LED, Serial Hello World, RGB LED, Simon Says, LCD 20×4, and Pi + Arduino serial control - One-click loading into the editor --- @@ -161,9 +237,10 @@ docker run -d \ ghcr.io/davidmonterocrespo24/velxio:master ``` -Open **http://localhost:3080**. +Open . The `/app/data` volume contains: + - `velxio.db` — SQLite database (users, projects metadata) - `projects/{id}/` — sketch files per project @@ -179,7 +256,7 @@ docker compose -f docker-compose.prod.yml up -d #### Environment variables (`backend/.env`) | Variable | Default | Description | -|---|---|---| +| --- | --- | --- | | `SECRET_KEY` | *(required)* | JWT signing secret | | `DATABASE_URL` | `sqlite+aiosqlite:////app/data/velxio.db` | SQLite path | | `DATA_DIR` | `/app/data` | Directory for project files | @@ -209,42 +286,53 @@ npm install npm run dev ``` -Open **http://localhost:5173**. +Open . **arduino-cli setup (first time):** + ```bash arduino-cli core update-index arduino-cli core install arduino:avr -# For Raspberry Pi Pico: + +# For Raspberry Pi Pico / Pico W: arduino-cli config add board_manager.additional_urls \ https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json arduino-cli core install rp2040:rp2040 + +# For ESP32 / ESP32-S3 / ESP32-C3: +arduino-cli config add board_manager.additional_urls \ + https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json +arduino-cli core install esp32:esp32@2.0.17 ``` --- ## Project Structure -``` +```text velxio/ ├── frontend/ # React + Vite + TypeScript │ └── src/ -│ ├── pages/ # LandingPage, EditorPage, ProjectByIdPage, ... +│ ├── pages/ # LandingPage, EditorPage, UserProfilePage, ... │ ├── components/ # Editor, simulator canvas, modals, layout -│ ├── simulation/ # AVRSimulator, RP2040Simulator, PinManager -│ ├── store/ # Zustand stores (auth, editor, simulator, project) +│ ├── simulation/ # AVRSimulator, RP2040Simulator, RiscVCore, +│ │ # RaspberryPi3Bridge, Esp32Bridge, PinManager +│ ├── store/ # Zustand stores (auth, editor, simulator, project, vfs) │ └── services/ # API clients ├── backend/ # FastAPI + Python │ └── app/ -│ ├── api/routes/ # compile, auth, projects, libraries +│ ├── api/routes/ # compile, auth, projects, libraries, simulation (ws) │ ├── models/ # User, Project (SQLAlchemy) -│ ├── services/ # arduino_cli, project_files +│ ├── services/ # arduino_cli, esp32_worker, qemu_manager, gpio_shim │ └── core/ # config, security, dependencies ├── wokwi-libs/ # Local clones of Wokwi repos -│ ├── wokwi-elements/ -│ ├── avr8js/ -│ └── rp2040js/ +│ ├── wokwi-elements/ # Web Components for electronic parts +│ ├── avr8js/ # AVR8 CPU emulator +│ ├── rp2040js/ # RP2040 emulator +│ └── qemu-lcgamboa/ # QEMU fork for ESP32 Xtensa emulation +├── img/ # Raspberry Pi 3 boot images (kernel8.img, dtb, OS image) ├── deploy/ # nginx.conf, entrypoint.sh +├── docs/ # Technical documentation ├── Dockerfile.standalone # Single-container production image ├── docker-compose.yml # Development compose └── docker-compose.prod.yml # Production compose @@ -255,10 +343,15 @@ velxio/ ## Technologies | Layer | Stack | -|---|---| +| --- | --- | | Frontend | React 19, Vite 7, TypeScript 5.9, Monaco Editor, Zustand, React Router 7 | | Backend | FastAPI, SQLAlchemy 2.0 async, aiosqlite, uvicorn | -| Simulation | avr8js (AVR8), rp2040js (RP2040), wokwi-elements (Web Components) | +| AVR Simulation | avr8js (ATmega328p / ATmega2560) | +| RP2040 Simulation | rp2040js (ARM Cortex-M0+) | +| RISC-V Simulation | RiscVCore.ts (RV32IMC, custom TypeScript) | +| ESP32 Simulation | QEMU 8.1.3 lcgamboa fork (Xtensa LX6/LX7) | +| Raspberry Pi 3 Simulation | QEMU 8.1.3 (`qemu-system-aarch64 -M raspi3b`) + Raspberry Pi OS Trixie | +| UI Components | wokwi-elements (Web Components) | | Compiler | arduino-cli (subprocess) | | Auth | JWT (httpOnly cookie), Google OAuth 2.0 | | Persistence | SQLite + disk volume (`/app/data/projects/{id}/`) | @@ -266,6 +359,24 @@ velxio/ --- +## Documentation + +| Topic | Document | +| --- | --- | +| Getting Started | [docs/getting-started.md](docs/getting-started.md) | +| Architecture Overview | [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) | +| Emulator Architecture | [docs/emulator.md](docs/emulator.md) | +| Wokwi Libraries Integration | [docs/WOKWI_LIBS.md](docs/WOKWI_LIBS.md) | +| RP2040 Emulation (Pico) | [docs/RP2040_EMULATION.md](docs/RP2040_EMULATION.md) | +| Raspberry Pi 3 Emulation | [docs/RASPBERRYPI3_EMULATION.md](docs/RASPBERRYPI3_EMULATION.md) | +| ESP32 Emulation (Xtensa) | [docs/ESP32_EMULATION.md](docs/ESP32_EMULATION.md) | +| RISC-V Emulation (ESP32-C3) | [docs/RISCV_EMULATION.md](docs/RISCV_EMULATION.md) | +| Components Reference | [docs/components.md](docs/components.md) | +| MCP Server | [docs/MCP.md](docs/MCP.md) | +| Roadmap | [docs/roadmap.md](docs/roadmap.md) | + +--- + ## Troubleshooting **`arduino-cli: command not found`** — install arduino-cli and add to PATH. @@ -274,7 +385,11 @@ velxio/ **Serial Monitor shows nothing** — ensure `Serial.begin()` is called before `Serial.print()`. -**Compilation errors** — check the compilation console; verify the correct core is installed. +**ESP32 not starting** — verify `libqemu-xtensa.dll` (Windows) or `libqemu-xtensa.so` (Linux) is present in `backend/app/services/`. + +**Pi 3 takes too long to boot** — QEMU needs 2–5 seconds to initialize; the "booting" status in the UI is expected. + +**Compilation errors** — check the compilation console; verify the correct core is installed for the selected board. --- @@ -288,7 +403,7 @@ Join the Discord server to ask questions, share projects, and follow updates: Suggestions, bug reports, and pull requests are welcome at [github.com/davidmonterocrespo24/velxio](https://github.com/davidmonterocrespo24/velxio). -If you'd like to support the project financially, see the [Support the Project](#️-support-the-project) section above or sponsor directly at [github.com/sponsors/davidmonterocrespo24](https://github.com/sponsors/davidmonterocrespo24). +If you'd like to support the project financially, see the [Support the Project](#support-the-project) section above or sponsor directly at [github.com/sponsors/davidmonterocrespo24](https://github.com/sponsors/davidmonterocrespo24). > **Note:** All contributors must sign a Contributor License Agreement (CLA) so that the dual-licensing model remains valid. A CLA check runs automatically on pull requests. @@ -297,7 +412,7 @@ If you'd like to support the project financially, see the [Support the Project]( Velxio uses a **dual-licensing** model: | Use case | License | Cost | -|----------|---------|------| +| --- | --- | --- | | Personal, educational, open-source (AGPLv3 compliant) | [AGPLv3](LICENSE) | Free | | Proprietary / closed-source product or SaaS | [Commercial License](COMMERCIAL_LICENSE.md) | Paid | @@ -313,5 +428,7 @@ See [LICENSE](LICENSE) and [COMMERCIAL_LICENSE.md](COMMERCIAL_LICENSE.md) for fu - [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 +- [lcgamboa/qemu](https://github.com/lcgamboa/qemu) — QEMU fork for ESP32 Xtensa emulation - [arduino-cli](https://github.com/arduino/arduino-cli) — Arduino compiler - [Monaco Editor](https://microsoft.github.io/monaco-editor/) — Code editor +- [QEMU](https://www.qemu.org) — Machine emulator (Raspberry Pi 3) diff --git a/docs/RASPBERRYPI3_EMULATION.md b/docs/RASPBERRYPI3_EMULATION.md new file mode 100644 index 0000000..eccb0d3 --- /dev/null +++ b/docs/RASPBERRYPI3_EMULATION.md @@ -0,0 +1,593 @@ +# Raspberry Pi 3 Emulation (BCM2837 / ARM Cortex-A53) + +> Status: **Functional** · Backend QEMU process · WebSocket communication +> Engine: **QEMU 8.1.3** (`qemu-system-aarch64 -M raspi3b`) +> Platform: **BCM2837 ARM Cortex-A53 @ 1.2 GHz** — 64-bit ARMv8, quad-core +> Runs: **Python scripts** (Raspberry Pi OS Trixie) — no Arduino compilation needed +> Available on: all platforms (Windows, macOS, Linux, Docker) + +--- + +## Table of Contents + +1. [Overview](#1-overview) +2. [Supported Boards](#2-supported-boards) +3. [Emulator Architecture](#3-emulator-architecture) +4. [System Components](#4-system-components) +5. [Boot Sequence — Step by Step](#5-boot-sequence--step-by-step) +6. [GPIO Shim — How Python Controls GPIO](#6-gpio-shim--how-python-controls-gpio) +7. [WebSocket Protocol](#7-websocket-protocol) +8. [Serial Communication (UART)](#8-serial-communication-uart) +9. [Pin Mapping — Physical to BCM GPIO](#9-pin-mapping--physical-to-bcm-gpio) +10. [Virtual File System (VFS)](#10-virtual-file-system-vfs) +11. [Multi-Board Integration — Pi + Arduino](#11-multi-board-integration--pi--arduino) +12. [Boot Images](#12-boot-images) +13. [QEMU Launch Command](#13-qemu-launch-command) +14. [Known Limitations](#14-known-limitations) +15. [Differences vs Other Emulators](#15-differences-vs-other-emulators) +16. [Key Files](#16-key-files) + +--- + +## 1. Overview + +The **Raspberry Pi 3B** is a full Linux single-board computer based on the **Broadcom BCM2837** SoC (4× ARM Cortex-A53, ARMv8 64-bit). Unlike the other boards in Velxio — which compile and run Arduino C++ code — the Raspberry Pi 3 emulation **boots a real Raspberry Pi OS** (Trixie) inside QEMU and lets you run Python scripts that interact with GPIO. + +There is **no compilation step** for the Raspberry Pi: you write a Python script in the editor, the backend uploads it to the emulated filesystem, and the Pi OS executes it directly. + +### Emulation Engine Comparison + +| Board | Engine | Location | Language | +| ----- | ------ | -------- | -------- | +| Arduino Uno / Nano / Mega | avr8js | Browser | C++ (Arduino) | +| Raspberry Pi Pico | rp2040js | Browser | C++ (Arduino) | +| ESP32-C3 / XIAO-C3 | RiscVCore.ts | Browser | C++ (Arduino) | +| ESP32 / ESP32-S3 | QEMU lcgamboa (Xtensa) | Backend WebSocket | C++ (Arduino) | +| **Raspberry Pi 3B** | **QEMU 8.1.3 (raspi3b)** | **Backend WebSocket** | **Python** | + +### Key Differences from Arduino-based Boards + +- **No FQBN** — no arduino-cli compilation; the board kind has `FQBN = null` +- **Boots a real OS** — Raspberry Pi OS Trixie runs inside QEMU (~2–5 seconds boot time) +- **Python runtime** — scripts use `RPi.GPIO` (or a compatible shim) to interact with GPIO +- **Persistent storage** — the OS image is a real disk image; a qcow2 overlay is used per session so the base image is never modified +- **Multi-board serial** — the Pi can communicate with co-simulated Arduino boards via virtual serial lines + +--- + +## 2. Supported Boards + +| Board | QEMU Machine | CPU | Notes | +| ----- | ------------ | --- | ----- | +| Raspberry Pi 3B | `raspi3b` | BCM2837, 4× Cortex-A53 | Full Raspberry Pi OS support | + +> **Raspberry Pi 3B+** and **Pi 4** are not currently supported. The `raspi3b` machine type in QEMU closely matches the standard 3B hardware. + +--- + +## 3. Emulator Architecture + +```text +Python Script (user writes in editor) + │ + ▼ (uploaded via WebSocket / VFS) + /home/pi/script.py (inside Raspberry Pi OS) + │ + ▼ python3 /home/pi/script.py + RPi.GPIO (shim) ← intercepted by gpio_shim.py + │ + ├── GPIO.output(17, HIGH) → "GPIO 17 1\n" → ttyAMA1 → Backend + │ │ + │ ▼ + │ gpio_change event + │ WebSocket → Frontend + │ PinManager → LED visual + │ + └── Serial.print() → ttyAMA0 → Backend → serial_output → Serial Monitor +``` + +### Communication Channels + +The Raspberry Pi uses **two independent TCP serial ports** exposed through QEMU: + +| Channel | QEMU Serial | TCP Port | Purpose | +| ------- | ----------- | -------- | ------- | +| User Serial | `-serial tcp:...:N` | dynamic | User `print()` output and `input()` — visible in Serial Monitor | +| GPIO Protocol | `-serial tcp:...:M` | dynamic | GPIO shim protocol (`GPIO \n`) | + +Both ports are allocated dynamically at startup to avoid conflicts on the host machine. + +--- + +## 4. System Components + +### Backend + +| Component | File | Responsibility | +| --------- | ---- | -------------- | +| `QemuManager` | `backend/app/services/qemu_manager.py` | Singleton that manages all Pi instances (one per WebSocket client) | +| `PiInstance` | `backend/app/services/qemu_manager.py` | Runtime state for one running Pi: QEMU process, TCP ports, overlay path | +| `gpio_shim` | `backend/app/services/gpio_shim.py` | `RPi.GPIO` drop-in replacement; speaks the GPIO text protocol over ttyAMA1 | +| WebSocket route | `backend/app/api/routes/simulation.py` | `GET /api/simulation/ws/{client_id}` — bidirectional JSON message bus | + +### Frontend + +| Component | File | Responsibility | +| --------- | ---- | -------------- | +| `RaspberryPi3Bridge` | `frontend/src/simulation/RaspberryPi3Bridge.ts` | WebSocket connection manager; sends/receives JSON messages | +| `useSimulatorStore` | `frontend/src/store/useSimulatorStore.ts` | Zustand store; wires bridge events to board state and pin manager | +| `useVfsStore` | `frontend/src/store/useVfsStore.ts` | Virtual filesystem tree per board; Python script editing | +| `RaspberryPi3.tsx` | `frontend/src/components/components-wokwi/RaspberryPi3.tsx` | React board component (SVG image, 40-pin header) | +| `boardPinMapping.ts` | `frontend/src/utils/boardPinMapping.ts` | Physical pin → BCM GPIO number translation | + +--- + +## 5. Boot Sequence — Step by Step + +```text +1. User clicks "Start" (or "Run") + │ + ▼ +2. SimulatorCanvas detects board kind 'raspberry-pi-3' + → calls startBoard(boardId) + +3. useSimulatorStore calls RaspberryPi3Bridge.connect() + +4. Bridge opens WebSocket: + ws://localhost:8001/api/simulation/ws/ + → sends { type: 'start_pi', data: { board: 'raspberry-pi-3' } } + +5. Backend (simulation.py) routes to: + QemuManager.start_instance(client_id, 'raspberry-pi-3', callback) + +6. QemuManager._boot(inst): + a. Allocate two free TCP ports (serial_port, gpio_port) + b. Create qcow2 overlay over base SD image: + qemu-img create -f qcow2 -b raspios.img overlay_.qcow2 + c. Launch qemu-system-aarch64 (see Section 13 for full command) + d. Emit { type: 'system', event: 'booting' } + +7. Wait ~2 seconds for QEMU to initialize TCP servers + +8. QemuManager._connect_serial(inst): + → Connect to ttyAMA0 TCP socket + → Start async reader loop (forwards bytes as serial_output events) + → Emit { type: 'system', event: 'booted' } + +9. QemuManager._connect_gpio(inst): + → Connect to ttyAMA1 TCP socket + → Start async reader loop (parses "GPIO \n" lines) + +10. Frontend receives 'booted' event + → Board UI updates to "running" state + → Serial Monitor shows first Linux kernel output + +11. Python script runs: + → python3 /home/pi/script.py (auto-launched via -append init=/bin/sh) +``` + +--- + +## 6. GPIO Shim — How Python Controls GPIO + +The `gpio_shim.py` module is injected into the Raspberry Pi OS at the standard `RPi.GPIO` installation path: + +``` +/usr/local/lib/python3.11/dist-packages/RPi/GPIO.py +``` + +When a Python script does `import RPi.GPIO as GPIO`, it gets this shim instead of the real hardware driver. The shim communicates over `/dev/ttyAMA1` (the second QEMU serial port) using a simple text protocol. + +### GPIO Text Protocol + +```text +Pi → Backend (output state change): + "GPIO <0|1>\n" + Example: "GPIO 17 1\n" ← GPIO 17 driven HIGH + +Backend → Pi (external input, e.g. button press from canvas): + "SET <0|1>\n" + Example: "SET 22 1\n" ← button wired to GPIO 22 pressed +``` + +### Supported RPi.GPIO API + +```python +import RPi.GPIO as GPIO + +# Numbering mode +GPIO.setmode(GPIO.BCM) # use BCM numbers (GPIO17, GPIO22, ...) +GPIO.setmode(GPIO.BOARD) # use physical pin numbers (11, 15, ...) + +# Pin direction +GPIO.setup(17, GPIO.OUT) +GPIO.setup(22, GPIO.IN, pull_up_down=GPIO.PUD_UP) + +# Digital output +GPIO.output(17, GPIO.HIGH) # → sends "GPIO 17 1\n" to backend +GPIO.output(17, GPIO.LOW) # → sends "GPIO 17 0\n" to backend +GPIO.output(17, True) # equivalent to GPIO.HIGH + +# Digital input +state = GPIO.input(22) # reads last known state (updated by "SET" messages) + +# Event detection +GPIO.add_event_detect(22, GPIO.RISING, callback=my_callback) +GPIO.add_event_detect(22, GPIO.FALLING, callback=my_callback) +GPIO.add_event_detect(22, GPIO.BOTH, callback=my_callback) + +# PWM (simplified — simulated as digital output) +pwm = GPIO.PWM(18, 1000) # pin 18, 1000 Hz +pwm.start(75) # 75% duty cycle → HIGH (duty > 50% → HIGH, else LOW) +pwm.ChangeDutyCycle(25) # 25% duty cycle → LOW +pwm.stop() + +# Cleanup +GPIO.cleanup() +GPIO.cleanup(17) # clean specific pin +``` + +> **PWM limitation:** The shim does not implement real PWM waveforms. It converts duty cycle to a binary state: `duty > 50` → HIGH, `duty ≤ 50` → LOW. Visual LED dimming is not supported for Pi GPIO PWM. + +### Example Python Script (Blink LED) + +```python +#!/usr/bin/env python3 +import time +import RPi.GPIO as GPIO + +GPIO.setmode(GPIO.BCM) +GPIO.setup(17, GPIO.OUT) + +try: + while True: + GPIO.output(17, GPIO.HIGH) + print("LED ON") + time.sleep(1) + GPIO.output(17, GPIO.LOW) + print("LED OFF") + time.sleep(1) +finally: + GPIO.cleanup() +``` + +--- + +## 7. WebSocket Protocol + +All communication between the frontend and backend passes through a single WebSocket connection per board instance. + +**Endpoint:** `GET /api/simulation/ws/{client_id}` + +### Frontend → Backend Messages + +| Message Type | Payload | Description | +| ------------ | ------- | ----------- | +| `start_pi` | `{ board: "raspberry-pi-3" }` | Launch QEMU, start the Pi | +| `stop_pi` | _(empty)_ | Stop QEMU, clean up overlay | +| `serial_input` | `{ bytes: number[] }` | Send bytes to ttyAMA0 (Serial Monitor → Pi) | +| `gpio_in` | `{ pin: number, state: 0\|1 }` | Inject external GPIO state (button press from canvas) | + +### Backend → Frontend Messages + +| Message Type | Payload | Description | +| ------------ | ------- | ----------- | +| `serial_output` | `{ data: string }` | String data from ttyAMA0 (Pi print output) | +| `gpio_change` | `{ pin: number, state: 0\|1 }` | A GPIO pin changed state (driven by Python script) | +| `system` | `{ event: "booting"\|"booted"\|"exited" }` | Boot lifecycle events | +| `error` | `{ message: string }` | Error from QEMU or backend | + +--- + +## 8. Serial Communication (UART) + +The Raspberry Pi 3 exposes two UART ports through QEMU: + +| Port | Device | Physical Pins | Role | +| ---- | ------ | ------------- | ---- | +| UART0 (ttyAMA0) | `/dev/ttyAMA0` | GPIO14 (TX), GPIO15 (RX) | User serial — `print()` output, `input()`, `serial.Serial()` | +| UART1 (ttyAMA1) | `/dev/ttyAMA1` | — (internal) | GPIO shim protocol — reserved, not accessible to user scripts | + +### Serial Monitor Integration + +Anything the Python script writes to stdout or to `/dev/ttyAMA0` appears in the Serial Monitor panel: + +```python +# stdout (print) — captured automatically +print("Hello from Pi!") + +# Direct ttyAMA0 (explicit serial) +import serial +port = serial.Serial('/dev/ttyAMA0', baudrate=9600, timeout=1) +port.write(b"Hello Arduino!\n") +``` + +### Sending Text to the Pi + +Text typed in the Serial Monitor input box is sent to ttyAMA0 as a `serial_input` message, which the Pi receives via `input()` or by reading `/dev/ttyAMA0`. + +--- + +## 9. Pin Mapping — Physical to BCM GPIO + +The Raspberry Pi 3B has a standard **40-pin GPIO header** (2 rows × 20 columns). The table below shows the mapping from physical pin number to BCM GPIO number: + +| Physical | BCM | Function | Physical | BCM | Function | +| -------- | --- | -------- | -------- | --- | -------- | +| 1 | — | 3.3 V | 2 | — | 5 V | +| 3 | **2** | I2C1 SDA | 4 | — | 5 V | +| 5 | **3** | I2C1 SCL | 6 | — | GND | +| 7 | **4** | GPIO | 8 | **14** | UART TX | +| 9 | — | GND | 10 | **15** | UART RX | +| 11 | **17** | GPIO | 12 | **18** | PWM0 | +| 13 | **27** | GPIO | 14 | — | GND | +| 15 | **22** | GPIO | 16 | **23** | GPIO | +| 17 | — | 3.3 V | 18 | **24** | GPIO | +| 19 | **10** | SPI MOSI | 20 | — | GND | +| 21 | **9** | SPI MISO | 22 | **25** | GPIO | +| 23 | **11** | SPI SCLK | 24 | **8** | SPI CE0 | +| 25 | — | GND | 26 | **7** | SPI CE1 | +| 27 | — | ID_SD | 28 | — | ID_SC | +| 29 | **5** | GPIO | 30 | — | GND | +| 31 | **6** | GPIO | 32 | **12** | PWM0 | +| 33 | **13** | PWM1 | 34 | — | GND | +| 35 | **19** | SPI1 MISO | 36 | **16** | SPI1 CE2 | +| 37 | **26** | GPIO | 38 | **20** | SPI1 MOSI | +| 39 | — | GND | 40 | **21** | SPI1 SCLK | + +> Pins 27 and 28 are reserved for ID EEPROM. Power and GND pins have BCM = —. + +### Pin Resolution in Frontend + +```typescript +// Wire connects physical pin "8" on the Pi board +boardPinToNumber('raspberry-pi-3', '8') // → 14 (BCM GPIO14, UART TX) +boardPinToNumber('raspberry-pi-3', 'GPIO17') // → 17 +boardPinToNumber('raspberry-pi-3', 'GND') // → null (not a GPIO) +``` + +--- + +## 10. Virtual File System (VFS) + +Each Raspberry Pi 3 board instance has its own **virtual filesystem tree** stored in the `useVfsStore` Zustand store. This lets you create and edit Python scripts directly in the Velxio editor before they are uploaded to the Pi. + +### Default VFS Tree + +```text +/ +└── home/ + └── pi/ + ├── script.py ← main Python script (editable) + └── hello.sh ← example shell script +``` + +### Default `script.py` + +```python +#!/usr/bin/env python3 +import time +import RPi.GPIO as GPIO + +GPIO.setmode(GPIO.BCM) +GPIO.setup(17, GPIO.OUT) + +while True: + GPIO.output(17, GPIO.HIGH) + print("LED on") + time.sleep(1) + GPIO.output(17, GPIO.LOW) + print("LED off") + time.sleep(1) +``` + +### VFS API + +```typescript +const vfs = useVfsStore.getState(); + +vfs.initBoardVfs(boardId) // create default tree +vfs.createNode(boardId, parentId, 'app.py', 'file') // add new file +vfs.setContent(boardId, nodeId, pythonCode) // update file content +vfs.serializeForUpload(boardId) // returns [{ path, content }, ...] +``` + +Files in the VFS are uploaded to the Pi OS at boot via the WebSocket connection before the script is executed. + +--- + +## 11. Multi-Board Integration — Pi + Arduino + +The Raspberry Pi 3 can be placed on the same canvas as Arduino or other boards. When wires connect a Pi GPIO pin to an Arduino pin, the stores route data between them automatically. + +### Pi → Arduino (Serial TX) + +```text +Pi Python script: + port.write(b"LED_ON\n") + │ + ▼ ttyAMA0 byte output + serial_output WebSocket message + │ + ▼ useSimulatorStore (serial callback) + AVRSimulator.serialWrite("L") ← feeds byte into Arduino RX FIFO + │ + ▼ Arduino sketch: + String cmd = Serial.readStringUntil('\n'); + if (cmd == "LED_ON") digitalWrite(8, HIGH); +``` + +### Arduino → Pi (Serial RX) + +```text +Arduino sketch: + Serial.println("SENSOR:1023"); + │ + ▼ USART byte emitted + useSimulatorStore serial callback + │ + ▼ bridge.sendSerialBytes([charCode, ...]) + serial_input WebSocket message → Backend + │ + ▼ qemu_manager.send_serial_bytes(client_id, bytes) + ttyAMA0 receives bytes → Pi reads with: + line = port.readline() # "SENSOR:1023\n" +``` + +### Example Project: Pi + Arduino LED Control + +This example (included in the gallery as `pi-to-arduino-led-control`) demonstrates bidirectional serial communication: + +**Pi Script:** + +```python +import serial, time + +port = serial.Serial('/dev/ttyAMA0', baudrate=9600, timeout=1) + +for _ in range(3): + port.write(b"LED1_ON\n") + time.sleep(0.5) + port.write(b"LED1_OFF\n") + time.sleep(0.5) + +port.write(b"LED2_ON\n") +time.sleep(2) +port.write(b"LED2_OFF\n") +``` + +**Arduino Sketch:** + +```cpp +const int LED1 = 8, LED2 = 9; + +void setup() { + Serial.begin(9600); + pinMode(LED1, OUTPUT); + pinMode(LED2, OUTPUT); +} + +void loop() { + if (Serial.available()) { + String cmd = Serial.readStringUntil('\n'); + if (cmd == "LED1_ON") digitalWrite(LED1, HIGH); + else if (cmd == "LED1_OFF") digitalWrite(LED1, LOW); + else if (cmd == "LED2_ON") digitalWrite(LED2, HIGH); + else if (cmd == "LED2_OFF") digitalWrite(LED2, LOW); + } +} +``` + +--- + +## 12. Boot Images + +QEMU needs three files from the `/img/` directory to boot the Raspberry Pi 3: + +| File | Size | Description | +| ---- | ---- | ----------- | +| `kernel8.img` | ~6 MB | ARM64 Linux kernel extracted from Raspberry Pi OS Trixie | +| `bcm271~1.dtb` | ~40 KB | Device tree binary — defines CPU, RAM, peripheral base addresses | +| `2025-12-04-raspios-trixie-armhf.img` | ~5.67 GB | Full Raspberry Pi OS SD card image (root filesystem) | + +> The base SD image is **never modified**. Each session creates a **qcow2 copy-on-write overlay** (`overlay_.qcow2`) that records only the changes made during that session. The overlay is automatically deleted when the session ends. + +### Creating the Overlay at Runtime + +```bash +# Backend does this automatically for each session: +qemu-img create -f qcow2 \ + -b /img/2025-12-04-raspios-trixie-armhf.img \ + /tmp/overlay_.qcow2 +``` + +--- + +## 13. QEMU Launch Command + +```bash +qemu-system-aarch64 \ + -M raspi3b \ + -kernel /img/kernel8.img \ + -dtb /img/bcm271~1.dtb \ + -drive file=/tmp/overlay_.qcow2,if=sd,format=qcow2 \ + -m 1G \ + -smp 4 \ + -nographic \ + -serial tcp:127.0.0.1:,server,nowait \ + -serial tcp:127.0.0.1:,server,nowait \ + -append 'console=ttyAMA0 root=/dev/mmcblk0p2 rootwait rw \ + dwc_otg.lpm_enable=0 quiet init=/bin/sh' +``` + +### Key Flags + +| Flag | Value | Meaning | +| ---- | ----- | ------- | +| `-M raspi3b` | machine type | Emulate the Raspberry Pi 3B hardware | +| `-m 1G` | RAM | 1 GB RAM (matches real Pi 3B) | +| `-smp 4` | CPU cores | 4 ARM Cortex-A53 cores | +| `-nographic` | no display | No HDMI/video output — serial only | +| `-serial tcp:...:N,server,nowait` | first serial | ttyAMA0 (user serial) served on TCP port N | +| `-serial tcp:...:M,server,nowait` | second serial | ttyAMA1 (GPIO shim protocol) served on TCP port M | +| `-append ... init=/bin/sh` | kernel cmdline | Boot straight to a shell (skips systemd login) | +| `-drive ...,format=qcow2` | disk | qcow2 overlay over the base SD image | + +--- + +## 14. Known Limitations + +| Limitation | Detail | +| ---------- | ------ | +| Boot time | QEMU takes 2–5 seconds to start; the frontend shows a "booting" state during this time | +| No real PWM | `GPIO.PWM` simulates duty cycle as binary state (>50% = HIGH, ≤50% = LOW); no analog dimming | +| No I2C emulation | `smbus`, `smbus2`, `i2c_msg` — I2C bus transactions are not forwarded to virtual devices | +| No SPI emulation | Hardware SPI registers not forwarded; `spidev` library will fail | +| Single UART for GPIO | ttyAMA1 is reserved for the GPIO shim; scripts cannot use it for other serial devices | +| No GUI / display | HDMI output is disabled (`-nographic`); GUI Python libraries (Tkinter, pygame, etc.) will not work | +| No networking | QEMU does not expose a network interface; `requests`, `socket`, `urllib` will fail | +| No persistent state | The qcow2 overlay is deleted after shutdown; files written to the Pi OS do not survive a restart | +| Reset is reconnect | `resetBoard()` is not implemented; to restart the Pi, stop it and start it again | +| Session isolation | Each board instance creates an independent QEMU process; two Pi boards do not share any state | +| Resource usage | Each Pi instance launches a full QEMU process (~200 MB RAM); hosting many simultaneous sessions is resource-intensive | + +--- + +## 15. Differences vs Other Emulators + +| Aspect | Raspberry Pi 3B | Raspberry Pi Pico | ESP32 (Xtensa) | Arduino AVR | +| ------ | --------------- | ----------------- | -------------- | ----------- | +| Engine | QEMU raspi3b | rp2040js (browser) | QEMU lcgamboa (backend) | avr8js (browser) | +| Backend required | **Yes** (QEMU process) | No | Yes (QEMU process) | No | +| Language | **Python** | C++ (Arduino) | C++ (Arduino) | C++ (Arduino) | +| Compilation step | **No** | Yes (arduino-cli) | Yes (arduino-cli) | Yes (arduino-cli) | +| OS | **Raspberry Pi OS (Linux)** | None (bare metal) | None (ESP-IDF) | None (bare metal) | +| Boot time | ~2–5 s | Instant | ~1–2 s | Instant | +| GPIO protocol | Text over ttyAMA1 | MMIO direct | QEMU callbacks + WebSocket | Port listeners | +| Serial | ttyAMA0 (real UART) | UART0/1 (rp2040js) | UART0 (QEMU) | USART0 (avr8js) | +| I2C | Not forwarded to frontend | 2 buses + virtual devices | Emulated | Not emulated | +| PWM | Binary (no waveform) | Hardware PWM | LEDC (mapped) | Timer-based | +| Multi-board comms | Yes (serial bridge) | No | No | No | +| Oscilloscope | No | Yes (8 ns resolution) | No | Yes | +| CI tests | No | Yes (Vitest) | No | Yes (Vitest) | +| Disk image required | **Yes** (~5.67 GB) | No | No | No | + +--- + +## 16. Key Files + +| File | Description | +| ---- | ----------- | +| `backend/app/services/qemu_manager.py` | `QemuManager` — manages QEMU process lifecycle, TCP sockets, qcow2 overlays | +| `backend/app/services/gpio_shim.py` | `RPi.GPIO` drop-in replacement; speaks text protocol over ttyAMA1 | +| `backend/app/api/routes/simulation.py` | WebSocket endpoint `/api/simulation/ws/{client_id}` | +| `frontend/src/simulation/RaspberryPi3Bridge.ts` | WebSocket client; routes `serial_output`, `gpio_change`, `system` events | +| `frontend/src/store/useSimulatorStore.ts` | Board lifecycle, serial bridge to co-simulated AVR/Pico boards | +| `frontend/src/store/useVfsStore.ts` | Per-board virtual filesystem (Python script editor) | +| `frontend/src/utils/boardPinMapping.ts` | Physical pin → BCM GPIO number mapping table | +| `frontend/src/components/components-wokwi/RaspberryPi3.tsx` | Board React component (SVG, 40-pin header coordinates) | +| `frontend/src/components/components-wokwi/RaspberryPi3Element.ts` | Web Component for canvas rendering and wire endpoints | +| `frontend/src/types/board.ts` | `BoardKind` type, `FQBN = null` for Raspberry Pi 3 | +| `img/kernel8.img` | ARM64 kernel extracted from Raspberry Pi OS Trixie | +| `img/bcm271~1.dtb` | Device tree binary for BCM2837 | +| `img/2025-12-04-raspios-trixie-armhf.img` | Raspberry Pi OS SD image (~5.67 GB) — base for qcow2 overlays | diff --git a/docs/RP2040_EMULATION.md b/docs/RP2040_EMULATION.md new file mode 100644 index 0000000..5e23ffe --- /dev/null +++ b/docs/RP2040_EMULATION.md @@ -0,0 +1,609 @@ +# RP2040 Emulation (Raspberry Pi Pico / Pico W) + +> Status: **Functional** · In-browser emulation · No backend dependencies +> Engine: **rp2040js** — ARM Cortex-M0+ emulator in TypeScript +> Platform: **RP2040 @ 125 MHz** — dual-core ARM Cortex-M0+ (single core emulated) +> Available on: all platforms (Windows, macOS, Linux, Docker) +> Applies to: **Raspberry Pi Pico**, **Raspberry Pi Pico W** + +--- + +## Table of Contents + +1. [Overview](#1-overview) +2. [Supported Boards](#2-supported-boards) +3. [Emulator Architecture](#3-emulator-architecture) +4. [Emulated Memory and Peripherals](#4-emulated-memory-and-peripherals) +5. [Full Flow: Compile and Run](#5-full-flow-compile-and-run) +6. [Binary Format and Loading](#6-binary-format-and-loading) +7. [GPIO](#7-gpio) +8. [UART — Serial Monitor](#8-uart--serial-monitor) +9. [ADC — Analog Inputs](#9-adc--analog-inputs) +10. [I2C Virtual Devices](#10-i2c-virtual-devices) +11. [SPI](#11-spi) +12. [PWM](#12-pwm) +13. [Simulation Execution Loop](#13-simulation-execution-loop) +14. [Pin Mapping](#14-pin-mapping) +15. [Oscilloscope / Logic Analyzer](#15-oscilloscope--logic-analyzer) +16. [Known Limitations](#16-known-limitations) +17. [Tests](#17-tests) +18. [Differences vs Other Emulators](#18-differences-vs-other-emulators) +19. [Key Files](#19-key-files) + +--- + +## 1. Overview + +The **Raspberry Pi Pico** and **Pico W** boards use the **RP2040** microcontroller — a dual-core **ARM Cortex-M0+** chip designed by Raspberry Pi. Unlike the ESP32 (which requires QEMU running in the backend), RP2040 emulation runs **entirely in the browser** using the [rp2040js](https://github.com/wokwi/rp2040js) library (a local clone in `wokwi-libs/rp2040js/`). + +### Emulation Engine Comparison + +| Board | CPU | Engine | +| ----- | --- | ------ | +| Arduino Uno / Nano / Mega | AVR ATmega | avr8js (browser) | +| Raspberry Pi Pico / Pico W | RP2040 ARM Cortex-M0+ | **rp2040js (browser, no backend)** | +| ESP32-C3, XIAO-C3 | RISC-V RV32IMC | RiscVCore.ts (browser) | +| ESP32, ESP32-S3 | Xtensa LX6/LX7 | QEMU lcgamboa (backend WebSocket) | + +### Advantages of the In-Browser Emulator + +- **No network dependencies** — works offline, no WebSocket connection to any backend process +- **Instant startup** — emulation begins immediately after compilation (no process launch latency) +- **Testable with Vitest** — the same TypeScript code runs in both production and CI tests +- **Cross-platform** — identical behavior on Windows, macOS, Linux, and Docker + +--- + +## 2. Supported Boards + +| Board | arduino-cli FQBN | Built-in LED | Notes | +| ----- | ---------------- | ------------ | ----- | +| Raspberry Pi Pico | `rp2040:rp2040:rpipico` | GPIO 25 | Standard Pico | +| Raspberry Pi Pico W | `rp2040:rp2040:rpipicow` | GPIO 25 (via CYW43) | WiFi chip not emulated | + +> **Pico W note:** The wireless chip (Infineon CYW43439) is not emulated. GPIO 25 drives the on-board LED in the same way as the standard Pico for simulation purposes. + +--- + +## 3. Emulator Architecture + +```text +Arduino Sketch (.ino) + │ + ▼ arduino-cli (backend, FQBN rp2040:rp2040:rpipico) + sketch.ino.bin ← raw ARM binary (no HEX format) + │ + ▼ base64 → frontend + compileBoardProgram(boardId, base64) + │ + ▼ RP2040Simulator.loadBinary(base64) + Uint8Array → copied into rp2040.flash at offset 0 + │ + ▼ rp2040.loadBootrom(bootromB1) + Bootrom B1 revision loaded + │ + ▼ PC reset to 0x10000000 (FLASH_START_ADDRESS) + CortexM0Core.executeInstruction() ← requestAnimationFrame @ 60 FPS + │ 2,083,333 cycles/frame (125 MHz ÷ 60) + ├── GPIO listener → PinManager → visual component update + ├── UART0/UART1 byte → onSerialData → Serial Monitor + ├── ADC channel read → channelValues[ch] → analogRead() + └── I2C bus events → virtual I2C device callbacks +``` + +### Main Classes + +| Class | File | Responsibility | +| ----- | ---- | -------------- | +| `RP2040Simulator` | `simulation/RP2040Simulator.ts` | Main wrapper: bootrom, GPIO, UART, ADC, I2C, SPI, RAF loop | +| `RP2040` | `rp2040js` (library) | Full hardware model: CPU, peripherals, memory map | +| `CortexM0Core` | `rp2040js` (library) | ARM Cortex-M0+ instruction decoder and executor | +| `PinManager` | `simulation/PinManager.ts` | Routes GPIO events to visual components | + +--- + +## 4. Emulated Memory and Peripherals + +### Memory Map + +| Region | Base Address | Size | Description | +| ------ | ------------ | ---- | ----------- | +| Flash (XIP) | `0x10000000` | 16 MB | Program storage (firmware binary) | +| SRAM | `0x20000000` | 264 KB | Data RAM (stack, variables) | +| USB DPRAM | `0x50100000` | 4 KB | USB dual-port RAM | +| Bootrom | `0x00000000` | 4 KB | B1 revision bootrom | + +### Peripherals Emulated by rp2040js + +| Peripheral | Details | +| ---------- | ------- | +| GPIO | All 30 pins (GPIO0–GPIO29), input/output | +| UART0 | TX/RX, baud rate auto-detection | +| UART1 | TX/RX, forwarded to same `onSerialData` callback | +| I2C0 | Master mode, virtual device callbacks | +| I2C1 | Master mode, virtual device callbacks | +| SPI0 | Default loopback; custom handler supported | +| SPI1 | Default loopback; custom handler supported | +| ADC | 5 channels (GPIO26–29 + internal temp sensor, ch4) | +| PWM | Available on any GPIO | +| Timers | Used internally for `delay()`, `millis()` | +| Watchdog | Present (reads return 0) | +| PLL / Clock | Simulated at fixed 125 MHz | + +### Peripherals NOT Emulated + +- **WiFi/BLE** (Pico W: CYW43439 wireless chip) +- **USB device stack** (USB device enumeration) +- **DMA transfers** (DMA control registers return 0) +- **PIO state machines** (PIO registers return 0) + +> PIO in particular is a significant limitation — `PicoLED`, `WS2812` (NeoPixel), `DHT`, and other timing-critical libraries that rely on PIO will not function. + +--- + +## 5. Full Flow: Compile and Run + +### 5.1 Compile the Sketch + +The backend compiles for the Pico using the earlephilhower arduino-pico core: + +```bash +# First-time setup — install the RP2040 board manager: +arduino-cli config add board_manager.additional_urls \ + https://github.com/earlephilhower/arduino-pico/releases/download/global/package_rp2040_index.json + +arduino-cli core install rp2040:rp2040 + +# Compile for Raspberry Pi Pico: +arduino-cli compile \ + --fqbn rp2040:rp2040:rpipico \ + --output-dir build/ \ + my_sketch/ + +# Output: build/my_sketch.ino.bin ← raw binary +``` + +The Velxio backend automatically finds `sketch.ino.bin` (or `sketch.ino.uf2` as fallback), encodes it as base64, and sends it to the frontend in `CompileResponse.binary_content`. + +### 5.2 Serial Redirection (Important) + +The backend **automatically prepends** `#define Serial Serial1` to `sketch.ino` for RP2040 boards: + +```python +# backend/app/services/arduino_cli.py +if "rp2040" in board_fqbn and write_name == "sketch.ino": + content = "#define Serial Serial1\n" + content +``` + +**Why?** The RP2040 bootrom uses UART0 for its own communication. To avoid conflicts, the Arduino `Serial` object is remapped to UART1. This means `Serial.print()` in your sketch goes through UART1, which the emulator also captures and shows in the Serial Monitor. + +### 5.3 Minimal Sketch for Raspberry Pi Pico + +```cpp +// Blink the built-in LED (GPIO 25) +void setup() { + pinMode(LED_BUILTIN, OUTPUT); + Serial.begin(115200); + Serial.println("Pico started!"); +} + +void loop() { + digitalWrite(LED_BUILTIN, HIGH); + Serial.println("LED ON"); + delay(500); + digitalWrite(LED_BUILTIN, LOW); + Serial.println("LED OFF"); + delay(500); +} +``` + +### 5.4 Analog Read Example + +```cpp +// Read a potentiometer on GPIO 26 (ADC channel 0) +void setup() { + Serial.begin(115200); +} + +void loop() { + int raw = analogRead(A0); // GPIO26 → ADC ch0, returns 0–4095 + float voltage = raw * 3.3f / 4095.0f; + Serial.print("ADC: "); + Serial.print(raw); + Serial.print(" → "); + Serial.print(voltage); + Serial.println(" V"); + delay(200); +} +``` + +--- + +## 6. Binary Format and Loading + +The RP2040 uses a **raw binary format** (`.bin`), not the Intel HEX format used by AVR: + +```typescript +// RP2040Simulator.loadBinary(base64: string) +loadBinary(base64: string): void { + const binary = Uint8Array.from(atob(base64), c => c.charCodeAt(0)); + // Copy directly into flash at offset 0 + this.rp2040.flash.set(binary, 0); + // Load bootrom and reset PC to 0x10000000 + this.rp2040.loadBootrom(bootromB1); +} +``` + +**Flash memory layout** (as seen by the CPU): + +```text +0x10000000 ← FLASH_START_ADDRESS — firmware entry point (PC reset here) +0x10000100 ... program .text section +0x10xxxxxx ... .rodata, .data, constants +0x20000000 ← SRAM — stack, heap, .bss +``` + +The bootrom B1 (`rp2040-bootrom.ts`) contains the RP2040's factory-programmed ROM code, required for correct flash XIP (eXecute In Place) initialization. + +--- + +## 7. GPIO + +All 30 GPIO pins (GPIO0–GPIO29) are emulated. Each pin has an event listener attached at startup: + +```typescript +// RP2040Simulator.ts — gpio listener setup +for (let gpioIdx = 0; gpioIdx < 30; gpioIdx++) { + const gpio = this.rp2040.gpio[gpioIdx]; + gpio.addListener((state: GPIOPinState) => { + const isHigh = state === GPIOPinState.High; + this.pinManager.triggerPinChange(gpioIdx, isHigh); + if (this.onPinChangeWithTime) { + const timeMs = this.rp2040.clock.timeUs / 1000; + this.onPinChangeWithTime(gpioIdx, isHigh, timeMs); + } + }); +} +``` + +### GPIO Input (Push Buttons / Switches) + +External components can drive GPIO pins from the UI: + +```typescript +// Set a pin HIGH or LOW from the simulator canvas (e.g. button press) +simulator.setPinState(gpioPin: number, state: boolean): void +// → rp2040.gpio[gpioPin].setInputValue(state) +``` + +This is equivalent to the signal propagated by a physical wire from a button to the GPIO pin. + +### LED_BUILTIN + +- `LED_BUILTIN` = GPIO 25 on both Pico and Pico W +- A pin change listener on GPIO 25 drives the on-board LED component +- `digitalWrite(LED_BUILTIN, HIGH)` → GPIO 25 goes high → LED visual component turns on + +--- + +## 8. UART — Serial Monitor + +The RP2040 has two UART controllers. Both are emulated and forwarded to the Serial Monitor: + +| Channel | TX Pin | RX Pin | Arduino Object | Notes | +| ------- | ------ | ------ | -------------- | ----- | +| UART0 | GPIO0 | GPIO1 | `Serial1` | Used by bootrom; Arduino `Serial` redirected away | +| UART1 | GPIO4 | GPIO5 | `Serial` (redirected) | Receives Arduino `Serial.print()` | + +### Serial Output (TX → Monitor) + +```typescript +// Both UART0 and UART1 forward bytes to the same callback: +this.rp2040.uart[0].onByte = (value: number) => { + this.onSerialData?.(String.fromCharCode(value)); +}; +this.rp2040.uart[1].onByte = (value: number) => { + this.onSerialData?.(String.fromCharCode(value)); +}; +``` + +### Serial Input (Monitor → Sketch) + +```typescript +// Feed text from the Serial Monitor input box into the sketch: +simulator.serialWrite("COMMAND\n"); +// → bytes queued in rp2040.uart[0].feedByte(charCode) +// → sketch reads them via Serial.read() / Serial.readString() +``` + +--- + +## 9. ADC — Analog Inputs + +The RP2040 has a 12-bit ADC (0–4095) with 5 channels: + +| ADC Channel | GPIO Pin | Arduino Alias | Default Value | Notes | +| ----------- | -------- | ------------- | ------------- | ----- | +| 0 | GPIO26 | A0 | 2048 (~1.65 V) | General purpose | +| 1 | GPIO27 | A1 | 2048 (~1.65 V) | General purpose | +| 2 | GPIO28 | A2 | 2048 (~1.65 V) | General purpose | +| 3 | GPIO29 | A3 | 2048 (~1.65 V) | General purpose | +| 4 | — (internal) | — | 876 (~27 °C) | Internal temperature sensor | + +### Injecting ADC Values from UI Components + +When a potentiometer is wired to an ADC pin on the canvas, the simulator canvas reads the potentiometer's value and injects it: + +```typescript +// SimulatorCanvas — potentiometer input event +simulator.setADCValue(channel: number, value: number): void +// value range: 0–4095 (clamped automatically) +// → rp2040.adc.channelValues[channel] = value +``` + +`analogRead(A0)` in the sketch reads `adc.channelValues[0]` directly. + +--- + +## 10. I2C Virtual Devices + +The RP2040 emulator supports virtual I2C devices — software objects that respond to I2C bus transactions from the firmware: + +```typescript +export interface RP2040I2CDevice { + address: number; // 7-bit I2C address + writeByte(value: number): boolean; // return true = ACK + readByte(): number; + stop?(): void; +} +``` + +### Default Virtual Devices (Auto-Registered) + +Three virtual I2C devices are registered automatically when a Pico program is loaded: + +| Device | Address | Bus | Description | +| ------ | ------- | --- | ----------- | +| `VirtualDS1307` | 0x68 | I2C0 | Real-time clock (DS1307 compatible) | +| `VirtualTempSensor` | 0x48 | I2C0 | Temperature sensor (LM75 / TMP102 compatible) | +| `I2CMemoryDevice` | 0x50 | I2C0 | 24C04 EEPROM (512 bytes) | + +### Default I2C0 Pins + +| Signal | GPIO | +| ------ | ---- | +| SDA | GPIO4 | +| SCL | GPIO5 | + +### I2C Bus Event Flow + +```text +firmware: Wire.beginTransmission(0x68) + │ + ▼ I2C master asserts START + address + rp2040.i2c[0].onConnect(address=0x68) + │ + ▼ device found in registry + ds1307.writeByte(register_address) + │ + Wire.requestFrom(0x68, 7) + │ + ▼ 7 read calls + ds1307.readByte() × 7 + │ + ▼ I2C STOP + ds1307.stop() +``` + +--- + +## 11. SPI + +Both SPI buses implement a **loopback** by default — bytes transmitted by the master are immediately echoed back as received bytes: + +```typescript +// Default: loopback +this.rp2040.spi[0].onTransmit = (value: number) => { + this.rp2040.spi[0].completeTransmit(value); +}; +``` + +### Default SPI0 Pins + +| Signal | GPIO | +| ------ | ---- | +| MISO | GPIO16 | +| CS | GPIO17 | +| SCK | GPIO18 | +| MOSI | GPIO19 | + +### Custom SPI Handler + +A custom handler can replace the loopback for simulating specific SPI peripherals (displays, sensors): + +```typescript +simulator.setSPIHandler(bus: 0 | 1, handler: (value: number) => number): void +// handler receives TX byte, returns RX byte +``` + +--- + +## 12. PWM + +PWM is available on any GPIO pin through the RP2040's hardware PWM slices. The rp2040js library emulates the PWM peripheral registers, so `analogWrite()` and `ledcWrite()` work at the firmware level. + +Visual PWM feedback (LED dimming) in the simulator canvas uses the `onPwmChange` callback from `PinManager`, which receives the duty cycle as a 0.0–1.0 float and sets `el.style.opacity` on the LED element. + +--- + +## 13. Simulation Execution Loop + +The simulation runs at **60 FPS** using `requestAnimationFrame`. Each frame executes enough CPU cycles to match a 125 MHz clock: + +``` +F_CPU = 125,000,000 Hz +CYCLE_NANOS = 1e9 / F_CPU = 8 ns/cycle +CYCLES_PER_FRAME = F_CPU / 60 = 2,083,333 cycles/frame +``` + +### WFI Optimization + +When the ARM core executes a **WFI** (Wait For Interrupt) instruction — which Arduino uses during `delay()` and `sleep()` — the loop skips ahead to the next pending timer alarm instead of executing millions of NOP-equivalent cycles: + +```typescript +while (cyclesDone < cyclesTarget) { + if (core.waiting) { + // CPU is sleeping — jump to next alarm + const jump = clock.nanosToNextAlarm; + if (jump <= 0) break; + clock.tick(jump); + cyclesDone += Math.ceil(jump / CYCLE_NANOS); + } else { + // Execute one ARM instruction + const cycles = core.executeInstruction(); + clock.tick(cycles * CYCLE_NANOS); + cyclesDone += cycles; + } +} +``` + +This allows `delay(1000)` to complete in microseconds of real time instead of simulating all 125 million cycles. + +### Variable Speed + +The simulation speed can be adjusted: + +```typescript +simulator.setSpeed(speed: number): void +// speed: 0.1 (10% = very slow, for debugging) to 10.0 (10× faster) +``` + +--- + +## 14. Pin Mapping + +The Pico has 40 physical pins. Below is the mapping from board pin names to GPIO numbers: + +| Board Pin | GPIO | Function | Board Pin | GPIO | Function | +| --------- | ---- | -------- | --------- | ---- | -------- | +| GP0 | 0 | UART0 TX | GP15 | 15 | SPI1 TX | +| GP1 | 1 | UART0 RX | GP16 | 16 | SPI0 MISO | +| GP2 | 2 | I2C1 SDA | GP17 | 17 | SPI0 CS | +| GP3 | 3 | I2C1 SCL | GP18 | 18 | SPI0 SCK | +| GP4 | 4 | I2C0 SDA | GP19 | 19 | SPI0 MOSI | +| GP5 | 5 | I2C0 SCL | GP20 | 20 | — | +| GP6 | 6 | SPI0 SCK | GP21 | 21 | — | +| GP7 | 7 | SPI0 TX | GP22 | 22 | — | +| GP8 | 8 | UART1 TX | GP26 | 26 | ADC ch0 (A0) | +| GP9 | 9 | UART1 RX | GP27 | 27 | ADC ch1 (A1) | +| GP10 | 10 | SPI1 SCK | GP28 | 28 | ADC ch2 (A2) | +| GP11 | 11 | SPI1 TX | GP29 | 29 | ADC ch3 (A3) | +| GP12 | 12 | SPI1 RX | **GP25** | **25** | **LED_BUILTIN** | +| GP13 | 13 | SPI1 CS | — | — | VBUS, VSYS, 3V3, GND | +| GP14 | 14 | SPI1 SCK | — | — | RUN, ADC_VREF | + +> All GPIO pins support PWM. GPIO 0–22 and 26–29 are available for general-purpose digital I/O. GPIO 23–25 are internal (power control, LED, SMPS mode). + +--- + +## 15. Oscilloscope / Logic Analyzer + +The RP2040 emulator provides timestamps for every GPIO transition using the internal simulation clock: + +```typescript +// Callback fires on every GPIO state change +simulator.onPinChangeWithTime = (pin: number, state: boolean, timeMs: number) => { + // timeMs = rp2040.clock.timeUs / 1000 + // Accurate to ~8 ns (one ARM clock cycle) +}; +``` + +The oscilloscope store (`useOscilloscopeStore`) subscribes to this callback and records samples: + +```text +GPIO event fired (pin=25, state=HIGH, timeMs=123.456) + │ + ▼ +useOscilloscopeStore.pushSample(channelId, 123.456, true) + │ + ▼ +Oscilloscope waveform display updates +``` + +This enables the built-in logic analyzer to display accurate waveforms for signals like PWM, UART bit patterns, and I2C clock/data. + +--- + +## 16. Known Limitations + +| Limitation | Detail | +| ---------- | ------ | +| Single-core only | RP2040 is dual-core; emulator runs core 0 only. Code that uses `multicore_launch_core1()` will not execute on core 1 | +| No PIO | PIO state machines return 0. Libraries that depend on PIO (WS2812 NeoPixels, DHT sensors, I2S audio, quadrature encoders) will not work | +| No WiFi (Pico W) | The CYW43439 wireless chip is not emulated; `WiFi.begin()` will not connect | +| No USB device | USB HID, CDC, and MIDI device modes are not emulated | +| No DMA | DMA transfers return without moving data; memcpy-based alternatives work fine | +| No hardware FPU | ARM Cortex-M0+ has no floating-point unit; float operations are emulated in software (slower, but correct) | +| Timing accuracy | Emulation runs at variable speed; `micros()` and `millis()` track simulated time, not wall-clock time | +| Flash writes | `LittleFS`, `EEPROM.commit()`, and other flash-write operations may not persist across simulated resets | +| Serial redirect | `Serial` is mapped to `Serial1` (UART1) at compile time; code that uses `Serial1` directly alongside `Serial` may behave unexpectedly | + +--- + +## 17. Tests + +RP2040 emulation tests are in `frontend/src/__tests__/`: + +```bash +cd frontend +npm test -- RP2040 +``` + +### Test Suites + +| Suite | Tests | What It Verifies | +| ----- | ----- | ---------------- | +| Lifecycle | 4 | `create`, `loadBinary`, `start`, `stop`, `reset` idempotency | +| GPIO | 8 | All 30 pins, state injection, listener callbacks, multiple listeners | +| ADC | 3 | Channel access (0–4), value clamping to 0–4095, `analogRead` integration | +| Serial | 4 | `onSerialData` callback, `serialWrite` input feed, both UART channels | +| I2C | 5 | Virtual device registration, address matching, read/write/stop callbacks | +| SPI | 2 | Custom handler registration, loopback default | +| Bootrom | 1 | Loads without errors, PC resets to `0x10000000` | + +--- + +## 18. Differences vs Other Emulators + +| Aspect | Raspberry Pi Pico (RP2040) | Arduino AVR | ESP32-C3 (RISC-V) | ESP32 (Xtensa) | +| ------ | -------------------------- | ----------- | ------------------ | -------------- | +| Engine | `rp2040js` (browser) | `avr8js` (browser) | `RiscVCore.ts` (browser) | QEMU backend (WebSocket) | +| Backend dependency | **No** | **No** | **No** | Yes | +| Architecture | ARM Cortex-M0+ | AVR 8-bit | RISC-V RV32IMC | Xtensa LX6 | +| Clock speed | 125 MHz | 16 MHz | 160 MHz | 240 MHz | +| Binary format | `.bin` (raw) | `.hex` (Intel HEX) | `.bin` (merged flash) | `.bin` (merged flash) | +| Arduino framework | Full | Full | Partial (no FreeRTOS) | Full | +| Serial | UART0 + UART1 | USART0 | UART0 | UART0 | +| ADC | 4 external + 1 temp | 6 channels (10-bit) | Not emulated | Emulated | +| I2C | 2 buses + virtual devices | Not emulated | Not emulated | Emulated | +| SPI | 2 buses (loopback) | Not emulated | Not emulated | Emulated | +| PIO | **Not emulated** | N/A | N/A | N/A | +| PWM | All GPIO pins | Timer-based | Not emulated | LEDC (mapped) | +| Oscilloscope support | Yes (8 ns resolution) | Yes | Yes | No | +| CI tests | Yes (Vitest) | Yes | Yes | No | + +--- + +## 19. Key Files + +| File | Description | +| ---- | ----------- | +| `frontend/src/simulation/RP2040Simulator.ts` | Main emulator wrapper (GPIO, UART, ADC, I2C, SPI, RAF loop) | +| `frontend/src/simulation/rp2040-bootrom.ts` | RP2040 B1 bootrom binary (required for flash XIP) | +| `frontend/src/simulation/PinManager.ts` | Routes GPIO events to visual components on canvas | +| `frontend/src/store/useSimulatorStore.ts` | Zustand store — `compileBoardProgram()`, `startBoard()`, serial wiring | +| `frontend/src/components/simulator/SimulatorCanvas.tsx` | Canvas rendering, pin subscriptions, ADC/button event forwarding | +| `frontend/src/components/components-wokwi/PiPicoWElement.ts` | Pico W SVG board rendering and pin coordinate map | +| `frontend/src/__tests__/RP2040Simulator.test.ts` | Unit and integration tests | +| `backend/app/services/arduino_cli.py` | Compilation — detects RP2040 FQBN, encodes `.bin` as base64, prepends `Serial1` redirect | +| `wokwi-libs/rp2040js/` | Local clone of the rp2040js library (ARM Cortex-M0+ emulator) | diff --git a/docs/getting-started.md b/docs/getting-started.md index de9bb01..7fd674f 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -114,3 +114,47 @@ void loop() { | LED doesn't blink | Check the browser console for port listener errors; verify pin assignment in the component property dialog. | | Serial Monitor is empty | Ensure `Serial.begin()` is called inside `setup()` before any `Serial.print()`. | | Compilation errors | Check the compilation console at the bottom of the editor for full `arduino-cli` output. | + +--- + +## Community & Links + +- **GitHub:** [github.com/davidmonterocrespo24/velxio](https://github.com/davidmonterocrespo24/velxio) — source code, issues, pull requests +- **Discord:** [YOUR_DISCORD_INVITE_URL] — ask questions, share projects, report issues +- **Live Demo:** [velxio.dev](https://velxio.dev) + +--- + +## Documentation + +### Orientation + +- [Introduction](./intro.md) — What is Velxio and why use it +- [Getting Started](./getting-started.md) — This page + +### Architecture & Internals + +- [Architecture](./ARCHITECTURE.md) — High-level project architecture +- [Emulator Architecture](./emulator.md) — How CPU emulation works layer by layer +- [Wokwi Libraries Integration](./WOKWI_LIBS.md) — Local wokwi-elements, avr8js, rp2040js + +### Boards & Emulation + +- [RP2040 Emulation](./RP2040_EMULATION.md) — Raspberry Pi Pico / Pico W in-browser emulator (ARM Cortex-M0+) +- [Raspberry Pi 3 Emulation](./RASPBERRYPI3_EMULATION.md) — BCM2837 / QEMU raspi3b, Python + GPIO shim +- [ESP32 Emulation](./ESP32_EMULATION.md) — Full Xtensa QEMU emulation (GPIO, ADC, PWM, WiFi, I2C, SPI, RMT) +- [RISC-V Emulation](./RISCV_EMULATION.md) — ESP32-C3 / XIAO-C3 in-browser emulator + +### Components & Examples + +- [Components Reference](./components.md) — All 48+ supported electronic components +- [Example Projects](./examples/README.md) — Built-in example gallery + +### API & Integrations + +- [MCP Server](./MCP.md) — Model Context Protocol server for AI agent integration + +### Project Status + +- [Roadmap](./roadmap.md) — Implemented, in-progress, and planned features +- [Setup Complete](./SETUP_COMPLETE.md) — Feature implementation status log diff --git a/docs/intro.md b/docs/intro.md index 56ab891..32d3089 100644 --- a/docs/intro.md +++ b/docs/intro.md @@ -26,11 +26,44 @@ Write Arduino C++ code, compile it with a real `arduino-cli` backend, and simula --- -## Quick Links +## Documentation + +### Getting Started + +- [Getting Started](./getting-started.md) — Quick setup guide (hosted, Docker, manual) +- [Introduction](./intro.md) — Overview, supported boards, quick links + +### Architecture & Internals + +- [Architecture](./ARCHITECTURE.md) — High-level project architecture +- [Emulator Architecture](./emulator.md) — How CPU emulation works layer by layer +- [Wokwi Libraries Integration](./WOKWI_LIBS.md) — Local wokwi-elements, avr8js, rp2040js setup + +### Boards & Emulation + +- [RP2040 Emulation](./RP2040_EMULATION.md) — Raspberry Pi Pico / Pico W in-browser emulator (ARM Cortex-M0+) +- [Raspberry Pi 3 Emulation](./RASPBERRYPI3_EMULATION.md) — BCM2837 / QEMU raspi3b, Python + GPIO shim +- [ESP32 Emulation](./ESP32_EMULATION.md) — Full Xtensa QEMU emulation (GPIO, ADC, PWM, WiFi, I2C, SPI, RMT) +- [RISC-V Emulation](./RISCV_EMULATION.md) — ESP32-C3 / XIAO-C3 in-browser emulator + +### Components & Examples + +- [Components Reference](./components.md) — All 48+ supported electronic components +- [Example Projects](./examples/README.md) — Built-in example gallery + +### API & Integrations + +- [MCP Server](./MCP.md) — Model Context Protocol server for AI agent integration + +### Project Status + +- [Roadmap](./roadmap.md) — Implemented, in-progress, and planned features +- [Setup Complete](./SETUP_COMPLETE.md) — Feature implementation status log + +--- + +## Community & Links -- [Getting Started](./getting-started.md) -- [Emulator Architecture](./emulator.md) -- [Components Reference](./components.md) -- [Roadmap](./roadmap.md) - [Live Demo](https://velxio.dev) - [GitHub Repository](https://github.com/davidmonterocrespo24/velxio) +- [Discord](YOUR_DISCORD_INVITE_URL) — Ask questions, share projects, report issues diff --git a/frontend/public/boards/Raspberry_Pi_3.svg b/frontend/public/boards/Raspberry_Pi_3.svg new file mode 100644 index 0000000..9e2a8b8 --- /dev/null +++ b/frontend/public/boards/Raspberry_Pi_3.svg @@ -0,0 +1,9138 @@ + + + +image/svg+xml \ No newline at end of file diff --git a/frontend/public/image.png b/frontend/public/image.png index 6a1f0f4..f2d5726 100644 Binary files a/frontend/public/image.png and b/frontend/public/image.png differ diff --git a/frontend/src/pages/LandingPage.css b/frontend/src/pages/LandingPage.css index f2723d8..c24df59 100644 --- a/frontend/src/pages/LandingPage.css +++ b/frontend/src/pages/LandingPage.css @@ -238,13 +238,13 @@ /* ── Hero ─────────────────────────────────────────────── */ .landing-hero { display: grid; - grid-template-columns: 1fr 1fr; + grid-template-columns: 1fr 1.3fr; align-items: center; - gap: 64px; - padding: 100px 80px 100px 80px; - max-width: 1240px; + gap: 56px; + padding: 80px 80px 80px 80px; + max-width: 1400px; margin: 0 auto; - min-height: 85vh; + min-height: 90vh; } .hero-left { @@ -387,10 +387,10 @@ .hero-preview-img { width: 100%; - max-width: 560px; + max-width: 100%; height: auto; border-radius: var(--radius); - filter: drop-shadow(0 16px 48px rgba(0, 0, 0, 0.7)); + filter: drop-shadow(0 24px 64px rgba(0, 0, 0, 0.75)); } /* ── Sections ─────────────────────────────────────────── */ @@ -898,8 +898,9 @@ /* ── Responsive ───────────────────────────────────────── */ @media (max-width: 1024px) { .landing-hero { - gap: 48px; - padding: 80px 48px; + grid-template-columns: 1fr 1.2fr; + gap: 40px; + padding: 72px 48px; } .landing-section {