87 lines
3.9 KiB
Markdown
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.
|