diff --git a/docs/micromate_protocol_reference.md b/docs/micromate_protocol_reference.md index e55a682..6350d69 100644 --- a/docs/micromate_protocol_reference.md +++ b/docs/micromate_protocol_reference.md @@ -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) → +``` + +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 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