darra_ethercat/utils/
kernel_guard.rs1
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}