跳到主要内容

事件

通过 master.Events 订阅所有主站级事件。

自动初始化

所有事件回调和日志系统在 Build() 时自动注册,无需手动调用。

从站级事件

从站 PDO 数据变化通知、FSoE 安全事件请参考 从站事件

自动日志

所有事件(PDO 周期回调除外)触发时系统均自动记录日志,无论是否订阅。确保关键运行状态不会被静默丢失。

PDO 周期回调(ProcessDataCyclicSync)为高频回调,不记录日志。

功能概览

类别事件说明自动日志
PDO 周期回调master.Events.ProcessDataCyclicSyncPDO 周期回调(同步,供 FSoE 等实时控制)
状态事件master.Events.StateChanged主站 EtherCAT 状态变化(含异常降级)
master.Events.SlaveStateChanged从站 EtherCAT 状态变化
热插拔事件master.Events.SlaveOffline从站离线(断开)
master.Events.SlaveOnline从站上线(恢复)
master.Events.SlaveIdentityMismatch从站身份不符(换成错误型号/低版本)
异常事件master.Events.EmergencyEventCoE Emergency 紧急消息
master.Events.PDOFrameLossPDO 连续丢帧(按组独立跟踪)
master.Events.DCSyncLostDC 同步丢失
冗余事件master.Events.RedundancyModeChanged冗余模式变化(Inactive/Dual/Degraded)
master.Events.SlavePortLinkChanged从站端口 link 变化(P0-P3 断开/恢复)
日志Logs.Updated日志数据更新通知

PDO 周期回调

PDO 数据通路

PDO 过程数据为纯内核 RT 收发,应用层经内核共享内存指针零拷贝直接读写过程映像。一般情况下直接轮询过程映像指针即可,无需事件回调。ProcessDataCyclicSync 仅在需要 FSoE 等当周期实时控制时使用。

ProcessDataCyclicSync

public event ProcessDataCyclicSyncEventHandler? ProcessDataCyclicSync;
// delegate void ProcessDataCyclicSyncEventHandler(ushort masterIndex);

每个 PDO 周期触发一次(同步模式)。回调在实时线程中直接执行,延迟最低但回调必须快速返回。

注意

同步回调中不要执行耗时操作(如 SDO 读写、文件 I/O、锁等待),否则会阻塞实时线程导致丢帧。

示例:

master.Events.ProcessDataCyclicSync += (masterIndex) =>
{
ref var input = ref slave.PDO.InputsMapping<ServoInput>();
ref var output = ref slave.PDO.OutputsMapping<ServoOutput>();
output.ControlWord = 0x000F;
};

状态事件

Master.StateChanged

master.Events.StateChanged += (sender, e) => { };
// EventHandler<StateChangedEventArgs>

主站 EtherCAT 状态变化时触发(包括主动切换和异常降级)。始终自动记录日志。该事件只反映主站自身的 EcState,与单个从站状态 (slave.Events.StateChanged) 和 FSoE 安全连接状态 (slave.FSoE.StateChanged) 互相独立。

回调参数:

public class StateChangedEventArgs
{
public EcState OldState { get; } // 变化前的状态
public EcState NewState { get; } // 变化后的状态
}

示例:

master.Events.StateChanged += (sender, e) =>
{
Console.WriteLine($"主站状态: {e.OldState}{e.NewState}");
};

SlaveStateChanged

master.Events.SlaveStateChanged += (masterIndex, slaveIndex, oldState, newState) => { };
// delegate void SlaveStateChangeEventHandler(ushort masterIndex, ushort slaveIndex, EcState oldState, EcState newState);

从站 EtherCAT 状态变化时触发。后台自动监控。始终自动记录日志。

回调参数:

  • masterIndex (ushort) — 主站索引
  • slaveIndex (ushort) — 从站索引(1-based)
  • oldState (EcState) — 变化前的状态
  • newState (EcState) — 变化后的状态

示例:

master.Events.SlaveStateChanged += (masterIndex, slaveIndex, oldState, newState) =>
{
Console.WriteLine($"从站 {slaveIndex}: {oldState}{newState}");

var slave = master.Slaves[slaveIndex - 1];
if (slave.ErrorCode != EcALState.NoError)
Console.WriteLine($" 错误码: {slave.ErrorCode}");
};
ErrorCode

