velxio/frontend/src/simulation/PioPeripheral.ts

71 lines
3.1 KiB
TypeScript
Raw Normal View History

feat(opencore): extract Pico W WiFi to a pluggable PIO peripheral seam Move the CYW43439 (Pico W) WiFi emulation out of the open-source tree so it can ship as a paid feature in a private overlay. OSS keeps a plain Pico W (no WiFi); the overlay registers the cyw43 protocol + backend network stack at runtime via generic seams. Frontend: - Add simulation/PioPeripheral.ts: a generic "PIO bus peripheral" seam (feedWord / inDiscardableWriteData / resetFraming / hostWakeLevel / onHostWake / onSimulationStart). No factory is installed in OSS, so createPioPeripheral() returns null and a Pico W simulates as a plain Pico. - RP2040Simulator: keep the fragile PIO-FIFO plumbing (it must re-run after loadMicroPython swaps the chip) but drive it through PioPeripheral instead of an inlined cyw43 import (attachCyw43 -> attachPioPeripheral, etc.). - useSimulatorStore: generic attach/detach + setBoardWifiStatus; drop the cyw43 bridge map. - MicroPythonLoader: add registerFirmwareVariant() so an overlay can add the RPI_PICO_W build; remove the OSS pico-w config + bundled .uf2. - Delete simulation/cyw43/ (moved to the overlay). Backend: - core/hooks.py: add generic register_ws_sim_handler / dispatch_ws_sim_message and register_gateway_proxy / dispatch_gateway_proxy seams. - simulation.py: route start_picow / stop_picow / picow_packet_out through the ws_sim_handler hook (the overlay handles + gates them). - iot_gateway.py: resolve the Pico W gateway through the gateway_proxy hook. - Delete services/picow_net/ + picow_net_bridge.py (moved to the overlay). Tests: move the cyw43/picow suites to the overlay; update RP2040Simulator mock stubs to attachPioPeripheral.
2026-06-15 13:33:28 +07:00
/**
* PioPeripheral — generic extension seam for a bit-banged-SPI/PIO peripheral
* attached to an RP2040 board (e.g. a WiFi co-processor reached over gSPI).
*
* RP2040Simulator owns the fragile PIO-FIFO plumbing (the non-dropping TX
* queue, the on-demand RX-pull, the sm.restart framing reset, the GPIO24
* host-wake re-sync after loadMicroPython swaps the chip) and drives it
* through this interface. A peripheral supplies only the *protocol*: it
* observes each outbound 32-bit word and returns reply bytes the plumbing
* repacks into the RX FIFO.
*
* This is deliberately generic (no product-specific names): any private SPI
* peripheral can register a factory. In the open-source build no factory is
* installed, so `createPioPeripheral` returns null and a pi-pico-w board
* simulates as a plain Pico (no WiFi). The velxio.dev pro overlay registers
* a CYW43439 implementation, gated behind a paid plan.
*
* Mirrors the install-impl + safe-dispatch + has-check shape of the pro
* gates in `src/lib/proBoardGate.ts`.
*/
export interface PioPeripheral {
/** Process one 32-bit word the firmware bit-banged onto the bus. Returns
* zero or more reply byte-blobs to repack into the RX FIFO. */
feedWord(word: number): Uint8Array[];
/** True while the firmware is streaming bulk data the peripheral wants the
* plumbing to DISCARD (keep only a few words so the PIO TXSTALLs). */
inDiscardableWriteData(): boolean;
/** Reset framing at a transfer boundary (the PIO sm.restart). */
resetFraming(): void;
/** Current host-wake level to drive onto GPIO24 (active-high). */
hostWakeLevel(): boolean;
/** Register the callback the peripheral fires when host-wake changes. */
onHostWake(cb: (active: boolean) => void): void;
/** Optional: called when the board's simulation starts (with the sketch
* files), so the peripheral can e.g. detect WiFi usage and connect. */
onSimulationStart?(files: { content: string }[]): void;
/** Optional teardown when the peripheral is detached. */
detach?(): void;
}
/** Factory the overlay installs. Returns null for OSS / unsupported boards. */
export type PioPeripheralFactory =
(boardKind: string, boardId: string) => PioPeripheral | null;
let _factory: PioPeripheralFactory | null = null;
/** Install (or clear with null) the peripheral factory. Called once by the
* pro overlay's mountPro(); never called in OSS builds. */
export function installPioPeripheralFactory(factory: PioPeripheralFactory | null): void {
_factory = factory;
}
/** True if a factory has been installed (pro build). */
export function hasPioPeripheralFactory(): boolean {
return _factory !== null;
}
/** Create a peripheral for the given board, or null if none applies (OSS,
* unsupported board, or the factory declined — e.g. a free user). Never throws. */
export function createPioPeripheral(boardKind: string, boardId: string): PioPeripheral | null {
if (!_factory) return null;
try {
return _factory(boardKind, boardId);
} catch (e) {
// eslint-disable-next-line no-console
console.warn('[pio-peripheral] factory threw:', e);
return null;
}
}