//! 协议常量解码 (转发到 DLL ec_*.h 模块)
//!
//! 本模块为 11 组 DLL 协议解码 API 提供 Rust 友好封装:
//! - AL_StatusCode  : ETG.1000.6 AL 状态码 (Severity / 描述 / Recovery Hint / VendorSpecific)
//! - SDOAbort       : CiA 301 SDO Abort (类别 / 描述 / 是否可重试 / 处理建议)
//! - EmcyCode       : CiA 301 Emergency 错误码 (大类 / 描述 / 错误寄存器位)
//! - EcState        : ESM 状态合法性 (转换检查 / 路径 / Bootstrap)
//! - EcPdoCodec     : PDO BitField 编解码 + 端口拓扑
//! - CiA402Modes    : CiA 402 操作模式 + 回零方法
//! - EcMailbox      : 邮箱协议类型/错误码
//! - EcSoE          : SoE 错误码
//! - EcSii          : SII (EEPROM) 解析
//! - EcCouplerId    : 耦合器/厂商识别
//! - EcDiagStrings  : 诊断信息文本
//!
//! 所有字符串结果在 C 端是 UTF-8 静态常量, 安全 borrow 后 to_string_lossy.
//! 失败 (NULL 指针) 时返回兜底字符串 (如 "未知" / "未知错误"), 不会 panic.

use std::ffi::CStr;
use std::os::raw::c_char;

use crate::utils::ffi;

/// 内部辅助: 将 C 端 const char* 转 String, NULL 时返回 fallback.
fn cstr_to_string(p: *const c_char, fallback: &str) -> String {
    if p.is_null() {
        return fallback.to_string();
    }
    unsafe { CStr::from_ptr(p).to_string_lossy().into_owned() }
}

/// AL Status Code 严重程度 (对齐 ec_status_codes.h al_status_severity_t)
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AlSeverity {
    None = 0,
    Info = 1,
    Warning = 2,
    Error = 3,
    Fatal = 4,
}

impl AlSeverity {
    pub fn from_i32(v: i32) -> Self {
        match v {
            0 => Self::None,
            1 => Self::Info,
            2 => Self::Warning,
            3 => Self::Error,
            _ => Self::Fatal,
        }
    }
}

/// SDO Abort 类别 (对齐 sdo_abort_category_t)
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SdoAbortCategory {
    Transfer = 0,
    Access = 1,
    Value = 2,
    Hardware = 3,
    General = 4,
}

impl SdoAbortCategory {
    pub fn from_i32(v: i32) -> Self {
        match v {
            0 => Self::Transfer,
            1 => Self::Access,
            2 => Self::Value,
            3 => Self::Hardware,
            _ => Self::General,
        }
    }
}

/// EMCY 大类 (对齐 emcy_class_t)
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EmcyClass {
    NoError = 0x0000,
    Generic = 0x1000,
    Current = 0x2000,
    Voltage = 0x3000,
    Temperature = 0x4000,
    Hardware = 0x5000,
    Software = 0x6000,
    AdditionalModules = 0x7000,
    Monitoring = 0x8000,
    External = 0x9000,
    AdditionalFunc = 0xF000,
    DeviceSpecific = 0xFF00,
}

impl EmcyClass {
    pub fn from_i32(v: i32) -> Self {
        match v {
            0x0000 => Self::NoError,
            0x1000 => Self::Generic,
            0x2000 => Self::Current,
            0x3000 => Self::Voltage,
            0x4000 => Self::Temperature,
            0x5000 => Self::Hardware,
            0x6000 => Self::Software,
            0x7000 => Self::AdditionalModules,
            0x8000 => Self::Monitoring,
            0x9000 => Self::External,
            0xF000 => Self::AdditionalFunc,
            _ => Self::DeviceSpecific,
        }
    }
}

/// ESM 状态转换类型 (对齐 ec_transition_type_t)
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EcTransitionType {
    Invalid = 0,
    Up = 1,
    Down = 2,
    Same = 3,
    Bootstrap = 4,
    JumpUp = 5,
    JumpDown = 6,
}

impl EcTransitionType {
    pub fn from_i32(v: i32) -> Self {
        match v {
            1 => Self::Up,
            2 => Self::Down,
            3 => Self::Same,
            4 => Self::Bootstrap,
            5 => Self::JumpUp,
            6 => Self::JumpDown,
            _ => Self::Invalid,
        }
    }
}

