跳到主要内容

属性与状态机

提示

属性

类别方法类型读写说明
基本信息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() 拿回结果。

参数:

返回值:

  • 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,与配置一致)

返回值:

  • booltrue=已接受并复位 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_online 的区别
  • on_slave_offline — 从站断电/断线(身份仍匹配)→ 自动恢复,触发 on_slave_online
  • on_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) — 是否比对 RevisionID
  • check_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 循环 → 关闭网卡 → 释放底层句柄). 不调用本方法时, EtherCATMasterDrop 时会自动执行同等清理。

何时显式调用:

  • 进程长期运行, 需在某个明确节点回收资源 (例如重启网卡)
  • 在 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 再次确认 (幂等)
不要在 panic hook 里调用 dispose

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)?;
与 validate_config 的区别

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);
实际 WKC 与组诊断

当前实现未提供 group_actual_wkc() / group_diag(), 实际 WKC 通过 master.diagnostics_info() 在主站级聚合; 组级偏差可通过 pdo_frame_loss_stats(group) 间接观测。