Files
trikkeSensors/tools/decode_binary.py
T

84 lines
2.8 KiB
Python

#!/usr/bin/env python3
"""Decode a validated or raw TRK1 byte stream into CSV."""
import argparse
import csv
from pathlib import Path
from trikke_protocol import (
CSV_COLUMNS,
PACKET_TYPE_METADATA,
Frame,
IntegrityTracker,
StreamParser,
sample_to_csv_row,
)
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("input", type=Path)
parser.add_argument("output", type=Path)
args = parser.parse_args()
stream = StreamParser()
frames: list[Frame] = []
with args.input.open("rb") as source:
while chunk := source.read(64 * 1024):
frames.extend(stream.feed(chunk))
metadata = next(
(frame.metadata for frame in frames if frame.packet_type == PACKET_TYPE_METADATA),
None,
)
if metadata is None:
print(
"No valid metadata frame found; "
f"trailing_partial_bytes={stream.buffered_bytes}"
)
return 2
args.output.parent.mkdir(parents=True, exist_ok=True)
sample_count = 0
integrity = IntegrityTracker()
with args.output.open("w", encoding="utf-8", newline="") as target:
writer = csv.writer(target)
writer.writerow(CSV_COLUMNS)
for frame in frames:
integrity.observe(frame)
if frame.packet_type == PACKET_TYPE_METADATA:
if frame.metadata is not None:
metadata = frame.metadata
continue
for sample in frame.samples:
writer.writerow(
sample_to_csv_row(sample, metadata, frame.loop_overrun_count)
)
sample_count += 1
print(
f"Decoded {sample_count} samples from {len(frames)} frames; "
f"startup_crc_rejects={stream.startup_crc_errors}, "
f"stream_crc_errors={stream.crc_errors}, header_errors={stream.header_errors}, "
f"skipped_nonframe_bytes={stream.skipped_bytes}, "
f"packet_gaps={integrity.packet_gap_count}, "
f"packet_resets={integrity.packet_reset_count}, "
f"sample_gaps={integrity.sample_gap_count}, "
f"sample_resets={integrity.sample_reset_count}, "
f"timing_anomalies={integrity.timing_anomaly_count}, "
"timestamp_saturation_frames="
f"{integrity.timestamp_saturation_frame_count}, "
f"accel_stale={integrity.accel_stale_count}, "
f"accel_overrun={integrity.accel_overrun_count}, "
f"gyro_stale={integrity.gyro_stale_count}, "
f"gyro_overrun={integrity.gyro_overrun_count}, "
f"dropped={integrity.final_dropped_sample_count}, "
f"acquisition_loop_overruns={integrity.final_loop_overrun_count}, "
f"trailing_partial_bytes={stream.buffered_bytes}; saved {args.output}"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())