slave.ErrorCode 读取 AL Status Code,返回状态切换失败的具体原因。详见 属性与状态机

热插拔事件

SlaveOffline

master.Events.SlaveOffline += (slaveIndex) => { };
// delegate void SlaveOfflineEventHandler(ushort slaveIndex);

从站离线事件。热插拔断开时触发,PDO 线程内置的恢复状态机会自动恢复从站(零 PDO 影响)。始终自动记录日志。

示例:

master.Events.SlaveOffline += (slaveIndex) =>
{
Console.WriteLine($"从站 {slaveIndex} 离线");
};

SlaveOnline

master.Events.SlaveOnline += (slaveIndex) => { };
// delegate void SlaveOnlineEventHandler(ushort slaveIndex);

从站上线事件。热插拔恢复时触发。始终自动记录日志。

示例:

master.Events.SlaveOnline += (slaveIndex) =>
{
Console.WriteLine($"从站 {slaveIndex} 上线");
};

IsSlaveOffline(ushort slaveIndex)

public bool IsSlaveOffline(ushort slaveIndex)

查询从站是否已被事件系统确认为离线状态。

参数:

  • slaveIndex (ushort) — 从站索引

返回值:

  • bool — 从站离线返回 true

示例:

if (master.Events.IsSlaveOffline(2))
Console.WriteLine("从站 2 处于离线状态");

SlaveIdentityMismatch

master.Events.SlaveIdentityMismatch += (sender, args) => { };
// EventHandler<SlaveIdentityMismatchEventArgs>

从站断电重插后身份不符时触发:EtherCAT 识别状态机读取到的 Vendor/Product 与配置不匹配,或 Revision 低于配置(向后兼容:实际 Revision ≥ 配置值视为匹配)。始终自动记录日志。

触发后从站进入 IDENT_REJECTED 状态,不会自动重探测(防止错设备反复刷屏)。操作员检查/更换设备后需调用 master.AcknowledgeSlaveReplacement 让 SDK 重新探测。

回调参数 (SlaveIdentityMismatchEventArgs):

public class SlaveIdentityMismatchEventArgs
{
public ushort MasterIndex { get; } // 主站索引
public ushort SlaveIndex { get; } // 从站索引(1-based)
public uint ExpectedVendor { get; } // 配置期望的厂商 ID
public uint ExpectedProduct { get; } // 配置期望的产品代码
public uint ExpectedRevision { get; } // 配置期望的最低修订号
public uint ActualVendor { get; } // 当前实际厂商 ID
public uint ActualProduct { get; } // 当前实际产品代码
public uint ActualRevision { get; } // 当前实际修订号
}

示例:

master.Events.SlaveIdentityMismatch += (sender, args) =>
{
Console.WriteLine($"从站 {args.SlaveIndex} 身份不符:");
Console.WriteLine($" 期望: Vendor=0x{args.ExpectedVendor:X8}, Product=0x{args.ExpectedProduct:X8}, Rev>=0x{args.ExpectedRevision:X8}");
Console.WriteLine($" 实际: Vendor=0x{args.ActualVendor:X8}, Product=0x{args.ActualProduct:X8}, Rev=0x{args.ActualRevision:X8}");
// UI 弹窗提示用户换回正确设备, 确认后调用 master.AcknowledgeSlaveReplacement(args.SlaveIndex)
};
去重机制

同一从站进入 IDENT_REJECTED 状态仅触发一次事件。调用 AcknowledgeSlaveReplacement 后重置探测,身份仍不匹配会再次触发。

异常事件

EmergencyEvent

master.Events.EmergencyEvent += (masterIndex, slaveIndex, errorCode, errorReg, b1, w1, w2) => { };
// delegate void EmergencyEventHandler(ushort masterIndex, ushort slaveIndex,
// ushort errorCode, ushort errorReg, byte b1, ushort w1, ushort w2);

CoE Emergency 紧急消息事件。从站固件检测到错误时发送,数据格式遵循 CANopen Emergency 协议(CiA 301)。始终自动记录日志。

回调参数:

  • masterIndex (ushort) — 主站索引
  • slaveIndex (ushort) — 从站索引(1-based)
  • errorCode (ushort) — 错误代码(CANopen Emergency Error Code,对象 0x603F)
  • errorReg (ushort) — 错误寄存器(对象 0x1001)
  • b1 (byte) — 制造商特定数据(字节 3)
  • w1 (ushort) — 制造商特定数据(字节 4-5)
  • w2 (ushort) — 制造商特定数据(字节 6-7)

