• Rust 57.2%
  • TypeScript 17.7%
  • Python 16.3%
  • JavaScript 3.7%
  • Svelte 3.7%
  • Other 1.3%
Find a file
Thomas Tu be9f844672 Design: the CRC is the firmware image's CRC (confirmed by the user); log the push
Validation: none (documents).

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-28 20:20:44 -07:00
.claude/skills T45: boards/check.sh A/B steps; README and nucleo skill: A/B layout, artifacts, probe-rs factory provisioning 2026-09-26 12:53:47 -07:00
apps T89: cargo fmt 2026-09-28 09:10:34 -07:00
boards T52: log, verifier map, status verifying 2026-09-26 18:35:28 -07:00
crates T88: answers are never dropped; unread answers bound the connection 2026-09-28 09:10:34 -07:00
daveos@cca30acecb Wave 0: scaffold Rust workspace, coordination system, oracle and skills 2026-09-26 08:44:21 -07:00
docs/design Design: the CRC is the firmware image's CRC (confirmed by the user); log the push 2026-09-28 20:20:44 -07:00
examples Per-crate logging features, platform-fake drops hal, layering wired into the gate (T34 requests) 2026-09-26 10:54:39 -07:00
oracle Oracle: gate runs harness self-tests; docs point at manifest.toml 2026-09-26 09:00:06 -07:00
plan Design: the CRC is the firmware image's CRC (confirmed by the user); log the push 2026-09-28 20:20:44 -07:00
sil T79: catalog v2 JSON and verifiers (Python loader, generator, TypeScript loader) 2026-09-27 13:30:55 -07:00
starters T52: log, verifier map, status verifying 2026-09-26 18:35:28 -07:00
tests T94: tests/web: every image the tests load goes through the check (host/artifacts.mjs over freshness.ts); a missing or stale image skips a file with one test that says why, fails it in the gate; README paragraph 2026-09-28 11:14:30 -07:00
tools T94: tests/web: every image the tests load goes through the check (host/artifacts.mjs over freshness.ts); a missing or stale image skips a file with one test that says why, fails it in the gate; README paragraph 2026-09-28 11:14:30 -07:00
.gitignore Wave 0: scaffold Rust workspace, coordination system, oracle and skills 2026-09-26 08:44:21 -07:00
.gitmodules Wave 0: scaffold Rust workspace, coordination system, oracle and skills 2026-09-26 08:44:21 -07:00
Cargo.lock T89: sil-can and sil-can-wasm are 0.2.0; VERSION from the package; device_arg on the image's four ports 2026-09-28 09:10:34 -07:00
Cargo.toml Wave 6.0: web bench design, frozen interfaces, scaffolds, gate tiers 2026-09-26 22:32:41 -07:00
CLAUDE.md Wave 0: scaffold Rust workspace, coordination system, oracle and skills 2026-09-26 08:44:21 -07:00
clippy.toml Wave 0: scaffold Rust workspace, coordination system, oracle and skills 2026-09-26 08:44:21 -07:00
README.md README and design: T94 (stale artifacts, check scripts build first) 2026-09-28 11:29:07 -07:00
rust-toolchain.toml Wave 6.0: web bench design, frozen interfaces, scaffolds, gate tiers 2026-09-26 22:32:41 -07:00
rustfmt.toml Wave 0: scaffold Rust workspace, coordination system, oracle and skills 2026-09-26 08:44:21 -07:00

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-host and system-host examples reproduce the C++ reference transcripts byte-for-byte after timestamp masking (tests/oracle, 23/23 scenarios, strict mode in the gate).
  • Crates (no_std, no alloc): 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; std platforms: 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-h563 console firmware with feature slots uart,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.hex and OTA packages, and the nucleo-h755 port (M7 firmware + sleeping M4 image). Nothing has run on hardware yet; bring-up checklists are in boards/README.md.
  • Web: firmware runs in a browser tab. daveos-platform-web implements the platform over a ten-function wasm ABI; sil-can-wasm (156 KB) and blinky-wasm (90 KB) are wasm32-unknown-unknown images; 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), skills daveos-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 in docs/design/core-review.md); STM32 stack decision: docs/design/stm32.md.
  • Board: uv run --no-project tools/orch/status.py.