darra-ethercat-master 2.0.6

商业 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/RedundancyManager.cs
//! 提供冗余网络启用/禁用和状态查询。

use crate::utils::ffi;
use crate::data::error::RedundancyState;

/// 冗余网络状态信息
///
/// 对应 C# RedundancyStatus
#[derive(Clone, Debug)]
pub struct RedundancyInfo {
    /// 冗余状态
    pub state: RedundancyState,
    /// 主链路是否连通
    pub primary_link_up: bool,
    /// 副链路是否连通
    pub secondary_link_up: bool,
    /// 主端口发送帧数
    pub primary_tx_frames: u32,
    /// 主端口接收帧数
    pub primary_rx_frames: u32,
    /// 副端口发送帧数
    pub secondary_tx_frames: u32,
    /// 副端口接收帧数
    pub secondary_rx_frames: u32,
    /// 故障转移次数
    pub failover_count: u32,
    /// 最后一次故障转移时间戳
    pub last_failover_time: u32,
}

impl std::fmt::Display for RedundancyInfo {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let state_str = match self.state {
            RedundancyState::None => "无冗余",
            RedundancyState::Primary => "主网络",
            RedundancyState::Secondary => "备用网络",
            RedundancyState::Both => "双网络活动",
        };
        write!(
            f,
            "状态: {}, 主链路: {}, 备链路: {}, 故障转移: {}",
            state_str,
            if self.primary_link_up { "UP" } else { "DOWN" },
            if self.secondary_link_up { "UP" } else { "DOWN" },
            self.failover_count,
        )
    }
}

/// 冗余网络管理器
///
/// 对应 C# DarraEtherCAT (RedundancyManager partial)
pub struct RedundancyManager {
    master_index: u16,
}

impl RedundancyManager {
    /// 创建新的冗余管理器
    pub fn new(master_index: u16) -> Self {
        Self { master_index }
    }

    /// 启用或禁用冗余网络
    pub fn enable(&self, enable: bool) -> bool {
        unsafe { ffi::EnableRedundancy(self.master_index, if enable { 1 } else { 0 }) != 0 }
    }

    /// 冗余网络状态
    pub fn status(&self) -> Option<RedundancyInfo> {
        unsafe {
            let ptr = ffi::GetRedundancyStatus(self.master_index);
            if ptr.is_null() {
                return None;
            }

            let native = &*(ptr as *const ffi::RedundancyStatus);
            let info = RedundancyInfo {
                state: match native.state {
                    0 => RedundancyState::None,
                    1 => RedundancyState::Primary,
                    2 => RedundancyState::Secondary,
                    3 => RedundancyState::Both,
                    _ => RedundancyState::None,
                },
                primary_link_up: native.primary_link_up != 0,
                secondary_link_up: native.secondary_link_up != 0,
                primary_tx_frames: native.primary_tx_frames,
                primary_rx_frames: native.primary_rx_frames,
                secondary_tx_frames: native.secondary_tx_frames,
                secondary_rx_frames: native.secondary_rx_frames,
                failover_count: native.failover_count,
                last_failover_time: native.last_failover_time,
            };

            ffi::FreeMemory(ptr as *mut std::os::raw::c_void);
            Some(info)
        }
    }

    /// 强制冗余故障转移
    pub fn force_failover(&self) -> bool {
        unsafe { ffi::ForceRedundancyFailover(self.master_index) != 0 }
    }

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

    /// 副链路状态
    pub fn secondary_link_status(&self) -> bool {
        unsafe { ffi::GetSecondaryLinkStatus(self.master_index) != 0 }
    }

    /// 环形模式 (0=Inactive, 1=Dual, 2=Degraded)
    pub fn ring_mode(&self) -> i32 {
        unsafe { ffi::GetRingMode(self.master_index) }
    }

    /// 设置冗余过程数据模式 (对齐 C# DarraEtherCAT.SetRedProcessdata)
    ///
    /// # 参数
    /// * `mode` - 冗余处理模式 (0=禁用, 1=启用)
    pub fn set_red_processdata(&self, mode: i32) {
        unsafe { ffi::SetRedProcessdata(mode) }
    }

    /// 获取冗余过程数据模式 (对齐 C# DarraEtherCAT.GetRedProcessdata)
    ///
    /// # 返回
    /// 当前冗余处理模式 (0=禁用, 非0=启用)
    pub fn get_red_processdata(&self) -> i32 {
        unsafe { ffi::GetRedProcessdata() }
    }
}