Skip to content

About

The radio-application layer remade in Rust: Wi-Fi CSI radar (presence/motion), LoRa point-to-point over lora-phy, BLE provisioning and telemetry over trouble-host, Wi-Fi station/AP lifecycle and ESP-NOW framing — every frame mID-signed. Memory safe, no_std core.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Repository files navigation

In The Wild with 366 Active Installs

FREE RAG Converter Online -- RAGconverter.com

rusty_esp_signal

Remade With Rust By Mata Network crates.io docs.rs License: MIT OR Apache-2.0

Radios and sensing for the Janus ESP32 family: Wi-Fi station policy, provisioning a device that has no network yet, a peer-to-peer link for chips with no access point, long-range radio, presence from channel state, and a millimetre-wave radar. Pure Rust, no C, no FFI, no_std by default.

  • A device with no network can still be given one. A browser hands an ESP32 its network over Bluetooth, on a page with no app and no server, inside an encrypted session that a setup code unlocks (SPAKE2+, the device proving its did:mata): the passphrase never crosses the air in the clear and never reaches a server, a log, or a command line. Verified from Chrome on an ESP32-S3 and an ESP32-CAM: a whole session costs the device 0.27 s on the S3 and 0.82 s on the original ESP32, and the board joins in about a second.
  • Presence from the Wi-Fi channel itself, judged against a labelled public capture rather than our own recording: an empty room reads 17.4% occupancy and a walking person 86.1%, with a held-out pair at 60.8%.
  • A link where there is no access point. Peer-to-peer framing sized to fit: 227 bytes of payload inside a 250-byte datagram, with hello, accept and confirm at 84, 100 and 18 bytes.
  • The radar's own documentation is wrong, and the tests say where. Field offsets in the vendor datasheet do not match the vendor's tool; ours follow the wire.

What has run on hardware

what measured
the setup session over Bluetooth, from Chrome (XIAO ESP32-S3, trouble-host) the device's time 0.27 s a session (Start 260 ms); joined in 995 ms, restarted without Bluetooth, the camera page on its token
the same on the ESP32-CAM (Bluedroid) 0.82 s a session (Start 695-790 ms, the portable P-256 path); a mistyped passphrase offers setup again; the page 200 on its token, 403 without
refusals, from an independent central (tools/setup_central.py) a wrong code, another device, a replayed session and a second writer refused; five wrong codes lock the window, and on the next power-on one more guess
provisioning over Bluetooth (the unencrypted version, now retired) joined in 7.5 s; the reboot joins alone in 9.5 s with no Bluetooth
the identity behind it the same did:mata held across six reflashes
the advertisement budget 31 bytes, which is what forced the name and service layout
a failed join must not spend the modem — a device that cannot join has to stay askable
a station on the open MAC (rusty_esp_signal-open, XIAO ESP32-S3) a WPA2 join, DHCP, 100/100 pings, the camera page and 1,500 stream frames; heap at radio start 53 KB on the blob, 0.1 KB here
an access point on the open MAC a laptop joined as 802.11n (65 Mbit/s), through power save, group-key rotation and re-association; the camera cell hosting it took a signed 538 KB update over its own network
the link on raw frames on the open MAC 1,000 of 1,000 round trips, three runs, against esp-radio's ESP-NOW on an ESP32-CAM; a signed 540 KB update through a relay in 35–41 s; a laptop streaming at 14.92 fps from the same radio meanwhile

Known gaps, stated plainly: channel-state presence is verified against captures and against the host, not on a chip; S1 as written (C6 to C6) has not run, for want of C6 boards. The ledger says so rather than implying otherwise.

The open MAC

rusty_esp_signal-open (off by default) is a station, an access point and the link on raw frames for the ESP32-S3, with no esp-radio. Images built on it carry no C except the PHY: Espressif's libphy, 18 members, 33.5 KB, which brings the radio up, calibrates it and tunes it. Our code calls ten of its functions and none that sets a transmit power or a regulatory table. The transmit power is capped where esp-radio caps it, 5 dBm, through the PHY's own init data (the vendored esp-phy's phy_max_tx_power, quarter dBm; ESP_PHY_CONFIG_PHY_MAX_TX_POWER = "80" for ESP-IDF's 20 dBm), so a firmware moving from esp-radio transmits as it did. The umbrella's tools/e6-phy.py checks all three for every open-MAC image. Not Wi-Fi certified.

Every number, with the run that produced it: docs/LEDGER.md.

Using it

use rusty_esp_signal::prelude::*;

use rusty_esp_signal::provision::Env;
use rusty_esp_signal::setup::Reset;
use rusty_esp_signal::wifi::{Action, Event};

// The owner's settings, the identity store, randomness and the device key.
let env = Env { settings, identity, rng, signer };
let mut provisioner = Provisioner::new(StationPolicy::default(), devpub, Reset::PowerOn, now, env)?;

// A stored network is joined at once; without one, the setup window is open
// and the BLE backend routes the `setup` and `discover` characteristics here.
// A setup code unlocks the session; only then does a network go in.
if provisioner.boot(now).action == Action::Connect {
    let event = match wifi.join(provisioner.credentials().unwrap()) {
        Ok(()) => Event::Connected,
        // A refusal has to leave the device askable, not spent.
        Err(_) => Event::Disconnected,
    };
    provisioner.on_event(event, now);
}

