tooling(micromate): --event selects what to download, incl. 'largest'
The tool downloaded only the first event, which on UM20147 is a 4,796 B histogram -- so it could not reach the 72,560 B event that is the whole point of the uint32 chunk-offset change. --event takes a key in hex, 'first', 'largest' or 'all'. 'largest' is the one worth running on an unfamiliar unit, since it is what exercises offsets past 64 KB; the output flags any event over 64 KB as carrying into params[1], and prints the chunk count so a 71-chunk walk is visible as such. Selected events are downloaded from inside iter_events(), so the chain cursor sits where THOR's would -- non-selected events are walked past without a download, which the browse walk already attests is fine. Also: connect() returning nothing now prints a hint rather than just a bare timeout. /dev/ttyACM* numbering shifts whenever another CDC-ACM device is plugged in, and this cost a debugging session when the tool was aimed at a TMI-Seismo MCU instead of the Micromate. `ls -l /dev/serial/by-id/` names each device and is stable, so the hint says so. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
This commit is contained in:
+54
-19
@@ -232,6 +232,18 @@ def _decode(blob: bytes, key: bytes, record: bytes) -> None:
|
||||
print(f" saved to {out} for offline analysis")
|
||||
|
||||
|
||||
def _select(refs, which: str):
|
||||
"""Pick which events `--download` fetches."""
|
||||
which = which.strip().lower()
|
||||
if which == "first":
|
||||
return refs[:1]
|
||||
if which == "all":
|
||||
return refs
|
||||
if which == "largest":
|
||||
return [max(refs, key=lambda r: r.size)]
|
||||
return [r for r in refs if r.key_hex.lower() == which]
|
||||
|
||||
|
||||
def step(label: str, fn):
|
||||
"""Run one read, report how long it took and what it returned."""
|
||||
t0 = time.monotonic()
|
||||
@@ -259,7 +271,12 @@ def main() -> int:
|
||||
"and negotiates its own rate.")
|
||||
ap.add_argument("--timeout", type=float, default=10.0)
|
||||
ap.add_argument("--download", action="store_true",
|
||||
help="also download the first stored event (read-only)")
|
||||
help="also walk the event chain and download (read-only)")
|
||||
ap.add_argument("--event", default="first", metavar="WHICH",
|
||||
help="which event --download fetches: a key in hex "
|
||||
"(e.g. 055d4a83), 'first', 'largest', or 'all'. "
|
||||
"'largest' is the one worth running on an unfamiliar "
|
||||
"unit -- it is what exercises offsets past 64 KB.")
|
||||
ap.add_argument("--capture", metavar="DIR",
|
||||
help="also write a raw_bw_*/raw_s3_*.bin pair to DIR, so "
|
||||
"this run can become a test fixture. Worth doing on "
|
||||
@@ -291,6 +308,12 @@ def main() -> int:
|
||||
|
||||
try:
|
||||
info = step("connect() identity", mm.connect)
|
||||
if info is None:
|
||||
print("\n Nothing answered. If the port opened but no frame came back,")
|
||||
print(" check it is actually a Micromate and not another CDC-ACM device —")
|
||||
print(" /dev/ttyACM* numbering shifts when anything else is plugged in.")
|
||||
print(" `ls -l /dev/serial/by-id/` names each device and is stable.")
|
||||
return 3
|
||||
if info:
|
||||
print(f" serial={info.serial} model={info.model} "
|
||||
f"fw={info.firmware_line} monitoring={info.monitoring}")
|
||||
@@ -345,24 +368,36 @@ def main() -> int:
|
||||
print(f" would be filed as {ref.filename}")
|
||||
|
||||
if refs:
|
||||
# Download via iter_events, which reproduces THOR's interleaved
|
||||
# order -- the one with captures behind it.
|
||||
print("\n download (first event, THOR's interleaved order):")
|
||||
for ref in mm.iter_events():
|
||||
t1 = time.monotonic()
|
||||
try:
|
||||
result = mm.get_event(ref) # verify=True
|
||||
except Exception as e:
|
||||
print(f" {ref.key_hex}: {type(e).__name__}: {e}")
|
||||
break
|
||||
dt = max(time.monotonic() - t1, 1e-6)
|
||||
n = sum(len(v) for v in getattr(result, "samples", {}).values())
|
||||
err = mm.decode_error(ref, result)
|
||||
check = ("PVS agrees to %+.4f%%" % (100 * err)
|
||||
if err is not None else "PVS check n/a (histogram)")
|
||||
print(f" {ref.key_hex} {ref.record_type:9} {ref.size:6} B "
|
||||
f"in {dt:.1f} s -> {n} samples, {check}")
|
||||
break
|
||||
wanted = _select(refs, a.event)
|
||||
if not wanted:
|
||||
print(f"\n --event {a.event!r} matched nothing")
|
||||
else:
|
||||
print(f"\n download ({len(wanted)} of {len(refs)}, "
|
||||
f"THOR's interleaved order):")
|
||||
want_keys = {r.key_hex for r in wanted}
|
||||
# iter_events() walks the chain; download only the selected
|
||||
# events, at the cursor position THOR would be at.
|
||||
for ref in mm.iter_events():
|
||||
if ref.key_hex not in want_keys:
|
||||
continue
|
||||
n_chunks = -(-ref.size // 1024)
|
||||
note = (" <- past 64 KB, carries into params[1]"
|
||||
if ref.size > 0x10000 else "")
|
||||
t1 = time.monotonic()
|
||||
try:
|
||||
result = mm.get_event(ref) # verify=True
|
||||
except Exception as e:
|
||||
print(f" {ref.key_hex} {ref.size:7} B "
|
||||
f"FAILED {type(e).__name__}: {e}")
|
||||
continue
|
||||
dt = max(time.monotonic() - t1, 1e-6)
|
||||
n = sum(len(v) for v in getattr(result, "samples", {}).values())
|
||||
err = mm.decode_error(ref, result)
|
||||
check = ("PVS %+.4f%%" % (100 * err) if err is not None
|
||||
else "PVS n/a (histogram)")
|
||||
print(f" {ref.key_hex} {ref.record_type:9} "
|
||||
f"{ref.size:7} B {n_chunks:3} chunks {dt:5.1f} s "
|
||||
f"{n:6} samples {check}{note}")
|
||||
|
||||
except ProtocolError as e:
|
||||
print(f"\n ABORTED {type(e).__name__}: {e}")
|
||||
|
||||
Reference in New Issue
Block a user