v0.12.6 #10
@@ -685,11 +685,45 @@ def write_blastware_file(
|
|||||||
body_frames = a5_frames
|
body_frames = a5_frames
|
||||||
term_frame = None
|
term_frame = None
|
||||||
|
|
||||||
|
# ── Identify first metadata frame and skip "extra chunks" ───────────────
|
||||||
|
# When extra_chunks_after_metadata=1 in read_bulk_waveform_stream(), the
|
||||||
|
# frame list is: [probe, data..., metadata, extra_chunk, terminator].
|
||||||
|
# The extra_chunk is downloaded to prime the TCP terminator response — its
|
||||||
|
# ADC data is NOT part of the Blastware file body. Skip it.
|
||||||
|
#
|
||||||
|
# Rule: any frame at index strictly between first_metadata_fi and last_fi
|
||||||
|
# (the final frame) is an extra chunk and must be excluded.
|
||||||
|
#
|
||||||
|
# If no metadata frame exists (e.g. full_waveform download), first_metadata_fi
|
||||||
|
# is None and no frames are skipped — all frames contribute normally.
|
||||||
|
first_metadata_fi: Optional[int] = None
|
||||||
|
for _fi_scan, _frame_scan in enumerate(body_frames):
|
||||||
|
if _fi_scan > 0 and any(m in bytes(_frame_scan.data) for m in _METADATA_FRAME_MARKERS):
|
||||||
|
first_metadata_fi = _fi_scan
|
||||||
|
break
|
||||||
|
last_fi = len(body_frames) - 1
|
||||||
|
|
||||||
|
log.warning(
|
||||||
|
"write_blastware_file: %d body_frames first_metadata_fi=%s last_fi=%d",
|
||||||
|
len(body_frames),
|
||||||
|
str(first_metadata_fi) if first_metadata_fi is not None else "None",
|
||||||
|
last_fi,
|
||||||
|
)
|
||||||
|
|
||||||
all_bytes = bytearray()
|
all_bytes = bytearray()
|
||||||
|
|
||||||
for fi, frame in enumerate(body_frames):
|
for fi, frame in enumerate(body_frames):
|
||||||
ftype = classify_frame(frame)
|
# Skip "extra chunk" frames: frames after the first metadata frame but
|
||||||
print(f"Frame {fi}: type={ftype}, page_key={frame.page_key:04x}, len={len(frame.data)}")
|
# before the last frame (terminator). These prime the TCP terminator but
|
||||||
|
# their ADC data must NOT appear in the Blastware file body.
|
||||||
|
if (first_metadata_fi is not None
|
||||||
|
and fi > first_metadata_fi
|
||||||
|
and fi < last_fi):
|
||||||
|
log.warning(
|
||||||
|
"write_blastware_file: fi=%d SKIP (extra chunk after metadata fi=%d last_fi=%d)",
|
||||||
|
fi, first_metadata_fi, last_fi,
|
||||||
|
)
|
||||||
|
continue
|
||||||
|
|
||||||
if fi == 0:
|
if fi == 0:
|
||||||
# Probe frame: always process regardless of classification.
|
# Probe frame: always process regardless of classification.
|
||||||
|
|||||||
+13
-9
@@ -885,14 +885,18 @@ def device_event_blastware_file(
|
|||||||
def _do():
|
def _do():
|
||||||
with _build_client(port, baud, host, tcp_port, timeout=120.0) as client:
|
with _build_client(port, baud, host, tcp_port, timeout=120.0) as client:
|
||||||
info = client.connect()
|
info = client.connect()
|
||||||
# Use stop_after_metadata=True (full_waveform=False) with 0 extra
|
# Use stop_after_metadata=True (full_waveform=False) with 1 extra
|
||||||
# chunks after "Project:". Confirmed from 4-26-26 BW RS-232 capture
|
# chunk after "Project:". The extra chunk is required to prime the
|
||||||
# of "copy event to file" on a 2-sec Continuous event (key=01110000):
|
# device over TCP: termination at term_counter=metadata_counter+0x0400
|
||||||
# BW sends the termination frame IMMEDIATELY after the chunk that
|
# returns only ~90 bytes (no useful footer) over TCP/cellular, but
|
||||||
# contains "Project:" — no extra chunk is downloaded first.
|
# termination at metadata_counter+0x0800 (one chunk later) returns
|
||||||
# extra_chunks_after_metadata=1 was WRONG: it downloaded one additional
|
# the full 737-byte frame containing the footer.
|
||||||
# chunk (counter = last_data_counter + 0x0400) adding ~1053 spurious
|
#
|
||||||
# bytes to the body, causing Blastware to reject the file.
|
# Confirmed from 4-26-26 BW RS-232 capture: BW terminates at 0x1800
|
||||||
|
# without an extra chunk (works on RS-232 but not TCP).
|
||||||
|
# write_blastware_file() automatically skips the extra chunk's
|
||||||
|
# contribution — only the probe+ADC+metadata+terminator bytes appear
|
||||||
|
# in the output file.
|
||||||
#
|
#
|
||||||
# full_waveform=True (natural end-of-stream) downloads ALL chunks
|
# full_waveform=True (natural end-of-stream) downloads ALL chunks
|
||||||
# including post-event silence (35+ chunks for a 9-sec event at
|
# including post-event silence (35+ chunks for a 9-sec event at
|
||||||
@@ -900,7 +904,7 @@ def device_event_blastware_file(
|
|||||||
events = client.get_events(
|
events = client.get_events(
|
||||||
full_waveform=False,
|
full_waveform=False,
|
||||||
stop_after_index=index,
|
stop_after_index=index,
|
||||||
extra_chunks_after_metadata=0,
|
extra_chunks_after_metadata=1,
|
||||||
)
|
)
|
||||||
matching = [ev for ev in events if ev.index == index]
|
matching = [ev for ev in events if ev.index == index]
|
||||||
return matching[0] if matching else None, info
|
return matching[0] if matching else None, info
|
||||||
|
|||||||
Reference in New Issue
Block a user