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>
This commit is contained in:
@@ -395,6 +395,44 @@ class MiniMateProtocol:
|
||||
)
|
||||
return key4
|
||||
|
||||
def read_compliance_config(self) -> bytes:
|
||||
"""
|
||||
Send the SUB 1A (CHANNEL_SCALING / COMPLIANCE_CONFIG) two-step read.
|
||||
|
||||
Returns the full 2090-byte compliance config block (E5 response)
|
||||
containing:
|
||||
- Trigger and alarm levels per channel (IEEE 754 BE floats)
|
||||
- Record time (float at offset +0x28)
|
||||
- Project strings (Project, Client, User Name, Seis Loc, Extended Notes)
|
||||
- Channel labels and unit strings
|
||||
- Per-channel max range values
|
||||
|
||||
Returns:
|
||||
2090-byte compliance config data (data[11:11+0x082A]).
|
||||
|
||||
Raises:
|
||||
ProtocolError: on timeout, bad checksum, or wrong response SUB.
|
||||
|
||||
Confirmed from protocol reference §7.6:
|
||||
- SUB 1A request uses all-zero params
|
||||
- E5 response is 2090 bytes (0x082A fixed length)
|
||||
- Response data section: data[11:11+0x082A]
|
||||
"""
|
||||
rsp_sub = _expected_rsp_sub(SUB_COMPLIANCE)
|
||||
length = 0x082A # 2090 bytes, fixed length for compliance config
|
||||
|
||||
log.debug("read_compliance_config: 1A probe")
|
||||
self._send(build_bw_frame(SUB_COMPLIANCE, 0))
|
||||
self._recv_one(expected_sub=rsp_sub)
|
||||
|
||||
log.debug("read_compliance_config: 1A data request offset=0x%04X", length)
|
||||
self._send(build_bw_frame(SUB_COMPLIANCE, length))
|
||||
data_rsp = self._recv_one(expected_sub=rsp_sub)
|
||||
|
||||
config = data_rsp.data[11:11 + length]
|
||||
log.debug("read_compliance_config: received %d config bytes", len(config))
|
||||
return config
|
||||
|
||||
# ── Internal helpers ──────────────────────────────────────────────────────
|
||||
|
||||
def _send(self, frame: bytes) -> None:
|
||||
|
||||
Reference in New Issue
Block a user