跳到主要内容

从站事件

通过 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}");
}