Added 3 new batteries
This commit is contained in:
@@ -433,6 +433,12 @@ class ModbusActivePoller:
|
||||
bytesize=8, parity="N", stopbits=1,
|
||||
)
|
||||
|
||||
# Some pack/FTDI combos (observed on 2026-05-11 batch) emit one or two
|
||||
# line-idle bytes before the real Modbus frame, e.g. "00 f0 40 03 4e …".
|
||||
# Tolerate up to this many leading non-frame bytes by sliding the
|
||||
# window and CRC-checking each candidate offset.
|
||||
_MAX_LEADING_IDLE = 4
|
||||
|
||||
def _read_block(self, start: int, count: int) -> list[int]:
|
||||
body = bytes([self._address, 0x03,
|
||||
start >> 8, start & 0xFF, count >> 8, count & 0xFF])
|
||||
@@ -443,7 +449,8 @@ class ModbusActivePoller:
|
||||
self._ser.reset_input_buffer()
|
||||
self._ser.write(frame)
|
||||
|
||||
expected = 3 + count * 2 + 2
|
||||
# Read enough bytes to also cover any leading idle bytes.
|
||||
expected = 3 + count * 2 + 2 + self._MAX_LEADING_IDLE
|
||||
buf = bytearray()
|
||||
deadline = time.monotonic() + self._timeout_s
|
||||
while time.monotonic() < deadline and len(buf) < expected:
|
||||
@@ -454,15 +461,21 @@ class ModbusActivePoller:
|
||||
log.debug("pack 0x%02x [%d@%d] tx=%s rx=%s",
|
||||
self._address, count, start, frame.hex(" "), raw.hex(" "))
|
||||
|
||||
if len(raw) < 5 or raw[0] != self._address or raw[1] != 0x03:
|
||||
raise RuntimeError(f"no/bad response ({len(raw)} B) for read({count}@{start})")
|
||||
bc = raw[2]
|
||||
if len(raw) < 3 + bc + 2:
|
||||
raise RuntimeError(f"truncated response for read({count}@{start})")
|
||||
if not _crc_ok(raw, 0, 3 + bc + 2):
|
||||
raise RuntimeError(f"CRC mismatch for read({count}@{start})")
|
||||
data = raw[3:3 + bc]
|
||||
return [(data[i] << 8) | data[i + 1] for i in range(0, len(data), 2)]
|
||||
# Locate the real frame: address byte + fn=0x03 + valid CRC, at
|
||||
# offset 0..MAX_LEADING_IDLE. Reject any candidate whose CRC fails.
|
||||
for off in range(min(self._MAX_LEADING_IDLE + 1, max(len(raw) - 4, 0))):
|
||||
if raw[off] != self._address or raw[off + 1] != 0x03:
|
||||
continue
|
||||
bc = raw[off + 2]
|
||||
frame_end = off + 3 + bc + 2
|
||||
if frame_end > len(raw):
|
||||
continue
|
||||
if not _crc_ok(raw, off, 3 + bc + 2):
|
||||
continue
|
||||
data = raw[off + 3:off + 3 + bc]
|
||||
return [(data[i] << 8) | data[i + 1] for i in range(0, len(data), 2)]
|
||||
|
||||
raise RuntimeError(f"no valid frame in {len(raw)} bytes for read({count}@{start})")
|
||||
|
||||
def poll(self) -> list[int]:
|
||||
self._open()
|
||||
|
||||
Reference in New Issue
Block a user