docs(series4): separate Thor's conventions from the protocol's requirements

SFM is not meant to reimplement Thor.  Thor is the only available teacher of the
wire protocol, but almost nothing about how it sequences its work has been shown
to be required by the device, and this document was starting to blur the two --
it said "a client should mirror it" where the honest claim is "Thor does this and
we have not checked whether the unit cares."

Adds a table separating the two, with required / not-required / unknown marked
honestly, and corrects the two places that gave Thor-copying advice.

The consequential unknowns, all testable:

  * Thor's POLL -> 0x15 -> 0x49 -> POLL preamble before EVERY operation.
    Plausibly required (Series III needed POLL x3 before 5A) but Thor sends it
    before trivial reads too.
  * 0x68 and 0x82 appear in every setup push carrying near-zero payloads that
    changed nothing in either capture.  If optional, our setup write is 3 frames
    instead of 7 with less to get wrong.  Worth settling BEFORE building the
    writer.
  * Whether a narrower write than the full 2,090-byte block is accepted.

One place Thor's shortcut is probably worse than the alternative: it reads with
offset=0xFFFF and skips the probe, but the probe works and reports the length
rather than making us trust a fixed one.

Two reliability problems to design against, both observed rather than assumed:
a zero ack does not mean a write applied (no failing write has ever been seen),
and nothing warns before clobbering a monitoring unit's active setup.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
This commit is contained in:
2026-09-24 19:44:05 -04:00
co-authored by Claude Opus 5
parent c5eed6fa46
commit bd876b6752
+47 -3
View File
@@ -1064,7 +1064,9 @@ Thor re-runs this before *every* operation — three times in this one capture:
POLL (0x5B) → SERIAL (0x15) → 0x49 → POLL (0x5B) → <the operation>
```
A client should mirror it. Note `POLL` here carries `offset = 0x0030` (its data
⚠ **Whether the unit requires this is untested** — see *Thor's conventions vs
the protocol's requirements*. Thor sends it before trivial reads too, so it may
be habit rather than handshake. Do not assume it is mandatory. Note `POLL` here carries `offset = 0x0030` (its data
length), not `0xFFFF` — `POLL` is the one read Thor still addresses by length.
### `SUB 0x96` / `0x97` — start and stop monitoring ✅
@@ -1159,8 +1161,10 @@ Micromate would reject the write. It squares with the earlier finding that a
push to the **active** setup overwrites silently — Thor is preventing exactly
the footgun the protocol leaves open.
**Any client we write should adopt the same rule**, and it is now cheap to
enforce: check `0x49` data[11] (or `0x1C` data[12]) before offering a write.
The *reason* behind the rule is sound and SFM should honour it — but not
necessarily by copying the greyed-out button. Stop → push → restart as a single
operation is what an operator usually wants, and `0x49` data[11] (or `0x1C`
data[12]) makes the state check cheap either way.
## Static analysis of the firmware (2026-09-23, solo session)
@@ -1297,6 +1301,46 @@ Worth noting the histogram (`…81`) and the loudest waveform (`…84`) report
the histogram's single 1-minute interval spans the whole thumping session, so
its maximum should equal the loudest event in it.
## Thor's conventions vs the protocol's requirements
**SFM is not meant to reimplement Thor.** Thor is the only available teacher of
the wire protocol, but almost nothing about *how* it sequences its work has been
shown to be required by the device. Those are two different things and this
document should not blur them.
The distinction matters because several observations above were written as
"a client should do X" when the honest statement is "Thor does X, and we have not
checked whether the unit cares."
| Thor does this | required? | what it means for SFM |
|---|---|---|
| `POLL → 0x15 → 0x49 → POLL` before **every** operation | **unknown** | Series III needed `POLL`×3 before `5A` *specifically*, so a preamble requirement is plausible — but Thor sends this before trivial reads too. **Testable:** issue one operation cold and see if it answers. |
| Reads with `offset = 0xFFFF`, skipping the probe | **no — the probe works** | We have a genuine choice, and the probe is arguably better: it reports the length instead of making us trust a fixed one. This is the one place Thor's shortcut is probably worse. |
| Sends `0x68` + `0x82` in every setup push | **unknown** | In both setup captures these carried near-zero payloads and **changed nothing**. If they are optional, a setup write is 3 frames instead of 7, with less to get wrong. **Worth testing before we build the writer.** |
| Rewrites the whole 2,090-byte config for a one-field change | **unknown** | No narrower write has been observed. Read-modify-write is safe and known; a targeted write would be nicer but is unevidenced. |
| Reads `0x41` twice in a row (scheduler capture, frames 6 and 8) | **no** | Plainly redundant. A reminder that Thor's sequence is not a minimal one. |
| Greys out send-to-unit while monitoring | **Thor policy** | The *reason* is real — a push to the active setup overwrites silently. But "the button is grey and you figure it out" is a UX choice, not the only answer. SFM could offer stop → push → restart as one operation, which is what an operator actually wants. |
| Names the target with `0xDA` before a config write | **almost certainly required** | The unit has to know which file to write. Closest thing here to a genuine protocol requirement. |
### What this implies for the build order
The read path is fully known and needs no Thor-shaped decisions, so a read-only
client can be written now with confidence. **The write path should not be built
by transcribing Thor's sequence** — the `0x68`/`0x82` question above decides
whether our setup write is 3 frames or 7, and it is answerable with one capture
plus one careful experiment.
Two reliability problems worth designing *against*, both observed rather than
assumed:
1. **A zero ack does not mean a write applied.** Every ack seen is 11 zero
bytes, across creates and overwrites alike, and no failing write has ever been
observed. Whatever SFM does, it should read back and compare rather than
trust the ack. `0x41` + `0x1A` makes that cheap.
2. **Nothing warns before clobbering a monitoring unit's active setup.** The
device will not stop it and the ack will not distinguish it. That guard has
to live in SFM.
## ⚠ Untested and unsafe-until-agreed
**Nothing below has been sent to a unit by us, and nothing should be without an