fix: waveform decode improved for accuracy.
feat: adds 5a diagnostic script to parse raw binary
This commit is contained in:
@@ -266,6 +266,73 @@ silence). Only the initial variable-size chunks contain actual signal.
|
||||
Removed. Terminator detection is via `page_key == 0x0000` in `read_bulk_waveform_stream`,
|
||||
not frame index.
|
||||
|
||||
### SUB 5A — re-probe at counter=0x1000 (DLE collision, FIXED 2026-04-15)
|
||||
|
||||
**Root cause (confirmed from diagnostic output, desk-thump event key=01110000):**
|
||||
`bulk_waveform_params()` sets `p[3] = (counter >> 8) & 0xFF`. For chunk 4, counter =
|
||||
`4 * 0x0400 = 0x1000`, so `p[3] = 0x10` — the DLE byte. Because `build_5a_frame` writes
|
||||
params RAW (no DLE stuffing), the on-wire byte sequence contains a bare `0x10`. The
|
||||
device DLE-decodes its own receive buffer: `10 00` (the p[3]/p[4] pair) is collapsed to
|
||||
`00`, so the counter field reads 0 — a probe request. The device re-sends the initial
|
||||
probe response (containing the STRT record and first waveform bytes).
|
||||
|
||||
**Effect:** In a 36-frame stream for key=01110000, fi=4 was a byte-for-byte duplicate of
|
||||
fi=0 (same db=1101B, same w[0:32] bytes, STRT present at w[10]). The old code treated it
|
||||
as a regular chunk, decoded the STRT bytes as int16 samples (producing T=21587="ST",
|
||||
V=21586="RT"), and shifted the running byte alignment for all subsequent frames.
|
||||
|
||||
**Fix (`_decode_a5_waveform`):** Check for STRT in every frame, not just fi==0. Any
|
||||
non-fi=0 frame containing STRT is a re-probe — log it and skip (do NOT add to
|
||||
`all_chunks`). Regular chunk path is reached only when `w.find(b"STRT") < 0`.
|
||||
|
||||
**Note:** This DLE collision is key-specific. For key=01110000 (`key4[2:4]=0x0000`),
|
||||
counter = `chunk_num * 0x0400`, so counter=0x1000 occurs at chunk 4 for every event with
|
||||
this key. For other keys (e.g. key=0111245a, `key4[2:4]=0x245A`), the chunk counter
|
||||
formula `key4[2:4] + n*0x0400` produces different values; the collision only occurs when
|
||||
the high byte of any counter is 0x10.
|
||||
|
||||
### SUB 5A — metadata false-positive (FIXED 2026-04-15)
|
||||
|
||||
**Root cause (confirmed from diagnostic output):**
|
||||
The old metadata-frame test was `b"Project:" in w` (single anchor). For the 36-frame
|
||||
desk-thump stream, fi=15 had `b"Project:"` at w[93] inside live ADC data — a coincidental
|
||||
4-byte pattern in the waveform. The frame (134 live sample-sets) was incorrectly skipped.
|
||||
|
||||
**Fix:** Require BOTH `b"Project:" in w` AND `b"Client:" in w` to classify a frame as
|
||||
metadata. The real metadata frame (fi=6 in the desk-thump stream) contains both strings
|
||||
as part of the compliance-setup ASCII block; random ADC data is statistically unlikely to
|
||||
contain both 8-byte sequences.
|
||||
|
||||
**Updated check in `_decode_a5_waveform`:**
|
||||
```python
|
||||
elif b"Project:" in w and b"Client:" in w:
|
||||
log.info("_decode_a5_waveform: fi=%d skipped (metadata frame)", fi)
|
||||
continue
|
||||
```
|
||||
|
||||
### SUB 5A — 0xFF tail frames beyond record window (confirmed 2026-04-15)
|
||||
|
||||
The device bulk-streams flash pages beyond the configured record window. Un-written flash
|
||||
pages read as 0xFF. Decoded as int16 LE, `0xFF 0xFF = -1`, which maps to ~0 in/s after
|
||||
the geo scale factor is applied — producing a visible flat-line at the end of the waveform.
|
||||
|
||||
**Confirmed from diagnostic output (desk-thump event, 1024 sps, record_time=3.0 s):**
|
||||
- total_samples = 256 (pretrig) + 3072 (post) = 3328
|
||||
- samples_decoded = 4417 (36 frames)
|
||||
- Excess tail: 4417 − 3328 = 1089 samples (8.7 frames of 0xFF data)
|
||||
- Flat-line onset: sample 1960, t=1664ms post-trigger (within the active signal window
|
||||
— earlier than expected because fi=4 re-probe and fi=15 false-positive removed ~270
|
||||
samples; once those bugs are fixed the real onset should be at or beyond total_samples)
|
||||
|
||||
**Fix (two parts):**
|
||||
1. `_decode_a5_waveform` (Python): already returns `total_samples` alongside
|
||||
`samples_decoded`; the field is populated from compliance config:
|
||||
`total_samples = pretrig_samples + round(record_time * sample_rate)`.
|
||||
2. `sfm_webapp.html` (`_buildWaveformCharts`): `display = Math.min(decoded, total_samples)`;
|
||||
`times` array and per-channel `samples` are both sliced to `display` length before
|
||||
plotting — `(channels[ch] || []).slice(0, display)`. Without this, the chart rendered
|
||||
all `decoded` samples including the 0xFF tail.
|
||||
|
||||
### SUB 1E / 1F — event iteration null sentinel and token position (FIXED, do not re-introduce)
|
||||
|
||||
**token_params bug (FIXED):** The token byte was at `params[6]` (wrong). Both 3-31-26 and
|
||||
@@ -1021,3 +1088,4 @@ call-home.
|
||||
- Modem manager — push RV50/RV55 configs via Sierra Wireless API
|
||||
- RV55 DCD/DTR issue — newer RV55 firmware doesn't assert DCD by default; units don't
|
||||
resume monitoring after call-home disconnect (`--restart-monitoring` flag deferred)
|
||||
| ||||