feat: first try at building waveform binary files.

This commit is contained in:
2026-04-21 22:57:53 -04:00
parent 4331215e23
commit dfbc9f29c5
8 changed files with 1148 additions and 19 deletions
+20 -8
View File
@@ -526,7 +526,8 @@ class MiniMateProtocol:
*,
stop_after_metadata: bool = True,
max_chunks: int = 32,
) -> list[bytes]:
include_terminator: bool = False,
) -> list[S3Frame]:
"""
Download the SUB 5A (BULK_WAVEFORM_STREAM) A5 frames for one event.
@@ -542,7 +543,9 @@ class MiniMateProtocol:
4. Termination (offset=_BULK_TERM_OFFSET, counter=last+_BULK_COUNTER_STEP)
Device responds with a final A5 frame (page_key=0x0000).
The termination frame (page_key=0x0000) is NOT included in the returned list.
By default the termination frame (page_key=0x0000) is NOT included in the
returned list. Pass include_terminator=True to append it; the blastware_file
writer needs the terminator frame's body to reconstruct the N00 footer.
Args:
key4: 4-byte waveform key from EVENT_HEADER (1E).
@@ -552,11 +555,16 @@ class MiniMateProtocol:
hundred KB). Set False to download everything.
max_chunks: Safety cap on the number of chunk requests sent
(default 32; a typical event uses 9 large frames).
include_terminator: If True, append the terminator A5 frame
(page_key=0x0000) to the returned list. The
terminator carries the N00 footer bytes.
Default False preserves existing caller behaviour.
Returns:
List of raw data bytes from each A5 response frame (not including
the terminator frame). Frame indices match the request sequence:
index 0 = probe response, index 1 = first chunk, etc.
List of S3Frame objects from each A5 response frame. Frame indices
match the request sequence: index 0 = probe response, index 1 = first
chunk, etc. If include_terminator=True, the last element is the
terminator frame (page_key=0x0000).
Raises:
ProtocolError: on timeout, bad checksum, or unexpected SUB.
@@ -571,7 +579,7 @@ class MiniMateProtocol:
raise ValueError(f"waveform key must be 4 bytes, got {len(key4)}")
rsp_sub = _expected_rsp_sub(SUB_BULK_WAVEFORM) # 0xFF - 0x5A = 0xA5
frames_data: list[bytes] = []
frames_data: list[S3Frame] = []
counter = 0
# ── Step 1: probe ────────────────────────────────────────────────────
@@ -588,7 +596,7 @@ class MiniMateProtocol:
key4.hex(), self._parser.bytes_fed,
)
raise
frames_data.append(rsp.data)
frames_data.append(rsp)
log.debug("5A A5[0] page_key=0x%04X %d bytes", rsp.page_key, len(rsp.data))
# ── Step 2: chunk loop ───────────────────────────────────────────────
@@ -631,9 +639,11 @@ class MiniMateProtocol:
if rsp.page_key == 0x0000:
# Device unexpectedly terminated mid-stream (no termination needed).
log.debug("5A A5[%d] page_key=0x0000 — device terminated early", chunk_num)
if include_terminator:
frames_data.append(rsp)
return frames_data
frames_data.append(rsp.data)
frames_data.append(rsp)
if stop_after_metadata and b"Project:" in rsp.data:
log.debug("5A A5[%d] metadata found — stopping early", chunk_num)
@@ -658,6 +668,8 @@ class MiniMateProtocol:
"5A termination response page_key=0x%04X %d bytes",
term_rsp.page_key, len(term_rsp.data),
)
if include_terminator:
frames_data.append(term_rsp)
except TimeoutError:
log.debug("5A no termination response — device may have already closed")