Two tracks

track what it is this crate
A std on ESP-IDF — Wi-Fi, Bluetooth provisioning, the radar's serial port rusty_esp_signal-esp --features esp-idf
B no_std on esp-hal — the protocols, the detector, the framing rusty_esp_signal-core, default

0.3.1

Additions only; nothing 0.3.0 offered has changed.

  • rusty_esp_signal-esp: a station and an access point at once on esp-radio (hal::netstack::access_point_station_config, one radio, both halves built where WPA2 is decided), and a DHCP server that hands its clients the upstream lease's DNS servers (dhcp_server_with_dns_task), for a board relaying for its clients.
  • rusty_esp_signal-esp: BLE setup fixes found on a C6 -- ble::setup_address (a fresh random address per boot, so a central's stale per-address state cannot hide services) and ble::ANSWER_GRACE.
  • rusty_esp_signal-core: setup::page, the setup session over a device's own open network with no Bluetooth (feature setup-page, ~76 KB of flash).
  • The family siblings are taken by published version (core 0.1.2, dsp 0.1.1, mid-core 0.1.2), not by git.

0.3.0 is a breaking release

The provisioning service carries the setup session (setup and discover); the plaintext credentials write and the public scan are gone, and Provisioner is the session's GATT router over the stores a platform lends it.

-  let mut p: Provisioner = Provisioner::new(StationPolicy::default());
-  p.restore(credentials, now);
+  let env = Env { settings, identity, rng, signer };
+  let mut p = Provisioner::new(StationPolicy::default(), devpub, Reset::PowerOn, now, env)?;
+  p.boot(now);

A device takes a session once a setup code's verifier (setup.v) is in its settings, written at flash time (espino's provision --setup-code-out, or the portal). The page is docs/provision.html, its wasm rusty_esp_signal-web. 0.3.0 also carries the CSI work (breathing and a heart band, the presence record at version 2, the CSI stream, a fall as a shape in the wander) and the link's HMAC on the S3's SHA unit (sha-accel).

0.2.0 was a breaking release

EspNowLink no longer takes a lifetime parameter. esp-radio 1.0.0-beta.1 dropped it from EspNowSender and EspNowReceiver, and carrying one here would have claimed a borrow the type does not hold — it owns the halves.

-  let link: EspNowLink<'_> = EspNowLink::new(sender, receiver, peer);
+  let link: EspNowLink    = EspNowLink::new(sender, receiver, peer);

The whole signal set moves to 0.2.0 together, the way it has always published, even though only -esp broke.

The chip backends also move to the esp-hal 1.2 companion set, and the library's dependency pins are ranges now rather than =: a firmware must not mix companion sets, but it is the firmware that picks which, and an = pin in a library took that choice away from every consumer at once.

S1, as a firmware you can run

firmware/c6-s1-link is the C6 ↔ C6 kill test, self-driving: one source, two images, 1,000 authenticated ESP-NOW frames each way, loss / replay / bad-tag counters straight from Session::counters(), and an unadopted identity that must be refused.

It needs two boards, not three — what has to be turned away is an unadopted identity, not a third piece of silicon, so the initiator mints a second key and tries again. Same radio, same distance: a refusal cannot be blamed on range.

Part of Janus

Janus rebuilds the Espressif ESP32 and Arduino application portfolio as independent, memory-safe Rust packages — so a hardware maker can ship a device that the MATA home computer discovers, catalogs honestly, adopts under its own identity, and pays for. Ten packages, three layers, and the dependency direction never reverses.

layer packages
0 — the vocabulary rusty_esp_core · rusty_esp_dsp
1 — the functions rusty_esp_image · rusty_esp_video · rusty_esp_audio · rusty_esp_signal · rusty_esp_mid · rusty_esp_iroh
2 — the surfaces rusty_esp_arduino — the sketch facade · espino — the maker's CLI (not published)

Every package is host-verified against an external oracle and keeps a ledger in which no number appears without the run that produced it. Five of seven device profiles have now run their kill tests on real silicon, three of them over a Wi-Fi network the board hosts itself.

Also check out the rest of Remade With Rust — including rusty_alloc, the pure-Rust rebuild of mimalloc that these firmwares run on, and rusty_jpeg, the JPEG engine behind the camera path — and our sister project remade_ffmpeg_rs, a ground-up Rust rebuild of FFmpeg.

About Mata Network

Mata Network builds sovereign, self-hostable infrastructure. Remade With Rust is our open-source home for the permissively-licensed building blocks that work depends on.

License

MIT OR Apache-2.0, at your option. See LICENSE-MIT and LICENSE-APACHE.

About

The radio-application layer remade in Rust: Wi-Fi CSI radar (presence/motion), LoRa point-to-point over lora-phy, BLE provisioning and telemetry over trouble-host, Wi-Fi station/AP lifecycle and ESP-NOW framing — every frame mID-signed. Memory safe, no_std core.

Topics

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages