darra-ethercat-master 2.7.0

Commercial EtherCAT master protocol stack, real-time kernel driver integration, Windows and Linux support, multi-language SDKs, complex topology and hot-plug support.
Documentation

#[derive(Debug, Clone)]
pub struct ExpectedSlaveConfig {

    pub index: u16,

    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 {

    pub slave_index: u16,

    pub slave_name: String,

    pub is_match: bool,

    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,

    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 {

    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,
}

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
}