Brian Harrison de02f9cccf Handle cold-boot timeout for TCP connections
- bridges/tcp_serial_bridge.py: increase default boot_delay 2s → 8s to
  cover MiniMate Plus cold-start time (unit wakes from RS-232 line
  assertion but takes 5-10s to be ready for POLL_PROBE).
- sfm/server.py: add _run_with_retry() — on TCP connections only, retries
  once on ProtocolError. Serial timeouts are not retried (usually a real
  fault). Confirmed behaviour: unit wakes purely from RS-232 line voltage,
  no software wake-up frame needed.
2026-03-31 12:02:52 -04:00
2026-03-31 00:24:12 -04:00
2026-03-10 12:30:12 -04:00

seismo-relay

Tools for capturing and reverse-engineering the RS-232 serial protocol between Blastware software and Instantel MiniMate Plus seismographs.

Built for Windows, stdlib-only (plus pyserial for the bridge).


What's in here

seismo-relay/
├── bridges/
│   ├── s3-bridge/
│   │   └── s3_bridge.py       ← The serial bridge (core capture tool)
│   ├── gui_bridge.py          ← Tkinter GUI wrapper for s3_bridge
│   └── raw_capture.py         ← Simpler raw-only capture tool
└── parsers/
    ├── s3_parser.py           ← Low-level DLE frame extractor
    ├── s3_analyzer.py         ← Protocol analyzer (sessions, diffs, exports)
    ├── gui_analyzer.py        ← Tkinter GUI for the analyzer
    └── frame_db.py            ← SQLite frame database

How it all fits together

The workflow has two phases: capture, then analyze.

  Blastware PC
       │
  Virtual COM (e.g. COM4)
       │
  s3_bridge.py  ←─── sits in the middle, forwards all bytes both ways
       │              writes raw_bw.bin and raw_s3.bin
  Physical COM (e.g. COM5)
       │
  MiniMate Plus seismograph

After capturing, you point the analyzer at the two .bin files to inspect what happened.


Part 1 — The Bridge

s3_bridge.py — Serial bridge

Transparently forwards bytes between Blastware and the seismograph while logging everything to disk. Blastware operates normally and has no idea the bridge is there.

Run it:

python bridges/s3-bridge/s3_bridge.py --bw COM4 --s3 COM5 --logdir captures/

Key flags:

Flag Default Description
--bw required COM port connected to Blastware
--s3 required COM port connected to the seismograph
--baud 38400 Baud rate (match your device)
--logdir . Where to write log/bin files
--raw-bw off Also write a flat raw file for BW→S3 traffic
--raw-s3 off Also write a flat raw file for S3→BW traffic

Output files (in --logdir):

  • s3_session_<timestamp>.bin — structured binary log with timestamps and direction tags (record format: [type:1][ts_us:8][len:4][payload])
  • s3_session_<timestamp>.log — human-readable hex dump (text)
  • raw_bw.bin — flat BW→S3 byte stream (if --raw-bw used)
  • raw_s3.bin — flat S3→BW byte stream (if --raw-s3 used)

The analyzer needs raw_bw.bin + raw_s3.bin. Always use --raw-bw and --raw-s3 when capturing.

Interactive commands (type while bridge is running):

  • m + Enter → prompts for a label and inserts a MARK record into the log
  • q + Enter → quit

gui_bridge.py — Bridge GUI

A simple point-and-click wrapper around s3_bridge.py. Easier than the command line if you don't want to type flags every time.

python bridges/gui_bridge.py

Set your COM ports, log directory, and tick the raw tap checkboxes before hitting Start. The Add Mark button lets you annotate the capture at any point (e.g. "changed record time to 13s").


Part 2 — The Analyzer

After capturing, you have raw_bw.bin (bytes Blastware sent) and raw_s3.bin (bytes the seismograph replied with). The analyzer parses these into protocol frames, groups them into sessions, and helps you figure out what each byte means.

What's a "session"?

Each time you open the settings dialog in Blastware and click Apply/OK, that's one session — a complete read/modify/write cycle. The bridge detects session boundaries by watching for the final write-confirm packet (SUB 0x74).

Each session contains a sequence of request/response frame pairs:

  • Blastware sends a request (BW→S3): "give me your config block"
  • The seismograph sends a response (S3→BW): here it is
  • At the end, Blastware sends the modified settings back in a series of write packets

The analyzer lines these up and diffs consecutive sessions to show you exactly which bytes changed.


gui_analyzer.py — Analyzer GUI