/// PDO 端口拓扑 (对齐 ec_topology_t)
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EcTopology {
    Unknown = 0,
    Line = 1,
    Pass = 2,
    Branch = 3,
    Cross = 4,
}

impl EcTopology {
    pub fn from_i32(v: i32) -> Self {
        match v {
            1 => Self::Line,
            2 => Self::Pass,
            3 => Self::Branch,
            4 => Self::Cross,
            _ => Self::Unknown,
        }
    }
}

/// 耦合器识别得到的设备类型 (对齐 ec_device_type_t)
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum EcDeviceType {
    Unknown = 0,
    Coupler = 1,
    Terminal = 2,
    Drive = 3,
    Sensor = 4,
    Gateway = 5,
    Safety = 6,
    Controller = 7,
}

impl EcDeviceType {
    pub fn from_i32(v: i32) -> Self {
        match v {
            1 => Self::Coupler,
            2 => Self::Terminal,
            3 => Self::Drive,
            4 => Self::Sensor,
            5 => Self::Gateway,
            6 => Self::Safety,
            7 => Self::Controller,
            _ => Self::Unknown,
        }
    }
}

/// Homing 触发源类型 (对齐 homing_trigger_t)
#[repr(i32)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum HomingTrigger {
    NegativeLimit = 0,
    PositiveLimit = 1,
    HomeSwitch = 2,
    IndexPulse = 3,
    HardStop = 4,
    CurrentPos = 5,
    Vendor = 6,
}

impl HomingTrigger {
    pub fn from_i32(v: i32) -> Self {
        match v {
            0 => Self::NegativeLimit,
            1 => Self::PositiveLimit,
            2 => Self::HomeSwitch,
            3 => Self::IndexPulse,
            4 => Self::HardStop,
            5 => Self::CurrentPos,
            _ => Self::Vendor,
        }
    }
}

/// 协议解码统一入口 (零状态结构, 仅起命名空间作用).
pub struct ProtocolCodes;

impl ProtocolCodes {
    // ===================== AL Status Code =====================

    /// AL_STATUS_CODE 中文描述 (ETG.1000.6 Table 11)
    pub fn al_status_description(code: u16) -> String {
        unsafe { cstr_to_string(ffi::AL_StatusCode_GetDescription(code), "未知错误") }
    }

    /// AL_STATUS_CODE 严重程度
    pub fn al_status_severity(code: u16) -> AlSeverity {
        unsafe { AlSeverity::from_i32(ffi::AL_StatusCode_GetSeverity(code)) }
    }

    /// AL_STATUS_CODE 推荐处理动作描述
    pub fn al_status_recovery_hint(code: u16) -> String {
        unsafe { cstr_to_string(ffi::AL_StatusCode_GetRecoveryHint(code), "请联系厂商") }
    }

    /// 是否为厂商自定义 AL Status Code (0x8000-0xFFFF)
    pub fn al_status_is_vendor_specific(code: u16) -> bool {
        unsafe { ffi::AL_StatusCode_IsVendorSpecific(code) != 0 }
    }

    // ===================== SDO Abort =====================

    /// SDO Abort Code 中英文描述
    pub fn sdo_abort_description(abort_code: u32) -> String {
        unsafe { cstr_to_string(ffi::SDOAbort_GetDescription(abort_code), "未知中止码") }
    }

    /// SDO Abort 类别
    pub fn sdo_abort_category(abort_code: u32) -> SdoAbortCategory {
        unsafe { SdoAbortCategory::from_i32(ffi::SDOAbort_GetCategory(abort_code)) }
    }

    /// SDO Abort 是否可重试
    pub fn sdo_abort_is_retryable(abort_code: u32) -> bool {
        unsafe { ffi::SDOAbort_IsRetryable(abort_code) != 0 }
    }

    /// SDO Abort 处理建议
    pub fn sdo_abort_hint(abort_code: u32) -> String {
        unsafe { cstr_to_string(ffi::SDOAbort_GetHint(abort_code), "请检查从站配置") }
    }

    // ===================== EMCY Emergency =====================

