
简介这份PDF面向半导体设备自动化工程师、上位机/主机系统开发者及SECS/GEM初学者围绕设备与主机之间的标准化数据通信问题提供金南瓜科技SECS-GEM规格说明书。文档从通信状态模型、控制状态模型与设备处理状态入手继而展开主机发起场景、事件通知、在线识别、动态事件报告配置、变量/跟踪/状态数据采集、报警管理、远程控制、设备常数、过程程序管理、时钟与终端服务等能力项并补充TCP/IP通讯超时及已实现事件、变量、状态变量、报警、设备常量的落地说明便于读者理解GEM适配范围与实施边界。资源包共1个PDF文件大小约1006KB近1MB单文件结构适合按目录检索与对照查阅。目前已有746人学习下载可作为设备端GEM功能梳理、主机联调前的规范核对与方案评估参考。1. 从一台清洗设备接入主机说起这套接口方案要解决什么半导体自动化产线上设备联网往往不是插根网线那么简单。某设备厂要给一台清洗设备做主机接口甲方主机是海外 MES团队此前一直用自定义 socket 加 JSON每换一家主机就要重写一遍解析层联调周期从两周拖到两个月最后连“设备现在到底在不在线”都要靠人跑去车间看灯。改成按 SECS/GEM 实现之后一次开发三家主机复用主机侧只改了配置。这套方案要解决的就是设备与主机之间用统一的消息语义、统一的状态机、统一的数据字典对话让自动化产线上的设备不再各说各话。它适合正在做设备联网毕设、半导体产线课设的人也适合要交付一份《主机通信手册》的从业者拿到这份规格说明书的完整结构基本能照着把接口一层层搭起来。2. 总体架构设计四层协议栈与五个模块的职责划分SECS/GEM 不是单一协议而是一组标准的组合。规格说明书里列出的参考标准有四份E5 定义 SECS-II 的消息内容也就是 S1F13 这类“流功能”的消息长什么样E30 定义 GEM 的行为模型也就是设备在什么状态下该做什么事E37 定义 HSMS 高速消息服务负责把消息可靠地送到对端E37.1 定义 HSMS 的单会话模式 HSMS-SS。四者关系是“E5 管说什么E30 管什么时候说E37 管怎么说出去”。很多初次接触的人会把它们混成一件事结果代码写完发现消息格式对了但行为不对——主机发来 S1F17 请求上线设备回了 S1F18 说成功可实际上设备还停在 OFF-LINE后续命令全被 SxF0 拒掉。这类问题的根子在于把协议栈当成了一个整体没有分层。2.1 协议栈分层与 HSMS-SS 的选型理由把四份标准映射到软件模块上层次是清楚的标准作用在方案中的落点SEMI E5SECS-II 消息内容与数据项编码编解码层负责 SxFy 与 SML 互转SEMI E30GEM 行为模型与能力集合状态层与数据字典层决定“该不该回”SEMI E37HSMS 消息服务传输层负责分帧、超时、重连SEMI E37.1HSMS-SS 单会话模式传输层固定一个会话 ID 与端口选 HSMS-SS 而不是 HSMS-GS理由很实际一台设备在同一时刻只服务一个主机连接多会话带来的会话管理、会话选择、会话隔离全是额外复杂度而产线上根本用不到。单会话模式下设备侧固定监听一个端口工程上默认 5000主机主动发起 TCP 连接或者设备主动去连主机二选一选定之后在配置里写死不要两边同时发起——这一点后面避坑章节会细说。超时参数是 HSMS 落地时最容易拍脑袋填的部分。规格说明书里明确列了“TCP/IP 通讯超时”实际实现时通常按下面这组值起步再根据产线网络状况微调参数含义典型值调小的后果调大的后果T3等待回复的超时45 s网络抖动就误判断链真断链时长时间卡住T5连接分离后的重连间隔10 s频繁重连冲击主机恢复慢T6控制事务超时5 s控制消息处理不完控制消息堆积T7未选中状态的超时10 s单会话场景影响小同上T8网络字符间超时5 s大包传输被切断半开连接占资源T3 是最关键的一个。它决定了设备发出一条主消息之后等多长时间没收到回复就判定失败。45 秒不是随便定的它要覆盖主机侧最慢的一次数据库写入如果主机侧做配方下发落盘T3 给 10 秒必然翻车。传输层的核心工作是分帧。HSMS 的消息头固定 10 字节后面跟消息体消息体前 4 字节是长度。写一个不依赖第三方库的解析函数比引一堆依赖更容易排查问题import struct HSMS_HEADER_LEN 10 def parse_hsms_frame(raw: bytes) - dict: 解析一帧 HSMS 消息返回头部字段与消息体 if len(raw) HSMS_HEADER_LEN 4: raise ValueError(frame too short, need at least 14 bytes) # 10 字节头会话ID(2) 头字节2(1) 头字节3(1) PType(1) SType(1) SystemBytes(4) session_id, hb2, hb3, ptype, stype, sysbytes struct.unpack(HBBBBI, raw[:10]) body_len struct.unpack(I, raw[10:14])[0] if len(raw) 14 body_len: return {complete: False, need: 14 body_len - len(raw)} return { complete: True, session_id: session_id, # 0xFFFF 表示控制消息非数据消息 stream: hb2, # 仅数据消息有效例如 0x01 表示 S1 function: hb3, # 仅数据消息有效例如 0x0D 表示 F13 p_type: ptype, # 0 表示 SECS-II 编码 s_type: stype, # 0数据 1Select 2Deselect 9Linktest system_bytes: sysbytes, # 事务号回复时必须原样带回 body: raw[14:14 body_len], }这段代码里system_bytes是重点。SECS-II 的请求与回复靠它配对主机发来 S1F13 带事务号 0x0000001A设备回的 S1F14 必须带回同一个值否则主机会认为这是一条无关消息直接丢弃表现为“设备明明回了主机说没收到”。s_type为 9 是链路测试消息不参与业务直接回一条同事务号的即可不要往业务分发器里塞。2.2 状态机与业务逻辑的边界划分分层之后模块职责要切干净否则后面改一处崩三处。我一般会按下面五块拆传输层只管字节收发、分帧、超时、断线重连不认识任何业务字段。编解码层把字节转成 SML 结构把 SML 结构转回字节处理数据类型与长度。状态层通讯状态机和控制状态机决定当前能不能发、要不要回 Sx,F0。数据字典层VID、CEID、ALID、ECID、RPTID 的定义与取值来源。业务适配层跟设备 PLC 或本地服务打交道把采集到的值填进字典。这里有一条血泪经验状态层绝对不能认识“温度”这种业务概念业务层也绝对不应该出现 SxFy 这种协议概念。中间靠数据字典做翻译——业务层说“反应腔温度变了”字典查表得到 CEID1201、VID1005状态层再把这俩送进消息。边界一旦糊掉换一台设备就要改状态机那分层就白做了。数据字典的编号规划要一开始就定死中途改 ID 等于把主机侧配置全部推翻。常见的做法是按区间划状态变量 SVID 用 1 到 99过程数据 VID 用 100 到 999集合事件 CEID 用 1000 起报警 ALID 用 1 到 999设备常数 ECID 用 1 到 99。留出空档别用连号占满后期加变量才有地方插。3. 状态模型落地通讯状态机与控制状态机的代码骨架规格说明书里两套状态图都用了 Harel 记法看起来复杂拆开其实只有两条主线一条管“通不通”一条管“听不听话”。前者是通讯状态模型后者是控制状态模型。这两套状态机如果实现得不严谨表现出来就是玄学问题——重启一次好了再跑两小时又断了。3.1 通讯状态模型四个状态与两个并列子状态通讯状态模型顶层只有两个状态DISABLED 和 ENABLED。DISABLED 下所有 SECS-II 通信立即停止操作员从 ENABLED 切到 DISABLED 时不会有任何缓冲正在排队的消息直接作废。ENABLED 下有两个子状态NOT COMMUNICATING 和 COMMUNICATING。NOT COMMUNICATING 是重点它下挂两个并列AND子状态HOST-INITIATED CONNECT 和 EQUIPMENT-INITIATED CONNECT两者同时有效。也就是说设备在等主机来连的同时自己也在尝试去连主机。EQUIPMENT-INITIATED CONNECT 下又分 WAIT CRA 和 WAIT DELAY进入时先置 CommDelay 定时器为“已过期”直接发 S1F13如果连接事务失败进入 WAIT DELAY启动 CommDelay 定时器把待发消息全部出队必要时进 spool 缓冲等定时器到期再回 WAIT CRA 重发 S1F13。状态转移表里有两条容易漏掉WAIT DELAY 期间收到非 S1F13 的消息要丢弃且不回复然后置定时器过期、发 S1F13WAIT CRA 期间收到 S1F14 且 COMMACK0才进 COMMUNICATING。COMMACK 非 0 表示对端拒绝要继续等。用代码表达状态就是一个枚举加一张转移表别写成嵌套 iffrom enum import Enum class CommState(Enum): DISABLED DISABLED NOT_COMMUNICATING NOT_COMMUNICATING WAIT_CRA WAIT_CRA # 设备已发 S1F13等 S1F14 WAIT_DELAY WAIT_DELAY # 失败后退避等 CommDelay 到期 WAIT_CR_FROM_HOST WAIT_CR_FROM_HOST # 等主机发 S1F13 COMMUNICATING COMMUNICATING # CommDelay 来自 ECID 定义单位秒EstablishCommunicationsTimeout 同理 COMM_DELAY_SEC 10 ESTABLISH_TIMEOUT_SEC 45 def on_enter_not_communicating(ctx): # 任一进入 NOT COMMUNICATING设备侧主动连接先置定时器过期并立即发 S1F13 ctx.comm_delay_expired True send_s1f13(ctx) ctx.state CommState.WAIT_CRA ctx.t3_deadline ctx.now() ESTABLISH_TIMEOUT_SEC def on_message(ctx, stream, function, commackNone): if ctx.state CommState.WAIT_CRA: if (stream, function) (1, 14) and commack 0: ctx.state CommState.COMMUNICATING return established # 收到非预期消息丢弃、不回复、置定时器过期、重发 S1F13 ctx.comm_delay_expired True send_s1f13(ctx) return ignored_and_resent if ctx.state CommState.WAIT_DELAY: if ctx.now() ctx.comm_delay_deadline: ctx.state CommState.WAIT_CRA send_s1f13(ctx) return backoff if ctx.state CommState.WAIT_CR_FROM_HOST: if (stream, function) (1, 13): send_s1f14(ctx, commack0) ctx.state CommState.COMMUNICATING return host_established return noop参数说明COMM_DELAY_SEC对应规格里 CommDelay 定时器的时长ESTABLISH_TIMEOUT_SEC对应 ECID 中的“建立通讯超时”。这两个值要能从配置文件读别写死在代码里现场调试时经常需要临时放大。send_s1f13里要把设备型号、软件版本这类 MDLN/SOFTREV 字段带上主机侧会用它们做设备识别字段缺失会导致主机侧永远认为设备未注册。还有一条不管从哪个状态掉线进入 NOT COMMUNICATING 时都要把发送队列清空需要保留的消息转进 spool 缓冲并按产生顺序排列。不做这一步重连之后主机会收到一堆过期事件时序全乱。3.2 控制状态模型OFF-LINE 下为什么必须回 Sx,F0控制状态模型定义的是主机和设备之间的协作级别。最核心的一条规则写得很直白OFF-LINE 状态下设备对主机发来的任何主消息都回 Sx,F0只有 S1F13 和 S1F17 例外——这两条照常处理并回复。S1F17 是主机请求设备切到 ON-LINE 的消息。Sx,F0 的意思是“这条消息我收到了但我现在不处理”。它跟“不回”是两回事不回会让主机侧一直等到 T3 超时然后判定设备异常回 Sx,F0 主机立刻知道设备在线但处于离线态可以走正常的上线流程。这个区别在很多实现里被忽略最后表现为主机侧日志里一堆 T3 timeout排查半天以为是网络问题。控制状态通常按 OFF-LINE、ON-LINE/LOCAL、ON-LINE/REMOTE 三态实现。LOCAL 表示设备本地操作面板有控制权REMOTE 表示主机有控制权。远程命令S2F41只在 REMOTE 下执行LOCAL 下要回带错误码的 S2F42不能默默吞掉。def dispatch_primary(ctx, stream, function, body): # 通讯未建立时除 S1F13 外一律不处理 if ctx.comm_state ! CommState.COMMUNICATING: return None # 控制离线时仅放行 S1F13 与 S1F17 if ctx.ctrl_state OFFLINE and (stream, function) not in [(1, 13), (1, 17)]: return build_reply(stream, 0, body) # SxF0不带数据体 if (stream, function) (1, 17): ctx.ctrl_state ONLINE_REMOTE return build_reply(1, 18, {ONLACK: 0}) # 0 表示接受上线 return route_to_gem_layer(ctx, stream, function, body)ONLACK的取值要按标准来0 接受1 设备已有其他主机在线2 设备处于不允许上线的状态。返回 2 而不是直接拒绝主机侧才能区分“设备忙”和“设备坏了”。3.3 设备处理状态与状态变量的映射设备处理状态描述的是设备在加工流程里处于哪一步规格里通常分 IDLE、EXECUTING 等。这一层不参与通讯但必须通过状态变量暴露给主机否则主机不知道设备到底在干嘛。我一般会把处理状态映射成一个 SVID取值用整数枚举同时在状态切换时主动触发一个 CEID 事件。两边都做是有原因的主机可以轮询 SVID 拿当前值也可以订阅事件拿变化通知不同主机的实现偏好不一样全给比只给一种省事。映射表要在文档里写清楚别只写在代码注释里。举个典型的处理状态SVID 值触发事件 CEID说明IDLE11100空闲等待配方SETUP21101换型、参数下发中EXECUTING31102正在加工PAUSED41103暂停需人工介入ERROR51104故障配合报警上报状态值改动时一定要判重值没变就不发事件。否则设备在 IDLE 下反复刷同一个事件主机侧数据库一天写几十万条无效记录运维会来找你。4. 设备能力实现事件报告、变量采集与远程控制GEM 的能力清单在规格说明书里是一张勾选表状态模型、事件通知、在线识别、动态事件报告配置、变量数据采集、跟踪数据采集、状态数据采集、报警管理、远程控制、设备常数、过程程序管理、时钟、终端服务这些项全部勾了“是”材料搬送和 Spooling 勾了“否”。这张表就是实现的边界勾了的必须做全没勾的可以不做但主机侧如果按全能力来配缺项会导致配置失败。4.1 动态事件报告配置S2F33、S2F35、S2F37 三步走事件报告是 GEM 里最核心也最容易做错的部分。主机要用三个动作配合先用 S2F33 定义报告里装哪些变量再用 S2F35 把报告挂到事件上最后用 S2F37 使能或禁用事件。三步顺序错了主机侧就会出现“报告定义了但收不到数据”。S2F33 的报文结构是“报告 ID 变量 ID 列表”。用 SML 写出来长这样S2F33 W L[2] L[0] # 空列表表示删除全部已有报告定义 L[1] L[2] U4 RPTID 1001 # 报告 ID L[3] U4 VID 1005 # 变量反应腔温度 U4 VID 1006 # 变量反应腔压力 U4 VID 1010 # 变量射频功率 这里有个细节第一项L[0]是“删除已有定义”的列表第二项才是“新增或修改”。主机重新配置时通常先发一次带删除列表的 S2F33 清场再发一次纯新增的。如果设备侧把删除和新增当成一次原子操作遇到清场报文里没有新增项就报错主机侧配置流程会直接卡死。正确做法是允许空新增。S2F35 负责绑定S2F35 W L[2] L[0] # 先解绑全部 L[1] L[2] U4 CEID 1102 # 事件开始加工 L[1] U4 RPTID 1001 # 该事件触发时上报报告 1001 S2F37 才是开关S2F37 W L[2] BOOLEAN 1 # TRUE 表示使能 L[1] U4 CEID 1102 # 只使能这一个事件空列表表示全部 响应 S2F38 只要回ACKC50表示接受非 0 表示拒绝并附原因码。别在这里偷懒统一回 0主机侧靠 ACKC5 判断配置是否生效全回 0 会让排障失去唯一线索。4.2 变量数据采集DVVAL、SV、EC 三种取值的区别变量采集在规格里分成三类数据变量DVVAL、状态变量SV、设备常数EC。三者语义不同混用会让主机侧采集周期失控。数据变量是实时值随工艺变化采集频率高状态变量是设备的离散状态变化时才需要采集设备常数是配置参数通常只在启动和人工修改时读取。工程上一般把数据变量的上报方式做成“事件触发 主机订阅”状态变量做成“轮询 S1F3 变化事件双通道”设备常数只走 S2F13、S2F15、S2F29 三个消息。跟踪数据采集Trace Data Collection走的是另一条路主机用 S2F23 下采样指令指定采样周期、总次数、变量列表设备按周期自动上报 S6F1。这个功能在工艺分析里很常用实现时要注意两点采样周期不能小于采集线程的实际能力否则队列会堆积总次数到 0 表示无限采样必须在设备侧留一个上限保护不然主机忘记停止日志文件会把磁盘写满。状态数据采集走 S1F3 请求和 S1F4 回复一次可带多个 SVID。回复时数据项的个数必须与请求严格对应顺序也要一致多一个少一个主机侧都会解析错位表现出来就是“温度看着像压力”。4.3 报警管理与设备常数报警管理的最小闭环是三条S5F3 使能/禁用报警、S5F1 上报报警、S5F5 查询报警列表。S5F1 里带的 ALCD 字节同时表达“发生/解除”和报警等级最高位为 1 表示报警发生为 0 表示解除。很多实现只发发生不发解除主机侧报警面板上红灯永远亮着操作员直接把报警面板关了。ALID 要和报警代码严格对应一个 ALID 只能对应一种报警。中途复用 ALID 会导致历史记录被覆盖追溯时查不出到底是哪次故障。设备常数走 S2F15 设置、S2F13 请求、S2F29 请求名称列表。设置时必须校验范围温度上限设成 9999 度设备不会报错等真跑起来就是事故。校验失败回 S2F16 带 EAC 非 0别直接回 0 然后内部忽略。4.4 远程控制与过程程序管理远程控制的核心是 S2F41带一个 RCMD 命令名和一组参数。响应 S2F42 里要带 HCACK 和每个参数的 CPACKHCACK0 表示命令已执行非 0 表示命令存在但参数非法或条件不满足。常见的错误是只回一个总体的 HCACK参数的 CPACK 全填 0主机侧就无法知道是哪个参数越界。过程程序管理涉及 S7 系列目录请求、上传、下载、删除。上传下载用 S7F3/S7F5 传程序体S7F1/S7F2 做授权与长度协商。程序体通常是文本或二进制传输前要做长度对齐设备侧要算好剩余空间再回 S7F2 的 GRANT空间不够就回 0 拒绝硬接下来写到一半断电会留下半个配方文件。时钟方面S2F17 请求时间、S2F18 回时间、S2F31 设置时间。时间格式固定别用本地时区主机侧和设备的时区不一致时事件时间戳会整体偏移排查起来非常费劲。终端服务 S10F3 用于给设备屏幕推消息实现时注意屏幕显示宽度超出部分要截断并记录日志。5. 避坑与排查SECS/GEM 联调里最容易翻车的五个点联调阶段的问题往往不在代码逻辑本身而在双方对标准的理解偏差。下面五条是踩得最多的。第一条两边同时发 S1F13链路建立后立刻互踢。现象是链路刚建立几秒就断反反复复。原因在于设备侧同时开了“设备主动连接”和“等待主机连接”两个并列子状态主机侧也在主动发 S1F13两边各发各的事务号对不上互相判定为非法消息。解决方式是配置层面明确谁是发起方主机主动连的产线设备侧就只保留 WAIT CR FROM HOST不去发 S1F13设备主动连的场景反过来。别指望运行期自动协商标准里没有这个机制。第二条S2F33 清场之后主机侧报告还在。现象是主机重新配置后收到重复数据。原因是设备侧处理 S2F33 时删除列表处理了但没有同步清掉 S2F35 的绑定关系旧报告还挂在事件上。正确顺序是收到 S2F33 后先解除全部绑定再重建或者至少在删除报告时把引用它的绑定一并失效。这一步在规格里没写得特别显眼很容易漏。第三条T3 超时后回复才到设备把它当成新消息。现象是偶发“消息重复执行”配方被下发两次。原因在于超时重发机制没有做事务号去重设备发了请求T3 到期判定失败重发主机处理慢第一条的回复这才到设备把它当作对第二条请求的回复于是第二条的回复永远等不到又重发一次。解决方式是维护一个近期事务号表收到回复先查表已超时的事务号直接丢弃并记日志不要重复消费。第四条报警只发生不解除。现象是主机报警面板红灯常亮。原因是设备侧把报警上报做成了“状态变化才发”但解除时状态没变或者 ALCD 最高位没清零。排查方法是抓 S5F1 报文逐字节看 ALCD别只看报警文本。我一般会在报警模块里加一条硬规则任何 ALID 的状态翻转都必须产生一条 S5F1不允许合并。第五条有符号数和字节序解释错温度变成天文数字。现象是主机侧显示 4.2e9 度。原因是设备把有符号整数按无符号发出去或者 SML 里的类型声明写成了 U4 而实际是 I4。SECS-II 的类型标记很严格I1/I2/I4/I8 和 U1/U2/U4/U8 是分开的编码时类型标错数值就完全变了。排查时用 SML 日志把原始报文打出来对着数据项字典逐个核对类型比猜快得多。6. 验收与答辩怎么证明这套接口真的通了接口做完不等于交付完成验收要能拿出证据。答辩或交付评审时最能说服人的不是架构图而是一份带时间戳的报文日志加一张逐项打勾的验收表。我一般按下面这张表逐项过每过一项就截一段真实报文附在后面验收项验收方法通过标准通讯建立断开网线再恢复观察重连15 秒内自动恢复 COMMUNICATING在线识别主机发 S1F1收到 S1F2MDLN 与 SOFTREV 非空控制状态设备置 OFF-LINE 后发 S1F3立即收到 S1F0不超时事件报告主机配 S2F33/S2F35/S2F37 后触发事件收到 S6F11变量个数与顺序正确变量采集连续采样 100 次无超时、无乱序、数值与本地显示一致报警管理手动触发与解除各一次收到两条 S5F1ALCD 最高位分别为 1 和 0远程控制发 S2F41 下发一条合法与一条越界命令合法回 HCACK0越界回非 0 且 CPACK 定位到具体参数过程程序上传后下载同一配方内容逐字节一致时钟同步设置时间后回读偏差在 1 秒内联调顺序也有讲究别一上来就配事件报告。正确顺序是先通链路S1F13/S1F14再验在线识别S1F1/S1F2然后过控制状态S1F17接着配数据字典S1F11 或 S1F21 拿名称列表核对之后才是事件报告三步走最后做远程控制和过程程序。反过来的话前面没通就配报告报错只会告诉你 ACKC5 非 0根本定位不到哪一层出问题。答辩现场有个技巧特别管用准备一份“故障注入”演示。当着评委的面把网线拔掉十秒后插回去展示设备在 NOT COMMUNICATING 状态下进入 WAIT DELAY、定时器到期、重发 S1F13、收到 S1F14 进 COMMUNICATING 的完整报文序列。这段演示比讲十分钟状态机有说服力因为它证明的不只是“能跑”而是“知道坏了之后怎么自己站起来”。从那以后我每次做这类接口交付都强制走一遍“断开—恢复—再断开”的流程并且要求报文日志必须落盘、必须带毫秒时间戳。日志是唯一的后悔药联调现场谁都说自己发了只有日志能说清到底是谁没发。希望这套结构能帮到你把手里那份规格说明书真正变成一套跑得起来的实现。本文还有配套的精品资源点击获取