diff --git a/CHANGELOG.md b/CHANGELOG.md index e8e9177..01c0dde 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,28 @@ All notable changes to seismo-relay are documented here. --- +## v0.14.2 — 2026-05-04 + +### Fixed + +- **`blastware_file.py` — removed harmful "duplicate header+STRT" strip.** + The v0.13.x strip logic was matching the byte sequence `00 12 03 00 STRT` + in legitimate waveform data — sample chunks at counter `0x1000` and + beyond often contain those bytes coincidentally — and zeroing 25 bytes + of valid samples per match. This is why event 0 (event-1 case in the + protocol) downloads of >1-sec recordings always failed in BW: the strip + destroyed real data at body offset `0x1012..0x102B` and propagated + alignment differences through the rest of the body. Sub-1-sec events + worked because their `end_offset` was below `0x1002`, so no sample + chunks landed in the metadata-page region and the strip's needle never + matched. Verified fix by re-feeding the BW 5-1-26 "copy 3sec" capture's + A5 frames into the file builder: output is now byte-identical to BW's + saved `M529LKIQ.G10` reference (8708 bytes, 0 differences). +- BW already concatenates frame contributions in stream order without + any de-duplication; SFM now does the same. + +--- + ## v0.14.1 — 2026-05-04 ### Fixed diff --git a/CLAUDE.md b/CLAUDE.md index bd2a92a..6894e6a 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.14.1**. +(Sierra Wireless RV50 / RV55). Current version: **v0.14.2**. When new information about the protocol is discovered, please update the instantel_protocol_reference.md with the findings in addition to this document diff --git a/minimateplus/blastware_file.py b/minimateplus/blastware_file.py index f708435..ee73390 100644 --- a/minimateplus/blastware_file.py +++ b/minimateplus/blastware_file.py @@ -732,24 +732,18 @@ def write_blastware_file( bytes(all_bytes[-28:]).hex() if len(all_bytes) >= 28 else bytes(all_bytes).hex(), ) - # Strip embedded "duplicate header+STRT" blocks from body (v0.14.1). - # Chunk@0x1000 sometimes lands on the device's metadata-mirror page, - # whose response includes a 25-byte "00 12 03 00 STRT ..." block that - # mirrors the file's own header + STRT record. BW treats embedded STRT - # markers as second-event starts and rejects the file. Replace these - # blocks with zeros to preserve file size + alignment. - needle = b"\x00\x12\x03\x00STRT" - pos = bytes(all_bytes).find(needle) - while pos >= 0: - end = pos + 25 - if end <= len(all_bytes): - all_bytes[pos:end] = b"\x00" * 25 - log.warning( - "write_blastware_file: stripped duplicate header+STRT at " - "all_bytes[%d:%d] (replaced with 25 zero-bytes)", - pos, end, - ) - pos = bytes(all_bytes).find(needle, end) + # NOTE: The "duplicate header+STRT strip" logic from v0.13.x has been + # REMOVED in v0.14.2. Under the v0.14.0 BW-exact 5A walk, body assembly + # is just contiguous concatenation of frame contributions in stream order + # (probe → meta@0x1002 → meta@0x1004 → samples → TERM), exactly as BW + # writes its files. The previous strip was matching the `00 12 03 00 STRT` + # byte sequence in legitimate waveform data — sample chunks at counter + # 0x1000 and beyond often contain those bytes coincidentally — and + # zeroing 25 bytes of valid samples per match. Compared to a known-good + # BW reference for the same 3-sec event 0, the strip introduced 26 bytes + # of zeros that BW did not have, then propagated alignment differences + # through the rest of the body. See decode_test/5-1-26/bw vs SFM diff + # at file[0x1012..0x102B] (2026-05-04 analysis). # Find the first valid 0e 08 footer marker (v0.14.0). footer_pos = -1