a5237bb3b4bf013eda438d33d686191bd2d85b27
4
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
b55e4e946a |
verify(micromate): 11.0BD confirmed on hardware -- every inference held
UM20147 read over USB by mm_client_check.py. The Thor firmware line was entirely inference until now, and two of its three differences were covered only by SYNTHESISED test frames. All three held: - flags = 0x03 identifies the line -> reported firmware_line="thor". That is only reachable if `10 03` in the flags position destuffs before indexing, since 0x03 is ETX -- so the escaped-flags case is confirmed too. - the model string is shorter -> reported "MM/ISEE/S" exactly. Anchoring the search on b"MM/" rather than a fixed span is what made this work. - the 0x1C block is 4 bytes longer with the extras TRAILING, so from-the-start offsets survive -> battery 3.55 V and a clock correct to the second. That last one is the one that mattered. Series III's from-the-end offsets would have given this unit 577.92 V, which is why mm_client_check watches for an impossible voltage: it is a free self-check on exactly the inference most likely to be wrong. Also clean: serial UM20147, 5 setups (factory.MMB -> test2.mmb), active setup test2.mmb, 15,000,000 B total and free, 21 reads / 2,165 B in. "One protocol stack drives the whole fleet regardless of firmware line" -- the headline finding of 2026-09-23 -- is now demonstrated by a working client rather than by matching response SUBs. Test and docstring claims downgraded from inference to confirmed where the hardware settled them, and left as synthesised-frame notes where it did not: the BEHAVIOUR is confirmed but raw BD bytes are still not in the repo. Added --capture DIR to mm_client_check: writes a raw_bw_*/raw_s3_* pair in the layout scratch/mm_frame_parse.py already reads, so a run on an unfamiliar unit becomes a test fixture without setting up a relay. Verified by round-tripping its own output through that parser: 28 frames, 0 bad checksums. Still not covered: a download from a BD unit (UM20147 had no events stored, so the chunk walk remains CB-only), raw BD fixture bytes, a monitoring unit, a nearly-full buffer, and the inbound call-home session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL |
||
|
|
0d6eb1621f |
verify(micromate): read client works on real hardware, both transports
Run against UM12947 by bridges/mm_client_check.py, read-only, over the USB-B CDC-ACM port and over the RX55 to TCP :9034. THE WIRE BYTES ARE IDENTICAL ON BOTH PATHS -- 11,580 B in and 761 B out, to the byte, with matching identity, state and a 24-entry setup walk. The protocol does not care which physical layer it runs over, which is the thing the modem path needed to prove. Three findings, one of them a correction to my own prediction: 1. THE MODEM NEEDS FEWER READS, NOT MORE. 36 against USB's 83. The tool's banner claimed the opposite. The modem coalesces -- it buffers ~1 s then forwards one large TCP segment, where CDC-ACM delivers many small chunks. That is reassuring rather than alarming: the risk was a frame arriving split across reads, and the modem splits LESS than USB does. Banner fixed to state the measured numbers instead of a guess. 2. ~0.65 s PER ROUND TRIP over cellular, independent of payload size. A 1,024 B chunk and a 16 B state read cost the same. list_setups() takes 16.05 s over the modem against 0.46 s over USB, for 24 commands. This is the number that matters for SFM's design: over cellular, minimise round trips, not bytes. Enumerating setups costs 16 s -- cache it, never refresh it on a timer. A 13 KB event is 14 chunks ~ 8.4 s of latency against ~0.03 s of data, which makes the unconfirmed single-request 0x5A streaming mode worth its two-minute bench test on its own. 3. THERE IS A RECORD-TYPE FIELD: 0x0C content[11], 0x07 waveform, 0x08 histogram. The reference says no type field is known and that the type must be carried out of the chain walk. Found by diffing the six bench events' 0x0C records against their known types -- exactly one byte separates the groups and is constant within each -- then confirmed by predicting the right suffix for 6 of 6 on a blind re-run. Six events split 4/2 is thin evidence for a byte that could be a counter or a channel count, so it is recorded as a strong candidate, not settled, and mm_client_check keeps a fallback: it tries the other suffix on failure and says when the guess was wrong. Also flagged: the reference's claim that the type comes from SUB 0x0A's length is not visible in the download capture, where 0x0A is a standalone monitor-log walk after the last chain entry, not a per-event probe. END TO END: all six bench events assembled by read_event_file() from captured 0x5A responses decode with the existing codec -- 4 waveforms at 12,288 / 12,288 / 12,288 / 8,192 samples and 2 histograms. No new codec work needed; /db/import/idf_file ingests a directly downloaded event unchanged. Not covered: 11.0BD (still pure inference), a monitoring unit, a nearly-full buffer, and the inbound call-home session. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL |
||
|
|
f7d9a1d9cb |
tooling(micromate): drop the pyserial dependency from mm_client_check
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 |
||
|
|
c7ffdab570 |
tooling(micromate): mm_client_check -- exercise the read client on real hardware
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
|