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.
//! RT 驱动版本信息 (Darra.Core.dll wrapper)
//!
//! 对应 Core.dll `GetDriverVersion` (ordinal 1654) /
//! `InvalidateDriverVersionCache` / `EnsureDriversRunning`.
//!
//! 用于在 Master.build() 启动时校验 SDK 与 RT 驱动版本是否兼容,
//! 不兼容时打印警告日志, 但不阻塞流程。

use crate::utils::ffi;
use crate::statics::version_info::{MAJOR_VERSION, MINOR_VERSION};

/// SDK 侧高层驱动版本结构 (与 C# `DriverVersionInfo` 对齐)
#[derive(Debug, Clone, Default)]
pub struct DriverVersionInfo {
    /// 主版本号
    pub major: u32,
    /// 次版本号
    pub minor: u32,
    /// 构建号
    pub build: u32,
    /// 构建日期 (UTF-8 字符串)
    pub build_date: String,
    /// 驱动文件名 (例如 "DarraRT.sys")
    pub driver_name: String,
    /// 驱动是否就绪可用
    pub available: bool,
    /// 错误信息 (查询失败 / 驱动未安装时填充)
    pub error_message: Option<String>,
}

fn read_packed_str(buf: &[u8; 32]) -> String {
    let null_pos = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
    String::from_utf8_lossy(&buf[..null_pos]).to_string()
}

/// 查询当前 RT 驱动版本 (透传 Core.dll GetDriverVersion)
pub fn get() -> DriverVersionInfo {
    let ptr = unsafe { ffi::GetDriverVersion() };
    if ptr.is_null() {
        return DriverVersionInfo {
            error_message: Some("GetDriverVersion 返回空指针 (Core.dll 未加载或符号缺失)".into()),
            ..Default::default()
        };
    }
    // packed(4) 结构体, 用 read_unaligned 读取避免 UB
    let info = unsafe { std::ptr::read_unaligned(ptr) };
    let major = unsafe { std::ptr::addr_of!(info.major).read_unaligned() };
    let minor = unsafe { std::ptr::addr_of!(info.minor).read_unaligned() };
    let build = unsafe { std::ptr::addr_of!(info.build).read_unaligned() };
    let available = unsafe { std::ptr::addr_of!(info.available).read_unaligned() };
    let error_code = unsafe { std::ptr::addr_of!(info.error_code).read_unaligned() };
    let build_date_raw = unsafe { std::ptr::addr_of!(info.build_date).read_unaligned() };
    let driver_name_raw = unsafe { std::ptr::addr_of!(info.driver_name).read_unaligned() };

    DriverVersionInfo {
        major,
        minor,
        build,
        build_date: read_packed_str(&build_date_raw),
        driver_name: read_packed_str(&driver_name_raw),
        available: available != 0,
        error_message: if error_code != 0 {
            Some(format!("驱动错误码 0x{:08X}", error_code))
        } else {
            None
        },
    }
}

/// 失效驱动版本缓存 (调试 / 热升级场景使用)
pub fn invalidate_cache() {
    unsafe { ffi::InvalidateDriverVersionCache() }
}

/// 确保 RT 驱动处于运行状态 (Core.dll EnsureDriversRunning)
///
/// 返回 0 表示全部就绪, 非 0 表示至少一个驱动未启动 / 缺失
pub fn ensure_drivers_running() -> i32 {
    unsafe { ffi::EnsureDriversRunning() as i32 }
}

/// 检查 SDK 与驱动主次版本是否兼容
///
/// 返回 (是否兼容, 详细信息)。规则:
///   - SDK MAJOR 必须 == 驱动 MAJOR
///   - SDK MINOR 必须 <= 驱动 MINOR (驱动可向后兼容老 SDK)
pub fn check_compatibility() -> (bool, String) {
    let info = get();
    if !info.available {
        let err = info.error_message.as_deref().unwrap_or("驱动不可用");
        return (false, format!("RT 驱动不可用: {}", err));
    }
    let sdk_major = MAJOR_VERSION as u32;
    let sdk_minor = MINOR_VERSION as u32;
    let drv_major = info.major;
    let drv_minor = info.minor;
    if sdk_major != drv_major {
        return (
            false,
            format!(
                "主版本不匹配: SDK={}.{} 驱动={}.{} ({})",
                sdk_major, sdk_minor, drv_major, drv_minor, info.driver_name
            ),
        );
    }
    if sdk_minor > drv_minor {
        return (
            false,
            format!(
                "SDK 次版本高于驱动: SDK={}.{} 驱动={}.{} (建议升级驱动)",
                sdk_major, sdk_minor, drv_major, drv_minor
            ),
        );
    }
    (
        true,
        format!(
            "兼容: SDK={}.{} 驱动={}.{}.{} ({}, build {})",
            sdk_major, sdk_minor, drv_major, drv_minor, info.build, info.driver_name, info.build_date
        ),
    )
}

/// 在日志中输出兼容性检查结果 (供 Master.build() 调用)
pub fn log_compatibility() {
    use crate::logging::logging::{LogManager, LogCategory};
    let (ok, msg) = check_compatibility();
    let category = if ok { LogCategory::Message } else { LogCategory::Warning };
    let line = if ok {
        format!("[DriverVersion] {}", msg)
    } else {
        format!("[DriverVersion] 不兼容: {}", msg)
    };
    LogManager::instance().add_log(category, &line);
    if !ok {
        eprintln!("{}", line);
    }
}