2. 消息结构解析:SECS-II 消息头与消息体的字节布局
SECS-II 消息是 SECS/GEM 协议栈中设备与主机之间交换的最小逻辑单元。一条完整的 SECS-II 消息由 消息头(Message Header) 和 消息体(Message Body) 两部分组成。消息头承载传输控制信息,消息体承载实际的设备数据或命令参数。理解其字节布局是协议栈移植和消息事务处理的基础。
关键概念: SECS-II 消息的字节序采用 大端序(Big-Endian),即高位字节存储在低地址。所有多字节字段(如 Device ID、System Bytes)均遵循此规则。
2.1 消息头(Message Header)字节布局
消息头固定长度为 10 字节,位于消息的最前端。其结构定义了消息的路由、类型和事务标识。下表列出了消息头各字段的偏移量、长度及含义:
| 偏移量(字节) | 长度(字节) | 字段名称 | 说明 |
|---|---|---|---|
| 0 | 2 | Device ID | 设备标识符,用于区分多设备场景下的目标设备。 |
| 2 | 1 | R bit + S bit + F bit | 控制位:R(Reply expected)、S(Secondary)、F(Function type)。 |
| 3 | 1 | Stream | 消息流编号(0-255),定义消息的类别。 |
| 4 | 1 | Function | 消息功能编号(0-255),定义消息的具体操作。 |
| 5 | 1 | P bit + S bit + Reserved | 控制位:P(Primary/Secondary)、S(Wait bit),其余保留。 |
| 6 | 4 | System Bytes | 系统字节,用于事务匹配和超时管理。 |
字段详解:
- Device ID (2字节): 取值范围 0-32767。在单设备场景下通常固定为 0。
- 控制位 (1字节): 第7位为 R bit(1=期望回复),第6位为 S bit(1=Secondary消息),第5位为 F bit(1=Function类型)。
- Stream/Function (各1字节): 组合成 SxFy 格式,例如 S1F13 表示 Stream 1, Function 13。
- System Bytes (4字节): 由发送方生成唯一值,接收方在回复消息中回传相同值以完成事务匹配。
以下 SVG 展示了消息头 10 字节的完整布局,并标注了每个字段的位偏移和功能:
2.2 消息体(Message Body)字节布局
消息体紧跟在消息头之后,其长度由消息头中的 Stream/Function 以及实际数据决定。消息体采用 SECS-II 数据项(Data Item) 格式进行编码,每个数据项由 长度字节(Length Bytes) 和 数据字节(Data Bytes) 组成。数据项可以嵌套,形成复杂的树形结构。
数据项的基本编码规则如下:
- 长度字节: 使用 1、2 或 3 字节表示后续数据字节的长度。长度字节的最高位(MSB)用于指示长度字节本身的个数(1=还有后续长度字节)。
- 数据字节: 包含实际的数据内容,格式由数据项的格式代码(Format Code)决定。
下表列出了常见的 SECS-II 数据项格式代码及其对应的数据类型:
| 格式代码(十六进制) | 数据类型 | 说明 |
|---|---|---|
| 0x00 | List | 列表,包含多个子数据项 |
| 0x10 | Binary | 二进制数据 |
| 0x20 | Boolean | 布尔值(TRUE/FALSE) |
| 0x30 | ASCII | ASCII 字符串 |
| 0x40 | JIS-8 | 日文汉字字符串 |
| 0x50 | I8 | 8 字节有符号整数 |
| 0x60 | I1 | 1 字节有符号整数 |
| 0x70 | I2 | 2 字节有符号整数 |
| 0x80 | I4 | 4 字节有符号整数 |
| 0x90 | F8 | 8 字节浮点数 |
| 0xA0 | F4 | 4 字节浮点数 |
| 0xB0 | U8 | 8 字节无符号整数 |
| 0xC0 | U1 | 1 字节无符号整数 |
| 0xD0 | U2 | 2 字节无符号整数 |
| 0xE0 | U4 | 4 字节无符号整数 |
注意: 在解析消息体时,必须严格按照长度字节指示的字节数读取数据,并递归处理嵌套的 List 数据项。错误的长度解析会导致消息边界错乱,进而引发协议栈解析异常。
以下 SVG 展示了一个包含 List 和 ASCII 数据项的消息体字节布局示例:
2.3 消息头与消息体的组合结构
在实际的 SECS-II 消息中,消息头和消息体连续排列,形成完整的消息帧。消息头提供路由和控制信息,消息体承载具体数据。以下 SVG 展示了完整消息帧的结构:
2.4 消息解析流程
在协议栈移植过程中,解析 SECS-II 消息通常遵循以下步骤:
- 读取消息头: 从接收缓冲区中读取前 10 字节,解析 Device ID、控制位、Stream、Function 和 System Bytes。
- 验证消息头: 检查控制位合法性(如 R bit 是否与期望一致),确认 Stream/Function 是否在支持列表中。
- 解析消息体: 根据消息头中的 Stream/Function 确定消息体的预期结构,然后递归解析数据项。
- 事务匹配: 使用 System Bytes 查找对应的事务上下文,将解析后的消息体挂载到事务对象中。
- 错误处理: 如果解析过程中发现长度不匹配、格式码无效或数据溢出,则触发错误回调并丢弃消息。
移植提示: 在嵌入式环境中,建议使用 状态机 驱动消息解析流程。状态机可以优雅地处理分片接收和部分数据到达的场景,避免阻塞式读取。典型的状态包括:WAIT_HEADER、PARSE_HEADER、WAIT_BODY、PARSE_BODY、MESSAGE_COMPLETE。