ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

半导体设备自动化:SECS/GEM协议开发入门与实践指南

半导体设备自动化:SECS/GEM协议开发入门与实践指南 1. 项目概述为什么SECS/GEM是半导体与显示面板厂的“普通话”如果你在半导体、LED或显示面板行业做设备自动化或软件集成那么“SECS/GEM”这个词对你来说可能既熟悉又陌生。熟悉是因为它频繁出现在设备规格书、客户稽核清单和集成会议里陌生则是因为它的资料往往零散、晦涩网上能找到的要么是几百页的英文标准文档要么是某个商业软件的宣传页真正能指导你从零开始动手开发的“硬核”内容少之又少。这个系列我就想和你聊聊怎么从一名软件工程师的角度把SECS/GEM这套协议给“啃”下来并真正做出能用的东西。你可以把它理解为一套在高端制造业里设备与上层生产管理系统MES/EAP之间必须使用的“普通话”。没有它价值几千万的设备就是个“哑巴”无法自动上报生产数据、接收配方、反馈报警整个工厂的智能化也就无从谈起。我接触这套协议快十年了从最初看文档看得一头雾水到后来独立开发通讯驱动、模拟器甚至参与制定客户的GEM合规标准踩过的坑不计其数。网上很多资料要么过于理论要么直接跳到某个商业库的使用缺少了中间最关键的一环一个开发者如何从协议标准文本一步步构建出自己的理解体系和代码实现。这个系列我就打算填补这个空白。第一篇我们不写代码只做“准备工作”。这个准备不是装个软件那么简单而是要搭建起正确的认知框架和工具环境这能让你在后续的开发中事半功倍避免在错误的方向上浪费大量时间。2. 核心概念解析SEMI、SECS-I、HSMS、SECS-II与GEM正式开始前我们必须把几个核心概念和它们之间的关系彻底理清。很多新手容易在这里混淆导致后续学习混乱。2.1 协议家族与层级关系SECS/GEM不是一个单一的协议而是一个由国际半导体设备与材料协会SEMI制定的一系列标准的集合。它们像网络协议栈一样分层工作物理与链路层SECS-I 这是最古老的标准SEMI E4定义了通过RS-232串口进行通讯的电气特性、数据帧格式10字节头正文、以及简单的超时重传机制。你可以把它想象成通过串口发送一封封有固定信封格式的信。由于其速率低早期9600bps、可靠性一般在新设备中已基本被淘汰但在一些老旧设备升级改造时仍可能遇到。通讯层HSMS 这是当前绝对的主流SEMI E37。全称是“High-Speed SECS Message Services”。它基于TCP/IP解决了SECS-I的速度和可靠性问题。HSMS定义了如何通过TCP/IP Socket建立连接、管理会话Select/Select-Reply、以及传输SECS-II消息的通用包装格式。我们后续开发几乎全部基于HSMS。你可以把它理解为为SECS-II消息定制的、运行在TCP/IP之上的一个简单应用层协议。消息层SECS-II 这是协议的核心“语言”部分SEMI E5。它定义了所有通讯内容的语法和词汇。SECS-II消息由“Stream”和“Function”编号唯一标识如S1F13表示Stream 1 Function 13并规定了消息的详细数据结构。这个数据结构非常灵活和强大是学习中的重点和难点。行为与状态模型层GEM 这是协议的“语义”和“场景”部分SEMI E30。GEMGeneric Equipment Model定义了设备应该具备哪些标准能力如通信状态管理、报警管理、数据收集、远程控制等以及在各种生产场景下设备与主机之间应该如何通过特定的SECS-II消息序列进行对话。GEM是SECS-II在具体业务上的实现指南。符合GEM意味着你的设备能用标准的“普通话”完成所有标准化的生产交互。它们的关系可以简单概括为HSMSTCP/IP负责可靠地“运送”SECS-II“语言包”而GEM则规定了在“工厂”这个场景下应该用这些“语言包”进行哪些标准对话。2.2 关键术语速查Host主机 通常指工厂的上层管理系统如MES制造执行系统或EAP设备自动化程序。它是通讯的发起方和控制方。Equipment设备 指生产线上的机台如光刻机、蚀刻机、贴片机等。它是通讯的响应方和执行方。Primary/Secondary 消息发送方为Primary接收方为Secondary。一次交互中谁先发消息谁就是Primary。注意Host和Equipment都可以是Primary。SxFy SECS-II消息的标准写法。S代表Stream流F代表Function功能。如S1F1是“Are You There?”询问S6F11是“发送事件报告”。Item数据项 SECS-II消息中数据的基本单元有类型如ASCII, Binary, I4, F8等和值。List列表 一种特殊的数据项其值是由多个数据项或子列表组成的序列。它是构建复杂消息结构的基础。Transaction事务 一次完整的消息交互。通常以Primary发送消息开始以收到对应的Reply消息结束。有些事务包含多轮对话。3. 开发环境与工具准备工欲善其事必先利其器理论清楚了我们就要搭建一个可以动手实验的环境。纯粹的阅读标准文档是无法真正学会SECS/GEM的必须通过实际的报文收发和分析来加深理解。3.1 核心工具SECS/GEM 模拟器对于开发者而言一个可靠的模拟器是必不可少的。它允许你在没有真实物理设备或主机系统的情况下模拟对方的行为进行协议测试和调试。1. SECS Simulator (如“SECS Simulator”)这是一个在业界广泛使用的商业软件模拟器功能非常强大。它既可以模拟Equipment端也可以模拟Host端。Equipment模拟你可以配置虚拟设备定义它能响应的SxFy并配置回复消息的内容。这对于测试你自己开发的Host端程序极其有用。Host模拟你可以主动向连接的真实设备或你自己开发的Equipment端程序发送各种SxFy命令并观察回复。报文分析它能以非常清晰的结构化方式展示收发的原始字节流、解析后的SECS-II消息树是学习报文格式的绝佳工具。获取方式通常需要从软件供应商处购买许可证。对于个人学习者可以留意其官网是否提供功能受限的试用版。请注意务必从官方或可信渠道获取软件避免安全风险。2. 开源替代方案调研如果商业模拟器不可及可以考虑一些开源项目但需要做好心理准备它们的完善度和易用性通常不如商业软件。libSECS、PySECS等这些是用于开发SECS/GEM应用程序的开源库本身不一定是带图形界面的模拟器。你可以基于它们快速构建自己的简易测试工具。自定义开发简易模拟器这也是本系列后续的目标之一。通过自己实现一个最简单的HSMS TCP Server/Client和基础的SECS-II消息解析你能最深刻地理解协议细节。实操心得在项目初期我强烈建议至少获得一个可用的模拟器即使是试用版。它能极大加速你的学习进程。把模拟器当作你的“协议实验室”所有看不懂的标准描述都尝试在模拟器里构造一条消息看看效果。3.2 辅助工具集网络调试工具Wireshark 这是终极的“照妖镜”。因为HSMS基于TCP/IP你可以用Wireshark抓取所有的网络包。通过过滤HSMS端口通常是5000你可以看到最原始的TCP数据流验证你的程序发送的字节序列是否正确或者分析第三方设备/软件的通讯行为。学会看Wireshark抓包是排查复杂通讯问题的杀手锏。TCP/UDP调试工具如NetAssist SocketTool 轻量级的工具用于快速测试端口连通性手动发送十六进制数据等。在初步验证你的HSMS连接逻辑时非常方便。文本/十六进制编辑器如VS Code with Hex Editor插件 用于查看和编辑原始的报文文件。有时你需要对比分析不同工具生成的报文差异。编程语言与IDE 选择你熟悉的语言。C#、Java、Python、C都是常见的选择。我个人更倾向于C#或Python因为它们在快速原型开发、字符串和字节数组处理上非常高效。IDE选择VS、VS Code、PyCharm等均可。3.3 文档资料准备SEMI标准文档核心必读E4 (SECS-I) 了解即可作为历史背景。E37 (HSMS)精读重点。必须理解HSMS-SS作为服务器和HSMS-CS作为客户端的角色、状态机、消息头结构10字节、以及Select/Deselect等会话管理流程。E5 (SECS-II)核心精读。这是最厚的文档。你不需要一次性记住所有SxFy。重点是理解第1-4章消息结构、数据项类型Item Format、列表List、以及消息交换协议。后续用到具体SxFy时再查阅第5章及以后。E30 (GEM)场景化精读。在理解了SECS-II的基础上阅读GEM。它告诉你一个合规的设备需要实现哪些“能力”如状态模型、报警、数据收集、配方管理等以及每个能力对应哪些SxFy的交互序列。先通读第1-5章了解框架后续按需深入。非官方指南与社区 可以搜索一些技术博客、论坛如Stack Overflow 但相关讨论较少或开源项目的README。这些资料通常以更易懂的方式解释了某些复杂概念。但务必以SEMI官方文档为最终依据。4. 思维模式建立从“字节流”到“业务对话”在动手写代码前建立正确的思维模式比掌握任何工具都重要。SECS/GEM开发要求你在不同抽象层次间切换思考。4.1 分层思考法当你在调试一个“设备不上报报警”的问题时你的排查思路应该是分层的物理/网络层网线插好了吗IP地址、端口对吗防火墙是否阻止了连接用ping和telnet测试。HSMS会话层TCP连接建立了吗HSMS的Select/Deselect流程成功了吗用Wireshark抓包看HSMS消息头前10字节的Session ID、Stream/Function是否为0xFFFF表示会话控制消息。SECS-II消息层主机发送的请求消息如S5F1报警请求格式正确吗设备回复的S5F2格式对吗数据项的类型和值是否符合E5标准用模拟器或报文分析工具查看解析树。GEM业务层设备配置的报警代码和严重性等级是否在主机定义的允许范围内报警上报的启用状态CEID链接是否已建立这需要对照E30文档和双方的业务配置。4.2 消息流可视化在纸上或白板上画出消息序列图Sequence Diagram这是理解复杂交互的利器。例如描述设备初始化后建立通信状态的过程Host (Primary) Equipment (Secondary) |----------S1F1 (Are You There?)---------| |---------S1F2 (ACK)---------------------| |----------S1F13 (Establish Comm)--------| |---------S1F14 (Comm Established)-------| |----------S2F13 (Equipment Constants Request)-| |---------S2F14 (Equipment Constants Data)-----|画出这样的图能让你清晰地看到每一次事务的发起方、消息类型和顺序对于设计和调试至关重要。4.3 状态机思维GEM核心定义了一个“设备通信状态模型”通常包括COMMUNICATINGNOT COMMUNICATINGEQUIPMENT OFF-LINE等。你的设备代码内部必须维护这个状态机。主机通过S1F13/F14、S1F15/F16等消息来驱动状态切换。你必须清楚在每种状态下设备能响应哪些消息拒绝哪些消息。实现时一个清晰的enum和switch-case或状态模式是很好的选择。5. 首个实践目标实现一个最小的HSMS Echo Server一切准备就绪我们来设定第一个小目标不涉及复杂的SECS-II只聚焦HSMS层实现一个能接受TCP连接、完成HSMS Select握手、并能将收到的任何HSMS消息原样发回的Echo Server。这个目标看似简单但涵盖了HSMS开发的所有基础环节网络编程 创建TCP监听Socket。HSMS协议解析 解析10字节的消息头获取消息长度。会话管理 处理Select/Select-Reply/Deselect流程。消息转发 实现业务逻辑这里就是Echo。5.1 步骤拆解与核心代码逻辑我们以Python为例因其代码简洁易懂。实际生产环境可能会用C#或Java。步骤1建立TCP服务器import socket import struct import threading class SimpleHsmsServer: def __init__(self, host0.0.0.0, port5000): self.server_socket socket.socket(socket.AF_INET, socket.SOCK_STREAM) self.server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) self.server_socket.bind((host, port)) self.server_socket.listen(5) print(f[*] HSMS Echo Server listening on {host}:{port}) def start(self): while True: client_socket, client_addr self.server_socket.accept() print(f[] Accepted connection from {client_addr}) # 为每个客户端创建一个新线程处理 client_thread threading.Thread(targetself.handle_client, args(client_socket,)) client_thread.start()步骤2定义HSMS消息头结构HSMS消息头是固定的10字节格式如下大端序Bytes 0-1: Total message length (不包括这前两个字节) Bytes 2-3: Session ID Bytes 4: Header Byte 2 (包含P-Type, S-Type) Bytes 5: Header Byte 3 (包含S-Type cont.) Bytes 6-7: System Bytes Bytes 8-9: Stream and Function (对于数据消息) 或 0xFFFF (对于控制消息)我们需要一个函数来解析和构建这个头。def parse_hsms_header(header_data): 解析10字节的HSMS头 if len(header_data) ! 10: raise ValueError(HSMS header must be 10 bytes) # 使用struct模块按大端序解析 # ’表示大端H’表示2字节无符号整数B’表示1字节无符号整数 total_len, session_id, hbyte2, hbyte3, system_b1, system_b2, stream, func \ struct.unpack(HHBBBBBB, header_data) # 计算实际的消息体长度 body_len total_len - 8 # 总长减去头部长(10-2) p_type (hbyte2 4) 0x07 s_type ((hbyte2 0x0F) 2) | ((hbyte3 6) 0x03) return { total_length: total_len, session_id: session_id, p_type: p_type, s_type: s_type, system_bytes: (system_b1 8) | system_b2, stream: stream, function: func, body_length: body_len } def build_hsms_header(session_id, s_type, system_bytes, stream0xff, func0xff, body_len0): 构建10字节的HSMS头 # P-Type 固定为0 (Separate Broker) p_type 0 hbyte2 (p_type 4) | ((s_type 2) 0x0F) hbyte3 ((s_type 0x03) 6) total_length body_len 8 # 消息体长 头部长(10-2) header struct.pack(HHBBBBBB, total_length, session_id, hbyte2, hbyte3, (system_bytes 8) 0xFF, system_bytes 0xFF, stream, func) return header步骤3处理客户端连接与HSMS握手在handle_client函数中我们需要先处理Select请求。def handle_client(self, client_socket): session_id 0x0000 # 简化处理使用固定Session ID system_byte_counter 1000 # 用于生成唯一的System Bytes try: # 1. 等待并处理Select.req (S-Type1) select_header client_socket.recv(10) if not select_header: return select_info parse_hsms_header(select_header) if select_info[s_type] ! 1: # 不是Select.req print(f[-] Expected Select.req, got S-Type: {select_info[s_type]}) client_socket.close() return print(f[*] Received Select.req, Session ID: {select_info[session_id]}) # 2. 发送Select.rsp (S-Type2) system_bytes select_info[system_bytes] # 回复使用请求中的System Bytes select_rsp_header build_hsms_header(session_id, 2, system_bytes) client_socket.send(select_rsp_header) print([] Sent Select.rsp) # 3. 进入消息循环 (Echo) self.message_loop(client_socket, session_id, system_byte_counter) except Exception as e: print(f[-] Error handling client: {e}) finally: client_socket.close() print(f[-] Connection closed)步骤4实现消息循环与Echo逻辑def message_loop(self, client_socket, session_id, system_byte_counter): while True: # 接收消息头 header_data client_socket.recv(10) if not header_data: break header_info parse_hsms_header(header_data) print(f[*] Received message: S{header_info[stream]}F{header_info[function]}, fBody Len: {header_info[body_length]}) # 接收消息体 body_data b if header_info[body_length] 0: body_data self.recv_all(client_socket, header_info[body_length]) # 如果是Deselect.req (S-Type5)则回复Deselect.rsp (S-Type6)并退出 if header_info[s_type] 5: print([*] Received Deselect.req, exiting loop.) deselect_rsp_header build_hsms_header(session_id, 6, header_info[system_bytes]) client_socket.send(deselect_rsp_header) break # Echo逻辑将收到的完整消息头体原样发回。 # 注意对于数据消息通常Primary需要等待Secondary的Reply。 # 这里简化处理直接原样发回模拟一个简单的Secondary行为。 # 生产代码中需要根据S-Type和SxFy生成正确的Reply。 full_message header_data body_data client_socket.send(full_message) print(f[] Echoed message back.) def recv_all(self, sock, length): 从socket接收指定长度的数据 data b while len(data) length: packet sock.recv(length - len(data)) if not packet: return None data packet return data5.2 测试你的Echo Server运行上面的Python脚本启动服务器。使用TCP/UDP调试工具如NetAssist作为客户端连接到服务器的IP和端口默认5000。手动发送HSMS Select.req消息。根据E37标准Select.req是10字节的控制消息没有消息体。其头部的S-Type1。你可以用以下十六进制数据模拟大端序总长度00 08(10字节总长-28)Session ID:00 00Header Byte2:00(P-Type0, S-Type高2位0)Header Byte3:01(S-Type低2位1 组合后S-Type1)System Bytes:00 00Stream/Func:FF FF(控制消息)完整十六进制序列00 08 00 00 00 01 00 00 FF FF将这段十六进制发送给服务器。你应该能立即收到服务器回复的Select.rspS-Type2。接着你可以尝试发送一个简单的数据消息例如一个S1F1Are You There?的请求。这需要构造一个完整的HSMS数据消息。这有点复杂但正是我们下一步要学习的。你可以先用模拟器生成一个S1F1的报文然后用调试工具发送给你的Echo Server观察它是否原样返回。注意事项这个Echo Server是极简的仅用于演示HSMS层的基础通信。它没有处理多会话、没有正确处理Primary/Secondary角色它把自己当成了Secondary直接Echo也没有解析SECS-II消息体。但它成功建立了HSMS连接这是一个非常重要的起点。在后续文章中我们将在此基础上逐步添加SECS-II消息的构造、解析以及GEM状态机。6. 常见问题与排查技巧实录即使做了万全准备实际开发中还是会遇到各种问题。这里记录一些我早期踩过的坑和解决方法。问题1连接建立失败提示“Connection refused”或超时。排查检查服务器程序是否真的在运行并监听正确端口netstat -an | findstr :5000或lsof -i:5000。检查防火墙设置是否阻止了5000端口的入站连接。检查客户端连接的IP地址和端口号是否正确。如果是虚拟机或容器环境检查网络模式桥接、NAT是否正确映射了端口。问题2HSMS Select握手成功但发送数据消息后无回复或连接断开。排查首要工具Wireshark。抓包查看客户端发送的完整报文。重点检查前10字节的HSMS头前两个字节表示的“总长度”是否计算正确总长度 消息体长度 8Session ID是否与Select时协商的一致我们示例中简化了实际可能动态分配S-Type是否正确数据消息的S-Type应为0。Stream和Function字节是否正确控制消息此处为0xFFFF。检查消息体长度。如果Header中声明的body_length是N那么TCP流中紧接着Header的后面是否真的有N个字节很多错误是由于长度计算不准导致接收方一直在等待剩余数据从而超时。查看服务器端日志是否在解析Header时抛出了异常如struct.unpack出错。问题3收到的SECS-II消息解析乱码或结构错误。排查确认字节序EndianSEMI标准规定HSMS和SECS-II均使用大端序Big-Endian Network Byte Order。这是最常见的错误来源之一。在x86/ARM等小端序主机上使用struct.pack/unpack或构建字节数组时务必显式指定格式符。使用模拟器或分析工具对照用SECS Simulator等工具构造一个你认为正确的消息然后对比你的程序生成的原始字节流一个字节一个字节地比对。差异点往往就是问题所在。检查数据项格式Item Format每个数据项前都有一个或两个格式字节。确保你生成的格式字节与数据内容匹配。例如一个包含3个ASCII字符的项其格式字节可能是0x41表示A类型长度1字节后面跟着长度字节0x03再后面是3个字符的ASCII码。问题4GEM状态机混乱设备行为不符合主机预期。排查画出状态迁移图在白板上清晰画出E30中定义的状态COMMUNICATING, NOT COMMUNICATING等以及触发状态迁移的消息S1F13, S1F15等。对照你的代码逻辑检查是否在所有可能路径上都正确更新了内部状态变量。日志是关键在代码的关键分支如收到消息、发送消息、状态改变时打印详细的日志包括时间戳、当前状态、消息SxFy等。这能帮你复盘整个交互过程。与主机侧对齐很多时候问题不在于设备实现而在于双方对GEM能力的理解不一致。例如主机试图请求一个设备未启用的数据收集项CEID。确保你的设备GEM配置文档与主机MES/EAP团队的期望一致。问题5性能问题处理大量数据收集Collection Event时延迟高。排查与优化异步与多线程HSMS消息处理特别是耗时的数据打包、数据库操作等一定要放在单独的线程或异步任务中避免阻塞网络接收线程。消息合并对于高频率的事件如秒级的温度读数不要每个事件都立即发送一条S6F11。可以实现一个缓存队列定期如每100ms或每积累10个事件打包成一条消息发送减少网络和小包开销。优化数据序列化SECS-II消息的组装特别是复杂的嵌套List可能是性能瓶颈。评估并优化你的数据项构建和字节数组拼接逻辑。对于固定结构的数据可以考虑预编译格式模板。准备工作到此为止我们已经搭好了舞台理解了角色也练习了最基本的台词HSMS握手。从下一篇开始我们将深入SECS-II这座语言大厦的内部学习如何构造和理解那些承载着具体生产指令和数据的信息实体。你会发现一旦基础打牢后面的一切都将有迹可循。
返回列表