
搞设备自动化这些年我最深的感受是SECS/GEM 这套东西本身不难难的是刚接触时根本不知道该从哪个点切入。很多人一上来就啃几百页的 SEMI 标准文档结果被 E5、E30、E37、E39 这些编号绕晕最后还是不知道一条事件从设备里出来到底经历了什么。所以我打算用一个系列把这套东西讲清楚第一篇先讲最核心的——事件Event。事件是 EAPEquipment Automation Program和设备之间最频繁、最关键的信息载体百分之八九十的业务联动都是靠它驱动的。这篇内容会覆盖从协议分层、消息类型、配置下发、设备触发、报文解析到 EAP 落地的完整过程同时把我在现场踩过的坑和排查思路一并写出来。适合刚开始做 SECS/GEM 集成的工程师也适合被设备不告警问题折磨过的运维同学。1. 从一次设备不告警的故障说起——事件机制为什么是设备自动化的地基1.1 一次真实的事件静默事故复盘先讲一个我遇到的现场问题。某厂区的刻蚀设备在跑完一批晶圆之后EAP 侧迟迟没有收到 Process Complete 事件整个批次卡在 WAIT 状态MES 上显示设备还在忙实际上设备已经空转了十几分钟。产线被迫停线排查。当时第一反应是检查网络。TCP 连接是通的HSMS 心跳正常能正常收发 S1F13/S1F14报警通道也是好的。设备端看日志工艺确实跑完了但 S6F11 报文根本没发出来。最后定位到根因设备重启后主机下发的 Link Event Report 配置丢了。也就是说事件本身没有被禁用但 CEIDCollection Event ID和 Report 之间的绑定关系被设备清掉了设备就算检测到工艺结束这个条件也不知道该往哪个报告里塞数据更不知道该不该发出去。这个问题的根源就是我对事件机制的几个关键角色——事件、报告、数据项——之间的协作关系理解得不够透彻。这也是为什么我要把事件单独拿出来讲。1.2 事件、状态和报警三兄弟的分工在 SECS/GEM 体系里描述设备行为的有三套机制很多初学者容易搞混我先把它说清楚。状态Status表示设备当前是什么。比如当前温度是多少、设备处于哪个状态Running、Idle、Down。典型消息是 S1F21读取状态变量和 S1F22返回状态变量值。状态是拉模式主机主动去问设备才回答。报警Alarm表示设备出事了。比如冷却水压低、腔体门未关。典型消息是 S5F1报警上报和 S5F2报警确认。报警是持续性的异常信号通常有设立和清除两个动作。事件Event表示设备发生了什么。比如工艺开始、工艺结束、载具到位。典型消息是 S6F11事件上报和 S6F12事件确认。事件是推模式设备主动告诉主机不需要主机轮询。用一个生活化的类比事件像微信消息提示手机响一声告诉你有人找状态像朋友圈你主动去刷才能看到最新内容报警像火灾报警器一直响到你处理完为止。做 EAP 集成时事件用得最多因为它天然适合驱动业务流程。但要注意事件是一次性的通知不携带设备的当前全貌。如果你需要确认设备当前状态还是得用 S1F21 去拉。这也是很多新手搞错的地方——只靠事件流去还原设备状态容易丢信息。1.3 为什么事件机制是 EAP 的第一道关卡EAP 的核心职责是把设备的自动化动作翻译成业务系统能理解的流程节点。设备什么时候开始跑、什么时候跑完、什么时候要送料、什么时候报错都需要事件来通知。如果事件链路不通EAP 就成了聋子。设备本身可能运行正常但 MES 看不到任何进展整个生产调度就会停摆。所以事件机制不光是协议层面的一个功能点它是设备自动化集成的第一道关卡这道关卡过不去后面的一切都无从谈起。2. 事件在SECS/GEM协议栈中的真实位置消息、报告与数据项的协作关系2.1 从SECS-I到GEM300先理清四层关系要理解事件先得理清 SECS/GEM 这套协议栈的层次关系否则你会看到一堆缩写不知道谁是谁。层级标准作用类比物理传输层SECS-I / HSMS定义数据怎么传。SECS-I 走 RS-232 串口HSMS 走 TCP/IP 网络快递公司的运输车队消息层SECS-IISEMI E5定义消息的格式和语义比如 S6F11 代表事件上报快递单的格式规范应用层GEMSEMI E30定义设备必须具备哪些能力、状态模型、事件/报警/远程命令的标准行为快递业务的完整流程产线扩展GEM300E39/E40/E84/E87等面向 300mm 大晶圆产线的设备自动化扩展强调 Process Job、载具跟踪等针对大客户定制的增值服务事件本身属于消息层和应用层之间的事情消息层提供 S6 流的报文格式应用层规定事件怎么定义、怎么绑定报告、什么时候触发。2.2 事件背后真正在跑的消息不只是S6F11很多教程一上来就告诉你事件就是 S6F11这话对了一半。S6F11 只是事件真正出发的那一下在它之前还有一串配置消息必须走通。我把这件事涉及的完整消息列出来消息方向作用S2F33 / S2F34主机→设备 / 设备→主机定义报告Define Report把一组数据项打包成一个报告S2F35 / S2F36主机→设备 / 设备→主机把事件和报告绑定起来Link Event ReportS2F37 / S2F38主机→设备 / 设备→主机启用/禁用事件报告Enable/Disable Event ReportS2F41 / S2F42主机→设备 / 设备→主机主机命令常被用来批量下发事件配置S6F11 / S6F12设备→主机 / 主机→设备事件上报与确认S6F11 是真正的事件内容注意我加粗了 S2F41/S2F42。实际项目里很多设备厂商不完全按标准的 S2F33/S2F35/S2F37 三连来配置事件而是提供一个自定义的主机命令让主机一次性把哪些事件需要上报、上报哪些数据项全部下发。这个时候你的 EAP 就得按设备厂商的私有协议来适配。所以做集成时第一件事永远是找设备厂商要 SECS 通信规范文档而不是拿标准文档生搬硬套。2.3 事件、CEID、Report、Data Item的四层模型理解了消息之后再看事件体系的四个核心概念我习惯用快递单来做类比CEIDCollection Event ID事件本身的编号。比如 501 代表工艺完成502 代表工艺开始。相当于快递单号告诉你发生的是什么事。RPTIDReport ID报告编号。一个报告就是一组数据的集合相当于一个包裹。一个事件下面可以挂多个报告。Data Item数据项具体的数据变量可以是状态变量SVID、设备常量ECID、或者系统变量比如时间戳。相当于包裹里的货物明细。绑定关系Link把 CEID 和 RPTID 关联起来告诉设备当发生这个事件时把哪些数据打包上报。这里有个关键点一个 CEID 可以绑定多个 RPTID但实际项目中主机和设备往往会约定一个事件只绑定一个报告减少配置复杂度和报文长度。如果你看到一份 SECS 规范里某个 CEID 下面写了三个 RPTID那通常意味着事件携带的数据类别差异很大比如一个报告放工艺参数另一个放设备状态需要分别处理。2.4 一个完整的Report配置实例为了让你有直观感受我放一个典型的配置示意。这里用 JSON 来表示实际 SECS-II 报文里是一层层嵌套的列表结构后面讲报文编码时再展开。{ reports: { RPT101: { ceid: 501, data_items: [ {vid: SVID_100, name: 腔体温度}, {vid: SVID_101, name: 腔室号}, {vid: SVID_102, name: 设备时间戳}, {vid: ECID_200, name: 配方ID} ] } } }这段配置的意思是当 CEID 501工艺完成发生时设备要把腔体温度、腔室号、设备时间戳、配方ID 这四个数据项打包成 RPT101然后通过 S6F11 发给主机。这个例子看起来简单但我在实际项目中见过太多问题出在这一步数据项的类型定义错了温度本来是无符号整数结果读出来变成负数时间格式不统一有的设备用 Unix 秒有的用字符串解析逻辑都得分别写。所以配置报告时一定要核对设备规范里每个 VID 的数据类型和单位。3. 一条事件从设备到EAP的完整旅程订阅、触发、编码、上报3.1 上电后的第一件事EAP把事件订阅清单发给设备事件不是设备想报就报的必须先由主机侧把订阅清单下发到设备上。典型的 GEM 初始化流程是这样建立连接。主机和设备通过 S1F13/S1F14 握手确认通信建立。获取设备信息。用 S1F1/S1F2 或者 S1F3/S1F4 查询设备 ID、软件版本、状态变量列表等。定义报告。主机用 S2F33 把 RPTID 和数据项列表发送给设备设备用 S2F34 回复确认。链接事件。主机用 S2F35 把 CEID 和 RPTID 关联起来设备用 S2F36 回复确认。启用事件报告。主机用 S2F37 启用指定的 CEID设备用 S2F38 回复确认。流程看起来不复杂但这里有一个细节你必须在联调时确认设备上电后是否保留之前的配置。有的设备断电重来后会清空所有事件配置如果 EAP 只在下发过一次后就不再重复下发那么设备重启后事件就会静默丢失。我见过不止一次就是因为 EAP 侧没有做定期刷新事件配置的逻辑导致夜班设备重启之后整个批次没有事件上报。所以我在 EAP 设计里通常会加一个事件配置健康检查每次设备通信恢复后主动读取设备当前的事件配置状态和主机侧期望的配置比对不一致就重新下发。3.2 设备侧发生了什么状态变化触发事件从设备内部视角看事件触发实际上是状态机的迁移。打个比方设备的工艺模块有一个状态机Idle → Ready → Running → Complete → Idle。当状态从 Running 跳到 Complete 时设备固件会检查当前状态迁移对应的事件是否已被启用如果启用就把绑定好的报告数据收集起来组成一个 S6F11 报文。这里有个值得注意的地方事件触发时采集的数据是瞬时的。比如工艺结束事件采集的是工艺结束那一刻的温度而不是工艺过程中的平均值。如果设备厂商在实现上报逻辑时对不同数据项的采样时刻处理不好你收到的温度可能根本不是事件发生那一刻的温度。我之前遇到过一种情况事件报文里的时间戳是报文生成时间而不是工艺结束时间导致 MES 侧做批次追溯时时间线对不上。3.3 报文在线上长什么样SECS-II格式拆解SECS-II 报文的基本结构是 Header Body。Header 里包含 Stream、Function、Session ID、Block 信息等。对于 S6F11 来说Stream6Function11。Body 是一个层级嵌套的列表结构用 SECS-II 值类型标记如 L 代表列表U4 代表无符号 4 字节整数等来编码。我用一个简化的报文示意来说明S6F11 事件上报简化结构 Header: Stream6, Function11, SessionID1 Body: L U4 501 -- CEID工艺完成 L L U4 101 -- RPTIDRPT101 U4 850 -- 温度值 25.5℃的原始值缩放表示 U2 3 -- 腔室号 U8 1530086400 -- 设备时间戳 A RECIPE_A -- 配方ID 这里我在报文里写了 U4 850而不是 25.5是因为 SECS-II 本身不直接支持浮点数温度值通常会被放大固定倍数后用整数传输。具体放大多少倍完全看设备厂商的实现。联调的时候你很容易发现一个温度明明该是 25.5设备上报却是 255 或者 850这时候就要去找规范里的 scaling factor 定义。3.4 收到S6F11之后EAP的确认与异常处理EAP 收到 S6F11 之后不是直接入库完事必须先回一个 S6F12 确认。S6F12 是设备衡量事件是否被主机正确接收的凭据。如果主机不确认设备会按自己的重试策略重新发送同一事件甚至可能导致设备事件缓冲队列溢出后续事件丢失。S6F12 的 Ack 值有几个约定0接受事件已收到1拒绝数据不完整或格式错误2拒绝事件未启用实测中最容易忽略的是EAP 必须先做基础校验再决定回 0 还是回非 0。如果你在业务逻辑还没处理完时就先回了 0然后业务处理又抛异常这时候你没有任何办法让设备重发那条事件只能自己吞了这个损失。所以我的习惯是先校验报文完整性通过后立刻回 Ack 0再把事件放进处理队列做后续处理。后续处理失败不等于报文接收失败设备没有义务为此负责。4. 事件数据的落地姿势EAP解析、状态更新与流程联动4.1 EAP内部的事件处理管线事件真正进入 EAP 之后处理流程通常可以拆成五个环节接收从 TCP 连接读取原始字节流按其传输层协议HSMS的格式还原出完整的消息。解析按 SECS-II 格式解码提取 Stream/Function、CEID、RPTID 和具体数据项。校验判断事件是否合法、是否重复、数据项是否齐全。标准化把设备私有的报文结构转换成统一的内部事件格式。分发持久化根据事件 ID把事件交给不同的业务处理器同时落库。这五个环节中最容易写坏的是标准化和分发。因为不同设备厂商上报的同一类事件数据项的排列顺序、类型、单位都可能不一样。如果你在业务代码里直接写死第三个数据项是温度换一款设备就要改代码。正确的做法是在标准化层做一个设备型号→内部模型的映射表让业务代码只关心统一格式。4.2 从事件ID到业务动作的映射EAP 的价值不在于把事件报文解析出来而在于把事件翻译成业务动作。我拿一个实际场景举例CEID事件含义EAP 业务动作501工艺完成通知 MES 批次结束释放载具502工艺开始记录开始时间更新设备状态为 Running601载具到达触发自动读取载具 ID校验批次配方610腔体温度稳定允许下发工艺启动命令701清洗完成更新设备可用状态触发下一批任务这种映射表一定要做成配置化的不要硬编码在代码里。原因很简单工厂产线调整、设备升级、新机种导入时事件 ID 的含义完全可能变化。配置化之后改一张表就能适应变化不用发版。4.3 事件处理中的稳定性和性能设计事件机制用久了你会遇到几个典型的稳定性问题这里提前给你打预防针。第一个是事件积压。设备侧的事件缓冲是有限的如果 EAP 处理太慢确认不及时设备就可能把更早的事件冲掉。所以 EAP 至少要保证接收线程只负责收包和回 Ack业务处理放队列后台消费不要让业务流程阻塞网络接收。第二个是重复事件。HSMS 链路抖动导致 TCP 重传或者设备固件 bug 导致同一条事件发了两次EAP 必须有去重机制。最简单的去重键是设备 ID CEID 事件发生时间戳但前提是设备时间戳足够可信。如果不可信可以退一步用设备 ID CEID 顺序号。第三个是乱序。如果 EAP 内部开了多个线程并发消费事件两个关联事件比如开始和完成可能会被不同线程处理导致入库顺序错乱。解决思路是按设备或按批次对相关事件做分区同一个设备/批次的事件交给同一个消费者线程。这些设计我在实际项目里都踩过不只是理论上的讨论。如果你在做的就是 EAP 平台开发我建议一开始就把事件消费模型定好比如用单消费线程加内存队列配合批量落库性能在大多数场景下都足够。5. 事件机制在GEM300环境下的进阶约束与协同5.1 GEM300到底是什么E30细化到产线级GEM300 不是一套独立的协议它是对 GEM 在 300mm 大晶圆产线场景下的补充和细化。如果说 GEM 解决的是设备和主机能不能通信、基本业务怎么走的问题GEM300 解决的就是在大规模自动化产线上设备如何与载具、Process Job、物料跟踪系统协同的问题。在 GEM300 环境里事件扮演的角色更重。因为产线自动化程度高设备不能只停在跑完一批上报完成这个粒度它要上报更细的环节节点载具到达、载具对接、晶圆开始加工、晶圆加工完成、载具卸载等。每一个节点都是一条甚至一组事件。5.2 事件与Process Job、Material Tracking的联动GEM300 里EAP 对设备下发的核心概念从批次变成了 Process Job。Process Job 是设备执行一次加工任务的逻辑单元包含配方、载具信息、晶圆数量等内容。Process Job 的每个阶段推进都靠事件驱动。举个实际例子EAP 收到载具到达事件读取载具 ID确认批次信息。EAP 下载配方并创建 Process Job下发启动命令。设备开始加工上报 Process Start 事件事件携带 Process Job ID。EAP 将 Process Job 状态更新为 Running。设备加工完成上报 Process Complete 事件同样携带 Process Job ID。EAP 将 Process Job 状态更新为 Complete通知 MES 批次结束触发下游搬运。这里的关键是每一个事件都必须携带足够的上下文 ID。如果 Process Complete 事件里没有 Process Job IDEAP 就无法把事件关联到具体的批次整个联动就断了。所以在配置事件报告时Process Job ID 和对应的 Material ID 这些数据项一定要加进去哪怕你暂时用不到也建议先带着省得后面追溯时抓瞎。5.3 事件数据一致性与追溯GEM300 产线对数据一致性要求很高因为最终产品的追溯链条完全建立在事件日志上。设备在每个工序节点上报的事件需要记录当时的工艺参数、操作人、配方版本、时间戳等。我的建议是无论业务系统是否需要EAP 都应该把事件原始报文完整落库。原始报文平时看起来占空间但一旦需要排查问题、做产线追溯、应对客户审计它就是最可靠的证据。不要只落库解析后的字段因为如果你解析逻辑写错了事后想回溯原始数据却没有只能干瞪眼。我见过不止一个项目查一个批次的数据异常时因为只保存了解析结果但原始报文被丢弃最后只能返厂找设备日志。6. 事件开发中最常踩的坑与排查思路6.1 事件没上报从链路到配置的四步排查法遇到事件没收到我建议按下面这个顺序排查不要一上来就怀疑代码步骤排查点验证手段1HSMS 链路是否正常看心跳是否正常尝试 S1F13/S1F14 握手2事件是否真被触发检查设备端操作日志设备是否确实发生了对应状态变化3事件配置是否生效用 S2F37 的查询命令或工具读取设备当前启用的 CEID 列表4主机是否收到但被丢弃抓包确认 S6F11 是否到达检查 EAP 日志是否有解析异常这四步里最容易卡住人的是第 3 步。很多设备厂商提供的 SECS 调试工具不够友好查事件启用状态得发原始消息。这时候你就得学会手动构造 S2F37 这样的查询消息。这也是为什么我建议 EAP 侧一定要做一个事件配置查询的功能能在关键时刻快速定位到底是没配置还是没上报。6.2 事件乱序与重复多线程消费的坑事件乱序和重复是 EAP 上线初期最容易暴露的问题。有一次我们做压力测试EAP 同时开着四个消费线程处理事件结果同一批次的 Process Start 事件比 Process Complete 事件晚到入库后设备状态直接从 Running 跳回 Idle 又跳成 CompleteMES 界面上的状态完全错乱。后来我们改成按设备 ID 对事件做分区消费同一台设备的事件永远走同一个线程乱序问题就基本消失了。重复事件则在标准化阶段做去重去重键用设备 ID CEID 事件时间戳如果设备时间戳不可靠就用报文序列号。6.3 事件风暴设备批量上报把EAP打死另一种常见故障是事件风暴。设备端因为某些原因积压了大量事件恢复后一次性把成百上千条事件发过来。如果 EAP 没有限流机制接收线程会瞬间被打满数据库写入超时甚至整个服务假死。我的经验是EAP 侧要设计两级缓冲网络接收线程和业务处理线程之间的队列长度要做上限超过上限时启动背压策略比如暂时延后确认或者丢弃非关键事件。同时针对设备侧可以在配置事件时和厂商确认是否有事件合并机制。有些设备支持把短暂时间内同类事件合并成一条能显著降低事件流量。6.4 时间戳与时区处理事件日志时最容易忽略的坑最后说一个最不起眼但坑人无数的问题时间。设备侧的时间不一定和主机侧同步有的设备用的是 UTC有的用本地时间有的甚至不配置时间就一直停在出厂值。EAP 在落库时如果直接用设备时间戳作为事件发生时间事后追溯很容易对不上。我的做法是事件表里同时存两个时间——设备时间戳原样保留和 EAP 接收时间主机本地时间。业务上默认以设备时间为准但必须在字段层面区分开并且统一转成同一个时区存放。如果设备经常出现时间跳变就要考虑在 EAP 里做设备时间的周期性对时任务或者至少在事件日志中标记设备时间异常。事件机制这部分讲到这里基本把一条事件的一生串完了。从协议分层到报文编码从订阅配置到数据落地再到现场排障的思路都是这几年做设备自动化集成攒下来的经验。我自己最后习惯做的事是在 EAP 里给每台设备维护一个最近事件到达统计图事件量突然掉零往往比设备报警更早暴露问题。做这行的都知道设备不说话的时候往往才是大麻烦开始的时候。下一篇准备写 GEM 状态模型和远程命令事件和状态机配合起来才是完整的设备行为闭环。如果你在事件排查上还有其他奇怪的案例欢迎交流。