Improve read reliability

This commit is contained in:
Odd Stråbø 2021-11-20 09:00:28 +01:00
parent b008f524bf
commit f7e359af6d

View file

@ -230,8 +230,8 @@ def construct_request(address, words=1, action=ACTION_READ, marker=0xFF):
return struct.pack("!BBHH", marker, action, address, words) return struct.pack("!BBHH", marker, action, address, words)
def log(*message: object): def log(*message: object, **kwargs):
print(datetime.datetime.utcnow().isoformat(" "), *message) print(datetime.datetime.utcnow().isoformat(" "), *message, **kwargs)
sys.stdout.flush() sys.stdout.flush()
@ -255,12 +255,52 @@ def parse_packet(data):
return payload return payload
def readMemory(fh: RawIOBase, address: int, words: int = 1): def discardUntil(fh: RawIOBase, byte: int, timeout=10) -> Optional[int]:
assert byte >= 0 and byte < 256, f"byte: Expected 8bit unsigned int, got {byte}"
def expand(b: Optional[bytes]):
if b is None:
return b
return b[0]
start = time.time()
discarded = 0
read_byte = expand(fh.read(1))
while read_byte != byte:
if read_byte is not None:
if not discarded:
log("Discarding", end="")
discarded += 1
print(f" {read_byte:02X}", end="")
sys.stdout.flush()
if time.time() - start > timeout:
read_byte = None
break
read_byte = expand(fh.read(1))
if discarded:
print()
sys.stdout.flush()
return read_byte
def readMemory(fh: RawIOBase, address: int, words: int = 1) -> Optional[bytes]:
# log(f"Reading {words} words from 0x{address:04X}") # log(f"Reading {words} words from 0x{address:04X}")
write(fh, construct_request(address, words=words)) request = construct_request(address, words=words)
header = fh.read(3) # log("Request:", request)
if header and len(header) == 3: write(fh, request)
tag, operation, size = header
tag = discardUntil(fh, 0xFF)
if tag is None:
return None
header = fh.read(2)
if header and len(header) == 2:
operation, size = header
data = fh.read(size) data = fh.read(size)
_crc = fh.read(2) _crc = fh.read(2)
if data and _crc: if data and _crc:
@ -268,6 +308,10 @@ def readMemory(fh: RawIOBase, address: int, words: int = 1):
calculated_crc = modbus(bytes([tag, operation, size, *data])) calculated_crc = modbus(bytes([tag, operation, size, *data]))
if crc == calculated_crc: if crc == calculated_crc:
return data return data
else:
log(f"readMemory: CRC error; {crc:04X} != {calculated_crc:04X}")
log("data or crc is falsely", header, data, _crc)
return None
class Periodical: class Periodical:
@ -311,6 +355,8 @@ def try_read_parse(
log(e) log(e)
log("0x0100 Unpack error:", len(res), res) log("0x0100 Unpack error:", len(res), res)
log("Flushed from read buffer; ", dev.read(timeout=0.5)) log("Flushed from read buffer; ", dev.read(timeout=0.5))
else:
log(f"No data read, expected {words*2} bytes (attempts left: {attempts})")
return None return None