client: use anchor-relative offsets for record_time and sample_rate
Fixed a 1-byte offset jitter that produced garbage values when the device was set to "faster" (4096 Sa/s) mode. Root cause: 4096 = 0x1000, so the sample_rate bytes in the raw S3 frame are `10 10 00` (DLE-escaped). After DLE unstuffing → `10 00` (2 bytes vs 3 for 1024/2048), making frame C 1 byte shorter and shifting all subsequent field offsets by -1. Fix: locate the stable 10-byte anchor `01 2c 00 00 be 80 00 00 00 00` (max-record-limit constant + first two alarm-level floats) and read: sample_rate = uint16_BE at anchor - 2 record_time = float32_BE at anchor + 10 Offline-validated against all five logged hex dumps (1071 and 1070 byte cfg, record times 3/5/8 s, sample rates 1024 and 4096): all five: correct values with anchor approach.
This commit is contained in:
@@ -584,18 +584,21 @@ def _decode_compliance_config_into(data: bytes, info: DeviceInfo) -> None:
|
||||
(frames B+C+D concatenated, echo headers stripped).
|
||||
|
||||
Confirmed field locations (BE11529 with 3-step read, duplicate detection):
|
||||
- cfg[89] = setup_name: first long ASCII string in cfg[40:250]
|
||||
- cfg[64] = record_time: float32 BE (BE11529 shows 3.0 s) ✅ candidate
|
||||
- cfg[52] = sample_rate: uint16 BE (BE11529 shows 1024 Sa/s) ✅ candidate
|
||||
- cfg[89] = setup_name: first long ASCII string in cfg[40:250] ✅
|
||||
- ANCHOR = b'\\x01\\x2c\\x00\\x00\\xbe\\x80\\x00\\x00\\x00\\x00' in cfg[40:100] ✅
|
||||
- anchor - 2 = sample_rate uint16_BE (1024 normal / 2048 fast / 4096 faster)
|
||||
- anchor + 10 = record_time float32_BE
|
||||
- "Project:" needle → project string
|
||||
- "Client:" needle → client string
|
||||
- "User Name:" needle → operator string
|
||||
- "Seis Loc:" needle → sensor_location string
|
||||
- "Extended Notes" needle → notes string
|
||||
|
||||
⚠️ record_time and sample_rate offsets are confirmed candidates from
|
||||
diagnostic scan but have NOT yet been validated by changing device settings
|
||||
and re-reading. Mark as ✅ once validated.
|
||||
Anchor approach is required because a DLE byte in the sample_rate field
|
||||
(4096 = 0x1000 → stored as 10 10 00 in raw S3 frame → unstuffed to 10 00,
|
||||
1 byte shorter than 04 00 or 08 00) causes frame C to be 1 byte shorter
|
||||
for "faster" mode, shifting all subsequent offsets by 1. The 10-byte
|
||||
anchor is stable across all modes.
|
||||
|
||||
Modifies info.compliance_config in-place.
|
||||
"""
|
||||
@@ -623,16 +626,36 @@ def _decode_compliance_config_into(data: bytes, info: DeviceInfo) -> None:
|
||||
except Exception as exc:
|
||||
log.warning("compliance_config: setup_name extraction failed: %s", exc)
|
||||
|
||||
# ── Record Time — float32 BE at cfg[64] ──────────────────────────────────
|
||||
# Diagnostic confirmed: cfg[64] float32_BE = 3.0 on BE11529 (set to 3 s).
|
||||
# Previous guess of 0x28 was wrong (that offset holds the "(L)" label string).
|
||||
# ⚠️ Validate by changing device record time and re-reading — mark ✅ once confirmed.
|
||||
try:
|
||||
if len(data) > 68:
|
||||
config.record_time = struct.unpack_from(">f", data, 64)[0]
|
||||
log.debug("compliance_config: record_time = %.3f s", config.record_time)
|
||||
except Exception as exc:
|
||||
log.warning("compliance_config: record_time extraction failed: %s", exc)
|
||||
# ── Record time + sample rate — anchor-relative ───────────────────────────
|
||||
# The 10-byte anchor sits between sample_rate and record_time in the cfg.
|
||||
# Absolute offsets are NOT reliable because sample_rate = 4096 (0x1000) is
|
||||
# DLE-escaped in the raw S3 frame (10 10 00 → 10 00 after unstuffing),
|
||||
# making frame C 1 byte shorter than for 1024/2048 and shifting everything.
|
||||
# sample_rate: uint16_BE at anchor - 2
|
||||
# record_time: float32_BE at anchor + 10
|
||||
_ANCHOR = b'\x01\x2c\x00\x00\xbe\x80\x00\x00\x00\x00'
|
||||
_anchor = data.find(_ANCHOR, 40, 100)
|
||||
if _anchor >= 2 and _anchor + 14 <= len(data):
|
||||
try:
|
||||
config.sample_rate = struct.unpack_from(">H", data, _anchor - 2)[0]
|
||||
log.debug(
|
||||
"compliance_config: sample_rate = %d Sa/s (anchor@%d)", config.sample_rate, _anchor
|
||||
)
|
||||
except Exception as exc:
|
||||
log.warning("compliance_config: sample_rate extraction failed: %s", exc)
|
||||
try:
|
||||
config.record_time = struct.unpack_from(">f", data, _anchor + 10)[0]
|
||||
log.debug(
|
||||
"compliance_config: record_time = %.3f s (anchor@%d)", config.record_time, _anchor
|
||||
)
|
||||
except Exception as exc:
|
||||
log.warning("compliance_config: record_time extraction failed: %s", exc)
|
||||
else:
|
||||
log.warning(
|
||||
"compliance_config: anchor %s not found in cfg[40:100] (len=%d) "
|
||||
"— sample_rate and record_time will be None",
|
||||
_ANCHOR.hex(), len(data),
|
||||
)
|
||||
|
||||
# ── Project strings ───────────────────────────────────────────────────────
|
||||
try:
|
||||
@@ -664,16 +687,6 @@ def _decode_compliance_config_into(data: bytes, info: DeviceInfo) -> None:
|
||||
except Exception as exc:
|
||||
log.warning("compliance_config: project string extraction failed: %s", exc)
|
||||
|
||||
# ── Sample Rate — uint16 BE at cfg[52] ───────────────────────────────────
|
||||
# Diagnostic confirmed: cfg[52] uint16_BE = 1024 on BE11529 (standard mode).
|
||||
# ⚠️ Validate by changing device sample rate and re-reading — mark ✅ once confirmed.
|
||||
try:
|
||||
if len(data) > 54:
|
||||
config.sample_rate = struct.unpack_from(">H", data, 52)[0]
|
||||
log.debug("compliance_config: sample_rate = %d Sa/s", config.sample_rate)
|
||||
except Exception as exc:
|
||||
log.warning("compliance_config: sample_rate extraction failed: %s", exc)
|
||||
|
||||
info.compliance_config = config
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user