4. SECS-I串行通信与协议转换
SECS-I(SEMI E4)是SECS/GEM体系中最早被标准化的物理层与数据链路层协议,它把SECS-II消息封装成定长块,通过RS-232串行链路在设备与主机之间传输。虽然现代300mm设备普遍采用HSMS(SEMI E37)走TCP/IP,但大量200mm及更早的设备、部分量测机台和特殊工艺设备仍然只提供SECS-I接口。做一致性测试时,必须理解SECS-I的块传输、握手、重试与超时机制,才能判断设备行为是否符合标准,也才能正确设计协议转换网关的测试用例。
块传输与握手信号
SECS-I把一条SECS-II消息切分成若干数据块,每块最大244字节(含10字节块头,实际数据最多234字节)。块头结构固定:设备ID(2字节)、消息ID(4字节,高2位为R-bit,低30位为消息编号)、块号(2字节,最高位为E-bit表示最后一块)。发送方按块号递增发送,接收方逐块确认。
握手采用独立的控制信号线,而不是数据字节:发送方拉低ENQ(请求发送),接收方若准备好则回EOT,否则回NAK;发送方收到EOT后发送数据块,接收方校验后回ACK或NAK。整个过程由RS-232的RTS/CTS/DTR/DSR等信号配合,形成严格的半双工交互。测试时最常观察的异常是:设备在收到EOT后长时间不发数据、收到NAK后不重发、或E-bit置位错误导致接收方一直等待后续块。
重试机制与超时参数
SECS-I定义了四个关键超时参数,它们直接决定通信的鲁棒性,也是一致性测试的重点:
| 参数 | 含义 | 典型值 | 测试关注点 |
|---|---|---|---|
| T1 | 发送ENQ后等待EOT的时间 | 0.5~2 s | 超时后是否按RTY重发ENQ |
| T2 | 接收方等待数据块的时间 | 1~5 s | 超时是否回NAK而非静默 |
| T3 | 发送方等待ACK/NAK的时间 | 1~5 s | 超时是否重发当前块 |
| T4 | 块与块之间的最大间隔 | 2~10 s | 超时是否上报链路错误 |
| RTY | 最大重试次数 | 3~7 | 超过后是否放弃并报错 |
测试时可以用串口监听工具人为制造超时:例如在设备发出ENQ后不回复EOT,观察主机是否在T1后重发ENQ,并统计重发次数是否等于RTY。若设备在RTY次后仍不报错,说明其重试逻辑不符合E4要求。
SECS-I与HSMS的差异对比
两者最根本的区别在于传输介质与连接模型。SECS-I是点对点串行链路,半双工,靠信号线握手;HSMS是TCP/IP上的全双工协议,用Select/Deslect或Separate模式管理连接,没有ENQ/EOT握手,而是用控制消息(Select.req、Linktest.req等)维持会话。SECS-I的块头包含设备ID和块号,HSMS的消息头包含Session ID、Header Byte 2/3、System Bytes和Status Bytes,字段语义完全不同。
从测试角度看,SECS-I的故障模式更偏物理层:线序错误、波特率不匹配、流控信号未连接都会导致握手失败;HSMS的故障则更多出现在TCP连接建立、Session ID冲突、超时重连等层面。协议转换网关必须同时处理这两套语义,把SECS-I的块重组为完整SECS-II消息,再封装成HSMS消息发送,反之亦然。
协议转换网关的测试要点
网关的核心职责是“块↔消息”和“串口↔TCP”的双向转换。测试时应重点覆盖以下场景:
- 分块重组:构造一条超过234字节的SECS-II消息,验证网关能否正确按块号重组,E-bit判断是否准确。
- 消息ID映射:SECS-I的消息ID为30位,HSMS的System Bytes为32位,验证映射后是否保持唯一性和可追溯性。
- 超时传递:当SECS-I侧发生T3超时,网关应向HSMS侧返回何种错误?通常应生成S9F7(非法数据)或S9F9(事务超时)等错误消息。
- 并发与缓冲:多台SECS-I设备接入同一网关时,验证串口队列和TCP会话是否隔离,避免消息串扰。
- 异常恢复:拔掉串口线再插回,观察网关是否自动重建链路并恢复通信。
搭建SECS-I仿真环境并验证基本通信
搭建仿真环境需要三部分:串口物理层、SECS-I协议栈、SECS-II消息构造工具。以下给出一个基于Python的简化示例,使用pyserial模拟设备侧,主机侧用另一进程发送S1F1(Are You There)。
# 设备侧仿真(简化示意)
import serial, time
ser = serial.Serial(
port='COM3', baudrate=9600,
bytesize=8, parity='N', stopbits=1,
timeout=1, rtscts=True
)
def recv_block():
# 等待ENQ(实际需通过控制线判断,此处简化)
time.sleep(0.1)
ser.write(b'\x06') # EOT
header = ser.read(10) # 块头
if len(header) < 10:
ser.write(b'\x15') # NAK
return None
dev_id = int.from_bytes(header[0:2], 'big')
msg_id = int.from_bytes(header[2:6], 'big')
blk_no = int.from_bytes(header[6:8], 'big')
e_bit = (blk_no >> 15) & 1
data = ser.read(234)
ser.write(b'\x06') # ACK
return dev_id, msg_id, blk_no, e_bit, data
print("SECS-I device simulator ready")
while True:
result = recv_block()
if result:
print("recv:", result[:4])
主机侧发送S1F1时,消息体为01 01 00 00(Stream 1, Function 1, W-bit=0, 空消息体),加上块头后总长14字节,单块即可传完,E-bit置1。设备侧收到后应回复S1F2,消息体为01 02 00 00。验证时用串口调试助手观察字节流,确认ENQ/EOT/ACK的时序和块头字段是否正确。
完成基本通信后,可以进一步注入异常:把设备侧波特率改为4800而主机保持9600,观察是否出现乱码和NAK;或在设备侧故意不回EOT,验证主机的T1重试和RTY上限。这些异常用例正是SECS-I一致性测试的核心内容,也是协议转换网关必须正确透传或转换的关键行为。