3、HSMS 消息结构:消息头格式与消息体编码规则

HSMS(High-Speed SECS Message Services)消息是 SECS/GEM 通信中设备与主机之间交换的基本数据单元。理解 HSMS 消息结构,特别是消息头(Header)的每个字段含义以及消息体(Body)的编码规则,是进行链路诊断和故障排查的基础。本节将详细拆解 HSMS 消息的二进制格式。

3.1 HSMS 消息头格式

每个 HSMS 消息都以一个固定长度为 10 字节(80 位)的消息头开始。消息头包含了控制消息类型、会话标识、数据项标识以及消息完整性校验所需的关键信息。其结构如下表所示:

字节偏移 字段名称 长度(字节) 描述
0-1 Length 2 消息体长度(不包括消息头),大端序(Big-Endian)
2 Session ID 1 设备 ID(Device ID),用于标识通信会话
3 Header Byte 3 1 包含 Stream, Function, P/B, W bit 等子字段
4-5 Stream & Function 2 Stream 号(高字节)和 Function 号(低字节)
6-7 P/B & W bit 2 包含 P/B 类型和 W bit 标志
8-9 System Bytes 2 系统字节,用于消息匹配和超时控制
关键点: 消息头的前 2 字节(Length)不包含消息头自身的 10 字节,仅表示其后跟随的消息体(Data Message)的字节数。对于控制消息(Select, Deselect, Linktest, Reject),Length 字段始终为 0。

3.1.1 核心字段详解

  • Session ID(设备 ID): 用于区分连接到同一主机的不同设备。在 HSMS 中,Session ID 通常与 SECS-I 中的 Device ID 对应。对于控制消息,此字段通常为 0xFFFF。
  • Stream & Function: 标识 SECS 消息的类型。Stream 号(S)定义消息的类别(如 S1 为设备状态,S2 为设备控制),Function 号(F)定义具体操作(如 F0 为 Abort,F13 为 Establish Communication Request)。
  • P/B(Primary/Block): 指示消息是主消息(Primary)还是从消息(Secondary)。P/B = 0 表示主消息,P/B = 1 表示从消息。
  • W bit(Wait bit): 指示发送方是否期望收到回复。W bit = 1 表示需要回复,W bit = 0 表示不需要回复(Fire-and-Forget)。
  • System Bytes: 由发送方生成的一个唯一标识符,用于将主消息与其对应的从消息(回复)进行匹配。接收方在回复时必须将 System Bytes 原样返回。
诊断提示: 在排查通信故障时,检查 System Bytes 是否匹配是判断消息是否被正确回复的关键。如果主机发送了一个 W bit = 1 的消息,但设备回复的 System Bytes 与主机发送的不一致,则说明消息匹配逻辑出现错误。

3.1.2 消息头结构 SVG 图

下图展示了 HSMS 消息头的完整字节布局,以及各字段在 10 字节中的具体位置:

HSMS 消息头结构图 HSMS 消息头结构(10 字节) 字节偏移: 0-1 2 3 4-5 6-7 8-9 Length Session ID Header Byte 3 Stream & Function P/B & W bit System Bytes R, S, P/B, W bit 子字段 Stream 号 (高字节) Function 号 (低字节) P/B 位 (bit 15) W bit (bit 14) 总长度:10 字节(80 位) | 大端序(Big-Endian)传输 控制消息(Select/Deselect/Linktest/Reject)的 Length 字段为 0

3.2 消息体编码规则

消息体(Body)紧跟在 10 字节的消息头之后,其长度由消息头中的 Length 字段指定。消息体采用 SECS-II 数据格式进行编码,这是一种基于类型-长度-值(TLV)的嵌套结构。SECS-II 定义了多种数据类型,用于表示整数、浮点数、字符串、列表等。

3.2.1 基本数据类型

格式代码 数据类型 描述 示例
00 List 包含多个子项的列表 <L [3]>
10 Binary 二进制数据 <B [2]> 0x01 0x02
20 Boolean 布尔值(TRUE/FALSE) <BOOLEAN [1]> TRUE
30 ASCII ASCII 字符串 <A [5]> "HELLO"
40 JIS-8 8 位日文字符 <J [3]> 0x82 0xA0 0x82
50 2-byte Unsigned Integer 无符号 16 位整数 <U2 [1]> 100
60 1-byte Signed Integer 有符号 8 位整数 <I1 [1]> -10
70 4-byte Signed Integer 有符号 32 位整数 <I4 [1]> 123456
80 8-byte Signed Integer 有符号 64 位整数 <I8 [1]> 9876543210
90 4-byte Float 单精度浮点数 <F4 [1]> 3.14
A0 8-byte Float 双精度浮点数 <F8 [1]> 2.71828

