Skip to main content

darra_ethercat/master/
state.rs

1
2use crate::utils::ffi;
3use crate::data::error::EcState;
4
5pub fn abort() {
6    unsafe { ffi::AbortNetwork(); }
7}
8
9pub fn reset_abort() {
10    unsafe { ffi::ResetAbortNetwork(); }
11}
12
13pub fn abort_scan() {
14    unsafe { ffi::AbortScan(); }
15}
16
17pub fn reset_scan_abort() {
18    unsafe { ffi::ResetScanAbort(); }
19}
20
21pub fn emergency_close_nics() {
22    unsafe { ffi::EmergencyCloseNics(); }
23}
24
25pub fn get_cpu_cores() -> i32 {
26    unsafe { ffi::GetAvailableCpuCores() }
27}
28
29pub fn set_cpu_affinity(master_index: u16, base_cpu_core: i32) -> bool {
30    unsafe { ffi::SetMasterCpuAffinity(master_index, base_cpu_core) != 0 }
31}
32
33pub fn set_process_cpu_affinity(cpu_core: i32) -> bool {
34    unsafe { ffi::SetProcessCpuAffinity(cpu_core) != 0 }
35}
36
37pub fn apply_realtime_optimizations() -> bool {
38    unsafe { ffi::ApplyRealtimeOptimizations() != 0 }
39}
40
41pub fn remove_realtime_optimizations() -> bool {
42    unsafe { ffi::RemoveRealtimeOptimizations() != 0 }
43}
44
45pub fn get_realtime_optimizations_status() -> bool {
46    unsafe { ffi::GetRealtimeOptimizationsStatus() != 0 }
47}
48
49pub fn set_all_slave_watchdog(master_index: u16, timeout_ms: u32) -> i32 {
50    unsafe { ffi::SetAllSlaveWatchdog(master_index, timeout_ms) }
51}
52
53pub fn set_all_slave_pdi_watchdog(master_index: u16, timeout_ms: u32) -> i32 {
54    unsafe { ffi::SetAllSlavePdiWatchdog(master_index, timeout_ms) }
55}
56
57pub fn get_max_master_instances() -> i32 {
58    unsafe { ffi::GetMaxMasterInstances() }
59}
60
61pub fn apply_auto_cpu_affinity(master_index: u16) -> bool {
62    let cpu_cores = get_cpu_cores();
63    if cpu_cores < 2 {
64        return false;
65    }
66
67    let cores_per_instance = 2;
68    let instance_offset = (master_index as i32 - 1) * cores_per_instance;
69    let mut base_cpu_core = (cpu_cores - 1) - instance_offset;
70
71    if base_cpu_core < 1 {
72        base_cpu_core = std::cmp::min(1, cpu_cores - 1);
73    }
74    if base_cpu_core >= cpu_cores {
75        base_cpu_core = cpu_cores - 1;
76    }
77    if base_cpu_core < 0 {
78        base_cpu_core = 0;
79    }
80
81    set_cpu_affinity(master_index, base_cpu_core)
82}
83
84pub fn init_console_info(_log_level: i32) {
85
86}
87
88#[derive(Debug, Clone)]
89pub struct StartupVerifyResult {
90
91    pub valid: bool,
92
93    pub slave_count: u16,
94
95    pub issues: Vec<String>,
96}
97
98pub fn wait_for_state(master_index: u16, target: EcState,
99                      timeout_ms: u32, poll_interval_ms: u32) -> bool {
100    use std::time::{Duration, Instant};
101    let deadline = Instant::now() + Duration::from_millis(timeout_ms as u64);
102    let interval = Duration::from_millis(poll_interval_ms.max(1) as u64);
103    let target_raw = target as u8;
104    loop {
105
106        let ptr = unsafe { ffi::GetMasterState(master_index) };
107        if !ptr.is_null() {
108            let cur = unsafe { *(ptr as *const u16) } as u8;
109            if (cur & 0x0F) == (target_raw & 0x0F) {
110                return true;
111            }
112        }
113        if Instant::now() >= deadline {
114
115            let ptr = unsafe { ffi::GetMasterState(master_index) };
116            if !ptr.is_null() {
117                let cur = unsafe { *(ptr as *const u16) } as u8;
118                return (cur & 0x0F) == (target_raw & 0x0F);
119            }
120            return false;
121        }
122        std::thread::sleep(interval);
123    }
124}
125
126pub fn wait_for_slave_state(master_index: u16, slave_index: u16, target: EcState,
127                             timeout_ms: u32, poll_interval_ms: u32) -> bool {
128    use std::time::{Duration, Instant};
129    let deadline = Instant::now() + Duration::from_millis(timeout_ms as u64);
130    let interval = Duration::from_millis(poll_interval_ms.max(1) as u64);
131    let target_raw = (target as u8) & 0x0F;
132    loop {
133        let cur = unsafe { ffi::GetSlaveState(master_index, slave_index) } & 0x0F;
134        if cur == target_raw {
135            return true;
136        }
137        if Instant::now() >= deadline {
138            let final_state = unsafe { ffi::GetSlaveState(master_index, slave_index) } & 0x0F;
139            return final_state == target_raw;
140        }
141        std::thread::sleep(interval);
142    }
143}
144
145pub fn verify_startup_configuration(master_index: u16) -> StartupVerifyResult {
146    let mut issues = Vec::new();
147    let mut slave_count: u16 = 0;
148
149    let link = unsafe { ffi::GetLinkStatus(master_index) };
150    if link == 0 {
151        issues.push("链路未连接".to_string());
152    }
153
154    for si in 1u16..256 {
155        let s_state = unsafe { ffi::GetSlaveState(master_index, si) };
156        if s_state == 0 {
157            break;
158        }
159        slave_count += 1;
160        let base = s_state & 0x0F;
161        if base < 2 {
162            issues.push(format!("从站 {} 状态异常: 0x{:02X}", si, s_state));
163        }
164        if (s_state & 0x10) != 0 {
165            let al_code = unsafe { ffi::GetSlaveALStatusCode(master_index, si) };
166            issues.push(format!("从站 {} 有 AL 错误: 0x{:04X}", si, al_code));
167        }
168    }
169
170    let result = unsafe { ffi::ec_validate_config(master_index) };
171    if result != 0 {
172        issues.push(format!("配置验证失败: 错误码 {}", result));
173    }
174
175    StartupVerifyResult {
176        valid: issues.is_empty(),
177        slave_count,
178        issues,
179    }
180}
181
182#[derive(Debug, Clone, Copy, PartialEq, Eq)]
183pub enum AlStatusClass {
184
185    NoError,
186
187    Configuration,
188
189    Communication,
190
191    Watchdog,
192
193    VendorSpecific,
194
195    Unknown(i32),
196}
197
198impl AlStatusClass {
199
200    fn from_raw(v: i32) -> Self {
201        match v {
202            0 => Self::NoError,
203            1 => Self::Configuration,
204            2 => Self::Communication,
205            3 => Self::Watchdog,
206            4 => Self::VendorSpecific,
207            other => Self::Unknown(other),
208        }
209    }
210}
211
212pub fn esm_is_legal_transition(from: EcState, to: EcState) -> bool {
213    unsafe { ffi::EsmIsLegalTransition(from as i32, to as i32) != 0 }
214}
215
216pub fn esm_legal_transitions(from: EcState) -> Vec<EcState> {
217    const MAX: usize = 8;
218    let mut buf = [0u8; MAX];
219    let n = unsafe {
220        ffi::EsmGetLegalTransitions(from as i32, buf.as_mut_ptr(), MAX as i32)
221    };
222    if n <= 0 { return Vec::new(); }
223    buf[..(n as usize).min(MAX)]
224        .iter()
225        .filter_map(|&raw| match raw {
226            0x00 => Some(EcState::None),
227            0x01 => Some(EcState::Init),
228            0x02 => Some(EcState::PreOp),
229            0x03 => Some(EcState::Boot),
230            0x04 => Some(EcState::SafeOp),
231            0x08 => Some(EcState::Operational),
232            _ => None,
233        })
234        .collect()
235}
236
237pub fn esm_default_timeout_ms(from: EcState, to: EcState) -> u32 {
238    unsafe { ffi::EsmGetDefaultTimeoutMs(from as i32, to as i32) }
239}
240
241pub fn esm_is_known_al_status_code(al_status_code: u16) -> bool {
242    unsafe { ffi::EsmIsKnownAlStatusCode(al_status_code) != 0 }
243}
244
245pub fn esm_classify_al_status_code(al_status_code: u16) -> AlStatusClass {
246    AlStatusClass::from_raw(unsafe { ffi::EsmClassifyAlStatusCode(al_status_code) })
247}
248
249pub fn esm_master_class(master_index: u16) -> u8 {
250    unsafe { ffi::EsmGetMasterClass(master_index) }
251}