- Rust 57.2%
- TypeScript 17.7%
- Python 16.3%
- JavaScript 3.7%
- Svelte 3.7%
- Other 1.3%
Validation: none (documents). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> |
||
|---|---|---|
| .claude/skills | ||
| apps | ||
| boards | ||
| crates | ||
| daveos@cca30acecb | ||
| docs/design | ||
| examples | ||
| oracle | ||
| plan | ||
| sil | ||
| starters | ||
| tests | ||
| tools | ||
| .gitignore | ||
| .gitmodules | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CLAUDE.md | ||
| clippy.toml | ||
| README.md | ||
| rust-toolchain.toml | ||
| rustfmt.toml | ||
rusty-daveos
An embedded-Rust port of DaveOS, a
cooperative run-to-completion scheduler with fixed storage, optional logging,
a typed command system and portable services (SPI/I2C HAL, console, watchdog,
A/B boot + OTA, OTP, storage, networking), targeting STM32 Nucleo boards and a
POSIX host. The C++ reference is pinned as the daveos/ submodule and used as
a behavioral oracle.
Status (2026-09-27)
- Host parity: the Rust
hello-host,console-hostandsystem-hostexamples reproduce the C++ reference transcripts byte-for-byte after timestamp masking (tests/oracle, 23/23 scenarios, strict mode in the gate). - Crates (
no_std, noalloc): foundation, core (scheduler, events, timers, logging, commands, application, yield), util, hal (+ scripted fakes), console, watchdog, boot, update, otp (+ flash emulator), storage (own FAT12/16/32), net (smoltcp), drivers;stdplatforms: fake-time and real-time host with file-backed flash/OTP/block devices. - Boards (
boards/, own workspace on embassy-stm32 as HAL + stm32-metapac):nucleo-h563console firmware with feature slotsuart,health,usb,net,tcp, bootloader,ota(50.8 KB default, 113 KB with everything),bootloader-h563(20.7 KB) with slot A/B images,factory.hexand OTA packages, and thenucleo-h755port (M7 firmware + sleeping M4 image). Nothing has run on hardware yet; bring-up checklists are inboards/README.md. - Web: firmware runs in a browser tab.
daveos-platform-webimplements the platform over a ten-function wasm ABI;sil-can-wasm(156 KB) andblinky-wasm(90 KB) arewasm32-unknown-unknownimages; the bench (tools/bench, a static site of about 800 KB with both images) lists an image's ports and lets you watch, drive and perturb each one. The SIL suite judges the wasm image exactly as it judges the native binary (35/35 in both modes, a fleet of ten devices on one bus included). - Tooling:
tools/daveos(ported Python tools, byte-identical goldens),tests/hil(probe-rs + watcher hardware suite with a PTY-simulated mode), skillsdaveos-reference,watcher,nucleo.
SIL CAN node (first application)
apps/sil-can is a DaveOS device on the host build (and, as
apps/sil-can-wasm, a wasm image): a 1 Hz HEARTBEAT, LIGHT_CMD → virtual LED
- LIGHT_STATE, and four telemetry messages at 1 Hz, the heartbeat's rate:
VOLTAGE, LIGHT_STATUS, TEMPERATURE and LEVEL (the fluid
level of a container), with SIM_CTRL fault injection for the three sensors,
all on a virtual CAN bus (
vcanbus, SLCAN over TCP, since macOS has no socketcan).
A device is told who it is when it starts: --device-id (0 to 127) is added
to the base of every CAN identifier it sends and accepts (device 5 beats at
0x105 and takes LIGHT_CMD at 0x205), so many devices share one bus;
--crc is the image CRC it reports. Both are on the bus in IDENTITY and on
the console (identity status). A board reads the two values from its
hardware; a simulation is given them. Design: docs/design/sil-fleet.md
(wave 7; it amends docs/design/can-sil.md); catalog: sil/catalog.json;
the device's observable contract: apps/sil-can/README.md.
cargo build -p daveos-vcan -p sil-can
target/debug/vcanbus & # bus on 127.0.0.1:29000
target/debug/sil-can --no-stdin --device-id 5 --crc 0xC0FFEE & # a device; console on 127.0.0.1:29001
uv run --project tools/sil-ui sil-ui serve --device-id 5 # UI on http://127.0.0.1:8765/
uv run --project tests/sil pytest tests/sil --sil # SIL suite against the real binaries
uv run --project tools/sil sil-run --build launches the stack under watcher
with transcripts; sil-cansniff/sil-cansend/sil-node are the CLI tools
(--device-id on each; sil-cansniff --senders says which node sent a
frame, which the broker reports on request: #senders).
Ten devices on one bus:
uv run --project tools/sil sil-run --build --devices 10 # ids 0-9, nodes sil-can-<id>, a CRC each;
# prints the bus, every console address and
# the command that puts the fleet on the bench
SIL_REAL=1 tests/sil/check.sh # the suite, fleet tests included, native
SIL_WASM=1 tests/sil/check.sh # the same with ten wasm images under Node
Web bench (firmware and UI as one static site)
A lab bench for firmware in the browser: put a target on it (a wasm
image, a native process or board behind the bridge, a recording), and every
port the target declares (UART, CAN, GPIO, or a kind the bench has never
seen) gets the same three verbs: peek (watch), poke (act as a
legitimate peer) and perturb (inject faults). Application views add
domain widgets when they match (the SIL CAN dashboard), scenarios are
scripted poke/expect checks that run against whatever is on the bench, and
workspaces are arrangements you compose. Design and frozen interfaces:
docs/design/web-bench.md; user guide: tools/bench/README.md.
tools/bench/build.sh # images + site in build/bench/site
uv run tools/bench/serve.py build/bench/site # http://127.0.0.1:8785/
# ?image=sil-can-wasm&workspace=view.sil-can the SIL CAN dashboard on live firmware
# ?image=sil-can-wasm&workspace=view.scenarios 24 scenarios; "Run all" runs the 23 that
# leave the machine running
# ...&args=--device-id 5 --crc 0xC0FFEE start arguments (also in the sidebar's form)
# ?image=blinky-wasm a second application: console, LED, button
# ?demo=1 a scripted target, no firmware
# the same UI on the native stack (watcher-based bridge; ports and their types in, a target out)
uv run --project tools/bench-bridge bench-bridge serve --ui build/bench/site --app sil-can \
--port tcp=uart:tcp:127.0.0.1:29001,newline=crlf,role=console \
--port can0=can:slcan:127.0.0.1:29000,target=sil-can,catalog=sil/catalog.json
# a native fleet as one target: `sil-run --devices 10` prints the bridge command for its fleet
# (a console port per device with device=<id>, one bus without target=) and the address to open.
# The SIL CAN view lists the devices with their nodes; selecting a row shows that device, its
# console and its node in every widget, and scenarios run "On device" of your choice.
SIL_WASM=1 tests/sil/check.sh # the SIL suite against the wasm image
tools/orch/verify.sh --web # only the web tiers of the gate
The scheduler is unchanged: Platform::idle blocks in a host import, and
the host chooses how (a worker blocked in Atomics.wait when the page is
cross-origin isolated, JavaScript Promise Integration otherwise, a virtual
clock in tests). The host owns the clock, so the bench can pause and scale
machine time, and hides host stalls from the firmware. Any static host can
serve the site; with the two isolation headers (serve.py sends them) the
blocking strategy is used.
On a busy host the machine clock keeps pace with the wall clock (measured: rate 0.9999 under ten CPU spinners on ten cores, like the native device); a host that cannot run the firmware at the asked speed makes machine time run behind instead of tripping the firmware's health checks.
Several wasm machines on one bus: the bench page still runs one machine with
a bus of its own. That ten images can share one bus and one clock (real time,
and deterministic virtual time) without any change to the image or the ABI,
and survive stalls of the host, is proven under Node by tests/web/fleet (a
coordinator prototype, with measurements); nothing of it is verified in a
browser. Moving it into the bench, mixing simulated devices with boards
on one bus, and a plant model that drives the sensors are designed, not
built: docs/design/sil-fleet.md ("Fleets", "Coordination layer", "Plant
model").
Build and verify
git submodule update --init # reference only; no vendor submodules needed
cargo build --workspace
tools/orch/verify.sh --boards # fmt, clippy (incl. logging-off), tests, thumb no_std,
# wasm images, docs, layering + starters, tools,
# simulated HIL, SIL, images under Node, bench, bridge,
# oracle diffs, boards/check.sh
Every check script (tests/sil/check.sh, tools/bench/check.sh, ...)
builds what its tests run against first (--no-build skips that). A test
that needs an image or a binary that is missing or older than its sources
says so and names the command that builds it: run by hand it skips, in the
gate (DAVEOS_REQUIRE_ARTIFACTS=1, set by verify.sh) it fails.
First hardware session (NUCLEO-H563ZI)
probe-rs list # note the ST-LINK serial
cd boards && cargo console # flash + run the console firmware (see boards/README.md)
cp tests/hil/h563.toml.example build/hil.toml # set probe_serial and features
uv run --project tests/hil pytest tests/hil/h563 --hil --hil-config build/hil.toml
boards/README.md has the per-feature checklists (UART, USB on CN13, Ethernet
on CN14, A/B boot and OTA) and tests/hil/README.md the harness details.
How work is organized
- The loop and git rules:
plan/README.md; architecture:plan/ARCHITECTURE.md; conventions:plan/CONVENTIONS.md; tasks:plan/tasks/; journal:plan/ORCHESTRATOR-LOG.md. - Applications and bench:
docs/design/can-sil.md,docs/design/web-bench.md,docs/design/sil-fleet.md. - Core design:
docs/design/core.md(adversarial review and resolutions indocs/design/core-review.md); STM32 stack decision:docs/design/stm32.md. - Board:
uv run --no-project tools/orch/status.py.