fix: serial decode offset, PPV label scan, debug mode for waveform records

- _decode_serial_number: read from data[11:] not data[:8] — was returning
  the LENGTH_ECHO byte (0x0A = '\n') instead of the serial string
- _extract_peak_floats: search for channel label strings ("Tran" etc) and
  read float at label+6; old step-4 aligned scan was reading trigger levels
  instead of PPV values
- get_events: add debug=False param; stashes raw 210-byte record on
  Event._raw_record when True for field-layout inspection
- server /device/events: add ?debug=true query param; includes
  raw_record_hex + raw_record_len in response when set
- models: add Event._raw_record optional bytes field
This commit is contained in:
Brian Harrison
2026-03-31 23:46:07 -04:00
parent 9f52745bb4
commit f74992f4e5
3 changed files with 32 additions and 11 deletions

View File

@@ -145,7 +145,7 @@ class MiniMateClient:
log.info("connect: %s", device_info)
return device_info
def get_events(self, include_waveforms: bool = True) -> list[Event]:
def get_events(self, include_waveforms: bool = True, debug: bool = False) -> list[Event]:
"""
Download all stored events from the device using the confirmed
1E → 0A → 0C → 1F event-iterator protocol.
@@ -218,6 +218,8 @@ class MiniMateClient:
# SUB 0C — full waveform record (peak values, project strings)
try:
record = proto.read_waveform_record(key4)
if debug:
ev._raw_record = record
_decode_waveform_record_into(record, ev)
except ProtocolError as exc:
log.warning(
@@ -262,14 +264,19 @@ def _decode_serial_number(data: bytes) -> DeviceInfo:
Returns:
New DeviceInfo with serial, firmware_minor, serial_trail_0 populated.
"""
if len(data) < 9:
# data is data_rsp.data = payload[5:]. The 11-byte section header occupies
# data[0..10]: [LENGTH_ECHO:1][00×4][KEY_ECHO:4][00×2].
# Actual serial payload starts at data[11].
actual = data[11:] if len(data) > 11 else data
if len(actual) < 9:
# Short payload — gracefully degrade
serial = data.rstrip(b"\x00").decode("ascii", errors="replace")
serial = actual.rstrip(b"\x00").decode("ascii", errors="replace")
return DeviceInfo(serial=serial, firmware_minor=0)
serial = data[:8].rstrip(b"\x00").decode("ascii", errors="replace")
trail_0 = data[8] if len(data) > 8 else None
fw_minor = data[9] if len(data) > 9 else 0
serial = actual[:8].rstrip(b"\x00").decode("ascii", errors="replace")
trail_0 = actual[8] if len(actual) > 8 else None
fw_minor = actual[9] if len(actual) > 9 else 0
return DeviceInfo(
serial=serial,

View File

@@ -197,6 +197,11 @@ class Event:
# requested (large data transfer — up to several MB per event).
raw_samples: Optional[dict] = None # {"Tran": [...], "Vert": [...], ...}
# ── Debug / introspection ─────────────────────────────────────────────────
# Raw 210-byte waveform record bytes, set when debug mode is active.
# Exposed by the SFM server via ?debug=true so field layouts can be verified.
_raw_record: Optional[bytes] = field(default=None, repr=False)
def __str__(self) -> str:
ts = str(self.timestamp) if self.timestamp else "no timestamp"
ppv = ""