# 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_.bin` — structured binary log with timestamps and direction tags (record format: `[type:1][ts_us:8][len:4][payload]`) - `s3_session_.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_.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\\.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 ```