//! EtherCAT 主站安全封装
//!
//! 提供 EtherCATMaster 结构体，RAII 管理主站生命周期。
//! Drop 时自动调用 Stop + Dispose 释放资源。
//!
//! 支持两种初始化方式:
//! 1. 直接方式: `EtherCATMaster::new()` + `set_network()` + `set_state_sequence()`
//! 2. 构建器方式: `MasterBuilder::new().set_eni("config.xml").build()`

use crate::data::error::{DarraError, EcState, LinkState, Result};
use crate::utils::ffi::{self, TopologyNode, MasterIdentity, MasterDiagData, SlaveIdentity};
use crate::slave::core::Slave;
use crate::statics::network::NetworkInfo;
use std::ffi::{CStr, CString};
use std::os::raw::c_int;
use std::ops::Deref;
use std::ptr::NonNull;

/// EtherCAT 主站 (RAII)
///
/// 封装一个主站实例的完整生命周期:
/// Initialize -> SetNetwork -> SetStateSequence -> Start -> ... -> Stop -> Dispose
///
/// Drop 时自动释放资源。
pub struct EtherCATMaster {
    /// 主站索引
    index: u16,
    /// 是否已启动 PDO 循环
    started: bool,
    /// 是否拥有资源 (防止 move 后双重释放)
    owned: bool,
}

impl EtherCATMaster {
    /// 初始化一个新的主站实例
    pub fn new() -> Result<Self> {
        let index = unsafe { ffi::Initialize() };
        if index == 0xFFFF {
            return Err(DarraError::AlreadyInitialized);
        }
        Ok(Self { index, started: false, owned: true })
    }

    /// 初始化指定索引的主站实例
    pub fn with_index(master_index: u16) -> Result<Self> {
        let index = unsafe { ffi::InitializeSpecificMaster(master_index) };
        if index == 0xFFFF {
            return Err(DarraError::AlreadyInitialized);
        }
        Ok(Self { index, started: false, owned: true })
    }

