docs(series4): the ACH session, from the THOR manual -- and I was asking the wrong question
Brian uploaded the Instantel manuals (gitignored, manuals/). The THOR Operator
Manual Rev 08 settles the thing this document called the blocker for a homebrew
receiver.
I had written that what gates a receiver is "how it learns an event was accepted
so it stops re-sending it." There is no such mechanism to find, because the unit
does not track it. Per THOR manual 6.2.2.2 an ACH session is a list of
SERVER-chosen actions -- Copy events, Copy monitor log, Delete events and Logs
from Unit, Set Date/Time -- and "Only applies to events not previously
downloaded" is computer-side bookkeeping. The manual's own warning proves copy
and delete are decoupled: enable delete but disable copy and "the events and logs
will be deleted without being uploaded."
That is exactly the model our Series III ACH server already implements
(ach_state.json high-water mark, erase as a deliberate separate step). No new
mechanism is needed for Series IV. A receiver needs: accept, identify, walk the
events (already solved), keep our own high-water mark, optionally erase. The
ERASE OPCODES are now the only genuinely missing piece and stay on the unsafe
list.
Other things the manual settles:
* The session is server-driven, matching the firmware state machine. Scheduled
and event-triggered ACH differ: with Monitoring While Calling Home enabled, an
event-triggered session will NOT delete events or sync time. So a receiver
that relies on erase to avoid re-reading would silently never erase on those
units -- the high-water mark has to be primary, erase an optimisation.
* Session Time Out is unit-side only, which places it in callhome.MMB -- another
reason to read that file with 0x94.
* Units are routed by serial number with wildcards, so the serial is presented
early enough for a server to dispatch on it.
* THOR requires Idle for ACH setup too, confirming the greyed-out send is
deliberate policy rather than a device refusal.
* THOR exposes four schedule actions; the firmware has five. 6.3.2 step 8
("A Unit Setup must exist") is THOR's own requirement, while the same section
says the unit "will execute any actions in a schedule using its current
settings" -- the two pull opposite ways, consistent with START_MONITOR
existing and THOR never emitting it.
* Schedule fields to look for when the entry is decoded: action, setup name,
time, day-or-week, day selection, repeat. The captured entry has seven bytes
before the name, the right order of magnitude for that list.
Flagged: the manual's filter example contradicts its own table (it has UM* and MP*
backwards). The table is right.
Marked throughout as vendor documentation rather than observed bytes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
This commit is contained in:
@@ -1301,6 +1301,125 @@ Worth noting the histogram (`…81`) and the loudest waveform (`…84`) report
|
|||||||
the histogram's single 1-minute interval spans the whole thumping session, so
|
the histogram's single 1-minute interval spans the whole thumping session, so
|
||||||
its maximum should equal the loudest event in it.
|
its maximum should equal the loudest event in it.
|
||||||
|
|
||||||
|
## What the THOR manual settles about the ACH session (2026-09-24)
|
||||||
|
|
||||||
|
Source: `manuals/723U0201 THOR Operator Manual Rev 08.pdf` §6.2, §3.6.
|
||||||
|
⚠ **This is vendor documentation, not observed bytes.** It tells us the shape of
|
||||||
|
the session and the vocabulary; it does not give opcodes. Treated as a strong
|
||||||
|
prior, not as confirmed protocol.
|
||||||
|
|
||||||
|
### 🔑 A unit does NOT learn that an event was accepted — the server decides
|
||||||
|
|
||||||
|
This document previously listed, as the thing *gating any homebrew receiver*:
|
||||||
|
|
||||||
|
> how a unit announces itself, and **how it learns an event was accepted so it
|
||||||
|
> stops re-sending it.**
|
||||||
|
|
||||||
|
**That was the wrong question.** There is no acknowledgement mechanism to
|
||||||
|
discover, because the unit is not tracking what has been collected. Per §6.2.2.2
|
||||||
|
the ACH session is a list of **server-chosen actions**, and two of them are
|
||||||
|
independent:
|
||||||
|
|
||||||
|
| ACH action | what it does |
|
||||||
|
|---|---|
|
||||||
|
| **Copy events** | downloads events — *"Only applies to events not previously downloaded"* |
|
||||||
|
| **Copy monitor log** | downloads the monitor log |
|
||||||
|
| **Delete events and Logs from Unit** | **explicitly** deletes them from the unit |
|
||||||
|
| **Set Date/Time** | unit synchronises its clock **from the computer** |
|
||||||
|
| Send Events / Schedule to Vision | Instantel cloud, not relevant to us |
|
||||||
|
|
||||||
|
"Not previously downloaded" is **computer-side bookkeeping**. The unit keeps its
|
||||||
|
events until a server tells it to erase them, and the manual's own warning proves
|
||||||
|
the two are decoupled:
|
||||||
|
|
||||||
|
> ⚠ *"If you enable 'Delete Events and Logs from Unit' but disable 'Copy Events'.
|
||||||
|
> The events and logs will be deleted without being uploaded."*
|
||||||
|
|
||||||
|
A server that never issues the delete simply re-reads the same events forever.
|
||||||
|
|
||||||
|
**This is exactly the model our Series III ACH server already implements** —
|
||||||
|
`ach_state.json` with `downloaded_keys` / `max_downloaded_key`, and erase as a
|
||||||
|
separate deliberate step. No new mechanism is needed for Series IV.
|
||||||
|
|
||||||
|
So a homebrew receiver needs: accept the connection, identify the unit, walk the
|
||||||
|
events (already solved — `0x08`/`0x1E`/`0x0A`/`0x5A`), keep our own high-water
|
||||||
|
mark, and *optionally* erase. **The erase opcodes are the only genuinely missing
|
||||||
|
piece**, and they remain on the unsafe list.
|
||||||
|
|
||||||
|
### The session is server-driven
|
||||||
|
|
||||||
|
Which matches the firmware's state machine and its
|
||||||
|
`CMD_EXIT_CALL_HOME_DELETE_EVENTS_START_MONITORING` /
|
||||||
|
`Call Home Deleting Events` strings: the unit dials in, then waits to be told
|
||||||
|
what to do, and returns to monitoring when the server is finished.
|
||||||
|
|
||||||
|
Scheduled ACH and event-triggered ACH behave differently (§3.6.1):
|
||||||
|
|
||||||
|
- **Event-triggered** (ACH enabled on the unit, an event occurred) — *"Records
|
||||||
|
events + transfer data, no stopping to monitor."* Governed by **Monitoring
|
||||||
|
While Calling Home**; with MWCH enabled *"the monitor log will not be copied,
|
||||||
|
events will not be deleted, and time will not synchronize"*.
|
||||||
|
- **Scheduled** — *"Stop monitoring + transfer data (or delete events, or
|
||||||
|
synchronize)."* Monitoring stops and in-progress events complete first.
|
||||||
|
|
||||||
|
⚠ Worth noting for SFM: with MWCH on, an event-triggered session **cannot**
|
||||||
|
delete or sync. A receiver that relies on erase to avoid re-reading will
|
||||||
|
silently never erase on those units. Our high-water mark must be the primary
|
||||||
|
mechanism, with erase as an optimisation — which is how Series III already does it.
|
||||||
|
|
||||||
|
### Session Time Out is unit-side only
|
||||||
|
|
||||||
|
§6.2 is explicit that THOR configures ACH on both ends *"with one exception; the
|
||||||
|
Session Time Out. This must be configured directly on the unit."* That matches
|
||||||
|
the firmware's `CallHome.SessionTimeout` field, and means it lives in
|
||||||
|
`callhome.MMB` rather than anywhere THOR reaches — one more reason to read that
|
||||||
|
file with `0x94`.
|
||||||
|
|
||||||
|
### Unit identification is by serial number, with wildcards
|
||||||
|
|
||||||
|
§6.2.2.2: filters match against the serial number the unit presents, `*`
|
||||||
|
wildcards allowed, best-match wins — `UM*` all Micromates, `MP*` all Minimate
|
||||||
|
Pros, `BE`/`BC` Minimate Plus variants.
|
||||||
|
|
||||||
|
So **the unit announces its serial early enough for the server to route on it.**
|
||||||
|
`SUB 0x15` returns the serial and is in Thor's standard preamble, which is
|
||||||
|
consistent, though the inbound direction has still never been observed.
|
||||||
|
|
||||||
|
⚠ The manual's worked example contradicts its own table — it says *"To filter
|
||||||
|
Micromate units type MP*"* and *"To filter Minimate Pro units type UM*"*, which is
|
||||||
|
backwards. The table is right. Noted so nobody copies the error.
|
||||||
|
|
||||||
|
### Thor requires Idle for configuration
|
||||||
|
|
||||||
|
§6.2.1 step 3: *"The Monitoring Mode must be 'Idle'."* Independent confirmation
|
||||||
|
that the greyed-out send observed on the bench is deliberate Thor policy, applied
|
||||||
|
to ACH setup as well as compliance setup — and still not evidence the device
|
||||||
|
refuses.
|
||||||
|
|
||||||
|
### The schedule's actions, from the UI side
|
||||||
|
|
||||||
|
§3.6 lists exactly **four** actions THOR exposes: Start monitoring, Stop
|
||||||
|
monitoring, Self-check, Auto Call Home. The firmware has **five** — it also has
|
||||||
|
a setup-less `DUTYCYCLE_START_MONITOR`.
|
||||||
|
|
||||||
|
§3.6.2 step 8 confirms the coupling is Thor's own requirement: *"Select the
|
||||||
|
appropriate Action and the Unit Setup. (A Unit Setup must exist…)"* — while §3.6.2
|
||||||
|
step 1 notes *"The unit will execute any actions in a schedule using its current
|
||||||
|
settings."* The two statements sit a paragraph apart and pull in opposite
|
||||||
|
directions, which is consistent with `START_MONITOR` existing and THOR never
|
||||||
|
emitting it.
|
||||||
|
|
||||||
|
Also from §3.6: schedules are **Day or Week** ("Select Day… Select Week"), have a
|
||||||
|
**Repeat Daily / Repeat Weekly** flag, carry a Name, Description and Unit Type,
|
||||||
|
and *"Saving a schedule will only store it on the computer, it must still be sent
|
||||||
|
to the unit and enabled"* — which is why the capture shows `0x8E` (send) and
|
||||||
|
`0x47` (enable) as separate steps.
|
||||||
|
|
||||||
|
Those are the fields to look for when the schedule entry is finally decoded:
|
||||||
|
**action, setup name, time, day-or-week, day selection, repeat.** The one
|
||||||
|
captured entry (`03 00 00 00 0f 03 02 …`) has seven bytes before the name, which
|
||||||
|
is the right order of magnitude for that field list.
|
||||||
|
|
||||||
## Thor's conventions vs the protocol's requirements
|
## Thor's conventions vs the protocol's requirements
|
||||||
|
|
||||||
**SFM is not meant to reimplement Thor.** Thor is the only available teacher of
|
**SFM is not meant to reimplement Thor.** Thor is the only available teacher of
|
||||||
@@ -1460,11 +1579,16 @@ Also unknown:
|
|||||||
|
|
||||||
- Whether `0x10` bytes inside **request params** need stuffing. (Write-frame
|
- Whether `0x10` bytes inside **request params** need stuffing. (Write-frame
|
||||||
**data** stuffing *is* now settled — `10 XX` → `XX`; see *The write path*.)
|
**data** stuffing *is* now settled — `10 XX` → `XX`; see *The write path*.)
|
||||||
- Everything about the **call-home session** — the device-initiated direction
|
- The **call-home session's bytes** — the device-initiated direction has still
|
||||||
has not been observed at all. Specifically: how a unit announces itself,
|
not been observed at all, and cannot be over USB.
|
||||||
and **how it learns an event was accepted so it stops re-sending it.**
|
|
||||||
That last question gates any homebrew receiver and cannot be answered over
|
✅ **The second half of this item is resolved** (2026-09-24, from the THOR
|
||||||
USB.
|
manual): "how it learns an event was accepted so it stops re-sending it" was
|
||||||
|
the wrong question — **it does not learn.** Collection state is server-side
|
||||||
|
bookkeeping and erase is a separate, optional, server-issued action. See
|
||||||
|
*What the THOR manual settles about the ACH session*. What remains unknown is
|
||||||
|
the framing of the inbound session and the **erase opcodes**, not any
|
||||||
|
acknowledgement mechanism.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user