BobBot c8c4199c5c
ci / test (push) Canceled after 0s
ci / build-arm64 (push) Canceled after 0s
feat(ecs): slice 2 — MattonellaState register image + Mattonella model
- state.rs: ports of mattonella_state.py (569 L), _dac_setting.py and the
  RegisterField byte plumbing — full 0x6C register image (64 pixel bytes,
  globals 0x40-0x4B, pairwise finetune-DAC nibbles 0x4C-0x6B) with exact
  range checks and enum parsing (ChannelMode, CalibrationTime)
- mattonella.rs: port of mattonella.py (426 L) — DACInterface (enable bit 7
  + 7-bit value RMW), 20 class-level descriptors, pixel batch ops
  (power/frontend/adj/ctrl/mask/ftdac), calibrate, full-state read/write
- 9 integration tests; verified from_bytes(to_bytes(s)) == s round-trip
- fake data_server moved to tests/common and fixed to advance the
  subaddress on multi-byte reads/writes (consecutive registers)
- divergences D1-D5 documented in docs/porting-notes.md
- workspace: 30 tests green
2026-11-12 23:36:32 +00:00

innesco-rs

Rust clone of innesco (the IGNITE64 control/DAQ software, timespot/innesco on baltig). This repo is a separate clean-room-style port: the original Python/C repository is untouched, and its license/authorship is respected.

Deployment target: AMD Kria K26 SOM (Zynq UltraScale+ MPSoC, quad Cortex-A53, aarch64, Ubuntu 22.04) — the board buffering/timestamping the IGNITE64 detector data.

Layout

crate ported from status
innesco-protocol innesco/ecs/protocol.py ECS wire protocol (Read/Write/Ping, >BI headers) + TCP client
innesco-decoding innesco/decoding/csrc/decoding.c 13-byte frame decoder, DCO calibration, position map; golden tests
innesco-cli — ping, decode subcommands (zero-dependency)

Zero external dependencies (pure std): cross-compiling for arm64 needs no cross-linked C libraries, and release binaries are small (panic = "abort", LTO).

Build (x86_64 host)

cargo test --workspace                       # golden tests
cargo build --release                        # host binary
export CARGO_TARGET_DIR=/tmp/innesco-rs-target   # keep artifacts off NFS

Build for arm64 (Kria K26)

scripts/build-arm64.sh --run-tests           # static musl binary (recommended)
scripts/build-arm64.sh --gnu                 # dynamic, glibc (Ubuntu 22.04 on board)

The script bootstraps everything without root: rustup target add, a ziglang pip venv as cross linker (via cargo-zigbuild), then cargo zigbuild --release --target aarch64-unknown-linux-musl. Artifacts land in dist/aarch64-<musl|gnu>/innesco-cli.

Deploy to the Kria: scp dist/aarch64-musl/innesco-cli <board>:~/ && ssh <board> ./innesco-cli ping localhost 8888.

Porting notes

See docs/porting-notes.md for the Python/C → Rust mapping and the (deliberate) divergences from the C extension (64-bit arithmetic where the C overflows 32-bit, strict socket reads where Python truncated silently, skip-and-count instead of abort on malformed packets).

Open Points

(details agreed with Lucio 2026-11-12; user-editable — tell me what to focus on)

  1. Storage layer (after #3) — decisions taken: polars-rs for parquet I/O (feature parity with the notebooks) + S3/MinIO upload is crucial (no local storage on the board — data must be pushed out). Schema need not be byte-identical, but must keep the notebook query surface: columns address, ix, iy, quadrant, tot, adj_ctrl, period, integr_time, v_inj (grep of notebooks 02/04/05/06/07) and the file-path conventions (results/{date}/analog_power=*/dcos-*.parquet, dataset-tag-{n}.parquet — duckdb queries use SELECT *, so paths matter more than column order). Original: 185-line ParquetStorage thread (queue → parquet → S3).
  2. REST API (after #3): 7 endpoints in rest_api.py (/ping, /metrics, /state, PUT /chunksize, POST /tag, POST /daq, GET /dataset). Port: axum + tokio in a separate crate with feature flag (library stays dependency-free). /state and /daq depend on #3; the other four can be ported independently.
  3. Board/slow-control model — IN PROGRESS, slices 1-2 done:
    • ✅ slice 1: _fields.py (199 L) + board.py (89) + pixel.py (77) → crates/innesco-ecs (7 integration tests against a fake data_server, incl. RMW semantics and the crystal-config sequencer; two faithful-port findings documented in docs/porting-notes.md #7/#8).
    • ✅ slice 2: mattonella_state.py (569 L) + mattonella.py (426 L) + _dac_setting.py → state.rs (full 0x6C-byte register image with exact RegisterField serialization) + mattonella.rs (DACInterface, 20 mattonella descriptors, pixel batch ops, calibration, full-state I/O). 9 more tests; verified round-trip from_bytes(to_bytes(s)) == s.
    • next: (3) asic_state 626 L → (4) quadrant 502 L → (5) daq+DataProcessor 574 L. Mirror-1:1 first, type-state validation later.
  4. Real-board validation: no qemu here, no network to the boards. (a) A raw frame dump from a real acquisition (even small) → decoder validated on physical data as an official golden test — highest value, zero prerequisites. Lucio will try next week; reminder set for Wed 2026-11-18 09:00. (b) network access to a Kria running data_server → live innesco-cli ping + harmless I2C read (0x7E).
  5. CI runner — deprioritized (Lucio 2026-11-12): verified 2026-11-12 that no Actions runner exists on this Gitea and self-hosting is impossible here (no Docker daemon). Local scripts/build-arm64.sh --run-tests is the working CI substitute.
S
Description
Rust clone of innesco (IGNITE64 ECS protocol + frame decoder), arm64 builds for AMD Kria K26
Readme
96 KiB
Languages
Rust 97.1%
Shell 2.9%