    /// 一步初始化: JSON 配置 -> Initialize + SetNetwork + SetState + Start
    pub fn from_json(json_config: &str) -> Result<Self> {
        // 错误信息文本 obfstr 编译期 XOR 混淆 (反编译看不到明文)
        let c_json = CString::new(json_config)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("JSON 包含空字节").into()))?;
        let index = unsafe { ffi::EcInit(c_json.as_ptr()) };
        if index == 0xFFFF {
            return Err(DarraError::ConfigLoadFailed(-1));
        }
        Ok(Self { index, started: true, owned: true })
    }

    /// 一步初始化: 从 JSON 文件路径
    pub fn from_json_file(path: &str) -> Result<Self> {
        let c_path = CString::new(path)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("路径包含空字节").into()))?;
        let index = unsafe { ffi::EcInitFromFile(c_path.as_ptr()) };
        if index == 0xFFFF {
            return Err(DarraError::ConfigLoadFailed(-1));
        }
        Ok(Self { index, started: true, owned: true })
    }

    /// 创建构建器 (链式 API 入口)
    ///
    /// 对应 C# `new DarraEtherCAT().SetENI(...).Build()` 模式。
    ///
    /// # 示例
    /// ```no_run
    /// // 通过 ENI 配置文件初始化
    /// let result = EtherCATMaster::builder()
    ///     .set_eni("config.xml")
    ///     .enable_auto_startup()
    ///     .build()
    ///     .unwrap();
    /// let master = result.master;
    ///
    /// // 通过网口名称初始化
    /// let result = EtherCATMaster::builder()
    ///     .set_network("\\Device\\NPF_{...}", None)
    ///     .set_esi_files("C:\\ESI")
    ///     .enable_auto_startup()
    ///     .build()
    ///     .unwrap();
    /// ```
    pub fn builder() -> MasterBuilder {
        MasterBuilder::new()
    }

    /// 获取主站索引
    pub fn index(&self) -> u16 {
        self.index
    }

    /// 主站编号 (C# 别名: MasterNumber)
    pub fn master_number(&self) -> u16 {
        self.index
    }

    // ===================== 主站级属性 =====================

    /// 主站 EtherCAT 状态
    pub fn state(&self) -> EcState {
        let raw = unsafe { ffi::GetMasterState(self.index) };
        if raw.is_null() { return EcState::None; }
        // 读取 主站状态结构中的 State 字段 (偏移 0, u16)
        let state_raw = unsafe { *(raw as *const u16) };
        EcState::from_raw(state_raw as u8).unwrap_or(EcState::None)
    }

    /// 输出位数 (主站级, 所有从站总计)
    pub fn obits(&self) -> u16 {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return 0; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).output.bits }
    }

    /// 输出字节数 (主站级, 所有从站总计)
    pub fn obytes(&self) -> u32 {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return 0; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).output.bytes }
    }

    /// 输入位数 (主站级, 所有从站总计)
    pub fn ibits(&self) -> u16 {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return 0; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).input.bits }
    }

    /// 输入字节数 (主站级, 所有从站总计)
    pub fn ibytes(&self) -> u32 {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return 0; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).input.bytes }
    }

    /// 是否支持 DC 同步 (主站级)
    pub fn has_dc(&self) -> bool {
        let ptr = unsafe { ffi::GetSlave(self.index, 0) };
        if ptr.is_null() { return false; }
        unsafe { (*(ptr as *const crate::utils::ffi::EcSlaveBlittable)).topo.has_dc != 0 }
    }

    /// 链路状态
    pub fn link_state(&self) -> LinkState {
        self.link_status()
    }

    /// PDO 交换周期时间 (纳秒)
    pub fn loop_cycle(&self) -> u32 {
        unsafe { ffi::GetTimingMode(self.index) }
    }

    /// 设置 PDO 交换周期时间 (纳秒)
    pub fn set_loop_cycle(&self, time_ns: u32) {
        unsafe { ffi::SetMasterLoopCycleTime(self.index, time_ns) };
    }

    /// 手动释放主站资源 (不等待 Drop)
    pub fn dispose(&mut self) {
        if self.owned {
            if self.started {
                unsafe { ffi::Stop(self.index) };
                self.started = false;
            }
            unsafe { ffi::Dispose(self.index) };
            self.owned = false;
        }
    }

    // ===================== 网络配置 =====================

    /// 设置网络适配器
    pub fn set_network(&self, adapter: &str, redundant: &str) -> Result<()> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let c_redundant = CString::new(redundant)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("冗余适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::SetNetwork(self.index, c_adapter.as_ptr(), c_redundant.as_ptr()) };
        if ret > 0 { Ok(()) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    /// `set_network` 返回的从站数 (与 DLL `SetNetwork` 返回值一致, 失败时 <= 0)
    /// 与 C SDKTest `slave_count = SetNetwork(...)` 等价, 调用方需在 build/状态切换前用该值
    /// 而不是依赖 `slave_count()` (后者按 group 累加, 在分组前是 0).
    pub fn set_network_with_count(&self, adapter: &str, redundant: &str) -> Result<i32> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let c_redundant = CString::new(redundant)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("冗余适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::SetNetwork(self.index, c_adapter.as_ptr(), c_redundant.as_ptr()) };
        if ret > 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    /// 获取主网口信息
    ///
    /// 返回当前主站使用的主网络适配器信息 (用于批量部署配置)。
    /// 对应 C# `PrimaryNetworkInfo` 属性。
    ///
    /// 注意: DLL 未导出 GetAdapterInfo, 当前返回 None。
    /// 请通过 GetNetworksPointer 获取网络信息。
    pub fn primary_network_info(&self) -> Option<NetworkInfo> {
        // DLL 未导出 GetAdapterInfo, 暂不支持
        None
    }

    /// 获取冗余网口信息
    ///
    /// 返回当前主站使用的冗余网络适配器信息。
    /// 未配置冗余时返回 None。
    /// 对应 C# `RedundantNetworkInfo` 属性。
    ///
    /// 注意: DLL 未导出 GetAdapterInfo, 当前返回 None。
    pub fn redundant_network_info(&self) -> Option<NetworkInfo> {
        // DLL 未导出 GetAdapterInfo, 暂不支持
        None
    }

    /// 快速扫描从站数量 (不需要主站实例)
    pub fn quick_slave_count(adapter: &str) -> Result<i32> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::QuickSlaveCount(c_adapter.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    /// 快速扫描从站数量 (冗余模式)
    pub fn quick_slave_count_redundant(primary: &str, secondary: &str) -> Result<i32> {
        let c_pri = CString::new(primary)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("主适配器名称包含空字节").into()))?;
        let _c_sec = CString::new(secondary)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("副适配器名称包含空字节").into()))?;
        // native 冗余快速计数入口已收敛，旧 API 保留参数校验后走主适配器探测。
        let ret = unsafe { ffi::QuickSlaveCount(c_pri.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    /// 扫描从站数量
    pub fn scan_slave_count(adapter: &str) -> Result<i32> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::QuickSlaveCount(c_adapter.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    /// 扫描从站数量 (冗余模式)
    pub fn scan_slave_count_redundant(primary: &str, secondary: &str) -> Result<i32> {
        let c_pri = CString::new(primary)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("主适配器名称包含空字节").into()))?;
        let _c_sec = CString::new(secondary)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("副适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::QuickSlaveCount(c_pri.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    /// 读取从站信息 (扫描并缓存)
    pub fn read_slave_info(adapter: &str) -> Result<i32> {
        let c_adapter = CString::new(adapter)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("适配器名称包含空字节").into()))?;
        let ret = unsafe { ffi::ReadSlaveInfo(c_adapter.as_ptr()) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::NetworkFailed(ret)) }
    }

    /// 获取已扫描的从站数量
    pub fn scanned_slave_count() -> i32 {
        unsafe { ffi::GetScannedSlaveCount() }
    }

    /// 获取环形拓扑从站数量
    pub fn ring_slave_count() -> i32 {
        unsafe { ffi::GetRingSlaveCount() }
    }

    // ===================== 状态管理 =====================

    /// 切换 EtherCAT 主站状态. 唯一公开状态机 API.
    ///
    /// 内部自动:
    /// - 链式转换 (Init→PreOp→SafeOp→OP, 跨多级一次到位)
    /// - 每步执行 Before/After Transition 启动参数
    /// - SafeOp/OP 进入后启动 PDO 线程
    /// - 默认每步 5s 超时
    ///
    /// # 参数
    /// - `state`: 目标状态 (EcState::Init/PreOp/SafeOp/Operational)
    pub fn set_state(&mut self, state: EcState) -> Result<()> {
        // [2026-05-04] SDK 内置 3 次重试 + 1.5s wait. OP 稳定期硬件偶发抖动 (Slave PHY
        // PLL fault), SDK 自动重试; 用户不必再写重试包装.
        for attempt in 0..3 {
            // SetStateSequence (D_1132) = ETG 标准状态机链 + 自动启动参数
            let ok = unsafe { ffi::SetStateSequence(self.index, state as c_int, 5000) } != 0;
            if ok {
                if matches!(state, EcState::SafeOp | EcState::Operational) && !self.started {
                    unsafe { ffi::Start(self.index) };
                    self.started = true;
                }
                return Ok(());
            }
            if attempt < 2 {
                std::thread::sleep(std::time::Duration::from_millis(1500));
            }
        }
        Err(DarraError::StateChangeFailed(state as u8))
    }

    /// 异步版 set_state, 在新线程中执行.
    /// 返回 `JoinHandle`, 调用 `.join()` 获取结果.
    pub fn set_state_async(&self, state: EcState) -> std::thread::JoinHandle<Result<()>> {
        let mi = self.index;
        std::thread::spawn(move || {
            let ok = unsafe { ffi::SetStateSequence(mi, state as c_int, 5000) } != 0;
            if !ok {
                return Err(DarraError::StateChangeFailed(state as u8));
            }
            if matches!(state, EcState::SafeOp | EcState::Operational) {
                unsafe { ffi::Start(mi) };
            }
            Ok(())
        })
    }

    /// 获取链路状态
    pub fn link_status(&self) -> LinkState {
        LinkState::from_raw(unsafe { ffi::GetLinkStatus(self.index) })
    }

    // ===================== PDO 循环控制 =====================

    /// 启动 PDO 循环线程
    pub fn start(&mut self) {
        unsafe { ffi::Start(self.index) };
        self.started = true;
    }

    /// 停止 PDO 循环线程
    pub fn stop(&mut self) {
        if self.started {
            unsafe { ffi::Stop(self.index) };
            self.started = false;
        }
    }

    // ===================== 从站访问 =====================

    /// 获取从站句柄
    pub fn slave(&self, slave_index: u16) -> Slave {
        Slave::new(self.index, slave_index)
    }

    /// 连接的从站数量
    pub fn slave_count(&self) -> u16 {
        // 汇总所有组的从站数量
        let mut total: u16 = 0;
        for g in 0..8u8 {
            total += unsafe { ffi::GetGroupSlaveCount(self.index, g) };
        }
        total
    }

    /// 获取所有从站句柄列表
    pub fn slaves(&self) -> Vec<Slave> {
        let count = self.slave_count();
        (1..=count).map(|i| Slave::new(self.index, i)).collect()
    }

    // ===================== 配置管理 =====================

    /// 从 JSON 字符串加载配置 (含启动参数)
    pub fn load_config_json(&self, json: &str) -> Result<()> {
        let c_json = CString::new(json)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("JSON 包含空字节").into()))?;
        let ret = unsafe {
            ffi::DarraCoreInvokeText(self.index, ffi::CORE_OP_23, c_json.as_ptr(), ffi::CORE_FLAG_01, 0, 0)
        };
        if ret >= 0 { Ok(()) } else { Err(DarraError::ConfigLoadFailed(ret)) }
    }

    /// 自动配置 SM2/SM3 物理参数 (slave_index=0 处理所有)
    pub fn auto_configure_sm(&self, slave_index: u16) -> Result<i32> {
        let ret = if slave_index == 0 {
            unsafe { ffi::DarraCoreInvoke(self.index, ffi::CORE_OP_24, 0, 0, 0) }
        } else {
            unsafe { ffi::DarraCoreInvoke(self.index, ffi::CORE_OP_25, slave_index as u32, 0, 0) }
        };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other(format!("自动配置 SM 失败 (返回码: {})", ret))) }
    }

    /// 清除所有从站的启动参数 (slave_index=0)
    pub fn clear_all_startup_parameters(&self) -> Result<()> {
        let ret = unsafe { ffi::ClearStartupParameters(self.index, 0) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other("清除启动参数失败".into())) }
    }

    /// 对所有从站执行启动参数
    pub fn apply_startup_parameters_all(&self, transition: u8, timing: u8) -> Result<i32> {
        let ret = unsafe {
            ffi::DarraCoreInvoke(self.index, ffi::CORE_OP_26, 0, 1u32 << transition, 1u32 << timing)
        };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other(format!("执行启动参数失败 (返回码: {})", ret))) }
    }

    // ===================== DC 分布式时钟 =====================

    /// 设置主站 DC 周期时间 (纳秒)
    pub fn set_dc_cycle_time(&self, time_ns: u32) {
        unsafe { ffi::SetMasterDCCycleTime(self.index, time_ns) };
    }

    /// 配置所有 DC 从站的同步
    pub fn configure_dc_all(&self, sync0_ns: u32, sync1_ns: u32) -> Result<i32> {
        let ret = unsafe { ffi::ConfigureDCAll(self.index, sync0_ns, sync1_ns) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other("DC 配置失败".into())) }
    }

    /// 更新所有 DC 从站的传播延迟
    pub fn update_propagation_delays(&self) -> Result<i32> {
        let ret = unsafe { ffi::UpdatePropagationDelays(self.index) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other("传播延迟更新失败".into())) }
    }

    /// 自动计算 DC 偏移
    pub fn auto_calculate_dc_shift(&self) -> Result<i32> {
        let ret = unsafe { ffi::AutoCalculateDCShift(self.index) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other("DC 偏移计算失败".into())) }
    }

    /// 设置 DC 自动偏移启用
    pub fn set_dc_auto_shift_enabled(&self, enable: bool) {
        unsafe { ffi::SetDCAutoShiftEnabled(self.index, if enable { 1 } else { 0 }) };
    }

    /// 获取 DC 自动偏移启用状态
    pub fn dc_auto_shift_enabled(&self) -> bool {
        (unsafe { ffi::GetDCAutoShiftEnabled(self.index) }) != 0
    }

    /// 设置同步窗口阈值 (ns)
    pub fn set_sync_window_threshold(&self, threshold_ns: i32) {
        unsafe { ffi::SetSyncWindowThreshold(self.index, threshold_ns) };
    }

    /// 获取同步窗口阈值 (ns)
    pub fn sync_window_threshold(&self) -> i32 {
        unsafe { ffi::GetSyncWindowThreshold(self.index) }
    }

    /// 最近一次 FRMW 取回的 64 位 DC 系统时间 (纳秒, 2000-01-01 纪元).
    ///
    /// 对齐 C# `DLL.GetMasterDCTime`.
    /// 返回 0 表示 DC 未激活 (无 DC 从站或 `UpdatePropagationDelays` 未调用).
    ///
    /// C 层签名返回 `int64`, 此处转为 `u64` (DC 时间语义上非负).
    pub fn master_dc_time(&self) -> u64 {
        let t = unsafe { ffi::GetMasterDCTime(self.index) };
        if t < 0 { 0 } else { t as u64 }
    }

    /// 参考时钟从站索引 (1-based).
    ///
    /// 对齐 C# `DLL.GetReferenceClockSlaveIndex`.
    /// 返回:
    /// - `> 0`: 作为 DC 参考时钟的从站索引
    /// - `0`:   无 DC 从站
    ///
    /// C 层签名返回 `uint16` (ec_coe.c Core.h §2333). 为统一"无" 语义与
    /// `SetSlaveGroup` 等返回 `i32`=-1 的 API, 这里暴露为 `i32`: 返回 0 即无,
    /// 其它非 0 正值即参考时钟索引.
    pub fn reference_clock_slave_index(&self) -> i32 {
        unsafe { ffi::GetReferenceClockSlaveIndex(self.index) as i32 }
    }

    /// 获取最大同步偏差 (ns)
    pub fn max_sync_difference(&self) -> i32 {
        unsafe { ffi::GetMaxSyncDifference(self.index) }
    }

    /// 检查所有从站是否同步
    pub fn is_all_slaves_in_sync(&self) -> bool {
        (unsafe { ffi::IsAllSlavesInSync(self.index) }) != 0
    }

    /// 启用/禁用连续传播延迟测量
    pub fn enable_continuous_measurement(&self, enable: bool, interval_sec: u32) {
        unsafe { ffi::EnableContinuousMeasurement(self.index, if enable { 1 } else { 0 }, interval_sec) };
    }

    /// 启用/禁用漂移补偿
    pub fn enable_drift_compensation(&self, enable: bool, threshold_ns: i32, gain: i32) {
        unsafe { ffi::EnableDriftCompensation(self.index, if enable { 1 } else { 0 }, threshold_ns, gain) };
    }

    /// 获取最大传播延迟 (纳秒)
    pub fn max_propagation_delay(&self) -> i32 {
        unsafe { ffi::GetMaxPropagationDelay(self.index) }
    }

    // ===================== CPU 与周期配置 =====================

    /// 设置 PDO 循环周期 (纳秒)
    pub fn set_cycle_time(&self, time_ns: u32) {
        unsafe { ffi::SetMasterLoopCycleTime(self.index, time_ns) };
    }

    /// 设置主站线程 CPU 亲和性 (基准核, 跟 csharp/java/python 对齐)
    /// [2026-05-05] 公开 API: 跟 csharp Master.SetMasterCpuAffinity 对齐.
    pub fn set_cpu_affinity(&self, cpu_core: i32) -> bool {
        (unsafe { ffi::SetMasterCpuAffinity(self.index, cpu_core) }) != 0
    }

    /// 设置 PDO 线程 CPU 亲和性 (跟 csharp/java/python 对齐)
    /// [2026-05-05] 公开 API: 跟 csharp Master.SetPDOThreadCpuAffinity 对齐.
    pub fn set_pdo_thread_cpu_affinity(&self, cpu_core: i32) -> bool {
        (unsafe { ffi::SetPDOThreadCpuAffinity(self.index, cpu_core) }) != 0
    }

    /// 获取 PDO 线程 CPU 亲和性
    pub fn pdo_thread_cpu_affinity(&self) -> i32 {
        unsafe { ffi::GetPDOThreadCpuAffinity(self.index) }
    }

    /// 获取可用 CPU 核心数
    pub fn available_cpu_cores() -> i32 {
        unsafe { ffi::GetAvailableCpuCores() }
    }

    /// 应用实时优化 (高精度定时器/内存锁定/进程高优先级)
    /// [2026-05-05] 公开 API: 跟 csharp Master.ApplyRealtimeOptimizations 对齐.
    pub fn apply_realtime_optimizations() -> bool {
        (unsafe { ffi::ApplyRealtimeOptimizations() }) != 0
    }

    /// 移除实时优化
    pub fn remove_realtime_optimizations() -> bool {
        (unsafe { ffi::RemoveRealtimeOptimizations() }) != 0
    }

    /// 获取实时优化状态
    #[allow(dead_code)]
    pub(crate) fn realtime_optimizations_status() -> bool {
        (unsafe { ffi::GetRealtimeOptimizationsStatus() }) != 0
    }

    /// 获取定时模式
    pub(crate) fn timing_mode(&self) -> u32 {
        unsafe { ffi::GetTimingMode(self.index) }
    }

    // ===================== 组管理 =====================

    /// 设置组周期分频器
    pub fn set_group_cycle_divider(&self, group: u8, divider: u8) -> bool {
        (unsafe { ffi::SetGroupCycleDivider(self.index, group, divider) }) != 0
    }

    /// 启用/禁用组
    pub fn set_group_enabled(&self, group: u8, enabled: bool) -> bool {
        (unsafe { ffi::SetGroupEnabled(self.index, group, if enabled { 1 } else { 0 }) }) != 0
    }

    /// 获取 PDO 组是否启用
    pub fn get_group_enabled(&self, group: u8) -> bool {
        (unsafe { ffi::GetGroupEnabled(self.index, group) }) != 0
    }

    /// 获取活跃组数量
    pub fn active_group_count(&self) -> u8 {
        unsafe { ffi::GetActiveGroupCount(self.index) }
    }

    /// 获取组的期望 WKC
    pub fn group_expected_wkc(&self, group: u8) -> u16 {
        unsafe { ffi::GetGroupExpectedWKC(self.index, group) }
    }

    /// 获取组内从站数量
    pub fn group_slave_count(&self, group: u8) -> u16 {
        unsafe { ffi::GetGroupSlaveCount(self.index, group) }
    }

    // ===================== 冗余模式 =====================

    /// 设置冗余处理模式
    pub fn set_redundancy_mode(mode: i32) {
        unsafe { ffi::SetRedProcessdata(mode) };
    }

    /// 获取冗余处理模式
    pub fn redundancy_mode() -> i32 {
        unsafe { ffi::GetRedProcessdata() }
    }

    /// 启用/禁用冗余
    pub fn enable_redundancy(&self, enable: bool) -> Result<()> {
        if unsafe { ffi::EnableRedundancy(self.index, if enable { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::RedundancyFailed)
        }
    }

    /// 获取冗余状态 (返回原始指针, 由调用者解析)
    pub fn redundancy_status_raw(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetRedundancyStatus(self.index) }
    }

    /// 强制冗余故障切换
    pub fn force_redundancy_failover(&self) -> Result<()> {
        if unsafe { ffi::ForceRedundancyFailover(self.index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::RedundancyFailed)
        }
    }

    /// 检查冗余健康状态
    pub fn check_redundancy_health(&self) -> bool {
        (unsafe { ffi::CheckRedundancyHealth(self.index) }) != 0
    }

    // ===================== 诊断与统计 =====================

    /// 获取详细诊断信息 (原始指针)
    pub fn detailed_diagnostics_raw(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetDetailedDiagnostics(self.index) }
    }

    /// 重置诊断计数器
    pub fn reset_diagnostics(&self) {
        unsafe { ffi::ResetDiagnostics(self.index) };
    }

    /// 获取诊断数据指针 (零拷贝)
    pub fn diagnostics_pointer(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetDiagnosticsPointer(self.index) }
    }

    /// 获取摘要数据指针 (零拷贝)
    pub fn summary_pointer(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetSummaryPointer(self.index) }
    }

    /// 启用/禁用诊断
    pub fn set_diagnostics_enabled(&self, enable: bool) {
        unsafe { ffi::SetDiagnosticsEnabled(self.index, if enable { 1 } else { 0 }) };
    }

    /// 获取诊断启用状态
    pub fn diagnostics_enabled(&self) -> bool {
        (unsafe { ffi::GetDiagnosticsEnabled(self.index) }) != 0
    }

    /// 获取通信统计 (原始指针)
    pub fn communication_stats_raw(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetCommunicationStats(self.index) }
    }

    /// 重置通信统计
    pub fn reset_communication_stats(&self) {
        unsafe { ffi::ResetCommunicationStats(self.index) };
    }

    /// 获取全局期望工作计数器
    pub fn expected_wkc(&self) -> u16 {
        unsafe { ffi::GetExpectedWKC(self.index) }
    }

    /// 设置全局期望工作计数器
    pub fn set_expected_wkc(&self, expected_wkc: u16) {
        unsafe { ffi::SetExpectedWKC(self.index, expected_wkc) };
    }

    /// 主网口 WKC (冗余模式独立跟踪)
    pub fn primary_wkc(&self) -> u16 {
        unsafe { ffi::GetPrimaryWKC() }
    }

    /// 副网口 WKC (冗余模式独立跟踪)
    pub fn secondary_wkc(&self) -> u16 {
        unsafe { ffi::GetSecondaryWKC() }
    }

    /// 获取从站链路质量 (0-100%)
    pub fn slave_link_quality(&self, slave_index: u16) -> i16 {
        unsafe { ffi::GetSlaveLinkQuality(self.index, slave_index) }
    }

    /// 记录周期时间 (微秒)
    pub fn record_cycle_time(&self, cycle_time_us: u32) {
        unsafe { ffi::RecordCycleTime(self.index, cycle_time_us) };
    }

    /// 记录 PDO 周期开始
    pub fn record_pdo_cycle_start(&self) {
        unsafe { ffi::RecordPDOCycleStart(self.index) };
    }

    /// 记录工作计数器
    pub fn record_wkc(&self, wkc: u16) {
        unsafe { ffi::RecordWKC(self.index, wkc) };
    }

    /// 更新诊断快照
    pub fn update_diagnostics_snapshot(&self) {
        unsafe { ffi::UpdateDiagnosticsSnapshot(self.index) };
    }

    /// 重置从站端口错误计数器
    pub fn reset_slave_port_error_counters(&self, slave_index: u16) -> bool {
        (unsafe { ffi::ResetSlavePortErrorCounters(self.index, slave_index) }) != 0
    }

    /// 读取从站端口错误计数器
    /// 返回 (rx_error[4], invalid_frame[4], lost_link[4]) 或 None
    pub fn read_slave_port_error_counters(&self, slave_index: u16) -> Option<([u8; 4], [u8; 4], [u8; 4])> {
        let mut rx_error = [0u8; 4];
        let mut invalid_frame = [0u8; 4];
        let mut lost_link = [0u8; 4];
        let ok = unsafe {
            ffi::ReadSlavePortErrorCounters(
                self.index, slave_index,
                rx_error.as_mut_ptr(), invalid_frame.as_mut_ptr(), lost_link.as_mut_ptr(),
            )
        };
        if ok != 0 { Some((rx_error, invalid_frame, lost_link)) } else { None }
    }

    /// 读取所有从站端口错误计数器
    pub fn read_all_slave_port_error_counters(&self) -> i32 {
        unsafe { ffi::ReadAllSlavePortErrorCounters(self.index) }
    }

    /// 获取从站端口错误统计指针
    pub fn slave_port_error_stats(&self, slave_index: u16) -> *const std::ffi::c_void {
        unsafe { ffi::GetSlavePortErrorStats(self.index, slave_index) }
    }

    /// 使用 ESC 错误更新诊断数据
    pub fn update_diagnostics_with_esc_errors(&self) {
        unsafe { ffi::UpdateDiagnosticsWithESCErrors(self.index) };
    }

    /// 获取故障点信息
    /// 返回 Vec<(slave_index, port, fault_type)>
    pub fn break_points(&self, max_results: u16) -> Vec<(u16, u8, u8)> {
        let mut slaves = vec![0u16; max_results as usize];
        let mut ports = vec![0u8; max_results as usize];
        let mut types = vec![0u8; max_results as usize];
        let count = unsafe {
            ffi::GetBreakPoints(
                self.index,
                slaves.as_mut_ptr(), ports.as_mut_ptr(), types.as_mut_ptr(),
                max_results,
            )
        };
        let n = count.max(0) as usize;
        (0..n).map(|i| (slaves[i], ports[i], types[i])).collect()
    }

    // ===================== IO 映射 =====================

    /// 写入从站输出数据
    pub fn write_slave_output(&self, slave_index: u16, data: &[u8]) {
        unsafe { ffi::WriteSlaveOutput(self.index, slave_index, data.as_ptr(), data.len() as u32) };
    }

    /// 写入从站输出单字节
    pub fn write_slave_output_byte(&self, slave_index: u16, offset: u32, value: u8) {
        unsafe { ffi::WriteSlaveOutputByte(self.index, slave_index, offset, value) };
    }

    /// 设置 Mutex 保护开关
    pub fn set_mutex_protection(&self, enable: bool) {
        unsafe { ffi::SetMutexProtection(self.index, if enable { 1 } else { 0 }) };
    }

    /// 获取 Mutex 保护状态
    pub fn mutex_protection(&self) -> bool {
        (unsafe { ffi::GetMutexProtection(self.index) }) != 0
    }

    // ===================== 日志控制 =====================

    /// 启用/禁用 PDO 日志
    pub fn set_pdo_logging(enable: bool) {
        unsafe { ffi::SetPDOLogging(if enable { 1 } else { 0 }) };
    }

    /// 启用/禁用邮箱日志
    pub fn set_mailbox_logging(enable: bool) {
        unsafe { ffi::SetMailboxLogging(if enable { 1 } else { 0 }) };
    }

    /// 启用/禁用调试日志
    pub fn set_debug_logging(enable: bool) {
        unsafe { ffi::SetDebugLogging(if enable { 1 } else { 0 }) };
    }

    /// 关闭调试日志文件
    pub fn close_debug_log() {
        unsafe { ffi::CloseDebugLog() };
    }

    // ===================== 回调注册 =====================

    /// 注册 PDO 帧丢失回调
    pub fn register_pdo_frame_loss_callback(callback: ffi::PDOFrameLossCallback) {
        unsafe { ffi::RegisterPDOFrameLossCallback(callback) };
    }

    /// 注册从站 PreOp 重配置回调
    pub fn register_preop_reconfig_callback(callback: ffi::SlavePreOpReconfigCallback) {
        unsafe { ffi::RegisterSlavePreOpReconfigCallback(callback) };
    }

    /// 设置崩溃通知回调
    pub fn set_crash_callback(callback: ffi::CrashNotifyCallback) {
        unsafe { ffi::SetCrashCallback(callback) };
    }

    /// 设置 DC 同步丢失回调
    pub fn set_dc_sync_lost_callback(callback: ffi::DCSyncLostCallback) {
        unsafe { ffi::SetDCSyncLostCallback(callback) };
    }

    // ===================== 版本信息 =====================

    /// 获取 DLL 版本信息
    pub fn dll_version() -> Option<(u16, u16, u16, u16)> {
        let ptr = unsafe { ffi::GetDllVersionInfo() };
        if ptr.is_null() { return None; }
        // packed 结构体不能直接创建引用，需要 read_unaligned 避免 UB
        let info = unsafe { std::ptr::read_unaligned(ptr) };
        Some((info.major, info.minor, info.patch, info.build))
    }

    // ===================== IO 映射锁 =====================

    /// 锁定 IOmap
    pub fn lock_iomap(&self) {
        unsafe { ffi::LockIOmap(self.index) };
    }

    /// 解锁 IOmap
    pub fn unlock_iomap(&self) {
        unsafe { ffi::UnlockIOmap(self.index) };
    }

    /// RAII IOmap 锁守卫
    pub fn iomap_guard(&self) -> IomapGuard<'_> {
        self.lock_iomap();
        IomapGuard { master: self }
    }

    // ===================== WDK 实时驱动 =====================

    /// 检查 WDK 驱动是否可用
    #[allow(dead_code)]
    pub(crate) fn is_wdk_available(&self) -> bool {
        (unsafe { ffi::IsWdkAvailable(self.index) }) != 0
    }

    /// 设置 WDK 模式
    #[allow(dead_code)]
    pub(crate) fn set_wdk_mode(&self, enable: bool) -> Result<()> {
        if unsafe { ffi::SetWdkMode(self.index, if enable { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::WdkFailed("设置 WDK 模式失败".into()))
        }
    }

    /// 获取 WDK 模式状态
    #[allow(dead_code)]
    pub(crate) fn wdk_mode(&self) -> bool {
        (unsafe { ffi::GetWdkMode(self.index) }) != 0
    }

    /// 启动 WDK 实时循环
    #[allow(dead_code)]
    pub(crate) fn start_wdk_rt(&self, cycle_us: u32, cpu_index: u32) -> Result<()> {
        if unsafe { ffi::StartWdkRT(self.index, cycle_us, cpu_index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::WdkFailed("启动 WDK RT 失败".into()))
        }
    }

    /// 停止 WDK 实时循环
    #[allow(dead_code)]
    pub(crate) fn stop_wdk_rt(&self) -> Result<()> {
        if unsafe { ffi::StopWdkRT(self.index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::WdkFailed("停止 WDK RT 失败".into()))
        }
    }

    // ===================== UDP 帧模式 =====================

    /// 设置 UDP 模式
    pub fn set_udp_mode(&self, enable: bool) -> Result<()> {
        if unsafe { ffi::SetUdpMode(self.index, if enable { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::UdpFailed)
        }
    }

    /// 获取 UDP 模式状态
    pub fn udp_mode(&self) -> bool {
        (unsafe { ffi::GetUdpMode(self.index) }) != 0
    }

    /// 检查 UDP 是否可用
    pub fn is_udp_available(&self) -> bool {
        (unsafe { ffi::IsUdpAvailable(self.index) }) != 0
    }

    // ===================== 拓扑查询 =====================

    /// 构建网络拓扑, 返回所有节点信息
    pub fn topology(&self) -> Vec<TopologyNode> {
        let mut buf = vec![TopologyNode {
            slave_index: 0, config_addr: 0, parent_index: 0,
            entry_port: 0, active_ports: 0, topology: 0, port_type: 0,
        }; 256];
        let count = unsafe { ffi::GetTopology(self.index, buf.as_mut_ptr(), 256) };
        if count > 0 {
            buf.truncate(count as usize);
            buf
        } else {
            Vec::new()
        }
    }

    /// 构建拓扑 (TopologyBuild)
    pub fn topology_build(&self) -> Vec<TopologyNode> {
        let mut buf = vec![TopologyNode {
            slave_index: 0, config_addr: 0, parent_index: 0,
            entry_port: 0, active_ports: 0, topology: 0, port_type: 0,
        }; 256];
        let count = unsafe { ffi::TopologyBuild(self.index, buf.as_mut_ptr(), 256) };
        if count > 0 {
            buf.truncate(count as usize);
            buf
        } else {
            Vec::new()
        }
    }

    /// 获取拓扑子节点
    pub fn topology_get_children(&self, parent_index: u16) -> Vec<u16> {
        let mut buf = vec![0u16; 64];
        let count = unsafe { ffi::TopologyGetChildren(self.index, parent_index, buf.as_mut_ptr(), 64) };
        if count > 0 { buf.truncate(count as usize); buf }
        else { Vec::new() }
    }

    /// 获取拓扑根节点
    pub fn topology_get_roots(&self) -> Vec<u16> {
        let mut buf = vec![0u16; 64];
        let count = unsafe { ffi::TopologyGetRoots(self.index, buf.as_mut_ptr(), 64) };
        if count > 0 { buf.truncate(count as usize); buf }
        else { Vec::new() }
    }

    // ===================== 授权与设备信息 =====================

    /// 验证授权, 返回授权是否有效
    pub fn verify_license() -> Result<bool> {
        let ret = unsafe { ffi::VerifyLicense() };
        Ok(ret != 0)
    }

    /// 检查授权是否有效
    pub fn is_license_valid() -> bool {
        unsafe { ffi::IsLicenseValid() != 0 }
    }

    /// 使授权失效
    pub fn invalidate_license() {
        unsafe { ffi::InvalidateLicense() };
    }

    /// 获取设备序列号
    // DLL返回内部静态缓冲区，无需FreeMemory
    pub fn serial_number() -> String {
        let ptr = unsafe { ffi::GetSerialNumber() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    /// 获取设备名称
    // DLL返回内部静态缓冲区，无需FreeMemory
    pub fn device_name() -> String {
        let ptr = unsafe { ffi::GetDeviceName() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    /// 获取用户邮箱
    // DLL返回内部静态缓冲区，无需FreeMemory
    pub fn user_email() -> String {
        let ptr = unsafe { ffi::GetUserEmail() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    /// 获取 Windows 产品密钥
    // DLL返回内部静态缓冲区，无需FreeMemory
    pub fn windows_product_key() -> String {
        let ptr = unsafe { ffi::GetWindowsProductKey() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    /// 获取驱动列表 (JSON 格式字符串)
    // DLL返回内部静态缓冲区，无需FreeMemory
    pub fn driver_list() -> String {
        let ptr = unsafe { ffi::GetDriverList() };
        if ptr.is_null() { return String::new(); }
        unsafe { CStr::from_ptr(ptr) }.to_string_lossy().into_owned()
    }

    // ===================== 主站信息查询 =====================

    /// 获取最大主站实例数
    pub fn max_master_instances() -> i32 {
        unsafe { ffi::GetMaxMasterInstances() }
    }

    /// 输出从站结构体偏移 (调试用)
    #[allow(dead_code)]
    pub(crate) fn dump_slave_struct_offsets() {
        unsafe { ffi::DumpSlaveStructOffsets() };
    }

    // ===================== 状态缓存配置 =====================

    /// 设置状态缓存更新间隔 (毫秒).
    ///
    /// 当前运行时 DLL 未导出状态缓存配置符号时返回错误, 不再静默 no-op.
    pub fn set_state_cache_update_interval(&self, interval_ms: u32) -> Result<()> {
        if ffi::dynamic_ffi::ffi_gap().set_state_cache_update_interval.is_none() {
            return Err(DarraError::DiagnosticsFailed);
        }
        unsafe { ffi::SetStateCacheUpdateInterval(self.index, interval_ms) };
        Ok(())
    }

    /// 获取状态缓存更新间隔 (毫秒).
    ///
    /// 返回 `None` 表示当前运行时 DLL 未导出状态缓存查询符号.
    pub fn state_cache_update_interval(&self) -> Option<u32> {
        if ffi::dynamic_ffi::ffi_gap().get_state_cache_update_interval.is_none() {
            return None;
        }
        Some(unsafe { ffi::GetStateCacheUpdateInterval(self.index) })
    }

    // ===================== 批量看门狗配置 =====================

    /// 批量设置所有从站看门狗
    pub fn set_all_slave_watchdog(&self, timeout_ms: u32) {
        unsafe { ffi::SetAllSlaveWatchdog(self.index, timeout_ms) };
    }

    /// 批量设置所有从站PDI看门狗
    pub fn set_all_slave_pdi_watchdog(&self, timeout_ms: u32) {
        unsafe { ffi::SetAllSlavePdiWatchdog(self.index, timeout_ms) };
    }

    // ===================== 从站热插拔重配置 =====================

    /// 查询从站是否需要启动参数重配置
    pub fn slave_needs_startup_reconfig(&self, slave_index: u16) -> bool {
        unsafe { ffi::GetSlaveNeedsStartupReconfig(self.index, slave_index) != 0 }
    }

    /// 清除从站启动参数重配置标志
    pub fn clear_slave_startup_reconfig(&self, slave_index: u16) {
        unsafe { ffi::ClearSlaveNeedsStartupReconfig(self.index, slave_index) };
    }

    // ===================== PDO 丢帧统计 =====================

    /// 获取 PDO 丢帧统计 (总丢帧, 连续丢帧, 最大连续丢帧)
    pub fn pdo_frame_loss_stats(&self, group: u8) -> (u32, u32, u32) {
        let mut total: u32 = 0;
        let mut consecutive: u32 = 0;
        let mut max_consecutive: u32 = 0;
        unsafe {
            ffi::GetPDOFrameLossStats(
                self.index, group,
                &mut total, &mut consecutive, &mut max_consecutive,
            );
        }
        (total, consecutive, max_consecutive)
    }

    /// 重置 PDO 丢帧统计
    pub fn reset_pdo_frame_loss_stats(&self, group: u8) {
        unsafe { ffi::ResetPDOFrameLossStats(self.index, group) };
    }

    // ===================== 定时器验证 =====================

    /// 验证定时器精度
    pub fn validate_timer_accuracy(expected_usec: u32, tolerance_usec: u32) -> bool {
        unsafe { ffi::DarraValidateTimerAccuracy(expected_usec, tolerance_usec) == 0 }
    }

    // ===================== PDO 监控 =====================

    /// 启用/禁用 PDO 监控.
    ///
    /// 当前运行时 DLL 未导出 `EnablePDOMonitoring` 时返回错误, 不再静默 no-op.
    pub fn set_pdo_monitoring(enable: bool) -> Result<()> {
        if ffi::dynamic_ffi::ffi_gap().enable_pdo_monitoring.is_none() {
            return Err(DarraError::PdoFailed("EnablePDOMonitoring 原生符号不可用".into()));
        }
        unsafe { ffi::EnablePDOMonitoring(if enable { 1 } else { 0 }) };
        Ok(())
    }

    /// 查询 PDO 监控是否启用.
    ///
    /// 返回 `None` 表示当前运行时 DLL 未导出 `IsPDOMonitoringEnabled`.
    pub fn is_pdo_monitoring_enabled() -> Option<bool> {
        if ffi::dynamic_ffi::ffi_gap().is_pdo_monitoring_enabled.is_none() {
            return None;
        }
        Some(unsafe { ffi::IsPDOMonitoringEnabled() != 0 })
    }

    /// 获取 PDO 统计指针.
    ///
    /// 返回 `None` 表示当前运行时 DLL 未导出 `GetPDOStats`, 或 native 返回 null.
    pub fn pdo_stats_raw(&self, slave_index: u16) -> Option<NonNull<std::ffi::c_void>> {
        if ffi::dynamic_ffi::ffi_gap().get_pdo_stats.is_none() {
            return None;
        }
        NonNull::new(unsafe { ffi::GetPDOStats(self.index, slave_index) as *mut std::ffi::c_void })
    }

    /// 重置 PDO 统计.
    ///
    /// 当前运行时 DLL 未导出 `ResetPDOStats` 时返回错误, 不再静默 no-op.
    pub fn reset_pdo_stats(&self, slave_index: u16) -> Result<()> {
        if ffi::dynamic_ffi::ffi_gap().reset_pdo_stats.is_none() {
            return Err(DarraError::PdoFailed("ResetPDOStats 原生符号不可用".into()));
        }
        unsafe { ffi::ResetPDOStats(self.index, slave_index) };
        Ok(())
    }

    // ===================== ETG.1510 主站诊断 =====================

    /// 获取主站身份信息
    pub fn master_identity(&self) -> Result<MasterIdentity> {
        let mut identity = MasterIdentity {
            vendor_id: 0, product_code: 0, revision_no: 0, serial_no: 0,
            device_name: [0; 64], hw_version: [0; 32], sw_version: [0; 32],
        };
        if unsafe { ffi::GetMasterIdentity(self.index, &mut identity) } != 0 {
            Ok(identity)
        } else {
            Err(DarraError::DiagnosticsFailed)
        }
    }

    /// 获取主站诊断数据
    pub fn master_diag_data(&self) -> Result<MasterDiagData> {
        let mut diag = MasterDiagData {
            cyclic_lost_frames: 0, acyclic_lost_frames: 0,
            cyclic_frames_per_sec: 0, acyclic_frames_per_sec: 0,
            master_state: 0,
        };
        if unsafe { ffi::GetMasterDiagData(self.index, &mut diag) } != 0 {
            Ok(diag)
        } else {
            Err(DarraError::DiagnosticsFailed)
        }
    }

    // ===================== 故障点检测 =====================

    /// 获取环拓扑冗余模式 (0=Inactive, 1=Dual, 2=Degraded)
    pub fn ring_mode(&self) -> i32 {
        unsafe { ffi::GetRingMode(self.index) }
    }

    /// 获取冗余链路状态
    pub fn secondary_link_status(&self) -> bool {
        unsafe { ffi::GetSecondaryLinkStatus(self.index) != 0 }
    }

    // ===================== 配置验证与导出 =====================

    /// 验证主站配置
    pub fn validate_config(&self) -> Result<i32> {
        let ret = unsafe { ffi::ec_validate_config(self.index) };
        if ret >= 0 { Ok(ret) } else { Err(DarraError::Other(format!("配置验证失败 (返回码: {})", ret))) }
    }

    /// 验证所有从站身份
    /// 参数:
    ///   expected - 期望的从站身份数组
    ///   check_revision - 是否检查修订号
    ///   check_serial - 是否检查序列号
    /// 返回不匹配位掩码 (第 N 位为 1 表示从站 N 不匹配), 全部匹配返回 Ok(0)
    pub fn verify_all_slave_identities(
        &self,
        expected: &[SlaveIdentity],
        check_revision: bool,
        check_serial: bool,
    ) -> Result<u64> {
        let mut mismatch_mask: u64 = 0;
        let ret = unsafe {
            ffi::VerifyAllSlaveIdentities(
                self.index,
                expected.as_ptr(),
                expected.len() as u32,
                if check_revision { 1 } else { 0 },
                if check_serial { 1 } else { 0 },
                &mut mismatch_mask,
            )
        };
        if ret >= 0 {
            Ok(mismatch_mask)
        } else {
            Err(DarraError::Other(format!("从站身份验证失败 (返回码: {})", ret)))
        }
    }

    /// 导出性能统计到 CSV 文件
    pub fn export_perf_csv(&self, filepath: &str) -> Result<()> {
        let c_path = CString::new(filepath)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("路径包含空字节").into()))?;
        let ret = unsafe { ffi::ec_perf_export_csv(self.index, c_path.as_ptr()) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other(format!("CSV 导出失败 (返回码: {})", ret))) }
    }

    // ===================== AoE 通知监听 =====================

    /// 启动 AoE 通知监听
    pub fn aoe_start_notification_listener(&self) -> Result<()> {
        if unsafe { ffi::AOEStartNotificationListener(self.index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::AoeFailed)
        }
    }

    /// 停止 AoE 通知监听
    pub fn aoe_stop_notification_listener() -> Result<()> {
        if unsafe { ffi::AOEStopNotificationListener() } != 0 {
            Ok(())
        } else {
            Err(DarraError::AoeFailed)
        }
    }

    /// 检查 AoE 通知监听是否运行
    pub fn aoe_is_notification_listening() -> bool {
        unsafe { ffi::AOEIsNotificationListening() != 0 }
    }

    // ===================== 扫描控制与紧急操作 =====================

    /// 中止正在进行的扫描
    pub fn abort_scan() {
        unsafe { ffi::AbortScan() };
    }

    /// 重置扫描中止标志
    pub fn reset_scan_abort() {
        unsafe { ffi::ResetScanAbort() };
    }

    /// 紧急关闭网卡
    pub fn emergency_close_nics() {
        unsafe { ffi::EmergencyCloseNics() };
    }

    /// 紧急释放所有主站资源 (崩溃/进程退出时使用)
    ///
    /// 直接关闭所有网卡句柄, 不依赖主站对象状态, 不等待线程退出。
    /// 必须在进程退出前调用, 否则 Npcap 句柄泄漏导致下次无法打开网卡。
    /// 对应 C# `EmergencyCleanup()` 静态方法。
    ///
    /// # 示例
    /// ```no_run
    /// // 在 panic hook 或 ctrlc handler 中调用
    /// EtherCATMaster::emergency_cleanup();
    /// ```
    pub fn emergency_cleanup() {
        // 一步完成: 中止标志 -> 等待 -> 直接关闭所有 pcap/WDK 句柄
        unsafe { ffi::EmergencyCloseNics() };
    }

    // ===================== 诊断信息 (MasterDiagnosticsInfo) =====================

    /// 获取主站诊断信息实例
    ///
    /// 帧/错误/抖动统计, 通过零拷贝指针访问共享内存。
    /// ```no_run
    /// let diag = master.diagnostics_info();
    /// diag.set_enabled(true);
    /// println!("丢包率: {:.2}%", diag.lost() * 100.0);
    /// println!("每秒帧数: {}", diag.rt_cnt());
    /// ```
    pub fn diagnostics_info(&self) -> crate::master::diagnostics::MasterDiagnosticsInfo<'_> {
        crate::master::diagnostics::MasterDiagnosticsInfo::new(self)
    }

    // ===================== 事件系统 =====================

    /// 获取主站事件集合
    ///
    /// 通过事件集合订阅所有 DLL 回调事件。
    /// ```no_run
    /// let events = master.events();
    /// events.on_pdo_cyclic_async(|master_idx| {
    ///     // PDO 周期回调
    /// });
    /// events.on_slave_offline(|slave_idx| {
    ///     println!("从站 {} 离线", slave_idx);
    /// });
    /// ```
    pub fn events(&self) -> crate::master::events::MasterEvents {
        crate::master::events::MasterEvents::new(self.index)
    }

    // ===================== 热插拔自修复 =====================

    /// 用户确认从站替换 (v2 热插拔自修复)
    ///
    /// 订阅 [`crate::master::events::MasterEvents::on_slave_identity_mismatch`]
    /// 收到身份不符报警后, 操作员检查/更换设备完毕, 调用本方法让 SDK 重新检测。
    ///
    /// 行为:
    /// - 若身份已纠正 (换回正确设备 / 同型号升级 Revision) → 自动恢复并触发 `on_slave_online`
    /// - 若身份仍不匹配 → 再次触发 `on_slave_identity_mismatch`, 回到 `IDENT_REJECTED` 状态
    ///
    /// # 参数
    /// - `slave_num`: 从站编号 (1-based, 与配置中一致)
    ///
    /// # 返回
    /// `true` = 已接受并复位 FSM;
    /// `false` = 参数无效或从站当前不在 `IDENT_REJECTED`/`FAILED` 状态
    /// (在收到 `SlaveIdentityMismatch` 事件之前调用返回 `false`)。
    pub fn acknowledge_slave_replacement(&self, slave_num: u16) -> Result<bool> {
        if slave_num == 0 {
            return Err(DarraError::InvalidParameter("slave_num 不能为 0".into()));
        }
        if ffi::dynamic_ffi::ffi_gap().acknowledge_slave_replacement.is_none() {
            return Err(DarraError::Other("AcknowledgeSlaveReplacement 原生符号不可用".into()));
        }
        Ok(unsafe { ffi::AcknowledgeSlaveReplacement(self.index, slave_num) != 0 })
    }

    // ===================== 拓扑管理 =====================

    /// 构建网络拓扑
    pub fn slave_topology(&self) -> crate::slave::topology::SlaveTopology {
        crate::slave::topology::SlaveTopology::build(self.index)
    }

    /// 重建拓扑 (重新扫描)
    pub fn rebuild_topology(&self) -> crate::slave::topology::SlaveTopology {
        crate::slave::topology::SlaveTopology::build(self.index)
    }

    // ===================== 多实例管理 =====================

    /// 获取当前活跃的主站实例数量
    pub fn active_instance_count() -> i32 {
        // DLL 层实际通过 GetMaxMasterInstances 返回支持的最大数,
        // 当前实例数由应用层管理
        // 此处返回 DLL 层可获取的信息
        unsafe { ffi::GetMaxMasterInstances() }
    }

    /// 获取最大可创建的主站实例数量
    pub fn max_instance_count() -> i32 {
        unsafe { ffi::GetMaxMasterInstances() }
    }

    // ===================== DC 重置所有同步窗口统计 =====================

    /// 重置所有从站的同步窗口统计
    pub fn reset_all_sync_window_stats(&self) {
        unsafe { ffi::ResetSlaveSyncWindowStats(self.index, 0) };
    }

    // ===================== 配置管理 (MasterConfig) =====================

    /// 获取主站配置管理实例
    ///
    /// 统一管理周期、网络传输、PDO、互斥锁保护等配置。
    /// ```no_run
    /// let config = master.config();
    /// config.set_loop_cycle(1_000_000); // 1ms
    /// config.set_frame_high_priority(true);
    /// ```
    pub fn config(&self) -> crate::master::config::MasterConfig<'_> {
        crate::master::config::MasterConfig::new(self)
    }

    // ===================== ETG.1510 主站对象字典 =====================

    /// 获取 ETG.1510 主站对象字典实例
    ///
    /// 用于诊断工具和 HMI 通过 SDO 访问主站诊断信息。
    /// ```no_run
    /// let od = master.master_od();
    /// let data = od.read_object(0x1000, 0); // 读取 Device Type
    /// ```
    pub fn master_od(&self) -> crate::master::master_od::MasterObjectDictionary<'_> {
        crate::master::master_od::MasterObjectDictionary::new(self)
    }

    // ===================== ETG.8200 Mailbox Gateway =====================

    /// 创建 Mailbox Gateway 服务实例
    ///
    /// 允许外部诊断工具通过 UDP/IP 访问 EtherCAT 从站和主站对象字典。
    /// ```no_run
    /// let mut gw = master.mailbox_gateway();
    /// gw.start().unwrap();
    /// // ... 诊断工具可通过 UDP 端口访问
    /// gw.stop();
    /// ```
    pub fn mailbox_gateway(&self) -> crate::master::mailbox_gateway::MailboxGatewayService {
        crate::master::mailbox_gateway::MailboxGatewayService::new(self.index)
    }

    // ===================== 状态管理执行 =====================

    /// 带状态管理的操作执行
    ///
    /// 将从站切换到目标状态, 执行操作, 然后恢复原状态。
    /// 适用于需要在特定状态 (如 PreOp) 下执行配置操作的场景。
    ///
    /// - `slave_index`: 从站索引
    /// - `target_state`: 目标状态 (如 EcState::PreOp)
    /// - `operation`: 在目标状态下执行的操作闭包
    /// - `timeout_ms`: 状态切换超时 (毫秒)
    pub fn execute_with_state_management<F>(
        &self,
        slave_index: u16,
        target_state: EcState,
        operation: F,
        timeout_ms: i32,
    ) -> Result<()>
    where
        F: FnOnce(&Slave) -> Result<()>,
    {
        let slave = self.slave(slave_index);
        let current_state = slave.state().unwrap_or(EcState::None);

        let target_raw = match target_state {
            EcState::Init => 0x01,
            EcState::PreOp => 0x02,
            EcState::Boot => 0x03,
            EcState::SafeOp => 0x04,
            EcState::Operational => 0x08,
            _ => return Err(DarraError::InvalidParameter(obfstr::obfstr!("无效的目标状态").into())),
        };

        // 切换到目标状态
        if current_state != target_state {
            let ret = unsafe {
                ffi::SetSlaveStateWithTimeout(self.index, slave_index, target_raw as c_int, timeout_ms as u32)
            };
            if ret == 0 {
                return Err(DarraError::StateChangeFailed(target_raw));
            }
        }

        // 执行操作
        let result = operation(&slave);

        // 恢复原状态
        if current_state != target_state {
            let current_raw = match current_state {
                EcState::Init => 0x01,
                EcState::PreOp => 0x02,
                EcState::Boot => 0x03,
                EcState::SafeOp => 0x04,
                EcState::Operational => 0x08,
                _ => 0x01,
            };
            unsafe {
                ffi::SetSlaveStateWithTimeout(self.index, slave_index, current_raw as c_int, timeout_ms as u32);
            }
        }

        result
    }

    // ===================== DLL 校验和 =====================

    /// 获取 DLL 文件校验和
    ///
    /// 注意: DLL 未导出 GetDllChecksum, 当前返回 None。
    pub fn dll_checksum() -> Option<String> {
        // DLL 未导出 GetDllChecksum, 暂不支持
        None
    }
}

impl Drop for EtherCATMaster {
    fn drop(&mut self) {
        if self.owned {
            if self.started {
                unsafe { ffi::Stop(self.index) };
            }
            unsafe { ffi::Dispose(self.index) };
        }
    }
}

// ===================== Display trait =====================

impl std::fmt::Display for EtherCATMaster {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "EtherCATMaster[{}] {} slaves", self.index, self.slave_count())
    }
}

// ===================== 从站迭代器 =====================

/// 从站迭代器 (按索引 1..=N 依次返回 Slave 句柄)
pub struct SlaveIterator {
    master_index: u16,
    current: u16,
    total: u16,
}

impl Iterator for SlaveIterator {
    type Item = Slave;

    fn next(&mut self) -> Option<Self::Item> {
        if self.current > self.total {
            return None;
        }
        let slave = Slave::new(self.master_index, self.current);
        self.current += 1;
        Some(slave)
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        // 修复: 当 current > total 时防止 u16 减法下溢
        let remaining = if self.current > self.total {
            0
        } else {
            (self.total - self.current + 1) as usize
        };
        (remaining, Some(remaining))
    }
}

impl EtherCATMaster {
    /// 返回从站迭代器
    pub fn iter(&self) -> SlaveIterator {
        SlaveIterator {
            master_index: self.index,
            current: 1,
            total: self.slave_count(),
        }
    }
}

impl<'a> IntoIterator for &'a EtherCATMaster {
    type Item = Slave;
    type IntoIter = SlaveIterator;

    fn into_iter(self) -> Self::IntoIter {
        self.iter()
    }
}

/// IOmap 锁守卫 (RAII)
/// 作用域结束时自动解锁
pub struct IomapGuard<'a> {
    master: &'a EtherCATMaster,
}

