darra_ethercat/master/
state.rs1
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}