Merge pull request #190 from davidmonterocrespo24/pi-phase-3.3-armhf
feat(pi): Phase 3.3 — Pi Zero / Pi 1 / Pi 2 armhf simulators
This commit is contained in:
commit
6a1e506db6
|
|
@ -33,6 +33,37 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"raspberry-pi-armhf": {
|
||||
"description": "Raspberry Pi Zero / 1 / 2 simulator on QEMU -M virt + cortex-a7. Velxio-built armhf kernel (Debian armmp) + initramfs (bundled ext4 + jbd2 + mbcache + crc16 + crc32c_generic + virtio_blk + virtio_mmio) + Alpine-based armhf rootfs. arm-32 virt PCI is broken (missing reg DT prop) so the QEMU command uses the mmio virtio transport; Pi Zero / Pi 1 share this image set with Pi 2 because the real ARMv6 silicon they have isn't supported by any QEMU-virt-capable upstream kernel.",
|
||||
"images": [
|
||||
{
|
||||
"name": "velxio-kernel-armhf",
|
||||
"asset_id": "velxio-kernel-armhf",
|
||||
"sha256": "9d7377c33b9a5631e99ab109c8d3d9d89f99331b53eb8cc755cd76e775c9d0d5",
|
||||
"size_bytes": 6033920,
|
||||
"version": "2026.05+v6.12.88-armmp+ext4mods"
|
||||
},
|
||||
{
|
||||
"name": "velxio-initramfs-armhf.cpio.gz",
|
||||
"asset_id": "velxio-initramfs-armhf",
|
||||
"sha256": "611eb3d219cb5d71a534d417dea564ed6eadbd2d1b40e33d28bb4a5a5f5829f5",
|
||||
"size_bytes": 1390924,
|
||||
"version": "2026.05+ext4mods"
|
||||
},
|
||||
{
|
||||
"name": "velxio-pi-rootfs-armhf.ext4",
|
||||
"asset_id": "velxio-pi-rootfs-armhf-zst",
|
||||
"sha256": "5f2eafc0e76acc9ecc79da42313c1ffaacd577f42df5a58934d97ea167fab4ee",
|
||||
"size_bytes": 629145600,
|
||||
"version": "2026.05+phase2-shims-armhf",
|
||||
"compressed": {
|
||||
"encoding": "zstd",
|
||||
"sha256": "ce9037b371aa1e847f2ce16bf6b0067c4ef51d48b66fe4c2d79941cbdff37b30",
|
||||
"size_bytes": 23322299
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"raspberry-pi-3": {
|
||||
"description": "[DEPRECATED \u2014 kept for one release to ease rollback] Original raspi3b setup. Replaced by 'raspberry-pi-3-virt' (see above). qemu_manager.py no longer references this entry; do not add new clients here.",
|
||||
"deprecated": true,
|
||||
|
|
|
|||
|
|
@ -66,6 +66,7 @@ PI_CONFIGS: dict[str, dict] = {
|
|||
'kernel': 'velxio-kernel-arm64',
|
||||
'initramfs': 'velxio-initramfs-arm64.cpio.gz',
|
||||
'rootfs': 'velxio-pi-rootfs-arm64.ext4',
|
||||
'bus': 'pci',
|
||||
},
|
||||
'raspberry-pi-4': {
|
||||
'qemu': 'qemu-system-aarch64',
|
||||
|
|
@ -76,6 +77,7 @@ PI_CONFIGS: dict[str, dict] = {
|
|||
'kernel': 'velxio-kernel-arm64',
|
||||
'initramfs': 'velxio-initramfs-arm64.cpio.gz',
|
||||
'rootfs': 'velxio-pi-rootfs-arm64.ext4',
|
||||
'bus': 'pci',
|
||||
},
|
||||
'raspberry-pi-5': {
|
||||
'qemu': 'qemu-system-aarch64',
|
||||
|
|
@ -86,8 +88,60 @@ PI_CONFIGS: dict[str, dict] = {
|
|||
'kernel': 'velxio-kernel-arm64',
|
||||
'initramfs': 'velxio-initramfs-arm64.cpio.gz',
|
||||
'rootfs': 'velxio-pi-rootfs-arm64.ext4',
|
||||
'bus': 'pci',
|
||||
},
|
||||
# ── armhf (32-bit ARM, Pi Zero / 1 / 2) ─────────────────────────────
|
||||
# QEMU virt for arm-32 does not probe PCI cleanly (the pci-host-generic
|
||||
# node is missing the "reg" DT property and probe fails -75), so we
|
||||
# use the MMIO virtio transport instead: -device virtio-blk-device /
|
||||
# virtio-serial-device. The kernel here is linux-image-armmp (Debian
|
||||
# generic ARMv7) which ships ext4 + virtio_mmio as MODULES — the
|
||||
# armhf initramfs bundles ext4.ko + jbd2.ko + mbcache.ko + crc16.ko +
|
||||
# crc32c_generic.ko and insmods them in dep order before /dev/vda
|
||||
# mount. Pi Zero / Pi 1 are ARMv6 which the Debian armmp kernel does
|
||||
# not target; Phase 3.3b tracks sourcing an ARMv6 kernel for those.
|
||||
'raspberry-pi-2': {
|
||||
'qemu': 'qemu-system-arm',
|
||||
'cpu': 'cortex-a7',
|
||||
'smp': '4',
|
||||
'memory': '1G',
|
||||
'image_set': 'raspberry-pi-armhf',
|
||||
'kernel': 'velxio-kernel-armhf',
|
||||
'initramfs': 'velxio-initramfs-armhf.cpio.gz',
|
||||
'rootfs': 'velxio-pi-rootfs-armhf.ext4',
|
||||
'bus': 'mmio',
|
||||
},
|
||||
# Pi 1 / Pi Zero are ARMv6 on real silicon (arm1176, BCM2835). Debian
|
||||
# dropped the ARMv6 kernel and Alpine's linux-rpi kernel is wired for
|
||||
# the actual BCM2835 hardware (no virtio_blk, no ext4 module) so it
|
||||
# cannot boot on QEMU virt. We follow the project's "looks-like-a-Pi
|
||||
# but isn't-exactly-a-Pi" architecture rule: serve them off the same
|
||||
# ARMv7 armmp kernel as Pi 2, with the smaller RAM / SMP profile of
|
||||
# the real boards. User code that uses RPi.GPIO / smbus2 / spidev
|
||||
# behaves identically. We do not advertise ARMv6 anywhere in the
|
||||
# rootfs (no /proc/cpuinfo lying).
|
||||
'raspberry-pi-1': {
|
||||
'qemu': 'qemu-system-arm',
|
||||
'cpu': 'cortex-a7',
|
||||
'smp': '1',
|
||||
'memory': '512M',
|
||||
'image_set': 'raspberry-pi-armhf',
|
||||
'kernel': 'velxio-kernel-armhf',
|
||||
'initramfs': 'velxio-initramfs-armhf.cpio.gz',
|
||||
'rootfs': 'velxio-pi-rootfs-armhf.ext4',
|
||||
'bus': 'mmio',
|
||||
},
|
||||
'raspberry-pi-zero': {
|
||||
'qemu': 'qemu-system-arm',
|
||||
'cpu': 'cortex-a7',
|
||||
'smp': '1',
|
||||
'memory': '512M',
|
||||
'image_set': 'raspberry-pi-armhf',
|
||||
'kernel': 'velxio-kernel-armhf',
|
||||
'initramfs': 'velxio-initramfs-armhf.cpio.gz',
|
||||
'rootfs': 'velxio-pi-rootfs-armhf.ext4',
|
||||
'bus': 'mmio',
|
||||
},
|
||||
# Pi Zero/1/2 require armhf — added in Phase 3.3.
|
||||
}
|
||||
|
||||
# Default board if the client doesn't specify one. Kept for clients
|
||||
|
|
@ -315,6 +369,20 @@ class QemuManager:
|
|||
#
|
||||
# Why no -dtb: virt machine generates its own DTB on the fly
|
||||
# from the runtime device list, so we don't ship one.
|
||||
# Virtio device suffix depends on the bus. arm64 virt has
|
||||
# working PCI so we use the -pci variants there. arm-32 virt's
|
||||
# pci-host-generic node has a broken DT (missing "reg" property)
|
||||
# so the bus never enumerates — we have to fall back to the
|
||||
# mmio variants. The same device names work for both blk and
|
||||
# serial; only the suffix changes.
|
||||
bus = cfg.get('bus', 'pci')
|
||||
if bus == 'mmio':
|
||||
blk_dev = 'virtio-blk-device,drive=rootfs'
|
||||
serial_dev = 'virtio-serial-device,id=virtio-serial0'
|
||||
else:
|
||||
blk_dev = 'virtio-blk-pci,drive=rootfs'
|
||||
serial_dev = 'virtio-serial-pci,id=virtio-serial0'
|
||||
|
||||
cmd = [
|
||||
cfg['qemu'],
|
||||
'-M', 'virt',
|
||||
|
|
@ -323,12 +391,12 @@ class QemuManager:
|
|||
'-m', cfg['memory'],
|
||||
'-kernel', str(kernel_path),
|
||||
'-initrd', str(initramfs_path),
|
||||
# Root filesystem via virtio-blk over PCI. virt machine
|
||||
# uses PCI as the primary virtio transport, so we use
|
||||
# `virtio-blk-pci` (not `virtio-blk-device`, which is for
|
||||
# mmio and silently leaves /dev/vda unregistered).
|
||||
# Root filesystem via virtio-blk. arm64 uses the pci
|
||||
# transport (works out of the box on virt-aarch64); armhf
|
||||
# uses the mmio transport because PCI is broken on
|
||||
# virt-arm32.
|
||||
'-drive', f'if=none,file={inst.overlay_path},format=qcow2,id=rootfs',
|
||||
'-device', 'virtio-blk-pci,drive=rootfs',
|
||||
'-device', blk_dev,
|
||||
# No default network / display / monitor / serial — we add
|
||||
# exactly the two chardev-backed virtio-serial ports we
|
||||
# need. -nographic auto-binds -serial mon:stdio which
|
||||
|
|
@ -342,7 +410,7 @@ class QemuManager:
|
|||
# port (replaces the old ttyAMA0 path).
|
||||
'-chardev', f'socket,id=cons,host=127.0.0.1,port={inst.serial_port},'
|
||||
f'server=on,wait=off',
|
||||
'-device', 'virtio-serial-pci,id=virtio-serial0',
|
||||
'-device', serial_dev,
|
||||
'-device', 'virtconsole,chardev=cons',
|
||||
# Protocol channel: pipe (FIFO pair) instead of a socket
|
||||
# chardev. virtserialport on socket chardev has a known
|
||||
|
|
|
|||
|
|
@ -41,8 +41,11 @@ const ALL_EXAMPLES: ExampleProject[] = [
|
|||
* coverage gap visible at code-review time.
|
||||
*/
|
||||
const ACCEPTED_UNCOVERED: ReadonlySet<BoardKind> = new Set([
|
||||
// Pi 3/4/5 run on the backend (QEMU ARM64) — no in-browser canvas
|
||||
// example because they boot a full Linux image.
|
||||
// Pi Zero / 1 / 2 / 3 / 4 / 5 run on the backend (QEMU ARM/ARM64) — no
|
||||
// in-browser canvas example because they boot a full Linux image.
|
||||
'raspberry-pi-zero',
|
||||
'raspberry-pi-1',
|
||||
'raspberry-pi-2',
|
||||
'raspberry-pi-3',
|
||||
'raspberry-pi-4',
|
||||
'raspberry-pi-5',
|
||||
|
|
|
|||
|
|
@ -67,6 +67,45 @@ export class ComponentRegistry {
|
|||
// Inject Raspberry Pi 3 / 4 / 5 metadata. All three share the
|
||||
// same 40-pin GPIO header; the simulator backend picks a
|
||||
// different QEMU CPU model per board (Cortex-A53/A72/A76).
|
||||
data.components.push({
|
||||
id: 'raspberry-pi-zero',
|
||||
tagName: 'velxio-raspberry-pi-3', // reuse 40-pin board art
|
||||
name: 'Raspberry Pi Zero',
|
||||
category: 'boards',
|
||||
description: 'Raspberry Pi Zero with 40-pin GPIO. QEMU virt + Cortex-A7 (armhf) backend; presents the Pi Zero memory/SMP profile (1 core, 512 MB).',
|
||||
thumbnail:
|
||||
'<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg"><rect width="64" height="64" fill="#7E2553" rx="4"/><text x="50%" y="50%" text-anchor="middle" dy=".3em" font-size="9" fill="#FFF">RPi0</text></svg>',
|
||||
properties: [],
|
||||
defaultValues: {},
|
||||
pinCount: 40,
|
||||
tags: ['raspberry', 'pi', 'pi-zero', 'board', 'qemu', 'linux'],
|
||||
});
|
||||
data.components.push({
|
||||
id: 'raspberry-pi-1',
|
||||
tagName: 'velxio-raspberry-pi-3', // reuse 40-pin board art
|
||||
name: 'Raspberry Pi 1',
|
||||
category: 'boards',
|
||||
description: 'Raspberry Pi 1 Model B+ with 40-pin GPIO. QEMU virt + Cortex-A7 (armhf) backend; 1 core / 512 MB profile.',
|
||||
thumbnail:
|
||||
'<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg"><rect width="64" height="64" fill="#A8324B" rx="4"/><text x="50%" y="50%" text-anchor="middle" dy=".3em" font-size="9" fill="#FFF">RPi1</text></svg>',
|
||||
properties: [],
|
||||
defaultValues: {},
|
||||
pinCount: 40,
|
||||
tags: ['raspberry', 'pi', 'rp1', 'board', 'qemu', 'linux'],
|
||||
});
|
||||
data.components.push({
|
||||
id: 'raspberry-pi-2',
|
||||
tagName: 'velxio-raspberry-pi-3',
|
||||
name: 'Raspberry Pi 2',
|
||||
category: 'boards',
|
||||
description: 'Raspberry Pi 2 Model B with 40-pin GPIO. QEMU virt + Cortex-A7 (armhf) backend; 4 cores / 1 GB.',
|
||||
thumbnail:
|
||||
'<svg width="64" height="64" xmlns="http://www.w3.org/2000/svg"><rect width="64" height="64" fill="#C73E5A" rx="4"/><text x="50%" y="50%" text-anchor="middle" dy=".3em" font-size="9" fill="#FFF">RPi2</text></svg>',
|
||||
properties: [],
|
||||
defaultValues: {},
|
||||
pinCount: 40,
|
||||
tags: ['raspberry', 'pi', 'rp2', 'board', 'qemu', 'linux'],
|
||||
});
|
||||
data.components.push({
|
||||
id: 'raspberry-pi-3',
|
||||
tagName: 'velxio-raspberry-pi-3',
|
||||
|
|
|
|||
|
|
@ -127,12 +127,9 @@ function isEsp32Bridge(boardKind: string): boolean {
|
|||
}
|
||||
|
||||
function isPi3Bridge(boardKind: string): boolean {
|
||||
// Pi 3 / 4 / 5 all use the same backend bridge (QEMU virt + virtio-serial).
|
||||
return (
|
||||
boardKind === 'raspberry-pi-3' ||
|
||||
boardKind === 'raspberry-pi-4' ||
|
||||
boardKind === 'raspberry-pi-5'
|
||||
);
|
||||
// Pi Zero / 1 / 2 / 3 / 4 / 5 all use the same backend bridge
|
||||
// (QEMU virt + virtio-serial). Exclude raspberry-pi-pico (RP2040).
|
||||
return boardKind.startsWith('raspberry-pi-') && boardKind !== 'raspberry-pi-pico';
|
||||
}
|
||||
|
||||
/** Resolve `(componentId, pinName)` to a `(boardId, pinNumber)` pair. */
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ import type { I2CDevice } from '../simulation/I2CBusManager';
|
|||
import type { RP2040I2CDevice } from '../simulation/RP2040Simulator';
|
||||
import type { Wire, WireInProgress, WireEndpoint } from '../types/wire';
|
||||
import type { BoardKind, BoardInstance, LanguageMode } from '../types/board';
|
||||
import { BOARD_SUPPORTS_MICROPYTHON } from '../types/board';
|
||||
import { BOARD_SUPPORTS_MICROPYTHON, isPiBoardKind } from '../types/board';
|
||||
import { calculatePinPosition } from '../utils/pinPositionCalculator';
|
||||
import { useOscilloscopeStore } from './useOscilloscopeStore';
|
||||
import { RaspberryPi3Bridge } from '../simulation/RaspberryPi3Bridge';
|
||||
|
|
@ -954,11 +954,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
|
||||
const serialCallback = (ch: string) => appendSerial(id, ch);
|
||||
|
||||
if (
|
||||
boardKind === 'raspberry-pi-3' ||
|
||||
boardKind === 'raspberry-pi-4' ||
|
||||
boardKind === 'raspberry-pi-5'
|
||||
) {
|
||||
if (isPiBoardKind(boardKind)) {
|
||||
const bridge = new RaspberryPi3Bridge(id, boardKind);
|
||||
bridge.onSerialData = (ch: string) => {
|
||||
serialCallback(ch);
|
||||
|
|
@ -1084,7 +1080,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
// Create the editor file group for this board
|
||||
useEditorStore.getState().createFileGroup(`group-${id}`);
|
||||
// Init VFS for Raspberry Pi 3 boards
|
||||
if (boardKind === 'raspberry-pi-3') {
|
||||
if (isPiBoardKind(boardKind)) {
|
||||
useVfsStore.getState().initBoardVfs(id);
|
||||
}
|
||||
// ── Interconnect: register the board and rebuild routes ──────────
|
||||
|
|
@ -1200,7 +1196,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
set({
|
||||
activeBoardId: boardId,
|
||||
// Sync legacy flat fields to this board's values
|
||||
boardType: (board.boardKind === 'raspberry-pi-3'
|
||||
boardType: (isPiBoardKind(board.boardKind)
|
||||
? 'arduino-uno'
|
||||
: board.boardKind) as BoardType,
|
||||
boardPosition: { x: board.x, y: board.y },
|
||||
|
|
@ -1247,7 +1243,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
}
|
||||
} else {
|
||||
const sim = getBoardSimulator(boardId);
|
||||
if (sim && board.boardKind !== 'raspberry-pi-3') {
|
||||
if (sim && !isPiBoardKind(board.boardKind)) {
|
||||
try {
|
||||
if (sim instanceof AVRSimulator) {
|
||||
sim.loadHex(program);
|
||||
|
|
@ -1369,7 +1365,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
const board = get().boards.find((b) => b.id === boardId);
|
||||
if (!board) return;
|
||||
|
||||
if (board.boardKind === 'raspberry-pi-3') {
|
||||
if (isPiBoardKind(board.boardKind)) {
|
||||
getBoardBridge(boardId)?.connect();
|
||||
} else if (isEsp32Kind(board.boardKind)) {
|
||||
// Pre-register sensors connected to this board so the QEMU worker
|
||||
|
|
@ -1532,7 +1528,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
const board = get().boards.find((b) => b.id === boardId);
|
||||
if (!board) return;
|
||||
|
||||
if (board.boardKind === 'raspberry-pi-3') {
|
||||
if (isPiBoardKind(board.boardKind)) {
|
||||
getBoardBridge(boardId)?.disconnect();
|
||||
} else if (isEsp32Kind(board.boardKind)) {
|
||||
getEsp32Bridge(boardId)?.disconnect();
|
||||
|
|
@ -1558,7 +1554,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
esp32Bridge.disconnect();
|
||||
setTimeout(() => esp32Bridge.connect(), 500);
|
||||
}
|
||||
} else if (board.boardKind !== 'raspberry-pi-3') {
|
||||
} else if (!isPiBoardKind(board.boardKind)) {
|
||||
const sim = getBoardSimulator(boardId);
|
||||
if (sim) {
|
||||
sim.reset();
|
||||
|
|
@ -2395,7 +2391,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
const board = get().boards.find((b) => b.id === boardId);
|
||||
if (!board) return;
|
||||
|
||||
if (board.boardKind === 'raspberry-pi-3') {
|
||||
if (isPiBoardKind(board.boardKind)) {
|
||||
const bridge = getBoardBridge(boardId);
|
||||
if (bridge) {
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
|
|
@ -2424,7 +2420,7 @@ export const useSimulatorStore = create<SimulatorState>((set, get) => {
|
|||
serialWriteToBoard: (boardId: string, text: string) => {
|
||||
const board = get().boards.find((b) => b.id === boardId);
|
||||
if (!board) return;
|
||||
if (board.boardKind === 'raspberry-pi-3') {
|
||||
if (isPiBoardKind(board.boardKind)) {
|
||||
const bridge = getBoardBridge(boardId);
|
||||
if (bridge) {
|
||||
for (let i = 0; i < text.length; i++) {
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ export type BoardKind =
|
|||
| 'arduino-mega'
|
||||
| 'raspberry-pi-pico' // RP2040, browser emulation
|
||||
| 'pi-pico-w' // RP2040 + WiFi, browser emulation (WiFi ignored)
|
||||
| 'raspberry-pi-zero' // QEMU virt + Cortex-A7 (armhf), backend — looks-like Pi Zero
|
||||
| 'raspberry-pi-1' // QEMU virt + Cortex-A7 (armhf), backend — looks-like Pi 1
|
||||
| 'raspberry-pi-2' // QEMU virt + Cortex-A7 (armhf), backend
|
||||
| 'raspberry-pi-3' // QEMU virt + Cortex-A53, backend
|
||||
| 'raspberry-pi-4' // QEMU virt + Cortex-A72, backend
|
||||
| 'raspberry-pi-5' // QEMU virt + Cortex-A76, backend
|
||||
|
|
@ -21,6 +24,13 @@ export type BoardKind =
|
|||
|
||||
export type LanguageMode = 'arduino' | 'micropython';
|
||||
|
||||
/** True for every Raspberry Pi backed by the QEMU bridge (Zero, 1, 2, 3, 4, 5).
|
||||
* Excludes the Pico boards (RP2040, browser emulation). */
|
||||
export function isPiBoardKind(kind: BoardKind | string): boolean {
|
||||
return typeof kind === 'string' && kind.startsWith('raspberry-pi-')
|
||||
&& kind !== 'raspberry-pi-pico';
|
||||
}
|
||||
|
||||
export const BOARD_SUPPORTS_MICROPYTHON = new Set<BoardKind>([
|
||||
'raspberry-pi-pico',
|
||||
'pi-pico-w',
|
||||
|
|
@ -72,6 +82,9 @@ export const BOARD_KIND_LABELS: Record<BoardKind, string> = {
|
|||
'arduino-mega': 'Arduino Mega 2560',
|
||||
'raspberry-pi-pico': 'Raspberry Pi Pico',
|
||||
'pi-pico-w': 'Raspberry Pi Pico W',
|
||||
'raspberry-pi-zero': 'Raspberry Pi Zero',
|
||||
'raspberry-pi-1': 'Raspberry Pi 1B+',
|
||||
'raspberry-pi-2': 'Raspberry Pi 2B',
|
||||
'raspberry-pi-3': 'Raspberry Pi 3B',
|
||||
'raspberry-pi-4': 'Raspberry Pi 4B',
|
||||
'raspberry-pi-5': 'Raspberry Pi 5',
|
||||
|
|
@ -94,6 +107,9 @@ export const BOARD_KIND_FQBN: Record<BoardKind, string | null> = {
|
|||
'arduino-mega': 'arduino:avr:mega',
|
||||
'raspberry-pi-pico': 'rp2040:rp2040:rpipico',
|
||||
'pi-pico-w': 'rp2040:rp2040:rpipicow',
|
||||
'raspberry-pi-zero': null,
|
||||
'raspberry-pi-1': null,
|
||||
'raspberry-pi-2': null,
|
||||
'raspberry-pi-3': null,
|
||||
'raspberry-pi-4': null,
|
||||
'raspberry-pi-5': null,
|
||||
|
|
|
|||
|
|
@ -144,15 +144,8 @@ function tableFor(boardKind: BoardKind | string): RoleTable | null {
|
|||
if (boardKind === 'raspberry-pi-pico' || boardKind === 'pi-pico-w') return RP2040_DEFAULT;
|
||||
if (boardKind === 'esp32-c3' || (boardKind as string).startsWith('esp32-c3')) return ESP32_C3_DEFAULT;
|
||||
if (boardKind === 'esp32' || (boardKind as string).startsWith('esp32')) return ESP32_DEFAULT;
|
||||
// Pi 3/4/5 all share the same 40-pin GPIO header → same BCM table.
|
||||
if (
|
||||
boardKind === 'raspberry-pi-3' ||
|
||||
boardKind === 'raspberry-pi-4' ||
|
||||
boardKind === 'raspberry-pi-5' ||
|
||||
(boardKind as string).startsWith('raspberry-pi-3') ||
|
||||
(boardKind as string).startsWith('raspberry-pi-4') ||
|
||||
(boardKind as string).startsWith('raspberry-pi-5')
|
||||
)
|
||||
// Pi Zero/1/2/3/4/5 all share the same 40-pin GPIO header → same BCM table.
|
||||
if ((boardKind as string).startsWith('raspberry-pi-'))
|
||||
return PI3_BCM;
|
||||
return ARDUINO_NANO; // default fallback: treat unknown as arduino-uno-like
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import type { ExampleProject } from '../data/examples';
|
||||
import type { BoardKind } from '../types/board';
|
||||
import { isPiBoardKind } from '../types/board';
|
||||
import { useEditorStore } from '../store/useEditorStore';
|
||||
import { useSimulatorStore, DEFAULT_BOARD_POSITION } from '../store/useSimulatorStore';
|
||||
import { useElectricalStore } from '../store/useElectricalStore';
|
||||
|
|
@ -129,12 +130,12 @@ export async function loadExample(
|
|||
// Arduino-style boards (AVR, RP2040, ESP32, …) all need the `.ino`
|
||||
// extension so arduino-cli auto-includes <Arduino.h>. Only the Pi 3B
|
||||
// uses a different toolchain (Python via VFS or g++ for `.cpp`).
|
||||
const filename = (eb.boardKind === 'raspberry-pi-3' || eb.boardKind === 'raspberry-pi-4' || eb.boardKind === 'raspberry-pi-5') ? 'main.cpp' : 'sketch.ino';
|
||||
const filename = isPiBoardKind(eb.boardKind) ? 'main.cpp' : 'sketch.ino';
|
||||
useEditorStore.getState().setActiveGroup(board.activeFileGroupId);
|
||||
useEditorStore.getState().loadFiles([{ name: filename, content: eb.code }]);
|
||||
}
|
||||
|
||||
if (eb.vfsFiles && (eb.boardKind === 'raspberry-pi-3' || eb.boardKind === 'raspberry-pi-4' || eb.boardKind === 'raspberry-pi-5')) {
|
||||
if (eb.vfsFiles && isPiBoardKind(eb.boardKind)) {
|
||||
const vfsState = useVfsStore.getState();
|
||||
const tree = vfsState.getTree(boardId);
|
||||
for (const [nodeId, node] of Object.entries(tree)) {
|
||||
|
|
@ -147,7 +148,7 @@ export async function loadExample(
|
|||
|
||||
const firstArduinoIdx = example.boards.findIndex(
|
||||
(eb) =>
|
||||
eb.boardKind !== 'raspberry-pi-3' && eb.boardKind !== 'raspberry-pi-4' && eb.boardKind !== 'raspberry-pi-5' &&
|
||||
!isPiBoardKind(eb.boardKind) &&
|
||||
eb.boardKind !== 'esp32' &&
|
||||
eb.boardKind !== 'esp32-s3' &&
|
||||
eb.boardKind !== 'esp32-c3',
|
||||
|
|
@ -242,7 +243,7 @@ export async function loadExample(
|
|||
// appear blank. (Regression test: load-example-transitions.test.ts.)
|
||||
const editorStore = useEditorStore.getState();
|
||||
editorStore.setActiveGroup(liveBoard.activeFileGroupId);
|
||||
const filename = (liveBoard.boardKind === 'raspberry-pi-3' || liveBoard.boardKind === 'raspberry-pi-4' || liveBoard.boardKind === 'raspberry-pi-5') ? 'main.cpp' : 'sketch.ino';
|
||||
const filename = isPiBoardKind(liveBoard.boardKind) ? 'main.cpp' : 'sketch.ino';
|
||||
editorStore.loadFiles([{ name: filename, content: example.code }]);
|
||||
} else {
|
||||
// Truly board-less: write the placeholder code to whatever the editor
|
||||
|
|
|
|||
Loading…
Reference in New Issue