//! 从站安全封装
//!
//! 提供 Slave 结构体，封装单个从站的属性访问和协议操作。
//! 通过 EtherCATMaster::slave() 获取实例。
//!
//! ## 命名规范
//! - 只读属性: `fn xxx(&self) -> T` (无 get 前缀, Rust 惯例)
//! - 可写属性: `fn set_xxx(&self, value: T)` (set 前缀)
//! - 方法/操作: 描述性命名

use crate::data::error::{CiA402State, DarraError, EcState, SyncWindowStatus, Result};
use crate::data::types::EcALState;
use crate::utils::ffi::{self, EcSlaveBlittable, EmcyRecord, SlaveIdentity, EsmTimeouts, FoEOptions};
use std::ffi::CString;
use std::os::raw::c_int;

/// 从站详细信息 (对齐 DLL slave_detailed_info_t, pack(1))
#[repr(C, packed)]
#[derive(Debug, Clone, Copy)]
pub struct SlaveDetailedInfo {
    /// 配置地址
    pub configadr: u16,
    /// 制造商 ID
    pub eep_man: u32,
    /// 产品 ID
    pub eep_id: u32,
    /// 修订号
    pub eep_rev: u32,
    /// 当前状态
    pub state: u8,
    /// 物理类型
    pub ptype: u8,
    /// 拓扑连接数
    pub topology: u8,
    /// 活动端口
    pub activeports: u8,
    /// 父站索引
    pub parent: u16,
    /// 是否支持 DC
    pub hasdc: u8,
    /// 所属组
    pub group: u8,
    /// 输入字节数
    pub ibytes: u16,
    /// 输出字节数
    pub obytes: u16,
    /// 邮箱协议支持
    pub mbx_proto: u16,
    /// 传播延迟
    pub pdelay: i32,
    /// DC SYNC0 周期
    pub dc_cycle: i32,
    /// DC 偏移
    pub dc_shift: i32,
    /// AL 状态码
    pub al_status_code: u16,
}

/// 从站句柄 (不拥有资源，生命周期依赖 EtherCATMaster)
#[derive(Debug, Clone, Copy)]
pub struct Slave {
    master_index: u16,
    slave_index: u16,
}

impl Slave {
    /// 创建从站句柄 (内部使用)
    pub(crate) fn new(master_index: u16, slave_index: u16) -> Self {
        Self { master_index, slave_index }
    }

    // ===================== 内部辅助方法 =====================

    /// 获取从站原生结构体指针
    fn slave_ptr(&self) -> Option<*const EcSlaveBlittable> {
        let ptr = unsafe { ffi::GetSlave(self.master_index, self.slave_index) };
        if ptr.is_null() { None } else { Some(ptr as *const EcSlaveBlittable) }
    }

    /// 安全读取从站原生结构体
    fn read_slave(&self) -> Option<EcSlaveBlittable> {
        self.slave_ptr().map(|ptr| unsafe { std::ptr::read_unaligned(ptr) })
    }

    // ===================== 详细信息 =====================

    /// 获取从站详细信息
    pub fn detailed_info(&self) -> Option<SlaveDetailedInfo> {
        let ptr = unsafe { ffi::GetSlaveDetailedInfo(self.master_index, self.slave_index) };
        if ptr.is_null() {
            None
        } else {
            Some(unsafe { std::ptr::read(ptr as *const SlaveDetailedInfo) })
        }
    }

    // ===================== 基本标识属性 (只读) =====================

    /// 从站索引
    pub fn index(&self) -> u16 {
        self.slave_index
    }

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

    /// 从站名称 (来自 EEPROM group_name 字段)
    pub fn name(&self) -> String {
        self.read_slave().map(|s| s.group_name_str()).unwrap_or_default()
    }

    /// 设备名 (来自 SDO 0x1008 Device Name)
    pub fn drive_name(&self) -> String {
        self.read_slave().map(|s| s.device_name_str()).unwrap_or_default()
    }

    /// 厂商 ID (EEPROM, Phase 2-E: metadata.identity.vendor_id)
    pub fn vendor_id(&self) -> u32 {
        self.read_slave().map(|s| s.metadata.identity.vendor_id).unwrap_or(0)
    }

    /// 产品 ID (EEPROM, Phase 2-E: metadata.identity.product_id)
    pub fn product_id(&self) -> u32 {
        self.read_slave().map(|s| s.metadata.identity.product_id).unwrap_or(0)
    }

    /// 修订版本 (EEPROM, Phase 2-E: metadata.identity.revision)
    pub fn rev_id(&self) -> u32 {
        self.read_slave().map(|s| s.metadata.identity.revision).unwrap_or(0)
    }

    /// 序列号 (EEPROM, Phase 2-E: metadata.identity.serial)
    pub fn serial_number(&self) -> u32 {
        self.read_slave().map(|s| s.metadata.identity.serial).unwrap_or(0)
    }

    /// 从站身份信息 (vendor/product/revision/serial)
    pub fn identity(&self) -> Result<SlaveIdentity> {
        let mut id = SlaveIdentity { vendor_id: 0, product_code: 0, revision_no: 0, serial_no: 0 };
        if unsafe { ffi::GetSlaveIdentity(self.master_index, self.slave_index, &mut id) } != 0 {
            Ok(id)
        } else {
            Err(DarraError::Other(obfstr::obfstr!("获取从站身份失败").into()))
        }
    }

    // ===================== 地址属性 (只读) =====================

    /// 别名地址
    pub fn alias_address(&self) -> u16 {
        self.read_slave().map(|s| s.alias_addr).unwrap_or(0)
    }

    /// 物理配置地址
    pub fn config_addr(&self) -> u16 {
        self.read_slave().map(|s| s.config_addr).unwrap_or(0)
    }

    /// SII 配置索引
    pub fn sii_index(&self) -> u16 {
        self.read_slave().map(|s| s.eeprom_config.sii_index).unwrap_or(0)
    }

    // ===================== 状态属性 =====================

    /// 当前 EtherCAT 状态 (枚举)
    pub fn state(&self) -> Option<EcState> {
        let raw = unsafe { ffi::GetSlaveState(self.master_index, self.slave_index) };
        EcState::from_raw(raw)
    }

    /// 当前 EtherCAT 状态 (原始值)
    pub fn state_raw(&self) -> u8 {
        unsafe { ffi::GetSlaveState(self.master_index, self.slave_index) }
    }

    /// AL Status Code (错误码, 枚举)
    pub fn error_code(&self) -> EcALState {
        let raw = unsafe { ffi::GetSlaveALStatusCode(self.master_index, self.slave_index) };
        EcALState::from_value(raw as i32)
    }

    /// AL Status Code (原始值)
    pub fn error_code_raw(&self) -> u16 {
        unsafe { ffi::GetSlaveALStatusCode(self.master_index, self.slave_index) }
    }

    /// 从站是否丢失 (Phase 2-E: runtime.is_lost)
    pub fn is_lost(&self) -> bool {
        self.read_slave().map(|s| s.runtime.is_lost != 0).unwrap_or(false)
    }

    /// Block LRW 标志 (Phase 2-E: runtime.block_lrw)
    pub fn block_lrw(&self) -> bool {
        self.read_slave().map(|s| s.runtime.block_lrw != 0).unwrap_or(false)
    }

    // ===================== 设备类型属性 (只读) =====================

    /// 设备类型 (Phase 2-E: metadata.identity.dtype)
    pub fn dtype(&self) -> u16 {
        self.read_slave().map(|s| s.metadata.identity.dtype).unwrap_or(0)
    }

    /// 物理端口类型
    pub fn physical_type(&self) -> u8 {
        self.read_slave().map(|s| s.topo.phy_type).unwrap_or(0)
    }

    /// E-bus 电流消耗 (mA, Phase 2-E: runtime.ebus_current)
    pub fn ebus_current(&self) -> i16 {
        self.read_slave().map(|s| s.runtime.ebus_current).unwrap_or(0)
    }

    // ===================== I/O 数据属性 (只读) =====================

    /// 输入位数
    pub fn input_bits(&self) -> u16 {
        self.read_slave().map(|s| s.input.bits).unwrap_or(0)
    }

    /// 输入字节数
    pub fn input_bytes(&self) -> u32 {
        self.read_slave().map(|s| s.input.bytes).unwrap_or(0)
    }

    /// 输出位数
    pub fn output_bits(&self) -> u16 {
        self.read_slave().map(|s| s.output.bits).unwrap_or(0)
    }

    /// 输出字节数
    pub fn output_bytes(&self) -> u32 {
        self.read_slave().map(|s| s.output.bytes).unwrap_or(0)
    }

    /// 输入在 IOmap 中的偏移
    pub fn input_offset(&self) -> u32 {
        self.read_slave().map(|s| s.input.offset).unwrap_or(0)
    }

    /// 输出在 IOmap 中的偏移
    pub fn output_offset(&self) -> u32 {
        self.read_slave().map(|s| s.output.offset).unwrap_or(0)
    }

    /// 输入起始位
    pub fn input_startbit(&self) -> u8 {
        self.read_slave().map(|s| s.input.startbit).unwrap_or(0)
    }

    /// 输出起始位
    pub fn output_startbit(&self) -> u8 {
        self.read_slave().map(|s| s.output.startbit).unwrap_or(0)
    }

    /// 获取 IO 映射指针和大小
    /// 返回 (输出字节数, 输出指针, 输入字节数, 输入指针)
    pub fn io(&self) -> Result<(i32, *mut u8, i32, *mut u8)> {
        let mut out_size: c_int = 0;
        let mut out_ptr: *mut u8 = std::ptr::null_mut();
        let mut in_size: c_int = 0;
        let mut in_ptr: *mut u8 = std::ptr::null_mut();
        let ret = unsafe {
            ffi::GetIO(self.master_index, self.slave_index,
                       &mut out_size, &mut out_ptr, &mut in_size, &mut in_ptr)
        };
        if ret != 0 { Ok((out_size, out_ptr, in_size, in_ptr)) }
        else { Err(DarraError::NullPointer) }
    }

    // ===================== 邮箱属性 (只读) =====================

