74 lines
2.2 KiB
Python
74 lines
2.2 KiB
Python
#!/usr/bin/env python3
|
|
"""Capture a line-oriented bare-metal UART stream with host timestamps."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import csv
|
|
import time
|
|
from pathlib import Path
|
|
|
|
import serial
|
|
|
|
|
|
def parse_args() -> argparse.Namespace:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--port", default="/dev/ttyUSB2")
|
|
parser.add_argument("--baud", type=int, default=115200)
|
|
parser.add_argument("--duration", type=float, default=60.0)
|
|
parser.add_argument("--output", type=Path, required=True)
|
|
parser.add_argument(
|
|
"--stop-text",
|
|
help="stop early after a line containing this text (duration remains a limit)",
|
|
)
|
|
return parser.parse_args()
|
|
|
|
|
|
def main() -> int:
|
|
args = parse_args()
|
|
args.output.parent.mkdir(parents=True, exist_ok=True)
|
|
|
|
line_count = 0
|
|
byte_count = 0
|
|
start_wall_ns = time.time_ns()
|
|
start_mono_ns = time.monotonic_ns()
|
|
deadline_ns = start_mono_ns + int(args.duration * 1e9)
|
|
|
|
with serial.Serial(args.port, args.baud, timeout=0.1) as uart, args.output.open(
|
|
"w", newline="", encoding="utf-8"
|
|
) as stream:
|
|
writer = csv.writer(stream)
|
|
writer.writerow(["host_monotonic_s", "host_unix_s", "uart_line"])
|
|
uart.reset_input_buffer()
|
|
|
|
while time.monotonic_ns() < deadline_ns:
|
|
raw = uart.readline()
|
|
if not raw:
|
|
continue
|
|
now_mono_ns = time.monotonic_ns()
|
|
now_wall_ns = time.time_ns()
|
|
byte_count += len(raw)
|
|
line = raw.decode("utf-8", errors="replace").rstrip("\r\n")
|
|
writer.writerow(
|
|
[
|
|
f"{(now_mono_ns - start_mono_ns) / 1e9:.9f}",
|
|
f"{now_wall_ns / 1e9:.9f}",
|
|
line,
|
|
]
|
|
)
|
|
line_count += 1
|
|
if args.stop_text and args.stop_text in line:
|
|
break
|
|
|
|
elapsed_s = (time.monotonic_ns() - start_mono_ns) / 1e9
|
|
print(
|
|
f"captured lines={line_count} bytes={byte_count} "
|
|
f"elapsed={elapsed_s:.3f}s output={args.output} "
|
|
f"start_unix={start_wall_ns / 1e9:.6f}"
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|