相关结构:

常见 Emergency Error Code:

  • 0x0000 — 错误已复位
  • 0x1000 — 通用错误
  • 0x2000 — 电流错误
  • 0x3000 — 电压错误
  • 0x4000 — 温度错误
  • 0x5000 — 设备硬件错误
  • 0x6000 — 设备软件错误
  • 0x7000 — 附加模块错误
  • 0x8000 — 监控错误(通信)
  • 0xFF00 — 制造商特定错误

示例:

master.Events.EmergencyEvent += (masterIndex, slaveIndex, errorCode, errorReg, b1, w1, w2) =>
{
Console.WriteLine($"从站 {slaveIndex} 紧急消息: 错误码=0x{errorCode:X4}, 寄存器=0x{errorReg:X2}");
};

PDOFrameLoss

master.Events.PDOFrameLoss += (masterIndex, group, consecutiveLostCount, totalLostCount) => { };
// delegate void PDOFrameLossEventHandler(ushort masterIndex, byte group,
// uint consecutiveLostCount, uint totalLostCount);

PDO 连续丢帧事件。当连续丢帧达到阈值时触发,单次丢帧仅计数不触发。每组独立跟踪。始终自动记录日志。

回调参数:

  • masterIndex (ushort) — 主站索引
  • group (byte) — 发生丢帧的组号(0-7),对应从站分组
  • consecutiveLostCount (uint) — 该组连续丢帧数
  • totalLostCount (uint) — 该组累计丢帧数

示例:

master.Events.PDOFrameLoss += (masterIndex, group, consecutive, total) =>
{
Console.WriteLine($"组 {group} 丢帧: 连续={consecutive}, 累计={total}");
};
丢帧统计

PDO 丢帧的详细统计(按组查询)请参考 主站诊断 - PDO 丢帧

DCSyncLost

master.Events.DCSyncLost += (masterIndex, slaveIndex, diffNs) => { };
// delegate void DCSyncLostEventHandler(ushort masterIndex, ushort slaveIndex, int diffNs);

DC 同步丢失事件。当从站从同步→失同步(超出阈值)时触发一次,持续超出不重复触发。始终自动记录日志。

回调参数:

  • masterIndex (ushort) — 主站索引
  • slaveIndex (ushort) — 失同步的从站索引(1-based)
  • diffNs (int) — 当前与参考时钟的时间差(纳秒)

示例:

master.Diagnostics.SyncWindowThreshold = 500;  // 500ns

master.Events.DCSyncLost += (masterIndex, slaveIndex, diffNs) =>
{
Console.WriteLine($"从站 {slaveIndex} DC 同步丢失: 偏差 {diffNs}ns");
};
单个从站 DC 诊断

slave.Diagnostics.DC.IsInSyncslave.Diagnostics.DC.SyncTimeDifference 可查询从站当前同步状态。详见 从站诊断 - DC 同步

冗余事件

RedundancyModeChanged

master.Events.RedundancyModeChanged += (masterIndex, oldMode, newMode) => { };
// delegate void RedundancyModeChangedEventHandler(ushort masterIndex, int oldMode, int newMode);

冗余运行模式发生变化时触发。oldMode / newMode 对应 RingMode 枚举值(0=Inactive, 1=Dual, 2=Degraded)。

示例:

master.Events.RedundancyModeChanged += (masterIndex, oldMode, newMode) =>
{
Console.WriteLine($"冗余模式: {oldMode}{newMode}");
};

SlavePortLinkChanged

master.Events.SlavePortLinkChanged += (masterIndex, slaveIndex, port, isUp) => { };
// delegate void SlavePortLinkChangedEventHandler(ushort masterIndex, ushort slaveIndex, byte port, bool isUp);

从站 ESC 端口物理链路变化时触发(P0-P3 之一断开或恢复)。每秒诊断周期检测 DL Status 寄存器的 link bit,从 1→0 触发"断开",从 0→1 触发"恢复"。始终自动记录日志。

用于精确定位故障线缆段(相邻从站的对向端口同时报断,说明中间线缆有问题)。

