test: attempted to do bw mimic, but it didnt work. just saving this for now.
This commit is contained in:
+132
-72
@@ -526,7 +526,7 @@ class MiniMateProtocol:
|
|||||||
self,
|
self,
|
||||||
key4: bytes,
|
key4: bytes,
|
||||||
*,
|
*,
|
||||||
stop_after_metadata: bool = True,
|
stop_after_metadata: bool = False,
|
||||||
max_chunks: int = 32,
|
max_chunks: int = 32,
|
||||||
include_terminator: bool = False,
|
include_terminator: bool = False,
|
||||||
extra_chunks_after_metadata: int = 1,
|
extra_chunks_after_metadata: int = 1,
|
||||||
@@ -625,106 +625,166 @@ class MiniMateProtocol:
|
|||||||
_effective_extra_chunks,
|
_effective_extra_chunks,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# # ── Step 2: chunk loop ───────────────────────────────────────────────
|
||||||
|
# # Counter formula: _chunk_base + (chunk_num - 1) * 0x0400
|
||||||
|
# # where _chunk_base = max(key4[2:4], 0x0400).
|
||||||
|
# #
|
||||||
|
# # For events with key4[2:4] != 0 (e.g. key 0111245a, offset 0x245a):
|
||||||
|
# # _chunk_base = 0x245a → chunk 1=0x245a, chunk 2=0x285a, ...
|
||||||
|
# # Confirmed from 4-3-26 capture.
|
||||||
|
# #
|
||||||
|
# # For events with key4[2:4] == 0 (e.g. key 01110000):
|
||||||
|
# # _chunk_base = max(0, 0x0400) = 0x0400
|
||||||
|
# # → chunk 1=0x0400, chunk 2=0x0800, ... (= old chunk_num*0x0400)
|
||||||
|
# # CRITICAL: counter=0x0000 (same as the probe) causes the device to
|
||||||
|
# # re-return the STRT record data for chunk 1, making frame 1 look like
|
||||||
|
# # a second probe response (confirmed from server log: frame 1 len=1097,
|
||||||
|
# # contains STRT\xff\xfe, contributes zero body bytes after DLE-strip).
|
||||||
|
# # counter=0x0400 for chunk 1 confirmed working (empirical test 2026-04-06).
|
||||||
|
# _chunk_base = max(_key4_offset, _BULK_COUNTER_STEP)
|
||||||
|
# for chunk_num in range(1, max_chunks + 1):
|
||||||
|
# counter = _chunk_base + (chunk_num - 1) * _BULK_COUNTER_STEP
|
||||||
|
# params = bulk_waveform_params(key4, counter)
|
||||||
|
# log.debug("5A chunk %d counter=0x%04X", chunk_num, counter)
|
||||||
|
# self._send(build_5a_frame(_BULK_CHUNK_OFFSET, params))
|
||||||
|
# self._parser.reset() # reset bytes_fed for accurate per-chunk count
|
||||||
|
# try:
|
||||||
|
# # Collect ALL frames from this chunk response.
|
||||||
|
# # Over TCP via modem, a single large A5 device response (~1100 bytes
|
||||||
|
# # RS-232) is split across ~2 TCP segments, each parsed as its own
|
||||||
|
# # complete S3 frame. _recv_5a_batch gathers all of them so that
|
||||||
|
# # every subsequent chunk request is paired with the correct response.
|
||||||
|
# batch = self._recv_5a_batch(rsp_sub, first_timeout=10.0)
|
||||||
|
# except TimeoutError:
|
||||||
|
# raw = self._parser.bytes_fed
|
||||||
|
# log.warning(
|
||||||
|
# "5A TIMEOUT chunk=%d counter=0x%04X raw_bytes=%d",
|
||||||
|
# chunk_num, counter, raw,
|
||||||
|
# )
|
||||||
|
# if raw > 0 and frames_data:
|
||||||
|
# # Device sent a partial byte (likely a bare DLE/ETX end-of-stream
|
||||||
|
# # signal) but never completed a full frame. Treat as graceful
|
||||||
|
# # stream end and fall through to the termination step.
|
||||||
|
# log.warning(
|
||||||
|
# "5A end-of-stream detected at chunk=%d (raw_bytes=%d, "
|
||||||
|
# "frames_collected=%d) — proceeding to termination",
|
||||||
|
# chunk_num, raw, len(frames_data),
|
||||||
|
# )
|
||||||
|
# break
|
||||||
|
# raise
|
||||||
|
|
||||||
|
# # Process all frames from this batch.
|
||||||
|
# metadata_found = False
|
||||||
|
# for rsp in batch:
|
||||||
|
# log.warning(
|
||||||
|
# "5A RX chunk=%d page_key=0x%04X data_len=%d contains_Project=%s",
|
||||||
|
# chunk_num, rsp.page_key, len(rsp.data), b"Project:" in rsp.data,
|
||||||
|
# )
|
||||||
|
# if rsp.page_key == 0x0000:
|
||||||
|
# # Device unexpectedly terminated mid-stream.
|
||||||
|
# log.debug("5A page_key=0x0000 — device terminated early")
|
||||||
|
# if include_terminator:
|
||||||
|
# frames_data.append(rsp)
|
||||||
|
# return frames_data
|
||||||
|
# frames_data.append(rsp)
|
||||||
|
# if stop_after_metadata and b"Project:" in rsp.data:
|
||||||
|
# metadata_found = True
|
||||||
|
|
||||||
|
# if metadata_found:
|
||||||
|
# # Download extra_chunks_after_metadata more chunks after metadata.
|
||||||
|
# # This primes the device to return the valid waveform footer in the
|
||||||
|
# # termination response — without it the terminator carries too few bytes
|
||||||
|
# # (confirmed 2026-04-23). The extra chunk data also belongs in the
|
||||||
|
# # file body (confirmed from TCP capture analysis 2026-04-27).
|
||||||
|
# log.debug("5A metadata found — fetching %d more chunk(s)",
|
||||||
|
# _effective_extra_chunks)
|
||||||
|
# for _extra_n in range(_effective_extra_chunks):
|
||||||
|
# chunk_num += 1
|
||||||
|
# counter = _chunk_base + (chunk_num - 1) * _BULK_COUNTER_STEP
|
||||||
|
# params = bulk_waveform_params(key4, counter)
|
||||||
|
# self._send(build_5a_frame(_BULK_CHUNK_OFFSET, params))
|
||||||
|
# try:
|
||||||
|
# extra_batch = self._recv_5a_batch(rsp_sub, first_timeout=10.0)
|
||||||
|
# for ef in extra_batch:
|
||||||
|
# log.debug(
|
||||||
|
# "5A extra chunk page_key=0x%04X data_len=%d",
|
||||||
|
# ef.page_key, len(ef.data),
|
||||||
|
# )
|
||||||
|
# if ef.page_key == 0x0000:
|
||||||
|
# if include_terminator:
|
||||||
|
# frames_data.append(ef)
|
||||||
|
# return frames_data
|
||||||
|
# frames_data.append(ef)
|
||||||
|
# except TimeoutError:
|
||||||
|
# log.debug("5A extra chunk %d timed out — end of stream", _extra_n + 1)
|
||||||
|
# break
|
||||||
|
# break
|
||||||
|
# else:
|
||||||
|
# log.warning(
|
||||||
|
# "5A reached max_chunks=%d without end-of-stream; sending termination",
|
||||||
|
# max_chunks,
|
||||||
|
# )
|
||||||
# ── Step 2: chunk loop ───────────────────────────────────────────────
|
# ── Step 2: chunk loop ───────────────────────────────────────────────
|
||||||
# Counter formula: _chunk_base + (chunk_num - 1) * 0x0400
|
# TEST MODE:
|
||||||
# where _chunk_base = max(key4[2:4], 0x0400).
|
# Do NOT stop on "Project:".
|
||||||
#
|
# Project appears inside the 5A data stream and is not an EOF marker.
|
||||||
# For events with key4[2:4] != 0 (e.g. key 0111245a, offset 0x245a):
|
|
||||||
# _chunk_base = 0x245a → chunk 1=0x245a, chunk 2=0x285a, ...
|
|
||||||
# Confirmed from 4-3-26 capture.
|
|
||||||
#
|
|
||||||
# For events with key4[2:4] == 0 (e.g. key 01110000):
|
|
||||||
# _chunk_base = max(0, 0x0400) = 0x0400
|
|
||||||
# → chunk 1=0x0400, chunk 2=0x0800, ... (= old chunk_num*0x0400)
|
|
||||||
# CRITICAL: counter=0x0000 (same as the probe) causes the device to
|
|
||||||
# re-return the STRT record data for chunk 1, making frame 1 look like
|
|
||||||
# a second probe response (confirmed from server log: frame 1 len=1097,
|
|
||||||
# contains STRT\xff\xfe, contributes zero body bytes after DLE-strip).
|
|
||||||
# counter=0x0400 for chunk 1 confirmed working (empirical test 2026-04-06).
|
|
||||||
_chunk_base = max(_key4_offset, _BULK_COUNTER_STEP)
|
_chunk_base = max(_key4_offset, _BULK_COUNTER_STEP)
|
||||||
|
|
||||||
for chunk_num in range(1, max_chunks + 1):
|
for chunk_num in range(1, max_chunks + 1):
|
||||||
counter = _chunk_base + (chunk_num - 1) * _BULK_COUNTER_STEP
|
counter = _chunk_base + (chunk_num - 1) * _BULK_COUNTER_STEP
|
||||||
params = bulk_waveform_params(key4, counter)
|
params = bulk_waveform_params(key4, counter)
|
||||||
log.debug("5A chunk %d counter=0x%04X", chunk_num, counter)
|
|
||||||
|
log.warning(
|
||||||
|
"5A chunk request chunk=%d counter=0x%04X",
|
||||||
|
chunk_num,
|
||||||
|
counter,
|
||||||
|
)
|
||||||
|
|
||||||
self._send(build_5a_frame(_BULK_CHUNK_OFFSET, params))
|
self._send(build_5a_frame(_BULK_CHUNK_OFFSET, params))
|
||||||
self._parser.reset() # reset bytes_fed for accurate per-chunk count
|
self._parser.reset()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# Collect ALL frames from this chunk response.
|
|
||||||
# Over TCP via modem, a single large A5 device response (~1100 bytes
|
|
||||||
# RS-232) is split across ~2 TCP segments, each parsed as its own
|
|
||||||
# complete S3 frame. _recv_5a_batch gathers all of them so that
|
|
||||||
# every subsequent chunk request is paired with the correct response.
|
|
||||||
batch = self._recv_5a_batch(rsp_sub, first_timeout=10.0)
|
batch = self._recv_5a_batch(rsp_sub, first_timeout=10.0)
|
||||||
except TimeoutError:
|
except TimeoutError:
|
||||||
raw = self._parser.bytes_fed
|
raw = self._parser.bytes_fed
|
||||||
log.warning(
|
log.warning(
|
||||||
"5A TIMEOUT chunk=%d counter=0x%04X raw_bytes=%d",
|
"5A TIMEOUT chunk=%d counter=0x%04X raw_bytes=%d",
|
||||||
chunk_num, counter, raw,
|
chunk_num,
|
||||||
|
counter,
|
||||||
|
raw,
|
||||||
)
|
)
|
||||||
|
|
||||||
if raw > 0 and frames_data:
|
if raw > 0 and frames_data:
|
||||||
# Device sent a partial byte (likely a bare DLE/ETX end-of-stream
|
|
||||||
# signal) but never completed a full frame. Treat as graceful
|
|
||||||
# stream end and fall through to the termination step.
|
|
||||||
log.warning(
|
log.warning(
|
||||||
"5A end-of-stream detected at chunk=%d (raw_bytes=%d, "
|
"5A probable end-of-stream at chunk=%d; proceeding to termination",
|
||||||
"frames_collected=%d) — proceeding to termination",
|
chunk_num,
|
||||||
chunk_num, raw, len(frames_data),
|
|
||||||
)
|
)
|
||||||
break
|
break
|
||||||
|
|
||||||
raise
|
raise
|
||||||
|
|
||||||
# Process all frames from this batch.
|
|
||||||
metadata_found = False
|
|
||||||
for rsp in batch:
|
for rsp in batch:
|
||||||
|
contains_project = b"Project:" in rsp.data
|
||||||
|
|
||||||
log.warning(
|
log.warning(
|
||||||
"5A RX chunk=%d page_key=0x%04X data_len=%d contains_Project=%s",
|
"5A RX chunk=%d page_key=0x%04X data_len=%d contains_Project=%s",
|
||||||
chunk_num, rsp.page_key, len(rsp.data), b"Project:" in rsp.data,
|
chunk_num,
|
||||||
|
rsp.page_key,
|
||||||
|
len(rsp.data),
|
||||||
|
contains_project,
|
||||||
)
|
)
|
||||||
|
|
||||||
if rsp.page_key == 0x0000:
|
if rsp.page_key == 0x0000:
|
||||||
# Device unexpectedly terminated mid-stream.
|
log.warning("5A page_key=0x0000 — device terminated stream")
|
||||||
log.debug("5A page_key=0x0000 — device terminated early")
|
|
||||||
if include_terminator:
|
if include_terminator:
|
||||||
frames_data.append(rsp)
|
frames_data.append(rsp)
|
||||||
return frames_data
|
return frames_data
|
||||||
|
|
||||||
frames_data.append(rsp)
|
frames_data.append(rsp)
|
||||||
if stop_after_metadata and b"Project:" in rsp.data:
|
|
||||||
metadata_found = True
|
|
||||||
|
|
||||||
if metadata_found:
|
|
||||||
# Download extra_chunks_after_metadata more chunks after metadata.
|
|
||||||
# This primes the device to return the valid waveform footer in the
|
|
||||||
# termination response — without it the terminator carries too few bytes
|
|
||||||
# (confirmed 2026-04-23). The extra chunk data also belongs in the
|
|
||||||
# file body (confirmed from TCP capture analysis 2026-04-27).
|
|
||||||
log.debug("5A metadata found — fetching %d more chunk(s)",
|
|
||||||
_effective_extra_chunks)
|
|
||||||
for _extra_n in range(_effective_extra_chunks):
|
|
||||||
chunk_num += 1
|
|
||||||
counter = _chunk_base + (chunk_num - 1) * _BULK_COUNTER_STEP
|
|
||||||
params = bulk_waveform_params(key4, counter)
|
|
||||||
self._send(build_5a_frame(_BULK_CHUNK_OFFSET, params))
|
|
||||||
try:
|
|
||||||
extra_batch = self._recv_5a_batch(rsp_sub, first_timeout=10.0)
|
|
||||||
for ef in extra_batch:
|
|
||||||
log.debug(
|
|
||||||
"5A extra chunk page_key=0x%04X data_len=%d",
|
|
||||||
ef.page_key, len(ef.data),
|
|
||||||
)
|
|
||||||
if ef.page_key == 0x0000:
|
|
||||||
if include_terminator:
|
|
||||||
frames_data.append(ef)
|
|
||||||
return frames_data
|
|
||||||
frames_data.append(ef)
|
|
||||||
except TimeoutError:
|
|
||||||
log.debug("5A extra chunk %d timed out — end of stream", _extra_n + 1)
|
|
||||||
break
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
log.warning(
|
|
||||||
"5A reached max_chunks=%d without end-of-stream; sending termination",
|
|
||||||
max_chunks,
|
|
||||||
)
|
|
||||||
|
|
||||||
|
# IMPORTANT:
|
||||||
|
# Do not stop on Project. It is metadata inside the stream,
|
||||||
|
# not a stream terminator.
|
||||||
# ── Step 3: termination ──────────────────────────────────────────────
|
# ── Step 3: termination ──────────────────────────────────────────────
|
||||||
term_counter = counter + _BULK_COUNTER_STEP
|
term_counter = counter + _BULK_COUNTER_STEP
|
||||||
term_params = bulk_waveform_term_params(key4, term_counter)
|
term_params = bulk_waveform_term_params(key4, term_counter)
|
||||||
|
|||||||
Reference in New Issue
Block a user