import argparse import struct import time import xml.etree.ElementTree as ET import serial SOF = b"\xAA\x55" EOF = b"\x0D" CMD_HANDSHAKE = 0x01 CMD_SET_ROLE = 0x02 CMD_READ_REGISTER = 0x10 CMD_WRITE_REGISTER = 0x11 CMD_READ_GROUP = 0x20 CMD_WRITE_GROUP = 0x21 CMD_READ_PACKAGE = 0x30 CMD_DATA_CHUNK = 0x31 CMD_READ_XML = 0x32 CMD_ACK = 0x7E CMD_ERROR = 0x7F XML_DATA_STRUCTURE_ID = 0xFFFF def checksum16(data: bytes) -> int: return sum(data) & 0xFFFF def build_frame(cmd: int, payload: bytes = b"") -> bytes: body = bytes([cmd]) + payload length = struct.pack(" 0: del self.buf[:sof_index] if len(self.buf) < 2 + 2: break length = struct.unpack(" str: if "}" in tag: return tag.split("}", 1)[1] return tag def parse_register_defaults(xml_bytes: bytes): result = {} try: root = ET.fromstring(xml_bytes) except Exception: return result for elem in root.iter(): if strip_namespace(elem.tag) != "register": continue reg_id = elem.attrib.get("id") reg_type = elem.attrib.get("type", "uint32") if not reg_id: continue default_value = "0" for child in list(elem): if strip_namespace(child.tag) == "value": default_value = child.attrib.get("default", "0") break result[int(reg_id)] = (reg_type, default_value) return result def encode_value(reg_type: str, text: str) -> bytes: try: if reg_type in ("uint8", "byte"): return struct.pack("