feat: complete project setup with Wokwi libraries integration and documentation
- Removed outdated WOKWI_LIBS.md and replaced with updated documentation. - Added ARCHITECTURE.md to describe project structure and data flow. - Created SETUP_COMPLETE.md for installation and configuration instructions. - Implemented automatic update script for Wokwi libraries. - Updated frontend components to utilize local Wokwi libraries. - Enhanced AVRSimulator to manage peripherals more efficiently. - Added example screenshot generation instructions for better documentation. - Updated components metadata and ensured proper integration with Vite.
This commit is contained in:
parent
879decab22
commit
d81aa76260
|
|
@ -0,0 +1,321 @@
|
|||
# Project Architecture - Arduino Emulator
|
||||
|
||||
## Overview
|
||||
|
||||
This project is a fully local Arduino emulator using official Wokwi repositories for maximum compatibility.
|
||||
|
||||
```
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ USER (Browser) │
|
||||
│ http://localhost:5173 │
|
||||
└──────────────────────────┬──────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ FRONTEND (React + Vite) │
|
||||
│ │
|
||||
│ ┌────────────────┐ ┌──────────────────┐ ┌─────────────┐ │
|
||||
│ │ Monaco Editor │ │ Zustand Store │ │ Simulator │ │
|
||||
│ │ (Code Edit) │ │ (State Mgmt) │ │ Canvas │ │
|
||||
│ └────────────────┘ └──────────────────┘ └─────────────┘ │
|
||||
│ │ │ │ │
|
||||
│ └───────────────────┴──────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌──────────────────────────────────────────────────────┐ │
|
||||
│ │ Wokwi Components Integration │ │
|
||||
│ │ (wokwi-elements + avr8js from local repos) │ │
|
||||
│ └──────────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────┬──────────────────────────────────┘
|
||||
│ HTTP (axios)
|
||||
▼
|
||||
┌─────────────────────────────────────────────────────────────┐
|
||||
│ BACKEND (FastAPI + Python) │
|
||||
│ http://localhost:8000 │
|
||||
│ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ POST /api/compile │ │
|
||||
│ │ - Receives Arduino code (.ino) │ │
|
||||
│ │ - Compiles with arduino-cli │ │
|
||||
│ │ - Returns .hex file │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
│ │ │
|
||||
│ ▼ │
|
||||
│ ┌─────────────────────────────────────────────────────┐ │
|
||||
│ │ Arduino CLI Service │ │
|
||||
│ │ (Invokes arduino-cli as subprocess) │ │
|
||||
│ └─────────────────────────────────────────────────────┘ │
|
||||
└──────────────────────────┬──────────────────────────────────┘
|
||||
│
|
||||
▼
|
||||
┌──────────────────────┐
|
||||
│ arduino-cli │
|
||||
│ (Local system) │
|
||||
└──────────────────────┘
|
||||
```
|
||||
|
||||
## Data Flow: Compilation and Simulation
|
||||
|
||||
### 1. Code Editing
|
||||
```
|
||||
User writes code
|
||||
↓
|
||||
Monaco Editor
|
||||
↓
|
||||
Zustand (useEditorStore)
|
||||
↓
|
||||
State: code
|
||||
```
|
||||
|
||||
### 2. Compilation
|
||||
```
|
||||
Click "Compile"
|
||||
↓
|
||||
EditorToolbar.tsx → compileCode()
|
||||
↓
|
||||
Axios POST → http://localhost:8000/api/compile
|
||||
↓
|
||||
Backend: ArduinoCLIService.compile()
|
||||
↓
|
||||
arduino-cli compile --fqbn arduino:avr:uno
|
||||
↓
|
||||
Generates .hex file in temp directory
|
||||
↓
|
||||
Backend reads .hex and returns content
|
||||
↓
|
||||
Frontend: useSimulatorStore.setCompiledHex()
|
||||
```
|
||||
|
||||
### 3. Simulation (Currently simplified)
|
||||
```
|
||||
Click "Run"
|
||||
↓
|
||||
useSimulatorStore.setRunning(true)
|
||||
↓
|
||||
SimulatorCanvas: useEffect detects running=true
|
||||
↓
|
||||
setInterval every 1000ms
|
||||
↓
|
||||
updateComponentState('led-builtin', !state)
|
||||
↓
|
||||
wokwi-led component updates visually
|
||||
```
|
||||
|
||||
### 4. Real Simulation (Coming with avr8js)
|
||||
```
|
||||
Compiled .hex file
|
||||
↓
|
||||
AVRSimulator.loadHex(hex)
|
||||
↓
|
||||
hexParser → Uint16Array (program memory)
|
||||
↓
|
||||
CPU = new CPU(program)
|
||||
↓
|
||||
Click "Run" → AVRSimulator.start()
|
||||
↓
|
||||
requestAnimationFrame loop
|
||||
↓
|
||||
CPU.tick() × 267,000 cycles/frame
|
||||
↓
|
||||
Writes to PORTB/PORTC/PORTD
|
||||
↓
|
||||
Write hooks → PinManager.updatePort()
|
||||
↓
|
||||
PinManager notifies callbacks
|
||||
↓
|
||||
Components update visual state
|
||||
```
|
||||
|
||||
## Key Components
|
||||
|
||||
### Frontend
|
||||
|
||||
#### 1. Stores (Zustand)
|
||||
- **[useEditorStore.ts](frontend/src/store/useEditorStore.ts)**
|
||||
- `code`: Current source code
|
||||
- `theme`: Editor theme (dark/light)
|
||||
- `setCode()`: Update code
|
||||
|
||||
- **[useSimulatorStore.ts](frontend/src/store/useSimulatorStore.ts)**
|
||||
- `running`: Simulation state
|
||||
- `compiledHex`: Compiled hex file
|
||||
- `components`: List of electronic components
|
||||
- `setCompiledHex()`: Save hex
|
||||
- `updateComponentState()`: Update LED/component
|
||||
|
||||
#### 2. UI Components
|
||||
- **[CodeEditor.tsx](frontend/src/components/editor/CodeEditor.tsx)**
|
||||
- Monaco Editor wrapper
|
||||
- C++ syntax highlighting
|
||||
- Auto-completion
|
||||
|
||||
- **[EditorToolbar.tsx](frontend/src/components/editor/EditorToolbar.tsx)**
|
||||
- Buttons: Compile, Run, Stop
|
||||
- Compilation state handling
|
||||
- Error/success messages
|
||||
|
||||
- **[SimulatorCanvas.tsx](frontend/src/components/simulator/SimulatorCanvas.tsx)**
|
||||
- Renders Arduino Uno
|
||||
- Renders components (LEDs)
|
||||
- Simulation loop
|
||||
|
||||
#### 3. Wokwi Component Wrappers
|
||||
- **[LED.tsx](frontend/src/components/components-wokwi/LED.tsx)**
|
||||
- React wrapper for `<wokwi-led>`
|
||||
- Props: color, value, x, y
|
||||
|
||||
- **[ArduinoUno.tsx](frontend/src/components/components-wokwi/ArduinoUno.tsx)**
|
||||
- React wrapper for `<wokwi-arduino-uno>`
|
||||
- Internal LED control (pin 13)
|
||||
|
||||
- **[Resistor.tsx](frontend/src/components/components-wokwi/Resistor.tsx)**
|
||||
- React wrapper for `<wokwi-resistor>`
|
||||
- Props: value (ohms)
|
||||
|
||||
- **[Pushbutton.tsx](frontend/src/components/components-wokwi/Pushbutton.tsx)**
|
||||
- React wrapper for `<wokwi-pushbutton>`
|
||||
- Events: onPress, onRelease
|
||||
|
||||
### Backend
|
||||
|
||||
#### 1. API Routes
|
||||
- **[compile.py](backend/app/api/routes/compile.py)**
|
||||
- `POST /api/compile`: Compile code
|
||||
- `GET /api/compile/boards`: List boards
|
||||
|
||||
#### 2. Services
|
||||
- **[arduino_cli.py](backend/app/services/arduino_cli.py)**
|
||||
- `compile()`: Compile sketch with arduino-cli
|
||||
- `list_boards()`: Get available boards
|
||||
- Temporary directory management
|
||||
|
||||
### Wokwi Libraries (Cloned Locally)
|
||||
|
||||
#### 1. wokwi-elements
|
||||
- **Location**: `wokwi-libs/wokwi-elements/`
|
||||
- **Build**: `dist/esm/` and `dist/cjs/`
|
||||
- **Components**: 50+ electronic elements
|
||||
- **Technology**: Lit (Web Components)
|
||||
|
||||
#### 2. avr8js
|
||||
- **Location**: `wokwi-libs/avr8js/`
|
||||
- **Build**: `dist/esm/` and `dist/cjs/`
|
||||
- **Functionality**: Complete ATmega328p emulator
|
||||
- **Supports**: CPU, Timers, USART, GPIO, ADC, etc.
|
||||
|
||||
#### 3. rp2040js
|
||||
- **Location**: `wokwi-libs/rp2040js/`
|
||||
- **Future use**: Raspberry Pi Pico support
|
||||
|
||||
## Vite Integration
|
||||
|
||||
### Alias Configuration
|
||||
```typescript
|
||||
// vite.config.ts
|
||||
resolve: {
|
||||
alias: {
|
||||
'avr8js': path.resolve(__dirname, '../wokwi-libs/avr8js/dist/esm'),
|
||||
'@wokwi/elements': path.resolve(__dirname, '../wokwi-libs/wokwi-elements/dist/esm'),
|
||||
},
|
||||
}
|
||||
```
|
||||
|
||||
This allows:
|
||||
- Use local repos instead of npm
|
||||
- Easy updates with `git pull`
|
||||
- Modify source code if needed
|
||||
|
||||
## Technology Stack
|
||||
|
||||
### Frontend
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|-----------|
|
||||
| React | 19.2 | UI framework |
|
||||
| Vite | 7.3 | Build tool & dev server |
|
||||
| TypeScript | 5.9 | Static typing |
|
||||
| Monaco Editor | 4.7 | Code editor (VSCode) |
|
||||
| Zustand | 5.0 | State management |
|
||||
| Axios | 1.13 | HTTP client |
|
||||
| wokwi-elements | 1.9.2 | Electronic components |
|
||||
| avr8js | 0.21.0 | AVR8 emulator |
|
||||
|
||||
### Backend
|
||||
| Technology | Version | Purpose |
|
||||
|------------|---------|-----------|
|
||||
| Python | 3.12+ | Runtime |
|
||||
| FastAPI | 0.115 | Web framework |
|
||||
| Uvicorn | 0.32 | ASGI server |
|
||||
| SQLAlchemy | 2.0 | ORM (future) |
|
||||
| aiosqlite | 0.20 | Async DB (future) |
|
||||
|
||||
### External Tools
|
||||
| Tool | Purpose |
|
||||
|------|---------|
|
||||
| arduino-cli | Arduino compiler |
|
||||
| Git | Version control for Wokwi libs |
|
||||
|
||||
## Architecture Advantages
|
||||
|
||||
### ✅ Separation of Concerns
|
||||
- **Frontend**: UI, UX, visualization
|
||||
- **Backend**: Compilation, business logic
|
||||
- **Wokwi Libs**: Emulation and components (maintained by Wokwi)
|
||||
|
||||
### ✅ Wokwi Compatibility
|
||||
- Official repositories = same functionality
|
||||
- Automatic updates with `git pull`
|
||||
- New components available immediately
|
||||
|
||||
### ✅ Scalability
|
||||
- Frontend can easily add more components
|
||||
- Backend can add more endpoints (projects, sensors)
|
||||
- Wokwi libs update independently
|
||||
|
||||
### ✅ Local Development
|
||||
- No internet required to work
|
||||
- Local compilation with arduino-cli
|
||||
- Local database (SQLite)
|
||||
|
||||
## Upcoming Improvements
|
||||
|
||||
### Phase 2: Real Emulation (avr8js)
|
||||
```
|
||||
[ ] Implement AVRSimulator.ts
|
||||
[ ] Intel HEX file parser
|
||||
[ ] PinManager with write hooks
|
||||
[ ] Integrate CPU execution loop
|
||||
[ ] Map Arduino pins to components
|
||||
```
|
||||
|
||||
### Phase 3: More Components
|
||||
```
|
||||
[ ] Integrate more wokwi-elements
|
||||
[ ] Buttons, potentiometers
|
||||
[ ] Sensors (DHT22, HC-SR04)
|
||||
[ ] Displays (LCD, 7-segment)
|
||||
```
|
||||
|
||||
### Phase 4: Persistence
|
||||
```
|
||||
[ ] SQLite database
|
||||
[ ] SQLAlchemy models
|
||||
[ ] Project CRUD
|
||||
[ ] Save circuits as JSON
|
||||
```
|
||||
|
||||
### Phase 5: Advanced Features
|
||||
```
|
||||
[ ] Serial Monitor
|
||||
[ ] Visual wiring (drag & drop)
|
||||
[ ] Multiple boards (Mega, Nano, ESP32)
|
||||
[ ] Export to Wokwi.com
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Wokwi Elements Repo](https://github.com/wokwi/wokwi-elements)
|
||||
- [AVR8js Repo](https://github.com/wokwi/avr8js)
|
||||
- [Wokwi Simulator](https://wokwi.com)
|
||||
- [Arduino CLI](https://arduino.github.io/arduino-cli/)
|
||||
- [FastAPI Docs](https://fastapi.tiangolo.com/)
|
||||
- [Vite Docs](https://vitejs.dev/)
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"version": "1.0.0",
|
||||
"generatedAt": "2026-03-04T16:36:16.155Z",
|
||||
"generatedAt": "2026-03-04T21:29:42.875Z",
|
||||
"components": [
|
||||
{
|
||||
"id": "arduino-mega",
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { CPU, AVRTimer, timer0Config, timer1Config, timer2Config, AVRUSART, usart0Config, AVRIOPort, portBConfig, portCConfig, portDConfig, avrInstruction, PinState, AVRADC, adcConfig } from 'avr8js';
|
||||
import { CPU, AVRTimer, timer0Config, timer1Config, timer2Config, AVRUSART, usart0Config, AVRIOPort, portBConfig, portCConfig, portDConfig, avrInstruction, AVRADC, adcConfig } from 'avr8js';
|
||||
import { PinManager } from './PinManager';
|
||||
import { hexToUint8Array } from '../utils/hexParser';
|
||||
|
||||
|
|
@ -27,10 +27,8 @@ const PWM_PINS = [
|
|||
|
||||
export class AVRSimulator {
|
||||
private cpu: CPU | null = null;
|
||||
private timer0: AVRTimer | null = null;
|
||||
private timer1: AVRTimer | null = null;
|
||||
private timer2: AVRTimer | null = null;
|
||||
private usart: AVRUSART | null = null;
|
||||
/** Peripherals kept alive by reference so GC doesn't collect their CPU hooks */
|
||||
private peripherals: unknown[] = [];
|
||||
private portB: AVRIOPort | null = null;
|
||||
private portC: AVRIOPort | null = null;
|
||||
private portD: AVRIOPort | null = null;
|
||||
|
|
@ -73,11 +71,13 @@ export class AVRSimulator {
|
|||
// Initialize CPU (ATmega328p @ 16MHz)
|
||||
this.cpu = new CPU(this.program);
|
||||
|
||||
// Initialize peripherals
|
||||
this.timer0 = new AVRTimer(this.cpu, timer0Config);
|
||||
this.timer1 = new AVRTimer(this.cpu, timer1Config);
|
||||
this.timer2 = new AVRTimer(this.cpu, timer2Config);
|
||||
this.usart = new AVRUSART(this.cpu, usart0Config, 16000000); // 16MHz
|
||||
// Initialize peripherals (kept alive so their CPU hooks are not GC'd)
|
||||
this.peripherals = [
|
||||
new AVRTimer(this.cpu, timer0Config),
|
||||
new AVRTimer(this.cpu, timer1Config),
|
||||
new AVRTimer(this.cpu, timer2Config),
|
||||
new AVRUSART(this.cpu, usart0Config, 16000000),
|
||||
];
|
||||
|
||||
// Initialize ADC (analogRead support)
|
||||
this.adc = new AVRADC(this.cpu, adcConfig);
|
||||
|
|
@ -93,7 +93,7 @@ export class AVRSimulator {
|
|||
// Set up pin change hooks
|
||||
this.setupPinHooks();
|
||||
|
||||
console.log('AVR CPU initialized successfully (ADC + Timer1/Timer2 enabled)');
|
||||
console.log(`AVR CPU initialized (${this.peripherals.length} peripherals, ADC + Timer1/Timer2 enabled)`);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -225,10 +225,12 @@ export class AVRSimulator {
|
|||
console.log('Resetting AVR CPU...');
|
||||
|
||||
this.cpu = new CPU(this.program);
|
||||
this.timer0 = new AVRTimer(this.cpu, timer0Config);
|
||||
this.timer1 = new AVRTimer(this.cpu, timer1Config);
|
||||
this.timer2 = new AVRTimer(this.cpu, timer2Config);
|
||||
this.usart = new AVRUSART(this.cpu, usart0Config, 16000000);
|
||||
this.peripherals = [
|
||||
new AVRTimer(this.cpu, timer0Config),
|
||||
new AVRTimer(this.cpu, timer1Config),
|
||||
new AVRTimer(this.cpu, timer2Config),
|
||||
new AVRUSART(this.cpu, usart0Config, 16000000),
|
||||
];
|
||||
this.adc = new AVRADC(this.cpu, adcConfig);
|
||||
|
||||
this.portB = new AVRIOPort(this.cpu, portBConfig);
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
import { PartSimulationRegistry } from './PartSimulationRegistry';
|
||||
import type { AVRSimulator } from '../AVRSimulator';
|
||||
|
||||
/**
|
||||
* Basic Pushbutton implementation (full-size)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,104 @@
|
|||
# Generar Screenshots de Ejemplos
|
||||
|
||||
Debido a restricciones CORS del navegador, no podemos capturar el canvas automáticamente con `toDataURL()`. En su lugar, necesitamos screenshots manuales.
|
||||
|
||||
## Método Rápido: Captura de Pantalla
|
||||
|
||||
### 1. Preparar el Navegador
|
||||
|
||||
```bash
|
||||
cd frontend
|
||||
npm run dev
|
||||
```
|
||||
|
||||
Abre http://localhost:5173
|
||||
|
||||
### 2. Para Cada Ejemplo
|
||||
|
||||
1. Ve a http://localhost:5173/examples
|
||||
2. Haz click en un ejemplo (ej: "Blink LED")
|
||||
3. Espera a que se cargue en el editor
|
||||
4. Ajusta el zoom del canvas si es necesario para que el circuito se vea bien centrado
|
||||
|
||||
### 3. Capturar Solo el Canvas
|
||||
|
||||
**Windows (Win + Shift + S):**
|
||||
- Presiona `Win + Shift + S`
|
||||
- Selecciona el área del simulador (panel derecho)
|
||||
- La captura se guarda en el portapapeles
|
||||
|
||||
**Guardar la imagen:**
|
||||
1. Abre Paint o cualquier editor
|
||||
2. Pega (Ctrl + V)
|
||||
3. Guarda como PNG en `doc/examples/[nombre-ejemplo].png`
|
||||
|
||||
### 4. Nombres de Archivo
|
||||
|
||||
Usa el ID del ejemplo:
|
||||
|
||||
- `blink-led.png` - Solo Arduino
|
||||
- `traffic-light.png` - Arduino + 3 LEDs (rojo, amarillo, verde)
|
||||
- `button-control.png` - Arduino + botón + LED
|
||||
- `fade-led.png` - Arduino + LED azul
|
||||
- `serial-hello.png` - Solo Arduino
|
||||
- `rgb-led.png` - Arduino + LED RGB
|
||||
- `simon-says.png` - Arduino + 4 LEDs + 4 botones
|
||||
|
||||
### 5. Actualizar el Código
|
||||
|
||||
Una vez tengas las imágenes, edita `frontend/src/data/examples.ts`:
|
||||
|
||||
```typescript
|
||||
{
|
||||
id: 'blink-led',
|
||||
title: 'Blink LED',
|
||||
description: 'Classic Arduino blink example - toggle an LED on and off',
|
||||
category: 'basics',
|
||||
difficulty: 'beginner',
|
||||
thumbnail: '/doc/examples/blink-led.png', // ← Agregar esta línea
|
||||
code: `...`,
|
||||
// ... resto
|
||||
}
|
||||
```
|
||||
|
||||
## Alternativa: Script Browser DevTools
|
||||
|
||||
Si prefieres algo más automatizado:
|
||||
|
||||
1. Abre el ejemplo en http://localhost:5173
|
||||
2. Abre DevTools (F12)
|
||||
3. Ve a la consola
|
||||
4. Ejecuta:
|
||||
|
||||
```javascript
|
||||
// Tomar screenshot del canvas del simulador
|
||||
const simulatorPanel = document.querySelector('.simulator-panel');
|
||||
const rect = simulatorPanel.getBoundingClientRect();
|
||||
|
||||
// Usar la API de screenshot del navegador (Chrome/Edge)
|
||||
chrome.tabs.captureVisibleTab(null, {format: 'png'}, function(dataUrl) {
|
||||
const link = document.createElement('a');
|
||||
link.download = 'example.png';
|
||||
link.href = dataUrl;
|
||||
link.click();
|
||||
});
|
||||
```
|
||||
|
||||
**Nota:** Este método requiere una extensión del navegador.
|
||||
|
||||
## Dimensiones Recomendadas
|
||||
|
||||
- **Ancho**: 600-800px
|
||||
- **Alto**: 400-600px
|
||||
- **Formato**: PNG
|
||||
- **Fondo**: El mismo del canvas (#1e1e1e)
|
||||
|
||||
## Resultado Esperado
|
||||
|
||||
Cada tarjeta en `/examples` mostrará la screenshot real del circuito en lugar del placeholder genérico.
|
||||
|
||||
## Limpieza (Opcional)
|
||||
|
||||
Una vez tengas las screenshots, puedes eliminar:
|
||||
- `frontend/src/utils/captureCanvasPreview.ts` (ya no se necesita)
|
||||
- `frontend/src/utils/generateExamplePreview.tsx` (SVG antiguo)
|
||||
Loading…
Reference in New Issue