python parsers/gui_analyzer.py

This is the main tool. It has five tabs:

Toolbar

  • S3 raw / BW raw — browse to your raw_s3.bin and raw_bw.bin files
  • Analyze — parse and load the captures
  • Live: OFF/ON — watch the files grow in real time while the bridge is running
  • Export for Claude — generate a self-contained .md report for AI-assisted analysis

Inventory tab

Shows all frames in the selected session — direction, SUB command, page, length, and checksum status. Click any frame in the left tree to drill in.

Hex Dump tab

Full hex dump of the selected frame's payload. If the frame had changed bytes vs the previous session, those are listed below the dump with before/after values and field names where known.

Diff tab

Side-by-side byte-level diff between the current session and the previous one. Only SUBs (command types) that actually changed are shown.

Full Report tab

Raw text version of the session report — useful for copying into notes.

Query DB tab

Search across all your captured sessions using the built-in database.


s3_analyzer.py — Analyzer (command line)

If you prefer the terminal:

python parsers/s3_analyzer.py --s3 raw_s3.bin --bw raw_bw.bin

Flags:

Flag Description
--s3 Path to raw_s3.bin
--bw Path to raw_bw.bin
--live Tail files in real time (poll mode)
--export Also write a claude_export_<ts>.md file
--outdir Where to write .report files (default: same folder as input)
--poll Live mode poll interval in seconds (default: 0.05)

Writes one .report file per session and prints a summary to the console.


The Frame Database

Every time you click Analyze, the frames are automatically saved to a SQLite database at:

C:\Users\<you>\.seismo_lab\frames.db

This accumulates captures over time so you can query across sessions and dates.

Query DB tab

Use the filter bar to search:

  • Capture — narrow to a specific capture (timestamp shown)
  • Dir — BW (requests) or S3 (responses) only
  • SUB — filter by command type (e.g. 0xF7 = EVENT_INDEX_RESPONSE)
  • Offset — filter to frames that have a specific byte offset
  • Value — combined with Offset: "show frames where byte 85 = 0x0A"

Click any result row, then use the Byte interpretation panel at the bottom to see what that offset's bytes look like as uint8, int8, uint16 BE/LE, uint32 BE/LE, and float32 BE/LE simultaneously.

This is the main tool for mapping unknown fields — if you change one setting in Blastware, capture before and after, then query for frames where that offset moved, you can pin down exactly which byte controls what.


Export for Claude

The Export for Claude button (orange, in the toolbar) generates a single .md file containing:

  1. Protocol background and known field map
  2. Capture summary (session count, frame counts, what changed)
  3. Per-diff tables — before/after bytes for every changed offset, with field names where known
  4. Full hex dumps of all frames in the baseline session

Paste this file into a Claude conversation to get help mapping unknown fields, interpreting data structures, or understanding sequences.


Protocol quick-reference

Term Value Meaning
DLE 0x10 Data Link Escape
STX 0x02 Start of frame
ETX 0x03 End of frame
ACK 0x41 Frame start marker (BW side)
DLE stuffing 10 10 on wire Literal 0x10 in payload

S3-side frame (seismograph → Blastware): DLE STX [payload] DLE ETX BW-side frame (Blastware → seismograph): ACK STX [payload] ETX

De-stuffed payload header (first 5 bytes after de-stuffing):

[0] CMD        0x10 = BW request, 0x00 = S3 response
[1] ?          0x00 (BW) or 0x10 (S3)
[2] SUB        Command/response identifier  ← the key field
[3] OFFSET_HI  Page address high byte
[4] OFFSET_LO  Page address low byte
[5+] DATA      Payload content

Response SUB rule: response_SUB = 0xFF - request_SUB Example: request SUB 0x08 → response SUB 0xF7


Requirements

pip install pyserial

Python 3.10+. Everything else is stdlib (Tkinter, sqlite3, struct, hashlib).

Tkinter is included with the standard Python installer on Windows. If it's missing, reinstall Python and make sure "tcl/tk and IDLE" is checked.


Virtual COM ports

The bridge needs two COM ports on the same PC — one that Blastware connects to, and one wired to the actual seismograph. On Windows, use a virtual COM port pair (e.g. com0com or VSPD) to give Blastware a port to talk to while the bridge sits in the middle.

Blastware → COM4 (virtual) ↔ s3_bridge ↔ COM5 (physical) → MiniMate
Description
Program to talk to, listen to, and control various devices such as seismographs.
Readme 672 KiB
Languages
Python 100%