    /// EMCY 错误码描述 (CiA 301 Table 24)
    pub fn emcy_description(error_code: u16) -> String {
        unsafe { cstr_to_string(ffi::EmcyCode_GetDescription(error_code), "未知紧急错误") }
    }

    /// EMCY 大类
    pub fn emcy_class(error_code: u16) -> EmcyClass {
        unsafe { EmcyClass::from_i32(ffi::EmcyCode_GetClass(error_code)) }
    }

    /// EMCY 大类名称
    pub fn emcy_class_name(class_code: EmcyClass) -> String {
        unsafe { cstr_to_string(ffi::EmcyCode_GetClassName(class_code as i32), "未知大类") }
    }

    /// 解析 Error Register 位掩码为可读字符串 (例 0x16 -> "通用|电流|温度|通讯")
    pub fn emcy_format_error_register(error_register: u8) -> String {
        let mut buf = vec![0u8; 128];
        unsafe {
            ffi::EmcyCode_FormatErrorRegister(error_register, buf.as_mut_ptr(), buf.len() as i32);
        }
        // 找到 NUL 终止符
        let len = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
        String::from_utf8_lossy(&buf[..len]).into_owned()
    }

    /// EMCY 是否为错误恢复消息 (error_code == 0x0000)
    pub fn emcy_is_recovery(error_code: u16) -> bool {
        unsafe { ffi::EmcyCode_IsRecovery(error_code) != 0 }
    }

    // ===================== ESM 状态合法性 =====================

    /// 检查从站状态转换是否合法 (传 ETG.1000.6 §6.4.1 表 14 数值)
    pub fn ec_state_is_valid_transition(from: u16, to: u16) -> bool {
        unsafe { ffi::EcState_IsValidTransition(from, to) != 0 }
    }

    /// 获取状态转换类型 (合法性 + 方向)
    pub fn ec_state_transition_type(from: u16, to: u16) -> EcTransitionType {
        unsafe { EcTransitionType::from_i32(ffi::EcState_GetTransitionType(from, to)) }
    }

    /// 获取从 from 到 to 必经的中间状态序列, 非法转换返回空 Vec
    pub fn ec_state_transition_path(from: u16, to: u16) -> Vec<u16> {
        let mut buf = [0u16; 8];
        let n =
            unsafe { ffi::EcState_GetTransitionPath(from, to, buf.as_mut_ptr(), buf.len() as i32) };
        if n <= 0 {
            return Vec::new();
        }
        buf[..(n as usize).min(buf.len())].to_vec()
    }

    /// 是否需要 Bootstrap (用于固件升级)
    pub fn ec_state_is_bootstrap_required(state: u16) -> bool {
        unsafe { ffi::EcState_IsBootstrapRequired(state) != 0 }
    }

    /// 状态名 (中文)
    pub fn ec_state_name(state: u16) -> String {
        unsafe { cstr_to_string(ffi::EcState_GetName(state), "未知状态") }
    }

    /// 状态名 (英文)
    pub fn ec_state_name_en(state: u16) -> String {
        unsafe { cstr_to_string(ffi::EcState_GetNameEn(state), "Unknown") }
    }

    /// 状态是否带 ERROR ACK 位 (0x10)
    pub fn ec_state_has_error_ack(state: u16) -> bool {
        unsafe { ffi::EcState_HasErrorAck(state) != 0 }
    }

    /// 去除 ERROR ACK 位, 返回基础状态
    pub fn ec_state_strip_error_ack(state: u16) -> u16 {
        unsafe { ffi::EcState_StripErrorAck(state) }
    }

    // ===================== PDO Codec / 端口拓扑 =====================

    /// 数据类型对应的 bit 长度. 0=未知, -1=变长字符串
    pub fn pdo_data_type_bit_size(dt: u16) -> i32 {
        unsafe { ffi::EcPdoCodec_DataTypeBitSize(dt as i32) }
    }

    /// 数据类型可读名 (英文)
    pub fn pdo_data_type_name(dt: u16) -> String {
        unsafe { cstr_to_string(ffi::EcPdoCodec_DataTypeName(dt as i32), "Unknown") }
    }

