big refactor of waveform protocol.

This commit is contained in:
2026-05-03 01:20:21 -04:00
parent d758825c67
commit 45e61fbcaf
7 changed files with 409 additions and 278 deletions
+19 -21
View File
@@ -37,6 +37,7 @@ from __future__ import annotations
import datetime
import logging
import sys
import tempfile
import threading
import time
from pathlib import Path
@@ -863,8 +864,8 @@ def device_event_blastware_file(
Supply either *port* (serial) or *host* (TCP/modem).
The file is written to /tmp and streamed back as a binary download.
Blastware can open it directly — filename encodes serial + timestamp.
The file is written to the OS temp directory and streamed back as a binary
download. Blastware can open it directly — filename encodes serial + timestamp.
Filename format: <prefix><serial3><stem><AB>0<W|H>
- prefix letter = chr(ord('B') + floor(serial_numeric / 1000))
@@ -885,26 +886,13 @@ def device_event_blastware_file(
def _do():
with _build_client(port, baud, host, tcp_port, timeout=120.0) as client:
info = client.connect()
# Use stop_after_metadata=True (full_waveform=False) with 1 extra
# chunk after "Project:". The extra chunk is required to prime the
# device over TCP: termination at term_counter=metadata_counter+0x0400
# returns only ~90 bytes (no useful footer) over TCP/cellular, but
# termination at metadata_counter+0x0800 (one chunk later) returns
# the full 737-byte frame containing the footer.
#
# 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
# including post-event silence (35+ chunks for a 9-sec event at
# 1024 sps) — this produces 24KB+ files that Blastware rejects.
# Under v0.14.0 BW-exact 5A walk, the chunk loop is bounded by
# the event end_offset extracted from STRT. No more
# stop_after_metadata / extra_chunks gymnastics — these
# kwargs are now no-ops.
events = client.get_events(
full_waveform=False,
stop_after_index=index,
extra_chunks_after_metadata=1,
)
matching = [ev for ev in events if ev.index == index]
return matching[0] if matching else None, info
@@ -940,8 +928,18 @@ def device_event_blastware_file(
# Build filename using the same algorithm Blastware uses
filename = blastware_filename(ev, serial)
# Write to /tmp so FastAPI can stream it back
out_path = Path("/tmp") / filename
# Write to OS temp dir (cross-platform: /tmp on Linux/macOS,
# %TEMP% on Windows) so FastAPI can stream it back via FileResponse.
out_path = Path(tempfile.gettempdir()) / filename
# Delete any stale file at this path before writing. On Windows we have
# observed the new (smaller) file getting trailing zero-bytes from the
# previous (larger) file when filesystem semantics around open(...,"wb")
# don't truncate cleanly (e.g. through a synced folder). Explicit unlink
# eliminates that ambiguity.
try:
out_path.unlink()
except FileNotFoundError:
pass
write_blastware_file(ev, a5_frames, out_path)
log.info(
"blastware_file: wrote %s (%d A5 frames, serial=%s)",