属性与状态机
属性
| 类别 | 方法 | 类型 | 读写 | 说明 |
|---|---|---|---|---|
| 基本信息 | index() | u16 | 只读 | 主站实例索引 |
| master_number() | u16 | 只读 | index() 的别名 | |
| slave_count() | u16 | 只读 | 网络中检测到的从站数量 | |
| slaves() | Vec<Slave> | 只读 | 从站句柄列表 | |
| slave(n) | Slave | 只读 | 获取指定索引的从站句柄 (1-based) | |
| 网络与链路 | primary_network_info() | Option<NetworkInfo> | 只读 | 主网络适配器信息 |
| redundant_network_info() | Option<NetworkInfo> | 只读 | 冗余网络适配器信息 | |
| link_state() | LinkState | 只读 | 网络链路状态 | |
| link_status() | LinkState | 只读 | link_state() 的别名 | |
| 错误码 | error_code() | EcALState | 只读 | 异常时的自动报警错误码(从站级属性,通过 slave.error_code() 访问) |
| 从站分组 | group_slave_count(u8) | u16 | 只读 | 获取指定组的从站数量 |
| active_group_count() | u8 | 只读 | 活跃组数量(映射后有效) | |
| IO 映射 | obytes() | u32 | 只读 | 总输出字节数 |
| ibytes() | u32 | 只读 | 总输入字节数 | |
| obits() | u16 | 只读 | 总输出位数 | |
| ibits() | u16 | 只读 | 总输入位数 | |
| DC 与周期 | has_dc() | bool | 只读 | 网络中是否有支持 DC 的从站 |
| 运行时 | state() | EcState | 只读 | 主站当前 EtherCAT 状态 |
| expected_wkc() / set_expected_wkc(u16) | u16 | 读写 | 期望的工作计数器 |
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LinkState {
Disconnected = 0, // 无连接
Connected = 1, // 链路正常
Redundancy = 2, // 冗余链路激活
PrimaryOnly = 3, // 仅主网口连接
SecondaryOnly = 4, // 仅冗余网口连接
}
状态机管理
主站状态机仅暴露 2 个公开 API: 同步 set_state 与异步 set_state_async。两者内部都走 ETG 标准状态机链 (Init → PreOp → SafeOp → OP), 自动跨级链式切换并按 transition 应用启动参数, 切换到 SafeOp / Operational 时自动启动 PDO 线程, 默认每步超时 5000 ms。失败原因通过 Result::Err 返回 (见 DarraError)。
state()
pub fn state(&self) -> EcState
读取主站当前 EtherCAT 状态。
相关枚举:
#[repr(u8)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EcState {
None = 0x00,
Init = 0x01,
PreOp = 0x02,
Boot = 0x03,
SafeOp = 0x04,
Operational = 0x08,
}
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EcALState {
NoError = 0x0000, // 无错误
UnspecifiedError = 0x0001, // 未指定错误
NoMemory = 0x0002, // 内存不足
InvalidDeviceSetup = 0x0003, // 无效设备设置
InvalidRevision = 0x0004, // 版本不匹配
SiiEepromMismatch = 0x0006, // SII/EEPROM 不匹配
FirmwareUpdateFailed = 0x0007, // 固件更新失败
LicenseError = 0x000E, // 许可证错误
InvalidStateChange = 0x0011, // 无效状态切换
UnknownRequestedState = 0x0012, // 未知状态请求
BootstrapNotSupported = 0x0013, // 不支持 Bootstrap
NoValidFirmware = 0x0014, // 无有效固件
InvalidMailboxConfig = 0x0015, // 无效邮箱配置 (SM0/SM1)
InvalidSyncManagerConfig = 0x0017, // 无效同步管理器配置
NoValidInputs = 0x0018, // 无有效输入
NoValidOutputs = 0x0019, // 无有效输出
SyncError = 0x001A, // 同步错误
SyncManagerWatchdog = 0x001B, // SM 看门狗
InvalidOutputConfig = 0x001D, // 无效输出配置
InvalidInputConfig = 0x001E, // 无效输入配置
InvalidWatchdogConfig = 0x001F, // 无效看门狗配置
NeedsColdStart = 0x0020, // 需要冷启动
NeedsInit = 0x0021, // 需要 Init
NeedsPreOp = 0x0022, // 需要 PreOp
NeedsSafeOp = 0x0023, // 需要 SafeOp
InvalidInputMapping = 0x0024, // 无效输入映射
InvalidOutputMapping = 0x0025, // 无效输出映射
InconsistentSettings = 0x0026, // 设置不一致
FreerunNotSupported = 0x0027, // 不支持自由运行
SyncNotSupported = 0x0028, // 不支持同步
CycleTimeTooSmall = 0x002E, // 周期时间过小
InvalidDcSyncConfig = 0x0030, // 无效 DC 同步配置
PllError = 0x0032, // PLL 错误
DcSyncIOError = 0x0033, // DC 同步 IO 错误
DcSyncTimeout = 0x0034, // DC 同步超时
MailboxAoe = 0x0041, // AoE 邮箱错误
MailboxCoe = 0x0043, // CoE 邮箱错误
MailboxFoe = 0x0044, // FoE 邮箱错误
MailboxSoe = 0x0045, // SoE 邮箱错误
EepromNoAccess = 0x0050, // EEPROM 无法访问
EepromError = 0x0051, // EEPROM 错误
ExternalHardwareNotReady = 0x0052, // 外部硬件未就绪
SlaveRestarted = 0x0060, // 从站已重启
SupplyVoltageTooLow = 0x0080, // 电压过低
SupplyVoltageTooHigh = 0x0081, // 电压过高
TemperatureTooLow = 0x0082, // 温度过低
TemperatureTooHigh = 0x0083, // 温度过高
Unknown = 0xFFFF, // 未知错误
}
set_state()
pub fn set_state(&mut self, state: EcState) -> Result<(), DarraError>
同步切换主站到目标状态, 阻塞当前线程直到完成或失败。
参数:
state(EcState) — 目标状态 (Init / PreOp / SafeOp / Operational)
返回值:
Ok(())— 已到达state, 若到达SafeOp/Operational则 PDO 线程已启动Err(DarraError::StateChangeFailed(state))— 切换失败, 携带目标状态码; 错误描述可直接Display输出
示例:
master.set_state(EcState::Operational)?;
if master.state() == EcState::Operational {
println!("主站已进入 OP");
}
- 协议层按 EtherCAT 标准状态机流程自动处理中间状态 (跨级一次到位)。
- 请在切换前完成网络配置 / 启动参数导入 / IO 映射构建。
- 内部 3 次重试: SDK 在每步状态切换内部自动执行最多 3 次尝试, 失败之间间隔 1.5 s, 用于吸收硬件 PHY/PLL 抖动等瞬态故障; 业务代码无需再写
for/loop重试包装。 - SafeOp 自动同步配置: 切换到
SafeOp时, SDK 按 ETG 标准为非 DC 从站自动配置同步循环计数阈值与 SyncManager 同步类型 (FreeRun 兜底), 提升大网络/混合厂商场景下的进入 OP 成功率; 用户无需手动写这些对象。如需自定义同步策略, 应在切到SafeOp之后再覆盖。 - SDO 时机: PreOp 进入后即可调用
slave.sdo_read/slave.sdo_write, 不必等 SafeOp; 启动参数也通常挂在PS(PreOp → SafeOp) 之前。
set_state_async()
pub fn set_state_async(&self, state: EcState) -> JoinHandle<Result<(), DarraError>>
异步切换主站状态, 在新线程中执行同步 set_state 等价逻辑, 不阻塞调用线程。返回标准库 std::thread::JoinHandle, 由调用方在合适时机 .join() 拿回结果。
参数:
state(EcState) — 目标状态
返回值:
JoinHandle<Result<(),DarraError>>— 工作线程句柄,.join()后得到内层Result; 错误语义与set_state一致
示例:
let handle = master.set_state_async(EcState::Operational);
// 主线程继续刷新 UI / 处理其他事件
ui_tick();
// 在合适节点收回结果
match handle.join().unwrap() {
Ok(()) => println!("主站已进入 OP"),
Err(e) => eprintln!("状态切换失败: {}", e),
}
start() / stop() / abort_scan()
pub fn start(&mut self)
pub fn stop(&mut self)
pub fn abort_scan()
start() / stop() 启动/停止 PDO 循环线程, start() 需要 &mut self,
stop() 返回后主站切换到 PRE_OP 状态;
abort_scan() 中断 DLL 层所有阻塞操作 (如 set_state()、构建器中的 set_network() 等),
可安全地从任意线程调用。
示例:
master.start();
// ... PDO 通信运行中
master.stop();
// 用户点击取消按钮时中断正在进行的状态切换
EtherCATMaster::abort_scan();
过程数据看门狗
set_all_slave_watchdog()
pub fn set_all_slave_watchdog(&self, timeout_ms: u32)
批量设置所有从站的过程数据看门狗超时。
单个从站的看门狗配置请使用 slave.set_watchdog()。
示例:
master.set_all_slave_watchdog(100); // 100ms 超时
set_all_slave_pdi_watchdog()
pub fn set_all_slave_pdi_watchdog(&self, timeout_ms: u32)
批量设置所有从站的 PDI 看门狗超时。
单个从站的看门狗配置请使用 slave.set_pdi_watchdog()。
示例:
master.set_all_slave_pdi_watchdog(100); // 100ms 超时
诊断控制方法
reset_diagnostics()
pub fn reset_diagnostics(&self)
重置主站诊断计数器。
reset_slave_port_error_counters()
pub fn reset_slave_port_error_counters(&self, slave_index: u16) -> bool
重置指定从站的端口错误计数器。
参数:
slave_index(u16) — 从站索引(1-based)
返回值:
bool— 成功返回true
诊断模块的 reset() 会同时重置主站诊断统计、所有从站端口错误计数器和 PDO 丢帧统计。
热插拔自修复
在断电重插/更换从站的场景下,SDK 自动识别身份不符并进入保护状态,避免错误设备被误纳入控制循环。事件流程见 on_slave_identity_mismatch 事件。
acknowledge_slave_replacement(slave_num)
pub fn acknowledge_slave_replacement(&self, slave_num: u16) -> bool
用户确认从站替换完毕,触发 EtherCAT 识别状态机重新探测该从站。
调用时机: 订阅 on_slave_identity_mismatch 接收到身份不符报警后,操作员检查/更换设备完毕,调用本方法让 SDK 重新检测。
行为:
- 若身份已纠正(换回正确设备 / 同型号升级 Revision)→ 自动恢复并触发
on_slave_online事件 - 若身份仍不匹配 → 再次触发
on_slave_identity_mismatch,回到IDENT_REJECTED状态
参数:
slave_num(u16) — 从站编号(1-based,与配置一致)
返回值:
bool—true=已接受并复位 FSM;false=参数无效,或从站当前不在IDENT_REJECTED/FAILED状态(在收到on_slave_identity_mismatch事件之前调用返回false)
在 on_slave_identity_mismatch 事件触发之前调用本方法无效。从站未进入保护状态时 SDK 会持续正常探测,无需手动确认。
示例:
let master_handle = master.clone(); // 假设使用 Arc<EtherCATMaster> 共享
master.events().on_slave_identity_mismatch(move |args| {
println!("从站 {} 身份不符: 期望 Vendor=0x{:08X}, 实际 Vendor=0x{:08X}",
args.slave_index, args.expected_vendor, args.actual_vendor);
// UI 弹窗: "请检查从站 N 的设备, 换回正确型号后点击确认"
if show_replacement_dialog(args.slave_index) {
let ok = master_handle.acknowledge_slave_replacement(args.slave_index);
if !ok {
println!("确认失败: 从站不在 IDENT_REJECTED 状态");
}
}
});
on_slave_offline— 从站断电/断线(身份仍匹配)→ 自动恢复,触发on_slave_onlineon_slave_identity_mismatch— 从站身份变了(换错设备 / 换同型号旧版本固件)→ 手动调acknowledge_slave_replacement
以下方法补充覆盖配置加载、配置验证、工作计数器、生命周期、冗余与组分频器等场景。
load_config_json()
pub fn load_config_json(&self, json: &str) -> Result<()>
从 JSON 字符串一次性加载主站 / 从站配置, 包括启动参数 (Startup Parameter, 写入 0x1C12 / 0x1C13 PDO 映射 / SDO 启动写入等). 适合在工程师电脑导出配置后, 在现场服务侧统一灌入。
参数:
json(&str) — 配置 JSON 字符串, UTF-8 编码
返回值:
Result<()>— 成功Ok(()); 失败Err(DarraError::ConfigLoadFailed(code)),code来自底层返回
JSON 顶层结构:
// 字段语义说明 (示意代码块, 实际为 JSON):
// {
// "master": {
// "loop_cycle_ns": 1000000, // PDO 周期 (纳秒)
// "frame_repeat_count": 1, // 帧重复次数 1~3
// "scan_revision_match": 2 // 0=精确 / 1=兼容 / 2=忽略
// },
// "slaves": [
// {
// "slave_num": 1, // 从站编号 1-based
// "group": 0, // 分组号 0~7
// "is_optional": false, // 可选从站
// "startup_parameters": [
// {
// "od_index": 6010, // SDO 索引 (十进制 / 十六进制均可)
// "sub_index": 0,
// "data": [15, 0], // 字节数组 (小端)
// "transition": "PS", // 转换点: IP/PS/PI/SP/SO/OS
// "timing": "before", // before / after
// "complete_access": false
// }
// ]
// }
// ]
// }
示例:
let json = std::fs::read_to_string("config.json")?;
master.load_config_json(&json)?;
master.set_state(EcState::Operational)?;
add_startup_parameter 的关系本方法是 slave.add_startup_parameter() 的批量持久化形式 — JSON 中的每个 startup_parameters 条目, 等价于一次 add_startup_parameter() 调用. 适合配置可重复部署的场景。
auto_configure_sm(&self, slave_index: u16) -> Result<i32> — 自动配置指定从站的 SM,
通常在加载配置后由内部调用, 不需手动调用。
validate_config()
pub fn validate_config(&self) -> Result<i32>
验证当前主站配置是否完整可用. 检查内容包括: 网络已设置 / ENI 已加载 (若使用) / 至少扫描到一个从站 / IO 映射布局已就绪. 通常在 set_state(EcState::Operational) 之前调用一次, 用于在进入实时阶段前快速发现配置缺漏。
参数: 无
返回值:
Ok(n)— 校验通过,n为参与校验的从站数量Err(DarraError::Other)— 校验失败, 错误消息中带有底层返回码
示例:
match master.validate_config() {
Ok(n) => println!("配置校验通过, 共 {} 个从站", n),
Err(e) => {
eprintln!("配置校验失败: {}", e);
return Err(e.into());
}
}
master.set_state(EcState::Operational)?;
verify_all_slave_identities()
pub fn verify_all_slave_identities(
&self,
expected: &[SlaveIdentity],
check_revision: bool,
check_serial: bool,
) -> Result<u64>
按期望身份数组逐个比对在线从站的 VendorID / ProductID / RevisionID / SerialNumber. 用于上线前 / 维护后的硬件清单核对, 防止接错从站。
参数:
expected(&[SlaveIdentity]) — 期望身份数组, 索引 0 对应从站 1, 索引 1 对应从站 2, 依次类推check_revision(bool) — 是否比对 RevisionIDcheck_serial(bool) — 是否比对 SerialNumber
返回值:
Ok(0)— 全部匹配Ok(mask)— 第 N 位 = 1 表示从站 N (1-based) 不匹配Err(DarraError::Other)— 调用本身失败 (索引非法 / 从站未上线等)
相关结构:
#[repr(C)]
pub struct SlaveIdentity {
pub vendor_id: u32,
pub product_id: u32,
pub revision_id: u32,
pub serial_number: u32,
}
示例:
let expected = vec![
SlaveIdentity { vendor_id: 0x00000002, product_id: 0x044C2C52, revision_id: 0x00120000, serial_number: 0 },
SlaveIdentity { vendor_id: 0x00000002, product_id: 0x07D43052, revision_id: 0x00110000, serial_number: 0 },
];
let mismatch = master.verify_all_slave_identities(&expected, true, false)?;
if mismatch == 0 {
println!("硬件清单一致");
} else {
for i in 1..=64u16 {
if (mismatch >> i) & 1 == 1 {
eprintln!("从站 {} 身份不匹配", i);
}
}
}
当 verify_all_slave_identities() 报告身份不符且对应从站随后触发 on_slave_identity_mismatch 事件, 操作员更换设备后调用 acknowledge_slave_replacement() 让 SDK 重新探测。
expected_wkc() / set_expected_wkc()
pub fn expected_wkc(&self) -> u16
pub fn set_expected_wkc(&self, expected_wkc: u16)
读取 / 写入主站的全局期望工作计数器 (Expected Working Counter). EtherCAT 每个 PDO 周期返回的 WKC 应等于此值, 不等表示部分从站未响应或邮箱繁忙。
实现细节:
- IO 映射 (
build()) 完成后, 主站会按"读 ×1 + 写 ×2 + 读写 ×3"的 ETG.1500 规则自动计算并写入expected_wkc, 通常无需手动设置。 - 仅在使用了不带 LRW 的特殊场景 (例如自定义降级模式 / 仅诊断) 时, 才需要手动覆盖。
- 实际 WKC 通过
master.diagnostics_info().wkc()读取, 或通过on_pdo_frame_loss事件感知偏差。
示例:
// 启动后核对自动计算结果
master.set_state(EcState::Operational)?;
let expected = master.expected_wkc();
println!("Expected WKC = {}", expected);
// 进入诊断模式后手动锁定 (按需)
master.set_expected_wkc(expected);
set_group_cycle_divider(&self, group: u8, divider: u8) -> bool — 设置组循环分频器,
让指定从站组以 PDO 主周期的整数倍频率运行, 通常用于慢速 IO 与高速运动并存的网络。
dispose()
pub fn dispose(&mut self)
显式释放主站资源 (停止 PDO 循环 → 关闭网卡 → 释放底层句柄). 不调用本方法时, EtherCATMaster 在 Drop 时会自动执行同等清理。
何时显式调用:
- 进程长期运行, 需在某个明确节点回收资源 (例如重启网卡)
- 在 panic hook / Ctrl+C handler 中需立即关闭网卡, 此场景推荐使用
EtherCATMaster::emergency_cleanup()静态方法
已释放状态判断:
Rust SDK 不暴露独立的 is_disposed() 查询方法. 释放状态由所有权语义保证:
- 调用
dispose()后, 同一个&mut master上的其他方法仍可调用, 但底层句柄已无效, 大部分方法会返回错误或默认值 - 推荐做法是调用
dispose()后立即drop(master);, 由编译期保证不会再访问已释放对象
示例:
{
let mut master = EtherCATMaster::new()?;
master.set_network("\\Device\\NPF_{...}", "")?;
master.set_state(EcState::Operational)?;
master.start();
// ... 业务逻辑 ...
master.stop();
master.dispose(); // 显式释放
} // master 离开作用域, Drop 再次确认 (幂等)
dispose() 会等待 PDO 线程退出, panic 路径推荐 EtherCATMaster::emergency_cleanup() 直接关闭网卡, 防止网卡句柄泄漏。
冗余相关方法 (详见 冗余):
| 方法 | 返回类型 | 说明 |
|---|---|---|
| enable_redundancy(bool) | Result<()> | 启用/禁用冗余 |
| force_redundancy_failover() | Result<()> | 强制冗余故障切换 |
| check_redundancy_health() | bool | 检查冗余健康状态 |
| ring_mode() | i32 | 获取环拓扑冗余模式 |
| secondary_link_status() | bool | 获取冗余链路状态 |
静态紧急/扫描控制方法
主站结构体之外, SDK 提供一组无需实例的全局工具函数, 适合 panic hook、Ctrl+C handler、独立扫描线程等场景。
emergency_cleanup()
pub fn emergency_cleanup()
紧急释放所有主站资源 (直接关闭所有 pcap/WDK 网卡句柄, 不依赖主站对象状态, 不等待线程退出)。在进程崩溃 / 用户强制退出时调用, 防止 Npcap 句柄泄漏导致下次无法打开网卡。对应 C# EmergencyCleanup() 静态方法。
示例:
std::panic::set_hook(Box::new(|info| {
eprintln!("Panic: {}", info);
EtherCATMaster::emergency_cleanup();
}));
ctrlc::set_handler(|| {
eprintln!("\nCtrl+C 收到, 关闭网卡");
EtherCATMaster::emergency_cleanup();
std::process::exit(0);
}).ok();
emergency_close_nics()
pub fn emergency_close_nics()
emergency_cleanup 的同义直名, 直接调用 EmergencyCloseNics DLL 入口, 行为完全一致。
abort_scan() / reset_scan_abort()
pub fn abort_scan()
pub fn reset_scan_abort()
中断 / 复位正在进行的网络扫描。abort_scan() 安全跨线程, 用于打断 set_state / set_network 等阻塞操作; 之后必须 reset_scan_abort() 才能重新启动扫描。
示例:
// UI 线程触发: 用户点击"取消扫描"
EtherCATMaster::abort_scan();
// 扫描线程结束后, 准备下一轮扫描
EtherCATMaster::reset_scan_abort();
state::abort() / state::reset_abort()
pub fn abort()
pub fn reset_abort()
来自 crate::master::state 模块, 中断 DLL 层所有阻塞操作 (含 set_state、构建器中的 set_network 等), 跨线程安全。abort_scan 仅打断扫描循环, abort() 影响范围更大。
启动配置校验
state::verify_startup_configuration(master_index)
pub fn verify_startup_configuration(master_index: u16) -> StartupVerifyResult
检查链路状态、逐从站 AL 状态码、配置验证, 在状态机推进到 Operational 前一次性发现配置缺漏。对应 C# VerifyStartupConfiguration。
返回结构:
#[derive(Debug, Clone)]
pub struct StartupVerifyResult {
/// 整体是否有效
pub valid: bool,
/// 在线从站数
pub slave_count: u16,
/// 问题描述列表 (空=完全通过)
pub issues: Vec<String>,
}
示例:
use ethercat::master::state::verify_startup_configuration;
let r = verify_startup_configuration(master.index());
if !r.valid {
eprintln!("启动校验失败 (从站数 {}):", r.slave_count);
for issue in &r.issues {
eprintln!(" - {}", issue);
}
return Err("无法进入 OP".into());
}
master.set_state(EcState::Operational)?;
master.validate_config() 校验主站层配置完整性 (网络 / ENI / IO 映射), 走 DLL ec_validate_config; verify_startup_configuration 还会逐从站检查 AL Status Code, 适合在 Init→PreOp→SafeOp→OP 之间任一阶段做诊断点。
主站全局诊断快照
other::get_diagnostics(master_index, slave_count)
pub fn get_diagnostics(master_index: u16, slave_count: u16) -> Option<SlaveDiagnosticsData>
一次性拉取所有从站链路质量 / 端口错误合计 / 链路丢失计数, 形成全网诊断快照 (索引 1-based)。slave_count = 0 时返回 None。对应 C# DarraEtherCAT.GetDiagnostics()。
返回结构:
pub struct SlaveDiagnosticsData {
/// 各从站链路质量百分比 (0-100), 索引 = 从站编号 (1-based)
pub link_quality_percent: Vec<u32>,
/// 各从站端口错误合计 (Rx + Invalid Frame)
pub port_error_count: Vec<u32>,
/// 各从站链路丢失计数
pub lost_link_count: Vec<u32>,
/// 帧错误数 / 丢失帧数 / 校验和错误 / 超时帧数
pub frame_errors: u32,
pub lost_frames: u32,
pub checksum_errors: u32,
pub timeout_frames: u32,
/// 主端口 / 副端口错误计数
pub primary_port_errors: u32,
pub secondary_port_errors: u32,
}
示例:
use ethercat::master::other::get_diagnostics;
if let Some(diag) = get_diagnostics(master.index(), master.slave_count()) {
for i in 1..=master.slave_count() as usize {
println!("从站 {}: 链路质量 {}%, 端口错误 {}, 链路丢失 {}",
i,
diag.link_quality_percent[i],
diag.port_error_count[i],
diag.lost_link_count[i]);
}
}
全局日志初始化
other::initialize_logging(log_callback, crash_callback)
pub fn initialize_logging(
log_callback: Option<crate::utils::ffi::LogCallback>,
crash_callback: Option<crate::utils::ffi::CrashNotifyCallback>,
)
注册全局日志回调与崩溃通知回调, 同时关闭 PDO/邮箱/调试日志默认开关。建议在主站 new() 之前调用一次。对应 C# InitializeLogging。
other::enable_pdo_logging / enable_mailbox_logging / enable_debug_logging
pub fn enable_pdo_logging(enable: bool)
pub fn enable_mailbox_logging(enable: bool)
pub fn enable_debug_logging(enable: bool)
按需打开三类日志开关, 默认全部关闭。EtherCATMaster::set_pdo_logging / set_mailbox_logging / set_debug_logging / close_debug_log 是等价的实例 API。
示例:
use ethercat::master::other;
other::initialize_logging(Some(my_log_cb), Some(my_crash_cb));
other::enable_mailbox_logging(true); // 仅打开邮箱日志
other::enable_debug_logging(false); // 关闭调试日志
拓扑重建
rebuild_topology()
pub fn rebuild_topology(&self) -> crate::slave::topology::SlaveTopology
重新扫描并构建网络拓扑结构, 等价于 slave_topology() 但语义上明确表达"刷新缓存"意图, 适合在热插拔事件后调用。
示例:
master.events().on_slave_online(|args| {
println!("从站 {} 上线, 重建拓扑", args.slave_index);
});
let topo = master.rebuild_topology();
println!("拓扑节点数: {}", topo.node_count());
组级 WKC 与诊断
主站对每个 PDO 组都维护独立的期望 / 实际 WKC 与从站数, 可按组诊断局部问题。
| 方法 | 返回类型 | 说明 |
|---|---|---|
| active_group_count() | u8 | 当前活跃组数量 (映射后有效) |
| group_slave_count(group: u8) | u16 | 指定组从站数量 |
| group_expected_wkc(group: u8) | u16 | 指定组期望 WKC |
| set_group_cycle_divider(group: u8, divider: u8) | bool | 设置组周期分频器 |
| set_group_enabled(group: u8, enabled: bool) | bool | 启用 / 禁用组 |
| get_group_enabled(group: u8) | bool | 查询组启用状态 |
示例:
let n = master.active_group_count();
println!("活跃组数: {}", n);
for g in 0..n {
let slaves = master.group_slave_count(g);
let exp = master.group_expected_wkc(g);
println!("组 {}: 从站 {}, 期望 WKC = {}", g, slaves, exp);
}
// 慢速 IO 组 1: 主周期 4 倍
master.set_group_cycle_divider(1, 4);
当前实现未提供 group_actual_wkc() / group_diag(), 实际 WKC 通过 master.diagnostics_info() 在主站级聚合; 组级偏差可通过 pdo_frame_loss_stats(group) 间接观测。