docs(series4): monitoring control, the setup-list walk, and the device clock

Thor started monitoring, listed the unit's setups and stopped monitoring while
seismo_lab recorded.  40 requests, 40 responses, every checksum valid.  As
before, Thor did all of it -- we have still never originated any of these.

Confirmed identical to Series III:

  * SUB 0x96 start monitoring -> ack 0x69
  * SUB 0x97 stop monitoring  -> ack 0x68

Both bare frames, no params, no data.  These were on the unsafe-until-agreed
list as entirely unobserved; they are now observed but still never sent by us.
Erase (0xA3/0xA2) is now the only genuinely untouched destructive path.

NOT identical to Series III, and worth not reusing constants for:

  * The monitoring flag is SUB 0x1C data[12] = 0x0E monitoring / 0x00 idle.
    Series III uses 0x10.
  * SUB 0x49 -> 0xB6 is a second, cheaper monitoring indicator at data[11]
    (0x02 monitoring / 0x00 idle) in a 21-byte response rather than 60.  Thor
    puts it in its preamble before every operation, so it is the routine check.

New this capture:

  * SUB 0x1C carries the DEVICE CLOCK at data[13:21] -- day, month, year (u16
    BE), hour, minute, second.  Verified against the capture's own wall time.
    Nothing else read so far reports the unit's time.  data[17] remains
    unidentified (32 monitoring, 100 idle) -- not claimed as anything.
  * Memory total is exactly 15,000,000 bytes; free dropped 4,096 bytes across a
    ~70s monitoring session, so free memory is not stable to compare against.
  * SUB 0x3F/0x40 walk the setup-file list, the same first/next shape as
    Series III's 1E/1F event walk.  0x3F -> 0xC0 first, 0x40 -> 0xBF next,
    terminating on an empty name.  23 setups on this unit.
  * Setup records carry ONLY the name -- 11-byte header, null-terminated name,
    zero padding.  There is no active-setup flag; the header is byte-identical
    on every record including the terminator.  The active setup is identified
    solely by SUB 0x41, which uses the same record format.  The asterisk on the
    unit's screen is UI decoration, not a field.
  * TEST1.mmb, created over the wire earlier today, appears in the list and is
    what 0x41 reports as active -- a written setup becomes a real enumerable
    file.

