Commit Graph

17 Commits

Author SHA1 Message Date
Brian Harrison
58a5f15ed5 client: fix setup_name; add diagnostic scan for record_time/sample_rate
- setup_name was broken: _find_string_after(b"Standard Recording Setup")
  returned what comes AFTER the string (i.e. "Project:"), not the name
  itself.  Fixed by searching for the first long (>=8 char) ASCII string
  in cfg[40:250] with _find_first_string().

- record_time offset 0x28 was wrong (that location holds "(L)", a unit
  label string).  Disabled for now to avoid returning garbage; correct
  offset will be determined from _cfg_diagnostic() output.

- Added _cfg_diagnostic(): logs all strings and all plausible float32/uint16
  values across the full cfg so record_time and sample_rate offsets can be
  pinpointed from a single device run.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:18:41 -04:00
Brian Harrison
eee1e36a1b protocol: send 3-step data requests for full compliance config (SUB 1A)
Reverse-engineered the full Blastware 4-frame sequence for SUB 1A:
  A (probe):      offset=0x0000, params[7]=0x64
  B (data req 1): offset=0x0400, params[2]=0x00, params[7]=0x64  → bytes 0..1023
  C (data req 2): offset=0x0400, params[2]=0x04, params[7]=0x64  → bytes 1024..2047
  D (data req 3): offset=0x002A, params[2]=0x08, params[7]=0x64  → bytes 2048..2089

We were only sending A+D and getting 44 bytes (the last chunk).
Now sends B, C, D in sequence; each E5 response has 11-byte echo header
stripped, and chunks are concatenated.  Devices that return all data in
one frame (BE18189 style) are handled — timeouts on B/C are skipped
gracefully and data from D still accumulates.

Total expected: 0x0400 + 0x0400 + 0x002A = 0x082A = 2090 bytes.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 15:08:50 -04:00
Brian Harrison
a5069c302d protocol: accumulate multiple E5 frames for chunked compliance config
BE11529 sends the compliance config (SUB 1A / E5 response) as a stream
of small frames (~44 bytes each) rather than one large frame like BE18189.

Changes:
- read_compliance_config(): loop calling _recv_one() until 0x082A bytes
  accumulated or 2s inter-frame gap; first frame strips 11-byte echo header,
  subsequent frames logged in full for structure analysis
- _recv_one(): add reset_parser=False option to preserve parser state and
  _pending_frames buffer between consecutive reads from one device response;
  also stash any extra frames parsed in a single TCP chunk so they are not lost

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 14:54:16 -04:00
Brian Harrison
6e0b83efa5 fix: update compliance config reading to handle variable payload sizes and improve logging 2026-04-01 14:31:03 -04:00
Brian Harrison
d4b1b834a7 fix: refine SUB 1A compliance config read parameters and logging 2026-04-01 14:20:12 -04:00
Brian Harrison
824322597a fix: validate offset size in build_bw_frame and adjust payload construction 2026-04-01 13:28:00 -04:00
Brian Harrison
7e501620fc fix: skip trigger/alarm extraction pending offset confirmation
The heuristic offsets for trigger/alarm levels were causing struct unpack
errors. These fields require detailed field mapping from actual E5 captures
to determine exact byte positions relative to channel labels.

For now, skip extraction and leave trigger_level_geo/alarm_level_geo as None.
This prevents the '500 Device error: bytes must be in range(0, 256)' error.

Once we capture an E5 response and map the exact float positions, we can
re-enable this section with correct offsets.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-01 13:07:04 -04:00
Brian Harrison
32b9d3050c feat: implement SUB 1A (compliance config) read
Adds full support for reading device compliance configuration (2090-byte E5
response) containing record time, trigger/alarm levels, and project strings.

protocol.py:
- Implement read_compliance_config() two-step read (SUB 1A → E5)
- Fixed length 0x082A (2090 bytes)

models.py:
- Add ComplianceConfig dataclass with fields: record_time, sample_rate,
  trigger_level_geo, alarm_level_geo, max_range_geo, project strings
- Add compliance_config field to DeviceInfo

client.py:
- Implement _decode_compliance_config_into() to extract:
  * Record time float at offset +0x28 
  * Trigger/alarm levels per-channel (heuristic parsing) 🔶
  * Project/setup strings from E5 payload
  * Placeholder for sample_rate (location TBD )
- Update connect() to read SUB 1A after SUB 01, cache in device_info
- Add ComplianceConfig to imports

