跳到主要内容

从站事件

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

事件自动路由

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

协议专属事件

FSoE 安全事件通过 FsoeManager 订阅,请参考 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 同步丢失
输入数据变化slave.events().on_input_changed()输入 PDO 数据变化(原生检测)

从站状态事件

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_event() 自动路由。

回调参数:

// 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);
});

输入数据变化

on_input_changed

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

从站输入 PDO 数据变化时触发。仅当输入数据与上一周期不同时回调。由 master.events().on_input_data_changed() 自动路由。

零开销
  • 无变化时:不触发回调,零性能开销
  • 有变化时:仅变化的从站收到回调,其他从站不受影响

示例:

slave.events().on_input_changed(|| {
let position = slave.read_input_i32(2);
println!("位置变化: {}", position);
});

线程安全

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

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

let position = Arc::new(Mutex::new(0i32));
let pos_clone = position.clone();

slave.events().on_input_changed(move || {
let actual = slave.read_input_i32(2);
*pos_clone.lock().unwrap() = actual;
});
注意

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

use std::sync::mpsc;

let (tx, rx) = mpsc::channel();
slave.events().on_input_changed(move || {
let pos = slave.read_input_i32(2);
let _ = tx.send(pos); // 快速发送
});

完整示例

use 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);
});

// ===== 输入数据变化 =====
slave.events().on_input_changed(|| {
let position = slave.read_input_i32(2);
println!("位置: {}", position);
});