Skip to main content

darra_ethercat/utils/
kernel_guard.rs

1
2use std::ffi::CStr;
3use std::os::raw::c_char;
4
5use thiserror::Error;
6
7use crate::utils::ffi;
8
9#[repr(i32)]
10#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
11pub enum DarraKernelStatus {
12
13    Ok = 0,
14
15    NotInstalled = 1,
16
17    Stopped = 2,
18
19    AccessDenied = 3,
20
21    SignatureFail = 4,
22
23    Blocked = 5,
24
25    DeviceMissing = 6,
26
27    Disabled = 7,
28
29    UnknownError = 99,
30}
31
32impl DarraKernelStatus {
33
34    pub fn from_i32(code: i32) -> Self {
35        match code {
36            0 => DarraKernelStatus::Ok,
37            1 => DarraKernelStatus::NotInstalled,
38            2 => DarraKernelStatus::Stopped,
39            3 => DarraKernelStatus::AccessDenied,
40            4 => DarraKernelStatus::SignatureFail,
41            5 => DarraKernelStatus::Blocked,
42            6 => DarraKernelStatus::DeviceMissing,
43            7 => DarraKernelStatus::Disabled,
44            _ => DarraKernelStatus::UnknownError,
45        }
46    }
47
48    pub fn as_i32(self) -> i32 {
49        self as i32
50    }
51}
52
53impl std::fmt::Display for DarraKernelStatus {
54    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
55
56        write!(f, "{}", get_status_message(*self))
57    }
58}
59
60#[derive(Error, Debug, Clone)]
61#[error("EtherCAT 内核驱动不可用 ({status:?}): {message}\n安装链接: {installer_url}")]
62pub struct DarraKernelNotAvailableError {
63
64    pub status: DarraKernelStatus,
65
66    pub message: String,
67
68    pub installer_url: String,
69}
70
71fn cstr_to_string(p: *const c_char, fallback: &str) -> String {
72    if p.is_null() {
73        return fallback.to_string();
74    }
75    unsafe { CStr::from_ptr(p).to_string_lossy().into_owned() }
76}
77
78pub fn probe() -> DarraKernelStatus {
79
80    let code = unsafe { ffi::DarraEcat_KernelProbe() };
81    DarraKernelStatus::from_i32(code as i32)
82}
83
84pub fn get_status_message(status: DarraKernelStatus) -> String {
85    let p = unsafe { ffi::DarraEcat_KernelStatusMessage(status.as_i32()) };
86    cstr_to_string(p, "EtherCAT 内核驱动状态未知")
87}
88
89pub fn get_installer_url() -> String {
90    let p = unsafe { ffi::DarraEcat_KernelInstallerUrl() };
91    cstr_to_string(p, "https://www.darrart.com/downloads/drivers")
92}
93
94pub fn assert_available() -> Result<(), DarraKernelNotAvailableError> {
95    let status = probe();
96    if status == DarraKernelStatus::Ok {
97        return Ok(());
98    }
99    let message = get_status_message(status);
100    let installer_url = get_installer_url();
101    Err(DarraKernelNotAvailableError {
102        status,
103        message,
104        installer_url,
105    })
106}
107
108pub fn open_installer_website() -> bool {
109    let url = get_installer_url();
110    if url.is_empty() {
111        return false;
112    }
113    open_url(&url)
114}
115
116#[cfg(target_os = "windows")]
117fn open_url(url: &str) -> bool {
118    use std::process::Command;
119
120    Command::new("cmd")
121        .args(["/C", "start", "", url])
122        .spawn()
123        .is_ok()
124}
125
126#[cfg(target_os = "macos")]
127fn open_url(url: &str) -> bool {
128    use std::process::Command;
129    Command::new("open").arg(url).spawn().is_ok()
130}
131
132#[cfg(all(unix, not(target_os = "macos")))]
133fn open_url(url: &str) -> bool {
134    use std::process::Command;
135    Command::new("xdg-open").arg(url).spawn().is_ok()
136}
137
138#[cfg(not(any(target_os = "windows", target_os = "macos", unix)))]
139fn open_url(_url: &str) -> bool {
140    false
141}