from dataclasses import dataclass from typing import Optional import struct @dataclass class Frame: """帧数据结构""" command: int # 命令码 (4字节) length: int # 数据长度 (4字节) frame_idx: int # 帧序号 (4字节) channels: list # 17个通道数据 (每个4字节) checksum: int # 校验和 (1字节) class FrameFormat: """帧格式描述类""" # 帧头魔数 (4字节) FRAME_HEADER = bytes([0xAA, 0xAA, 0xAA, 0xAA]) # 各字段长度定义 HEADER_SIZE = 4 COMMAND_SIZE = 4 LENGTH_SIZE = 4 INDEX_SIZE = 4 CHECKSUM_SIZE = 1 CHANNEL_SIZE = 4 # 每个通道的字节数 CHANNEL_COUNT = 17 # 通道数量 # 帧固定部分的长度(不包含可变长度的数据部分) FIXED_SIZE = HEADER_SIZE + COMMAND_SIZE + LENGTH_SIZE + INDEX_SIZE + CHECKSUM_SIZE # 数据部分的长度(帧IDX + 通道数据) DATA_SIZE = INDEX_SIZE + (CHANNEL_COUNT - 1) * CHANNEL_SIZE # 帧IDX + (通道数-1)个通道数据 @classmethod def generateFrameData(cls, frame_idx: int, command: int = None, channel_values: list = None) -> bytes: """ 生成测试用的帧数据 Args: frame_idx: 帧序号 command: 命令码,如果为None则使用frame_idx作为命令码 channel_values: 通道数据列表,如果为None则生成随机数据 Returns: bytes: 完整的帧数据 """ # 使用frame_idx作为默认命令码 if command is None: command = frame_idx # 生成随机通道数据 if channel_values is None: import random channel_values = [] for _ in range(cls.CHANNEL_COUNT): # 使用类常量确保17个通道 # 生成-1000到1000之间的随机浮点数,转换为整数存储 value = int(random.uniform(-1000, 1000) * 1000) # 放大1000倍以保持精度 channel_values.append(value) elif len(channel_values) != cls.CHANNEL_COUNT: raise ValueError(f"通道数据数量必须为 {cls.CHANNEL_COUNT},当前为 {len(channel_values)}") # 构建数据部分(帧IDX + 通道数据) data = struct.pack(" Optional[Frame]: """ 解析帧数据 Args: data: 完整的帧数据 Returns: Frame: 解析后的帧对象,如果解析失败返回None """ try: # 检查数据长度 if len(data) < cls.FIXED_SIZE + cls.DATA_SIZE: print(f"数据长度不足: {len(data)} < {cls.FIXED_SIZE + cls.DATA_SIZE}") return None # 检查帧头 if data[:cls.HEADER_SIZE] != cls.FRAME_HEADER: print(f"帧头不匹配: {data[:cls.HEADER_SIZE].hex()} != {cls.FRAME_HEADER.hex()}") return None # 解析固定字段 offset = cls.HEADER_SIZE command = struct.unpack(" len(data): print("错误:数据长度不足以读取所有通道") return None channel_value = struct.unpack("= len(data): print("错误:数据长度不足以读取校验和") return None # 提取校验和 checksum = data[offset] # 验证校验和 if not cls.verify_checksum(data[:offset], checksum): print("校验和验证失败") return None return Frame( command=command, length=length, frame_idx=frame_idx, channels=channels, checksum=checksum ) except Exception as e: print(f"解析帧时出错: {e}") return None @classmethod def build_frame(cls, command: int, index: int, data: bytes) -> bytes: """ 构建帧数据 Args: command: 命令码 index: 帧索引 data: 数据内容 Returns: bytes: 完整的帧数据 """ # 构建帧数据(不包含校验和) frame_data = ( cls.FRAME_HEADER + struct.pack(" int: """ 计算校验和 - 不包含校验码本身 Args: data: 需要计算校验和的数据(不包含校验码) Returns: int: 校验和值 """ # 简单的字节累加校验 return sum(data) & 0xFF @classmethod def verify_checksum(cls, data: bytes, checksum: int) -> bool: """ 验证校验和 Args: data: 数据内容(不包含校验码) checksum: 校验和值 Returns: bool: 校验结果 """ return cls.calculate_checksum(data) == checksum @classmethod def get_frame_length(cls, data: bytes) -> Optional[int]: """ 从数据中获取帧总长度 Args: data: 至少包含帧头和长度字段的数据 Returns: int: 帧总长度,如果数据不足返回None """ min_size = cls.HEADER_SIZE + cls.COMMAND_SIZE + cls.LENGTH_SIZE if len(data) < min_size: return None if data[:cls.HEADER_SIZE] != cls.FRAME_HEADER: return None length = struct.unpack("= {FrameFormat.FIXED_SIZE}") # 2. 检查帧头 frame_header = test_data[:FrameFormat.HEADER_SIZE] print(f"2. 检查帧头: {frame_header.hex().upper()} == {FrameFormat.FRAME_HEADER.hex().upper()}") # 3. 解析命令码 offset = FrameFormat.HEADER_SIZE command_bytes = test_data[offset:offset+FrameFormat.COMMAND_SIZE] command = struct.unpack("