60 lines
1.7 KiB
Python
60 lines
1.7 KiB
Python
#!/usr/bin/env python3
|
|
"""Summarize fixed-size hex frames from serial helper logs."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import collections
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
FRAME_RE = re.compile(
|
|
r"\b(?P<direction>RX|TX)(?:\s+cmd\s+0x[0-9A-Fa-f]{2})?"
|
|
r"(?:\s+fields\b.*?)?\s+"
|
|
r"frame\s+\d+\s+(?P<frame>(?:[0-9A-Fa-f]{2}\s*)+)(?:\s+\S.*)?$"
|
|
)
|
|
|
|
|
|
def frames_from_log(path: Path) -> list[tuple[str, str]]:
|
|
frames: list[tuple[str, str]] = []
|
|
for line in path.read_text(encoding="utf-8").splitlines():
|
|
match = FRAME_RE.search(line.strip())
|
|
if match:
|
|
direction = match.group("direction")
|
|
frame = " ".join(match.group("frame").upper().split())
|
|
frames.append((direction, frame))
|
|
return frames
|
|
|
|
|
|
def checksum_note(frame: str) -> str:
|
|
values = [int(part, 16) for part in frame.split()]
|
|
if len(values) != 6:
|
|
return ""
|
|
|
|
checksum = 0x5A
|
|
for value in values[:5]:
|
|
checksum ^= value
|
|
|
|
if checksum == values[5]:
|
|
return " checksum ok"
|
|
return f" checksum expected {checksum:02X}"
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="Count frames in capture logs.")
|
|
parser.add_argument("logs", nargs="+", type=Path)
|
|
args = parser.parse_args()
|
|
|
|
for log in args.logs:
|
|
frames = frames_from_log(log)
|
|
counts = collections.Counter(frames)
|
|
print(f"{log}: {len(frames)} frames, {len(counts)} unique direction/frame pairs")
|
|
for (direction, frame), count in counts.most_common():
|
|
print(f" {count:5d} {direction:<2} {frame}{checksum_note(frame)}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|