impl<'a> Drop for IomapGuard<'a> {
    fn drop(&mut self) {
        self.master.unlock_iomap();
    }
}

// ===================== 从站组访问器 (对应 C# SlaveGroupList) =====================

/// 从站组访问器
///
/// 提供按组访问从站的能力, 支持分频器配置和迭代。
/// 对应 C# `SlaveGroupList` 功能。
///
/// # 示例
/// ```no_run
/// let accessor = master.group_accessor();
/// println!("组数: {}", accessor.count());
/// for slave in accessor.slaves(0) {
///     println!("组0从站: {}", slave.index());
/// }
/// ```
pub struct SlaveGroupAccessor<'a> {
    master: &'a EtherCATMaster,
}

impl<'a> SlaveGroupAccessor<'a> {
    /// 创建从站组访问器
    pub fn new(master: &'a EtherCATMaster) -> Self {
        Self { master }
    }

    /// 获取活跃组数量
    pub fn count(&self) -> usize {
        self.master.active_group_count() as usize
    }

    /// 获取指定组的所有从站
    ///
    /// 参数:
    /// - `group`: 组编号 (0~7)
    ///
    /// 返回该组内所有从站的句柄列表
    pub fn slaves(&self, group: u8) -> Vec<Slave> {
        let group_count = unsafe { ffi::GetGroupSlaveCount(self.master.index, group) };
        if group_count == 0 {
            return Vec::new();
        }
        // 遍历所有从站, 筛选属于指定组的
        let total = self.master.slave_count();
        let mut result = Vec::new();
        for i in 1..=total {
            let slave = Slave::new(self.master.index, i);
            if slave.group() == group {
                result.push(slave);
            }
        }
        result
    }

