From 7976b544edfef1432d9d1fff36d8cb2093204d37 Mon Sep 17 00:00:00 2001 From: Brian Harrison Date: Sun, 26 Apr 2026 00:59:36 -0400 Subject: [PATCH] fix(blastware_file): never skip A5 frames based on classification at fi>0 Frame 0 is always the probe; frames 1+ are always data (waveform ADC chunks, compliance config, compliance continuation). Gating on classify_frame() at fi>0 produces false positives: ADC binary data can coincidentally contain b"STRT\xff\xfe", causing frames 1 and 5 to be silently dropped from the body (confirmed from live capture on event key=01110000). Remove all type-based filtering; include every frame unconditionally with the standard index-based skip amounts. --- minimateplus/blastware_file.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/minimateplus/blastware_file.py b/minimateplus/blastware_file.py index 15c9835..79a1e1e 100644 --- a/minimateplus/blastware_file.py +++ b/minimateplus/blastware_file.py @@ -686,24 +686,19 @@ def write_blastware_file( # Probe frame: always process regardless of classification. # It holds the STRT record; probe_skip positions us past it. skip = probe_skip - elif ftype == "probe_or_strt": - # Real duplicate probe frames should be skipped (very rare). - log.warning( - "write_blastware_file: frame %d classified as probe_or_strt — skipping", - fi, - ) - continue else: - # Waveform chunks, metadata/compliance frames, and unknown frames are all - # included. The A5 stream is collected with stop_after_metadata=True + - # extra_chunks_after_metadata=1, so body_frames contains: - # [0] probe frame - # [1..N] waveform ADC chunks - # [N+1] first compliance frame (contains "Project:", "Client:", etc.) - # [N+2] second compliance frame (continuation of compliance block) - # All of these contribute to the body; the 26-byte footer is separated out - # at the end. Do NOT gate on metadata classification here — the compliance - # block spans 2 frames and skipping frame N+2 produces a truncated file. + # ALL subsequent frames are included unconditionally — no filtering on + # frame type. In the A5 stream, frame 0 is always the probe response; + # frames 1+ are always data (waveform chunks, compliance config, or + # compliance continuation). Classification is for logging only. + # + # DO NOT gate on classify_frame() here: + # - "probe_or_strt" at fi>0 is always a false positive — ADC binary + # data can coincidentally contain b"STRT\xff\xfe" (confirmed from + # live capture: frames 1 and 5 matched on event key=01110000). + # - "metadata" frames must be included (compliance config body). + # - The compliance block spans 2 frames; skipping either produces a + # truncated file that Blastware rejects. skip = 13 if fi == 1 else 12 all_bytes.extend(_frame_body_bytes(frame, skip))