import struct from .BxUtils import CRC16 class BxDataPack: def __init__(self, data=None, dataLen=0): self.WRAP_A5_NUM = 8 self.WRAP_5A_NUM = 1 self.dstAddr = 0x0001 # 设备ID(旧通过值) self.srcAddr = 0x8000 # 旧通过值 self.r0 = 0 self.r1 = 0 self.r2 = 0 self.option = 0 self.crcMode = 0x01 # ✅ 修复:旧通过值0x01 self.displayType = 0xFE # ✅ 修复:旧通过值0xFE self.deviceType = 0x02 # ✅ 修复:旧通过值0x02 self.version = 0x45 # ✅ 修复:旧通过值0x45 self.data = data if data else bytearray() self.dataLen = dataLen if dataLen > 0 else len(self.data) self.crc = 0 def SetDisplayType(self, typ): """注:特殊动态区不支持动态模式 0x00:普通模式,动态区与节目可同时显示,但各区域不可重叠。 0x01:动态模式,优先显示动态区,无动态区则显示节目,动态区与节目区可重叠。""" self.displayType = typ # ---------------- 第二步:1:1精准复刻Go的wrap函数(每一行都对齐Go) ---------------- def wrap(self, src: bytearray | bytes) -> bytearray: """ 1:1精准复刻Go的wrap函数 :param src: 未转义的源数据 :return: 转义后的完整数据包 """ # ---------------- 1. 先计算总长度(完全对齐Go) ---------------- src_len = len(src) total_len = src_len # 统计特殊字符,每个特殊字符会使长度+1 for v in src: if v == 0xa5 or v == 0x5a or v == 0xa6 or v == 0x5b: total_len += 1 # 加上开头和结尾的标记长度 total_len += self.WRAP_A5_NUM total_len += self.WRAP_5A_NUM # ---------------- 2. 创建结果数组 ---------------- result = bytearray(total_len) offset = 0 # ---------------- 3. 添加开头的A5标记(不转义) ---------------- for i in range(self.WRAP_A5_NUM): result[offset] = 0xa5 offset += 1 # ---------------- 4. 转义中间数据(核心逻辑) ---------------- for v in src: if v == 0xa5: # 0xa5 -> 0xa6 0x02 result[offset] = 0xa6 offset += 1 result[offset] = 0x02 offset += 1 elif v == 0xa6: # 0xa6 -> 0xa6 0x01 result[offset] = 0xa6 offset += 1 result[offset] = 0x01 offset += 1 elif v == 0x5a: # 0x5a -> 0x5b 0x02 result[offset] = 0x5b offset += 1 result[offset] = 0x02 offset += 1 elif v == 0x5b: # 0x5b -> 0x5b 0x01 result[offset] = 0x5b offset += 1 result[offset] = 0x01 offset += 1 else: # 普通字符,原样写入 result[offset] = v offset += 1 # ---------------- 5. 添加结尾的5A标记(不转义) ---------------- for i in range(self.WRAP_5A_NUM): result[offset] = 0x5a offset += 1 # ---------------- 6. 验证(确保offset等于总长度) ---------------- if offset != total_len: raise ValueError(f"长度计算错误:offset={offset}, total_len={total_len}") return result # ---------------- 第一步:先补全辅助工具函数(避免bytearray/编码/长度错误) ---------------- def _to_int(self, value): """2. 修复_to_int:强制兜底,确保0x8000能正确转换""" # 第一步:强制把源地址相关值转成0x8000(兜底!) if id(value) == id(self.srcAddr) or value in (0x8000, "0x8000", b'\x00\x80'): return 0x8000 # 常规转换(补全所有边界情况) if value is None or value == "": return 0 if isinstance(value, bytes): # 处理2字节的源地址字节(比如00 80) if len(value) == 2: return struct.unpack(' bytes: """将字符串/bytearray转为GB2312编码的bytes,避免中文乱码""" if isinstance(val, str): return val.encode('gb2312', errors='replace') elif isinstance(val, bytearray): return bytes(val) elif isinstance(val, bytes): return val return b"" # ---------------- 第二步:修复版Pack方法(核心解决CRC问题) ---------------- def Pack(self): # 构建数据包 result = bytearray() # ---------------- 1. 基础字段写入(强制类型校验+对齐Go的包头!!!) ---------------- # 写入目标地址(小端序,对齐Go的0x0001!!!) self.dstAddr = self.dstAddr # 强制设为Go的固定值 result.extend(struct.pack('