Also: Thor greys out send-to-unit while a unit is monitoring, and transmits
nothing (this capture contains no 0xDA or 0x71).  That is Thor policy, not a
device refusal -- nothing suggests the Micromate would reject it, and a push to
the active setup overwrites silently.  Thor is guarding the footgun the protocol
leaves open, and any client we write should do the same.  Checking 0x49 data[11]
first makes that cheap.

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:18:58 -04:00
co-authored by Claude Opus 5
parent b5e34ce8ae
commit 5400f1bef7
+122 -2
View File
@@ -442,6 +442,13 @@ memory 15,000,000 total and free (no events stored).
scan targets.
12. **The geophone scale factor is `3.10308`**, exactly half Series III's
`6.206053`, with an ADC of 10,000 counts per volt.
13. **The monitoring flag is `0x0E`**, where Series III uses `0x10` — and it
sits at `SUB 0x1C` `data[12]`. A second indicator lives at `SUB 0x49`
`data[11]` (`0x02` monitoring), which Series III has no equivalent of.
14. **Setup files are enumerated** with a `0x3F`/`0x40` first/next walk.
Series III has one config and nothing to enumerate.
15. **`SUB 0x1C` carries the device clock** (day/month/year/h/m/s at
`data[13:21]`). Nothing else read so far reports the unit's own time.
---
@@ -913,6 +920,118 @@ a create and an overwrite. We have never seen this protocol report a *failed*
write, so **do not treat a zero ack as proof a write was applied.** Read the
config back and compare; `SUB 0x41` plus `SUB 0x1A` make that cheap.
## Monitoring control and the setup list (2026-09-24)
Capture: `bridges/captures/9-24-26 - micromate2/*_turn_on_monitormode_*`.
Thor started monitoring, listed the unit's setups, and stopped monitoring.
**40 request frames and 40 responses, every checksum valid.**
### Thor's per-operation preamble
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
length), not `0xFFFF` — `POLL` is the one read Thor still addresses by length.
### `SUB 0x96` / `0x97` — start and stop monitoring ✅
Identical to Series III, including the acks:
| request | ack | effect |
|---|---|---|
| `0x96` | `0x69` | **start monitoring** |
| `0x97` | `0x68` | **stop monitoring** |
Both are bare frames — no params, no data — and both ack with the usual 16-byte
zero-data response. Thor follows each with a `SUB 0x1C` status read to confirm.
### `SUB 0x1C` — monitor status, 55-byte data
```
data[12] monitoring flag 0x0E monitoring / 0x00 idle
data[13] day
data[14] month
data[15:17] year, uint16 BE
data[17] ⚠ unidentified — 32 while monitoring, 100 when idle
data[18] hour ─┐ device clock, verified against the capture's
data[19] minute │ own wall time (19:12:25 → 19:13:34 EDT)
data[20] second ─┘
data[-8:-4] memory total, uint32 BE = 15,000,000 bytes exactly
data[-4:] memory free, uint32 BE
```
⚠ **The monitoring flag is `0x0E`, not Series III's `0x10`.** Do not reuse the
Series III constant. Only five bytes differ between the monitoring and idle
responses: the flag, `data[17]`, the clock, and the memory-free field.
Memory free dropped by exactly **4,096 bytes** across the ~70-second monitoring
session — monitoring allocates as it runs, so free memory is not a stable value
to compare against.
The device clock is free here, on a command Thor already sends. That is worth
having: nothing else read so far reports the unit's own time.
### `SUB 0x49` → `0xB6` — a cheap state check
16-byte data, in Thor's preamble before every operation:
```
05 00 00 00 00 00 00 00 00 00 00 [ST] e8 00 0b 00
↑ data[11]: 0x02 monitoring, 0x00 idle
```
**A second monitoring indicator, in a 21-byte response instead of `0x1C`'s 60.**
Different encoding from `0x1C`'s flag (`0x02` vs `0x0E`), so they are separate
fields, not the same byte read twice. For a polling client this is the cheaper
of the two, and Thor evidently treats it as the routine one.
### `SUB 0x3F` / `0x40` — walking the setup-file list ✅
The same first/next shape as Series III's `1E`/`1F` event walk, applied to
setup files:
| request | ack | meaning |
|---|---|---|
| `0x3F` | `0xC0` | **first** setup record |
| `0x40` | `0xBF` | **next** setup record; repeat until the name is empty |
Every record is 266 bytes of data and carries **nothing but the name**:
```
ff 00 00 00 00 00 00 00 00 00 00 <null-terminated name> 00 …
└──────────── 11-byte header ─────┘
```
The walk ends on a record whose name is empty — 24 records for 23 setups.
`factory.MMB` comes first, from `0x3F`.
**There is no active-setup flag in the list.** The header is byte-identical on
every record including the terminator, and the tail is all zeros. The active
setup is identified only by `SUB 0x41`, whose response uses this exact record
format. (On the unit's own screen the active setup is marked with a trailing
asterisk — that is a UI decoration, not a field.)
`TEST1.mmb`, created over the wire earlier the same day, appears in the list and
is what `0x41` reports as active — independent confirmation that a written setup
becomes a real, enumerable file.
### Thor refuses to send a setup while a unit is monitoring
Send-to-unit is **greyed out in Thor's UI** when the unit is monitoring, and
nothing is transmitted — this capture contains no `0xDA` or `0x71` at all.
That is a Thor-side policy, not a device refusal: nothing observed suggests the
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.
## Static analysis of the firmware (2026-09-23, solo session)
### Architecture
@@ -1061,8 +1180,9 @@ is known; our encoder is unwritten and unproven.
- **Writes** (`0x68`–`0x83`) — format now known, never sent by us
- **Call-home write** (`0x7E` / `0x7F`) — not observed at all
- **Erase** (`0xA3` / `0xA2`)
- **Start / stop monitoring** (`0x96` / `0x97`)
- **Erase** (`0xA3` / `0xA2`) — **the only genuinely untouched destructive path**
- **Start / stop monitoring** (`0x96` / `0x97`) — observed via Thor 2026-09-24,
acks `0x69` / `0x68`; still never originated by us
- `0x1F` (advance event pointer) — non-destructive on Series III but it does
move device state, so it is parked with the rest