    /// BitField 抽取 u64. 失败返回 None.
    pub fn pdo_extract_u64(src: &[u8], bit_offset: i32, bit_length: i32) -> Option<u64> {
        let mut out: u64 = 0;
        let r = unsafe {
            ffi::EcPdoCodec_ExtractU64(
                src.as_ptr(),
                src.len() as i32,
                bit_offset,
                bit_length,
                &mut out,
            )
        };
        if r == 0 {
            Some(out)
        } else {
            None
        }
    }

    /// BitField 抽取 i64 (按 bit_length 做符号扩展)
    pub fn pdo_extract_i64(src: &[u8], bit_offset: i32, bit_length: i32) -> Option<i64> {
        let mut out: i64 = 0;
        let r = unsafe {
            ffi::EcPdoCodec_ExtractI64(
                src.as_ptr(),
                src.len() as i32,
                bit_offset,
                bit_length,
                &mut out,
            )
        };
        if r == 0 {
            Some(out)
        } else {
            None
        }
    }

    /// BitField 写入 u64. 返回 true 表示成功.
    pub fn pdo_insert_u64(dst: &mut [u8], bit_offset: i32, bit_length: i32, value: u64) -> bool {
        let n = dst.len() as i32;
        unsafe { ffi::EcPdoCodec_InsertU64(dst.as_mut_ptr(), n, bit_offset, bit_length, value) == 0 }
    }

    /// BitField 写入 i64
    pub fn pdo_insert_i64(dst: &mut [u8], bit_offset: i32, bit_length: i32, value: i64) -> bool {
        let n = dst.len() as i32;
        unsafe { ffi::EcPdoCodec_InsertI64(dst.as_mut_ptr(), n, bit_offset, bit_length, value) == 0 }
    }

    /// 抽取 REAL32 (bit_offset 必须 8 对齐)
    pub fn pdo_extract_real32(src: &[u8], bit_offset: i32) -> Option<f32> {
        let mut out: f32 = 0.0;
        let r = unsafe {
            ffi::EcPdoCodec_ExtractReal32(src.as_ptr(), src.len() as i32, bit_offset, &mut out)
        };
        if r == 0 {
            Some(out)
        } else {
            None
        }
    }

    /// 抽取 REAL64 (bit_offset 必须 8 对齐)
    pub fn pdo_extract_real64(src: &[u8], bit_offset: i32) -> Option<f64> {
        let mut out: f64 = 0.0;
        let r = unsafe {
            ffi::EcPdoCodec_ExtractReal64(src.as_ptr(), src.len() as i32, bit_offset, &mut out)
        };
        if r == 0 {
            Some(out)
        } else {
            None
        }
    }

    /// 写入 REAL32
    pub fn pdo_insert_real32(dst: &mut [u8], bit_offset: i32, value: f32) -> bool {
        let n = dst.len() as i32;
        unsafe { ffi::EcPdoCodec_InsertReal32(dst.as_mut_ptr(), n, bit_offset, value) == 0 }
    }

    /// 写入 REAL64
    pub fn pdo_insert_real64(dst: &mut [u8], bit_offset: i32, value: f64) -> bool {
        let n = dst.len() as i32;
        unsafe { ffi::EcPdoCodec_InsertReal64(dst.as_mut_ptr(), n, bit_offset, value) == 0 }
    }

    /// ActivePorts 字节中活跃端口数 (0..4)
    pub fn pdo_count_active_ports(active_ports: u8) -> i32 {
        unsafe { ffi::EcPdoCodec_CountActivePorts(active_ports) }
    }

    /// ActivePorts 解码为拓扑类型
    pub fn pdo_get_topology(active_ports: u8) -> EcTopology {
        unsafe { EcTopology::from_i32(ffi::EcPdoCodec_GetTopology(active_ports)) }
    }

    /// 拓扑类型中文名
    pub fn pdo_topology_name(topo: EcTopology) -> String {
        unsafe { cstr_to_string(ffi::EcPdoCodec_GetTopologyName(topo as i32), "未知") }
    }

    /// 拓扑类型英文名
    pub fn pdo_topology_name_en(topo: EcTopology) -> String {
        unsafe { cstr_to_string(ffi::EcPdoCodec_GetTopologyNameEn(topo as i32), "Unknown") }
    }

    /// 检查指定端口是否活跃 (port: 0..3)
    pub fn pdo_is_port_active(active_ports: u8, port: i32) -> bool {
        unsafe { ffi::EcPdoCodec_IsPortActive(active_ports, port) != 0 }
    }

