Slave API
通过 master.slave(n) 获取从站句柄 (1-based 索引),或通过 master.slaves() 获取所有从站。
快速开始
索引访问
let slave = master.slave(1); // 第1个从站 (1-based)
let count = master.slave_count(); // 从站总数 (u16)
let all = master.slaves(); // 所有从站 Vec<Slave>
标识访问
let name: String = slave.name(); // 设备名称
let drive_name: String = slave.drive_name(); // 驱动名称 (SDO 0x1008)
let vendor_id: u32 = slave.vendor_id(); // 厂商 ID
let product_id: u32 = slave.product_id(); // 产品 ID
let revision: u32 = slave.rev_id(); // 修订号
let serial: u32 = slave.serial_number(); // 序列号
地址访问
let addr: u16 = slave.config_addr(); // 物理配置地址
let alias: u16 = slave.alias_address(); // 别名地址
// 按地址查找
let target = master.slaves().iter()
.find(|s| s.config_addr() == 0x1001);
组访问
// 查询从站所在组
let group: u8 = slave.group();
// 查询组内从站数
let group_count = master.group_slave_count(1);
提示
组相关属性详见 从站分组。
协议访问
| 协议 | 方法 | 说明 |
|---|---|---|
| SDO | slave.sdo_read_value::<T>() / sdo_write_value() | 类型化 SDO 读写 |
| OD 树 | OdList::load(master_idx, slave_idx) | 对象字典遍历 |
| CiA 402 | CiA402Instance::new(master_idx, slave_idx, pdo_map) | 独立构造伺服驱动器实例 |
| SoE | slave.soe() | Servo over EtherCAT |
| FoE | slave.foe() | File over EtherCAT |
| EoE | slave.eoe() | Ethernet over EtherCAT |
| AoE | slave.aoe() | ADS over EtherCAT |
| VoE | slave.voe() | Vendor over EtherCAT |
| FSoE | FsoeManager / FsoeMdp | 功能安全协议 (独立构造) |
| MDP | mdp_discover() | 模块化设备发现 (模块级函数) |
| DC | slave.dc() | DC 同步配置 |
PDO 数据读写
io(&self) -> Result<(i32, *mut u8, i32, *mut u8)> 获取 IO 映射指针和大小, 返回
(输出字节数, 输出指针, 输入字节数, 输入指针)。除原始字节与结构体映射外, SDK 还支持按类型
直接读写 PDO, 无需定义结构体, 详见 PDO 输入输出。
let slave = master.slave(1);
let (out_size, _out_ptr, in_size, _in_ptr) = slave.io()?;
println!("输出 {} 字节, 输入 {} 字节", out_size, in_size);
// 按类型读取输入 PDO (offset 为字节偏移量, 直接返回值)
let bits: u8 = slave.read_input_u8(0); // 数字输入
let status: u16 = slave.read_input_u16(2); // StatusWord
let position: i32 = slave.read_input_i32(4); // ActualPosition
let torque: i16 = slave.read_input_i16(8); // ActualTorque
// 按类型写入输出 PDO (offset 为字节偏移量, 无返回值)
slave.write_output_u8(0, 0xFF); // 数字输出
slave.write_output_u16(2, 0x000F); // ControlWord
slave.write_output_i32(4, 100000); // TargetPosition
slave.write_output_i16(8, 500); // TargetTorque
支持的类型: u8 / i8 (1 字节)、u16 / i16 (2 字节)、u32 / i32 / f32 (4 字节)。
SDO 读写示例:
// 类型化读取
let status: u16 = slave.sdo_read_value(0x6041, 0x00)?;
let position: i32 = slave.sdo_read_value(0x6064, 0x00)?;
// 类型化写入
slave.sdo_write_value(0x6040, 0x00, &0x0006u16)?;
// 原始字节读写 (第三个参数: complete_access)
let data = slave.sdo_read(0x1000, 0x00, false)?;
slave.sdo_write(0x6040, 0x00, false, &[0x06, 0x00])?;
EMCY 紧急消息
use ethercat::{emcy_get_count, emcy_get_history, emcy_clear_history};
let count = emcy_get_count(master.index(), 1);
let history = emcy_get_history(master.index(), 1);
for msg in &history {
println!("错误码: 0x{:04X}", msg.error_code);
}
emcy_clear_history(master.index(), 1);
拓扑查询
主站层提供两套拓扑接口, 按使用场景选择:
平铺节点列表 (topology() / topology_build()) — 适用于只需要节点列表 / 子节点 /
根节点的简单查询场景。
let topo = master.topology(); // Vec<TopologyNode>, 第一次构建后缓存
let topo2 = master.topology_build(); // 强制重建 (重新扫描后调用)
let children = master.topology_get_children(1); // 直接子节点 Vec<u16>
let roots = master.topology_get_roots(); // 根节点 Vec<u16>
高级 SlaveTopology 对象 (slave_topology()) — 返回封装好的 SlaveTopology 实例,
内部一次扫描后构建 parent/children 双向索引, 支持深度计算 / 路径查找 / 按地址查询等结构化
遍历。适合需要在拓扑树上做多次查询的工具型代码 (如 IDE 拓扑图、配置导出器)。
pub fn slave_topology(&self) -> SlaveTopology
let topo = master.slave_topology();
topo.nodes(); // &[TopologyNode] — 全部节点
topo.count(); // usize — 节点数
topo.root_slaves(); // &[u16] — 根从站列表
topo.children(parent_idx); // &[u16] — 子从站索引
topo.child_count(parent_idx);// usize — 子节点数
topo.get(slave_index); // Option<&TopologyNode>
topo.get_by_address("0x1001"); // Option<&TopologyNode>, 支持 hex / dec
topo.parent_of(slave_index); // Option<u16>
topo.depth(slave_index); // u32 — 到根节点距离
何时用哪个
- 快速查询根 / 子节点 →
topology_get_children/topology_get_roots - 构建拓扑可视化 / 多次结构化查询 →
slave_topology(), 一次构建复用 - 重新扫描后 →
topology_build()或重新调用slave_topology()
启动参数 (add_startup_parameter / clear_startup_parameters):
// 添加启动参数
slave.add_startup_parameter(
0x1C12, 0x00, // 索引, 子索引
&[0x00], // 数据
TRANS_IP, // Init -> PreOp 转换时
TIMING_BEFORE, // 转换前执行
false, // 非 Complete Access
);
// 清除所有启动参数
slave.clear_startup_parameters();