跳到主要内容

从站事件

通过 slave.events() 访问。事件参数已过滤到当前从站,签名简洁。

事件自动路由

主站级 DLL 回调会自动路由到对应从站的 slave.events()。订阅从站事件无需 master_index/slave_index 参数,系统已自动过滤到当前从站。

协议专属事件

FSoE 安全事件 (状态变化 / 错误 / 失效安全 / 安全数据更新) 通过 FsoeEventCallbacks 结构体注册(set_on_state_changed / set_on_error / set_on_failsafe / set_on_safe_data_updated),连接管理用 SafetyManager,请参考 FSoE

功能概览

类别事件 / 方法说明
从站状态事件slave.events().on_state_changed()从站 EtherCAT 状态变化
slave.events().on_emergency()CoE Emergency 紧急消息
slave.events().on_offline()从站离线(热插拔断开)
slave.events().on_online()从站上线(热插拔恢复)
slave.events().on_dc_sync_lost()DC 同步丢失

从站状态事件

on_state_changed

slave.events().on_state_changed(|old_state, new_state| { });
// Fn(i32, i32)

从站 EtherCAT 状态变化时触发。由 master.events().on_slave_state_changed() 自动路由。

示例:

slave.events().on_state_changed(|old_state, new_state| {
println!("状态变化: {:?} → {:?}", old_state, new_state);
});

on_emergency

slave.events().on_emergency(|error_code, error_reg, b1, w1, w2| { });
// Fn(u16, u16, u8, u16, u16)

CoE Emergency 紧急消息。由 master.events().on_emergency() 自动路由。

回调参数:

// Fn(u16, u16, u8, u16, u16)
error_code: u16, // 错误代码(CANopen Emergency Error Code)
error_reg: u16, // 错误寄存器(对象 0x1001)
b1: u8, // 制造商特定数据(字节 3)
w1: u16, // 制造商特定数据(字节 4-5)
w2: u16, // 制造商特定数据(字节 6-7)

示例:

slave.events().on_emergency(|error_code, _error_reg, _b1, _w1, _w2| {
println!("紧急消息: 错误码=0x{:04X}", error_code);
});

on_offline

slave.events().on_offline(|| { });
// Fn()

从站离线(热插拔断开)。由 master.events().on_slave_offline() 自动路由。

示例:

slave.events().on_offline(|| {
println!("从站离线");
});

on_online

slave.events().on_online(|| { });
// Fn()

从站上线(热插拔恢复)。由 master.events().on_slave_online() 自动路由。

示例:

slave.events().on_online(|| {
println!("从站上线");
});

on_dc_sync_lost

slave.events().on_dc_sync_lost(|diff_ns| { });
// Fn(i32)

DC 同步丢失。由 master.events().on_dc_sync_lost() 自动路由。

示例:

slave.events().on_dc_sync_lost(|diff_ns| {
println!("DC 同步丢失: 偏差 {}ns", diff_ns);
});

输入数据变化

2026-05-21 架构清理 — 已删除

slave.events().on_input_changed() 已删除。它是主站 on_input_data_changed 机制的从站镜像,旧机制靠 SDK 底层每周期对输入 PDO 做逐字节比对检测变化。PDO 过程数据通路改为纯内核共享内存指针轮询(零拷贝)后,应用层直接读写过程映像,"每周期变化检测 + 回调分发"环节不再驱动。

替代方式: 需感知输入变化时,自行轮询从站输入指针并比对上一周期快照:

let slave = master.slave(1);
let mut last = slave.read_input_i32(2);
loop {
std::thread::sleep(std::time::Duration::from_millis(10));
let now = slave.read_input_i32(2);
if now != last {
println!("从站 1 位置变化: {}", now);
last = now;
}
}

线程安全

事件回调在 PDO 线程上触发,非主线程。在 Rust 中,回调闭包必须满足 Send + 'static 约束。使用共享数据时需要同步:

use std::sync::{Arc, Mutex};

let last_state = Arc::new(Mutex::new(0i32));
let st_clone = last_state.clone();

slave.events().on_state_changed(move |_old, new| {
*st_clone.lock().unwrap() = new;
});
注意

回调中避免执行耗时操作。如需处理大量数据,将数据发送到 channel 异步处理:

use std::sync::mpsc;

let (tx, rx) = mpsc::channel();
slave.events().on_emergency(move |ec, _er, _b1, _w1, _w2| {
let _ = tx.send(ec); // 快速发送
});

完整示例

use darra_ethercat::EcState;

let slave = master.slave(1);

// ===== 从站状态事件 =====
slave.events().on_state_changed(|old, new| {
println!("状态: {:?} → {:?}", old, new);
});

slave.events().on_emergency(|ec, _er, _b1, _w1, _w2| {
println!("紧急消息: 0x{:04X}", ec);
});

slave.events().on_offline(|| println!("从站离线"));
slave.events().on_online(|| println!("从站上线"));

slave.events().on_dc_sync_lost(|diff_ns| {
println!("DC 同步丢失: {}ns", diff_ns);
});

// 注: on_input_changed 已于 2026-05-21 删除 — PDO 通路改为纯内核共享内存指针轮询,
// 需感知输入变化请轮询从站输入指针并比对上一周期快照。