从站事件
通过 slave.Events 访问。事件参数已过滤到当前从站,签名简洁。
主站级 DLL 回调会自动路由到对应从站的 slave.Events。订阅从站事件无需 masterIndex/slaveIndex 参数,系统已自动过滤到当前从站。
FSoE 安全事件通过 slave.FSoE 订阅,请参考 FSoE。
功能概览
| 类别 | 事件 / 方法 | 读写 | 说明 |
|---|---|---|---|
| 从站状态事件 | slave.Events.StateChanged | 只读 | 从站 EtherCAT 状态变化 |
| slave.Events.Emergency | 只读 | CoE Emergency 紧急消息 | |
| slave.Events.Offline | 只读 | 从站离线(热插拔断开) | |
| slave.Events.Online | 只读 | 从站上线(热插拔恢复) | |
| slave.Events.DCSyncLost | 只读 | DC 同步丢失 | |
| PDO 数据变化 | slave.PDO.InputsMapping(onChanged 重载)/ ProcessDataCyclicSync | 只读 | 映射一次钉页;变化回调自动通知,或在周期回调里比较字段 |
从站状态事件
Slave.StateChanged
slave.Events.StateChanged += (oldState, newState) => { };
// Action<EcState, EcState>
从站 EtherCAT 状态变化时触发。由 master.Events.SlaveStateChanged 自动路由。该事件只反映该从站的 EcState (Init/PreOp/SafeOp/OP),与主站全局状态 (master.Events.StateChanged) 和 FSoE 安全连接状态 (slave.FSoE.StateChanged) 互相独立。
示例:
slave.Events.StateChanged += (oldState, newState) =>
{
Console.WriteLine($"状态变化: {oldState} → {newState}");
};
Emergency
slave.Events.Emergency += (errorCode, errorReg, b1, w1, w2) => { };
// Action<ushort, ushort, byte, ushort, ushort>
CoE Emergency 紧急消息。由 master.Events.EmergencyEvent 自动路由。
回调参数:
// Action<ushort, ushort, byte, ushort, ushort>
errorCode, // ushort — 错误代码(CANopen Emergency Error Code)
errorReg, // ushort — 错误寄存器(对象 0x1001)
b1, // byte — 制造商特定数据(字节 3)
w1, // ushort — 制造商特定数据(字节 4-5)
w2 // ushort — 制造商特定数据(字节 6-7)
示例:
slave.Events.Emergency += (errorCode, errorReg, b1, w1, w2) =>
{
Console.WriteLine($"紧急消息: 错误码=0x{errorCode:X4}");
};
Offline
slave.Events.Offline += () => { };
// Action
从站离线(热插拔断开)。由 master.Events.SlaveOffline 自动路由。
示例:
slave.Events.Offline += () =>
{
Console.WriteLine("从站离线");
};
Online
slave.Events.Online += () => { };
// Action
从站上线(热插拔恢复)。由 master.Events.SlaveOnline 自动路由。
示例:
slave.Events.Online += () =>
{
Console.WriteLine("从站上线");
};
DCSyncLost
slave.Events.DCSyncLost += (diffNs) => { };
// Action<int>
DC 同步丢失。由 master.Events.DCSyncLost 自动路由。
示例:
slave.Events.DCSyncLost += (diffNs) =>
{
Console.WriteLine($"DC 同步丢失: 偏差 {diffNs}ns");
};
PDO 数据变化
slave.PDO.InputsMapping<T>(onChanged) / slave.PDO.InputsSliceMapping<T>(offset, onChanged) 自带变化回调(约 1 ms 后台轮询比较,不在 PDO 周期内触发),无需自己在周期回调里比较字段。详见 PDO 输入输出。
结构体映射周期采样
进 OP 后把 packed 结构体映射到过程映像,在周期回调里比较字段(lambda 不能捕获 ref 局部,映射在回调体内取)。
示例:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct InPdo
{
public ushort StatusWord;
public int ActualPosition;
public int ActualVelocity;
}
InPdo previous = default;
master.Events.ProcessDataCyclicSync += (mi) =>
{
ref readonly InPdo current = ref slave.PDO.InputsMapping<InPdo>();
if (current.ActualPosition != previous.ActualPosition)
Console.WriteLine($"位置变化: {previous.ActualPosition} -> {current.ActualPosition}");
previous = current;
};
MDP 模块化设备用 slave.PDO.InputsSliceMapping<T>(offset) 从模块字节偏移映射结构体。
线程安全
事件回调在非 UI 线程上触发。更新 UI 时需要线程同步:
// 事件线程先取一份值快照(ref 局部不能捕获进 lambda),再交给 UI 线程
InPdo snapshot = slave.PDO.InputsMapping<InPdo>();
// WinForms
this.Invoke(() => labelValue.Text = $"位置: {snapshot.ActualPosition}");
// WPF
Dispatcher.Invoke(() => PositionText = $"位置: {snapshot.ActualPosition}");
回调中避免执行耗时操作。如需处理大量数据,将数据放入队列异步处理:
master.Events.ProcessDataCyclicSync += (mi) =>
{
_dataQueue.Enqueue(slave.PDO.InputsMapping<InPdo>()); // 入队一份值快照,不阻塞周期
};
完整示例
var slave = master.Slaves[0];
// ===== 从站状态事件 =====
slave.Events.StateChanged += (oldState, newState) =>
Console.WriteLine($"状态: {oldState} → {newState}");
slave.Events.Emergency += (errorCode, errorReg, b1, w1, w2) =>
Console.WriteLine($"紧急消息: 0x{errorCode:X4}");
slave.Events.Offline += () =>
Console.WriteLine("从站离线");
slave.Events.Online += () =>
Console.WriteLine("从站上线");
slave.Events.DCSyncLost += (diffNs) =>
Console.WriteLine($"DC 同步丢失: {diffNs}ns");
// ===== PDO 数据变化(钉页 0 拷贝,回调里比较字段) =====
InPdo previous = default;
master.Events.ProcessDataCyclicSync += (mi) =>
{
ref readonly InPdo current = ref slave.PDO.InputsMapping<InPdo>();
if (current.ActualPosition != previous.ActualPosition)
Console.WriteLine($"位置变化: {previous.ActualPosition} -> {current.ActualPosition}");
previous = current;
};
// ===== FSoE 安全事件(协议专属) =====
if (slave.FSoE != null)
{
slave.FSoE.StateChanged += (sender, e) =>
Console.WriteLine($"FSoE: {e.OldState} → {e.NewState}");
}