    /// 获取指定组的周期分频器
    ///
    /// 参数:
    /// - `group`: 组编号 (0~7)
    pub fn divider(&self, group: u8) -> u8 {
        unsafe { ffi::GetGroupCycleDivider(self.master.index, group) }
    }

    /// 设置指定组的周期分频器
    ///
    /// 参数:
    /// - `group`: 组编号 (0~7)
    /// - `div`: 分频值 (必须 > 0)
    pub fn set_divider(&self, group: u8, div: u8) {
        if div > 0 {
            unsafe { ffi::SetGroupCycleDivider(self.master.index, group, div) };
        }
    }

    /// 获取指定组的从站数量
    pub fn group_slave_count(&self, group: u8) -> u16 {
        unsafe { ffi::GetGroupSlaveCount(self.master.index, group) }
    }

    /// 获取指定组的期望 WKC
    pub fn group_expected_wkc(&self, group: u8) -> u16 {
        unsafe { ffi::GetGroupExpectedWKC(self.master.index, group) }
    }
}

/// 从站组迭代器 - 迭代所有活跃组编号
pub struct SlaveGroupIter<'a> {
    accessor: &'a SlaveGroupAccessor<'a>,
    current_group: u8,
}

impl<'a> Iterator for SlaveGroupIter<'a> {
    type Item = u8;