    // ===================== CiA402 模式 / 回零方法 =====================

    /// 模式对应 0x6502 SupportedDriveModes 的 bit 索引. -1=无对应位
    pub fn cia402_mode_to_supported_bit(mode: i8) -> i32 {
        unsafe { ffi::CiA402Modes_ModeToSupportedBit(mode) }
    }

    /// 检查 0x6502 掩码是否支持指定模式
    pub fn cia402_is_mode_supported(mask: u32, mode: i8) -> bool {
        unsafe { ffi::CiA402Modes_IsModeSupportedInMask(mask, mode) != 0 }
    }

    /// 展开 0x6502 掩码为模式列表
    pub fn cia402_expand_supported_mask(mask: u32) -> Vec<i8> {
        let mut buf = [0i8; 16];
        let n =
            unsafe { ffi::CiA402Modes_ExpandSupportedMask(mask, buf.as_mut_ptr(), buf.len() as i32) };
        if n <= 0 {
            return Vec::new();
        }
        buf[..(n as usize).min(buf.len())].to_vec()
    }

    /// 模式名 (中文 + 英文缩写)
    pub fn cia402_mode_name(mode: i8) -> String {
        unsafe { cstr_to_string(ffi::CiA402Modes_GetModeName(mode), "未知模式") }
    }

    /// 模式名 (英文全称)
    pub fn cia402_mode_name_en(mode: i8) -> String {
        unsafe { cstr_to_string(ffi::CiA402Modes_GetModeNameEn(mode), "Unknown") }
    }

    /// 模式描述 (用途说明)
    pub fn cia402_mode_description(mode: i8) -> String {
        unsafe { cstr_to_string(ffi::CiA402Modes_GetModeDescription(mode), "无描述") }
    }

    /// 是否周期同步模式 (CSP/CSV/CST/CSTCA)
    pub fn cia402_is_cyclic_sync_mode(mode: i8) -> bool {
        unsafe { ffi::CiA402Modes_IsCyclicSyncMode(mode) != 0 }
    }

    /// 模式是否需要 DC 同步
    pub fn cia402_requires_dc(mode: i8) -> bool {
        unsafe { ffi::CiA402Modes_RequiresDC(mode) != 0 }
    }

    /// 是否标准 ETG.6010 回零方法 (1..35 或 37)
    pub fn cia402_is_standard_homing_method(method: i8) -> bool {
        unsafe { ffi::CiA402Modes_IsStandardHomingMethod(method) != 0 }
    }

    /// 回零方法描述 (中文)
    pub fn cia402_homing_method_name(method: i8) -> String {
        unsafe { cstr_to_string(ffi::CiA402Modes_GetHomingMethodName(method), "厂商自定义") }
    }

    /// 回零方法触发源
    pub fn cia402_homing_trigger(method: i8) -> HomingTrigger {
        unsafe { HomingTrigger::from_i32(ffi::CiA402Modes_GetHomingTrigger(method)) }
    }

    /// 回零方法移动方向: -1=负, 0=不移动, +1=正
    pub fn cia402_homing_direction(method: i8) -> i32 {
        unsafe { ffi::CiA402Modes_GetHomingDirection(method) }
    }

    /// 列出所有标准回零方法编号 (0,1..35,37)
    pub fn cia402_list_standard_homing_methods() -> Vec<i8> {
        let mut buf = [0i8; 64];
        let n = unsafe {
            ffi::CiA402Modes_ListStandardHomingMethods(buf.as_mut_ptr(), buf.len() as i32)
        };
        if n <= 0 {
            return Vec::new();
        }
        buf[..(n as usize).min(buf.len())].to_vec()
    }

    // ===================== Mailbox =====================

    /// 邮箱类型中文名
    pub fn mailbox_type_name(mbx_type: u16) -> String {
        unsafe { cstr_to_string(ffi::EcMailbox_GetTypeName(mbx_type), "未知") }
    }

    /// 邮箱类型英文名
    pub fn mailbox_type_name_en(mbx_type: u16) -> String {
        unsafe { cstr_to_string(ffi::EcMailbox_GetTypeNameEn(mbx_type), "Unknown") }
    }