sfm/server.py:
- Add _serialise_compliance_config() JSON encoder
- Include compliance_config in /device/info response
- Updated _serialise_device_info() to output compliance config

Both record_time (at fixed offset 0x28) and project strings are  CONFIRMED
from protocol reference §7.6. Trigger/alarm extraction uses heuristics
pending more detailed field mapping from captured data.

Sample rate remains undiscovered in the E5 payload — likely in the
mystery flags at offset +0x12 or requires a "fast mode" capture.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 12:08:43 -04:00
Brian Harrison
4944974f6e feat: decode waveform record timestamp, record type, and Peak Vector Sum
Confirmed 2026-04-01 against Blastware event report for BE11529 thump
event ("00:28:12 April 1, 2026", PVS 3.906 in/s).

models.py:
- Timestamp.from_waveform_record(): decode 9-byte format from 0C record
  bytes[0-8]: [day][sub_code][month][year:2BE][?][hour][min][sec]
- Timestamp: add hour/minute/second optional fields; __str__ includes
  time when available
- PeakValues: add peak_vector_sum field (confirmed fixed offset 87)

client.py:
- _decode_waveform_record_into: add timestamp decode from bytes[0:9]
- _extract_record_type: decode byte[1] (sub_code), not ASCII string
  search; 0x10 → "Waveform", histogram TBD
- _extract_peak_floats: add PVS from offset 87 (IEEE 754 BE float32)
  = √(T²+V²+L²) at max instantaneous vector moment

sfm/server.py:
- _serialise_timestamp: add hour/minute/second/day fields to JSON
- _serialise_peak_values: add peak_vector_sum to JSON

docs: update §7.7.5 and §8 with confirmed 9-byte timestamp layout,
PVS field, and byte[1] record type encoding; update command table;
close resolved open questions.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-01 00:53:34 -04:00
Brian Harrison
f74992f4e5 fix: serial decode offset, PPV label scan, debug mode for waveform records
- _decode_serial_number: read from data[11:] not data[:8] — was returning
  the LENGTH_ECHO byte (0x0A = '\n') instead of the serial string
- _extract_peak_floats: search for channel label strings ("Tran" etc) and
  read float at label+6; old step-4 aligned scan was reading trigger levels
  instead of PPV values
- get_events: add debug=False param; stashes raw 210-byte record on
  Event._raw_record when True for field-layout inspection
- server /device/events: add ?debug=true query param; includes
  raw_record_hex + raw_record_len in response when set
- models: add Event._raw_record optional bytes field
2026-03-31 23:46:07 -04:00
Brian Harrison
9f52745bb4 feat: add full event download pipeline 2026-03-31 20:48:03 -04:00
Brian Harrison
8074bf0fee bump timeout to 30s to deal with modem slowness. 2026-03-31 12:12:36 -04:00
Brian Harrison
51d1aa917a Add TCP/modem transport (Sierra Wireless RV55/RX55 field units)
- minimateplus/transport.py: add TcpTransport — stdlib socket-based transport
  with same interface as SerialTransport. Overrides read_until_idle() with
  idle_gap=1.5s to absorb the modem's 1-second serial data forwarding buffer.
- minimateplus/client.py: make `port` param optional (default "") so
  MiniMateClient works cleanly when a pre-built transport is injected.
- minimateplus/__init__.py: export SerialTransport and TcpTransport.
- sfm/server.py: add `host` / `tcp_port` query params to all device endpoints.
  New _build_client() helper selects TCP or serial transport automatically.
  OSError (connection refused, timeout) now returns HTTP 502.
- docs/instantel_protocol_reference.md: add changelog entry and full §14
  (TCP/Modem Transport) documenting confirmed transparent passthrough, no ENQ
  on connect, modem forwarding delay, call-up vs ACH modes, and hardware note
  deprecating Raven X in favour of RV55/RX55.

Usage: GET /device/info?host=<modem_ip>&tcp_port=12345
2026-03-31 00:44:50 -04:00
Brian Harrison
3f142ce1c0 fix: stop raising on S3 checksum mismatches 2026-03-31 00:15:07 -04:00
serversdwn
88adcbcb81 fix: s3parser now looks for bare ETX, not DLE+ETX. 2026-03-31 00:10:13 -04:00
serversdwn
8e985154a7 bumps timeout up 2026-03-30 23:46:34 -04:00
serversdwn
f8f590b19b sfm first build 2026-03-30 23:23:29 -04:00