darra-ethercat-master 2.0.7

商业 EtherCAT 主站协议栈 · 实时内核驱动 · 抖动 1µs · Windows + Linux · 多编程语言 · 全协议 · 支持复杂拓扑 + 热插拔 · ethercat.darra.xyz · Commercial EtherCAT Master protocol stack · Real-time kernel driver · 1µs jitter · Multi-platform · Multi-language · Complex topology + hot-plug.
//! 主站其他功能
//!
//! 对应 C# Master/Other.cs
//! 包含诊断数据快照、日志初始化等功能。

use crate::utils::ffi;

/// 全局从站诊断数据快照
///
/// 对应 C# SlaveDiagnosticsData
pub struct SlaveDiagnosticsData {
    /// 各从站链路质量百分比 (0-100),索引=从站编号(1-based)
    pub link_quality_percent: Vec<u32>,
    /// 各从站端口错误合计 (Rx + 无效帧),索引=从站编号(1-based)
    pub port_error_count: Vec<u32>,
    /// 各从站链路丢失计数,索引=从站编号(1-based)
    pub lost_link_count: Vec<u32>,

    /// 帧错误数
    pub frame_errors: u32,
    /// 丢失帧数
    pub lost_frames: u32,
    /// 校验和错误数
    pub checksum_errors: u32,
    /// 超时帧数
    pub timeout_frames: u32,

    /// 主端口错误计数
    pub primary_port_errors: u32,
    /// 副端口错误计数
    pub secondary_port_errors: u32,
}

/// 获取全局从站诊断数据快照
///
/// 对应 C# DarraEtherCAT.GetDiagnostics()
pub fn get_diagnostics(master_index: u16, slave_count: u16) -> Option<SlaveDiagnosticsData> {
    if slave_count == 0 {
        return None;
    }

    let count = slave_count as usize;
    let mut link_quality = vec![0u32; count + 1];
    let mut port_error = vec![0u32; count + 1];
    let mut lost_link = vec![0u32; count + 1];

    for i in 1..=count {
        let slave_idx = i as u16;
        unsafe {
            let lq = ffi::GetSlaveLinkQuality(master_index, slave_idx);
            link_quality[i] = if lq < 0 { 0 } else { lq as u32 };

            let mut rx = [0u8; 4];
            let mut inv = [0u8; 4];
            let mut lost = [0u8; 4];
            if ffi::ReadSlavePortErrorCounters(
                master_index, slave_idx,
                rx.as_mut_ptr(), inv.as_mut_ptr(), lost.as_mut_ptr(),
            ) != 0 {
                for p in 0..4 {
                    port_error[i] += (rx[p] as u32) + (inv[p] as u32);
                    lost_link[i] += lost[p] as u32;
                }
            }
        }
    }

    Some(SlaveDiagnosticsData {
        link_quality_percent: link_quality,
        port_error_count: port_error,
        lost_link_count: lost_link,
        frame_errors: 0,
        lost_frames: 0,
        checksum_errors: 0,
        timeout_frames: 0,
        primary_port_errors: 0,
        secondary_port_errors: 0,
    })
}

/// 日志初始化
///
/// 对应 C# InitializeLogging()
pub fn initialize_logging(
    log_callback: Option<crate::utils::ffi::LogCallback>,
    crash_callback: Option<crate::utils::ffi::CrashNotifyCallback>,
) {
    unsafe {
        if let Some(cb) = log_callback {
            ffi::SetLogCallback(cb);
        }
        if let Some(cb) = crash_callback {
            ffi::SetCrashCallback(cb);
        }
        // 默认关闭 PDO/邮箱/调试日志
        ffi::SetPDOLogging(0);
        ffi::SetMailboxLogging(0);
        ffi::SetDebugLogging(0);
    }
}

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

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

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