    fn next(&mut self) -> Option<Self::Item> {
        while self.current_group < 8 {
            let group = self.current_group;
            self.current_group += 1;
            if unsafe { ffi::GetGroupSlaveCount(self.accessor.master.index, group) } > 0 {
                return Some(group);
            }
        }
        None
    }
}

impl<'a> IntoIterator for &'a SlaveGroupAccessor<'a> {
    type Item = u8;
    type IntoIter = SlaveGroupIter<'a>;

    fn into_iter(self) -> Self::IntoIter {
        SlaveGroupIter {
            accessor: self,
            current_group: 0,
        }
    }
}

impl EtherCATMaster {
    /// 获取从站组访问器
    ///
    /// 对应 C# `SlaveGroupList` 属性
    pub fn group_accessor(&self) -> SlaveGroupAccessor<'_> {
        SlaveGroupAccessor::new(self)
    }
}

// ===================== 构建结果 (对应 C# BuildResult) =====================

/// 构建结果
///
/// 包含主站实例和初始化状态信息。
/// 实现 `Deref<Target = EtherCATMaster>` 便于直接访问主站方法。
///
/// # 示例
/// ```no_run
/// let result = EtherCATMaster::builder()
///     .set_eni("config.xml")
///     .build()
///     .unwrap();
///
/// // 通过 Deref 直接访问主站方法
/// println!("从站数量: {}", result.slave_count());
///
/// // 也可以解构获取主站实例
/// let BuildResult { master, slave_count, success } = result;
/// ```
pub struct BuildResult {
    /// 主站实例
    pub master: EtherCATMaster,
    /// 扫描到的从站数量
    pub slave_count: usize,
    /// 是否初始化成功
    pub success: bool,
}

