From 744473888344ae221e6185801e6eb35c0fa65015 Mon Sep 17 00:00:00 2001 From: Brian Harrison Date: Tue, 5 May 2026 16:46:35 -0400 Subject: [PATCH] debug(protocol): event-N probe is now at counter = start_offset instead of start_offset + 0x46 --- CHANGELOG.md | 23 +++++++++++++++++++++++ CLAUDE.md | 27 ++++++++++++++++++++++++--- docs/instantel_protocol_reference.md | 21 ++++++++++++++++++--- minimateplus/protocol.py | 20 +++++++++++++++----- 4 files changed, 80 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 42236a6..e8e9177 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,29 @@ All notable changes to seismo-relay are documented here. --- +## v0.14.1 — 2026-05-04 + +### Fixed + +- **`read_bulk_waveform_stream` — event-N probe counter off-by-`0x46`.** + Continuation events (start_key[2:4] != 0) were being probed at counter + `start_offset + 0x0046` instead of just `start_offset`. In the iteration + walk, `cur_key` from 1F is already the off=0x46 WAVEHDR record key, so the + earlier formula effectively double-counted the WAVEHDR offset. The probe + landed one WAVEHDR past the actual event start, the response no longer + contained the STRT record at byte 17, `parse_strt_end_offset` returned + `None`, and the chunk loop fell back to the `max_chunks=128` cap — walking + ~110 chunks of post-event circular-buffer garbage. Verified against the + 5-1-26 "copy 2nd address" and 5-4-26 BW 2-sec event captures: BW probes + counter=`0x2238` with key=`01112238` and STRT is present at byte 17 of + the response (end_offset=`0x417E`). +- **CLAUDE.md / docs/instantel_protocol_reference.md** — corrected the + event-N section to clarify that `start_key` in those formulas is the + off=0x46 key, not the off=0x2C boundary key, and removed the spurious + `+0x46` from the chunk-walk pseudocode. + +--- + ## v0.12.6 — 2026-05-01 ### Fixed diff --git a/CLAUDE.md b/CLAUDE.md index dbfa3c2..bd2a92a 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -2,7 +2,7 @@ Ground-up Python replacement for **Blastware**, Instantel's Windows-only software for managing MiniMate Plus seismographs. Connects over direct RS-232 or cellular modem -(Sierra Wireless RV50 / RV55). Current version: **v0.13.2**. +(Sierra Wireless RV50 / RV55). Current version: **v0.14.1**. When new information about the protocol is discovered, please update the instantel_protocol_reference.md with the findings in addition to this document @@ -160,13 +160,28 @@ firmware reserved area for the first slot in a freshly-erased buffer. Harmless #### Event 2+ case — start_key[2:4] != 0x0000 (continuation events) ``` -1. First chunk at counter = start_key[2:4] + 0x0046 (this IS the probe — response - contains STRT) +1. First chunk at counter = start_key[2:4] (this IS the probe — response + contains STRT at byte 17) 2. Sample chunks: counter += 0x0200 each, up to but not including end_offset 3. TERM frame ``` +**`start_key` here is the off=0x46 WAVEHDR record key returned by 1F** (e.g. `01112238`), +NOT the off=0x2C boundary key that immediately precedes it. An earlier draft of this +doc described event-N as "probe at start + 0x46" — that formula came from naming the +boundary key as `start_key`. In the iteration walk, `cur_key` passed to +`read_bulk_waveform_stream` is always the off=0x46 key (the partial-record skip path in +`get_events` re-runs 1F to advance past boundary records before invoking 5A), so the +probe counter is just `cur_key[2:4]` with no extra offset. **Adding +0x46 caused the +probe to overshoot, miss the STRT record at byte 17 of the response, fall back to the +`max_chunks=128` cap, and walk ~110 chunks of post-event garbage** — observed in +SFM 5-4-26 capture before the fix. + +Confirmed across: +- 5-1-26 "copy 2nd address" BW capture: probe counter=0x2238, key=01112238, STRT@17 end=0x417E. +- 5-4-26 BW 2-sec event capture: probe counter=0x2238, key=01112238, TERM offset_word=0x0146 → end=0x417E. + No metadata pages — those have already been read during event 1 in the same Blastware session, and BW caches them. Note that the metadata-page reads happen ONCE per Blastware-session-on-the-device, not once per event, so an SFM session that downloads @@ -180,6 +195,12 @@ several events should read 0x1002/0x1004 only once at the start. - 2026-04-26: `max(key4[2:4], 0x0400) + (chunk_num-1) * 0x0400` (broken — over-read past event end). - 2026-05-01: Increments are 0x0200 not 0x0400; absolute addresses inside event range; bounded by STRT end_key, not by `max_chunks` cap or device-side timeout. +- 2026-05-04: Removed spurious `+0x0046` from event-N probe counter. `cur_key` from 1F + is already the off=0x46 WAVEHDR key, so adding +0x46 would have placed the probe one + WAVEHDR past the actual event start. This caused probe responses to lack a STRT + record (no `end_offset` parsed → `0xFFFF` fallback → `max_chunks=128` cap), walking + ~110 chunks of post-event circular-buffer garbage. Fixed in protocol.py + `read_bulk_waveform_stream`. ### SUB 5A — STRT record encodes end_offset (NEW 2026-05-01) diff --git a/docs/instantel_protocol_reference.md b/docs/instantel_protocol_reference.md index 0d90732..af8d1fc 100644 --- a/docs/instantel_protocol_reference.md +++ b/docs/instantel_protocol_reference.md @@ -1383,12 +1383,26 @@ the first slot in a freshly-erased buffer. Harmless to skip; BW does the same. **Event 2+ / start_key[2:4] != 0x0000** (continuation events in a populated buffer): ``` -1. First chunk at counter = start_key[2:4] + 0x0046 ← acts as both probe and first - sample chunk; response carries STRT +1. First chunk at counter = start_key[2:4] ← acts as both probe and first + sample chunk; response carries STRT at byte 17 2. Walk sample chunks counter += 0x0200 each 3. TERM ``` +**`start_key` here is the off=0x46 WAVEHDR record key returned by 1F** (e.g. `01112238`), +NOT the off=0x2C boundary key that immediately precedes it. An earlier draft of this +spec described event-N as "probe at start + 0x46" — that formula was correct only if +"start" meant the boundary key (0x21F2 in the 5-1-26 event 2 case). In the iteration +walk used by SFM and BW, `cur_key` passed into the 5A flow is always the off=0x46 key, +so the probe counter equals `cur_key[2:4]` with no extra offset. Adding +0x46 places +the probe one WAVEHDR past the actual event start, the response no longer contains +STRT at byte 17, and the chunk loop falls back to the `max_chunks` cap. + +Confirmed: +- 5-1-26 "copy 2nd address" BW capture: probe counter=0x2238 with key=01112238; A5[0] + has STRT@17 with end_offset=0x417E. +- 5-4-26 BW 2-sec event capture: same probe counter=0x2238, same end_offset=0x417E. + **No metadata-page reads.** Pages 0x1002/0x1004 are session-global and were already read during event 1 in the same Blastware session. In SFM, treat metadata pages as a once- per-`MiniMateClient.connect()` (or once-per-call-home) read, not per-event. @@ -1399,7 +1413,8 @@ per-`MiniMateClient.connect()` (or once-per-call-home) read, not per-event. |---|---|---|---|---|---| | 4-27-26 "open 2sec" / "copy event to disk" | `01110000` | `01111ABE` | `0x1ABE` | 6,846 B | 0x0600 (event-1 case) | | 5-1-26 "copy 3sec" / Download All event 1 | `01110000` | `011121F2` | `0x21F2` | 8,690 B | 0x0600 (event-1 case) | -| 5-1-26 "copy 2nd address" / DA event 2 | `011121F2` | `0111417E` | event 2 size = 0x1F8C = 8,076 B | 0x2238 (= 0x21F2 + 0x46) | +| 5-1-26 "copy 2nd address" / DA event 2 | `01112238` (= 1F result) | `0111417E` | `0x417E`, span 0x1F8C = 8,076 B | 0x2238 (= cur_key[2:4]) | +| 5-4-26 BW 2-sec event | `01112238` | `0111417E` | `0x417E` | 0x2238 (= cur_key[2:4]) | #### 7.8.6 TERM Frame Formula (NEW 2026-05-01) ✅ diff --git a/minimateplus/protocol.py b/minimateplus/protocol.py index 48fbfbe..3fb3b05 100644 --- a/minimateplus/protocol.py +++ b/minimateplus/protocol.py @@ -608,13 +608,23 @@ class MiniMateProtocol: probe_params = bulk_waveform_params(key4, 0, is_probe=True) log.debug("5A probe (event-1) key=%s counter=0x0000", key4.hex()) else: - # Continuation events: first 5A request lands at start+0x0046, - # acting as both probe and first sample chunk. Confirmed from - # 5-1-26 "copy 2nd address event" capture. - probe_counter = start_offset + 0x0046 + # Continuation events: first 5A request lands at counter = key[2:4] + # (i.e. the address of the off=0x46 WAVEHDR record returned by 1F). + # The probe response carries STRT at byte 17 with end_offset. + # + # Confirmed 2026-05-04 from 5-1-26 "copy 2nd address" capture + # (BW probes counter=0x2238 with key=01112238, STRT@17 end=0x417E) + # and 5-4-26 BW captures (2-sec event probes counter=0x2238). + # + # The earlier "+0x46" formula in the doc came from calling + # start_key the BOUNDARY (off=0x2C) key, but the iteration walk + # uses 1F's off=0x46 key as cur_key, which already incorporates + # the +0x46 offset relative to the boundary. Adding it again + # caused the probe to overshoot, miss STRT, and run uncapped. + probe_counter = start_offset probe_params = bulk_waveform_params(key4, probe_counter) log.debug( - "5A probe (event-N) key=%s counter=0x%04X (start+0x46)", + "5A probe (event-N) key=%s counter=0x%04X", key4.hex(), probe_counter, )