fix: remove special case chunk counter, all chunks use chunk_num * 0x0400
This commit is contained in:
@@ -109,6 +109,22 @@ S3→BW (response):
|
||||
Both differences confirmed by reproducing Blastware's exact wire bytes from the 1-2-26
|
||||
BW TX capture. All 10 frames verified.
|
||||
|
||||
### SUB 5A — chunk counter is monotonic (CORRECTED 2026-04-06)
|
||||
|
||||
**Chunk counters are `chunk_num * 0x0400` for ALL chunks including chunk 1.**
|
||||
|
||||
The 4-2-26 BW TX capture showed `counter=0x1004` for chunk 1 of event key `01110000`, which
|
||||
led to `_CHUNK1_COUNTER = 0x1004` being hardcoded as a special case. This was a Blastware
|
||||
artifact, not a protocol requirement. Empirical test 2026-04-06: with `counter=0x1004` for
|
||||
chunk 1 the device times out (120 s); with `counter=0x0400` (= `1 * 0x0400`) it responds
|
||||
immediately and streams all frames correctly.
|
||||
|
||||
The 4-3-26 capture confirms the pattern for a second event (key `0111245a`):
|
||||
chunk 1 = `0x245A`, chunk 2 = `0x285A`, chunk 3 = `0x2C5A` (each +0x0400). Blastware's
|
||||
true formula is `key4[2:4] + n * 0x0400` — but since `key4[2:4]` of the first event is
|
||||
`0x0000`, `n * 0x0400` produces the right result. The device does not strictly validate the
|
||||
counter and streams data for any valid 5A request; using `chunk_num * 0x0400` is correct.
|
||||
|
||||
### SUB 5A — params are 11 bytes for chunk frames, 10 for termination
|
||||
|
||||
`bulk_waveform_params()` returns 11 bytes (extra trailing `0x00`). The 11th byte was
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
| 2026-04-06 | §6.1 | **CONFIRMED — SUB 1F(token=0xFE) must precede POLL×3 before 5A.** BW always sends 1F(0xFE) before the 3 POLL cycles before 5A. 5A still uses the pre-advance key (set by 0A+1E-arm+0C); 1F only arms the device's 5A state machine. |
|
||||
| 2026-04-06 | §6.1 | **CONFIRMED — browse 1F must be conditional.** Calling 1F(browse=True/all-zero) after a FAILED 5A disrupts device state and causes the next event's 5A probe to time out with 0 bytes received. Browse 1F is only called after a SUCCESSFUL 5A. Failure fallback: use the key returned by the prior 1F(arm/0xFE) call. |
|
||||
| 2026-04-06 | §7.8 | **ADDED — `bytes_fed` diagnostic counter on S3FrameParser.** Counts raw bytes fed to the parser since last `reset()`. Logged at WARNING when 5A probe times out — distinguishes "device sent no bytes at all" from "device responded but frame was malformed or had wrong SUB". |
|
||||
| 2026-04-06 | §7.8.2 | **CORRECTED — SUB 5A chunk counter is monotonic for ALL chunks.** Previous doc hard-coded chunk 1 counter as `0x1004` (from 4-2-26 BW TX capture). This was a Blastware artifact. Empirically confirmed: `counter = chunk_num * 0x0400` works (device responds immediately); counter=0x1004 for chunk 1 causes 120 s timeout. BW's true internal formula appears to be `key4[2:4] + n * 0x0400` — for event 1 (key `01110000`) this equals `n * 0x0400`. The device does not strictly validate counter values. |
|
||||
|
||||
---
|
||||
|
||||
@@ -1140,13 +1141,24 @@ Two critical differences from `build_bw_frame`:
|
||||
|
||||
#### 7.8.2 Request Sequence
|
||||
|
||||
| Frame | offset_word | params | Purpose |
|
||||
|---|---|---|---|
|
||||
| Probe | `0x1004` | 10 bytes (`bulk_waveform_params(0)`) | Initiate transfer |
|
||||
| Chunk 1 | `0x1004` | 11 bytes (`bulk_waveform_params(counter)`) | First data chunk |
|
||||
| Chunk 2 | `0x1004` | 11 bytes, counter += `0x0400` | Second chunk |
|
||||
| … | … | … | … |
|
||||
| Termination | `0x005A` | 11 bytes, term_counter = last+`0x0400` | End transfer |
|
||||
| Frame | offset_word | counter | params | Purpose |
|
||||
|---|---|---|---|---|
|
||||
| Probe | `0x1004` | `0x0000` | 10 bytes (`bulk_waveform_params(0)`) | Initiate transfer |
|
||||
| Chunk 1 | `0x1004` | `0x0400` | 11 bytes | First data chunk |
|
||||
| Chunk 2 | `0x1004` | `0x0800` | 11 bytes | Second chunk |
|
||||
| Chunk N | `0x1004` | `N * 0x0400` | 11 bytes | Nth chunk |
|
||||
| … | … | … | … | … |
|
||||
| Termination | `0x005A` | `last + 0x0400` | 10 bytes | End transfer |
|
||||
|
||||
> ⚠️ **2026-04-06 CORRECTED — chunk counter is monotonic for ALL chunks.**
|
||||
> The 4-2-26 BW TX capture showed counter=0x1004 for chunk 1, which was hardcoded as a
|
||||
> special case. This was a Blastware artifact. Empirically confirmed: counter=0x0400 for
|
||||
> chunk 1 works correctly; counter=0x1004 causes the device to time out. The device does
|
||||
> NOT strictly validate the counter value — it streams data for any valid 5A request for
|
||||
> the given key. Use `chunk_num * 0x0400` (monotonic) for all chunks.
|
||||
> BW's true internal formula is `key4[2:4] + n * 0x0400`. For event 1 (key `01110000`)
|
||||
> this equals `n * 0x0400` since `key4[2:4] = 0x0000`. The monotonic formula is correct
|
||||
> for all keys encountered on this device.
|
||||
|
||||
The `stop_after_metadata=True` flag causes the loop to stop as soon as `b"Project:"` is
|
||||
found in the accumulated A5 frame data, typically after 7–9 chunks. A termination frame
|
||||
|
||||
@@ -508,11 +508,13 @@ class MiniMateProtocol:
|
||||
log.debug("5A A5[0] page_key=0x%04X %d bytes", rsp.page_key, len(rsp.data))
|
||||
|
||||
# ── Step 2: chunk loop ───────────────────────────────────────────────
|
||||
# Chunk 1 uses a fixed counter of 0x1004, confirmed from 4-2-26 BW TX capture.
|
||||
# Chunks 2+ use n * 0x0400. Device silently ignores frames with wrong counter.
|
||||
_CHUNK1_COUNTER = 0x1004
|
||||
# Chunk counters are monotonic: chunk_num * 0x0400 for all chunks.
|
||||
# The 4-2-26 BW TX capture showed 0x1004 for chunk 1, but this is a
|
||||
# Blastware artifact — the device accepts any counter value and streams
|
||||
# data regardless. Empirically confirmed 2026-04-06: 0x0400 for chunk 1
|
||||
# works; 0x1004 causes the device to ignore the frame (timeout).
|
||||
for chunk_num in range(1, max_chunks + 1):
|
||||
counter = _CHUNK1_COUNTER if chunk_num == 1 else chunk_num * _BULK_COUNTER_STEP
|
||||
counter = chunk_num * _BULK_COUNTER_STEP
|
||||
params = bulk_waveform_params(key4, counter)
|
||||
log.debug("5A chunk %d counter=0x%04X", chunk_num, counter)
|
||||
self._send(build_5a_frame(_BULK_CHUNK_OFFSET, params))
|
||||
|
||||
Reference in New Issue
Block a user