写给第一天被老板安排「把设备跟工厂系统对接」的你。 我假设你:没听过 SECS、不知道 S1F2 是什么、不知道参数长什么样、不知道这些编号谁规定的。 没关系。这篇文章从拉网线讲起,中间自己虚构一份完整的示例规格书带你逐页读,读完你就能干活。
第 0 章:先搞清楚你在干嘛
老板说的「对接」,翻译成大白话:
工厂办公室里有一套电脑系统,车间里有你的设备。老板要它俩通过网线聊天:电脑能指挥设备开工、能随时问设备「你现在啥状态」,设备出了事要主动喊报告。
你要写的,就是设备这一端的「聊天程序」。
聊天的规矩是行业标准,叫 SECS/GEM。全世界的半导体设备都这么聊,所以工厂系统不用为每台设备单独开发一套——这就是你能「对接」而不是「定制开发」的原因。
第 1 章:名词扫盲(一张表,先背下来)
看任何 SECS 文档之前,先把这些词认了,不然规格书一个字都看不懂:
| 名词 | 全称/含义 | 人话 |
|---|---|---|
SEMI | 国际半导体设备与材料协会 | 定规矩的组织 |
SECS | SEMI Equipment Communications Standard | 「设备通信标准」,聊天的语言 |
GEM | Generic Equipment Model | 聊天的礼仪:什么场合该说什么话 |
HSMS | High-Speed SECS Message Services | 语言走网线的寄送方式 |
Host | 上位机、主机 | 工厂那台电脑 |
MES | 制造执行系统 | Host 上跑的软件,管派工、批号、追溯 |
EAP | 设备自动化程序 | Host 的另一种叫法,规格书里常见 |
EQP | Equipment | 你的设备,就是你这边 |
规格书 | SECS/GEM Interface Specification | 工厂给你的「聊天内容清单」,你的圣经 |
再记四个标准编号,文档里会反复出现:
| 标准 | 名字 | 管什么 |
|---|---|---|
SEMI E4 | SECS-I | 走串口的传输(老设备,了解即可) |
SEMI E5 | SECS-II | 每句话的格式(S1F1、S2F41 都定义在这) |
SEMI E30 | GEM | 设备行为:在线/离线、事件、报警怎么玩 |
SEMI E37 | HSMS | 走网线的传输:IP、端口、握手、超时 |
一句话总结:E5 管「说什么」,E37 管「怎么寄」,E30 管「什么场合说什么」。 三层叠起来,就是日常说的「SECS/GEM 对接」。
第 2 章:S1F2 到底是什么(最多人卡住的地方)
2.1 编号拆开读
S1F2读作「Stream 1,Function 2」。
- Stream(流)= 科室。就像医院分内科、外科、化验科,SECS 把「设备通信」这件大事按事情种类分成十几个科室。
- Function(功能)= 科室里第几张单子。化验科有「验血申请单」「验尿申请单」,S1 科室里有「1 号单」「2 号单」。
常用科室一览(先混眼熟,后面逐章细讲):
| Stream | 科室 | 管什么 |
|---|---|---|
S1 | 设备状态科 | 在不在线、建立通信、查变量 |
S2 | 设备控制科 | 远程命令、对时、定义报表 |
S5 | 报警科 | 报警上报、报警开关 |
S6 | 数据收集科 | 事件上报(开批、结批) |
S7 | 配方科 | 工艺配方的上传下载 |
S9 | 纠错科 | 收到不认识的单子怎么处理 |
S10 | 终端科 | Host 在设备屏幕上弹文字 |
S14 | 对象服务科 | 按条码查某个物料的信息 |
2.2 最重要的规律:奇数问,偶数答
Function 编号有个铁律:
奇数 = 提问/请求,偶数 = 回答/回执。而且编号配对:F1 问、F2 答;F41 问、F42 答。
看几个例子就懂了:
| 谁发 | 报文 | 意思 |
|---|---|---|
Host → 设备 | S1F1 | 「你在吗?」 |
设备 → Host | S1F2 | 「在,我是 XX 机型,软件版本 XX」 |
Host → 设备 | S2F41 | 「执行命令:开批!」 |
设备 → Host | S2F42 | 「收到,已执行 / 拒绝,原因是……」 |
设备 → Host | S6F11 | 「报告:批次开始了!」 |
Host → 设备 | S6F12 | 「知道了」 |
设备 → Host | S5F1 | 「报告:1001 号报警发生了!」 |
Host → 设备 | S5F2 | 「知道了」 |
所以「S1 代表某个功能吗?」——不准确。S1 是一个科室;S1F1、S1F2 才是具体的单子。 一次完整对话永远是两张单子:奇数问,偶数答。
「SECS 相当于函数」——这个直觉是对的,补全一下就精确了:
一张奇数单 ≈ 函数调用(带着参数),配对的偶数单 ≈ 函数返回值。 你代码里那个叫
S1F2的类,不是协议本身,只是「负责拼这张回单」的代码。
第 3 章:参数在哪?返回值长什么样?
3.1 报文 = 信封 + 正文
每张单子(报文)分两部分:
- 头部(Header):信封。写着这是 S 几 F 几、发往几号设备(Device ID)、快递单号(SystemBytes,用来把「问」和「答」配成对)。
- 正文(Body):参数就装在这里。返回值也在对方回单的正文里。
3.2 正文是一种「嵌套清单」,按 JSON 理解就行
正文的材料只有几种,文档里用尖括号加类型表示:
| 记号 | 类型 | 人话 | 例子 |
|---|---|---|---|
| List | 清单,里面还能再装清单 |
|
| ASCII | 字符串,n 是长度 |
|
| 无符号整数 | 数字 |
|
| 有符号整数 | 可为负的数字 | |
| 浮点 | 小数 |
|
| 字节 | 状态码 |
|
| 布尔 | 真/假 |
第一个例子:S1F2。
Host 发 S1F1,正文是空的——就问一句「在吗」,不用带参数。设备回 S1F2,标准定义的正文:
S1F2 <L[2] <A "DEMO-3000"> ← 第 1 项:MDLN,设备型号 <A "1.2.0"> ← 第 2 项:SOFTREV,软件版本 >翻译:S1F2 的正文是一个装 2 项的清单,第 1 项型号、第 2 项版本。这就是「你在吗」的返回值。
第二个例子:S1F3 查变量。
Host 发 S1F3,正文是「要查的变量编号」清单:
S1F3 W ← W 表示「我需要你回复」 <L[2] <U4 103> ← 我要查批号 <U4 108> ← 我要查 UPH >设备回 S1F4,按同样顺序给值:
S1F4 <L[2] <A "LOT20260826"> ← 103 的值 <U4 3200> ← 108 的值 >像不像查询(103, 108)返回["LOT20260826", 3200]?
参数在问单正文,返回值在答单正文,顺序一一对应。这就是全部秘密。
3.3 最难的一张单:S2F41 远程命令
Host 让设备「选配方开批」,发 S2F41(下面这份是我虚构的示例,第 5 章会完整定义):
S2F41 W <L[2] <A[8] "PPSELECT"> ← 第 1 项:命令名 <L[3] ← 第 2 项:参数清单(3 个参数) <L[2] <A[11] "ProductName"> ← 参数名 <A[13] "DEMO-PRODUCT-01"> ← 参数值 > <L[2] <A[7] "LULMODE"> <A[4] "LOAD"> ← 上料模式 > <L[2] <A[5] "LotID"> <A[12] "LOT20260826"> ← 批号 > > >结构就是「命令名 + 一堆(参数名, 参数值)对」,一层套一层。设备解析完,回 S2F42:
S2F42 <L[2] <B 0> ← HCACK:0 = 已执行 <L[0]> ← 参数错误清单(空 = 没错) >那个B 0就是这次「函数调用」的返回值,叫 HCACK,标准定义:
| HCACK | 意思 |
|---|---|
0 | 已执行 |
1 | 没这个命令 |
2 | 现在做不了 |
3 | 至少一个参数不合法 |
4 | 收下了,做完用事件通知你 |
5 | 已经是这个状态了,拒绝重复做 |
6 | 对象不存在 |
设备代码里解析这棵树,就是一层层按下标取:第 0 项当命令名,第 1 项里逐个遍历「参数名-参数值」对:
CString sRcmd = msg.m_Body.m_SecsBobyVec.at(0).m_sData.bstrVal; // "PPSELECT" // 再遍历 at(1) 里的每个 L[2],比对 ProductName / LULMODE / LotID看着繁琐,本质就是在遍历上面那棵清单树。
第 4 章:谁定义的?——标准定骨架,工厂填血肉
新人最大的困惑:这些编号、参数名、事件号,到底谁定的?
答案:一半 SEMI 定死,一半工厂自定。
SEMI 定死的(全世界一样,没得商量)
- 配对关系:S1F1 必须回 S1F2,S2F41 必须回 S2F42
- 每张单的骨架:S2F42 第一项必须是 HCACK;S6F11 必须是 DATAID + CEID + 报表清单
- 传输规则:怎么连线、怎么握手、超时怎么处理
- GEM 行为模型:Offline/Local/Remote 三态、事件要上报、报警要能开关
工厂自定的(写在规格书里,一家一份)
| 内容 | 谁定 | 例子 |
|---|---|---|
支持哪些远程命令、参数名叫什么 | 工厂 | PPSELECT 带 ProductName / LULMODE / LotID |
事件号(CEID)多少、叫什么 | 工厂 | 5001=批次开始、5002=批次结束 |
变量号(SVID)多少对应什么 | 工厂 | 103=批号、108=UPH |
报警 ID 表 | 工厂 | 1001=气压低、1002=真空不足 |
批号、产品名格式 | 工厂 | 产品名必须能对应到本地配方文件 |
所以开工第一件事:找工厂要《SECS/GEM 规格书》。 没有它,你写的每个编号都是瞎猜。
规格书长什么样?下一章我自己虚构一份完整的带你读。学会了读法,拿到任何工厂的真实规格书你都看得懂。
第 5 章:示例规格书逐页精读(本文核心)
假设我们做的是一台虚构的 「DEMO-3000 IC 测试分选机」,工厂给了我们一份规格书。一份典型规格书通常有这些页:连接参数 / SVID / ECID / CEID / RPTID / RCMD / ALARMID / 各 Stream 支持清单。
5.1 连接参数页:先把线接通
| 参数 | 示例值 | 说明 |
|---|---|---|
设备 IP / 端口 | 192.168.1.10 : 5000 | HSMS 常用 5000 |
连接模式 | Passive | 设备监听,Host 来连(大多数设备是这种) |
Device ID | 0 | 报文头里的设备号,双方必须一致 |
T3 | 45 秒 | 发出后等回复的超时 |
T5 | 10 秒 | 断线重连间隔 |
T7 | 10 秒 | Select 握手超时 |
这一页决定「能不能连上」,后面所有页决定「连上之后说什么」。
5.2 SVID 页:设备有哪些「可被查询的变量」
SVID = Status Variable ID,状态变量编号。Host 用 S1F3 凭编号来查,设备用 S1F4 回值。
我们虚构的 SVID 表:
| SVID | 名称 | 含义 / 取值 | 类型 |
|---|---|---|---|
101 | ControlState | 控制状态:0=Offline 1=Local 2=Remote | U4 |
102 | MachineState | 机台状态:1=HALT 2=RUNNING 3=PAUSE 4=HOME | U4 |
103 | LotID | 当前批号,如 LOT20260826 | ASCII |
104 | OperatorID | 操作员工号 | ASCII |
105 | CurrentPPID | 当前配方名 | ASCII |
106 | ProcessedCount | 本批已处理数量 | U4 |
107 | YieldRate | 本批良率(%) | F8 |
108 | UPH | 每小时产能 | U4 |
三个要点:
① 「103 是批号」不是标准规定的,是这张表规定的。 换一家工厂,批号可能就是 2003。你的代码照表绑定。
② 类型要和值匹配。 批号是字符串就用 ASCII,数量是整数就用 U4,良率带小数就用 F8。类型写错,对端解析直接报错。
③ 设备端的做法是「绑定内存地址」。 启动时把变量和编号绑一次:
AddSVID(&m_LotID, CStringPointer, 103, "LotID", SecsFormat::ASCII); AddSVID(&m_ProcessedCount, intPointer, 106, "ProcessedCount", SecsFormat::U4); AddSVID(&m_UPH, intPointer, 108, "UPH", SecsFormat::U4);绑完之后,Host 发 S1F3 查 103,协议层自动从那个内存地址读当前值回 S1F4——你什么都不用做,这就是「绑定」的威力:Host 看到的永远是变量的实时值。
5.3 ECID 页:设备的「配置参数」
ECID = Equipment Constant ID,设备常量。和 SVID 的区别是新人必问:
| SVID | ECID | |
|---|---|---|
是什么 | 运行中实时变化的值 | 配置项,不常变 |
例子 | 批号、UPH、已测数量 | 机型、软件版本、超时时间 |
Host 怎么读 | S1F3 查 | S2F13 查 |
Host 能改吗 | 不能,只读 | 有的能(S2F15 改),权限在表里标 |
我们虚构的 ECID 表:
| ECID | 名称 | 含义 | 权限 |
|---|---|---|---|
201 | MDLN | 设备型号 DEMO-3000 | 只读 |
202 | SOFTREV | 软件版本 1.2.0 | 只读 |
203 | MaxSpeed | 最大运行速度 | 读写 |
注意 201/202 这两个:还记得 S1F2 回的「型号 + 版本」吗?很多工厂会把它们同时登记成 ECID,Host 既能用 S1F1 探活时顺带拿到,也能用 S2F13 单独查。
5.4 CEID 页:设备会「主动上报哪些事」
CEID = Collection Event ID,事件编号。设备发生某件事,就用 S6F11 把这个号报给 Host。
我们虚构的 CEID 表:
| CEID | 事件名 | 触发时机 |
|---|---|---|
5001 | LotStart | 开批成功 |
5002 | LotEnd | 本批做完 |
5003 | ProcessStart | 设备开始运行 |
5004 | ProcessEnd | 设备停止运行 |
5005 | Pause | 暂停生效 |
5006 | Resume | 从暂停恢复 |
5007 | ControlStateOffline | 控制状态切到 Offline |
5008 | ControlStateLocal | 切到 Local |
5009 | ControlStateRemote | 切到 Remote |
5010 | HomeFinish | 归零完成 |
设备代码里对应一张一模一样的表,业务发生时调上报接口:
enum class SECS_EVENT { LotStart = 5001, LotEnd = 5002, /* ... */ }; // 开批真正成功的那个时刻: UpdateEvent((int)SECS_EVENT::LotStart, info); // 落到协议上就是发 S6F11注意「真正成功」四个字——先做成,再上报。开批函数一进来就报 LotStart,后面加载配方失败了,Host 以为开批了、设备其实没开,两边状态就再也对不上了。
5.5 RPTID 页:最难懂的一页,必须拿下
RPTID = Report ID,报表编号。这是新手最容易懵的概念,用外卖打比方:
事件(CEID)是「外卖到了」这条通知。 报表(RPTID)是通知里附带的小票——小票上写哪些内容(SVID),提前约定好。
为什么需要小票?Host 收到「批次开始」,光知道「开始了」没用,它还想顺带知道:哪个批?用的什么配方? 与其让 Host 再发 S1F3 问一遍,不如事件里直接带上。
我们虚构的 RPTID 表:
| RPTID | 打包的 SVID | 人话 |
|---|---|---|
101 | {101, 102, 105} | 控制状态 + 机台状态 + 当前配方 |
102 | {103, 105} | 批号 + 配方 |
103 | {106, 107, 108} | 已测数量 + 良率 + UPH |
RPTID 就是「一篮子 SVID」。 至于「哪个事件带哪几篮子」,由 Host 在运行时动态配置——这就是下一章的 S2F33/S2F35/S2F37,GEM 的灵魂,单独开一章讲。
5.6 RCMD 页:Host 能指挥设备干什么
RCMD = Remote Command,远程命令,全走 S2F41 → S2F42。我们虚构 4 条:
| 命令 | 作用 | 参数 |
|---|---|---|
PPSELECT | 选配方、开批 | ProductName、LotID |
START | 开始运行 | 无(或形式参数) |
STOP | 暂停 | 无 |
HOME | 归零 | 无 |
以 PPSELECT 为例,规格书会给出完整报文样例(就是第 3.3 节那棵树的「官方版本」),并写清每个参数的校验规则:ProductName 必须在本地配方列表里、LotID 不能为空……
设备端收到后的标准动作四步:解析 → 门禁检查 → 调设备原有功能 → 回 S2F42。
「门禁检查」是重头戏,以 START 为例:
- 没开批?拒绝
- 已经在跑?拒绝(HCACK=5,已是目标状态)
- 正在归零?拒绝(HCACK=2,现在做不了)
- 当前是 Offline/Local?拒绝(GEM 规定:不在 Remote 不许远程操作)
- 都通过 → 调设备原来的启动逻辑
关键设计原则:SECS 层只做翻译和门禁,不写业务。 远程 START 和面板上的启动按钮,最终调的是同一个启动函数。协议层只是一个新入口,和按钮平级。在 S2F41 的处理函数里直接搬气缸、走手臂,后面维护会哭。
5.7 ALARMID 页:报警清单
一长表,每行一个报警:ID + 文本。我们虚构几条:
| ALID | 报警文本 |
|---|---|
1001 | 气压不足 |
1002 | 真空吸附失败 |
1003 | 安全门被打开 |
2001 | 料盘卡住 |
设备报警时发 S5F1:
S5F1 W <L[3] <B 1> ← ALCD:1=发生(set),0=消除(clear) <U4 1002> ← ALID:报警编号,查 ALARMID 表 <A "真空吸附失败"> ← ALTX:报警文本 >三个要点:
① 发生报一次,消除还要报一次。 ALCD=1 是「报警了」,ALCD=0 是「好了」。Host 界面上那条报警的红字,靠 ALCD=0 才会消掉。
② Host 能关掉某条报警的上报(S5F3)。 设备要维护一张使能表,被关掉的 ID 就别再发了。
③ 上报失败本身要处理。 发 S5F1 失败,说明 Host 不知道设备出事了——这本身就该在设备本地留个记录,不然现场查问题两头都懵。
5.8 各 Stream 支持清单:你的工作量列表
规格书最后会把 SEMI 标准的单子列出来,逐张标「支持 / 不支持」。我们虚构的支持清单:
| Stream | 支持的单子 | 用途 |
|---|---|---|
S1 | S1F1/F2、S1F3/F4、S1F13/F14、S1F15/F16、S1F17/F18 | 探活、查变量、建立通信、上/下线 |
S2 | S2F31/F32、S2F33~F38、S2F41/F42 | 对时、报表三件套、远程命令 |
S5 | S5F1/F2、S5F3/F4 | 报警上报、报警开关 |
S6 | S6F11/F12 | 事件上报 |
S7 | S7F1~F6、S7F19/F20 | 配方传输、配方列表 |
S10 | S10F3/F4 | Host 在设备屏弹字 |
读法:标了「支持」的每一张单,就是你要实现(或确认协议库已实现)的工作。 拿到新规格书,先把这页扫一遍,工作量心里就有数了。
第 6 章:GEM 的灵魂——报表链(S2F33 → S2F35 → S2F37 → S6F11)
这是全文最难、也最值得学会的一节。Host 不是被动等设备报事件,而是先配置「事件怎么报」,再收事件。配置分三步:
第 1 步:S2F33 Define Report(定义报表)——Host 告诉设备:「RPTID 102 = {103, 105}」
S2F33 W <L[2] <U4 0> ← DATAID <L[1] <L[2] <U4 102> ← RPTID <L[2] <U4 103> <U4 105> > ← 包含的 SVID:批号 + 配方 > > >设备回 S2F34 确认。
第 2 步:S2F35 Link Event Report(把报表挂到事件上)——Host 告诉设备:「CEID 5001 触发时,带上 RPTID 102」
S2F35 W <L[2] <U4 0> <L[1] <L[2] <U4 5001> ← CEID:批次开始 <L[1] <U4 102> > ← 关联的 RPTID > > >设备回 S2F36 确认。
第 3 步:S2F37 Enable/Disable Event Report(打开开关)——Host 告诉设备:「5001 这个事件,允许上报」
S2F37 W <L[2] <B 1> ← 1=使能,0=禁止 <L[1] <U4 5001> > ← CEID 清单 >设备回 S2F38 确认。
配好之后,设备开批成功,发 S6F11——正文自动带上小票:
S6F11 W <L[3] <U4 0> ← DATAID <U4 5001> ← CEID:批次开始 <L[1] <L[2] <U4 102> ← RPTID 102 <L[2] <A "LOT20260826"> ← 103 批号的当前值 <A "DEMO-PRODUCT-01"> ← 105 配方的当前值 > > > >Host 回 S6F12:「知道了」。
这条链一次记住:S2F33 定义小票 → S2F35 把小票挂在事件上 → S2F37 打开开关 → S6F11 事件带着小票飞过去。 设备端只要 SVID 绑定做得好,小票里的值全是自动填的。
第 7 章:一次完整开批,报文时间线
把前面所有知识串成一条线。Host 要让 DEMO-3000 做一批上料:
1. 网线插上,TCP 连通 2. HSMS Select 握手 ← 快递通道建立(这还不是 SECS) 3. S1F13 → S1F14 ← 「建立通信吧」「同意」 4. S1F1 → S1F2 ← 「在吗」「在,DEMO-3000,版本 1.2.0」 5. S2F33 → S2F34 ← Host 定义报表(小票内容) 6. S2F35 → S2F36 ← Host 把报表挂到事件上 7. S2F37 → S2F38 ← Host 使能事件 8. S1F17 → S1F18 ← Host 要求上线,设备同意 9. 设备切 Remote ← 设备主动报 S6F11(CEID=5009) 10. S2F41(PPSELECT) → S2F42(0) ← Host 远程开批,设备回「已执行」 11. 设备报 S6F11(CEID=5001) ← 「批次开始」,小票带批号和配方 12. 归零完成,报 S6F11(5010) 13. S2F41(START) → S2F42(0) ← Host 启动 14. 设备报 S6F11(5003) ← ProcessStart 15. 跑着跑着真空报警 → S5F1(ALCD=1, ALID=1002) 处理完报警消除 → S5F1(ALCD=0, ALID=1002) 16. Host 随时 S1F3 查 {103, 108} → 设备 S1F4 回批号和 UPH 17. 本批做完,设备报 S6F11(5002) ← LotEnd注意第 9 步:状态变化也是事件,设备要主动报,不是等 Host 问。 这就是 GEM 和「一问一答」最大的区别——设备是个会主动说话的下属。
第 8 章:代码里怎么用(最短路径)
好消息:TCP、HSMS 握手、拆包组包、超时重发、S1F1/S1F13 这种标准单的自动应答,协议库都帮你干了。你要写的只有三件事:
① 启动时绑定变量和事件(照规格书 SVID/CEID 页抄):
AddSVID(&m_LotID, CStringPointer, 103, "LotID", SecsFormat::ASCII); AddSVID(&m_UPH, intPointer, 108, "UPH", SecsFormat::U4); AddCEID(5001, "批次开始事件"); AddCEID(5002, "批次结束事件");② 实现远程命令的业务函数(照 RCMD 页):
byte RCMD_PPSELECT(product, lotID) { // 1. 门禁:已开批?在跑?Offline?→ 返回对应 HCACK 拒绝 // 2. 调设备原有功能:加载配方、写批号、切模式 // 3. 成功后 → 上报 LotStart 事件 // 4. 返回 HCACK = 0 }③ 在业务节点上报事件和报警(照 CEID/ALARMID 页):
UpdateEvent((int)SECS_EVENT::LotStart, info); // 事件 → S6F11 SendAlarm(alarmID, text, /*set=*/true); // 报警 → S5F1两个工程细节,都是血泪:
- 上报失败本身要报警。
UpdateEvent返回 false,说明 Host 没收到,必须让现场知道,不然批就乱了。 - 不要在界面线程里等 Host 回复。 主动向 Host 要数据(比如 S14 查物料信息)可能卡几秒,放工作线程里等。
第 9 章:联调方法与新手必踩的坑
怎么测
- 先用模拟器。 装一个 SECS 模拟 Host 的工具在自己电脑上,IP 指本机,先把 S1F1、开批、事件整条链路跑通,再去现场。
- 逐条对规格书。 每实现一张单,用模拟器发一遍,核对正文结构。
- 留通信日志。 每条收发报文落盘带时间戳。现场出事先翻日志对报文,不要猜。
- 做断线测试。 拔网线、杀 Host 进程,看设备会不会乱:该拒的命令要拒,重连后状态要对得上。
九个坑(checklist)
- 把 S1F2 当函数名满工程找。 它是报文编号,代码里的
S1F2类只是拼这张回单的。 - 以为编号全世界通用。 S1F1 通用;但 CEID 5001、SVID 103 是这份规格书定的,换厂先换表。
- 只发不收。 你发 S6F11,Host 要回 S6F12。回复超时(T3)就是失败,要记日志、要报警。
- 网通了就以为对接好了。 Ping 通 ≠ Select 成功 ≠ S1F13 建立 ≠ Remote。四层,一层层查。
- 正文少包一层 List。 联调第一大错。对着规格书的
<L[2] ...>一层层数。 - 在协议层写业务。 S2F41 处理函数里直接走手臂,维护时会哭。协议层只翻译、只门禁、只调旧接口。
- 内部错误码直接回给 Host。 内部用 10、11 区分原因没问题,S2F42 的 HCACK 必须落在标准 0~6。
- 忘了 Offline/Local/Remote。 不在 Remote,远程命令必须拒。现场「Host 发了没反应」,一半是这个原因。
- 事件提前报。 先做成,再上报。顺序反了,两边状态永远对不上。
收尾:一页纸记住全部
- SECS = SEMI 定的设备聊天语言;HSMS = 走网线;GEM = 聊天礼仪。E5 管说什么,E37 管怎么寄,E30 管什么场合说。
- S1F2 = S1 科室(设备状态)的第 2 号单,是 S1F1「你在吗」的回单。奇数问,偶数答。
- 参数在问单正文(Body)里,返回值在答单正文里;正文是
L/A/U4/B嵌套的清单树,按 JSON 理解。 - 谁定的:单子骨架 SEMI 定死;命令参数、SVID、CEID、RPTID、报警 ID,工厂规格书定,一家一份。
- 规格书核心表:SVID(能查什么)、ECID(能配什么)、CEID(会报什么)、RPTID(事件带什么小票)、RCMD(能指挥什么)、ALARMID(报警清单)。
- GEM 灵魂链:S2F33 定义报表 → S2F35 挂到事件 → S2F37 使能 → S6F11 带小票上报。
- 你的代码只做三件事:绑定变量、实现 RCMD、在业务点打事件报警。
协议只是翻译官,设备本身的流程才是本体。把规格书放手边,照着填,你也能接。