    /// 邮箱写入缓冲区长度 (字节)
    pub fn mbx_length(&self) -> u16 {
        self.read_slave().map(|s| s.mbx.length).unwrap_or(0)
    }

    /// 邮箱支持的协议位掩码
    pub fn mbx_protocol(&self) -> u16 {
        self.read_slave().map(|s| s.mbx.supported_proto).unwrap_or(0)
    }

    /// 邮箱读取长度
    pub fn mbx_read_length(&self) -> u16 {
        self.read_slave().map(|s| s.mbx.read_length).unwrap_or(0)
    }

    /// 邮箱写入偏移
    pub fn mbx_write_offset(&self) -> u16 {
        self.read_slave().map(|s| s.mbx.write_offset).unwrap_or(0)
    }

    /// 邮箱读取偏移
    pub fn mbx_read_offset(&self) -> u16 {
        self.read_slave().map(|s| s.mbx.read_offset).unwrap_or(0)
    }

    /// 邮箱计数器
    pub fn mbx_count(&self) -> u8 {
        self.read_slave().map(|s| s.mbx.cnt).unwrap_or(0)
    }

    // ===================== DC (分布式时钟) 属性 (只读) =====================

    /// 是否支持 DC 同步
    pub fn has_dc(&self) -> bool {
        self.read_slave().map(|s| s.topo.has_dc != 0).unwrap_or(false)
    }

    /// DC AssignActivate 值 (0=禁用)
    pub fn dc_active(&self) -> u16 {
        self.read_slave().map(|s| s.dc.active).unwrap_or(0)
    }

    /// SYNC0 周期 (纳秒)
    pub fn dc_cycle0(&self) -> i32 {
        self.read_slave().map(|s| s.dc.cycle0).unwrap_or(0)
    }

    /// SYNC1 周期 (纳秒)
    pub fn dc_cycle1(&self) -> i32 {
        self.read_slave().map(|s| s.dc.cycle1).unwrap_or(0)
    }

    /// DC 相位偏移 (纳秒)
    pub fn dc_shift(&self) -> i32 {
        self.read_slave().map(|s| s.dc.shift).unwrap_or(0)
    }

    /// DC 链中下一个从站索引
    pub fn dc_next(&self) -> u16 {
        self.read_slave().map(|s| s.dc.next).unwrap_or(0)
    }

    /// DC 链中上一个从站索引
    pub fn dc_previous(&self) -> u16 {
        self.read_slave().map(|s| s.dc.prev).unwrap_or(0)
    }

    /// DC 父端口号
    pub fn dc_parent_port(&self) -> u8 {
        self.read_slave().map(|s| s.topo.parent_port).unwrap_or(0)
    }

    /// 端口 A DC 接收时间 (纳秒)
    pub fn dc_receive_time_a(&self) -> i32 {
        self.read_slave().map(|s| s.dc.recvtime[0]).unwrap_or(0)
    }

    /// 端口 B DC 接收时间 (纳秒)
    pub fn dc_receive_time_b(&self) -> i32 {
        self.read_slave().map(|s| s.dc.recvtime[1]).unwrap_or(0)
    }

    /// 端口 C DC 接收时间 (纳秒)
    pub fn dc_receive_time_c(&self) -> i32 {
        self.read_slave().map(|s| s.dc.recvtime[2]).unwrap_or(0)
    }

    /// 端口 D DC 接收时间 (纳秒)
    pub fn dc_receive_time_d(&self) -> i32 {
        self.read_slave().map(|s| s.dc.recvtime[3]).unwrap_or(0)
    }

    /// 传播延迟 (纳秒)
    pub fn propagation_delay(&self) -> i32 {
        unsafe { ffi::GetSlavePropagationDelay(self.master_index, self.slave_index) }
    }

    // ===================== 拓扑属性 (只读) =====================

    /// 活跃端口位掩码
    pub fn active_ports(&self) -> u8 {
        unsafe { ffi::GetSlaveActivePorts(self.master_index, self.slave_index) }
    }

    /// 拓扑类型
    pub fn topology(&self) -> u8 {
        self.read_slave().map(|s| s.topo.link_count).unwrap_or(0)
    }

    /// 入口端口号
    pub fn entry_port(&self) -> u8 {
        self.read_slave().map(|s| s.topo.entry_port).unwrap_or(0)
    }

    /// 父节点从站地址
    pub fn parent(&self) -> u16 {
        unsafe { ffi::GetSlaveParent(self.master_index, self.slave_index) }
    }

    /// 父端口号
    pub fn parent_port(&self) -> u8 {
        self.read_slave().map(|s| s.topo.parent_port).unwrap_or(0)
    }

    // ===================== EEPROM 属性 (只读) =====================

    /// EEPROM 是否 8 字节寻址
    pub fn eep_8byte_addressing(&self) -> bool {
        self.read_slave().map(|s| s.eeprom_config.read_8byte != 0).unwrap_or(false)
    }

    /// EEPROM PDI 访问模式
    pub fn eep_pdi(&self) -> u8 {
        self.read_slave().map(|s| s.eeprom_config.pdi).unwrap_or(0)
    }

    // ===================== 协议详情 (只读, 来自 SII EEPROM, Phase 2-E: capabilities 子结构) =====================

    /// CoE (CANopen over EtherCAT) 协议详情
    pub fn coe_details(&self) -> u8 {
        self.read_slave().map(|s| s.capabilities.coe_details).unwrap_or(0)
    }

    /// FoE (File over EtherCAT) 协议详情
    pub fn foe_details(&self) -> u8 {
        self.read_slave().map(|s| s.capabilities.foe_details).unwrap_or(0)
    }

    /// EoE (Ethernet over EtherCAT) 协议详情
    pub fn eoe_details(&self) -> u8 {
        self.read_slave().map(|s| s.capabilities.eoe_details).unwrap_or(0)
    }

    /// SoE (Servo over EtherCAT) 协议详情
    pub fn soe_details(&self) -> u8 {
        self.read_slave().map(|s| s.capabilities.soe_details).unwrap_or(0)
    }

    // ===================== FMMU 属性 (只读, Phase 2-E: sm_fmmu.fmmu_func) =====================

    /// FMMU0 功能类型
    pub fn fmmu0_func(&self) -> u8 {
        self.read_slave().map(|s| s.sm_fmmu.fmmu_func[0]).unwrap_or(0)
    }

    /// FMMU1 功能类型
    pub fn fmmu1_func(&self) -> u8 {
        self.read_slave().map(|s| s.sm_fmmu.fmmu_func[1]).unwrap_or(0)
    }

    /// FMMU2 功能类型
    pub fn fmmu2_func(&self) -> u8 {
        self.read_slave().map(|s| s.sm_fmmu.fmmu_func[2]).unwrap_or(0)
    }

    /// FMMU3 功能类型
    pub fn fmmu3_func(&self) -> u8 {
        self.read_slave().map(|s| s.sm_fmmu.fmmu_func[3]).unwrap_or(0)
    }

    /// SyncManager 数量 (从 metadata 子结构)
    pub fn sync_manager_count(&self) -> u16 {
        self.read_slave().map(|s| s.metadata.sm_count).unwrap_or(0)
    }

    // ===================== 启动配置标志 =====================

    /// 是否支持 SDO Complete Access
    pub fn supports_complete_access(&self) -> bool {
        self.read_slave().map(|s| s.pdo_config.supports_complete_access != 0).unwrap_or(false)
    }

    /// 设置 Complete Access 支持标志
    pub fn set_supports_complete_access(&self, value: bool) {
        if let Some(ptr) = self.slave_ptr() {
            unsafe { (*(ptr as *mut EcSlaveBlittable)).pdo_config.supports_complete_access = if value { 1 } else { 0 }; }
        }
    }

    /// 是否写入 PDO Assignment
    pub fn pdo_assignment_enabled(&self) -> bool {
        self.read_slave().map(|s| s.pdo_config.assignment_enabled != 0).unwrap_or(true)
    }

    /// 设置 PDO Assignment 写入标志
    pub fn set_pdo_assignment_enabled(&self, value: bool) {
        if let Some(ptr) = self.slave_ptr() {
            unsafe { (*(ptr as *mut EcSlaveBlittable)).pdo_config.assignment_enabled = if value { 1 } else { 0 }; }
        }
    }

    /// 是否写入 PDO Configuration
    pub fn pdo_configuration_enabled(&self) -> bool {
        self.read_slave().map(|s| s.pdo_config.configuration_enabled != 0).unwrap_or(false)
    }

    /// 设置 PDO Configuration 写入标志
    pub fn set_pdo_configuration_enabled(&self, value: bool) {
        if let Some(ptr) = self.slave_ptr() {
            unsafe { (*(ptr as *mut EcSlaveBlittable)).pdo_config.configuration_enabled = if value { 1 } else { 0 }; }
        }
    }

    // ===================== 分组 (读写) =====================

    /// 从站分组 (0-7)
    pub fn group(&self) -> u8 {
        unsafe { ffi::GetSlaveGroup(self.master_index, self.slave_index) }
    }