    /// 邮箱错误码描述
    pub fn mailbox_error_description(mbx_error_code: u16) -> String {
        unsafe { cstr_to_string(ffi::EcMailbox_GetErrorDescription(mbx_error_code), "未知错误") }
    }

    /// Mailbox Counter 1..7 循环
    pub fn mailbox_next_counter(current: u8) -> u8 {
        unsafe { ffi::EcMailbox_NextCounter(current) }
    }

    // ===================== SoE =====================

    /// SoE 错误码描述 (中文)
    pub fn soe_error_description(soe_error: u16) -> String {
        unsafe { cstr_to_string(ffi::EcSoE_GetErrorDescription(soe_error), "未知 SoE 错误") }
    }

    // ===================== SII (EEPROM) =====================

    /// 在 SII 缓冲中查找指定 Category, 返回 (起始字节偏移, 字节长度); 未找到返回 None.
    pub fn sii_find_category(sii_data: &[u8], cat_type: u16) -> Option<(i32, i32)> {
        let mut out_size: i32 = 0;
        let off = unsafe {
            ffi::EcSii_FindCategory(sii_data.as_ptr(), sii_data.len() as i32, cat_type, &mut out_size)
        };
        if off < 0 {
            None
        } else {
            Some((off, out_size))
        }
    }

    /// 枚举 SII 中所有 Category 类型
    pub fn sii_enumerate_categories(sii_data: &[u8]) -> Vec<u16> {
        let mut buf = vec![0u16; 32];
        let n = unsafe {
            ffi::EcSii_EnumerateCategories(
                sii_data.as_ptr(),
                sii_data.len() as i32,
                buf.as_mut_ptr(),
                buf.len() as i32,
            )
        };
        if n <= 0 {
            return Vec::new();
        }
        buf.truncate((n as usize).min(buf.len()));
        buf
    }

    /// 从 Strings Category 取第 idx (1-based) 个字符串
    pub fn sii_get_string_by_index(cat_data: &[u8], idx: i32) -> Option<String> {
        let mut buf = vec![0u8; 256];
        let n = unsafe {
            ffi::EcSii_GetStringByIndex(
                cat_data.as_ptr(),
                cat_data.len() as i32,
                idx,
                buf.as_mut_ptr(),
                buf.len() as i32,
            )
        };
        if n < 0 {
            return None;
        }
        let n = (n as usize).min(buf.len());
        Some(String::from_utf8_lossy(&buf[..n]).into_owned())
    }

    /// 字符串总数
    pub fn sii_get_string_count(cat_data: &[u8]) -> i32 {
        unsafe { ffi::EcSii_GetStringCount(cat_data.as_ptr(), cat_data.len() as i32) }
    }

    /// SII 中的 Vendor ID (Word 8-9)
    pub fn sii_get_vendor_id(sii_data: &[u8]) -> u32 {
        unsafe { ffi::EcSii_GetVendorId(sii_data.as_ptr(), sii_data.len() as i32) }
    }

    /// SII 中的 Product Code (Word 10-11)
    pub fn sii_get_product_code(sii_data: &[u8]) -> u32 {
        unsafe { ffi::EcSii_GetProductCode(sii_data.as_ptr(), sii_data.len() as i32) }
    }

    /// SII 中的 Revision (Word 12-13)
    pub fn sii_get_revision(sii_data: &[u8]) -> u32 {
        unsafe { ffi::EcSii_GetRevision(sii_data.as_ptr(), sii_data.len() as i32) }
    }

    /// SII 中的 Serial Number (Word 14-15)
    pub fn sii_get_serial_number(sii_data: &[u8]) -> u32 {
        unsafe { ffi::EcSii_GetSerialNumber(sii_data.as_ptr(), sii_data.len() as i32) }
    }

    /// SII 中的 Configured Station Alias (Word 4)
    pub fn sii_get_configured_alias(sii_data: &[u8]) -> u16 {
        unsafe { ffi::EcSii_GetConfiguredAlias(sii_data.as_ptr(), sii_data.len() as i32) }
    }

    /// CoE 启用 (Bit 0)
    pub fn sii_coe_enabled(coe_details: u8) -> bool {
        unsafe { ffi::EcSii_CoeEnabled(coe_details) != 0 }
    }

    /// CoE SDO Info (Bit 1)
    pub fn sii_coe_sdo_info(coe_details: u8) -> bool {
        unsafe { ffi::EcSii_CoeSdoInfo(coe_details) != 0 }
    }

