73 lines
2.3 KiB
Python
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())
|