回调参数:

  • masterIndex (ushort) — 主站索引
  • slaveIndex (ushort) — 从站索引(1-based)
  • port (byte) — 端口号 0-3,对应 P0 / P1 / P2 / P3
  • isUp (bool) — true=link 恢复, false=link 断开

示例:

master.Events.SlavePortLinkChanged += (masterIndex, slaveIndex, port, isUp) =>
{
string state = isUp ? "恢复" : "断开";
Console.WriteLine($"从站 {slaveIndex} 端口 P{port} link {state}");
};
配合断点定位

master.Diagnostics.BreakPoint / GetAllBreakPoints() 提供聚合后的故障点视图(断线 + CRC 故障)。SlavePortLinkChanged 是原始事件源,适合做实时告警。详见 主站诊断 - 冗余状态

清除事件订阅

Events.ClearAll()

public void ClearAll()

一键清除所有主站级事件订阅,防止内存泄漏。在销毁主站或重新初始化前调用。

示例:

// 销毁前清除所有事件
master.Events.ClearAll();
master.Close();
从站级事件

从站也有 slave.Events.ClearAll() 方法,清除该从站的所有事件订阅。

线程安全

事件回调在非 UI 线程上触发。更新 UI 时需要线程同步:

// WinForms
master.Events.SlaveOffline += (idx) =>
this.Invoke(() => labelStatus.Text = $"从站 {idx} 离线");

// WPF
master.Events.SlaveOffline += (idx) =>
Dispatcher.Invoke(() => StatusText = $"从站 {idx} 离线");
C# 特有语法糖

C# 还支持 IObservable<T> 流式事件订阅, 用 using var sub = master.StateChangeStream().Subscribe(...) 自动反订阅, 并配合 System.ReactiveWhere/Throttle/Buffer 等 LINQ-to-Events 操作符链式过滤. 详见 IObservable<T> 事件流.

完整示例

// ===== 主站状态 =====
master.Events.StateChanged += (sender, e) =>
Console.WriteLine($"主站: {e.OldState}{e.NewState}");

//从站状态
master.Events.SlaveStateChanged += (masterIndex, slaveIndex, oldState, newState) =>
{
var slave = master.Slaves[slaveIndex - 1];
Console.WriteLine($"从站 {slaveIndex}: {oldState}{newState}");
if (slave.ErrorCode != EcALState.NoError)
Console.WriteLine($" 错误码: {slave.ErrorCode}");
};

// ===== 热插拔 =====
master.Events.SlaveOffline += (slaveIndex) =>
Console.WriteLine($"从站 {slaveIndex} 离线");
master.Events.SlaveOnline += (slaveIndex) =>
Console.WriteLine($"从站 {slaveIndex} 上线");

// ===== 异常事件 =====
master.Events.EmergencyEvent += (masterIndex, slaveIndex, errorCode, errorReg, b1, w1, w2) =>
Console.WriteLine($"从站 {slaveIndex} 紧急消息: 0x{errorCode:X4}");

master.Events.PDOFrameLoss += (masterIndex, group, consecutive, total) =>
Console.WriteLine($"组 {group} 丢帧: 连续={consecutive}, 累计={total}");

master.Events.DCSyncLost += (masterIndex, slaveIndex, diffNs) =>
Console.WriteLine($"从站 {slaveIndex} DC 同步丢失: {diffNs}ns");

// ===== 冗余事件 =====
master.Events.RedundancyModeChanged += (masterIndex, oldMode, newMode) =>
Console.WriteLine($"冗余模式变化: {oldMode}{newMode}");

master.Events.SlavePortLinkChanged += (masterIndex, slaveIndex, port, isUp) =>
Console.WriteLine($"从站 {slaveIndex} P{port} link {(isUp ? "恢复" : "断开")}");

// ===== 热插拔身份不符 =====
master.Events.SlaveIdentityMismatch += (sender, args) =>
Console.WriteLine($"从站 {args.SlaveIndex} 身份不符, 换设备后调用 AcknowledgeSlaveReplacement({args.SlaveIndex})");

// ===== PDO 周期回调(同步,供 FSoE 等实时控制;PDO 数据通常直接轮询过程映像指针)=====
master.Events.ProcessDataCyclicSync += (masterIndex) =>
{
// 当周期实时控制
};