impl Deref for BuildResult {
    type Target = EtherCATMaster;

    /// 解引用到内部的 EtherCATMaster, 便于直接调用主站方法
    fn deref(&self) -> &Self::Target {
        &self.master
    }
}

impl std::fmt::Display for BuildResult {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "BuildResult(success={}, slaves={})", self.success, self.slave_count)
    }
}

impl std::fmt::Debug for BuildResult {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("BuildResult")
            .field("success", &self.success)
            .field("slave_count", &self.slave_count)
            .field("master_index", &self.master.index)
            .finish()
    }
}

// ===================== 主站构建器 (对应 C# 链式 API) =====================

/// 主站构建器 - 链式 API 配置并初始化主站
///
/// 对应 C# `new DarraEtherCAT().SetENI(...).SetEsiFiles(...).EnableAutoStartup().Build()` 模式。
///
/// # 示例
/// ```no_run
/// use ethercat::master::core::{MasterBuilder, BuildResult};
///
/// // 通过 ENI 配置文件初始化
/// let result = MasterBuilder::new()
///     .set_eni("config.xml")
///     .enable_auto_startup()
///     .build()
///     .unwrap();
///
/// // 通过网口名称初始化 + ESI 文件目录
/// let result = MasterBuilder::new()
///     .set_network("\\Device\\NPF_{GUID}", None)
///     .set_esi_files("C:\\ESI")
///     .enable_auto_startup()
///     .build()
///     .unwrap();
/// ```
/// 构建器配置验证结果
#[derive(Debug, Clone)]
pub struct ValidationResult {
    /// 配置是否有效
    pub is_valid: bool,
    /// 错误信息列表 (为空表示无错误)
    pub errors: Vec<String>,
}

