"""Parse `.tlog` files emitted by `mavproxy-listener`. `.tlog` is the standard MAVLink dialect dump format: each message is a 6-byte unix-microsecond timestamp followed by the wire bytes of the MAVLink frame. pymavlink ships `mavlogfile` which knows how to iterate this. This module exposes a small typed wrapper so per-scenario tests can: 1. Filter for the message types they care about. 2. Compute summary statistics (count per type, message-rate Hz, ratio of signed vs unsigned messages for NFT-SEC-03). 3. Attach the source `.tlog` path to the evidence bundler. Concrete iteration logic is owned by AZ-416 (FT-P-09-AP); AZ-406 commits to the public surface. """ from __future__ import annotations from dataclasses import dataclass from pathlib import Path from typing import Iterator @dataclass(frozen=True) class TlogMessage: timestamp_us: int msg_type: str signed: bool fields: dict[str, object] def iter_messages(tlog_path: Path) -> Iterator[TlogMessage]: """Iterate `.tlog` messages oldest-first. AZ-406 raises until AZ-416 fills in the pymavlink-backed iterator. """ raise NotImplementedError( "mavproxy_tlog_reader.iter_messages is owned by AZ-416 — " "AZ-406 supplies only the public surface." ) def count_by_type(tlog_path: Path) -> dict[str, int]: """Return ``{msg_type: count}`` for every distinct message type.""" counts: dict[str, int] = {} for msg in iter_messages(tlog_path): counts[msg.msg_type] = counts.get(msg.msg_type, 0) + 1 return counts