3. SECS-II数据项类型全解

SECS-II 消息体由一串“数据项”组成,每个数据项都带一个格式字节,用来告诉接收端“我是什么类型、有多长”。理解这些类型的编码规则,是解析报文、构造回复、排查长度错位问题的基本功。本节把常用类型分成四组来看:结构类(L)、位与逻辑类(B、BOOLEAN)、字符类(A、JIS8)、数值类(I、U、F)。

核心规律:SECS-II 采用大端序(Big-Endian)。格式字节的高 6 位是格式码,低 2 位是长度字节数(1、2 或 3 字节)。长度字段表示的是“元素个数”,不是字节数——这一点对 I2、F8 这类多字节类型尤其关键。

格式字节与长度字段

每个数据项以 1 字节格式码开头。格式码 = (格式编号 << 2) | 长度字节数。例如 A 类型格式编号为 020 八进制(即 0x10),若长度用 1 字节表示,格式字节就是 0x10 | 0x01 = 0x11;若长度需要 2 字节,则为 0x12。长度字段紧随其后,按大端序读取,其值等于该数据项包含的元素个数。对于 A、JIS8、B 这类单字节元素,元素个数等于字节数;对于 I2、U4、F8,元素个数要乘以元素宽度才是实际字节数。

示例:A 类型,内容 "HELLO"(5 字节)
格式字节 = 0x11        (A, 1 字节长度)
长度字段 = 0x05        (5 个字符)
数据     = 48 45 4C 4C 4F

示例:U4 类型,内容 [0x00000001, 0x00000002]
格式字节 = 0x72        (U4, 2 字节长度)
长度字段 = 0x0002      (2 个元素)
数据     = 00 00 00 01 00 00 00 02   (共 8 字节)

结构类:L(List)

L 是唯一可以嵌套的类型,相当于“容器”。它的长度字段表示列表中包含的子数据项个数,而不是字节数。解析 L 时必须递归:先读格式字节和长度,再循环读取 N 个子项,每个子项自己带格式字节。L 的格式编号为 000 八进制,格式字节常见为 0x01(1 字节长度)。空列表写作 0x01 0x00。L 是构建复杂消息(如多参数事件报告)的骨架,几乎所有结构化报文都从 L 开始。

位与逻辑类:B、BOOLEAN

B(Binary)表示任意二进制位串,格式编号 010 八进制,格式字节 0x21/0x22/0x23。长度字段是字节数,每个字节 8 位,高位在前。B 常用于传输位掩码、状态字、原始字节块。BOOLEAN 格式编号 011 八进制,格式字节 0x25/0x26/0x27,每个元素占 1 字节,0x00 表示 False,非 0(通常 0x01)表示 True。注意 BOOLEAN 的长度是元素个数,不是位打包,所以 8 个布尔值占 8 字节,而不是 1 字节。

字符类:A、JIS8

A(ASCII)格式编号 020 八进制,格式字节 0x41/0x42/0x43,每个字符 1 字节,按 ASCII 编码。JIS8 格式编号 021 八进制,格式字节 0x45/0x46/0x47,每个字符 1 字节,按 JIS X 0201 的 8 位编码,常用于日文设备。两者长度字段都等于字符个数。解析时若遇到非 ASCII 字节,应检查是否误用了 JIS8。A 类型是设备名、配方名、错误文本最常用的载体。

数值类:I、U、F

有符号整数 I1/I2/I4/I8 分别占 1/2/4/8 字节,格式编号 030/032/034/036 八进制,格式字节 0x65/0x69/0x71/0x79(以 1 字节长度为例)。无符号整数 U1/U2/U4/U8 格式编号 031/033/035/037 八进制,格式字节 0x67/0x6B/0x73/0x7B。浮点 F4/F8 遵循 IEEE 754,格式编号 040/044 八进制,格式字节 0x91/0x99。所有数值类型都是大端序,长度字段为元素个数。例如 U2 的 3 个元素占 6 字节,长度字段写 0x0003。

SECS-II 数据项类型编码与内存表示总览 格式字节结构(1 字节) 高 6 位:格式编号(Format Code) 低 2 位:长度字节数 长度字段值 = 元素个数(非字节数) 结构类 L(List) 格式编号:000 八进制 格式字节:0x01 / 0x02 / 0x03 长度 = 子项个数 可嵌套,递归解析 空列表:0x01 0x00 用途:消息骨架、参数组 位与逻辑类 B(Binary) 格式编号:010 八进制 格式字节:0x21 / 0x22 / 0x23 长度 = 字节数,位串 BOOLEAN 格式编号:011 八进制 0x00=False,非0=True 字符类 A(ASCII) 格式编号:020 八进制 格式字节:0x41 / 0x42 / 0x43 1 字符 = 1 字节 JIS8 格式编号:021 八进制 JIS X 0201 编码 数值类 有符号 I1/I2/I4/I8 030/032/034/036 八进制 1/2/4/8 字节,补码 无符号 U1/U2/U4/U8 031/033/035/037 八进制 1/2/4/8 字节 浮点 F4/F8(IEEE 754) 内存表示示例(大端序) U2 值 [0x1234, 0x00FF] 格式字节:0x69 长度字段:0x0002(2 元素) 数据:12 34 00 FF 共 4 字节,元素宽度 2 长度≠字节数,需乘宽度 F4 值 [1.0] 格式字节:0x91 长度字段:0x0001(1 元素) 数据:3F 80 00 00 IEEE 754 单精度 大端序,高位在前 L 嵌套示例 0x01 0x02 (L,2 子项) 0x41 0x03 41 42 43 (A "ABC") 0x69 0x01 00 05 (U2 值 5) 递归读取,先读格式再读长度 子项各自独立编码

解析时的关键判断

拿到一段报文后,先读格式字节,用 (fmt >> 2) 得到格式编号,用 (fmt & 0x03) 得到长度字节数。然后按长度字节数读取长度字段,得到元素个数 N。接着根据格式编号确定元素宽度 W:A/JIS8/B/BOOLEAN/I1/U1 为 1,I2/U2 为 2,I4/U4/F4 为 4,I8/U8/F8 为 8,L 特殊——它的“数据”是 N 个子项,需要递归。实际字节数 = N × W(L 除外)。若剩余字节不足,说明报文被截断或长度字段解析错误。

常见坑:把 U4 的长度字段当成字节数,导致只读了 2 个字节就以为结束;或者把 BOOLEAN 当成位打包,误以为 8 个布尔只占 1 字节。记住“长度 = 元素个数”这条铁律,再乘元素宽度,就能避免绝大多数长度错位。

类型选择建议

设备名、配方名用 A;日文文本用 JIS8;状态字、位掩码用 B;开关量、使能标志用 BOOLEAN;计数、ID、端口号用 U1/U2/U4;温度、压力等可能为负的测量值用 I2/I4;需要小数的工艺参数用 F4/F8。选型时优先考虑接收端能否正确解析,以及数值范围是否够用。例如温度范围 -40~150℃,用 I2 足够;若需要 0.01℃ 精度,可放大 100 倍后用 I2 传输,或直接用 F4。