@@ -2,7 +2,7 @@
Ground-up Python replacement for **Blastware ** , Instantel's Windows-only software for
managing MiniMate Plus seismographs. Connects over direct RS-232 or cellular modem
(Sierra Wireless RV50 / RV55). Current version: **v0.12.2 ** .
(Sierra Wireless RV50 / RV55). Current version: **v0.12.3 ** .
When new information about the protocol is discovered, please update the instantel_protocol_reference.md with the findings in addition to this document
@@ -27,9 +27,9 @@ CHANGELOG.md ← version history
---
## Current implementation state (v0.10.0 )
## Current implementation state (v0.12.3 )
Full read pipeline + write pipeline + erase pipeline + monitor log working end-to-end over TCP/cellular:
Full read pipeline + write pipeline + erase pipeline + monitor log + call home config working end-to-end over TCP/cellular:
| Step | SUB | Status |
|---|---|---|
@@ -45,7 +45,8 @@ Full read pipeline + write pipeline + erase pipeline + monitor log working end-t
| Event advance / next key | 1F | ✅ |
| **Write commands (push config to device) ** | **68– 83 ** | ✅ new v0.8.0 |
| **Erase all events ** | **0xA3 → 0x1C → 0x06 → 0xA2 ** | ✅ new v0.9.0 |
| **Monitor log entries (partial 0x2C records) ** | **0A browse ** | ✅ ** new v0.10.0** |
| **Monitor log entries (partial 0x2C records) ** | **0A browse ** | ✅ new v0.10.0 |
| **Auto Call Home config (read + write) ** | **2C → 7E → 7F ** | ✅ **new v0.12.3 ** |
`get_events()` sequence per event: `1E → 0A → 0C → 5A → 1F`
@@ -971,12 +972,104 @@ call-home.
---
## Auto Call Home config (SUBs 0x2C / 0x7E / 0x7F) — confirmed 2026-04-20
Full read/write pipeline confirmed from `bridges/captures/4-20-26/call home settings/`
(10 BW TX write frames diffed against the S3 read response).
Accessible in Blastware: **Remote Access → Setup Unit ** .
### Protocol
**SUB 0x2C — Call Home Config READ (response 0xD3) **
Standard two-step read: probe offset `0x0000` , data offset `0x007C` (124).
Returns 125 raw bytes (one more than DATA_LENGTH) because the device encodes
num_retries value `3` as `\x10\x03` on the wire — S3FrameParser preserves both
bytes literally, shifting all subsequent field positions by +1.
**SUB 0x7E — Call Home Config WRITE (response 0x81) **
Write format (only BW_CMD `0x10` doubled on wire; DLE-aware checksum).
Payload = 125-byte read payload + `\x00\x00` = 127 bytes.
Offset = `data[1] + 2 = 0x7C + 2 = 0x7E` .
**SUB 0x7F — Call Home WRITE CONFIRM (response 0x80) **
Confirm frame, no data payload. Required after SUB 0x7E.
### Field map (raw 125-byte array from `data_rsp.data[11:]`)
| Raw Offset | Field | Notes |
|---|---|---|
| `[5]` | `auto_call_home_enabled` | `0x00` =off, `0x01` =on |
| `[6:46]` | `dial_string` | 40-byte null-padded ASCII |
| `[87]` | `after_event_recorded` | bool |
| `[91]` | `at_specified_times` | bool |
| `[93]` | `time1_enabled` | bool |
| `[101]` | `time1_hour` | 0– 23 |
| `[102]` | `time1_min` | 0– 59 |
| `[95]` | `time2_enabled` | bool |
| `[105]` | `time2_hour` | 0– 23 |
| `[106]` | `time2_min` | 0– 59 |
| `[117]` | DLE prefix `0x10` | Part of `\x10\x03` (DLE-escaped ETX encoding value 3) |
| `[118]` | `num_retries` | Value = 3; detect via `raw[117] == 0x10` |
| `[120]` | `time_between_retries_sec` | Shifted +1 from logical 119 |
| `[122]` | `wait_for_connection_sec` | Shifted +1 from logical 121 |
| `[124]` | `warm_up_time_sec` | Shifted +1 from logical 123 |
**DLE-escaped 0x03 at raw[117:119]: ** The byte value `0x03` is indistinguishable from the
frame ETX terminator, so the device encodes it as `\x10\x03` (DLE + ETX inner-terminator).
S3FrameParser in `STATE_AFTER_DLE` on ETX appends both bytes as literal payload. The write
frame sends them verbatim — device accepts `\x10\x03` and interprets it as value 3.
**Unconfirmed fields: ** time slots 3 and 4 (offsets unknown), `modem_power_relay_enabled` .
### `CallHomeConfig` model — models.py
``` python
@dataclass
class CallHomeConfig :
raw : Optional [ bytes ] = None # 125-byte raw read payload
auto_call_home_enabled : Optional [ bool ] = None # raw[5]
dial_string : Optional [ str ] = None # raw[6:46]
after_event_recorded : Optional [ bool ] = None # raw[87]
at_specified_times : Optional [ bool ] = None # raw[91]
time1_enabled : Optional [ bool ] = None # raw[93]
time1_hour : Optional [ int ] = None # raw[101]
time1_min : Optional [ int ] = None # raw[102]
time2_enabled : Optional [ bool ] = None # raw[95]
time2_hour : Optional [ int ] = None # raw[105]
time2_min : Optional [ int ] = None # raw[106]
num_retries : Optional [ int ] = None # raw[118] (DLE-prefixed)
time_between_retries_sec : Optional [ int ] = None # raw[120] (shifted +1)
wait_for_connection_sec : Optional [ int ] = None # raw[122] (shifted +1)
warm_up_time_sec : Optional [ int ] = None # raw[124] (shifted +1)
```
### SFM REST API — sfm/server.py
```
GET /device/call_home?host=1.2.3.4&tcp_port=9034 ← read call home config
POST /device/call_home?host=1.2.3.4&tcp_port=9034 ← write call home config
```
POST body fields (all optional): `auto_call_home_enabled` , `after_event_recorded` ,
`at_specified_times` , `time1_enabled` , `time1_hour` , `time1_min` , `time2_enabled` ,
`time2_hour` , `time2_min` .
**Note: ** `dial_string` is read-only in the current implementation (omitted from POST
body) because writing a dial string may require DLE escaping for embedded control characters.
---
## What's next
- **Database** — SQLite store for events + monitor log entries; dedup by key; queryable
- **Histograms** — decode histogram-mode A5 data (noise floor tracking)
- Compliance config encoder — build raw write payloads from a `ComplianceConfig` object
- Locate "Sensor Check" byte in compliance config (need capture with Disabled vs Before-monitoring)
- Call Home — map time slots 3/4 offsets; add dial_string write support; confirm `modem_power_relay_enabled`
- Modem manager — push RV50/RV55 configs via Sierra Wireless API
- RV55 DCD/DTR issue — newer RV55 firmware doesn't assert DCD by default; units don't
resume monitoring after call-home disconnect (`--restart-monitoring` flag deferred)