Files
trikkeSensors/docs/binary-record-v1.md
T

4.9 KiB
Raw Blame History

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 sensor read failure or queue overflow
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. Both host tools report any frame carrying this flag instead of silently treating its reconstructed timestamps as exact.

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. Firmware ends the current packet before a delta exceeds the representable 655.35 ms range, making the next sample the exact base timestamp of a new packet. As a defensive encoder fallback, an unrepresentable delta 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:

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 512-entry RAM queue. The lower-priority output task batches up to eight records per frame. At 100 Hz this queue represents about 5.12 seconds of decoupling when the transport reports backpressure or failure accurately. A failed write retains and retries the same encoded packet rather than dequeuing more samples, so the queue accumulates the outage backlog. After reconnection, the oldest retained data is sent first. If the queue fills, acquisition drops new samples rather than overwriting older ones; sequence gaps and the cumulative lost-sample counter expose that permanent loss.

The shared transport state machine distinguishes three nonfatal states. RETRY means zero bytes were accepted and the complete frame may be submitted again. PENDING means the backend owns an in-flight frame, so firmware may only poll that transfer. COMPLETE permits the output task to reuse its packet buffer and consume more samples. This prevents a timeout after partial progress from causing an ambiguous whole-frame duplicate.

The direct USB Serial/JTAG backend atomically copies a complete frame into its TX ring, then polls a bounded transmit-drain wait. A timeout remains PENDING; it does not trigger resubmission. This closes the VFS/stdio path's silent-discard case for a connected host that stops draining.

USB drain is not end-to-end application delivery confirmation. A host process may attach after earlier frames have already left the endpoint, or fail after the endpoint accepts them. CRC and sequence checks make resulting loss visible, but an application acknowledgement and replay window are still required to guarantee receipt.

Receivers report bytes left in an incomplete trailing frame when capture ends. Those bytes cannot pass CRC validation and are not silently admitted as samples.