add framed binary telemetry transport

This commit is contained in:
Jay
2026-08-17 11:13:53 -04:00
parent a5c3087ee4
commit aceaa2b270
13 changed files with 1320 additions and 110 deletions
+81
View File
@@ -0,0 +1,81 @@
# TRK1 Binary Telemetry — Version 1
The binary stream is the shared transport and storage representation for USB,
BLE, and any later nonvolatile buffer. All multibyte integers and IEEE-754
float32 values are little-endian. Frames are self-identifying and may be split or
combined by an underlying byte transport.
## Frame header (36 bytes)
| Offset | Size | Field |
| ---: | ---: | --- |
| 0 | 4 | ASCII magic `TRK1` |
| 4 | 1 | Wire version (`1`) |
| 5 | 1 | Packet type: metadata `1`, samples `2` |
| 6 | 1 | Header size (`36`) |
| 7 | 1 | Record size (`0` or `20`) |
| 8 | 1 | Record count (`0` or 18) |
| 9 | 1 | Packet flags |
| 10 | 2 | Payload size |
| 12 | 4 | Monotonic packet sequence |
| 16 | 8 | Base ESP timer timestamp in microseconds |
| 24 | 4 | Cumulative samples lost to read failure, queue overflow, or output failure |
| 28 | 4 | Cumulative acquisition-loop overruns |
| 32 | 4 | IEEE CRC-32 |
CRC uses polynomial `0xEDB88320`, initial value `0xFFFFFFFF`, and final XOR
`0xFFFFFFFF`. It covers header bytes 431 followed by the complete payload. The
magic and stored CRC field are excluded.
Packet flag bit 0 means at least one sample timestamp delta saturated.
## Sample record (20 bytes)
| Offset | Size | Field |
| ---: | ---: | --- |
| 0 | 4 | Sample sequence |
| 4 | 2 | Timestamp delta from the preceding record, in 10 us units |
| 6 | 2 | Enclosure accel X raw (`int16`) |
| 8 | 2 | Enclosure accel Y raw (`int16`) |
| 10 | 2 | Enclosure accel Z raw (`int16`) |
| 12 | 2 | Enclosure gyro X raw (`int16`) |
| 14 | 2 | Enclosure gyro Y raw (`int16`) |
| 16 | 2 | Enclosure gyro Z raw (`int16`) |
| 18 | 1 | Raw ADXL345 `INT_SOURCE` |
| 19 | 1 | Raw L3G4200D `STATUS_REG` |
The first record has delta zero and uses the frame's base timestamp. Each later
timestamp is reconstructed by cumulatively adding its delta. A delta that cannot
fit is stored as `0xFFFF` and sets packet flag bit 0. Sample sequence gaps remain
detectable independently.
Mapped raw counts are authoritative. The original sensor-native axes can be
reconstructed because the mappings are lossless:
```text
accel native = (-enclosure_y, enclosure_x, enclosure_z)
gyro native = ( enclosure_x, enclosure_y, enclosure_z)
```
## Metadata payload (48 bytes)
Metadata frames repeat approximately every five seconds so a receiver may attach
midstream. The payload contains:
- Sample rate, accelerometer range, gyroscope range, and mapping/calibration flags
- Three accel offset float32 values
- Three accel counts/g float32 values
- Three gyro bias float32 values
- Nominal gyro mdps/LSB float32 value
A byte-stream receiver may begin inside an incomplete frame. It discards bytes
until a magic/header/CRC combination validates. Host tools report any rejection
before that first valid frame separately from CRC failures after synchronization.
## Buffering
Acquisition runs in a dedicated higher-priority task and writes complete samples
to a 128-entry RAM queue. The lower-priority output task batches up to eight
records per frame. At 100 Hz this queue represents about 1.28 seconds of
decoupling from a blocked transport. Queue overflow never overwrites an older
sample silently: sequence gaps and the cumulative lost-sample counter expose it.