Adds first-class support for the Raspberry Pi 5's WiFi chip (CYW43455 /
BCM43455c0 — the same 802.11ac wireless as the Pi 4 / Pi 3B+ / Pi 400, and the
chip with the most mature nexmon_csi support), plus a registry of the other
Nexmon-supported Broadcom/Cypress chips.
rvcsi-adapter-nexmon — new `chips.rs`:
- `NexmonChip` (Bcm43455c0, Bcm43436b0, Bcm4366c0, Bcm4375b1, Bcm4358, Bcm4339,
Unknown{chip_ver}) + `RaspberryPiModel` (Pi5/Pi4/Pi400/Pi3BPlus/PiZero2W/
PiZeroW) — Pi5/Pi4/Pi400/Pi3B+ → Bcm43455c0; PiZero2W → Bcm43436b0.
- `nexmon_adapter_profile(chip)` / `raspberry_pi_profile(model)` build the
per-device `AdapterProfile` (channels: 2.4 GHz 1-13 + 5 GHz UNII for dual-band;
bandwidths 20/40/80[/160]; expected subcarrier counts 64/128/256[/512]) that
`validate_frame` bounds CSI frames against.
- `NexmonChip::from_chip_ver` (0x4345 → Bcm43455c0, 0x4339, 0x4358, 0x4366,
0x4375 — best-effort; the raw `chip_ver` is always preserved) and `from_slug`
/ `RaspberryPiModel::from_slug` ("pi5", "raspberry pi 4", "bcm43455c0", ...).
- `NexmonCsiHeader::chip()`; `NexmonPcapAdapter` auto-detects the chip from the
packets' `chip_ver` and uses the matching profile, overridable via
`.with_chip(NexmonChip)` / `.with_pi_model(RaspberryPiModel)`; `.detected_chip()`.
rvcsi-runtime: `decode_nexmon_pcap_for(.., chip_spec)` (validate against a chip /
Pi model, drop non-conforming) + `nexmon_profile_for(spec)`; `NexmonPcapSummary`
gains `chip_names` + `detected_chip`; `CaptureSummary` gains `chip`.
rvcsi-cli: `record --source nexmon-pcap --chip pi5`; new `nexmon-chips`
subcommand (lists chips + Pi models, human or `--json`); `inspect-nexmon` and
`inspect` now print the resolved chip.
rvcsi-node (napi-rs): `nexmonDecodePcap` gains an optional `chip` arg;
`nexmonChipName(chipVer)`, `nexmonProfile(spec)`, `nexmonChips()`. @ruv/rvcsi
SDK + `.d.ts` updated (AdapterProfile / NexmonChipsListing interfaces, the new
fns, `chip` on CaptureSummary, `chip_names`/`detected_chip` on NexmonPcapSummary).
168 rvcsi tests pass (adapter-nexmon 22→28, cli 9→10), 0 failures, clippy-clean.
The synthetic test captures now stamp chip_ver = 0x4345 (the BCM4345 family chip
ID), so the chip-detection happy path is exercised end to end.
ADR-096, CHANGELOG, README, CLAUDE.md updated.
https://claude.ai/code/session_01CdYAPvRTjcch6YrYf42n1z
|
||
|---|---|---|
| .. | ||
| __test__ | ||
| src | ||
| Cargo.toml | ||
| README.md | ||
| build.rs | ||
| index.d.ts | ||
| index.js | ||
| package.json | ||
README.md
@ruv/rvcsi
Node.js bindings (napi-rs) for rvCSI — the edge RF sensing runtime: ingest WiFi CSI from files / Nexmon dumps, validate and normalize it, run reusable DSP, emit typed presence / motion / quality / anomaly events, and export temporal embeddings to an RF-memory store. See ADR-095 and ADR-096.
This package wraps the Rust crates in
v2/crates/rvcsi-*. The Rust side does all the work (parsing, validation, DSP, events, embeddings); this is a thin, safe JS surface — nothing crosses the boundary except validated/normalized objects (delivered as JSON the SDK parses for you).
Build
The native addon is produced from the rvcsi-node Rust crate:
# from v2/crates/rvcsi-node
npm install # installs @napi-rs/cli
npm run build # -> rvcsi-node.<triple>.node + binding.js + binding.d.ts
(cargo build -p rvcsi-node also compiles the addon as a cdylib; napi build
additionally emits the platform loader and .d.ts.)
Usage
const { RvCsi, inspectCaptureFile, eventsFromCaptureFile, nexmonDecodeRecords } = require('@ruv/rvcsi');
// One-shot: summarize a capture
const summary = inspectCaptureFile('lab.rvcsi');
console.log(summary.frame_count, summary.channels, summary.mean_quality);
// One-shot: replay a capture into events
for (const e of eventsFromCaptureFile('lab.rvcsi')) {
console.log(e.kind, e.timestamp_ns, e.confidence);
}
// Streaming
const rt = RvCsi.openCaptureFile('lab.rvcsi');
let frame;
while ((frame = rt.nextCleanFrame()) !== null) {
// frame.validation is 'Accepted' | 'Degraded' | 'Recovered' — never 'Pending'/'Rejected'
if (frame.quality_score > 0.5) { /* ... */ }
}
const events = rt.drainEvents();
console.log(rt.health());
// Decode raw Nexmon records (the napi-c shim format) straight from a Buffer
const fs = require('fs');
const frames = nexmonDecodeRecords(fs.readFileSync('nexmon.bin'), 'wlan0', 1);
TypeScript types ship in index.d.ts (CsiFrame, CsiWindow, CsiEvent,
SourceHealth, CaptureSummary, ValidationStatus, CsiEventKind, ...).
What's here vs. not (yet)
Implemented: file/replay + Nexmon sources, the validation pipeline, the DSP
stages, window aggregation + the event state machines, RuVector-style RF-memory
export. Not yet wired into this addon: live radio capture, the WebSocket daemon,
and the MCP tool server — those come with rvcsi-daemon / rvcsi-mcp.