4、GEM消息类型:Stream消息、Function消息、Block消息
GEM协议里的消息,说白了就是设备(比如机器人、泵、阀门)和主机之间沟通的“语言”。我刚开始接触的时候,觉得消息类型这个概念很抽象。后来在项目里调了几个月,才真正摸清楚它们的脾气。
GEM标准定义了三种核心消息类型:Stream消息、Function消息和Block消息。它们不是平级关系,而是层层嵌套的。你想想看,就像寄快递:Stream是快递公司,Function是包裹里的物品类别,Block就是物品本身的数据。
4.1 消息结构总览
先看一张整体结构图,后面我们再逐个拆解。
4.2 Stream消息——消息的大类
Stream是消息的第一层分类。它定义了这条消息属于哪个功能域。GEM标准里,Stream 0 是测试流,Stream 1 到 Stream 255 是正式流。不过实际项目中,常用的也就十几个。
我记得第一次看SECS-II协议文档时,被Stream列表吓了一跳。后来发现,大部分项目只需要用到Stream 1、2、5、6、7这几个。其他的,说实话,很多设备厂商自己都没实现。
| Stream编号 | 功能域 | 典型用途 |
|---|---|---|
| S0 | 测试/诊断 | 通信测试、回环测试 |
| S1 | 设备状态 | 设备ID查询、状态模型、在线/离线 |
| S2 | 设备控制与诊断 | 参数设置、诊断请求、时间设置 |
| S5 | 报警管理 | 报警上报、报警确认、报警列表 |
| S6 | 数据收集 | 事件上报、追溯数据、SPC数据 |
| S7 | 配方管理 | 配方下载、配方上传、配方验证 |
| S10 | 终端服务 | 终端显示消息、操作员交互 |
4.3 Function消息——消息的具体操作
确定了Stream之后,Function告诉对方你要做什么。每个Function都有一个编号,而且有个规律:奇数Function是请求,偶数Function是响应。
举个例子,S1F13是“请求设备ID”,S1F14就是“返回设备ID”。你发S1F13过去,对方回S1F14给你。这个配对关系,是GEM通信的基础。
为什么会这样设计?说白了,就是为了让通信双方能明确知道:我发的请求有没有被处理,处理结果是什么。如果对方回了一个错误的Function编号,那基本可以断定通信出问题了。
常见的Function编号示例:
- S1F13 / S1F14:设备ID查询
- S1F17 / S1F18:在线/离线请求
- S2F41 / S2F42:远程命令发送
- S5F1 / S5F2:报警上报
- S6F11 / S6F12:事件数据上报
4.4 Block消息——真正的数据
Block是消息的最内层,也是实际数据的载体。GEM支持两种数据格式:ASCII和二进制。
ASCII格式可读性好,调试方便。二进制格式效率高,适合传输大量数据。我个人习惯:开发阶段用ASCII,方便抓包看数据;正式上线前再切到二进制,提升性能。
Block消息的结构如下:
Block = 长度(2字节) + 数据(N字节) + 校验(1字节)
长度:整个Block的字节数(包含长度和校验字段)
数据:实际的消息内容
校验:异或校验,用于检测传输错误
4.5 三种消息的协作流程
现在我们把三者串起来,看一个完整的通信流程。
这个流程看起来简单,但实际开发中,每一步都有坑。比如:
- 主机发了S1F13,设备没响应怎么办?——需要设置超时重传机制。
- 设备返回的Block数据格式不对怎么办?——需要做数据校验和格式检查。
- 网络断开后重连,消息序号怎么处理?——需要维护消息计数器。
4.6 消息类型对比总结
| 特性 | Stream消息 | Function消息 | Block消息 |
|---|---|---|---|
| 层级 | 第一层(外层) | 第二层(中间层) | 第三层(内层) |
| 作用 | 定义消息类别 | 定义具体操作 | 承载实际数据 |
| 取值范围 | 0 ~ 255 | 0 ~ 255 | 无固定范围 |
| 奇偶规则 | 无 | 奇数请求,偶数响应 | 无 |
| 数据格式 | 无 | 无 | ASCII 或 二进制 |
| 调试难度 | 低 | 中 | 高(需解析数据) |
嗯,到这里,三种消息类型的基本概念应该清楚了。记住这个三层结构,后面讲消息编码和解析时,你会回来感谢我的。