好的,欢迎来到:
第五讲:设备触发事件 S6F11,我该怎么处理?
关键词:S6F11 报文解析、事件驱动、CEID、VID 值提取、自动回应、业务逻辑绑定
本讲目标
这讲我们要做的是:
- 设备发来 S6F11,主机能自动接收
- 解析 CEID,判断触发了哪个事件
- 从报文里提取出关键变量(VID)
- 回复 S6F12 保持协议完整
- 执行业务逻辑,比如"记录日志"、"通知人"、"触发控制指令"
这部分是 EAP 或 Host 主机逻辑最核心的"反应机制",掌握了这个,你的系统才有"感知设备"的能力。
一、S6F11 是什么?
S6F11 是 设备上报的"事件",也是 Host 最常收到的一条报文。
格式一般是:
S6F11 W
<L
U2 CEID
<L
U2 RPTID
<L
... 多个 VID 和对应的值
>
>
>
也可能有多个 Report:
<L
U2 CEID
<L
<L U2 RPTID1 <L VID1 VAL1 VID2 VAL2>>
<L U2 RPTID2 <L VID3 VAL3>>
>
>
二、自动监听消息
你只要在启动程序时挂上这个事件:
csharp
gem.MessageReceived += OnSecsMessageReceived;
然后写:
csharp
private async void OnSecsMessageReceived(object sender, SecsMessage e)
{
if (e.Stream == 6 && e.Function == 11)
{
await HandleS6F11(e);
}
}
三、怎么解析 CEID?(事件码)
例子
csharp
ushort ceid = e.SecsItem[0].GetValue<ushort>();
Console.WriteLine($"触发事件:CEID = {ceid}");
你可以用 switch 做事件分发:
csharp
switch (ceid)
{
case 1:
Console.WriteLine("批次开始");
break;
case 2:
Console.WriteLine("批次结束");
break;
case 99:
Console.WriteLine("设备异常");
break;
}
四、怎么提取 RPTID 和 VID 值?
结构大概是:
e.SecsItem[1] => List of Reports
Each Report:
[0] => RPTID
[1] => List of Variables (VID + Value)
代码如下:
csharp
var reports = e.SecsItem[1].Items;
foreach (var rpt in reports)
{
var rptId = rpt[0].GetValue<ushort>();
var variables = rpt[1].Items;
Console.WriteLine($"RPTID: {rptId}");
foreach (var item in variables)
{
Console.WriteLine("变量值:" + item.Format());
}
}
这样你就能拿到所有变量值,例如:
RPTID: 100
变量值:A "LOT123"
变量值:A "RECIPE_XYZ"
五、怎么回应 S6F11?(S6F12)
你必须回应 S6F11 否则设备会卡住。
csharp
var reply = e.Reply(Item.B(0)); // 表示接受成功
await gem.SendAsync(reply);
完整流程:
csharp
private async Task HandleS6F11(SecsMessage e)
{
ushort ceid = e.SecsItem[0].GetValue<ushort>();
Console.WriteLine($"触发事件:CEID = {ceid}");
// 提取数据
var reports = e.SecsItem[1].Items;
foreach (var rpt in reports)
{
var rptId = rpt[0].GetValue<ushort>();
var variables = rpt[1].Items;
Console.WriteLine($"RPTID: {rptId}");
foreach (var item in variables)
{
Console.WriteLine("变量值:" + item.Format());
}
}
// 回复 S6F12
var reply = e.Reply(Item.B(0));
await gem.SendAsync(reply);
}
六、如何绑定业务逻辑?
比如当 CEID = 1(批次开始),你想记录批次信息。
你可以这样设计:
csharp
switch (ceid)
{
case 1:
var lotId = reports[0][1].Items[0].GetValue<string>();
var recipe = reports[0][1].Items[1].GetValue<string>();
StartLot(lotId, recipe);
break;
case 99:
var errorCode = reports[0][1].Items[0].GetValue<ushort>();
LogError(errorCode);
break;
}
七、S6F11 报文可变怎么办?
你在实际开发中遇到的问题是:
有些设备报文结构不一样怎么办?
那你需要:
- 跟设备厂确认 CEID 报文结构文档(SEMI E5 spec 或 OEM 提供)
- 写容错代码(TryGet + 判断结构层级)
- 记录下原始 Item 树结构,用日志观察规律
示例:
csharp
try
{
var ceid = e.SecsItem[0].GetValue<ushort>();
var rptItems = e.SecsItem[1]?.Items;
if (rptItems != null && rptItems.Count > 0)
{
foreach (var rpt in rptItems)
{
// 结构保护判断
}
}
}
catch (Exception ex)
{
Console.WriteLine("解析失败:" + ex.Message);
}
第五讲 · 小结
你已经掌握了:
- S6F11 是设备主动上报事件的报文;
- 如何解析 CEID,判断什么事件;
- 如何读出 RPTID 下的所有变量(VID);
- 如何回应 S6F12,维持通讯;
- 如何绑定具体业务逻辑,实现设备"状态感知";
- 如何应对设备结构差异,保证代码健壮性。
下一讲,将进入更加工程化的一章:
第六讲:如何实现主机批量注册事件?一次性启用设备所有触发事件
这一讲,你会掌握如何发 S2F33、S2F35、S2F37,把设备的事件"激活"起来,变被动为主动。
只需你一句:"继续",马上开始。