从站事件
所有事件回调包含 master_index 和 slave_index 参数,由调用方自行过滤。
完整回调注册列表详见 事件。
协议专属事件
FSoE 安全事件通过独立回调注册,请参考 FSoE。
功能概览
| 类别 | 注册函数 | 说明 |
|---|---|---|
| 状态变化 | RegisterSlaveStateChangeCallbackSync/Async | 从站 EtherCAT 状态变化 |
| 紧急消息 | RegisterEmergencyEventCallback | CoE Emergency 紧急消息 |
| 热插拔 | RegisterSlaveDiscoveryCallbackSync/Async | 从站上线/离线 |
| DC 同步丢失 | SetDCSyncLostCallback | DC 同步偏差超过阈值 |
| 输入数据变化 | RegisterInputDataChangedCallback | 输入 PDO 数据变化 |
| PreOP 重配置 | RegisterSlavePreOpReconfigCallback | 热插拔后自动恢复 |
状态变化
void RegisterSlaveStateChangeCallbackSync(state_change_callback_t callback);
void RegisterSlaveStateChangeCallbackAsync(state_change_callback_t callback);
从站 EtherCAT 状态变化通知。
回调类型:
typedef void (*state_change_callback_t)(uint16_t master_index, uint16_t slave_index,
int old_state, int new_state);
紧急消息
void RegisterEmergencyEventCallback(emergency_callback_t callback);
CoE Emergency 消息通知。
回调类型:
typedef void (*emergency_callback_t)(uint16_t master_index, uint16_t slave_index,
uint16_t error_code, uint16_t error_reg, uint8_t b1, uint16_t w1, uint16_t w2);
回调参数说明:
error_code(uint16_t) — 错误代码(CANopen Emergency Error Code)error_reg(uint16_t) — 错误寄存器(对象 0x1001)b1(uint8_t) — 制造商特定数据(字节 3)w1(uint16_t) — 制造商特定数据(字节 4-5)w2(uint16_t) — 制造商特定数据(字节 6-7)
从站发现/移除(热插拔)
void RegisterSlaveDiscoveryCallbackSync(discovery_callback_t callback);
void RegisterSlaveDiscoveryCallbackAsync(discovery_callback_t callback);
从站上线/离线通知。
回调类型:
typedef void (*discovery_callback_t)(uint16_t master_index, uint16_t slave_index, BOOL is_found);
DC 同步丢失
void SetDCSyncLostCallback(dc_sync_lost_callback_t callback);
DC 同步偏差超过阈值时通知。
回调类型:
typedef void (*dc_sync_lost_callback_t)(uint16_t master_index, uint16_t slave_index, int diff_ns);
输入 PDO 数据变化
void RegisterInputDataChangedCallback(input_changed_callback_t callback);
输入 PDO 数据发生变化时通知。DLL 层自动检测每个从站的输入数据变化,仅当输入数据与上一周期不同时触发回调。
回调类型:
typedef void (*input_changed_callback_t)(uint16_t master_index,
const uint8_t* changed_slave_bits, uint16_t changed_count);
回调参数说明:
master_index(uint16_t) — 主站索引changed_slave_bits(const uint8_t*) — 变化从站位图(每个 bit 对应一个从站,1=变化)changed_count(uint16_t) — 变化的从站数量
零开销
- 无变化时:不触发回调,零性能开销
- 有变化时:通过位图高效传递,一次回调覆盖所有变化从站
示例:
static void on_input_changed(uint16_t mi, const uint8_t* bits, uint16_t count) {
/* 检查从站1是否有变化 (从站索引 1-based, bit 0 = 从站1) */
if (bits[0] & 0x01) {
/* 读取从站1的输入数据 */
uint16_t status = dll.PDOReadInputU16(mi, 1, 0);
printf("从站1 状态字变化: 0x%04X\n", status);
}
}
PreOP 重配置
void RegisterSlavePreOpReconfigCallback(preop_reconfig_callback_t callback);
从站需要 PreOP 重配置时通知(热插拔后自动恢复)。
回调类型:
typedef void (*preop_reconfig_callback_t)(uint16_t master_index, uint16_t slave_index);
线程安全
同步 vs 异步回调
同步回调 (*Sync) 在实时 PDO 线程中直接执行,不要执行耗时操作(如文件IO、网络请求、锁竞争)。
异步回调 (*Async) 在独立线程中执行,延迟略高但更安全。
回调中避免执行耗时操作。如需处理大量数据,将数据放入队列异步处理:
static void on_state_sync(uint16_t mi, uint16_t si, int old_s, int new_s) {
/* 快速入队,不做耗时操作 */
enqueue_event(mi, si, old_s, new_s);
}
完整示例
#define DYNAMIC_LOAD
#include "ethercat.h"
#include <stdio.h>
/* ===== 状态事件 ===== */
static void on_state(uint16_t mi, uint16_t si, int old_s, int new_s) {
printf("从站 %d 状态变化: %d -> %d\n", si, old_s, new_s);
}
/* ===== 热插拔事件 ===== */
static void on_discovery(uint16_t mi, uint16_t si, BOOL found) {
printf("从站 %d %s\n", si, found ? "上线" : "离线");
}
/* ===== 紧急消息事件 ===== */
static void on_emcy(uint16_t mi, uint16_t si,
uint16_t code, uint16_t reg, uint8_t b1, uint16_t w1, uint16_t w2) {
printf("从站 %d 紧急消息: 错误码=0x%04X, 寄存器=0x%04X\n", si, code, reg);
}
/* ===== DC 同步丢失事件 ===== */
static void on_dc_sync_lost(uint16_t mi, uint16_t si, int diff_ns) {
printf("从站 %d DC 同步丢失: 偏差 %d ns\n", si, diff_ns);
}
/* ===== 输入数据变化事件 ===== */
static void on_input_changed(uint16_t mi, const uint8_t* bits, uint16_t count) {
printf("输入数据变化: %d 个从站\n", count);
}
/* ===== PreOP 重配置事件 ===== */
static void on_preop_reconfig(uint16_t mi, uint16_t si) {
printf("从站 %d 需要 PreOP 重配置\n", si);
}
int main(void) {
dll_t dll;
LOAD_DLL(&dll, "Darra.Core.dll");
/* 注册所有从站事件回调 */
if (dll.RegisterStateChangeSync) dll.RegisterStateChangeSync(on_state);
if (dll.RegisterDiscoverySync) dll.RegisterDiscoverySync(on_discovery);
if (dll.RegisterEmergency) dll.RegisterEmergency(on_emcy);
if (dll.SetDCSyncLostCallback) dll.SetDCSyncLostCallback(on_dc_sync_lost);
if (dll.RegisterInputChanged) dll.RegisterInputChanged(on_input_changed);
if (dll.RegisterPreOpReconfig) dll.RegisterPreOpReconfig(on_preop_reconfig);
uint16_t master = dll.Initialize();
dll.SetNetwork(master, "\\Device\\NPF_{...}", "");
dll.SetStateSequence(master, EC_STATE_OPERATIONAL, 10000);
dll.Start(master);
printf("按回车退出...\n");
getchar();
dll.Stop(master);
dll.Dispose(master);
UNLOAD_DLL(&dll);
return 0;
}