    /// 设置从站分组 (0-7)
    pub fn set_group(&self, group: u8) -> Result<()> {
        if unsafe { ffi::SetSlaveGroup(self.master_index, self.slave_index, group) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("设置从站分组失败").into()))
        }
    }

    // ===================== 可选从站 (读写) =====================

    /// 从站是否标记为可选
    pub fn is_optional(&self) -> bool {
        (unsafe { ffi::GetSlaveOptional(self.master_index, self.slave_index) }) != 0
    }

    /// 设置从站可选标志
    pub fn set_optional(&self, optional: bool) -> Result<()> {
        if unsafe { ffi::SetSlaveOptional(self.master_index, self.slave_index, if optional { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("设置可选标志失败").into()))
        }
    }

    // ===================== 帧重发支持 =====================

    /// 从站是否支持帧重发
    pub fn supports_frame_repeat(&self) -> bool {
        (unsafe { ffi::GetSlaveSupportsFrameRepeat(self.master_index, self.slave_index) }) != 0
    }

    /// 设置从站帧重发支持标志
    pub fn set_supports_frame_repeat(&self, supports: bool) -> Result<()> {
        if unsafe { ffi::SetSlaveSupportsFrameRepeat(self.master_index, self.slave_index, if supports { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("设置帧重发支持标志失败").into()))
        }
    }

    // ===================== 看门狗 =====================

    /// 设置过程数据看门狗超时 (毫秒, 0=禁用)
    pub fn set_watchdog(&self, timeout_ms: u32) -> Result<()> {
        if unsafe { ffi::SetSlaveWatchdog(self.master_index, self.slave_index, timeout_ms) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("设置看门狗失败").into()))
        }
    }

    /// 设置 PDI 看门狗超时 (毫秒, 0=禁用)
    pub fn set_pdi_watchdog(&self, timeout_ms: u32) -> Result<()> {
        if unsafe { ffi::SetSlavePdiWatchdog(self.master_index, self.slave_index, timeout_ms) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("设置 PDI 看门狗失败").into()))
        }
    }

    /// 看门狗配置
    pub fn watchdog_config(&self) -> Result<ffi::WatchdogConfig> {
        let mut config = ffi::WatchdogConfig { wd_divider: 0, wd_time_pdi: 0, wd_time_pd: 0 };
        if unsafe { ffi::GetSlaveWatchdogConfig(self.master_index, self.slave_index, &mut config) } != 0 {
            Ok(config)
        } else {
            Err(DarraError::Other(obfstr::obfstr!("获取看门狗配置失败").into()))
        }
    }

    /// 看门狗状态
    pub fn watchdog_status(&self) -> Result<ffi::WatchdogStatus> {
        let mut status = ffi::WatchdogStatus { wd_status: 0, wd_counter: 0, wd_divider: 0, wd_time_pd: 0 };
        if unsafe { ffi::GetSlaveWatchdogStatus(self.master_index, self.slave_index, &mut status) } != 0 {
            Ok(status)
        } else {
            Err(DarraError::Other(obfstr::obfstr!("获取看门狗状态失败").into()))
        }
    }

    // ===================== 状态控制 =====================

    /// 设置从站状态 (带超时)
    pub fn set_state(&self, state: EcState, timeout_ms: u32) -> Result<()> {
        let ret = unsafe {
            ffi::SetSlaveStateWithTimeout(self.master_index, self.slave_index, state as c_int, timeout_ms)
        };
        if ret != 0 { Ok(()) } else { Err(DarraError::StateChangeFailed(state as u8)) }
    }

    // ===================== DC 同步配置 =====================

    /// 设置 DC 同步参数 (纳秒)
    pub fn set_dc_sync(&self, sync0_ns: u32, sync1_ns: u32, shift_ns: i32) {
        unsafe {
            ffi::SetSyncBySlaveIndex(self.master_index, self.slave_index, sync0_ns, sync1_ns, shift_ns);
        }
    }

    // ===================== DC 同步窗口 =====================

    /// 同步窗口状态
    pub fn sync_window_status(&self) -> Result<SyncWindowStatus> {
        let mut diff: c_int = 0;
        let mut max_diff: c_int = 0;
        let mut min_diff: c_int = 0;
        let mut in_sync: i32 = 0;
        let mut out_count: u32 = 0;
        if unsafe {
            ffi::GetSlaveSyncWindowStatus(
                self.master_index, self.slave_index,
                &mut diff, &mut max_diff, &mut min_diff,
                &mut in_sync, &mut out_count,
            )
        } != 0 {
            Ok(SyncWindowStatus {
                diff_ns: diff,
                max_diff_ns: max_diff,
                min_diff_ns: min_diff,
                in_sync: in_sync != 0,
                out_of_sync_count: out_count,
            })
        } else {
            Err(DarraError::Other(obfstr::obfstr!("获取同步窗口状态失败").into()))
        }
    }

    /// 重置同步窗口统计
    pub fn reset_sync_window_stats(&self) {
        unsafe { ffi::ResetSlaveSyncWindowStats(self.master_index, self.slave_index) };
    }

    // ===================== 身份验证 =====================

    /// 验证从站身份是否匹配
    pub fn verify_identity(&self, expected: &SlaveIdentity, check_rev: bool, check_serial: bool) -> bool {
        unsafe {
            ffi::VerifySlaveIdentity(
                self.master_index, self.slave_index, expected,
                if check_rev { 1 } else { 0 },
                if check_serial { 1 } else { 0 },
            ) != 0
        }
    }

    // ===================== ESM 超时 =====================

    /// ESM 超时配置
    pub fn esm_timeouts(&self) -> Result<EsmTimeouts> {
        let mut t = EsmTimeouts { ip: 0, ps: 0, so: 0, os: 0, sp: 0, pi: 0, bi: 0, ib: 0 };
        if unsafe { ffi::GetSlaveEsmTimeouts(self.master_index, self.slave_index, &mut t) } != 0 {
            Ok(t)
        } else {
            Err(DarraError::Other(obfstr::obfstr!("获取 ESM 超时失败").into()))
        }
    }

    /// 设置 ESM 超时配置
    pub fn set_esm_timeouts(&self, timeouts: &EsmTimeouts) -> Result<()> {
        if unsafe { ffi::SetSlaveEsmTimeouts(self.master_index, self.slave_index, timeouts) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("设置 ESM 超时失败").into()))
        }
    }

    // ===================== 寄存器/SM/FMMU 直接访问 =====================

    /// 写入从站寄存器
    pub fn write_register(&self, reg_addr: u16, data: &[u8]) -> Result<()> {
        if unsafe { ffi::WriteSlaveRegister(self.master_index, self.slave_index, reg_addr, data.as_ptr(), data.len() as u32) } != 0 {
            Ok(())
        } else {
            Err(DarraError::RegisterFailed)
        }
    }

    /// 读取从站寄存器
    pub fn read_register(&self, reg_addr: u16, len: u32) -> Result<Vec<u8>> {
        let mut buf = vec![0u8; len as usize];
        if unsafe { ffi::ReadSlaveRegister(self.master_index, self.slave_index, reg_addr, buf.as_mut_ptr(), len) } != 0 {
            Ok(buf)
        } else {
            Err(DarraError::RegisterFailed)
        }
    }

    /// 读取从站 SII EEPROM 字节区域 (按 word 循环, 内部走 SIIReadWord D_1263)
    pub fn read_eeprom(&self, byte_offset: u16, byte_length: u16) -> Result<Vec<u8>> {
        if byte_length == 0 {
            return Ok(Vec::new());
        }
        let word_addr = byte_offset >> 1;
        let word_count = (byte_length + 1) >> 1;
        let first_byte_odd = byte_offset & 1;
        let mut result: Vec<u8> = Vec::with_capacity(byte_length as usize);
        for i in 0..word_count {
            let mut w: u16 = 0;
            if unsafe { ffi::SIIReadWord(self.master_index, self.slave_index, word_addr + i, &mut w) } == 0 {
                return Err(DarraError::Other(obfstr::obfstr!("EEPROM 读失败").into()));
            }
            let lo = (w & 0xFF) as u8;
            let hi = ((w >> 8) & 0xFF) as u8;
            if i == 0 && first_byte_odd != 0 {
                if (result.len() as u16) < byte_length { result.push(hi); }
            } else {
                if (result.len() as u16) < byte_length { result.push(lo); }
                if (result.len() as u16) < byte_length { result.push(hi); }
            }
        }
        Ok(result)
    }

    /// 写入从站 SII EEPROM 字节区域 (按 word 循环, 调用方需先 SIIAcquire).
    /// 要求 byte_offset 和 data.len() 偶数.
    pub fn write_eeprom(&self, byte_offset: u16, data: &[u8]) -> Result<()> {
        if data.is_empty() || (byte_offset & 1) != 0 || (data.len() & 1) != 0 {
            return Err(DarraError::InvalidParameter(obfstr::obfstr!("EEPROM 写参数无效").into()));
        }
        let word_addr = byte_offset >> 1;
        let word_count = (data.len() / 2) as u16;
        for i in 0..word_count {
            let idx = (i as usize) * 2;
            let w: u16 = (data[idx] as u16) | ((data[idx + 1] as u16) << 8);
            if unsafe { ffi::SIIWriteWord(self.master_index, self.slave_index, word_addr + i, w) } == 0 {
                return Err(DarraError::Other(obfstr::obfstr!("EEPROM 写失败").into()));
            }
        }
        Ok(())
    }

    /// 配置 SyncManager
    pub fn configure_sync_manager(&self, sm_index: u8, start_addr: u16, length: u16, control: u8, enable: bool) -> Result<()> {
        if unsafe { ffi::ConfigureSyncManager(self.master_index, self.slave_index, sm_index, start_addr, length, control, if enable { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("配置 SyncManager 失败").into()))
        }
    }

    /// 配置 FMMU
    pub fn configure_fmmu(
        &self, fmmu_index: u8, logical_addr: u32, length: u16,
        logical_start_bit: u8, logical_end_bit: u8,
        physical_addr: u16, physical_start_bit: u8,
        fmmu_type: u8, enable: bool,
    ) -> Result<()> {
        if unsafe {
            ffi::ConfigureFMMU(
                self.master_index, self.slave_index, fmmu_index,
                logical_addr, length, logical_start_bit, logical_end_bit,
                physical_addr, physical_start_bit, fmmu_type,
                if enable { 1 } else { 0 },
            )
        } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("配置 FMMU 失败").into()))
        }
    }

    // ===================== DL Port 端口控制 =====================
    //
    // 直接读写 ESC 的 DL Port Control 寄存器 (0x0101), 用于端口故障注入测试
    // 与冗余/环拓扑的手动诊断。正常运行时无需调用。
    //
    // DLPORT 值:
    // - `0x00` = Auto (所有端口由 ESC 自动管理, 默认)
    // - `0x03` = 关闭 P0
    // - `0x0C` = 关闭 P1
    // - `0x30` = 关闭 P2
    // - `0xC0` = 关闭 P3
    //
    // SDK 自动采用 primary → secondary → APWR 三级回退写入路径,
    // 即使 P0 关闭后仍能通过副网口/广播恢复。

    /// 写入从站 DL Port 控制寄存器 (0x0101)
    ///
    /// # 参数
    /// - `value`: DLPORT 值 (0x00=Auto, 0x03=P0关, 0x0C=P1关, 0x30=P2关, 0xC0=P3关)
    ///
    /// # 返回
    /// `true` = 写入成功
    pub fn write_dl_port(&self, value: u8) -> bool {
        unsafe { ffi::WriteSlaveDLPORT(self.master_index, self.slave_index, value) != 0 }
    }

    /// 读取从站 DL Port 控制寄存器 (0x0101) 的当前值
    ///
    /// # 返回
    /// `Some(dlport)` 读取成功; `None` 读取失败 (如从站离线)
    pub fn read_dl_port(&self) -> Option<u8> {
        let mut val: u8 = 0;
        let ok = unsafe { ffi::ReadSlaveDLPORT(self.master_index, self.slave_index, &mut val) };
        if ok != 0 { Some(val) } else { None }
    }

    // ===================== OpOnly / DeviceEmulation 标志 =====================

    /// 是否为 OpOnly 从站
    pub fn is_op_only(&self) -> bool {
        unsafe { ffi::GetSlaveOpOnlyFlag(self.master_index, self.slave_index) != 0 }
    }

    /// 是否为 Device Emulation 设备
    pub fn is_device_emulation(&self) -> bool {
        unsafe { ffi::GetSlaveDeviceEmulationFlag(self.master_index, self.slave_index) != 0 }
    }

    /// 启用输出 SyncManager
    pub fn enable_output_sync_manager(&self) -> Result<()> {
        if unsafe { ffi::EnableOutputSyncManager(self.master_index, self.slave_index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("启用输出 SyncManager 失败").into()))
        }
    }

    /// 禁用输出 SyncManager
    pub fn disable_output_sync_manager(&self) -> Result<()> {
        if unsafe { ffi::DisableOutputSyncManager(self.master_index, self.slave_index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("禁用输出 SyncManager 失败").into()))
        }
    }

    /// 设置错误确认位
    pub fn set_error_ack(&self, set_ack: bool) -> Result<()> {
        if unsafe { ffi::SetSlaveErrorAck(self.master_index, self.slave_index, if set_ack { 1 } else { 0 }) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("设置错误确认位失败").into()))
        }
    }

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

    /// 是否需要启动参数重配置
    pub fn needs_startup_reconfig(&self) -> bool {
        unsafe { ffi::GetSlaveNeedsStartupReconfig(self.master_index, self.slave_index) != 0 }
    }

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

    // ===================== CoE (CANopen over EtherCAT) =====================

    /// SDO 读取 (返回原始字节)
    pub fn sdo_read(&self, index: u16, subindex: u8, complete_access: bool) -> Result<Vec<u8>> {
        let mut size: c_int = 0;
        let ptr = unsafe {
            ffi::SDOread(self.master_index, self.slave_index, index, subindex,
                         if complete_access { 1 } else { 0 }, &mut size)
        };
        if ptr.is_null() || size <= 0 {
            if !ptr.is_null() { unsafe { ffi::FreeMemory(ptr as *mut _) }; }
            return Err(DarraError::SdoReadFailed { index, subindex });
        }
        let data = unsafe { std::slice::from_raw_parts(ptr, size as usize).to_vec() };
        unsafe { ffi::FreeMemory(ptr as *mut _) };
        Ok(data)
    }

    /// SDO 读取并转换为指定类型
    pub fn sdo_read_value<T: Copy>(&self, index: u16, subindex: u8) -> Result<T> {
        let data = self.sdo_read(index, subindex, false)?;
        if data.len() < std::mem::size_of::<T>() {
            return Err(DarraError::SdoReadFailed { index, subindex });
        }
        Ok(unsafe { std::ptr::read_unaligned(data.as_ptr() as *const T) })
    }

    /// SDO 写入 (原始字节)
    pub fn sdo_write(&self, index: u16, subindex: u8, complete_access: bool, data: &[u8]) -> Result<()> {
        let ok = unsafe {
            ffi::SDOwrite_raw(self.master_index, self.slave_index, index, subindex,
                              if complete_access { 1 } else { 0 }, data.as_ptr(), data.len() as c_int)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::SdoWriteFailed { index, subindex }) }
    }

    /// SDO 写入指定类型的值
    pub fn sdo_write_value<T: Copy>(&self, index: u16, subindex: u8, value: &T) -> Result<()> {
        let bytes = unsafe {
            std::slice::from_raw_parts(value as *const T as *const u8, std::mem::size_of::<T>())
        };
        self.sdo_write(index, subindex, false, bytes)
    }

    // ===================== SoE (Servo over EtherCAT) =====================

    /// SoE 读取 IDN 参数
    pub fn soe_read(&self, idn: u16, drive_no: u8, element_flags: u8, timeout_us: i32) -> Result<Vec<u8>> {
        let mut data_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut data_size: c_int = 0;
        let ok = unsafe {
            ffi::SoERead(self.master_index, self.slave_index, drive_no, element_flags, idn,
                         &mut data_ptr, &mut data_size, timeout_us)
        };
        if ok == 0 || data_ptr.is_null() || data_size <= 0 {
            if !data_ptr.is_null() { unsafe { ffi::FreeMemory(data_ptr) }; }
            return Err(DarraError::SoeFailed(idn));
        }
        let data = unsafe { std::slice::from_raw_parts(data_ptr as *const u8, data_size as usize).to_vec() };
        unsafe { ffi::FreeMemory(data_ptr) };
        Ok(data)
    }

    /// SoE 写入 IDN 参数
    pub fn soe_write(&self, idn: u16, drive_no: u8, element_flags: u8, data: &[u8], timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::SoEWrite(self.master_index, self.slave_index, drive_no, element_flags, idn,
                          data.as_ptr(), data.len() as c_int, timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::SoeFailed(idn)) }
    }

    /// SoE 读取 IDN 名称
    pub fn soe_read_name(&self, idn: u16, drive_no: u8, timeout_us: i32) -> Result<String> {
        let mut name_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut name_len: c_int = 0;
        let ok = unsafe {
            ffi::SoEReadName(self.master_index, self.slave_index, drive_no, idn,
                             &mut name_ptr, &mut name_len, timeout_us)
        };
        if ok == 0 || name_ptr.is_null() || name_len <= 0 {
            if !name_ptr.is_null() { unsafe { ffi::FreeMemory(name_ptr) }; }
            return Err(DarraError::SoeFailed(idn));
        }
        let bytes = unsafe { std::slice::from_raw_parts(name_ptr as *const u8, name_len as usize) };
        // [2026-05-08 修复乱码] SoE IDN 名走多编码兜底 (UTF-8/ASCII/Latin-1)
        let name = crate::utils::help::decode_ethercat_string(bytes);
        unsafe { ffi::FreeMemory(name_ptr) };
        Ok(name)
    }

    /// SoE 读取 IDN 单位
    pub fn soe_read_unit(&self, idn: u16, drive_no: u8, timeout_us: i32) -> Result<String> {
        let mut unit_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut unit_len: c_int = 0;
        let ok = unsafe {
            ffi::SoEReadUnit(self.master_index, self.slave_index, drive_no, idn,
                             &mut unit_ptr, &mut unit_len, timeout_us)
        };
        if ok == 0 || unit_ptr.is_null() || unit_len <= 0 {
            if !unit_ptr.is_null() { unsafe { ffi::FreeMemory(unit_ptr) }; }
            return Err(DarraError::SoeFailed(idn));
        }
        let bytes = unsafe { std::slice::from_raw_parts(unit_ptr as *const u8, unit_len as usize) };
        // [2026-05-08 修复乱码] SoE IDN 单位走多编码兜底 (UTF-8/ASCII/Latin-1)
        let unit = crate::utils::help::decode_ethercat_string(bytes);
        unsafe { ffi::FreeMemory(unit_ptr) };
        Ok(unit)
    }

    /// SoE 读取 IDN 最小最大值
    pub fn soe_read_min_max(&self, idn: u16, drive_no: u8, timeout_us: i32) -> Result<(Vec<u8>, Vec<u8>)> {
        let mut min_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut min_size: c_int = 0;
        let mut max_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut max_size: c_int = 0;
        let ok = unsafe {
            ffi::SoEReadMinMax(self.master_index, self.slave_index, drive_no, idn,
                               &mut min_ptr, &mut min_size, &mut max_ptr, &mut max_size, timeout_us)
        };
        if ok == 0 {
            return Err(DarraError::SoeFailed(idn));
        }
        let min_data = if !min_ptr.is_null() && min_size > 0 {
            let d = unsafe { std::slice::from_raw_parts(min_ptr as *const u8, min_size as usize).to_vec() };
            unsafe { ffi::FreeMemory(min_ptr) };
            d
        } else { Vec::new() };
        let max_data = if !max_ptr.is_null() && max_size > 0 {
            let d = unsafe { std::slice::from_raw_parts(max_ptr as *const u8, max_size as usize).to_vec() };
            unsafe { ffi::FreeMemory(max_ptr) };
            d
        } else { Vec::new() };
        Ok((min_data, max_data))
    }

    /// SoE 读取 IDN 属性字 (4字节)
    pub fn soe_read_attributes(&self, idn: u16, drive_no: u8, timeout_us: i32) -> Result<u32> {
        let mut attrs: u32 = 0;
        let ok = unsafe {
            ffi::SoEReadAttributes(self.master_index, self.slave_index, drive_no, idn,
                                   &mut attrs, timeout_us)
        };
        if ok != 0 { Ok(attrs) } else { Err(DarraError::SoeFailed(idn)) }
    }

    /// SoE 获取从站支持的所有 IDN 列表
    pub fn soe_read_idn_list(&self, drive_no: u8, timeout_us: i32) -> Result<Vec<u16>> {
        let mut list_ptr: *mut u16 = std::ptr::null_mut();
        let mut list_count: c_int = 0;
        let ok = unsafe {
            ffi::SoEReadIDNList(self.master_index, self.slave_index, drive_no,
                                &mut list_ptr, &mut list_count, timeout_us)
        };
        if ok == 0 || list_ptr.is_null() || list_count <= 0 {
            if !list_ptr.is_null() { unsafe { ffi::FreeMemory(list_ptr as *mut _) }; }
            return Err(DarraError::SoeFailed(0));
        }
        let idns = unsafe {
            std::slice::from_raw_parts(list_ptr, list_count as usize).to_vec()
        };
        unsafe { ffi::FreeMemory(list_ptr as *mut _) };
        Ok(idns)
    }

    // ===================== FoE (File over EtherCAT) =====================

    /// FoE 下载文件 (从从站读取)
    pub fn foe_read(&self, filename: &str, password: u32, timeout_us: i32) -> Result<Vec<u8>> {
        let c_filename = CString::new(filename)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("文件名包含空字节").into()))?;
        let mut file_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut file_size: c_int = 0;
        let ok = unsafe {
            ffi::FOERead(self.master_index, self.slave_index, c_filename.as_ptr(),
                         password, &mut file_ptr, &mut file_size, timeout_us)
        };
        if ok == 0 || file_ptr.is_null() {
            return Err(DarraError::FoeFailed(filename.to_string()));
        }
        let data = if file_size > 0 {
            unsafe { std::slice::from_raw_parts(file_ptr as *const u8, file_size as usize).to_vec() }
        } else { Vec::new() };
        unsafe { ffi::FreeMemory(file_ptr) };
        Ok(data)
    }

    /// FoE 上传文件 (写入从站)
    pub fn foe_write(&self, filename: &str, password: u32, data: &[u8], timeout_us: i32) -> Result<()> {
        let c_filename = CString::new(filename)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("文件名包含空字节").into()))?;
        let ok = unsafe {
            ffi::FOEWrite(self.master_index, self.slave_index, c_filename.as_ptr(),
                          password, data.as_ptr() as *const _, data.len() as c_int, timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::FoeFailed(filename.to_string())) }
    }

    /// FoE 扩展读取 (带选项)
    pub fn foe_read_ex(&self, filename: &str, password: u32, timeout_us: i32, options: &mut FoEOptions) -> Result<Vec<u8>> {
        let c_filename = CString::new(filename)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("文件名包含空字节").into()))?;
        let mut file_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut file_size: c_int = 0;
        let ok = unsafe {
            ffi::FOEReadEx(self.master_index, self.slave_index, c_filename.as_ptr(),
                           password, &mut file_ptr, &mut file_size, timeout_us, options)
        };
        if ok == 0 || file_ptr.is_null() {
            return Err(DarraError::FoeFailed(filename.to_string()));
        }
        let data = if file_size > 0 {
            unsafe { std::slice::from_raw_parts(file_ptr as *const u8, file_size as usize).to_vec() }
        } else { Vec::new() };
        unsafe { ffi::FreeMemory(file_ptr) };
        Ok(data)
    }

    /// FoE 扩展写入 (带选项)
    pub fn foe_write_ex(&self, filename: &str, password: u32, data: &[u8], timeout_us: i32, options: &mut FoEOptions) -> Result<()> {
        let c_filename = CString::new(filename)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("文件名包含空字节").into()))?;
        let ok = unsafe {
            ffi::FOEWriteEx(self.master_index, self.slave_index, c_filename.as_ptr(),
                            password, data.as_ptr() as *const _, data.len() as c_int, timeout_us, options)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::FoeFailed(filename.to_string())) }
    }

    /// 设置 FoE 进度回调
    pub fn foe_set_progress_hook(master_index: u16, callback: ffi::FoEProgressCallback) -> Result<()> {
        if unsafe { ffi::FOESetProgressHook(master_index, Some(callback)) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("设置 FoE 进度回调失败").into()))
        }
    }

    /// 清除 FoE 进度回调
    pub fn foe_clear_progress_hook(master_index: u16) -> Result<()> {
        if unsafe { ffi::FOEClearProgressHook(master_index) } != 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("清除 FoE 进度回调失败").into()))
        }
    }

    // ===================== EoE (Ethernet over EtherCAT) =====================

    /// EoE 设置 IP 参数
    pub fn eoe_set_ip(&self, port: u8, ip: u32, subnet: u32, gateway: u32, timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::EOESetIP(self.master_index, self.slave_index, port, ip, subnet, gateway, timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    /// EoE 获取 IP 参数
    pub fn eoe_ip(&self, port: u8, timeout_us: i32) -> Result<(u32, u32, u32)> {
        let mut ip: u32 = 0;
        let mut subnet: u32 = 0;
        let mut gateway: u32 = 0;
        let ok = unsafe {
            ffi::EOEGetIP(self.master_index, self.slave_index, port,
                          &mut ip, &mut subnet, &mut gateway, timeout_us)
        };
        if ok != 0 { Ok((ip, subnet, gateway)) } else { Err(DarraError::EoeFailed) }
    }

    /// EoE 发送以太网帧
    pub fn eoe_send_frame(&self, port: u8, data: &[u8], timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::EOESendFrame(self.master_index, self.slave_index, port,
                              data.as_ptr(), data.len() as c_int, timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    /// EoE 接收以太网帧
    pub fn eoe_receive_frame(&self, port: u8, timeout_us: i32) -> Result<Vec<u8>> {
        let mut frame_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut frame_size: c_int = 0;
        let ok = unsafe {
            ffi::EOEReceiveFrame(self.master_index, self.slave_index, port,
                                 &mut frame_ptr, &mut frame_size, timeout_us)
        };
        if ok == 0 || frame_ptr.is_null() {
            return Err(DarraError::EoeFailed);
        }
        // 修复: 无论 frame_size 是否为 0，只要 DLL 分配了内存就必须释放
        let data = if frame_size > 0 {
            unsafe { std::slice::from_raw_parts(frame_ptr as *const u8, frame_size as usize).to_vec() }
        } else {
            Vec::new()
        };
        unsafe { ffi::FreeMemory(frame_ptr) };
        Ok(data)
    }

    /// EoE 设置 MAC 地址
    pub fn eoe_set_mac(&self, port: u8, mac: &[u8; 6], timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::EOESetMAC(self.master_index, self.slave_index, port, mac.as_ptr(), timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    /// EoE 获取 MAC 地址
    pub fn eoe_mac(&self, port: u8, timeout_us: i32) -> Result<[u8; 6]> {
        let mut mac = [0u8; 6];
        let ok = unsafe {
            ffi::EOEGetMAC(self.master_index, self.slave_index, port, mac.as_mut_ptr(), timeout_us)
        };
        if ok != 0 { Ok(mac) } else { Err(DarraError::EoeFailed) }
    }

    /// EoE 设置 DNS 参数
    pub fn eoe_set_dns(&self, port: u8, dns_ip: u32, dns_name: &str, timeout_us: i32) -> Result<()> {
        let c_name = CString::new(dns_name)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("DNS 名称包含空字节").into()))?;
        let ok = unsafe {
            ffi::EOESetDNS(self.master_index, self.slave_index, port, dns_ip, c_name.as_ptr(), timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    /// EoE 获取 DNS 参数
    pub fn eoe_dns(&self, port: u8, timeout_us: i32) -> Result<(u32, String)> {
        let mut dns_ip: u32 = 0;
        let mut dns_name_buf = [0i8; 256];
        let ok = unsafe {
            ffi::EOEGetDNS(self.master_index, self.slave_index, port,
                           &mut dns_ip, dns_name_buf.as_mut_ptr(), timeout_us)
        };
        if ok == 0 { return Err(DarraError::EoeFailed); }
        let name = unsafe { std::ffi::CStr::from_ptr(dns_name_buf.as_ptr()) }
            .to_string_lossy().into_owned();
        Ok((dns_ip, name))
    }

    /// EoE 获取全部参数
    pub fn eoe_full_param(&self, port: u8, timeout_us: i32) -> Result<(u32, u32, u32, [u8; 6], u32, String)> {
        let mut ip: u32 = 0;
        let mut subnet: u32 = 0;
        let mut gateway: u32 = 0;
        let mut mac = [0u8; 6];
        let mut dns_ip: u32 = 0;
        let mut dns_name_buf = [0i8; 256];
        let ok = unsafe {
            ffi::EOEGetFullParam(
                self.master_index, self.slave_index, port,
                &mut ip, &mut subnet, &mut gateway,
                mac.as_mut_ptr(), &mut dns_ip, dns_name_buf.as_mut_ptr(), timeout_us,
            )
        };
        if ok == 0 { return Err(DarraError::EoeFailed); }
        let name = unsafe { std::ffi::CStr::from_ptr(dns_name_buf.as_ptr()) }
            .to_string_lossy().into_owned();
        Ok((ip, subnet, gateway, mac, dns_ip, name))
    }

    /// EoE 设置全部参数
    pub fn eoe_set_full_param(
        &self, port: u8, ip: u32, subnet: u32, gateway: u32,
        mac: &[u8; 6], dns_ip: u32, dns_name: &str, timeout_us: i32,
    ) -> Result<()> {
        let c_name = CString::new(dns_name)
            .map_err(|_| DarraError::InvalidParameter(obfstr::obfstr!("DNS 名称包含空字节").into()))?;
        let ok = unsafe {
            ffi::EOESetFullParam(
                self.master_index, self.slave_index, port,
                ip, subnet, gateway, mac.as_ptr(), dns_ip, c_name.as_ptr(), timeout_us,
            )
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    /// EoE 设置地址过滤
    pub fn eoe_set_address_filter(&self, port: u8, mac_filters: &[u8], filter_count: u8, timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::EOESetAddressFilter(
                self.master_index, self.slave_index, port,
                filter_count, mac_filters.as_ptr(), timeout_us,
            )
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::EoeFailed) }
    }

    /// EoE 获取地址过滤
    pub fn eoe_address_filter(&self, port: u8, max_filters: i32, timeout_us: i32) -> Result<(u8, Vec<u8>)> {
        let mut filter_count: u8 = 0;
        let buf_size = (max_filters as usize) * 6;
        let mut mac_buf = vec![0u8; buf_size];
        let ok = unsafe {
            ffi::EOEGetAddressFilter(
                self.master_index, self.slave_index, port,
                &mut filter_count, mac_buf.as_mut_ptr(), max_filters, timeout_us,
            )
        };
        if ok == 0 { return Err(DarraError::EoeFailed); }
        mac_buf.truncate((filter_count as usize) * 6);
        Ok((filter_count, mac_buf))
    }

    // ===================== AoE (ADS over EtherCAT) =====================

    /// AoE 读写操作
    pub fn aoe_read_write(&self, index_group: u32, index_offset: u32, read_length: u32, write_data: &[u8], timeout_us: i32) -> Result<Vec<u8>> {
        let mut read_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut bytes_read: u32 = 0;
        let ok = unsafe {
            ffi::AOEReadWrite(self.master_index, self.slave_index, index_group, index_offset,
                              read_length, write_data.len() as u32, write_data.as_ptr(),
                              &mut read_ptr, &mut bytes_read, timeout_us)
        };
        if ok == 0 { return Err(DarraError::AoeFailed); }
        let data = if !read_ptr.is_null() && bytes_read > 0 {
            let d = unsafe { std::slice::from_raw_parts(read_ptr as *const u8, bytes_read as usize).to_vec() };
            unsafe { ffi::FreeMemory(read_ptr) };
            d
        } else { Vec::new() };
        Ok(data)
    }

    /// AoE 读取设备信息
    pub fn aoe_read_device_info(&self, timeout_us: i32) -> Result<(u8, u8, u16, String)> {
        let mut major: u8 = 0;
        let mut minor: u8 = 0;
        let mut build: u16 = 0;
        let mut name_buf = [0u8; 64];
        let ok = unsafe {
            ffi::AOEReadDeviceInfo(self.master_index, self.slave_index,
                                   &mut major, &mut minor, &mut build,
                                   name_buf.as_mut_ptr(), 64, timeout_us)
        };
        if ok == 0 { return Err(DarraError::AoeFailed); }
        let name_len = name_buf.iter().position(|&b| b == 0).unwrap_or(64);
        // [2026-05-08 修复乱码] AoE 设备名走多编码兜底 (UTF-8/ASCII/Latin-1)
        let name = crate::utils::help::decode_ethercat_string(&name_buf[..name_len]);
        Ok((major, minor, build, name))
    }

    /// AoE 读取状态
    pub fn aoe_read_state(&self, timeout_us: i32) -> Result<(u16, u16)> {
        let mut ads_state: u16 = 0;
        let mut device_state: u16 = 0;
        let ok = unsafe {
            ffi::AOEReadState(self.master_index, self.slave_index,
                              &mut ads_state, &mut device_state, timeout_us)
        };
        if ok != 0 { Ok((ads_state, device_state)) } else { Err(DarraError::AoeFailed) }
    }

    /// AoE 写入控制
    pub fn aoe_write_control(&self, ads_state: u16, device_state: u16, data: &[u8], timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::AOEWriteControl(self.master_index, self.slave_index,
                                 ads_state, device_state, data.as_ptr(), data.len() as c_int, timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::AoeFailed) }
    }

    /// AoE 添加通知
    pub fn aoe_add_notification(
        &self, index_group: u32, index_offset: u32, length: u32,
        trans_mode: u32, max_delay: u32, cycle_time: u32, timeout_us: i32,
    ) -> Result<u32> {
        let mut handle: u32 = 0;
        let ok = unsafe {
            ffi::AOEAddNotification(self.master_index, self.slave_index,
                                    index_group, index_offset, length,
                                    trans_mode, max_delay, cycle_time,
                                    &mut handle, timeout_us)
        };
        if ok != 0 { Ok(handle) } else { Err(DarraError::AoeFailed) }
    }

    /// AoE 删除通知
    pub fn aoe_del_notification(&self, handle: u32, timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::AOEDelNotification(self.master_index, self.slave_index, handle, timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::AoeFailed) }
    }

    /// AoE 设置配置
    pub fn aoe_set_config(&self, target_net_id: &[u8; 6], target_port: u16, source_net_id: &[u8; 6], source_port: u16) -> Result<()> {
        let ok = unsafe {
            ffi::AOESetConfig(self.master_index, self.slave_index,
                              target_net_id.as_ptr(), target_port,
                              source_net_id.as_ptr(), source_port)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::AoeFailed) }
    }

    /// AoE 获取配置
    pub fn aoe_config(&self) -> Result<([u8; 6], u16, [u8; 6], u16)> {
        let mut target_net_id = [0u8; 6];
        let mut target_port: u16 = 0;
        let mut source_net_id = [0u8; 6];
        let mut source_port: u16 = 0;
        let ok = unsafe {
            ffi::AOEGetConfig(self.master_index, self.slave_index,
                              target_net_id.as_mut_ptr(), &mut target_port,
                              source_net_id.as_mut_ptr(), &mut source_port)
        };
        if ok != 0 { Ok((target_net_id, target_port, source_net_id, source_port)) }
        else { Err(DarraError::AoeFailed) }
    }

    /// AoE 发送命令
    pub fn aoe_send_command(&self, target_port: u16, command_id: u16, command_data: &[u8], timeout_us: i32) -> Result<Vec<u8>> {
        let mut response_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut response_size: u32 = 0;
        let ok = unsafe {
            ffi::AOESendCommand(
                self.master_index, self.slave_index, target_port, command_id,
                command_data.as_ptr(), command_data.len() as u32,
                &mut response_ptr, &mut response_size, timeout_us,
            )
        };
        if ok == 0 { return Err(DarraError::AoeFailed); }
        let data = if !response_ptr.is_null() && response_size > 0 {
            let d = unsafe { std::slice::from_raw_parts(response_ptr as *const u8, response_size as usize).to_vec() };
            unsafe { ffi::FreeMemory(response_ptr) };
            d
        } else { Vec::new() };
        Ok(data)
    }

    // ===================== VoE (Vendor over EtherCAT) =====================

    /// 是否支持 VoE
    pub fn voe_is_supported(&self) -> bool {
        (unsafe { ffi::VOEIsSupported(self.master_index, self.slave_index) }) != 0
    }

    /// VoE 发送数据
    pub fn voe_send(&self, vendor_id: u32, vendor_type: u16, data: &[u8], timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::VOESend(self.master_index, self.slave_index, vendor_id, vendor_type,
                         data.as_ptr(), data.len() as c_int, timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::VoeFailed) }
    }

    /// VoE 接收数据
    pub fn voe_receive(&self, timeout_us: i32) -> Result<(u32, u16, Vec<u8>)> {
        let mut vendor_id: u32 = 0;
        let mut vendor_type: u16 = 0;
        let mut data_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut data_size: c_int = 0;
        let ok = unsafe {
            ffi::VOEReceive(self.master_index, self.slave_index,
                            &mut vendor_id, &mut vendor_type, &mut data_ptr, &mut data_size, timeout_us)
        };
        if ok == 0 { return Err(DarraError::VoeFailed); }
        let data = if !data_ptr.is_null() && data_size > 0 {
            let d = unsafe { std::slice::from_raw_parts(data_ptr as *const u8, data_size as usize).to_vec() };
            unsafe { ffi::FreeMemory(data_ptr) };
            d
        } else { Vec::new() };
        Ok((vendor_id, vendor_type, data))
    }

    /// VoE 发送原始帧
    pub fn voe_send_raw(&self, frame_data: &[u8], timeout_us: i32) -> Result<()> {
        let ok = unsafe {
            ffi::VOESendRaw(self.master_index, self.slave_index,
                            frame_data.as_ptr(), frame_data.len() as c_int, timeout_us)
        };
        if ok != 0 { Ok(()) } else { Err(DarraError::VoeFailed) }
    }

    /// VoE 接收原始帧
    pub fn voe_receive_raw(&self, timeout_us: i32) -> Result<Vec<u8>> {
        let mut data_ptr: *mut std::ffi::c_void = std::ptr::null_mut();
        let mut data_size: c_int = 0;
        let ok = unsafe {
            ffi::VOEReceiveRaw(self.master_index, self.slave_index,
                               &mut data_ptr, &mut data_size, timeout_us)
        };
        if ok == 0 { return Err(DarraError::VoeFailed); }
        let data = if !data_ptr.is_null() && data_size > 0 {
            let d = unsafe { std::slice::from_raw_parts(data_ptr as *const u8, data_size as usize).to_vec() };
            unsafe { ffi::FreeMemory(data_ptr) };
            d
        } else { Vec::new() };
        Ok(data)
    }

    // ===================== 启动参数 =====================

    /// 添加启动参数
    pub fn add_startup_parameter(
        &self, index: u16, sub_index: u8, data: &[u8],
        transition: u8, timing: u8, complete_access: bool,
    ) -> Result<()> {
        let mut param = ffi::StartupParam {
            index, sub_index, data: [0u8; 256],
            data_len: data.len().min(256) as u16,
            transition, timing, priority: 0,
            complete_access: if complete_access { 1 } else { 0 },
            is_register_write: 0,
        };
        let copy_len = data.len().min(256);
        param.data[..copy_len].copy_from_slice(&data[..copy_len]);
        let ret = unsafe { ffi::AddStartupParameter(self.master_index, self.slave_index, &param) };
        if ret >= 0 { Ok(()) }
        else { Err(DarraError::Other(format!("添加启动参数失败 (返回码: {})", ret))) }
    }

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

    /// 启动参数数量
    pub fn startup_parameter_count(&self) -> i32 {
        unsafe { ffi::GetStartupParameterCount(self.master_index, self.slave_index) }
    }

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

    // ===================== 输出写入 =====================

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

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

    // ===================== CiA 402 驱动器控制 =====================

    /// 当前 CiA 402 驱动器状态
    pub fn cia402_state(&self) -> CiA402State {
        let sw = unsafe { ffi::CiA402_ReadStatusWord(self.master_index, self.slave_index) };
        let raw = unsafe { ffi::CiA402_ParseState(sw) };
        CiA402State::from_raw(raw)
    }

    /// 使能驱动器
    pub fn cia402_enable(&self) -> Result<()> {
        let ret = unsafe { ffi::CiA402_Enable(self.master_index, self.slave_index, 50) };
        if ret >= 0 { Ok(()) }
        else { Err(DarraError::CiA402Failed(format!("使能失败 (返回码: {})", ret))) }
    }

    /// 设置 CiA 402 运行模式
    pub fn cia402_set_mode(&self, mode: i8) -> Result<()> {
        let ret = unsafe { ffi::CiA402_SetMode(self.master_index, self.slave_index, mode) };
        if ret >= 0 { Ok(()) }
        else { Err(DarraError::CiA402Failed(format!("设置模式失败 (返回码: {})", ret))) }
    }

    /// 当前 CiA 402 运行模式
    pub fn cia402_mode(&self) -> i8 {
        unsafe { ffi::CiA402_GetMode(self.master_index, self.slave_index) }
    }

    /// StatusWord
    pub fn cia402_status_word(&self) -> u16 {
        unsafe { ffi::CiA402_ReadStatusWord(self.master_index, self.slave_index) }
    }

    /// 写入 ControlWord
    pub fn cia402_write_control_word(&self, cw: u16) -> Result<()> {
        let ret = unsafe { ffi::CiA402_WriteControlWord(self.master_index, self.slave_index, cw) };
        if ret >= 0 { Ok(()) }
        else { Err(DarraError::CiA402Failed("写入控制字失败".into())) }
    }

    /// 故障复位
    pub fn cia402_fault_reset(&self) -> Result<()> {
        let ret = unsafe { ffi::CiA402_FaultReset(self.master_index, self.slave_index) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::CiA402Failed("故障复位失败".into())) }
    }

    // ===================== EMCY 紧急报文 =====================

    /// EMCY 历史记录
    pub fn emcy_history(&self) -> Vec<EmcyRecord> {
        let mut buf = vec![
            EmcyRecord { error_code: 0, error_register: 0, data: [0u8; 5], slave_index: 0, timestamp_ms: 0 };
            64
        ];
        let count = unsafe {
            ffi::EmcyGetHistory(self.master_index, self.slave_index, buf.as_mut_ptr(), 64)
        };
        if count > 0 { buf.truncate(count as usize); buf }
        else { Vec::new() }
    }

    /// EMCY 记录数量
    pub fn emcy_count(&self) -> usize {
        let count = unsafe { ffi::EmcyGetCount(self.master_index, self.slave_index) };
        if count > 0 { count as usize } else { 0 }
    }

    /// 清除 EMCY 历史记录
    pub fn clear_emcy(&self) {
        unsafe { ffi::EmcyClearHistory(self.master_index, self.slave_index) };
    }

    // ===================== PDO 类型化读取 =====================

    /// 读取输入 PDO u8 值
    pub fn read_input_u8(&self, offset: u32) -> u8 {
        unsafe { ffi::PDOReadInputU8(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO i8 值
    pub fn read_input_i8(&self, offset: u32) -> i8 {
        unsafe { ffi::PDOReadInputU8(self.master_index, self.slave_index, offset) as i8 }
    }

    /// 读取输入 PDO i16 值
    pub fn read_input_i16(&self, offset: u32) -> i16 {
        unsafe { ffi::PDOReadInputI16(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO u16 值
    pub fn read_input_u16(&self, offset: u32) -> u16 {
        unsafe { ffi::PDOReadInputU16(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO i32 值
    pub fn read_input_i32(&self, offset: u32) -> i32 {
        unsafe { ffi::PDOReadInputI32(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO u32 值
    pub fn read_input_u32(&self, offset: u32) -> u32 {
        unsafe { ffi::PDOReadInputU32(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO f32 值
    pub fn read_input_f32(&self, offset: u32) -> f32 {
        unsafe { ffi::PDOReadInputF32(self.master_index, self.slave_index, offset) }
    }

    // ===================== PDO 类型化写入 =====================

    /// 写入输出 PDO u8 值
    pub fn write_output_u8(&self, offset: u32, value: u8) {
        let _ = unsafe { ffi::PDOWriteOutputU8(self.master_index, self.slave_index, offset, value) };
    }

    /// 写入输出 PDO i8 值
    pub fn write_output_i8(&self, offset: u32, value: i8) {
        let _ = unsafe { ffi::PDOWriteOutputU8(self.master_index, self.slave_index, offset, value as u8) };
    }

    /// 写入输出 PDO i16 值
    pub fn write_output_i16(&self, offset: u32, value: i16) {
        let _ = unsafe { ffi::PDOWriteOutputI16(self.master_index, self.slave_index, offset, value) };
    }

    /// 写入输出 PDO u16 值
    pub fn write_output_u16(&self, offset: u32, value: u16) {
        let _ = unsafe { ffi::PDOWriteOutputU16(self.master_index, self.slave_index, offset, value) };
    }

    /// 写入输出 PDO i32 值
    pub fn write_output_i32(&self, offset: u32, value: i32) {
        let _ = unsafe { ffi::PDOWriteOutputI32(self.master_index, self.slave_index, offset, value) };
    }

    /// 写入输出 PDO u32 值
    pub fn write_output_u32(&self, offset: u32, value: u32) {
        let _ = unsafe { ffi::PDOWriteOutputU32(self.master_index, self.slave_index, offset, value) };
    }

    /// 写入输出 PDO f32 值
    pub fn write_output_f32(&self, offset: u32, value: f32) {
        let _ = unsafe { ffi::PDOWriteOutputF32(self.master_index, self.slave_index, offset, value) };
    }

    // ===================== PDO 新接口 (带返回值) =====================

    /// 读取输入 PDO u8 (新接口)
    pub fn pdo_read_input_u8(&self, offset: u32) -> u8 {
        unsafe { ffi::PDOReadInputU8(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO i16 (新接口)
    pub fn pdo_read_input_i16(&self, offset: u32) -> i16 {
        unsafe { ffi::PDOReadInputI16(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO u16 (新接口)
    pub fn pdo_read_input_u16(&self, offset: u32) -> u16 {
        unsafe { ffi::PDOReadInputU16(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO i32 (新接口)
    pub fn pdo_read_input_i32(&self, offset: u32) -> i32 {
        unsafe { ffi::PDOReadInputI32(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO u32 (新接口)
    pub fn pdo_read_input_u32(&self, offset: u32) -> u32 {
        unsafe { ffi::PDOReadInputU32(self.master_index, self.slave_index, offset) }
    }

    /// 读取输入 PDO f32 (新接口)
    pub fn pdo_read_input_f32(&self, offset: u32) -> f32 {
        unsafe { ffi::PDOReadInputF32(self.master_index, self.slave_index, offset) }
    }

    /// 写入输出 PDO u8 (新接口, 返回状态码)
    pub fn pdo_write_output_u8(&self, offset: u32, val: u8) -> Result<()> {
        let ret = unsafe { ffi::PDOWriteOutputU8(self.master_index, self.slave_index, offset, val) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other(format!("PDO 写入 u8 失败 (返回码: {})", ret))) }
    }

    /// 写入输出 PDO i16 (新接口, 返回状态码)
    pub fn pdo_write_output_i16(&self, offset: u32, val: i16) -> Result<()> {
        let ret = unsafe { ffi::PDOWriteOutputI16(self.master_index, self.slave_index, offset, val) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other(format!("PDO 写入 i16 失败 (返回码: {})", ret))) }
    }

    /// 写入输出 PDO u16 (新接口, 返回状态码)
    pub fn pdo_write_output_u16(&self, offset: u32, val: u16) -> Result<()> {
        let ret = unsafe { ffi::PDOWriteOutputU16(self.master_index, self.slave_index, offset, val) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other(format!("PDO 写入 u16 失败 (返回码: {})", ret))) }
    }

    /// 写入输出 PDO i32 (新接口, 返回状态码)
    pub fn pdo_write_output_i32(&self, offset: u32, val: i32) -> Result<()> {
        let ret = unsafe { ffi::PDOWriteOutputI32(self.master_index, self.slave_index, offset, val) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other(format!("PDO 写入 i32 失败 (返回码: {})", ret))) }
    }

    /// 写入输出 PDO u32 (新接口, 返回状态码)
    pub fn pdo_write_output_u32(&self, offset: u32, val: u32) -> Result<()> {
        let ret = unsafe { ffi::PDOWriteOutputU32(self.master_index, self.slave_index, offset, val) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other(format!("PDO 写入 u32 失败 (返回码: {})", ret))) }
    }

    /// 写入输出 PDO f32 (新接口, 返回状态码)
    pub fn pdo_write_output_f32(&self, offset: u32, val: f32) -> Result<()> {
        let ret = unsafe { ffi::PDOWriteOutputF32(self.master_index, self.slave_index, offset, val) };
        if ret >= 0 { Ok(()) } else { Err(DarraError::Other(format!("PDO 写入 f32 失败 (返回码: {})", ret))) }
    }

    // ===================== 诊断 =====================

    /// 链路质量 (0-100%)
    pub fn link_quality(&self) -> i16 {
        unsafe { ffi::GetSlaveLinkQuality(self.master_index, self.slave_index) }
    }

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

    /// 读取端口错误计数器
    /// 返回 (rx_error[4], invalid_frame[4], lost_link[4]) 或 None
    pub fn read_port_error_counters(&self) -> 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.master_index, self.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 port_error_stats(&self) -> *const std::ffi::c_void {
        unsafe { ffi::GetSlavePortErrorStats(self.master_index, self.slave_index) }
    }

    /// DC 调试信息
    pub fn debug_dc(&self) {
        unsafe { ffi::DebugSlaveHasDC(self.master_index, self.slave_index) };
    }

    // ===================== C# 兼容别名 =====================
    // C# SDK 使用不同命名, 此处提供别名方便迁移

    /// 输入位数 (C# 别名: Ibits)
    pub fn ibits(&self) -> u16 { self.input_bits() }

    /// 输入字节数 (C# 别名: Ibytes)
    pub fn ibytes(&self) -> u32 { self.input_bytes() }

    /// 输出位数 (C# 别名: Obits)
    pub fn obits(&self) -> u16 { self.output_bits() }

    /// 输出字节数 (C# 别名: Obytes)
    pub fn obytes(&self) -> u32 { self.output_bytes() }

    /// 输入偏移 (C# 别名: Ioffset)
    pub fn ioffset(&self) -> u32 { self.input_offset() }

    /// 输出偏移 (C# 别名: Ooffset)
    pub fn ooffset(&self) -> u32 { self.output_offset() }

    /// 输入起始位 (C# 别名: Istartbit)
    pub fn istartbit(&self) -> u8 { self.input_startbit() }

    /// 输出起始位 (C# 别名: Ostartbit)
    pub fn ostartbit(&self) -> u8 { self.output_startbit() }

    /// 修订版本号别名 (与 rev_id 相同)
    pub fn revision(&self) -> u32 { self.rev_id() }

    /// 传播延迟 (纳秒, C# 别名: PDelay)
    pub fn pdelay(&self) -> i32 {
        self.read_slave().map(|s| s.dc.propagation_delay).unwrap_or(0)
    }

    /// 父站地址 (C# 别名: ParentStation)
    pub fn parent_station(&self) -> u16 {
        self.read_slave().map(|s| s.topo.parent).unwrap_or(0)
    }

    /// 邮箱支持协议位掩码 (C# 别名: MbxProto)
    pub fn mbx_proto(&self) -> u16 { self.mbx_protocol() }

    // ===================== ESI 相关属性 =====================

    /// ESI 文件是否已加载
    pub fn has_esi(&self) -> bool {
        unsafe { ffi::GetSlaveHasEsi(self.master_index, self.slave_index) != 0 }
    }

    /// 设置 ESI 文件
    pub fn set_esi_file(&self, name: &str) -> bool {
        let c_name = match CString::new(name) {
            Ok(s) => s,
            Err(_) => return false,
        };
        unsafe { ffi::SetSlaveEsiFile(self.master_index, self.slave_index, c_name.as_ptr()) != 0 }
    }

    /// ESI 文件版本
    pub fn esi_version(&self) -> String {
        let mut buf = [0i8; 64];
        let ok = unsafe {
            ffi::GetSlaveEsiVersion(self.master_index, self.slave_index, buf.as_mut_ptr(), 64)
        };
        if ok != 0 {
            unsafe { std::ffi::CStr::from_ptr(buf.as_ptr()) }
                .to_string_lossy().into_owned()
        } else {
            String::new()
        }
    }

    /// 是否支持 MDP (Modular Device Profile)
    pub fn has_mdp(&self) -> bool {
        unsafe { ffi::GetSlaveHasMDP(self.master_index, self.slave_index) != 0 }
    }

    /// 厂商名称
    pub fn vendor_name(&self) -> String {
        let mut buf = [0i8; 128];
        let ok = unsafe {
            ffi::GetSlaveVendorName(self.master_index, self.slave_index, buf.as_mut_ptr(), 128)
        };
        if ok != 0 {
            unsafe { std::ffi::CStr::from_ptr(buf.as_ptr()) }
                .to_string_lossy().into_owned()
        } else {
            String::new()
        }
    }

    // ===================== 冗余状态属性 =====================

    /// 冗余是否已激活
    pub fn redundancy_activated(&self) -> bool {
        unsafe { ffi::GetSlaveRedundancyActivated(self.master_index, self.slave_index) != 0 }
    }

    /// 主线路是否断路
    pub fn primary_link_broken(&self) -> bool {
        unsafe { ffi::GetSlavePrimaryLinkBroken(self.master_index, self.slave_index) != 0 }
    }

    /// 冗余线路是否断路
    pub fn secondary_link_broken(&self) -> bool {
        unsafe { ffi::GetSlaveSecondaryLinkBroken(self.master_index, self.slave_index) != 0 }
    }

    // ===================== 拓扑子节点 =====================

    /// 获取拓扑子节点数量
    pub fn child_count(&self) -> u16 {
        let mut buf = vec![0u16; 64];
        let count = unsafe {
            ffi::TopologyGetChildren(self.master_index, self.slave_index, buf.as_mut_ptr(), 64)
        };
        if count > 0 { count as u16 } else { 0 }
    }

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

    // ===================== SM/FMMU 获取 =====================

    /// 获取 SyncManager 配置 (从站结构体中 sm_buffer, 8条目 x 8字节)
    pub fn sync_managers(&self) -> Vec<u8> {
        self.read_slave().map(|s| s.sm_buffer.to_vec()).unwrap_or_default()
    }

    /// 获取 SM 类型数组 (8 字节, 对应 8 个 SM 的类型, Phase 2-E: sm_fmmu.sm_type)
    pub fn sync_manager_types(&self) -> Vec<u8> {
        self.read_slave().map(|s| s.sm_fmmu.sm_type.to_vec()).unwrap_or_default()
    }

    /// 获取 FMMU 配置 (从站结构体中 fmmu_buffer, 4条目 x 16字节)
    pub fn fmmus(&self) -> Vec<u8> {
        self.read_slave().map(|s| s.fmmu_buffer.to_vec()).unwrap_or_default()
    }

    /// 获取 FMMU 配置 (通过寄存器读取, 兼容旧接口)
    pub fn fmmus_raw(&self) -> Vec<u8> {
        self.read_register(0x0600, 256).unwrap_or_default()
    }

    /// 获取 SyncManager 配置 (通过寄存器读取, 兼容旧接口)
    pub fn sync_managers_raw(&self) -> Vec<u8> {
        self.read_register(0x0800, 128).unwrap_or_default()
    }

    /// 刷新从站指针 (状态转换后调用)
    pub fn refresh_pointer(&self) {
        // Rust SDK 每次调用都重新获取指针, 无需刷新缓存
        // 此方法仅为 C# API 兼容保留
    }

    // ===================== 子对象访问器 =====================

    /// CiA 401 I/O 模块辅助实例
    pub fn cia401(&self) -> crate::slave::cia401::CiA401 {
        crate::slave::cia401::CiA401::new(*self)
    }

    /// ESI 文件加载器
    pub fn esi(&self) -> crate::slave::esi::EsiLoader {
        crate::slave::esi::EsiLoader::new(*self)
    }

    /// 从站事件集合
    pub fn events(&self) -> crate::master::events::SlaveEvents {
        crate::master::events::SlaveEvents::new(self.master_index, self.slave_index)
    }

    /// VoE 实例
    pub fn voe(&self) -> crate::slave::voe::VoEInstance {
        crate::slave::voe::VoEInstance::new(self.master_index, self.slave_index)
    }

    /// AoE 实例
    pub fn aoe(&self) -> crate::slave::aoe::AoEInstance {
        crate::slave::aoe::AoEInstance::new(self.master_index, self.slave_index)
    }

    /// SoE 实例 (驱动器编号默认为 0)
    pub fn soe(&self) -> crate::slave::soe::SoEInstance {
        crate::slave::soe::SoEInstance::new(self.master_index, self.slave_index, 0)
    }

    /// SoE 实例 (指定驱动器编号)
    pub fn soe_drive(&self, drive_number: u8) -> crate::slave::soe::SoEInstance {
        crate::slave::soe::SoEInstance::new(self.master_index, self.slave_index, drive_number)
    }

    /// EoE 实例
    pub fn eoe(&self) -> crate::slave::eoe::EoEInstance {
        crate::slave::eoe::EoEInstance::new(self.master_index, self.slave_index, 0)
    }

    /// FoE 实例
    pub fn foe(&self) -> crate::slave::foe::FoEInstance {
        crate::slave::foe::FoEInstance::new(self.master_index, self.slave_index)
    }

    /// 启动参数管理器
    pub fn startup(&self) -> crate::slave::startup::StartupParameterList {
        crate::slave::startup::StartupParameterList::new(self.master_index, self.slave_index)
    }

    /// DC 同步配置
    pub fn dc(&self) -> crate::slave::dc::SlaveDC {
        crate::slave::dc::SlaveDC::new(self.master_index, self.slave_index)
    }

    /// 从站诊断
    pub fn diagnostics(&self) -> crate::slave::slave_stats::SlaveDiagnostics {
        crate::slave::slave_stats::SlaveDiagnostics::new(self.master_index, self.slave_index)
    }

    /// 网络拓扑管理器
    pub fn topology_info(&self) -> crate::slave::topology::SlaveTopology {
        crate::slave::topology::SlaveTopology::build(self.master_index)
    }

    /// 从 ESI 文件自动配置从站 (SM/FMMU/PDO 映射)
    ///
    /// 读取从站 ESI 信息, 自动配置 SyncManager、FMMU 和 PDO 映射。
    /// 需要在 PreOp 或更高状态下调用。
    pub fn configure_from_esi(&self) -> Result<()> {
        let ret = unsafe {
            ffi::DarraCoreInvoke(
                self.master_index,
                ffi::CORE_OP_25,
                self.slave_index as u32,
                0,
                0)
        };
        if ret >= 0 {
            Ok(())
        } else {
            Err(DarraError::Other(obfstr::obfstr!("ESI 自动配置失败").into()))
        }
    }

    /// 根据 ESI 文件自动配置从站 (对应 C# ConfigByEsi)
    ///
    /// 综合执行: AutoConfigureSM + ConfigureDC, 一步完成从站配置。
    pub fn config_by_esi(&self) -> Result<()> {
        // 先执行基础 ESI 配置 (SM + PDO)
        self.configure_from_esi()?;
        // DC 配置会由 AutoConfigureSM 自动处理
        // 此处确保配置已生效
        Ok(())
    }

    // 保持旧接口兼容 (将在下个版本移除)
    #[doc(hidden)]
    pub fn voe_instance(&self) -> crate::slave::voe::VoEInstance { self.voe() }
    #[doc(hidden)]
    pub fn aoe_instance(&self) -> crate::slave::aoe::AoEInstance { self.aoe() }
    #[doc(hidden)]
    pub fn startup_params(&self) -> crate::slave::startup::StartupParameterList { self.startup() }
}

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

impl std::fmt::Display for Slave {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let name = self.name();
        let vid = self.vendor_id();
        let pid = self.product_id();
        write!(f, "Slave[{}] {} ({:#010x}:{:#010x})", self.slave_index, name, vid, pid)
    }
}
