ruview @ v0.6.2-esp32
integrity
- size
- 41.3 MiB
- downloaded
- last checked
release notes
First firmware release of the ADR-081 Adaptive CSI Mesh Kernel, plus the Timer Service stack-overflow regression fix caught by on-device validation. Ships both 8 MB and 4 MB variants from CI.
Highlights
- 5-layer adaptive CSI kernel (Radio Abstraction → Adaptive Controller → Mesh Plane → Feature State → Rust handoff) — swap radio silicon without touching the Rust signal/ruvector/mat crates
- 60-byte
rv_feature_state_tpacket (magic0xC5110006) replaces raw CSI as the default upstream — ~99.7 % bandwidth reduction (300 B/s at 5 Hz vs ~100 KB/s raw) - Mesh sensing plane (
rv_mesh) with 4 roles, 7 message types, CRC32-integrity envelope — HEALTH every 30 s, ANOMALY_ALERT on state transitions - Host-testable pure decision policy (
adaptive_controller_decide.c) — 33/33 assertions,decide()at 3.2 ns/call - 4 MB variant (ESP32-S3 SuperMini) now built in CI alongside the 8 MB default
Validated on real hardware
ESP32-S3 QFN56 rev v0.2 (MAC 3c:0f:02:e9:b5:f8), 38 s continuous run after flash:
App version: 0.6.2✅- 0 stack-overflow / panic / reboot markers
- 28
adaptive_ctrlmedium ticks, steady state, no drift - 149
rv_feature_state_temissions at ~5 Hz on earlier 30 s validation - Real WiFi CSI: 37 – 72 pps yield, RSSI -43 to -57 dBm
Fixes
| Fix | Detail |
|---|---|
| Timer Svc stack overflow (new) | emit_feature_state() + stream_sender network I/O runs inside FreeRTOS Timer Svc; ESP-IDF default 2 KiB stack overflows ~1 s after boot. Bumped CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=8192 in all three sdkconfig.defaults*. Follow-up: move heavy work out of the timer daemon. |
adaptive_controller.c implicit decl (#404) |
fast_loop_cb called emit_feature_state() before its static definition, tripping -Werror=implicit-function-declaration. Added forward declaration. |
provision.py esptool v5 compat (#391) |
write-flash (hyphenated) in dry-run hint for esptool ≥ 5. |
provision.py silent NVS wipe (#391) |
Now refuses to run without --ssid, --password, --target-ip unless --force-partial is passed; --force-partial prints which keys will be wiped. |
Defensive node_id capture (#232, #375, #385, #386, #390) |
csi_collector_init() now captures g_nvs_config.node_id once into a module-local; a canary WARN fires on divergence. |
CI change
firmware-ci.yml is now a matrix job building both variants in parallel and uploading variant-named artifacts — 6-binary releases no longer need local ESP-IDF.
Installing
Six binaries are attached below. The default flash layout for ESP32-S3 8 MB:
esptool.py --chip esp32s3 --port /dev/ttyUSB0 --baud 460800 \
--before default_reset --after hard_reset \
write_flash -z --flash_mode dio --flash_freq 80m --flash_size 8MB \
0x0 bootloader.bin \
0x8000 partition-table.bin \
0xf000 ota_data_initial.bin \
0x20000 esp32-csi-node.bin
For ESP32-S3 SuperMini 4 MB, use esp32-csi-node-4mb.bin at 0x20000 and partition-table-4mb.bin at 0x8000 (reuse the same bootloader and OTA data).
After flash, provision WiFi + target (replaces the full csi_cfg NVS namespace — pass all creds at once):
python firmware/esp32-csi-node/provision.py \
--port /dev/ttyUSB0 \
--ssid <SSID> --password <PSK> --target-ip <DEST_IP>
Artifacts
| File | Size | Target |
|---|---|---|
esp32-csi-node.bin |
1.06 MB | 8 MB app (flash @ 0x20000) |
esp32-csi-node-4mb.bin |
851 KB | 4 MB app (flash @ 0x20000) |
bootloader.bin |
18 KB | Both (flash @ 0x0) |
partition-table.bin |
3 KB | 8 MB layout (flash @ 0x8000) |
partition-table-4mb.bin |
3 KB | 4 MB layout (flash @ 0x8000) |
ota_data_initial.bin |
8 KB | OTA data (flash @ 0xf000) |
Compatibility
- ESP-IDF: v5.4
- Target: ESP32-S3 (Xtensa dual-core). Not supported: ESP32 (original), ESP32-C3 (single-core, can't run CSI DSP).
- Supersedes: v0.6.1-esp32
- Wire format:
rv_feature_state_tmagic0xC5110006is the new default upstream; raw ADR-018 CSI (magic0xC5110001) remains available as a debug stream gated by the channel plan.
Reference
- ADR-081 — Adaptive CSI Mesh Firmware Kernel (
docs/adr/ADR-081-adaptive-csi-mesh-firmware-kernel.md) - Full changelog entry:
CHANGELOG.md#v062-esp32 - Source tag:
ae40e2b
download
curl -fL -o v0.6.2-esp32.zip https://ratatoskr.space/pkg/ruview/v0.6.2-esp32.zip
printf '%s %s\n' '8d1eb78a94b5d3934cfcdae6296d4355e247291f23ec86bf874a96fc4fae8e99' 'v0.6.2-esp32.zip' | sha256sum -c -
$url = "https://ratatoskr.space/pkg/ruview/v0.6.2-esp32.zip"
$out = "v0.6.2-esp32.zip"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "8d1eb78a94b5d3934cfcdae6296d4355e247291f23ec86bf874a96fc4fae8e99") { throw "sha256 mismatch" }
curl -fL -o v0.6.2-esp32.tar.gz https://ratatoskr.space/pkg/ruview/v0.6.2-esp32.tar.gz
printf '%s %s\n' '3a43655faff864b84d9d7734038ff192456339e327d93b7fbd31f6b94fe0ffdc' 'v0.6.2-esp32.tar.gz' | sha256sum -c -
$url = "https://ratatoskr.space/pkg/ruview/v0.6.2-esp32.tar.gz"
$out = "v0.6.2-esp32.tar.gz"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "3a43655faff864b84d9d7734038ff192456339e327d93b7fbd31f6b94fe0ffdc") { throw "sha256 mismatch" }
download via yggdrasil mesh
curl -fL -o v0.6.2-esp32.zip http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v0.6.2-esp32.zip
printf '%s %s\n' '8d1eb78a94b5d3934cfcdae6296d4355e247291f23ec86bf874a96fc4fae8e99' 'v0.6.2-esp32.zip' | sha256sum -c -
$url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v0.6.2-esp32.zip"
$out = "v0.6.2-esp32.zip"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "8d1eb78a94b5d3934cfcdae6296d4355e247291f23ec86bf874a96fc4fae8e99") { throw "sha256 mismatch" }
curl -fL -o v0.6.2-esp32.tar.gz http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v0.6.2-esp32.tar.gz
printf '%s %s\n' '3a43655faff864b84d9d7734038ff192456339e327d93b7fbd31f6b94fe0ffdc' 'v0.6.2-esp32.tar.gz' | sha256sum -c -
$url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v0.6.2-esp32.tar.gz"
$out = "v0.6.2-esp32.tar.gz"
Invoke-WebRequest -Uri $url -OutFile $out
if ((Get-FileHash $out -Algorithm SHA256).Hash.ToLowerInvariant() -ne "3a43655faff864b84d9d7734038ff192456339e327d93b7fbd31f6b94fe0ffdc") { throw "sha256 mismatch" }
| artifact | format | size | hashes |
|---|---|---|---|
| v0.6.2-esp32.zip | zip | 41.1 MiB |
blake3-24 684d135755c06687d5c66a4b2a8044fc9f94c80105058672
sha256 8d1eb78a94b5d3934cfcdae6296d4355e247291f23ec86bf874a96fc4fae8e99
sha1 242c2b416520e21c9f11848af3237a9117e000b6
|
| v0.6.2-esp32.tar.gz | tar.gz | 39.9 MiB |
blake3-24 960e226f52ba33719ddb87f487591d1a02e345d9cee4849d
sha256 3a43655faff864b84d9d7734038ff192456339e327d93b7fbd31f6b94fe0ffdc
sha1 37142135476c48fcba4c040ac8473490accb078d
|
install
http_archive(
name = "ruview",
urls = ["https://ratatoskr.space/pkg/ruview/v0.6.2-esp32.tar.gz"],
integrity = "sha256-OkNlX6/4ZLhNnXc0A4/xkkVjOeMn2Tt/vTH2uU/g/9w=",
strip_prefix = "ruview-v0.6.2-esp32",
)
.url = "https://ratatoskr.space/pkg/ruview/v0.6.2-esp32.tar.gz",
install via yggdrasil mesh
http_archive(
name = "ruview",
urls = ["http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v0.6.2-esp32.tar.gz"],
integrity = "sha256-OkNlX6/4ZLhNnXc0A4/xkkVjOeMn2Tt/vTH2uU/g/9w=",
strip_prefix = "ruview-v0.6.2-esp32",
)
.url = "http://14cc7d57b5e70f679b851fe5b272ce17c70632ff4beb5b35ab64bc706b2485af.pk.ygg/pkg/ruview/v0.6.2-esp32.tar.gz",