Five events on the bench unit (4 waveform + 1 histogram). The Series III browse walk -- 1E, then 0A/0C per key, then 1F to advance -- works unmodified, and the null sentinel terminated correctly after exactly 5. Findings: - Event keys are a sequential counter (055d4a81..85), NOT flash-buffer addresses. Series III key arithmetic does not carry over; its 5A chunk walk assumes addresses and must not be ported blindly. - The 4 bytes after the key in 1E/1F are the event's SIZE in bytes, where Series III puts an offset to the next key. 4,076 for the histogram and 8.7-13.4 KB for the waveforms, matching real .IDFH/.IDFW file sizes. - SUB 0x0C returns a 210-byte (0xD2) waveform record -- the same length as Series III -- carrying the event key, date/time, the title note "Location", the PROJECT STRING, the serial, channel labels Tran/Vert/Long/Mic and float32 peaks. That last point closes the biggest open question for the call-home receiver: the job identity strings that today arrive only via Thor's .txt sidecar, and which no amount of sample decoding can reconstruct, are readable over the wire. Direct-to-SFM events need not arrive with blank metadata. - SUB 0x0A returns len 0x1E for the histogram and 0x00 for every waveform. The histogram payload holds two timestamps plus a "Vert: 0.300 in/s" trigger string -- structurally the Series III monitor-log partial record. So 0A describes interval records and 0C describes triggered events; Series III's 0x46-vs-0x2C length discriminator does not apply. - DLE stuffing in responses is now confirmed (previously marked untested): the 0C timestamp contains 10 10, which destuffs to one 0x10 and yields a clock reading of 16:33 on 23 Sep 2026 -- matching when the events were recorded. Read-only throughout. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Ru8Lg9HkkYvX9VWWo65SmL
16 KiB
Micromate Protocol Reference — Thor / Micromate Series IV, live wire protocol
Sibling to instantel_protocol_reference.md
(Series III, "the Rosetta Stone") and
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:
- What file format does a
11.0CBunit 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. - Does Thor still work with a
11.0CBunit? If not, flashing a production unit breaks data collection until the replacement path exists. - Are any Micromate-specific capabilities lost on the Blastware line?
- 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
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.
The event chain — walked end to end (2026-09-23, 5 events)
With 5 events on the bench unit (4 waveform + 1 histogram), the Series III browse walk works unmodified:
1E (all-zero params) -> first key + size
0A (key) -> partial record, histogram only
0C (key) -> 210-byte waveform record
1F (all-zero params/browse) -> next key + size
... repeat ...
1F -> all-zero key = NULL SENTINEL, chain ends
The sentinel terminated correctly after exactly 5 events.
Event keys are sequential, not addresses
055d4a81 055d4a82 055d4a83 055d4a84 055d4a85
This is a real divergence. Series III keys are flash-buffer addresses
(01110000, 011121F2, …) that advance by the event's byte length, which is
why its 5A chunk walk is address-arithmetic. Micromate keys are a plain
incrementing counter. Any port of the Series III download walk must not
assume key arithmetic means anything.
The 4 bytes after the key are the event's size
1E/1F return [key 4B][size 4B]. Series III uses that slot as an offset
to the next key; here it is a byte count:
| key | size | kind |
|---|---|---|
055d4a81 |
4,076 | histogram |
055d4a82 |
11,032 | waveform |
055d4a83 |
11,502 | waveform |
055d4a84 |
13,424 | waveform |
055d4a85 |
8,746 | waveform |
Consistent with real file sizes (corpus .IDFH ≈ 3.7–25 KB, .IDFW ≈
8.6–15.8 KB), and the histogram is unmistakably the small one. ⚠ Inferred,
not proven: the sizes sum to 48,780 while monitor status reports 57,344 bytes
used, so ~8.5 KB of overhead is unaccounted for.
SUB 0x0C — waveform record, and it carries the job metadata
Length 0xD2 = 210 bytes — identical to Series III. Contents confirmed
across all 5 events:
- the event key, echoed
- date + time (
17 09 07 ea→ 23 Sep 2026, then10 21→ 16:33 — matching the actual bench recording time) - title note
"Location" - the project string —
"Univ of Pitt-1st Yr Housing-Loc1 Ruskin" - serial
"UM12947" - channel labels
Tran/Vert/Long/Mic— the same labels Series III uses, and the same label-relative float32 layout - per-event float32 peaks: 3.5152, 1.3720, 2.3542, 3.5152, 0.4227 in/s across the five events (varied deliberately during recording)
This closes the biggest open question for the call-home-receiver goal.
The job identity strings (project / client / operator / setup) that
today arrive only via Thor's .txt sidecar — and which no amount of sample
decoding can reconstruct — are available over the wire from 0x0C. A
direct-to-SFM event need not arrive with blank metadata.
SUB 0x0A — partial record, histogram only
0x0A returned len = 0x1E (30 B) for the histogram and len = 0x00 for all
four waveforms. The histogram payload carries two timestamps and the
ASCII string "\r Vert: 0.300 in/s" — structurally the Series III
monitor-log partial record (0x2C type), which likewise holds a start/stop
pair and a "Geo: <float> in/s" trigger string.
So on the Micromate the division of labour is: 0x0A describes interval-style
records, 0x0C describes triggered events. Series III uses 0x0A's
response length (0x46 vs 0x2C) to tell real events from boundaries;
that discriminator does not apply here.
DLE stuffing in responses — confirmed present
Earlier marked untested. The 0x0C timestamp field contains 10 10, which
destuffs to a single 0x10 and yields a sensible clock reading. Responses
are DLE-stuffed, so a parser must destuff before applying field offsets.
Divergences from Series III (running list)
- No
DLEprefix on responses — bareSTX. - Response flags byte is
0xC5, not0x10. - Call-home config is 126 bytes, not 124.
- Data lengths are discoverable from the probe response at
payload[9]. 4b. Event keys are a sequential counter, not flash addresses. 4c.1E/1Freturn the event size, where Series III returns an offset. 4d.0x0Avs0x0Csplit by record type, not by the0x46/0x2Clength discriminator Series III uses. - 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
0x10bytes inside request params need stuffing - Whether the bulk waveform stream (
5Aon Series III) exists here, and whether it is the transport for.IDFWbodies 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.