
简介这份资源是面向半导体设备自动化领域开发者的 SECS/GEM 协议源码包适合从事 EAP 系统开发、设备通信对接的工程师及希望深入理解 SEMI 标准的进阶学习者。它解决了协议实现细节不透明、缺少可运行参考代码的问题可用于搭建设备与主机之间的通信框架、研究状态机与消息编解码逻辑。压缩包共 97 个文件约 158KB以 46 个 Python 源码文件为核心覆盖 GEM、SECS、HSMS 等模块及配套测试用例另有 38 个 rst 文档用于说明安装、参考与快速上手辅以 yml、sh、Makefile 等构建与配置脚本整体结构清晰、便于按模块研读。目前已有 791 人学习下载。读者可从中获得完整的协议分层实现、连接状态模型、数据项与事件处理示例以及可复用的测试脚本为二次开发与问题排查提供直接参考。1. 从 secsgem-master.zip 说起半导体 EAP 为什么绕不开 SECS/GEM一条 12 寸产线上几十台设备来自不同年代、不同厂商上位机却要统一拿到它们的运行状态、配方、报警和良率数据。设备侧只认 SECS/GEM 这套 SEMI 标准协议而 MES、EAP 侧往往是 Java、C# 或 Python 写的业务系统。中间这层协议转换就是 EAPEquipment Automation Program存在的理由。secsgem-master.zip这类源码包本质是把 SECS/GEM 的报文编解码、状态机、超时重传、事件上报封装成可调用的库让工程师不用从 HSMS 字节流开始手搓。它解决的是「设备说 SEMI 方言、业务系统说 HTTP/JSON」的翻译问题适合做设备自动化、EAP 开发、产线数据采集的工程师也适合想搞懂 SECS 到底是单向还是双向的协议初学者。2. SECS/GEM 协议栈拆解与 secsgem 源码结构2.1 SECS-I、HSMS 与 SECS-II 的分层关系SECS/GEM 不是单一协议而是三层叠起来的。最底下是传输层早期用 SECS-I基于 RS-232 串口带块传输和握手现在主流是 HSMSHigh-Speed SECS Message Services跑在 TCP/IP 上默认端口 5000。中间是 SECS-II定义消息的语义结构每条消息用 Stream 和 Function 编号标识比如 S1F1 是「Are You There」、S1F2 是它的回复、S6F11 是事件报告。最上面是 GEM规定设备必须实现哪些 Stream/Function、状态模型怎么走、报警和事件怎么管理。理解这个分层才能看懂secsgem-master.zip里的目录。常见做法是hsms或secs目录放传输层和消息编解码gem目录放 GEM 状态机和高层接口clients/servers放主动连接和被动监听两种角色。SECS 是双向的——设备可以主动发 S6F11 上报事件主机也可以主动发 S2F41 下发远程命令谁先发取决于角色和场景不存在「只能主机问、设备答」的单向限制。2.2 从源码目录定位核心模块拿到源码包先别急着跑先看结构。以 Python 实现的 secsgem 为例典型布局如下secsgem-master/ ├── secsgem/ │ ├── secs/ │ │ ├── hsms.py # HSMS 连接、状态机、超时 │ │ ├── secs2.py # SECS-II 数据类型编解码 │ │ └── functions.py # Stream/Function 基类 │ ├── gem/ │ │ ├── gem.py # GEM 设备/主机行为 │ │ ├── handler.py # 事件、报警、数据变量回调 │ │ └── stream_function.py │ └── common/ │ └── settings.py # 连接参数、超时、设备 ID ├── samples/ # 官方示例先跑这个 └── tests/ # 单元测试看协议边界samples/目录是最有价值的入口它通常包含一个最小可运行的设备端和主机端。先读 sample 再读核心库比直接啃hsms.py效率高得多。2.3 消息编解码SECS-II 数据类型怎么落到代码SECS-II 的数据项有明确类型LList、AASCII、BBinary、Boolean、U1/U2/U4/U8无符号整数、I1/I2/I4/I8有符号整数、F4/F8浮点。源码里通常有一个SecsVar基类和一堆子类负责把 Python 对象和字节流互转。from secsgem.secs.secs2 import Secs2 from secsgem.secs.variables import U4, A, L, Boolean # 构造一个 S1F2 的回复体设备 ID 在线状态 body L( A(EQP001), # 设备 IDASCII 类型 Boolean(True), # 是否在线 U4(12345) # 累计处理晶圆数 ) encoded body.encode() print(encoded.hex()) # 输出 SECS-II 字节流L是列表容器可以嵌套A存字符串U4是 4 字节无符号整数。编码后的字节流再交给 HSMS 层加上 10 字节消息头含 Session ID、Stream、Function、Block 号等才成为完整报文。参数上要注意整数类型选错会导致设备解析失败比如设备期望 U2 你发了 U4长度对不上直接报错。3. 用 secsgem 跑通第一个 HSMS 连接3.1 环境准备与依赖安装先确认 Python 版本secsgem 一般要求 3.7 以上。用虚拟环境隔离依赖python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txt # 源码包自带 # 或者直接装 pip install secsgem如果源码包里有setup.py用pip install -e .以可编辑模式安装方便改代码调试。装完先跑pytest tests/确认环境没问题测试全绿再动手写业务。3.2 设备端Equipment最小实现设备端通常作为 HSMS 的被动方监听端口等主机连进来。下面是一个最小设备端from secsgem.gem import GemEquipmentHandler from secsgem.secs.functions import SecsS01F01, SecsS01F02 from secsgem.secs.variables import A, L, Boolean class MyEquipment(GemEquipmentHandler): def __init__(self, settings): super().__init__(settings) # 注册 S1F1 的处理主机问 Are You There self.register(SecsS01F01, self.on_s1f1) def on_s1f1(self, handler, message): # 回复 S1F2带上设备 ID 和在线状态 return L(A(EQP001), Boolean(True)) settings { address: 0.0.0.0, port: 5000, session_id: 0, device_id: EQP001, is_equipment: True, } equipment MyEquipment(settings) equipment.enable() equipment.serve_forever()register把 Stream/Function 和处理函数绑定收到对应消息就回调。session_id在 HSMS 里用于区分连接设备端和主机端必须一致。is_equipmentTrue决定角色行为比如谁主动发 Select 请求。3.3 主机端Host连接与 S1F1 握手主机端作为主动方连到设备 IP 和端口from secsgem.gem import GemHostHandler from secsgem.secs.functions import SecsS01F01 settings { address: 192.168.1.100, # 设备 IP port: 5000, session_id: 0, device_id: HOST01, is_equipment: False, } host GemHostHandler(settings) host.enable() # 主动发 S1F1 探测设备是否在线 response host.send_and_waitfor_response(SecsS01F01()) print(response) # 应收到 S1F2含设备 ID 和在线状态send_and_waitfor_response是同步调用内部会等超时。如果设备没响应先查网络连通性telnet 设备IP 5000再查session_id是否匹配最后看设备端日志有没有收到 Select 请求。3.4 关键连接参数与超时设置参数含义常见值调错后果session_idHSMS 会话标识0 或设备编号不匹配直接拒绝连接portHSMS 监听端口5000改错连不上T3回复超时45 秒太短误判断线T5连接分离超时10 秒影响重连速度T6控制消息超时5 秒影响 Select 握手T7未选择超时10 秒连接建立后未 Select 会断T8网络字符间超时5 秒影响大报文传输这些 T 值在 SEMI 标准里有推荐范围但不同设备厂商会改。调试时先把 T3 调大比如 60 秒确认通信正常后再收紧。T7 特别容易踩坑连接建立后必须在 T7 内发 Select 请求否则设备主动断开。4. GEM 状态机、事件上报与远程命令实战4.1 设备状态模型与 S1F3/S1F4 状态查询GEM 定义了一套设备状态模型主机通过 S1F3Selected Equipment Status Request查询状态变量设备用 S1F4 回复。状态变量包括控制状态Online/Offline、处理状态Idle/Running/Down等。from secsgem.secs.variables import U4, A, L # 设备端注册 S1F3 处理 def on_s1f3(self, handler, message): # message 里带主机想查的 SVID 列表 svids message.get() # 比如 [1001, 1002] values [] for svid in svids: if svid 1001: values.append(A(Online)) elif svid 1002: values.append(U4(42)) # 当前批次晶圆数 return L(*values)SVIDStatus Variable ID是设备侧定义的编号主机必须知道每个编号对应什么。实际项目里会有一份 SVID 对照表通常由设备厂商提供。查错时先确认 SVID 编号对不对再看数据类型是否匹配。4.2 事件上报 S6F11 与报告定义设备主动上报是 SECS 双向性的典型体现。设备通过 S6F11Event Report Send把事件推给主机事件里可以带一组报告Report报告里是数据变量DV。# 设备端触发一个事件 def report_event(self): # CEID2001 表示「批次开始」 # RPTID3001 关联一组 DV self.trigger_event( ceid2001, reports{ 3001: [A(LOT123), U4(25), A(RecipeA)] } )主机端要提前用 S2F33Define Report和 S2F35Link Event Report定义好 CEID、RPTID、VID 的对应关系否则收到 S6F11 也不知道数据含义。这是新手最容易漏的一步光注册事件回调不够报告定义必须先协商好。4.3 远程命令 S2F41 与 S2F49 的落地主机下发远程命令用 S2F41Host Command Send设备执行后回 S2F42。命令带参数比如「开始加工」带配方名。from secsgem.secs.functions import SecsS02F41 from secsgem.secs.variables import L, A # 主机端下发命令 command SecsS02F41( L( A(START), # 命令名 L(L(A(RECIPE), A(RecipeA))) # 参数列表 ) ) response host.send_and_waitfor_response(command) # response 里 HCACK0 表示命令被接受HCACKHost Command Acknowledge是关键返回码0 表示接受1 表示命令不存在2 表示参数不对3 表示当前状态不能执行。设备端实现时要根据实际状态返回正确的 HCACK否则主机会误判。4.4 报警管理 S5F1 与确认流程设备报警用 S5F1Alarm Report Send上报主机用 S5F2 确认。报警分两类个人报警Personal Alarm和系统报警System AlarmALCD 字节里的 bit 7 表示报警是「发生」还是「清除」。# 设备端上报报警 def report_alarm(self, alarm_id, is_set): alcd 0x80 if is_set else 0x00 # bit71 表示报警发生 self.send_alarm(alcd, alarm_id, 温度超限)主机收到 S5F1 后必须回 S5F2否则设备可能重发。报警清除也要发一次 S5F1ALCD 的 bit7 置 0。很多现场问题出在报警只报不清导致主机侧报警列表一直挂着。5. 联调排错与性能调优的实用技巧5.1 用日志和抓包定位 HSMS 通信问题secsgem 一般支持日志级别配置把logging调到 DEBUG 能看到每条报文的十六进制和解析结果。如果日志不够用tcpdump抓包sudo tcpdump -i eth0 -w secs.pcap port 5000抓完用 Wireshark 打开过滤tcp.port 5000。HSMS 报文头是 10 字节前 4 字节是长度接着是 Session ID2 字节、Header Byte 2/3含 Stream/Function 和 W/B 位、PType、SType、System Bytes。看 System Bytes 是否匹配请求和回复能快速判断是设备没回还是回了但解析错。5.2 常见错误码与超时排查顺序遇到通信失败按这个顺序查网络层ping设备 IPtelnet 设备IP 5000看端口通不通。HSMS 层看有没有 Select 请求和 Select 响应T7 超时通常是没发 Select。SECS-II 层看 Stream/Function 是否注册未注册的消息会被忽略或回 S9F5。GEM 层看报告定义、SVID、CEID 是否和主机侧一致。业务层看 HCACK、ACKC5、ACKC6 等返回码。S9 系列是错误消息S9F1 是不认识的消息S9F3 是不认识的 StreamS9F5 是不认识的 FunctionS9F7 是非法数据。设备收到无法处理的消息时应该回 S9而不是静默丢弃。5.3 高频消息下的连接稳定性调优产线设备每秒可能发几十条 S6F11如果每条都同步等回复吞吐上不去。常见做法是事件上报用异步发送不等回复只有命令类消息才同步等 ACK。secsgem 里通常有send和send_and_waitfor_response两个方法事件用前者。另外把 T3 适当调大避免高负载下误判断线T8 调大能容忍大报文传输慢。但 T 值不能无限大否则真断线时恢复太慢。一般 T3 设 45 到 60 秒T8 设 5 到 10 秒具体看设备手册。提示不同厂商对 T 值的默认设置差异很大联调前先拿到设备的 SECS/GEM 手册按手册设不要照搬示例。5.4 用 pytest 写协议回归测试协议改动后容易引入回归建议用 pytest 写针对 Stream/Function 的单元测试from secsgem.secs.variables import L, A, U4 def test_s1f2_encode(): body L(A(EQP001), U4(100)) encoded body.encode() decoded L.decode(encoded) assert decoded[0].get() EQP001 assert decoded[1].get() 100编解码对称性测试能挡住大部分数据类型错误。再往上可以 mock 一个 HSMS 连接测消息收发流程。测试覆盖 S1F1/S1F2、S1F3/S1F4、S6F11、S2F41/S2F42 这几组核心消息基本能覆盖 80% 的联调场景。本文还有配套的精品资源点击获取