pub struct MasterBuilder {
    /// 主网口名称 (延迟配置)
    pending_network: Option<String>,
    /// 冗余网口名称 (延迟配置)
    pending_redundant: Option<String>,
    /// ENI/DENI 配置文件路径 (延迟配置)
    pending_eni_path: Option<String>,
    /// ESI 文件/目录路径列表 (延迟配置, 支持多个)
    pending_esi_paths: Vec<String>,
    /// 是否启用自动启动配置 (延迟配置)
    pending_auto_startup: bool,
    /// 是否已设置配置
    configuration_set: bool,
}

impl MasterBuilder {
    /// 创建新的构建器实例
    pub fn new() -> Self {
        Self {
            pending_network: None,
            pending_redundant: None,
            pending_eni_path: None,
            pending_esi_paths: Vec::new(),
            pending_auto_startup: false,
            configuration_set: false,
        }
    }

    /// 设置 ENI/DENI 配置文件路径 (延迟配置, Build 时生效)
    ///
    /// ENI 文件包含完整的网络拓扑和从站配置。
    /// 链式调用时后调用的方法会覆盖前面的网口配置。
    /// 对应 C# `SetENI()` 方法。
    ///
    /// # 参数
    /// - `path`: ENI/DENI 配置文件路径
    pub fn set_eni(mut self, path: &str) -> Self {
        self.pending_eni_path = Some(path.to_string());
        self.configuration_set = true;
        self
    }

    /// 设置单个 ESI 文件路径 (延迟配置, Build 时生效)
    ///
    /// 可多次调用添加多个 ESI 文件。
    /// 对应 C# `SetEsiFile()` 方法。
    ///
    /// # 参数
    /// - `path`: ESI 文件路径 (.xml)
    pub fn set_esi_file(mut self, path: &str) -> Self {
        if !path.is_empty() {
            self.pending_esi_paths.push(path.to_string());
        }
        self
    }

    /// 设置 ESI 文件目录路径 (延迟配置, Build 时生效)
    ///
    /// 加载目录下所有 ESI 文件。可多次调用添加多个路径。
    /// 对应 C# `SetEsiFiles()` 方法。
    ///
    /// # 参数
    /// - `path`: ESI 文件目录路径或单个文件路径
    pub fn set_esi_files(mut self, path: &str) -> Self {
        if !path.is_empty() {
            self.pending_esi_paths.push(path.to_string());
        }
        self
    }

    /// 设置网口 (延迟配置, Build 时生效)
    ///
    /// 通过网口名称设置主网口和可选的冗余网口。
    /// 对应 C# `SetNetwork()` 方法。
    ///
    /// # 参数
    /// - `primary`: 主网口名称 (设备路径, 如 `\\Device\\NPF_{GUID}`)
    /// - `redundant`: 冗余网口名称 (可选)
    pub fn set_network(mut self, primary: &str, redundant: Option<&str>) -> Self {
        self.pending_network = Some(primary.to_string());
        self.pending_redundant = redundant.map(|s| s.to_string());
        self.configuration_set = true;
        self
    }

    /// 启用自动启动配置 (Build 时执行)
    ///
    /// 已有启动参数的从站 (ENI/DENI 已配置) 会被跳过, 仅对未配置的从站生效。
    /// 对应 C# `EnableAutoStartup()` 方法。
    pub fn enable_auto_startup(mut self) -> Self {
        self.pending_auto_startup = true;
        self
    }

    /// Build 前配置预检查
    ///
    /// 在调用 `build()` 之前验证当前配置是否合理。
    /// 不会执行实际初始化，仅检查配置参数。
    ///
    /// # 示例
    /// ```no_run
    /// let builder = EtherCATMaster::builder()
    ///     .set_eni("config.xml");
    /// let result = builder.validate();
    /// if !result.is_valid {
    ///     for err in &result.errors {
    ///         println!("配置错误: {}", err);
    ///     }
    /// }
    /// ```
    pub fn validate(&self) -> ValidationResult {
        let mut errors = Vec::new();

        // 检查是否设置了网口或 ENI 配置
        if !self.configuration_set {
            errors.push("未设置网口或 ENI 配置, 主站无法初始化".into());
        }

        // 检查 ENI 路径和网口是否都未设置
        if self.pending_eni_path.is_none() && self.pending_network.is_none() {
            errors.push("未设置 ENI 配置文件路径或网口名称".into());
        }

        // 检查 ENI 路径是否为空字符串
        if let Some(ref path) = self.pending_eni_path {
            if path.trim().is_empty() {
                errors.push("ENI 配置文件路径不能为空".into());
            }
        }

        // 检查网口名称是否为空字符串
        if let Some(ref primary) = self.pending_network {
            if primary.trim().is_empty() {
                errors.push("主网口名称不能为空".into());
            }
        }

        ValidationResult {
            is_valid: errors.is_empty(),
            errors,
        }
    }