3.2.2 编码规则:格式字节与长度字节

每个 SECS-II 数据项都以一个 格式字节(Format Byte) 开头,随后是 长度字节(Length Bytes),最后是 数据字节(Data Bytes)。

  • 格式字节(1 字节): 高 4 位表示数据类型(如 0x5 表示 U2),低 4 位表示长度字节的个数(通常为 0 或 1)。如果低 4 位为 0,则数据项为空;如果为 1,则后面跟 1 个长度字节;如果为 2,则后面跟 2 个长度字节(用于长度大于 255 的数据)。
  • 长度字节(1 或 2 字节): 表示数据字节的实际个数。对于 List 类型,长度表示子项的数量。
  • 数据字节: 实际的数据内容,按照大端序排列。
常见编码错误: 在诊断过程中,经常发现格式字节的低 4 位与后续长度字节的个数不匹配。例如,格式字节为 0x51(表示 U2 类型,且低 4 位为 1),但后面却跟了 2 个长度字节,这会导致解析器读取错误的数据长度,进而引发消息解析失败。

3.2.3 消息体编码示例

以下是一个 S1F13(Establish Communication Request)消息体的编码示例,它包含一个 List,其中包含一个 ASCII 字符串(MDLN)和一个 ASCII 字符串(SOFTREV):

// S1F13 消息体编码(十六进制)
// 格式: <L [2]> <A [4]> "ABCD" <A [6]> "123456"

// 编码分解:
// 0x01 0x02    -- 消息头 Length = 2 字节(消息体长度)
// 0x01 0x13    -- 消息头 Stream = 1, Function = 13
// 0x00 0x01    -- 消息头 P/B = 0, W bit = 1
// 0x00 0x01    -- 消息头 System Bytes = 1

// 消息体开始:
// 0x01 0x02    -- 格式字节: 0x01 (List, 低4位=1, 表示1个长度字节), 长度字节: 0x02 (2个子项)
// 0x41 0x04    -- 格式字节: 0x41 (ASCII, 低4位=1), 长度字节: 0x04 (4个字符)
// 0x41 0x42 0x43 0x44  -- 数据: "ABCD"
// 0x41 0x06    -- 格式字节: 0x41 (ASCII), 长度字节: 0x06 (6个字符)
// 0x31 0x32 0x33 0x34 0x35 0x36  -- 数据: "123456"

3.2.4 消息体编码规则 SVG 图

下图展示了 SECS-II 消息体的 TLV 编码结构,以及格式字节和长度字节的详细位布局:

SECS-II 消息体 TLV 编码结构 SECS-II 消息体 TLV 编码结构 格式字节 长度字节 数据字节(N 个) 高 4 位: 数据类型 (0x0-0xA) 低 4 位: 长度字节数 (0, 1, 2) 1 字节: 长度 < 256 2 字节: 长度 >= 256 嵌套 List List 的子项可以是 任意数据类型,包括 另一个 List 编码顺序:格式字节 → 长度字节 → 数据字节 示例:0x41 0x05 0x48 0x45 0x4C 0x4C 0x4F 表示 ASCII 字符串 "HELLO"

3.3 消息头与消息体组合示例

以下是一个完整的 HSMS 消息(S1F13 W)的十六进制转储示例,展示了消息头与消息体如何组合在一起:

// 完整的 S1F13 W 消息(十六进制)
// 消息头 (10 字节):
00 0E    // Length = 14 (消息体有 14 字节)
00       // Session ID = 0 (设备 ID)
01       // Header Byte 3 (R=0, S=0, P/B=0, W=1)
01 0D    // Stream = 1, Function = 13
40 01    // P/B = 0, W bit = 1
00 01    // System Bytes = 1

// 消息体 (14 字节):
01 02    // List, 2 个子项
41 04    // ASCII, 4 个字符
41 42 43 44  // "ABCD"
41 06    // ASCII, 6 个字符
31 32 33 34 35 36  // "123456"
诊断技巧: 使用网络抓包工具(如 Wireshark)捕获 HSMS 流量时,可以按照上述结构逐字节解析。首先找到 10 字节的消息头,确认 Length 字段的值,然后根据 Length 读取后续的消息体。如果 Length 字段的值与实际消息体长度不符,则说明消息帧存在错误,可能是由于 TCP 粘包或分包导致的。