#[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
}