    /// 构建并初始化主站 (终结方法)
    ///
    /// 执行流程:
    /// 1. 验证配置
    /// 2. 初始化主站 (Initialize)
    /// 3. 加载 ESI 文件 (如果配置了)
    /// 4. 加载 ENI 配置或设置网口
    /// 5. 扫描从站 (SetNetwork)
    /// 6. 自动配置 (如果启用了 AutoStartup)
    /// 7. 应用实时优化
    ///
    /// 对应 C# `Build()` 方法。
    ///
    /// # 返回
    /// - `Ok(BuildResult)`: 初始化成功, 包含主站实例和从站数量
    /// - `Err(DarraError)`: 初始化失败
    pub fn build(self) -> Result<BuildResult> {
        // 1. 验证配置
        if !self.configuration_set {
            return Err(DarraError::Other(
                "未设置网口或 ENI 配置, 主站无法初始化".into()
            ));
        }

        // 2. 初始化主站
        let index = unsafe { ffi::Initialize() };
        if index == 0xFFFF {
            return Err(DarraError::AlreadyInitialized);
        }
        let mut master = EtherCATMaster {
            index,
            started: false,
            owned: true,
        };

        // 3. 加载 ESI 文件 (通过从站级 ESI 设置)
        // ESI 文件在 Build 阶段加载, 供后续 AutoStartup 使用
        // 注意: ESI 文件路径存储在构建器中, 在 AutoStartup 阶段由 DLL 内部处理
        for _esi_path in &self.pending_esi_paths {
            // ESI 文件由 DLL 内部在 SetNetwork 后根据从站信息自动加载
            // 此处记录路径, 实际加载在状态切换时进行
        }

        // 4. 加载 ENI 配置或设置网口
        if let Some(ref eni_path) = self.pending_eni_path {
            // 通过 JSON 配置加载 ENI (ENI 包含网口和从站配置)
            let config_json = format!(
                "{{\"eni_path\": \"{}\", \"auto_startup\": {}}}",
                eni_path.replace('\\', "\\\\").replace('"', "\\\""),
                self.pending_auto_startup
            );
            let c_json = CString::new(config_json)
                .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("配置 JSON 包含空字节").into()))?;
            let ret = unsafe {
                ffi::DarraCoreInvokeText(index, ffi::CORE_OP_23, c_json.as_ptr(), ffi::CORE_FLAG_01, 0, 0)
            };
            if ret < 0 {
                // 初始化失败, 清理资源
                master.owned = false;
                unsafe { ffi::Dispose(index) };
                return Err(DarraError::ConfigLoadFailed(ret));
            }
        }

        if let Some(ref primary) = self.pending_network {
            // 设置网口并扫描从站
            let c_adapter = CString::new(primary.as_str())
                .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("主网口名称包含空字节").into()))?;
            let redundant_str = self.pending_redundant.as_deref().unwrap_or("");
            let c_redundant = CString::new(redundant_str)
                .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("冗余网口名称包含空字节").into()))?;
            let ret = unsafe { ffi::SetNetwork(index, c_adapter.as_ptr(), c_redundant.as_ptr()) };
            if ret <= 0 {
                master.owned = false;
                unsafe { ffi::Dispose(index) };
                return Err(DarraError::NetworkFailed(ret));
            }
        }

        // 5. 获取从站数量
        let slave_count = master.slave_count() as usize;

        // 6. 自动配置 (AutoStartup: 自动配置 SM + 执行启动参数)
        if self.pending_auto_startup && slave_count > 0 {
            // 自动配置 SM2/SM3
            let ret = unsafe { ffi::DarraCoreInvoke(index, ffi::CORE_OP_24, 0, 0, 0) };
            if ret < 0 {
                master.owned = false;
                unsafe { ffi::Dispose(index) };
                return Err(DarraError::Other(format!("AutoStartup native protocol action failed: {}", ret)));
            }
        }

        // 7. 应用实时优化
        unsafe { ffi::ApplyRealtimeOptimizations() };

        Ok(BuildResult {
            master,
            slave_count,
            success: slave_count > 0,
        })
    }
}

impl Default for MasterBuilder {
    fn default() -> Self {
        Self::new()
    }
}

impl EtherCATMaster {
    // ===================== SDO 批量操作 =====================

    /// 批量读取多个从站的 SDO 对象字典
    ///
    /// 返回每个从站的 OdList, 失败的从站返回 None。
    /// 对应 DLL GetMultiSlaveSDOList / FreeMultiSlaveSDOList。
    pub fn get_multi_slave_sdo_list(&self, slave_indices: &[u16]) -> Vec<Option<crate::slave::coe::OdList>> {
        use std::os::raw::c_int;

        let count = slave_indices.len() as c_int;
        if count == 0 {
            return Vec::new();
        }

        let mut results: Vec<*const std::ffi::c_void> = vec![std::ptr::null(); count as usize];
        let ret = unsafe {
            ffi::GetMultiSlaveSDOList(
                self.index,
                slave_indices.as_ptr(),
                count,
                results.as_mut_ptr(),
            )
        };

        let mut output = Vec::with_capacity(count as usize);
        if ret <= 0 {
            // 全部失败
            for _ in 0..count {
                output.push(None);
            }
            return output;
        }

        for i in 0..count as usize {
            if results[i].is_null() {
                output.push(None);
            } else {
                // 使用与 OdList::load 相同的解析逻辑
                match crate::slave::coe::OdList::from_raw_ptr(
                    self.index, slave_indices[i], results[i],
                ) {
                    Ok(od) => output.push(Some(od)),
                    Err(_) => output.push(None),
                }
            }
        }

        // 释放 DLL 分配的批量结果
        unsafe { ffi::FreeMultiSlaveSDOList(results.as_mut_ptr(), count) };
        output
    }

    /// 解构赋值 (对应 C# Deconstruct)
    ///
    /// 返回 BuildResult 信息元组。
    pub fn deconstruct(&self) -> (bool, u16, u16) {
        (self.owned, self.slave_count(), self.index)
    }

    /// PDO 总丢帧数 (对应 C# PdoLostFrames)
    pub fn pdo_lost_frames(&self, group: u8) -> u32 {
        let mut total: u32 = 0;
        let mut consecutive: u32 = 0;
        let mut max_consecutive: u32 = 0;
        unsafe {
            ffi::GetPDOFrameLossStats(self.index, group,
                                       &mut total, &mut consecutive, &mut max_consecutive);
        }
        total
    }

    /// 当前连续丢帧数 (对应 C# PdoConsecutiveLost)
    pub fn pdo_consecutive_lost(&self, group: u8) -> u32 {
        let mut total: u32 = 0;
        let mut consecutive: u32 = 0;
        let mut max_consecutive: u32 = 0;
        unsafe {
            ffi::GetPDOFrameLossStats(self.index, group,
                                       &mut total, &mut consecutive, &mut max_consecutive);
        }
        consecutive
    }

    /// 历史最大连续丢帧数 (对应 C# PdoMaxConsecutiveLost)
    pub fn pdo_max_consecutive_lost(&self, group: u8) -> u32 {
        let mut total: u32 = 0;
        let mut consecutive: u32 = 0;
        let mut max_consecutive: u32 = 0;
        unsafe {
            ffi::GetPDOFrameLossStats(self.index, group,
                                       &mut total, &mut consecutive, &mut max_consecutive);
        }
        max_consecutive
    }

    // ===================== ESI 解析与启动参数 =====================

    /// 加载指定目录下的全部 ESI XML (对应 EcEsi_LoadDirectory)
    ///
    /// 返回成功载入的设备条目数 (>=0).
    pub fn esi_load_directory(&self, dir: &str) -> Result<i32> {
        let c_dir = CString::new(dir)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("ESI dir 含空字节").into()))?;
        let n = unsafe { ffi::EcEsi_LoadDirectory(c_dir.as_ptr()) };
        Ok(n)
    }

    /// 加载单个 ESI 文件 (对应 EcEsi_LoadFile)
    pub fn esi_load_file(&self, path: &str) -> Result<i32> {
        let c_path = CString::new(path)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("ESI 路径含空字节").into()))?;
        let n = unsafe { ffi::EcEsi_LoadFile(c_path.as_ptr()) };
        Ok(n)
    }

    /// 清空 ESI 缓存 (对应 EcEsi_Clear)
    pub fn esi_clear(&self) {
        unsafe { ffi::EcEsi_Clear() }
    }

    /// 当前已载入 ESI 设备条目数 (对应 EcEsi_GetLoadedCount)
    pub fn esi_loaded_count(&self) -> i32 {
        unsafe { ffi::EcEsi_GetLoadedCount() }
    }

    /// 自动按 vendor/product 把 ESI 匹配到全部从站 (对应 EcEsi_AutoMatchAll)
    ///
    /// 返回匹配成功的从站个数.
    pub fn esi_auto_match_all(&self) -> i32 {
        unsafe { ffi::EcEsi_AutoMatchAll(self.index) }
    }

    /// 给某个从站手动绑定 ESI 文件 (对应 EcEsi_BindToSlave)
    pub fn esi_bind_to_slave(&self, slave_index: u16, path: &str) -> Result<i32> {
        let c_path = CString::new(path)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("ESI 路径含空字节").into()))?;
        let n = unsafe { ffi::EcEsi_BindToSlave(self.index, slave_index, c_path.as_ptr()) };
        Ok(n)
    }

    /// 注册某从站的启动参数表 (对应 EcEsi_RegisterStartupParameters)
    pub fn esi_register_startup_parameters(&self, slave_index: u16) -> i32 {
        unsafe { ffi::EcEsi_RegisterStartupParameters(self.index, slave_index) }
    }

    /// 把所有已绑定 ESI 的从站启动参数注册到 SDO 队列 (对应 EcEsi_ApplyAllSlaves)
    ///
    /// 返回登记成功的启动参数总数.
    pub fn esi_apply_all_slaves(&self) -> i32 {
        unsafe { ffi::EcEsi_ApplyAllSlaves(self.index) }
    }

    /// 显式给从站设 ESI 文件名 (对应 SetSlaveEsiFile, 无路径形式)
    pub fn set_slave_esi_file(&self, slave_index: u16, name: &str) -> Result<i32> {
        let c_name = CString::new(name)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("ESI 文件名含空字节").into()))?;
        let n = unsafe { ffi::SetSlaveEsiFile(self.index, slave_index, c_name.as_ptr()) };
        Ok(n)
    }
}
