diff --git a/docs/micromate_protocol_reference.md b/docs/micromate_protocol_reference.md index 5b69bcc..9f86180 100644 --- a/docs/micromate_protocol_reference.md +++ b/docs/micromate_protocol_reference.md @@ -652,6 +652,112 @@ This is the **read half of setup management**, and it means a setup can be round-tripped: read the active config, modify, write it back. The write half is not yet attempted. +## Static analysis of the firmware (2026-09-23, solo session) + +### Architecture + +**ColdFire / 68K, big-endian, Freescale MQX RTOS** — not ARM as the vector +table first suggested. The giveaway is the function epilogue/prologue +`4E 5E 4E 75 4E 56` = `UNLK A6` / `RTS` / `LINK A6`, littered through both +images, plus an `MQX_OK` assertion string. + +### CB vs BD: the same source, ~10 lines apart + +A byte diff is useless — **68% of bytes differ** because the two are separately +linked builds with everything relocated. A *string-set* diff is +position-independent and tells the real story: **17,128 strings shared**, and +almost every "unique" string is the same message with a different source line +number: + +``` +CB: MONITOR[3268]: STATUS_BATTERY_LOW +BD: MONITOR[3258]: STATUS_BATTERY_LOW ← consistently 10 lines apart +``` + +The offset is exactly 10 across `STATUS_BATTERY_LOW`, `STATUS_BATTERY_CRITICAL`, +`Battery Critical Exit Monitor`, `histogram interval size of 0` and +`Offsets by channel` — so one ~10-line block differs in the monitor module and +essentially nothing else. The only functional string unique to either build is +`CITIZEN` (a receipt-printer brand) in BD. + +**This corroborates the bench A/B from the other direction:** the CB/BD split +is a tiny code delta, not two protocol stacks. Whatever drives Instantel to +ship two downloads, it is not a different wire protocol. + +⚠ The `SUB` dispatch is a 68K switch jump table (`CMPI.L` bounds check → +`MOVE.W (table,PC,Dn)` → `JMP (d8,PC,Xn)`). Byte-pattern hunting will not +isolate the write opcodes — that needs a real disassembler. + +### Call-home config field names, from the firmware's own debug dump + +``` +CallHome.Enable = %s +CallHome.DialString = "%s" +CallHome.Retries = %d +CallHome.SessionTimeout = %d +CallHome.WaitForConnection = %d +CallHome.WarmupTime = %d +CallHome.PowerSave = %s +``` + +Seven fields, which is what the 126-byte `SUB 0x2C` block has to encode. Note +`SessionTimeout` and `PowerSave` have no Series III equivalent, and Series III's +scheduled-time fields (`time1/time2 hour/min`) are absent here — consistent +with Series IV moving scheduling into the THOR-downloaded scheduler instead. + +Also present: `AT+CSQ` (signal quality), so the firmware talks AT to the modem +directly. + +## All five bench events, downloaded and decoded + +Read-only, over USB, no Instantel software: + +| key | declared size | got | decoded | +|---|---|---|---| +| `055d4a81` | 4,076 | 4,076 | histogram, 1 interval, 16:33:16 | +| `055d4a82` | 11,032 | 11,032 | waveform, 3072 × 4 ch, 16:33:19 | +| `055d4a83` | 11,502 | 11,502 | waveform, 3072 × 4 ch, 16:33:27 | +| `055d4a84` | 13,424 | 13,424 | waveform, 3072 × 4 ch, 16:33:34 | +| `055d4a85` | 8,746 | 8,746 | waveform, 2048 × 4 ch, 16:33:36 | + +Every event arrived at exactly its declared size, every channel came out equal +length, and the timestamps are sequential across the recording session. + +### ⚠ Gap: no content-based record-type discriminator + +`read_idf_file()` decides waveform vs histogram from the **filename suffix** +(`.IDFH` / `.IDFW`) — and there is no filename when downloading over the wire. +The first 64 bytes of a histogram and a waveform are **byte-identical**, so the +header does not obviously carry the type either. + +The protocol does supply one: **`SUB 0x0A` returns length `0x1E` for a +histogram and `0x00` for a waveform** (see the event-chain section). Any +direct-download implementation must carry the type from the chain walk rather +than inferring it from the payload, or find the type field inside the IDF +header. + +### ⚠ Unresolved: the `0x0C` peak float + +The float32 extracted from `0x0C` runs 2–5% above `max(Tran, Vert, Long)` from +the decoded samples: + +| key | `0x0C` float | max channel | +|---|---|---| +| `…81` | 3.5152 | 3.4419 | +| `…82` | 1.3720 | 1.3706 | +| `…83` | 2.3542 | 2.2227 | +| `…84` | 3.5152 | 3.4419 | +| `…85` | 0.4227 | 0.4198 | + +It is not peak vector sum either (computed PVS runs *higher* than both). The +field may not be the peak at all — its offset was inferred from a byte marker, +not established. **Do not rely on it** until it is pinned properly. + +Worth noting the histogram (`…81`) and the loudest waveform (`…84`) report +*identical* peaks to four decimals, in both measures. That is self-consistent: +the histogram's single 1-minute interval spans the whole thumping session, so +its maximum should equal the loudest event in it. + ## ⚠ Untested and unsafe-until-agreed Nothing below has been sent to a unit, and nothing should be without an