fix: max_geo_range correctly identified as ADC Scale factor number.
This commit is contained in:
+35
-20
@@ -876,8 +876,10 @@ class MiniMateClient:
|
||||
Trigger/alarm thresholds (geo channels, in/s):
|
||||
trigger_level_geo : float — trigger threshold (e.g. 0.5)
|
||||
alarm_level_geo : float — alarm threshold (e.g. 1.0)
|
||||
max_range_geo : float — full-scale calibration constant (e.g. 6.206)
|
||||
rarely changed — only set if you know what you're doing
|
||||
max_range_geo : float — ADC-to-velocity scale factor (= 1/sensitivity, in/s per V)
|
||||
e.g. 6.206053 for the standard Instantel geophone.
|
||||
This is a hardware/firmware constant — do NOT write it.
|
||||
Accepted for API compatibility but silently ignored.
|
||||
|
||||
Project / operator strings (max 41 ASCII characters each):
|
||||
project : str
|
||||
@@ -1679,9 +1681,13 @@ def _encode_compliance_config(
|
||||
record_time → float32 BE at anchor_pos + 6
|
||||
|
||||
Channel block (anchored on b"Tran" with unit-string guard):
|
||||
max_range_geo → float32 BE at tran_pos + 28
|
||||
trigger_level_geo → float32 BE at tran_pos + 34
|
||||
alarm_level_geo → float32 BE at tran_pos + 42
|
||||
NOTE: tran_pos + 28 (float32 = 6.206053) is the ADC-to-velocity scale factor
|
||||
(= 1/sensitivity, in/s per V) for the standard Instantel geophone. Confirmed
|
||||
from Interface Handbook §4.5: Range = 1.61133 V × 6.206053 = 10.000 in/s.
|
||||
This is a hardware/firmware constant common to all MiniMate Plus S3 units.
|
||||
It must NOT be written. max_range_geo is accepted as a parameter but silently ignored.
|
||||
|
||||
String field locations (64-byte slots, label+22 format):
|
||||
b"Project:" → value at label_pos + 22, max 41 chars + null
|
||||
@@ -1722,9 +1728,18 @@ def _encode_compliance_config(
|
||||
log.debug("_encode_compliance_config: record_time=%.3f -> offset %d", record_time, _anc + 6)
|
||||
|
||||
# ── Numeric: channel block (Tran label + unit-string guard) ───────────────
|
||||
_needs_channel = any(
|
||||
v is not None for v in (trigger_level_geo, alarm_level_geo, max_range_geo)
|
||||
)
|
||||
# NOTE: max_range_geo (float32 at tran_pos+28) is the ADC-to-velocity scale factor
|
||||
# (1/sensitivity = 6.206053 (in/s)/V — confirmed: 1.61133 V × 6.206053 = 10.000 in/s).
|
||||
# It is a hardware/firmware constant common to all MiniMate Plus S3 units.
|
||||
# It must NOT be written. The parameter is accepted for API compatibility but silently ignored.
|
||||
if max_range_geo is not None:
|
||||
log.warning(
|
||||
"_encode_compliance_config: max_range_geo=%s ignored — "
|
||||
"tran_pos+28 is the ADC scale factor (6.206053 (in/s)/V), a hardware constant "
|
||||
"that must not be overwritten",
|
||||
max_range_geo,
|
||||
)
|
||||
_needs_channel = any(v is not None for v in (trigger_level_geo, alarm_level_geo))
|
||||
if _needs_channel:
|
||||
_tran = buf.find(b"Tran", 44)
|
||||
_valid = (
|
||||
@@ -1737,12 +1752,9 @@ def _encode_compliance_config(
|
||||
if not _valid:
|
||||
log.warning(
|
||||
"_encode_compliance_config: 'Tran' channel block not found or unit "
|
||||
"guard failed — trigger/alarm/max_range will not be written"
|
||||
"guard failed — trigger/alarm will not be written"
|
||||
)
|
||||
else:
|
||||
if max_range_geo is not None:
|
||||
struct.pack_into(">f", buf, _tran + 28, max_range_geo)
|
||||
log.debug("_encode_compliance_config: max_range_geo=%.4f -> offset %d", max_range_geo, _tran + 28)
|
||||
if trigger_level_geo is not None:
|
||||
struct.pack_into(">f", buf, _tran + 34, trigger_level_geo)
|
||||
log.debug("_encode_compliance_config: trigger_level_geo=%.4f -> offset %d", trigger_level_geo, _tran + 34)
|
||||
@@ -1800,7 +1812,7 @@ def _decode_compliance_config_into(data: bytes, info: DeviceInfo) -> None:
|
||||
Channel block layout (✅ confirmed 2026-04-02 from 3-11-26 E5 frame 78
|
||||
and 1-2-26 A5 frame 77):
|
||||
"Tran" label at tran_pos
|
||||
tran_pos + 28 = max_range float32_BE (e.g. 6.206053 in/s)
|
||||
tran_pos + 28 = scale_factor float32_BE (= 1/sensitivity = 6.206053 (in/s)/V — ADC scale; NOT a UI setting)
|
||||
tran_pos + 34 = trigger_level float32_BE (e.g. 0.600000 in/s)
|
||||
tran_pos + 38 = "in.\\x00" (unit string anchor)
|
||||
tran_pos + 42 = alarm_level float32_BE (e.g. 1.250000 in/s)
|
||||
@@ -1897,14 +1909,15 @@ def _decode_compliance_config_into(data: bytes, info: DeviceInfo) -> None:
|
||||
# The channel block is only present in the full cfg (frame D delivered,
|
||||
# ~2126 bytes). Layout confirmed 2026-04-02 from both E5 frame 78 of the
|
||||
# 3-11-26 compliance-config capture and A5 frame 77 of the 1-2-26 event
|
||||
# download capture:
|
||||
# download capture. Cross-checked 2026-04-17 across both BE11529 and BE18189.
|
||||
#
|
||||
# "Tran" label at tran_pos (+0 to +3)
|
||||
# max_range float32_BE at tran_pos + 28 (e.g. 6.206053 in/s)
|
||||
# trigger float32_BE at tran_pos + 34 (e.g. 0.600000 in/s)
|
||||
# "in.\x00" unit string at tran_pos + 38 ✅ confirmed
|
||||
# alarm float32_BE at tran_pos + 42 (e.g. 1.250000 in/s)
|
||||
# "/s\x00\x00" unit string at tran_pos + 46 ✅ confirmed
|
||||
# max_range_enum uint8 at tran_pos + 20 (range selector: 0x01=10in/s, 0x00=1.25in/s — unconfirmed)
|
||||
# adc_scale float32_BE at tran_pos + 28 (= 1/sensitivity = 6.206053 (in/s)/V; confirmed: 1.61133 V × 6.206053 = 10.000 in/s Normal range; hardware constant — do NOT write)
|
||||
# trigger float32_BE at tran_pos + 34 (e.g. 0.600000 in/s) ✅
|
||||
# "in.\x00" unit string at tran_pos + 38 ✅ confirmed
|
||||
# alarm float32_BE at tran_pos + 42 (e.g. 1.250000 in/s) ✅
|
||||
# "/s\x00\x00" unit string at tran_pos + 46 ✅ confirmed
|
||||
#
|
||||
# Unit strings serve as layout anchors — if they match, the float offsets
|
||||
# are reliable. Skip "Tran2" (a later repeated label) via the +4 check.
|
||||
@@ -1917,12 +1930,14 @@ def _decode_compliance_config_into(data: bytes, info: DeviceInfo) -> None:
|
||||
and data[tran_pos + 38 : tran_pos + 42] == b"in.\x00"
|
||||
and data[tran_pos + 46 : tran_pos + 50] == b"/s\x00\x00"
|
||||
):
|
||||
config.max_range_geo = struct.unpack_from(">f", data, tran_pos + 28)[0]
|
||||
config.max_range_geo_enum = data[tran_pos + 20] # range selector enum (see above)
|
||||
config.max_range_geo = struct.unpack_from(">f", data, tran_pos + 28)[0] # hw constant
|
||||
config.trigger_level_geo = struct.unpack_from(">f", data, tran_pos + 34)[0]
|
||||
config.alarm_level_geo = struct.unpack_from(">f", data, tran_pos + 42)[0]
|
||||
log.debug(
|
||||
"compliance_config: trigger=%.4f alarm=%.4f max_range=%.4f in/s",
|
||||
config.trigger_level_geo, config.alarm_level_geo, config.max_range_geo,
|
||||
"compliance_config: trigger=%.4f alarm=%.4f range_enum=0x%02X hw_const=%.6f",
|
||||
config.trigger_level_geo, config.alarm_level_geo,
|
||||
config.max_range_geo_enum, config.max_range_geo,
|
||||
)
|
||||
elif tran_pos >= 0:
|
||||
log.warning(
|
||||
|
||||
+13
-4
@@ -269,7 +269,7 @@ class ChannelConfig:
|
||||
label: str # e.g. "Tran", "Vert", "Long", "MicL" ✅
|
||||
trigger_level: float # in/s (geo) or psi (MicL) ✅
|
||||
alarm_level: float # in/s (geo) or psi (MicL) ✅
|
||||
max_range: float # full-scale calibration constant (e.g. 6.206) 🔶
|
||||
max_range: float # hardware/firmware sensitivity constant (e.g. 6.206053) ✅ confirmed same on all units
|
||||
unit_label: str # e.g. "in./s" or "psi" ✅
|
||||
|
||||
|
||||
@@ -344,9 +344,18 @@ class ComplianceConfig:
|
||||
# Trigger/alarm levels (✅ CONFIRMED per-channel at §7.6)
|
||||
# For now we store the first geo channel (Transverse) as representatives;
|
||||
# full per-channel data would require structured Channel objects.
|
||||
trigger_level_geo: Optional[float] = None # in/s (first geo channel)
|
||||
alarm_level_geo: Optional[float] = None # in/s (first geo channel)
|
||||
max_range_geo: Optional[float] = None # in/s full-scale range
|
||||
trigger_level_geo: Optional[float] = None # in/s (first geo channel) ✅
|
||||
alarm_level_geo: Optional[float] = None # in/s (first geo channel) ✅
|
||||
max_range_geo: Optional[float] = None # ADC-to-velocity scale factor (float32 at Tran+28) ✅
|
||||
# = inverse sensitivity = 1/sensitivity (in/s per V)
|
||||
# Formula (Interface Handbook §4.5): Range = 1.61133 V × scale_factor
|
||||
# → 1.61133 × 6.206053 = 10.000 in/s (Normal range) ✅
|
||||
# Firmware uses: PPV (in/s) = ADC_voltage (V) × 6.206053
|
||||
# Identical on BE11529 and BE18189 — same Instantel geophone hardware.
|
||||
# NOT a user-configurable setting. Must NOT be written (use _encode_compliance_config).
|
||||
max_range_geo_enum: Optional[int] = None # max range selector: uint8 at Tran+20
|
||||
# hypothesis: 0x01 = Normal 10.000 in/s, 0x00 = Sensitive 1.25 in/s
|
||||
# reads 0x01 on all tested units — UNCONFIRMED (need 1.25 in/s capture)
|
||||
|
||||
# Project/setup strings (sourced from E5 / SUB 71 write payload)
|
||||
# These are the FULL project metadata from compliance config,
|
||||
|
||||
Reference in New Issue
Block a user