Files
trikkeSensors/tools/decode_binary.py
T

73 lines
2.3 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_FLAG_TIMESTAMP_DELTA_SATURATED,
PACKET_TYPE_METADATA,
Frame,
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
timestamp_saturation_frame_count = 0
with args.output.open("w", encoding="utf-8", newline="") as target:
writer = csv.writer(target)
writer.writerow(CSV_COLUMNS)
for frame in frames:
if frame.flags & PACKET_FLAG_TIMESTAMP_DELTA_SATURATED:
timestamp_saturation_frame_count += 1
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"timestamp_saturation_frames={timestamp_saturation_frame_count}, "
f"trailing_partial_bytes={stream.buffered_bytes}; saved {args.output}"
)
return 0
if __name__ == "__main__":
raise SystemExit(main())