stm32f4-emu 1.1.1 → 1.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +52 -26
- package/index.d.ts +289 -1
- package/index.mjs +8 -3
- package/mcp/server.mjs +23 -0
- package/package.json +8 -4
- package/site/app.js +637 -29
- package/site/boards.js +337 -0
- package/site/components.js +37 -0
- package/site/console.html +1098 -0
- package/site/emulator.d.ts +9 -0
- package/site/emulator.js +799 -75
- package/site/firmware.js +184 -8
- package/site/index.html +142 -696
- package/site/loaders.js +15 -10
- package/site/netsim.js +564 -6
- package/site/remote-emu.js +30 -1
- package/site/stm32f4.js +1265 -37
- package/site/vendor/stm32_periph_wasm.d.ts +829 -0
- package/site/vendor/stm32_periph_wasm.js +1438 -56
- package/site/vendor/stm32_periph_wasm_bg.wasm +0 -0
- package/site/vendor/stm32_periph_wasm_bg.wasm.d.ts +124 -0
- package/site/vendor/stm32f401.svd +24876 -0
- package/site/vendor/stm32f411.svd +24914 -0
- package/site/vendor/stm32f429.svd +62106 -0
- package/site/ws-bridge.mjs +35 -0
- package/tools/make_firmware.mjs +229 -48
package/README.md
CHANGED
|
@@ -6,6 +6,14 @@
|
|
|
6
6
|
[](https://github.com/danish9661/stm32F4-emulator/actions/workflows/ci.yml)
|
|
7
7
|
[](https://github.com/danish9661/stm32F4-emulator/actions/workflows/pages.yml)
|
|
8
8
|
|
|
9
|
+
> **Status: emulation complete.** All 41 peripheral modules are Detailed
|
|
10
|
+
> (0 Partial), all five board maps verify green (37/37/72/73/59 presets),
|
|
11
|
+
> and the Ethernet descriptor layer (EDFE, TCH/TER + RCH/RER walks, RDES4,
|
|
12
|
+
> backoff probe) plus the Wireshark-validated pcap capture (`a1b2c3d4`,
|
|
13
|
+
> tcpdump-verified DHCP→TCP→HTTP) are in. What remains is product work,
|
|
14
|
+
> not emulation: npm publish, https gateway endpoint, VS Code packaging
|
|
15
|
+
> (see [docs/progress-and-future.md](docs/progress-and-future.md)).
|
|
16
|
+
|
|
9
17
|
An STM32F407 microcontroller emulator that runs real Cortex-M4 firmware. It
|
|
10
18
|
combines a **Rust CPU core** (a WASM-native Thumb-2 interpreter with exact
|
|
11
19
|
Cortex-M exception entry/return, including the VFPv4-SP FPU) with a
|
|
@@ -15,7 +23,12 @@ browser tab**, with no SDL, no native deps, no hardware.
|
|
|
15
23
|
|
|
16
24
|
It ships three real networking firmwares (`eth_http`, `eth_dhcp`, `eth_test`)
|
|
17
25
|
that do DHCP + TCP + HTTP against a simulated (or a real gVisor-backed)
|
|
18
|
-
network, a
|
|
26
|
+
network, a 66-marker Ethernet feature matrix (`eth_feat_test`: PHY/MDIO,
|
|
27
|
+
checksum offload, hash/perfect/SA/DA filtering, VLAN, PTP, WOL, wire
|
|
28
|
+
pacing, deferral/collisions, pause frames, MMC, RBUS — see
|
|
29
|
+
[NETWORKING.md](NETWORKING.md)) plus real LwIP 2.2.1 (`lwip_demo`) and
|
|
30
|
+
MII/RMII pin mirrors (`eth_pins_test`), a browser demo, and a publishable
|
|
31
|
+
npm package.
|
|
19
32
|
|
|
20
33
|
## Live demo
|
|
21
34
|
|
|
@@ -24,7 +37,7 @@ The browser demo deploys to GitHub Pages:
|
|
|
24
37
|
**https://danish9661.github.io/stm32F4-emulator/**
|
|
25
38
|
|
|
26
39
|
A single console page that starts **idle** — nothing runs until you pick a
|
|
27
|
-
firmware: a preset dropdown with
|
|
40
|
+
firmware: a preset dropdown with 223 bundled binaries (network demos, a
|
|
28
41
|
bare-metal LED blinker, peripheral/crypto/UART/SPI test binaries), custom
|
|
29
42
|
firmware upload (`.bin`, Intel `.hex`, `.elf` — with loadable RAM segments
|
|
30
43
|
and symbols — plus `.map` for a symbol table), Run/Stop/Reset, a **gateway
|
|
@@ -35,7 +48,7 @@ characters excluded per HTML spec, see AGENTS.md §11), GPIO pin readout
|
|
|
35
48
|
for banks A–E, and key peripheral registers. Interrupt-driven firmware
|
|
36
49
|
(`rx_interrupt_test`, `rx_crypto_test`) gets inline guest-IRQ delivery;
|
|
37
50
|
polling firmware (the ETH demos) never uses it. For automation, a
|
|
38
|
-
preset can auto-boot via the URL:
|
|
51
|
+
preset can auto-boot via the URL: `console.html?fw=eth_http`, `console.html?fw=blinky`, `console.html?fw=crypto_test`, …
|
|
39
52
|
|
|
40
53
|
## DOOM (in the browser)
|
|
41
54
|
|
|
@@ -60,7 +73,7 @@ reloads.
|
|
|
60
73
|
- Controls: move W/S/A/D + arrows · strafe Shift · fire Ctrl · use
|
|
61
74
|
Space · menu Enter/Esc · save F2/F6 · load F3/F9 · F1/F10/F11/F12.
|
|
62
75
|
- Boot → menu → gameplay verified end-to-end by
|
|
63
|
-
`node site/
|
|
76
|
+
`node site/test_doom_wasm.mjs` (boot markers, menu navigation to E1M1,
|
|
64
77
|
palette + framebuffer, W-move + turn, audio, **save → `SAVE ok slot=0`
|
|
65
78
|
→ load handshake**).
|
|
66
79
|
- `site/doom1.wad` is the 4.2 MB shareware WAD; the firmware never reads
|
|
@@ -77,13 +90,13 @@ npm run serve # then open http://127.0.0.1:8123
|
|
|
77
90
|
npm test # == node site/test_flow.mjs
|
|
78
91
|
|
|
79
92
|
# websocket bridge: headless Node serves the emulator, browser is a thin UI
|
|
80
|
-
npm run bridge -- blinky/blinky.bin --port 8234
|
|
81
|
-
# then open http://127.0.0.1:8123?bridge=ws://127.0.0.1:8234
|
|
93
|
+
npm run bridge -- firmware/blinky/blinky.bin --port 8234
|
|
94
|
+
# then open http://127.0.0.1:8123/console.html?bridge=ws://127.0.0.1:8234
|
|
82
95
|
|
|
83
96
|
# gateway-backed run: firmware talks to a REAL network stack (gVisor)
|
|
84
97
|
cd stm32-periph-wasm/pkg
|
|
85
|
-
node cli.mjs ../../eth_http/eth_http.bin 10000000 \
|
|
86
|
-
--gateway --config=../../eth_http/config.yaml
|
|
98
|
+
node cli.mjs ../../firmware/eth_http/eth_http.bin 10000000 \
|
|
99
|
+
--gateway --config=../../firmware/eth_http/config.yaml
|
|
87
100
|
# (requires an HTTP server at 127.0.0.1:8092; see AGENTS.md §10)
|
|
88
101
|
```
|
|
89
102
|
|
|
@@ -119,6 +132,11 @@ custom SPI/I2C devices) to pins and buses with the component API —
|
|
|
119
132
|
`ext_devices.spiDevices`/`i2cDevices` for your own bus protocol. See
|
|
120
133
|
[docs/components.md](docs/components.md).
|
|
121
134
|
|
|
135
|
+
For platform integration (Wokwi/OpenHW/Velxio) use the `STM32F4` facade —
|
|
136
|
+
factories, GPIO/USART/SPI/I2C objects, polled event callbacks, DMA
|
|
137
|
+
controller, live displays, SWD/JTAG/power/probe helpers. See
|
|
138
|
+
[docs/facade.md](docs/facade.md).
|
|
139
|
+
|
|
122
140
|
## Drive it from an AI agent (MCP)
|
|
123
141
|
|
|
124
142
|
`mcp/server.mjs` exposes the emulator over the Model Context Protocol —
|
|
@@ -142,17 +160,17 @@ is a thin UI. Zero impact on the existing local WASM path:
|
|
|
142
160
|
|
|
143
161
|
```bash
|
|
144
162
|
# 1. Start the bridge in Node (serves the emulator over WS on port 8234)
|
|
145
|
-
node site/ws-bridge.mjs eth_http/eth_http.bin --port 8234
|
|
163
|
+
node site/ws-bridge.mjs firmware/eth_http/eth_http.bin --port 8234
|
|
146
164
|
|
|
147
165
|
# 2. Open the browser console with the bridge URL param
|
|
148
|
-
open "http://127.0.0.1:8123
|
|
166
|
+
open "http://127.0.0.1:8123/console.html?bridge=ws://127.0.0.1:8234"
|
|
149
167
|
```
|
|
150
168
|
|
|
151
169
|
The `RemoteEmu` adapter (`site/remote-emu.js`) is a drop-in replacement
|
|
152
170
|
for the local `emu` object — same `step()`/`drainUart()`/`read32()` API,
|
|
153
171
|
all proxied over binary WebSocket. Device stubs (OLED/TFT/etc.) run in
|
|
154
172
|
Node and are not visible to browser JS. Without `?fw=`, the page boots
|
|
155
|
-
whatever firmware the bridge was started with; with
|
|
173
|
+
whatever firmware the bridge was started with; with `console.html?fw=blinky&bridge=ws://…`,
|
|
156
174
|
the browser sends the firmware image over the bridge.
|
|
157
175
|
|
|
158
176
|
See AGENTS.md §20 for the full binary protocol reference.
|
|
@@ -164,8 +182,11 @@ See AGENTS.md §20 for the full binary protocol reference.
|
|
|
164
182
|
| `eth_http/` | DHCP + TCP client + HTTP GET + prints the response | `TCP connected`, `=== HTTP <len>b ===` |
|
|
165
183
|
| `eth_dhcp/` | Loops DHCP Discover/Offer/Request/Ack | `DHCP SUCCESS` |
|
|
166
184
|
| `eth_test/` | Raw ETH TX/RX self-test | `ETH Test: done` |
|
|
185
|
+
| `eth_feat_test/` | 66-marker Ethernet feature matrix (netsim, F407 + F429) | `FEAT Test: done` (all 66 markers, `FAIL`/`TIMEOUT` anti-markers) |
|
|
186
|
+
| `lwip_demo/` | Real LwIP 2.2.1 (DHCP→DNS→TCP echo→TCP server→UDP echo) | `LWIP DEMO DONE` |
|
|
187
|
+
| `eth_pins_test/` | MII/RMII pin-level mirrors (TX_EN/CRS_DV/RXD/COL/MDIO/MDC) | `PINS ALL PASS` |
|
|
167
188
|
| `blinky/` | **No ethernet** — LED blinker on GPIOA PA5 + UART tick counter | `tick N LED=ON/OFF` |
|
|
168
|
-
| `doom/` | **DOOM 1 shareware** (doomgeneric F407 port, browser page `site/doom.html`) | `node site/
|
|
189
|
+
| `doom/` | **DOOM 1 shareware** (doomgeneric F407 port, browser page `site/doom.html`) | `node site/test_doom_wasm.mjs` (boot + menu + gameplay + save/load) |
|
|
169
190
|
|
|
170
191
|
Plus 17 more test binaries (`crypto_test`, `hal_test`, `timer_test`,
|
|
171
192
|
`periph_test`, `echo_test`, `blink_serial`, `rx_interrupt_test`,
|
|
@@ -198,10 +219,13 @@ firmware .bin ──► Rust WASM CPU (Thumb-2 + NVIC/exceptions)
|
|
|
198
219
|
(SysTick, ETH, USART, SVC/PendSV) are delivered inline with exact
|
|
199
220
|
exception stacking — no native deps, no JIT, no hooks.
|
|
200
221
|
- **Peripherals**: a `wasm-bindgen` crate (`stm32-periph-wasm/`); registers
|
|
201
|
-
and bit fields come from the vendor SVD (`
|
|
202
|
-
- **Ethernet**: TX is captured from the DMA descriptors
|
|
203
|
-
|
|
204
|
-
|
|
222
|
+
and bit fields come from the vendor SVD (`site/vendor/stm32f407.svd`).
|
|
223
|
+
- **Ethernet**: TX is captured from the DMA descriptors (OWN/FS/LS poll
|
|
224
|
+
demand); RX frames are delivered head-only with FS+LS status, IPHCE/PCE
|
|
225
|
+
checksum status, and PTP snapshots for event messages. The full MAC
|
|
226
|
+
register map is cross-checked against CMSIS `stm32f407xx.h` (DMASR/
|
|
227
|
+
DMAIER/MACFFR/MACPMTCTL positions — see [NETWORKING.md](NETWORKING.md)
|
|
228
|
+
§6 for the audit). Optionally, a Go gateway
|
|
205
229
|
(`openhw-local-gateway/`) with a gVisor network stack makes the firmware
|
|
206
230
|
talk to a real network: `node cli.mjs <fw.bin> <inst> --gateway`.
|
|
207
231
|
- **Browser build** (`site/`): same modules as ESM; `site/emulator.js` is an
|
|
@@ -230,13 +254,13 @@ firmware .bin ──► Rust WASM CPU (Thumb-2 + NVIC/exceptions)
|
|
|
230
254
|
├── index.mjs, package.json npm package entry (stm32f4-emu)
|
|
231
255
|
├── mcp/ MCP server (drive the emulator from an AI agent)
|
|
232
256
|
├── .github/workflows/ CI (Linux/Windows/macOS test matrix) + Pages deploy
|
|
233
|
-
├── tools/make_firmware.mjs Regenerates site/firmware.js from
|
|
257
|
+
├── tools/make_firmware.mjs Regenerates site/firmware.js from firmware/*/.bin
|
|
234
258
|
├── stm32-periph-wasm/ Rust peripheral model (WASM build + pkg/)
|
|
235
|
-
├── eth_http/ eth_dhcp/ eth_test/ Sample network firmwares + configs
|
|
236
|
-
├── doom/
|
|
259
|
+
├── firmware/eth_http/ eth_dhcp/ eth_test/ Sample network firmwares + configs
|
|
260
|
+
├── firmware/doom/ DOOM 1 port (doomgeneric f407 target + WAD path)
|
|
237
261
|
├── openhw-local-gateway/ Go gateway (gVisor network stack)
|
|
238
262
|
├── scripts/verify_ethernet.sh Regression runner for all three firmwares
|
|
239
|
-
├──
|
|
263
|
+
├── hardware/monox/, hardware/saturn/ Upstream printer firmwares (heritage)
|
|
240
264
|
└── AGENTS.md Full architecture, build steps, runbook
|
|
241
265
|
```
|
|
242
266
|
|
|
@@ -248,10 +272,9 @@ cd stm32-periph-wasm && wasm-pack build --release --target nodejs
|
|
|
248
272
|
|
|
249
273
|
# firmware (bare-metal Makefiles; toolchain from the Arduino core)
|
|
250
274
|
TOOLCHAIN="$HOME/.arduino15/packages/STMicroelectronics/tools/xpack-arm-none-eabi-gcc/14.2.1-1.1/bin/arm-none-eabi-" \
|
|
251
|
-
make -C eth_http
|
|
275
|
+
make -C firmware/eth_http # also eth_dhcp, eth_test (all firmware lives in firmware/)
|
|
252
276
|
|
|
253
|
-
# native SDL emulator
|
|
254
|
-
cd stm32-emulator-main && cargo build --release
|
|
277
|
+
# (no native SDL emulator in this tree — the headless WASM path above is the only backend)
|
|
255
278
|
```
|
|
256
279
|
|
|
257
280
|
`wasm-pack` writes `site/vendor/.gitignore` containing `*` after a browser
|
|
@@ -259,7 +282,10 @@ rebuild — delete it so the vendor assets stay tracked/committed.
|
|
|
259
282
|
|
|
260
283
|
## Testing
|
|
261
284
|
|
|
262
|
-
- `npm test` — flow test (`site/test_flow.mjs`) +
|
|
285
|
+
- `npm test` — flow test (`site/test_flow.mjs`) + Ethernet mock harnesses
|
|
286
|
+
(`site/test_eth_mock_model.mjs`: 18 checks, fake bindings + real driver;
|
|
287
|
+
`site/test_eth_mock_consumer.mjs`: 44 checks, fake firmware + real model)
|
|
288
|
+
+ blinky test
|
|
263
289
|
(`site/test_blinky.mjs`) + interrupt-UART test (`site/test_rx_interrupt.mjs`)
|
|
264
290
|
+ component-API tests (`site/test_component_{led,button,pwm,i2cregfile}.mjs`,
|
|
265
291
|
each against real firmware — LED/blinky, Button/exti_test, Pwm/buzzer_test,
|
|
@@ -269,7 +295,7 @@ rebuild — delete it so the vendor assets stay tracked/committed.
|
|
|
269
295
|
process (see docs/components.md). The same suite runs in CI on
|
|
270
296
|
`ubuntu-latest`/`windows-latest`/`macos-latest`
|
|
271
297
|
([.github/workflows/ci.yml](.github/workflows/ci.yml)) on every push.
|
|
272
|
-
- `node site/
|
|
298
|
+
- `node site/test_doom_wasm.mjs` — DOOM boot → menu → E1M1 gameplay + save/load
|
|
273
299
|
(see the DOOM section above).
|
|
274
300
|
- `scripts/verify_ethernet.sh [max_inst]` — runs all three firmwares through
|
|
275
301
|
the gateway, asserts the success markers and 0 `TCP fail`.
|
|
@@ -281,7 +307,7 @@ rebuild — delete it so the vendor assets stay tracked/committed.
|
|
|
281
307
|
- [site/about.html](site/about.html) — in-repo About page: what it is, architecture, featured firmwares, and how to use it (CLI / browser / Node API / MCP).
|
|
282
308
|
- [docs/architecture.md](docs/architecture.md) — how the emulator is put
|
|
283
309
|
together (CPU, peripheral model, drivers, ETH flow, interrupts).
|
|
284
|
-
- [docs/peripherals.md](docs/peripherals.md) — all
|
|
310
|
+
- [docs/peripherals.md](docs/peripherals.md) — all 41 peripherals and the
|
|
285
311
|
level each is implemented to, plus external devices and known gaps.
|
|
286
312
|
- [docs/usage.md](docs/usage.md) — CLI, browser, and npm-library usage,
|
|
287
313
|
config files, env vars, building.
|
package/index.d.ts
CHANGED
|
@@ -18,7 +18,287 @@ export const bindings: any;
|
|
|
18
18
|
export const unicornFactory: any;
|
|
19
19
|
export const svdXml: string;
|
|
20
20
|
|
|
21
|
-
//
|
|
21
|
+
// STM32F4 high-level facade (see site/stm32f4.js). F1-API parity surface:
|
|
22
|
+
// factories, execute/step results, GPIO/USART/SPI/I2C classes, symbol
|
|
23
|
+
// helpers, and engine pass-throughs. TX is a single shared model buffer
|
|
24
|
+
// (only usart1.onData/output fire); event callbacks beyond SPI/I2C taps
|
|
25
|
+
// are absent by design (no core event queue on F4).
|
|
26
|
+
export interface ExecuteResult { instCount: number; stopped: boolean; }
|
|
27
|
+
export interface FacadeStepResult { pc: number; instCount: number; stopped: boolean; }
|
|
28
|
+
export class GPIOPin {
|
|
29
|
+
constructor(mcu: STM32F4, port: string, pin: number);
|
|
30
|
+
on(event: 'change', cb: (high: boolean) => void): () => void;
|
|
31
|
+
addListener(cb: (high: boolean) => void): () => void;
|
|
32
|
+
read(): boolean;
|
|
33
|
+
readInput(): boolean;
|
|
34
|
+
setInput(high: boolean): void;
|
|
35
|
+
setInputValue(high: boolean): void;
|
|
36
|
+
detach(): void;
|
|
37
|
+
}
|
|
38
|
+
export class GPIO {
|
|
39
|
+
constructor(mcu: STM32F4);
|
|
40
|
+
pin(port: string | number, pin: number): GPIOPin;
|
|
41
|
+
}
|
|
42
|
+
export interface ChipRecord {
|
|
43
|
+
key: string;
|
|
44
|
+
svd: string;
|
|
45
|
+
flash_size: number;
|
|
46
|
+
ram_size: number;
|
|
47
|
+
maxClockMHz: number;
|
|
48
|
+
label: string;
|
|
49
|
+
idcode: number;
|
|
50
|
+
usarts: number[];
|
|
51
|
+
timers: number[];
|
|
52
|
+
can: number[];
|
|
53
|
+
dac: boolean;
|
|
54
|
+
ltdc: boolean;
|
|
55
|
+
gpioBanks: number;
|
|
56
|
+
spi: number[];
|
|
57
|
+
i2c: number[];
|
|
58
|
+
uart78: number[];
|
|
59
|
+
i2s: number[];
|
|
60
|
+
sai: number[];
|
|
61
|
+
sdio: boolean;
|
|
62
|
+
dcmi: boolean;
|
|
63
|
+
crc: boolean;
|
|
64
|
+
cryp: boolean;
|
|
65
|
+
hash: boolean;
|
|
66
|
+
rng: boolean;
|
|
67
|
+
fsmc: boolean;
|
|
68
|
+
dma2d: boolean;
|
|
69
|
+
qspi: boolean;
|
|
70
|
+
}
|
|
71
|
+
export declare const CHIPS: Record<string, Omit<ChipRecord, 'key'>>;
|
|
72
|
+
export declare function chipInfo(key?: string): ChipRecord;
|
|
73
|
+
export class USART {
|
|
74
|
+
readonly n: number;
|
|
75
|
+
onData: ((byte: number) => void) | null;
|
|
76
|
+
constructor(mcu: STM32F4, n: number);
|
|
77
|
+
send(data: string | Uint8Array | number[]): void;
|
|
78
|
+
sendData(data: string | Uint8Array | number[]): void;
|
|
79
|
+
get output(): string;
|
|
80
|
+
}
|
|
81
|
+
export class SPI {
|
|
82
|
+
readonly ch: number;
|
|
83
|
+
onTransfer: ((channel: string, tx: number[], rx: number[]) => void) | null;
|
|
84
|
+
constructor(mcu: STM32F4, ch: number);
|
|
85
|
+
injectMiso(bytes: Uint8Array | number[]): void;
|
|
86
|
+
}
|
|
87
|
+
export class I2C {
|
|
88
|
+
readonly ch: number;
|
|
89
|
+
onStart: ((addr: number, isRead: boolean) => void) | null;
|
|
90
|
+
onWrite: ((byte: number) => void) | null;
|
|
91
|
+
onRead: (() => void) | null;
|
|
92
|
+
onStop: (() => void) | null;
|
|
93
|
+
constructor(mcu: STM32F4, ch: number);
|
|
94
|
+
injectRx(bytes: Uint8Array | number[]): void;
|
|
95
|
+
}
|
|
96
|
+
export class DMAStream {
|
|
97
|
+
constructor(mcu: STM32F4, streamIndex: number);
|
|
98
|
+
pendingCount(): number;
|
|
99
|
+
setCompleted(success?: boolean): void;
|
|
100
|
+
tcif(): boolean;
|
|
101
|
+
htif(): boolean;
|
|
102
|
+
cr(): number;
|
|
103
|
+
ndtr(): number;
|
|
104
|
+
}
|
|
105
|
+
export class DMAController {
|
|
106
|
+
constructor(mcu: STM32F4, controller?: 1 | 2);
|
|
107
|
+
lisr(): number;
|
|
108
|
+
hisr(): number;
|
|
109
|
+
tcif(s: number): boolean;
|
|
110
|
+
htif(s: number): boolean;
|
|
111
|
+
cr(s: number): number;
|
|
112
|
+
ndtr(s: number): number;
|
|
113
|
+
par(s: number): number;
|
|
114
|
+
m0ar(s: number): number;
|
|
115
|
+
m1ar(s: number): number;
|
|
116
|
+
fcr(s: number): number;
|
|
117
|
+
stream(s: number): DMAStream;
|
|
118
|
+
}
|
|
119
|
+
export class Display {
|
|
120
|
+
constructor(mcu: STM32F4);
|
|
121
|
+
get oled(): { w: number; h: number; fb: Uint8Array; frame: number } | null;
|
|
122
|
+
get tft(): { w: number; h: number; fb: Uint8Array; frame: () => number } | null;
|
|
123
|
+
ltdc(): { w: number; h: number; pf: string; fb: Uint8Array; addr: number; pitch: number } | null;
|
|
124
|
+
}
|
|
125
|
+
export class STM32F4 {
|
|
126
|
+
readonly gpio: GPIO;
|
|
127
|
+
readonly usart: USART;
|
|
128
|
+
// Slots for absent-silicon USARTs are null (F401/F411: 3,4,5).
|
|
129
|
+
readonly usart1: USART; readonly usart2: USART; readonly usart3: USART | null;
|
|
130
|
+
readonly usart4: USART | null; readonly usart5: USART | null; readonly usart6: USART;
|
|
131
|
+
readonly usart7: USART | null; readonly usart8: USART | null;
|
|
132
|
+
readonly usarts: Record<number, USART>;
|
|
133
|
+
readonly spi1: SPI | null; readonly spi2: SPI; readonly spi3: SPI;
|
|
134
|
+
readonly spi4: SPI | null; readonly spi5: SPI | null; readonly spi6: SPI | null;
|
|
135
|
+
readonly spiBus: Record<number, SPI>;
|
|
136
|
+
readonly i2c1: I2C; readonly i2c2: I2C; readonly i2c3: I2C;
|
|
137
|
+
readonly i2cBus: Record<number, I2C>;
|
|
138
|
+
readonly spi: { specs: any[]; pushMiso(peripheral: string, bytes: Uint8Array | number[]): void };
|
|
139
|
+
readonly i2c: { specs: any[]; pushRx(peripheral: string, bytes: Uint8Array | number[]): void };
|
|
140
|
+
readonly dma: { stream(index: number): DMAStream; controller(ctl: 1 | 2): DMAController };
|
|
141
|
+
readonly display: Display;
|
|
142
|
+
readonly chip: ChipRecord;
|
|
143
|
+
readonly chipSvdXml: string | null;
|
|
144
|
+
// Wokwi/OpenHW/Velxio integration callbacks (polled dispatch, see site/stm32f4.js).
|
|
145
|
+
onExtiEdge: ((line: number) => void) | null;
|
|
146
|
+
onCanTx: ((can: number) => void) | null;
|
|
147
|
+
onCanRx: ((can: number, id: number, len: number, data: number[]) => void) | null;
|
|
148
|
+
onTimUpdate: ((tim: number) => void) | null;
|
|
149
|
+
onTimCapture: ((tim: number, ch: number, val: number) => void) | null;
|
|
150
|
+
onDmaTc: ((controller: number, stream: number) => void) | null;
|
|
151
|
+
onWdogReset: ((which: number) => void) | null;
|
|
152
|
+
onUsbIn: ((ep: number, data: number[]) => void) | null;
|
|
153
|
+
onUsbHsIn: ((ep: number, data: number[]) => void) | null;
|
|
154
|
+
onItmByte: ((port: number, byte: number) => void) | null;
|
|
155
|
+
onFsmcAccess: ((bank: number, off: number, write: boolean, size: number, val: number) => void) | null;
|
|
156
|
+
onAdcDone: ((adc: number, chan: number, value: number) => void) | null;
|
|
157
|
+
onDacWrite: ((chan: number, value: number) => void) | null;
|
|
158
|
+
onCrcResult: ((value: number) => void) | null;
|
|
159
|
+
onRtcAlarm: ((which: number) => void) | null;
|
|
160
|
+
onI2cAlert: ((peripheral: number, asserted: boolean) => void) | null;
|
|
161
|
+
onHostTx: ((...args: any[]) => void) | null;
|
|
162
|
+
onHostRx: ((...args: any[]) => void) | null;
|
|
163
|
+
constructor(emu: any, bindings?: any, chip?: ChipRecord, chipSvdXml?: string | null);
|
|
164
|
+
static create(opts?: any): Promise<STM32F4>;
|
|
165
|
+
static fromELF(buf: Uint8Array | ArrayBuffer, opts?: any): Promise<STM32F4>;
|
|
166
|
+
static fromBin(buf: Uint8Array | ArrayBuffer, opts?: any): Promise<STM32F4>;
|
|
167
|
+
static fromHex(text: string, opts?: any): Promise<STM32F4>;
|
|
168
|
+
loadBin(bytes: Uint8Array | ArrayBuffer, base?: number): void;
|
|
169
|
+
loadHex(text: string): void;
|
|
170
|
+
loadELF(bytes: Uint8Array | ArrayBuffer): void;
|
|
171
|
+
// Live peripheral injection (anytime unless noted).
|
|
172
|
+
setAdcChannel(peripheral: string, channel: number, value: number): void;
|
|
173
|
+
clearAdcChannel(peripheral: string, channel: number): void;
|
|
174
|
+
takeAdcDma(): number[];
|
|
175
|
+
canInject(id: number, dlc: number, data: Uint8Array | number[]): void;
|
|
176
|
+
canInjectFd(id: number, data: Uint8Array | number[], brs?: boolean): void;
|
|
177
|
+
timInjectCapture(timer: number, ch: number): void;
|
|
178
|
+
timPwmPulseUs(timer: number, ch: number, clockHz: number): number;
|
|
179
|
+
timOcMode(timer: number, ch: number): number;
|
|
180
|
+
timMoe(timer: number): boolean;
|
|
181
|
+
timEncoderStep(timer: number, ti: number, rising: boolean): void;
|
|
182
|
+
timBreakInput(timer: number, asserted: boolean): void;
|
|
183
|
+
dacTrigger(ch: number, src: number, dmaStaged?: boolean): void;
|
|
184
|
+
dacUnderrun(ch: number): boolean;
|
|
185
|
+
takeSpeakerSamples(): Float32Array;
|
|
186
|
+
usbInjectSetup(bytes: Uint8Array | number[]): boolean;
|
|
187
|
+
usbInjectOut(ep: number, bytes: Uint8Array | number[]): boolean;
|
|
188
|
+
usbTakeIn(ep: number): number[];
|
|
189
|
+
usbReset(): void;
|
|
190
|
+
usbEnumerated(): void;
|
|
191
|
+
usbHsInjectSetup(bytes: Uint8Array | number[]): boolean;
|
|
192
|
+
usbHsInjectOut(ep: number, bytes: Uint8Array | number[]): boolean;
|
|
193
|
+
usbHsTakeIn(ep: number): number[];
|
|
194
|
+
usbHsReset(): void;
|
|
195
|
+
usbHsEnumerated(): void;
|
|
196
|
+
ethInject(frame: Uint8Array | number[]): void;
|
|
197
|
+
// Fault / model-harness methods (mirror wasm exports 1:1).
|
|
198
|
+
uartSetCts(base: number, asserted: boolean): void;
|
|
199
|
+
uartFaultRx(base: number, fe: boolean, pe: boolean): void;
|
|
200
|
+
uartIdle(base: number): void;
|
|
201
|
+
uartLinBreak(base: number): void;
|
|
202
|
+
uartBreakPending(base: number): boolean;
|
|
203
|
+
uartTxLen(base: number): number;
|
|
204
|
+
uartMuted(base: number): boolean;
|
|
205
|
+
spiFaultCrc(base: number): void;
|
|
206
|
+
spiFaultModf(base: number): void;
|
|
207
|
+
spiSlaveSelect(base: number, asserted: boolean): void;
|
|
208
|
+
spiSlaveClock(base: number, mosi: number): number;
|
|
209
|
+
spiSlaveGate(base: number): boolean;
|
|
210
|
+
i2cArmArbLoss(base: number): void;
|
|
211
|
+
i2cArmSmbusAlert(base: number, addr: number): void;
|
|
212
|
+
i2cSlaveAddress(base: number, addr: number, isRead: boolean): boolean;
|
|
213
|
+
i2cSlaveWrite(base: number, byte: number): void;
|
|
214
|
+
i2cSlaveRead(base: number): number;
|
|
215
|
+
i2cSlaveStop(base: number): void;
|
|
216
|
+
i2cSlaveStatus(base: number): number;
|
|
217
|
+
sdioFaultDataCrc(): void;
|
|
218
|
+
rccInjectFailure(srcMask: number, dead: boolean): void;
|
|
219
|
+
flashRdpLevel(): number;
|
|
220
|
+
flashSetRdp(levelByte: number): void;
|
|
221
|
+
rngSeedEntropy(words: number[] | Uint32Array): void;
|
|
222
|
+
rngEntropyAvail(): number;
|
|
223
|
+
rtcTamperPin(level: boolean): void;
|
|
224
|
+
rtcTimestamp(): void;
|
|
225
|
+
setIntrPending(irq: number): void;
|
|
226
|
+
hasPendingInterrupt(): boolean;
|
|
227
|
+
// Scope probes (read-only model state).
|
|
228
|
+
adcDualLatched(): boolean;
|
|
229
|
+
ethPpsCount(): number;
|
|
230
|
+
ethPpsLevel(): boolean;
|
|
231
|
+
ethLinkUp(): boolean;
|
|
232
|
+
ethSetLink(up: boolean): void;
|
|
233
|
+
ltdcScanline(): number;
|
|
234
|
+
ltdcFrameCount(): number;
|
|
235
|
+
audioRemaining(): number;
|
|
236
|
+
audioClear(): void;
|
|
237
|
+
dcmiSync(vsync: boolean, hsync: boolean, pclkDiv: number): void;
|
|
238
|
+
qspiMmapLive(): boolean;
|
|
239
|
+
qspiMmapRead(offset: number): number;
|
|
240
|
+
sdioBusWidth(): number;
|
|
241
|
+
sdioCardBlocks(): number;
|
|
242
|
+
sdioReadBlock(block: number): number[];
|
|
243
|
+
takeItm(port: number): number[];
|
|
244
|
+
itmPending(port: number): number;
|
|
245
|
+
takeFsmc(bank: number): number[];
|
|
246
|
+
pushFsmc(bank: number, values: number[] | Uint32Array): void;
|
|
247
|
+
regfileGet(peripheral: string, offset: number): number;
|
|
248
|
+
regfileSet(peripheral: string, offset: number, value: number): void;
|
|
249
|
+
get oled(): any;
|
|
250
|
+
get tft(): any;
|
|
251
|
+
get rtc(): any;
|
|
252
|
+
get buzzer(): any;
|
|
253
|
+
get camera(): any;
|
|
254
|
+
execute(cycles?: number): ExecuteResult;
|
|
255
|
+
step(cycles?: number): FacadeStepResult;
|
|
256
|
+
uartRx(byte: number): boolean;
|
|
257
|
+
get uartOutput(): string;
|
|
258
|
+
setSymbols(mapText: string): number;
|
|
259
|
+
resolveSymbol(pc: number): string | null;
|
|
260
|
+
read32(addr: number): number;
|
|
261
|
+
write32(addr: number, val: number): void;
|
|
262
|
+
memRead32(addr: number): number;
|
|
263
|
+
memWriteBytes(addr: number, bytes: Uint8Array | number[]): void;
|
|
264
|
+
periphRead(addr: number, width?: number): number;
|
|
265
|
+
periphWrite(addr: number, width: number, value: number): void;
|
|
266
|
+
addJsPeripheral(base: number, size: number, read: (addr: number, size: number) => number, write: (addr: number, value: number, size: number) => void): boolean;
|
|
267
|
+
pwrMode(): number;
|
|
268
|
+
pwrEstimate(): number;
|
|
269
|
+
swdHalted(): boolean;
|
|
270
|
+
swdHalt(): void;
|
|
271
|
+
swdResume(): void;
|
|
272
|
+
swdStep(): number;
|
|
273
|
+
swdAddWatch(kind: number, addr: number, len: number): number;
|
|
274
|
+
swdRemoveWatch(slot: number): void;
|
|
275
|
+
swdTakeTrip(): number[];
|
|
276
|
+
swdDpRead(addr: number): number;
|
|
277
|
+
swdDpWrite(addr: number, value: number): void;
|
|
278
|
+
swdApRead(bank: number, reg: number): number;
|
|
279
|
+
swdApWrite(bank: number, reg: number, value: number): void;
|
|
280
|
+
swdRegRead(idx: number): number;
|
|
281
|
+
swdRegWrite(idx: number, value: number): void;
|
|
282
|
+
jtagReset(): void;
|
|
283
|
+
jtagIr(ir: number): void;
|
|
284
|
+
jtagIdcode(): number;
|
|
285
|
+
jtagDp(addr: number, rnw: boolean, wdata: number): number;
|
|
286
|
+
jtagAp(bank: number, reg: number, rnw: boolean, wdata: number): number;
|
|
287
|
+
dmaController(ctl?: 1 | 2): DMAController;
|
|
288
|
+
getRegisters(): any;
|
|
289
|
+
getPc(): number;
|
|
290
|
+
getSp(): number;
|
|
291
|
+
faultInfo(): any;
|
|
292
|
+
takeFault(): [number, number] | null;
|
|
293
|
+
stop(): void;
|
|
294
|
+
reset(): void;
|
|
295
|
+
close(): void;
|
|
296
|
+
resetCpu(): void;
|
|
297
|
+
setNrst(asserted: boolean): boolean;
|
|
298
|
+
isNrstAsserted(): boolean;
|
|
299
|
+
bootPreset(image: any): void;
|
|
300
|
+
ledStatus(fwName: string, boardKey: string): any;
|
|
301
|
+
}
|
|
22
302
|
export class LED {
|
|
23
303
|
constructor(emu: any, port: string, num: number, opts?: { activeLow?: boolean });
|
|
24
304
|
on(): void;
|
|
@@ -46,3 +326,11 @@ export class Potentiometer {
|
|
|
46
326
|
export class I2cRegisterDevice {
|
|
47
327
|
constructor(emu: any, peripheral: string, opts?: any);
|
|
48
328
|
}
|
|
329
|
+
|
|
330
|
+
// Component-attachment API (attach devices to an emulator handle).
|
|
331
|
+
// Board LED map + host reset/boot control (see site/boards.js,
|
|
332
|
+
// site/emulator.js, site/stm32f4.js).
|
|
333
|
+
export interface BoardLed { bank: number; pin: number; label: string; }
|
|
334
|
+
export declare const BOARD_LED: Record<string, BoardLed>;
|
|
335
|
+
export declare const BOARD_LED_ALIASES: Record<string, BoardLed>;
|
|
336
|
+
export declare function boardLed(fwName: string, boardKey: string): BoardLed;
|
package/index.mjs
CHANGED
|
@@ -7,13 +7,17 @@ import { createEmulator } from './site/emulator.js';
|
|
|
7
7
|
import { createNetSim } from './site/netsim.js';
|
|
8
8
|
import { FIRMWARES } from './site/firmware.js';
|
|
9
9
|
import { LED, Button, Pwm, I2cRegisterDevice, Potentiometer } from './site/components.js';
|
|
10
|
-
import { STM32F4, GPIOPin, USART, DMAStream } from './site/stm32f4.js';
|
|
10
|
+
import { STM32F4, GPIOPin, GPIO, USART, SPI, I2C, DMAStream, DMAController, Display, CHIPS, chipInfo } from './site/stm32f4.js';
|
|
11
11
|
|
|
12
12
|
// Node consumers get a one-call setup that injects the bundled assets. The
|
|
13
13
|
// `firmware` option is optional (defer to loadBin/loadHex/loadELF after
|
|
14
14
|
// create), matching the rp2040js / avr8js ergonomics.
|
|
15
|
+
// NOTE: svdXml is deliberately NOT injected here. STM32F4._create resolves
|
|
16
|
+
// the SVD per `chip` (F401/F411/F407/F429) itself; injecting the F407 default
|
|
17
|
+
// would shadow the chip map (right sizes + IDCODE, wrong registers). A caller
|
|
18
|
+
// passing svdXml explicitly still wins (override path in _create).
|
|
15
19
|
STM32F4.create = (opts = {}) => STM32F4._create({
|
|
16
|
-
bindings,
|
|
20
|
+
bindings, wasmInit: wasmBytes, ...opts,
|
|
17
21
|
});
|
|
18
22
|
|
|
19
23
|
const svdXml = readFileSync(new URL('./site/vendor/stm32f407.svd', import.meta.url), 'utf8');
|
|
@@ -39,4 +43,5 @@ export async function createSTM32F407(opts = {}) {
|
|
|
39
43
|
return createEmulator({ ...opts, firmware: bin, bindings, svdXml, wasmInit: wasmBytes });
|
|
40
44
|
}
|
|
41
45
|
|
|
42
|
-
export { createEmulator, createNetSim, FIRMWARES, bindings, svdXml, LED, Button, Pwm, I2cRegisterDevice, Potentiometer, STM32F4, GPIOPin, USART, DMAStream };
|
|
46
|
+
export { createEmulator, createNetSim, FIRMWARES, bindings, svdXml, LED, Button, Pwm, I2cRegisterDevice, Potentiometer, STM32F4, GPIOPin, GPIO, USART, SPI, I2C, DMAStream, DMAController, Display, CHIPS, chipInfo };
|
|
47
|
+
export { boardLed, BOARD_LED, BOARD_LED_ALIASES } from './site/boards.js';
|
package/mcp/server.mjs
CHANGED
|
@@ -252,4 +252,27 @@ server.registerTool('reset', {
|
|
|
252
252
|
return text(`closed session (${was})`);
|
|
253
253
|
});
|
|
254
254
|
|
|
255
|
+
server.registerTool('reset_cpu', {
|
|
256
|
+
description: 'Host reset button: CPU back to the vector-table SP/PC, peripherals keep state (like a real NRST pulse without the hold). Prefer over load_firmware when re-running the same image.',
|
|
257
|
+
inputSchema: {},
|
|
258
|
+
}, async () => {
|
|
259
|
+
const { emu } = requireSession();
|
|
260
|
+
if (typeof emu.resetCpu === 'function') emu.resetCpu();
|
|
261
|
+
else emu.reset();
|
|
262
|
+
return text('cpu reset to vector table');
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
server.registerTool('set_nrst', {
|
|
266
|
+
description: 'Hold (assert=true) or release the NRST line. While held, step() only advances the model clock — the CPU executes nothing, like real hardware in reset. Query with level omitted.',
|
|
267
|
+
inputSchema: { level: z.boolean().optional().describe('true = assert (hold in reset), false = release; omit to query') },
|
|
268
|
+
}, async ({ level }) => {
|
|
269
|
+
const { emu } = requireSession();
|
|
270
|
+
if (level === undefined) {
|
|
271
|
+
const s = typeof emu.isNrstAsserted === 'function' ? emu.isNrstAsserted() : false;
|
|
272
|
+
return text({ asserted: !!s });
|
|
273
|
+
}
|
|
274
|
+
const s = typeof emu.setNrst === 'function' ? emu.setNrst(level) : false;
|
|
275
|
+
return text({ asserted: !!s });
|
|
276
|
+
});
|
|
277
|
+
|
|
255
278
|
await server.connect(new StdioServerTransport());
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "stm32f4-emu",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"description": "STM32F407 emulator: Rust CPU + peripheral model (WASM). Runs real Cortex-M4 firmware in Node or the browser.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.mjs",
|
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
"site/emulator.js",
|
|
32
32
|
"site/emulator.d.ts",
|
|
33
33
|
"site/stm32f4.js",
|
|
34
|
+
"site/boards.js",
|
|
34
35
|
"site/components.js",
|
|
35
36
|
"site/netsim.js",
|
|
36
37
|
"site/firmware.js",
|
|
@@ -39,6 +40,7 @@
|
|
|
39
40
|
"site/ws-bridge.mjs",
|
|
40
41
|
"site/app.js",
|
|
41
42
|
"site/index.html",
|
|
43
|
+
"site/console.html",
|
|
42
44
|
"site/vendor/",
|
|
43
45
|
"mcp/server.mjs",
|
|
44
46
|
"tools/make_firmware.mjs"
|
|
@@ -66,8 +68,8 @@
|
|
|
66
68
|
"node": ">=20"
|
|
67
69
|
},
|
|
68
70
|
"scripts": {
|
|
69
|
-
"test": "node site/test_stm32f4_api.mjs && node site/test_stm32f4_periph.mjs && node site/test_ws_bridge.mjs && node site/test_flow.mjs && node site/test_blinky.mjs && node site/test_rx_interrupt.mjs && node site/test_component_led.mjs && node site/test_component_button.mjs && node site/test_component_pwm.mjs && node site/test_component_i2cregfile.mjs && node site/test_component_adc.mjs && node site/test_multi_instance.mjs && node site/test_fsmc_dcmi.mjs && node site/test_fsmc.mjs && node site/test_dcmi.mjs && node site/probe_freertos.mjs && node site/test_candemo.mjs && node site/test_lowpower.mjs && node site/test_edge_cases.mjs && node site/test_can_inject.mjs && node site/test_watchdog.mjs && node site/test_wwdg.mjs && node site/test_wwdg_window.mjs && node site/test_tim_capture.mjs && node site/test_qspi.mjs && node site/test_fpu.mjs && node site/test_fpu_irq.mjs && node site/test_mpu.mjs && node site/test_usb.mjs && node site/test_qspi_cdp.mjs && node site/test_browser.mjs",
|
|
70
|
-
"test:unit": "node site/test_stm32f4_api.mjs && node site/test_stm32f4_periph.mjs && node site/test_ws_bridge.mjs && node site/test_flow.mjs && node site/test_blinky.mjs && node site/test_rx_interrupt.mjs && node site/test_component_led.mjs && node site/test_component_button.mjs && node site/test_component_pwm.mjs && node site/test_component_i2cregfile.mjs && node site/test_component_adc.mjs && node site/test_multi_instance.mjs && node site/test_fsmc_dcmi.mjs && node site/test_fsmc.mjs && node site/test_dcmi.mjs && node site/probe_freertos.mjs && node site/test_candemo.mjs && node site/test_lowpower.mjs && node site/test_edge_cases.mjs && node site/test_can_inject.mjs && node site/test_watchdog.mjs && node site/test_wwdg.mjs && node site/test_wwdg_window.mjs && node site/test_tim_capture.mjs && node site/test_qspi.mjs",
|
|
71
|
+
"test": "node site/test_stm32f4_api.mjs && node site/test_stm32f4_periph.mjs && node site/test_ws_bridge.mjs && node site/test_flow.mjs && node site/test_eth_mock_model.mjs && node site/test_eth_mock_consumer.mjs && node site/test_periph_mock_consumer.mjs && node site/test_blinky.mjs && node site/test_blinky_f401.mjs && node site/test_blinky_f411.mjs && node site/test_blinky_f407g.mjs && node site/test_blinky_nucleo_f401.mjs && node site/test_blinky_nucleo_f411.mjs && node site/test_blinky_f429.mjs && node site/test_blinky_f407ve.mjs && node site/test_rx_interrupt.mjs && node site/test_component_led.mjs && node site/test_component_button.mjs && node site/test_component_pwm.mjs && node site/test_component_i2cregfile.mjs && node site/test_component_adc.mjs && node site/test_multi_instance.mjs && node site/test_fsmc_dcmi.mjs && node site/test_fsmc.mjs && node site/test_dcmi.mjs && node site/probe_freertos.mjs && node site/test_candemo.mjs && node site/test_lowpower.mjs && node site/test_edge_cases.mjs && node site/test_can_inject.mjs && node site/test_watchdog.mjs && node site/test_wwdg.mjs && node site/test_wwdg_window.mjs && node site/test_tim_capture.mjs && node site/test_qspi.mjs && node site/test_fpu.mjs && node site/test_fpu_irq.mjs && node site/test_mpu.mjs && node site/test_usb.mjs && node site/test_arduino_boards.mjs && node site/test_exti.mjs && node site/test_flash.mjs && node site/test_spi_flash.mjs && node site/test_board_matrix.mjs && node site/test_qspi_cdp.mjs && node site/test_browser.mjs",
|
|
72
|
+
"test:unit": "node site/test_stm32f4_api.mjs && node site/test_stm32f4_periph.mjs && node site/test_ws_bridge.mjs && node site/test_flow.mjs && node site/test_blinky.mjs && node site/test_blinky_f401.mjs && node site/test_blinky_f411.mjs && node site/test_blinky_f407g.mjs && node site/test_blinky_nucleo_f401.mjs && node site/test_blinky_nucleo_f411.mjs && node site/test_blinky_f429.mjs && node site/test_blinky_f407ve.mjs && node site/test_rx_interrupt.mjs && node site/test_component_led.mjs && node site/test_component_button.mjs && node site/test_component_pwm.mjs && node site/test_component_i2cregfile.mjs && node site/test_component_adc.mjs && node site/test_multi_instance.mjs && node site/test_fsmc_dcmi.mjs && node site/test_fsmc.mjs && node site/test_dcmi.mjs && node site/probe_freertos.mjs && node site/test_candemo.mjs && node site/test_lowpower.mjs && node site/test_edge_cases.mjs && node site/test_can_inject.mjs && node site/test_watchdog.mjs && node site/test_wwdg.mjs && node site/test_wwdg_window.mjs && node site/test_tim_capture.mjs && node site/test_qspi.mjs",
|
|
71
73
|
"test:bridge": "node site/test_ws_bridge.mjs",
|
|
72
74
|
"test:bridge:browser": "node site/test_bridge_cdp.mjs",
|
|
73
75
|
"test:flow": "node site/test_flow.mjs",
|
|
@@ -81,7 +83,9 @@
|
|
|
81
83
|
"test:wwdgwin": "node site/test_wwdg_window.mjs",
|
|
82
84
|
"test:timcap": "node site/test_tim_capture.mjs",
|
|
83
85
|
"test:lowpower": "node site/test_lowpower.mjs",
|
|
86
|
+
"test:standby": "node site/test_standby.mjs",
|
|
84
87
|
"test:qspi": "node site/test_qspi.mjs",
|
|
88
|
+
"test:eth:mock": "node site/test_eth_mock_model.mjs && node site/test_eth_mock_consumer.mjs && node site/test_periph_mock_consumer.mjs",
|
|
85
89
|
"test:fpu": "node site/test_fpu.mjs",
|
|
86
90
|
"test:fpuirq": "node site/test_fpu_irq.mjs",
|
|
87
91
|
"test:mpu": "node site/test_mpu.mjs",
|
|
@@ -100,7 +104,7 @@
|
|
|
100
104
|
"lint": "eslint site mcp tools index.mjs cli.mjs",
|
|
101
105
|
"format": "prettier --check .",
|
|
102
106
|
"format:write": "prettier --write .",
|
|
103
|
-
"build:wasm": "wasm-pack build stm32-periph-wasm --target web --out-dir ../site/vendor && rm -f site/vendor/.gitignore &&
|
|
107
|
+
"build:wasm": "wasm-pack build stm32-periph-wasm --target web --out-dir ../site/vendor && rm -f site/vendor/.gitignore && git checkout -- site/vendor/stm32f407.svd site/vendor/stm32f401.svd site/vendor/stm32f411.svd site/vendor/stm32f429.svd 2>/dev/null || true; command -v wasm-opt >/dev/null 2>&1 && wasm-opt -O3 site/vendor/stm32_periph_wasm_bg.wasm -o site/vendor/stm32_periph_wasm_bg.wasm || echo 'wasm-opt not found, skipping'",
|
|
104
108
|
"build:wasm:node": "wasm-pack build stm32-periph-wasm --target nodejs --out-dir pkg",
|
|
105
109
|
"build:wasm:opt": "wasm-opt -O3 site/vendor/stm32_periph_wasm_bg.wasm -o site/vendor/stm32_periph_wasm_bg.wasm",
|
|
106
110
|
"test:wasm": "node site/test_wasm_cpu.mjs && node site/test_flow_wasm.mjs && node site/test_audio_wasm.mjs && node site/test_wasm_multi.mjs && node site/test_lowpower_wasm.mjs && node site/probe_freertos.mjs && node site/test_doom_wasm.mjs"
|