    /// CoE PDO Assign (Bit 2)
    pub fn sii_coe_pdo_assign(coe_details: u8) -> bool {
        unsafe { ffi::EcSii_CoePdoAssign(coe_details) != 0 }
    }

    /// CoE PDO Config (Bit 3)
    pub fn sii_coe_pdo_config(coe_details: u8) -> bool {
        unsafe { ffi::EcSii_CoePdoConfig(coe_details) != 0 }
    }

    /// CoE Upload at Startup (Bit 4)
    pub fn sii_coe_upload_at_startup(coe_details: u8) -> bool {
        unsafe { ffi::EcSii_CoeUploadAtStartup(coe_details) != 0 }
    }

    /// CoE Complete Access (Bit 5)
    pub fn sii_coe_complete_access(coe_details: u8) -> bool {
        unsafe { ffi::EcSii_CoeCompleteAccess(coe_details) != 0 }
    }

    /// FoE 启用 (Bit 0)
    pub fn sii_foe_enabled(foe_details: u8) -> bool {
        unsafe { ffi::EcSii_FoeEnabled(foe_details) != 0 }
    }

    /// EoE 启用 (Bit 0)
    pub fn sii_eoe_enabled(eoe_details: u8) -> bool {
        unsafe { ffi::EcSii_EoeEnabled(eoe_details) != 0 }
    }

    // ===================== 耦合器识别 =====================

    /// 根据 VendorID + ProductCode 识别设备类型
    pub fn coupler_detect_device_type(vendor_id: u32, product_code: u32) -> EcDeviceType {
        unsafe {
            EcDeviceType::from_i32(ffi::EcCouplerId_DetectDeviceType(vendor_id, product_code))
        }
    }

    /// 是否为耦合器 (头模块)
    pub fn coupler_is_coupler(vendor_id: u32, product_code: u32) -> bool {
        unsafe { ffi::EcCouplerId_IsCoupler(vendor_id, product_code) != 0 }
    }

    /// 是否为终端 I/O 模块
    pub fn coupler_is_terminal(vendor_id: u32, product_code: u32) -> bool {
        unsafe { ffi::EcCouplerId_IsTerminal(vendor_id, product_code) != 0 }
    }

    /// 厂商名称 (中文)
    pub fn coupler_vendor_name(vendor_id: u32) -> String {
        unsafe { cstr_to_string(ffi::EcCouplerId_GetVendorName(vendor_id), "未知厂商") }
    }

    /// 厂商名称 (英文)
    pub fn coupler_vendor_name_en(vendor_id: u32) -> String {
        unsafe { cstr_to_string(ffi::EcCouplerId_GetVendorNameEn(vendor_id), "Unknown") }
    }

    /// 设备类型名称 (中文)
    pub fn coupler_device_type_name(dtype: EcDeviceType) -> String {
        unsafe { cstr_to_string(ffi::EcCouplerId_GetDeviceTypeName(dtype as i32), "未知") }
    }

    // ===================== 诊断翻译 =====================

    /// 拓扑描述 (0=线性, 1=环形, 2=环+分支)
    pub fn diag_topology_description(topo: u8) -> String {
        unsafe { cstr_to_string(ffi::EcDiagStrings_TopologyDescription(topo), "未知") }
    }

    /// 定时模式描述
    pub fn diag_timing_mode(mode: u32) -> String {
        unsafe { cstr_to_string(ffi::EcDiagStrings_TimingMode(mode), "未知") }
    }

    /// 断点故障类型描述
    pub fn diag_breakpoint_type(bp: u8) -> String {
        unsafe { cstr_to_string(ffi::EcDiagStrings_BreakpointType(bp), "未知故障") }
    }

    /// 综合断点信息格式化 (例: "从站5 P2 断线")
    pub fn diag_format_breakpoint(slave_idx: u16, port: u8, bp: u8) -> String {
        let mut buf = vec![0u8; 128];
        unsafe {
            ffi::EcDiagStrings_FormatBreakpoint(
                slave_idx,
                port,
                bp,
                buf.as_mut_ptr(),
                buf.len() as i32,
            );
        }
        let len = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
        String::from_utf8_lossy(&buf[..len]).into_owned()
    }
}
