From 2a2031c3a97550930c6466de7979f33ab1739e28 Mon Sep 17 00:00:00 2001 From: Brian Harrison Date: Thu, 23 Apr 2026 17:08:36 -0400 Subject: [PATCH] fix(protocol): fetch additional chunk after metadata to ensure valid termination response --- minimateplus/protocol.py | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/minimateplus/protocol.py b/minimateplus/protocol.py index 7ff0a03..1359abf 100644 --- a/minimateplus/protocol.py +++ b/minimateplus/protocol.py @@ -646,7 +646,27 @@ class MiniMateProtocol: 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) + # Download exactly one more chunk after finding metadata — this is + # what Blastware does. The extra chunk contains the tail ADC data + # and primes the device to return a valid footer in the termination + # response. Without it, termination returns an empty ack with no + # footer bytes (confirmed 2026-04-23 from HxD comparison). + log.debug("5A A5[%d] metadata found — fetching one more chunk then stopping", chunk_num) + chunk_num += 1 + counter = chunk_num * _BULK_COUNTER_STEP + params = bulk_waveform_params(key4, counter) + self._send(build_5a_frame(_BULK_CHUNK_OFFSET, params)) + try: + extra = self._recv_one(expected_sub=rsp_sub, timeout=10.0) + log.debug("5A A5[%d] extra chunk page_key=0x%04X data_len=%d", + chunk_num, extra.page_key, len(extra.data)) + if extra.page_key == 0x0000: + if include_terminator: + frames_data.append(extra) + return frames_data + frames_data.append(extra) + except TimeoutError: + log.debug("5A extra chunk timed out — end of stream") break else: log.warning(