Hit on the bench: mint-mac has no pyserial, and `pip install pyserial` is
refused outright by PEP 668 (externally-managed-environment) on Mint 22 /
Ubuntu 24.04 / Debian 12. A field diagnostic that needs a pip install on a
locked-down host is one you cannot run at the moment you need it -- which is
exactly when this tool is for.
Replaced minimateplus.SerialTransport with a ~30-line stdlib `termios` port,
the same approach bridges/mm_link.py and scratch/fake_unit.py already take in
this repo. Runs on a stock Python 3 anywhere.
Not a general SerialTransport replacement: no flow control, no parity options,
Linux/macOS only. Enough for a Micromate, which is 8N1 with no handshaking.
Verified end to end against a fake unit on a pty, dribbling responses in
64-byte pieces: 194 reads for 10,958 B, identity/state/setup-walk all correct,
and a 4,076 B event downloaded across 4 chunks at the exact expected length.
Also clarified --baud in the help: it applies to the USB-A/FTDI path, and is
ignored by the USB-B "PC" port, which is CDC-ACM and negotiates its own rate.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
Read-only: POLL, SERIAL, state, monitor status, the setup walk, and optionally
one event download. Never writes, erases, or changes monitoring state.
Exists because everything in micromate/{framing,protocol,client}.py is
verified against captures taken over USB on one firmware line (11.0CB). Two
things that cannot be verified that way:
- The modem path. An RX55/RV55 buffers up to ~1 s before forwarding, so one
logical response arrives as many small reads. The client reads to frame
completion rather than using read_until_idle's idle-gap detection, which
should be strictly more robust for this -- but that needed proving.
- The 11.0BD firmware line, which reports flags=0x03, a shorter model string,
and a 0x1C block 4 bytes longer. All inference from one 2026-09-23 sweep
whose captures never landed in the repo. The tool says so loudly when it
meets one, and flags an impossible battery voltage as the signature of the
from-the-end offset bug.
Run it over both paths and diff; anything differing beyond timings is a
finding. It counts reads and bytes per transport, because a higher read count
for the same bytes IS the buffering, made visible.
Smoke-tested against a scripted TCP unit replaying captured response bytes in
37-byte dribbles: 289 reads to carry 10,958 B, every frame reassembled, a
4,076 B event downloaded across 4 chunks with the assembled length exact.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL