1
0

16 bit length

This commit is contained in:
2026-02-25 16:36:57 +01:00
parent 7ddacd8545
commit e606802541
4 changed files with 189 additions and 72 deletions

View File

@@ -1,6 +1,7 @@
import serial
import struct
import time
from warnings import warn
def crc8(data: bytes) -> int:
crc = 0x00
@@ -12,39 +13,49 @@ def crc8(data: bytes) -> int:
return crc
class I2CPCClient:
def __init__(self, port, baudrate=115200, timeout=1):
def __init__(self, port, baudrate=115200, timeout=1, wake_bauds: list | None = None):
if wake_bauds is None: wake_bauds = [921_600, 115_200, 9600, 19200, 576_000]
self.ser = serial.Serial(port=port, baudrate=baudrate, timeout=timeout)
self.ser.write(b"~/")
self.ser.write(b"\x00"*128)
self.ser.flush()
self.ser.write(b"~/")
self.ser.flush()
start = time.monotonic()
while not ((d := self.ser.read_all()) and b"\xff" in d):
time.sleep(0.01)
if ((time.monotonic()) - start) > 5: raise ConnectionError("Could not wake")
def wake(baud: int | None):
if baud: self.ser.baudrate = baud
self.ser.write(b"~/")
self.ser.write(b"\x00"*128)
self.ser.flush()
self.ser.write(b"~/")
self.ser.flush()
start = time.monotonic()
while not ((d := self.ser.read_all()) and b"\xff" in d):
time.sleep(0.01)
if ((time.monotonic()) - start) > 2: return False
return True
if not wake(None):
for baud in wake_bauds:
if wake(baud):
warn(f"Initial baud was changed to {baud}, due to the device being in it")
break
else: raise ConnectionError("Could not wake")
def _send_packet(self, payload: bytes, crc: bool = True):
if len(payload) > 127: raise ValueError("Payload too large")
if len(payload) > 0x7fff: raise ValueError("Payload too large")
length_byte = len(payload) | (0x80 if crc else 0x00)
data = bytes([length_byte]) + payload
length_data = len(payload) | (0x8000 if crc else 0)
data = struct.pack(">H", length_data) + payload
if crc: data += bytes([crc8(data)])
self.ser.write(data)
# Read response length
resp_len_raw = self.ser.read(1)
resp_len_raw = self.ser.read(2)
if not resp_len_raw: raise TimeoutError("No response")
resp_len = resp_len_raw[0]
resp_has_crc = bool(resp_len & 0x80)
resp_len &= 0x7F
resp_len, *_ = struct.unpack(">H", resp_len_raw)
resp_has_crc = bool(resp_len & 0x8000)
resp_len &= 0x7FFF
total_to_read = resp_len + (1 if resp_has_crc else 0)
response = self.ser.read(total_to_read)
if response[0] == 0xff and len(response) > 1: raise Exception(f"Error from device: {response[1]}")
if len(response) != total_to_read: raise TimeoutError("Incomplete response")
if resp_has_crc:
@@ -52,9 +63,7 @@ class I2CPCClient:
body = resp_len_raw + response[:-1]
if crc8(body) != received_crc: raise ValueError("CRC mismatch")
response = response[:-1]
if response[0] == 0xff and resp_len == 1: raise Exception(f"Error from device: {response[1]}")
return response[1:]
def set_clock(self, clock_hz: int):
payload = bytes([0]) + struct.pack(">I", clock_hz)
@@ -67,7 +76,7 @@ class I2CPCClient:
def write_read_i2c(self, addr: int, write_data: bytes, read_len: int):
payload = bytes([2, addr, len(write_data)]) + write_data + bytes([read_len])
return self._send_packet(payload, False)
def write_eeprom(self, addr: int, data: bytes):
payload = bytes([7]) + struct.pack(">H", addr) + data
return self._send_packet(payload, False)