Files
seismo-relay/docs/micromate_protocol_reference.md
T
serversdownandClaude Opus 5 b9c52442a7 docs(series4): the Series III behaviour is firmware-conditional
The bench unit reports 11.0CB -- Instantel's *Blastware* firmware line. It
almost certainly answers Series III commands because it is in Blastware mode,
not because the Micromate natively speaks Series III. Instantel ships two
lines: 11.0CB (Blastware) and 11.0BD (THOR, Vision, Vision II).

That also explains the two-ACH-server problem as designed behaviour rather
than misconfiguration.

Corpus firmware audit: 932 event files from 11.0AK, 83 from 10.90GC. UM12947
itself produced 10.90GC files in production last year and reports 11.0CB now,
so units get reflashed and firmware is not stable per-unit over time.

Records the resulting strategic fork (standardise on the Blastware line vs
reverse-engineer the Thor line) with the four unknowns that decide it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
2026-09-23 16:04:42 -04:00

293 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Micromate Protocol Reference — Thor / Micromate Series IV, live wire protocol
Sibling to [instantel_protocol_reference.md](instantel_protocol_reference.md)
(Series III, "the Rosetta Stone") and
[idf_protocol_reference.md](idf_protocol_reference.md) (Series IV *file*
format). This document covers the Series IV **live device protocol** — what
the unit says over the wire, as opposed to what it writes into a `.IDFW`.
**Status (2026-09-23): opening session.** Everything below was established in
a single bench session against one unit. Treat it as a strong start, not a
settled spec — in particular, everything here comes from **one unit, over USB,
with no events stored**.
---
## The headline
**A Micromate running the *Blastware* firmware answers Series III command
frames.**
An unmodified Series III `POLL` (`SUB 0x5B`), built by
`minimateplus.framing.build_bw_frame` with no changes at all, produced a
complete two-step probe/data cycle. Ten Series III read commands were then
tried and **all ten answered**, every one obeying the Series III response-SUB
rule.
⚠ **That qualifier is load-bearing, and it was discovered after the fact.**
Instantel ships the Micromate in two firmware lines:
| firmware | Instantel's own description |
|---|---|
| `11.0CB` | "Utilize with **Blastware**" |
| `11.0BD` | "Utilize with **THOR, Vision, Vision II**" |
The bench unit reports **`11.0CB`** — the Blastware build. So the clean
Series III behaviour above is very likely *because the unit is in Blastware
mode*, not because the Micromate natively speaks Series III. **Nothing here
should be assumed to hold on a `11.0BD` unit until tested.**
This reframes the project. The question is no longer only "what is the
Series IV protocol" but **"which firmware line do we target, and does one of
them let the existing Series III stack drive the whole fleet?"**
---
## Firmware — the variable nobody knew was a variable
This explains a production problem TMI has lived with: two ACH servers, two
machines, and units that will not cross over. It is not a misconfiguration.
**Instantel ships different firmware for different host software**, and the
wire protocol differs with it.
Versions observed so far:
| where | version | notes |
|---|---|---|
| bench unit UM12947, today | **`11.0CB`** | Blastware line — answers Series III |
| corpus, 932 event files | `11.0AK` | produced Thor-collected `.IDFW`/`.IDFH` |
| corpus, 83 event files | `10.90GC` | older; UM12947's own files from Sept 2025 |
Note UM12947 produced `10.90GC` files in production last year and reports
`11.0CB` on the bench now — so **it has been reflashed at some point**, and
firmware is not stable per-unit over time. Any fleet-wide claim needs a
per-unit firmware audit first.
The version is readable over the wire from `SUB 0x01` as two separate ASCII
runs — `"0CB"` then `"11"` — with no single concatenated string.
### The strategic fork
- **Option A — standardise the fleet on the Blastware line.** Every unit,
MiniMate and Micromate alike, then speaks Series III, and the existing
`minimateplus/` stack drives all of it. One protocol, one call-home
receiver. Dramatically cheaper *if* it holds up.
- **Option B — reverse-engineer the Thor line (`11.0BD`) and support both.**
Option A is the shortcut, but it is unproven and carries real unknowns, all
of which are cheap to answer on the bench and expensive to discover later:
1. **What file format does a `11.0CB` unit produce?** If it emits Blastware
binaries rather than `.IDFW`/`.IDFH`, the (now exact) Series III decoder
applies and the IDF codec becomes a legacy path. Not a loss — we have
both — but it changes what the ingest pipeline sees.
2. **Does Thor still work with a `11.0CB` unit?** If not, flashing a
production unit breaks data collection until the replacement path exists.
3. **Are any Micromate-specific capabilities lost** on the Blastware line?
4. **Is the flash reversible in the field**, and what does it cost in downtime?
## How this was obtained
No Thor, no modem, no Windows machine. The Micromate exposes its protocol on
a **USB CDC-ACM virtual serial port**:
```
ID 2504:0300 Instantel Inc. MICROMATE COM PORT
driver: cdc_acm ATTRS{serial}=="V1.00"
→ /dev/ttyACM0
```
Plain CDC ACM, so no vendor driver and no proprietary USB layer — any host
that can open a serial port can talk to the unit.
**Baud is irrelevant over USB.** Identical byte-for-byte responses at 38400
and 115200; CDC-ACM ignores the line rate. TMI provisions Micromate *modem*
links at **115200** (Series III uses 38400) — that matters for the cellular
path, not for USB.
**The device never speaks first.** 20 s of passive listening on an idle open
port produced zero bytes. It is strictly request/response.
---
## Physical + framing layer
### Requests — Series III format, unmodified
Every frame in this session was produced by `build_bw_frame(sub, offset)` with
no Series IV changes, and the device accepted all of them:
```
[ACK 0x41] [STX 0x02] [10 10] [flags 00] [SUB] [00] [00] [offset] [params×10] [chk] [ETX 0x03]
```
⚠ Only the doubled `BW_CMD` (`10 10`) form has been exercised. Whether other
literal `0x10` bytes inside params require stuffing is **untested** — none of
the probes sent carried one.
### Responses — Series III *minus the DLE prefix*
```
Series III: [DLE 0x10] [STX 0x02] … [chk] [ETX 0x03]
Micromate: [STX 0x02] … [chk] [ETX 0x03] ← no leading DLE
```
This single byte matters operationally: Blastware's parser locates frames by
scanning for `DLE+STX`, so it will **never find a frame boundary** in Micromate
traffic no matter what else is correct. That is a structural reason a
Micromate cannot call into a Blastware ACH server, independent of any baud
mismatch.
### Response payload header
```
[0] CMD 0x00 same as Series III
[1] flags 0xC5 ← Series III uses 0x10. Constant across all 10 SUBs.
[2] SUB 0xFF − request_SUB
[3] PAGE_HI
[4] PAGE_LO
[5+] data
```
### Checksum — the DLE-aware variant
```python
chk = sum(b for b in payload if b != 0x10) & 0xFF
```
Confirmed on every frame captured. The `POLL` probe response contains no
`0x10` and so cannot distinguish plain SUM8 from the DLE-aware form; the
`POLL` **data** response contains a `0x10` at payload offset 42, and only the
DLE-aware rule matches there. This is the same checksum Series III uses for
its `5A` bulk-stream and write frames — not the plain SUM8 of ordinary
Series III reads.
### The probe response carries the data length
Series III hardcodes `DATA_LENGTHS` per SUB. On the Micromate the **probe
response tells you**, at `payload[9]`:
| SUB | command | `payload[9]` | Series III constant |
|---|---|---|---|
| `0x15` | serial number | `0x0A` | `0x0A` ✓ |
| `0x01` | device info | `0x98` | `0x98` ✓ |
| `0x1C` | monitor status | `0x2C` | `0x2C` ✓ |
| `0x06` | storage range | `0x24` | `0x24` ✓ |
| `0x2C` | call-home config | `0x7E` | `0x7C` ✗ **differs by 2** |
| `0x08` | event index | `0x5A` | — |
| `0x1E` | event header | `0x08` | — |
| `0x1A` | compliance config | `0x2C` | — |
| `0x0A` | waveform header | `0x00` | — (no event context) |
| `0xFE` | full config | `0x00` | — (see note) |
Four of four known Series III lengths match exactly. **Read the length from
the probe rather than hardcoding it** — it is free, and it already caught the
call-home divergence.
---
## Confirmed commands (read-only)
All ten below answered with a correct `0xFF − SUB` response. Nothing that
writes, erases, or changes monitoring state has been sent to a unit.
| SUB | RSP | Command | Data proven |
|---|---|---|---|
| `0x5B` | `0xA4` | POLL / handshake | yes — ID block |
| `0x15` | `0xEA` | Serial number | yes — `UM12947` |
| `0x01` | `0xFE` | Device info | yes — 152 B |
| `0x2C` | `0xD3` | Call-home config | yes — 126 B |
| `0x1C` | `0xE3` | Monitor status | yes — 44 B |
| `0x06` | `0xF9` | Event storage range | yes — 36 B |
| `0x08` | `0xF7` | Event index | probe only |
| `0x1E` | `0xE1` | Event header / first key | probe only |
| `0x0A` | `0xF5` | Waveform header | probe only |
| `0x1A` | `0xE5` | Compliance config | probe only |
### Decoded so far
**`SUB 0x15` — serial.** ASCII, null-terminated: `UM12947`.
**`SUB 0x5B` / `0x01` — identification strings.**
`Instantel\0` and `MM/ISEE/S/IO` (MicroMate / ISEE standard). `0x01` also
carries eight consecutive `3f 80 00 00` float32 values (= `1.0f`) — almost
certainly per-channel calibration/scale factors, by analogy with Series III's
`geo_hardware_constant`. **Unverified.**
**`SUB 0x1C` — monitor status. Series III field offsets apply unchanged:**
| field | offset | read |
|---|---|---|
| battery × 100 | `payload[-10:-8]` uint16 BE | `0x017D` → **3.81 V** |
| memory total | `payload[-8:-4]` uint32 BE | 15,000,000 |
| memory free | `payload[-4:]` uint32 BE | 15,000,000 (empty) |
| date | `payload[18:22]` | day 23, month 9, year `0x07EA` = 2026 |
The battery reading independently corroborates: Thor's own event reports for
these units print `BatteryLevel : 3.8 volts`.
**`SUB 0x2C` — call-home config.** Contains the ASCII string `RADIO RING`.
Worth flagging: that is the *exact* string seen in the RV50 `ALEOS_SERIAL`
debug during the BE12599 incident —
`'ATQ1^MATE0^MATS0=2^M^MRADIO RING^M'`. So this block holds the modem dial /
answer strings, and it is the most directly relevant command to the
call-home-receiver goal. Field layout **not yet mapped**; Series III's map
(`raw[5]` enabled, `raw[6:46]` dial string) is a starting hypothesis only, and
the length already differs (`0x7E` vs `0x7C`).
**`SUB 0x06` — storage range.** All zeros on this unit, consistent with
`memory free == memory total`. Series III reads first/last event keys from
the final 8 bytes; untestable until the unit holds events.
---
## Divergences from Series III (running list)
1. **No `DLE` prefix on responses** — bare `STX`.
2. **Response flags byte is `0xC5`**, not `0x10`.
3. **Call-home config is 126 bytes**, not 124.
4. **Data lengths are discoverable** from the probe response at `payload[9]`.
5. **Modem serial rate is 115200**, not 38400 (per TMI provisioning practice;
not independently verified here).
---
## ⚠ Untested and unsafe-until-agreed
Nothing below has been sent to a unit, and nothing should be without an
explicit decision:
- **Writes** (`0x68`–`0x83`), **call-home write** (`0x7E`/`0x7F`)
- **Erase** (`0xA3` / `0xA2`)
- **Start / stop monitoring** (`0x96` / `0x97`)
- `0x1F` (advance event pointer) — non-destructive on Series III but it does
move device state, so it is parked with the rest
Also unknown:
- Whether `0x10` bytes inside request params need stuffing
- Whether the bulk waveform stream (`5A` on Series III) exists here, and
whether it is the transport for `.IDFW` bodies we already decode
- Everything about the **call-home session** — the device-initiated direction
has not been observed at all. Specifically: how a unit announces itself,
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
USB.
---
## Session provenance
Unit **UM12947**, firmware **`11.0CB`** (Blastware line), on the bench via
USB, **zero events stored** (memory free == total). Read commands only.
Every response in this document was checksum-validated.
⚠ Firmware is the single biggest caveat on this document. Every finding here
is from one unit on the Blastware build. A `11.0BD` unit has not been
touched.
An empty unit is a real limitation: `0x08`, `0x1E`, `0x0A` and `0x06` all have
event-dependent payloads that could not be exercised. Recording a couple of
events on the bench unit would unlock the entire event-walk half of the
protocol.