diff --git a/CLAUDE.md b/CLAUDE.md index b2ceb14..bf05b6f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -171,25 +171,39 @@ the `b'STRT'` magic bytes: ``` +0..3 b'STRT' magic +4..5 flags 0xFF 0xFE (single-shot) or 0xFF 0xFD (continuous) -+6..9 key4 4-byte event key -+10..13 prev_key4 -+14..15 uint16 BE total_samples (full event sample-set count) ← confirmed 4-9-26 -+16..17 uint16 BE pretrig_samples (pre-trigger sample-set count) ++6..9 next_key4 ← key of the NEXT stored event (NOT the current event) ← confirmed 2026-04-14 ++10..13 prev_key4 ← key of the PREVIOUS stored event ← confirmed 2026-04-14 ++14..15 UNKNOWN (values seen: 0xDA63=55907, 0xF38F=62351, 0x5685=22149) — NOT total_samples ++16..17 UNKNOWN (values seen: 0x0122=290, 0x011A=282, 0x00FA=250) — NOT pretrig_samples +18 uint8 record-MODE byte — NOT rectime in seconds -+19..20 typically 0x00 0x00 ++19..20 0x00 0x00 ``` +**CONFIRMED field values (2026-04-14) from 3 desk-thump events, firmware S338.17:** + +| Field | What it is | Confirmed | +|---|---|---| +| +4..5 | 0xFFFE single-shot / 0xFFFD continuous | ✅ | +| +6..9 | next_event_key (NOT current) | ✅ 3 events | +| +10..13 | prev_event_key | ✅ 3 events | +| +18 | mode byte: 0x46 ('F') = single-shot, 0x0E = continuous | ✅ | + +**UNCONFIRMED — total_samples and pretrig_samples locations unknown:** +The prior documented offsets (+14..15 for total_samples, +16..17 for pretrig_samples) were +WRONG — confirmed by cross-checking STRT-derived rectime against compliance record_time +(4-14-26): all 3 events give STRT-derived rectime of 21–61 s vs actual 3.0 s (ratio 7–20×). +The "confirmed 4-9-26" note in prior versions was incorrect. + +The true offsets for total_samples and pretrig_samples within STRT have not been located. +**Until they are found, `_decode_a5_waveform` relies on the compliance-config cross-check +fallback for all total_samples and pretrig_samples values.** + **CRITICAL — strt[18] is a record-mode byte, NOT rectime_seconds (confirmed 2026-04-14):** Analysis of 15 distinct STRT records across the 4-9-26 ACH capture shows: - `flags=0xFFFE` (single-shot) → `strt[18] = 0x46` ('F') for EVERY event regardless of duration - `flags=0xFFFD` (continuous) → `strt[18] = 0x0E` for EVERY event regardless of duration -The actual record duration (post-trigger seconds) must be computed as: -```python -rectime_seconds = int(round((total_samples - pretrig_samples) / sample_rate)) -``` -`_decode_a5_waveform` uses `sample_rate=1024` as a default; the server overrides with -`compliance_config.sample_rate` when available. Do NOT use `strt[18]` for rectime. +Do NOT use `strt[18]` for rectime. **Pre-trigger time is separate from record_time (confirmed 2026-04-14):** Blastware documentation states: "The default Time Scale is -0.25 second to 1 second — this @@ -197,17 +211,17 @@ negative number accounts for the pre-trigger set for compliance monitoring." Th - `record_time` (3.0 s) is POST-TRIGGER duration only - Pre-trigger = 0.25 s = 256 samples at 1024 sps (compliance monitoring standard default) - The pre-trigger field has NOT yet been located in the raw compliance config bytes -- When STRT layout is invalid, `_decode_a5_waveform` falls back to pretrig = 0.25 × sr +- `_decode_a5_waveform` falls back to pretrig = 0.25 × sr from compliance standard - TODO: locate pretrig_time offset in ComplianceConfig — search around anchor or channel blocks The device bulk-streams zero-padded frames BEYOND the configured record window. The viewer clips `displayCount = total_samples = pretrig + post_trig` to exclude this padding. -**Sanity check — pretrig_samples must be less than total_samples:** -If `pretrig_samples >= total_samples` the STRT parse is invalid. Possible causes: -DLE-stuffed `0x10` byte within prev_key4 or key4 shifted field offsets, or a different -STRT record variant. `_decode_a5_waveform` logs `raw strt[0:21]` at WARNING level and -clamps `pretrig_samples = 0` so the viewer renders (showing the full waveform from t=0). +**Validity checks in `_decode_a5_waveform`:** +Check 1: `pretrig_samples >= total_samples` → invalid (original check). +Check 2: STRT-derived rectime differs from `compliance_config.record_time` by more than 2× +→ invalid. Both failures fall back to the compliance-config derived values. +`_decode_a5_waveform` logs `raw strt[0:21]` at WARNING level on any failure. Observed once (2026-04-14) with `strt[16:18] = 0x41 0x01` → pretrig=16641 (impossible). Root cause not yet identified — capture the warning log hex dump to diagnose. diff --git a/minimateplus/client.py b/minimateplus/client.py index e7637fe..afc5245 100644 --- a/minimateplus/client.py +++ b/minimateplus/client.py @@ -1389,11 +1389,18 @@ def _decode_a5_waveform( # # NOTE: strt[8:10] is the LOWER 2 bytes of key4, NOT total_samples. # Confirmed from raw_rx capture (4-9-26): strt[14:16] = total_samples. ✅ - strt = w0[strt_pos : strt_pos + 21] + # Extract 32 bytes so we can see past the first 21 — the true total_samples + # and pretrig_samples offsets have not yet been confirmed and may be > +20. + strt = w0[strt_pos : strt_pos + 32] if len(strt) < 21: log.warning("_decode_a5_waveform: STRT record truncated (%dB)", len(strt)) return + log.info( + "_decode_a5_waveform: STRT raw[0:32]: %s", + strt[:32].hex(' '), + ) + total_samples = struct.unpack_from(">H", strt, 14)[0] pretrig_samples = struct.unpack_from(">H", strt, 16)[0]