wifi-densepose/firmware/esp32-csi-node/components/ruv_temporal/README.md

87 lines
3.9 KiB
Markdown

# `ruv_temporal` — ESP32-S3 on-device temporal head
ESP-IDF component implementing ADR-095 (#513). The Rust staticlib at
`src/lib.rs` wraps `ruvllm_sparse_attention` (vendored at
`vendor/ruvector/crates/ruvllm_sparse_attention`) and exposes a narrow
C ABI declared in `include/ruv_temporal.h`.
## Status
| Phase | Scope | State |
|-------|-------|-------|
| 4 — Scaffold | Cargo.toml, src/{lib.rs,window.rs,weights.rs}, include/ruv_temporal.h, CMakeLists.txt, .cargo/config.toml | **Done.** |
| 5 — Cross-compile | `cargo +esp build --release --target xtensa-esp32s3-none-elf` produces `libruv_temporal.a`. | **Blocked** — see below. |
| 6 — Wire from edge_processing.c | FreeRTOS task on Core 1, queue from adaptive_controller fast loop, push() in fast tick, classify() at 1 Hz, emit `0xC5110007` packet. | **Done** in `main/temporal_task.c` (no-op shim path verified by 8MB firmware build with feature off). |
| 7 — COM8 validation | Flash 8MB build with `CONFIG_CSI_TEMPORAL_HEAD_ENABLED=y`, soak ≥5 min, check no Tmr Svc / task_wdt overflow. | Pending board reattach. |
## Module map
| File | Purpose |
|------|---------|
| `src/lib.rs` | C ABI: `ruv_temporal_init / push / classify / destroy / kernel_self_test` |
| `src/window.rs` | `FrameRing` rolling buffer used by `ruv_temporal_push` |
| `src/weights.rs` | Loader-side mirror of host `wifi_densepose_temporal::weights`. Parses the `.rvne` blob format (magic `RVNE`, version 1, FP32/FP16, CRC32-IEEE). Bit-exact with the host crate; a blob produced by the host's `WeightBlob::serialize()` parses here byte-for-byte. |
| `include/ruv_temporal.h` | Public C header consumed by `main/temporal_task.c` |
| `shim.c` | Empty C shim for `idf_component_register` |
## Phase 5 blocker — esp toolchain rust-src bug
The system esp toolchain at `C:\Users\ruv\.rustup\toolchains\esp` has
no precompiled `core` for `xtensa-esp32s3-none-elf`. It requires
`-Z build-std=core,alloc`, but the bundled rust-src snapshot
(`esp` channel, nightly 2025-09-16) hits two known bugs when build-std
compiles `core`:
1. `library/portable-simd/crates/core_simd/src/simd/ptr/mut_ptr.rs`
`Copy` trait and `size_of` not in scope, ~16,000 errors.
2. `library/core` itself — "cannot resolve a prelude import",
"attributes starting with `rustc` are reserved", `concat!` macro
not found.
These are upstream Rust nightly snapshot regressions, not anything
this component is doing wrong. The fix is to refresh the esp toolchain
to a newer nightly:
```powershell
C:/Users/ruv/.cargo/bin/espup.exe install
# (re-source export-esp.ps1 / export-esp.sh after install)
```
`espup install` pulls the latest pinned esp Rust + LLVM. It is a
~1.5 GB download and ~5-10 min install. That step lands in the next
loop iteration of #513 implementation work.
## Build (once Phase 5 unblocks)
From this directory:
```bash
cargo +esp build --release --target xtensa-esp32s3-none-elf
```
Output:
`target/xtensa-esp32s3-none-elf/release/libruv_temporal.a`.
ESP-IDF's `idf.py build` will pick this up via `CMakeLists.txt`
`add_custom_command` runs the cargo build before
`idf_component_register` consumes the static library.
## C ABI summary
```c
esp_err_t ruv_temporal_init(const uint8_t *weights, size_t wlen,
uint32_t input_dim, uint32_t window_len,
uint32_t n_classes,
ruv_temporal_ctx_t **out_ctx);
esp_err_t ruv_temporal_push(ruv_temporal_ctx_t *ctx, const float *frame);
esp_err_t ruv_temporal_classify(ruv_temporal_ctx_t *ctx,
float *logits, uint32_t n_classes);
void ruv_temporal_destroy(ruv_temporal_ctx_t *ctx);
esp_err_t ruv_temporal_kernel_self_test(void);
```
Threading: caller is responsible. Per ADR-095 §3.3, the firmware will
spawn a single dedicated FreeRTOS task that owns the context and
serialises all calls — push() and classify() are not internally
synchronised.