diff --git a/docs/micromate_protocol_reference.md b/docs/micromate_protocol_reference.md index f2bda66..124adde 100644 --- a/docs/micromate_protocol_reference.md +++ b/docs/micromate_protocol_reference.md @@ -449,6 +449,13 @@ memory 15,000,000 total and free (no events stored). 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. +18. **Deletion is per-event** (`0xA8` + a key, then `0xAA`), where Series III can + only erase everything (`0xA3`/`0xA2`). +19. **`SUB 0x93` arms each event** before `1E`/`1F`, replacing Series III's + `1E(token=0xFE)` — no token, no params. +20. **Event keys are a sequential counter** (`055D4A81…86`), not flash addresses. +21. **The ACH enable is `0x05`/`0x04`**, not Series III's `0x01`/`0x00` — bit 0 + is the flag, bit 2 is set in both states. 16. **There is a generic file transfer addressed by full path** — `0x94`/`0x48` read, `0x8D`/`0x8E` write. Series III has nothing comparable; its config is reachable only through dedicated commands. @@ -1301,6 +1308,141 @@ 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. +## Event download, per-event delete, and ACH config (2026-09-25) + +Three captures with operator-supplied ground truth, including Thor screenshots of +the event list and the schedule. All Thor-originated; we still send nothing. + +### ✅ `Day` is the day of week — and `[0]` is the schedule type + +A **weekly** schedule settles both fields. Thor's screen: *"multiday, Repeat +Weekly: Disabled, Start Monitoring at 8:00 AM every day, alternating +TEST1 / test2."* The file is **7 × 260 + 4 = 1,824 bytes**, and every record +matches: + +| rec | `1/2h` | time | `Day` | | `[6]` | name | +|---|---|---|---|---|---|---| +| @0 | 16 | 08:00 | **0** | Sun | 2 | `TEST1.mmb` | +| @260 | 16 | 08:00 | **1** | Mon | 2 | `test2.mmb` | +| @520 | 16 | 08:00 | **2** | Tue | 2 | `TEST1.mmb` | +| @780 | 16 | 08:00 | **3** | Wed | 2 | `test2.mmb` | +| @1040 | 16 | 08:00 | **4** | Thu | 2 | `TEST1.mmb` | +| @1300 | 16 | 08:00 | **5** | Fri | 2 | `test2.mmb` | +| @1560 | 16 | 08:00 | **6** | Sat | 2 | `TEST1.mmb` | + +**`Day` = 0 Sunday … 6 Saturday**, and the alternating setup names line up with +the screen row for row. + +`[0]` on record 0 read **4** here, against `2` and `3` in the daily schedules — +so it carries the schedule *type* as well as Repeat: + +| `[0]` | meaning | +|---|---| +| `2` | Daily, repeat off | +| `3` | Daily, repeat on | +| `4` | **Weekly, repeat off** | +| `5` | Weekly, repeat on — ⚠ predicted, not observed | + +Bit 0 is Repeat; `2` and `4` are the Day/Week bases. Same bitmask style as +`[6]`. + +⚠ In *daily* schedules `Day` reads `3` in every record of every capture. With +`[0]` already saying "daily", the field is presumably ignored there — but that is +inference, and `3` is unexplained. + +### Event download — `SUB 0x93` arms each event + +Thor's download of six events: + +``` +POLL 0x15 0x49 POLL 0x1C 0x15 0x49 0x06 + 0x93 0x1E 0x0C 0x5A×4 ← event 1 + 0x93 0x1F 0x0C 0x5A×11 ← event 2 + 0x93 0x1F 0x0C 0x5A×12 ← event 3 + 0x93 0x1F 0x0C 0x5A×14 ← event 4 + 0x93 0x1F 0x0C 0x5A×9 ← event 5 + 0x93 0x1F 0x0C 0x5A×6 ← event 6 + 0x93 0x06 0x93 0x1E 0x0A×9 ← re-walk the list +``` + +**`SUB 0x93` → ack `0x6C`** is sent before every event, with empty params and an +all-zero ack. It is the Series IV analogue of Series III's `1E(token=0xFE)` arm +step, and it is simpler: no token, no params. + +**Event keys are a plain sequential counter.** The six events walked as +`055D4A81 … 055D4A86`, consecutive, at `data[11:15]` of the `0x1E`/`0x1F` +response, with the event's byte size at `data[17:19]`. Nothing like Series III's +flash addresses. + +`SUB 0x0A` walks the event list returning **30-byte records** carrying start and +stop timestamps (`[11]` day, `[12]` month, `[13:15]` year BE …), terminating on +an all-zero record. The dates match Thor's event list exactly (five events on +09/23/2026, one on 09/24/2026). + +### 🔑 Delete is PER-EVENT — `SUB 0xA8` + `0xAA` + +``` +0xA8 params[0:4] = → ack 0x57 +0xAA params = zeros → ack 0x55 +``` + +The operator deleted the **top row of Thor's list** — the newest event — and +`0xA8` carried `05 5d 4a 86`, the **highest** key from the walk. Thor lists +newest-first, so newest = highest key. Confirmed end to end. + +**This is the last piece a homebrew ACH receiver was missing.** The manual +established that collection state is server-side bookkeeping and that "delete +events from unit" is a separate server-issued action; this is that action's +opcodes. + +Two things worth noting against Series III: + +- Series III erases **everything** (`0xA3 → 0x1C → 0x06 → 0xA2`). Series IV + deletes **one named event**, which is strictly safer — a receiver can delete + exactly what it has confirmed it stored. +- The opcodes are different. Do not reach for `0xA3`/`0xA2` here. + +⚠ `SUB 0x06` (storage range) read **identically before and after** the delete in +this capture, so it is not a quick way to confirm a deletion landed. Re-walk the +event list instead. + +### ✅ ACH config — `0x2C` / `0x7E` / `0x7F`, exactly Series III + +Thor enabling then disabling Auto Call Home, twice through the same sequence: + +``` +POLL → 0x15 → 0x49 → POLL → 0x2C (read) → 0x7E (write, 126 B) → 0x7F (confirm) +``` + +Same SUBs and the same acks as Series III — `0x2C`→`0xD3`, `0x7E`→`0x81`, +`0x7F`→`0x80`. The write payload is **126 bytes** with `offset = 0x007E`, and +the `0x2C` read returns those same 126 bytes behind an **11-byte prefix**, so +`read[n + 11]` is `write[n]`. + +**The enable flag is `write[5]`** (= `read[16]`): + +| value | state | +|---|---| +| `0x05` | Auto Call Home **enabled** | +| `0x04` | **disabled** | + +Bit 0 is the enable — the same bit position Series III uses at `raw[5]`, but with +bit 2 set as well in both states. Do not test for `0x01`/`0x00`. + +`write[6:]` holds the dial string, null-padded — `"RADIO RING"` on this unit, +matching Series III's `raw[6:46]`. + +⚠ **`write[118:120]` changed on its own between the two sessions** (`43 23` → +`2e 5e`) without the operator touching anything. Thor reads it and writes back +whatever it read. Its meaning is unknown — plausibly a counter, timer or +session value. **Round-trip this field; never synthesise it.** `write[117]` is +`0x03`, which lines up with Series III's `num_retries` of 3, and `write[120:122]` +is `00 3c` = 60. + +⚠ Beyond the enable byte and the dial string, **the field map is not +established** — only one setting was varied. Series III's offsets are a starting +hypothesis, not a transfer. + ## 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. @@ -1776,11 +1918,19 @@ because Thor performed it while we recorded. Observed is not the same as exercised — **we have still never originated a write frame.** The wire format 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`) — **the only genuinely untouched destructive path** +- **Writes** (`0x68`–`0x83`) — format known, never sent by us +- **Call-home write** (`0x7E` / `0x7F`) — ✅ observed 2026-09-25, acks `0x81` / + `0x80`; enable flag isolated +- **Per-event delete** (`0xA8` / `0xAA`) — ✅ observed 2026-09-25, acks `0x57` / + `0x55`. **Destructive.** Series III's `0xA3`/`0xA2` erase-all has *not* been + seen on Series IV and may not exist - **Start / stop monitoring** (`0x96` / `0x97`) — observed via Thor 2026-09-24, - acks `0x69` / `0x68`; still never originated by us + acks `0x69` / `0x68` +- **Scheduler enable** (`0x47`) — observed; `params[7]` semantics still unclear + +Every one of these is now *observed*. **None has ever been originated by us**, +and that is the line that still matters: the wire format is known, our encoder is +unwritten and unproven. - `0x1F` (advance event pointer) — non-destructive on Series III but it does move device state, so it is parked with the rest