darra-ethercat-master 2.1.0

商业 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.
//! 启动配置验证器
//!
//! 用于验证实际从站配置是否符合预期 (VendorID / ProductCode / RevisionNo 等)。
//! 对应 C# `Utils/StartupConfigurationVerifier.cs`。

/// 预期从站配置
#[derive(Debug, Clone)]
pub struct ExpectedSlaveConfig {
    /// 从站索引 (1-based)
    pub index: u16,
    /// 厂商 ID
    pub vendor_id: u32,
    /// 产品代码
    pub product_code: u32,
    /// 修订号
    pub revision_no: u32,
    /// 序列号
    pub serial_no: u32,
    /// 别名地址
    pub alias_addr: u16,
    /// 活跃端口
    pub active_ports: u8,
    /// 拓扑类型
    pub topology: u8,
    /// 从站名称
    pub name: String,
}

/// 从站验证详情
#[derive(Debug, Clone)]
pub struct SlaveVerifyDetail {
    /// 从站索引 (1-based)
    pub slave_index: u16,
    /// 从站名称
    pub slave_name: String,
    /// 是否整体匹配
    pub is_match: bool,
    /// 厂商 ID 匹配
    pub vendor_id_match: bool,
    /// 产品代码匹配
    pub product_code_match: bool,
    /// 修订号匹配
    pub revision_match: bool,
    /// 序列号匹配
    pub serial_match: bool,
    /// 别名地址匹配
    pub alias_match: bool,
    /// 拓扑匹配
    pub topology_match: bool,
    /// 实际厂商 ID
    pub actual_vendor_id: u32,
    /// 实际产品代码
    pub actual_product_code: u32,
    /// 实际修订号
    pub actual_revision: u32,
    /// 实际序列号
    pub actual_serial: u32,
    /// 实际别名地址
    pub actual_alias: u16,
}

/// 验证结果
#[derive(Debug, Clone)]
pub struct VerificationResult {
    /// 验证是否通过
    pub success: bool,
    /// 错误列表
    pub errors: Vec<String>,
    /// 警告列表
    pub warnings: Vec<String>,
    /// 每个从站的详细验证结果
    pub slave_details: Vec<SlaveVerifyDetail>,
}

impl VerificationResult {
    /// 创建空的验证结果
    pub fn new() -> Self {
        Self {
            success: true,
            errors: Vec::new(),
            warnings: Vec::new(),
            slave_details: Vec::new(),
        }
    }
}

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

/// 实际从站信息 (用于验证)
#[derive(Debug, Clone)]
pub struct ActualSlaveInfo {
    /// 厂商 ID
    pub vendor_id: u32,
    /// 产品代码
    pub product_code: u32,
    /// 修订号
    pub revision: u32,
    /// 序列号
    pub serial: u32,
    /// 别名地址
    pub alias_addr: u16,
    /// 活跃端口
    pub active_ports: u8,
    /// 拓扑类型
    pub topology: u8,
    /// 从站名称
    pub name: String,
}

/// 验证从站配置
///
/// 对比实际扫描到的从站与预期配置,检查 VendorID / ProductCode 等是否匹配。
///
/// # 参数
/// - `actual_slaves` - 实际扫描到的从站信息列表
/// - `expected_configs` - 预期配置列表
/// - `strict_mode` - 严格模式: 额外验证 RevisionNo 和 SerialNo
pub fn verify_configuration(
    actual_slaves: &[ActualSlaveInfo],
    expected_configs: &[ExpectedSlaveConfig],
    strict_mode: bool,
) -> VerificationResult {
    let mut result = VerificationResult::new();

    if expected_configs.is_empty() {
        result.warnings.push("没有预期配置进行验证".to_string());
        return result;
    }

    // 检查从站数量
    if actual_slaves.len() != expected_configs.len() {
        result.warnings.push(format!(
            "从站数量不匹配: 实际 {}, 预期 {}",
            actual_slaves.len(),
            expected_configs.len()
        ));
    }

    let count = actual_slaves.len().min(expected_configs.len());

    for i in 0..count {
        let actual = &actual_slaves[i];
        let expected = &expected_configs[i];

        let vendor_id_match = actual.vendor_id == expected.vendor_id;
        let product_code_match = actual.product_code == expected.product_code;
        let revision_match = !strict_mode || actual.revision == expected.revision_no;
        let serial_match = !strict_mode || expected.serial_no == 0 || actual.serial == expected.serial_no;
        let alias_match = expected.alias_addr == 0 || actual.alias_addr == expected.alias_addr;

        let topology_match = if expected.active_ports == 0 && expected.topology == 0 {
            true // 无拓扑信息,跳过
        } else {
            actual.active_ports == expected.active_ports && actual.topology == expected.topology
        };

        let is_match = vendor_id_match && product_code_match &&
                       revision_match && serial_match &&
                       alias_match && topology_match;

        if !is_match {
            result.success = false;
            let mut err_parts = Vec::new();
            if !vendor_id_match {
                err_parts.push(format!("VID 0x{:X}!=0x{:X}", actual.vendor_id, expected.vendor_id));
            }
            if !product_code_match {
                err_parts.push(format!("PID 0x{:X}!=0x{:X}", actual.product_code, expected.product_code));
            }
            if !revision_match {
                err_parts.push(format!("Rev 0x{:X}!=0x{:X}", actual.revision, expected.revision_no));
            }
            if !serial_match {
                err_parts.push(format!("SN 0x{:X}!=0x{:X}", actual.serial, expected.serial_no));
            }
            if !alias_match {
                err_parts.push(format!("Alias {}!={}", actual.alias_addr, expected.alias_addr));
            }
            if !topology_match {
                err_parts.push("拓扑不匹配".to_string());
            }
            result.errors.push(format!("从站 {} 不匹配: {}", i + 1, err_parts.join(", ")));
        }

        result.slave_details.push(SlaveVerifyDetail {
            slave_index: (i + 1) as u16,
            slave_name: actual.name.clone(),
            is_match,
            vendor_id_match,
            product_code_match,
            revision_match,
            serial_match,
            alias_match,
            topology_match,
            actual_vendor_id: actual.vendor_id,
            actual_product_code: actual.product_code,
            actual_revision: actual.revision,
            actual_serial: actual.serial,
            actual_alias: actual.alias_addr,
        });
    }

    result
}