1
2use std::fmt;
3
4#[derive(Debug, Clone)]
5pub enum DarraError {
6
7 AlreadyInitialized,
8
9 NotInitialized,
10
11 Timeout,
12
13 NoSlaves,
14
15 NetworkFailed(i32),
16
17 StateChangeFailed(u8),
18
19 SdoReadFailed { index: u16, subindex: u8, abort_code: Option<crate::data::types::SDOError> },
20
21 SdoWriteFailed { index: u16, subindex: u8, abort_code: Option<crate::data::types::SDOError> },
22
23 SoeFailed(u16),
24
25 FoeFailed(String),
26
27 EoeFailed,
28
29 AoeFailed,
30
31 VoeFailed,
32
33 InvalidParameter(String),
34
35 ConfigLoadFailed(i32),
36
37 NullPointer,
38
39 CiA402Failed(String),
40
41 EmcyFailed,
42
43 PdoFailed(String),
44
45 TopologyFailed,
46
47 RedundancyFailed,
48
49 RegisterFailed,
50
51 DiagnosticsFailed,
52
53 WdkFailed(String),
54
55 UdpFailed,
56
57 Cancelled(String),
58
59 Other(String),
60}
61
62impl fmt::Display for DarraError {
63 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64 match self {
65 Self::AlreadyInitialized => write!(f, "主站已初始化"),
66 Self::NotInitialized => write!(f, "主站未初始化"),
67 Self::Timeout => write!(f, "操作超时"),
68 Self::NoSlaves => write!(f, "未发现从站"),
69 Self::NetworkFailed(code) => write!(f, "网络配置失败 (返回码: {})", code),
70 Self::StateChangeFailed(state) => write!(f, "状态切换失败 (目标: 0x{:02X})", state),
71 Self::SdoReadFailed { index, subindex, abort_code } => {
72 match abort_code {
73 Some(ac) => write!(f, "SDO 读取失败 (0x{:04X}:{:02X}, abort=0x{:08X})", index, subindex, *ac as u32),
74 None => write!(f, "SDO 读取失败 (0x{:04X}:{:02X})", index, subindex),
75 }
76 }
77 Self::SdoWriteFailed { index, subindex, abort_code } => {
78 match abort_code {
79 Some(ac) => write!(f, "SDO 写入失败 (0x{:04X}:{:02X}, abort=0x{:08X})", index, subindex, *ac as u32),
80 None => write!(f, "SDO 写入失败 (0x{:04X}:{:02X})", index, subindex),
81 }
82 }
83 Self::SoeFailed(idn) => write!(f, "SoE 操作失败 (IDN: 0x{:04X})", idn),
84 Self::FoeFailed(name) => write!(f, "FoE 操作失败 (文件: {})", name),
85 Self::EoeFailed => write!(f, "EoE 操作失败"),
86 Self::AoeFailed => write!(f, "AoE 操作失败"),
87 Self::VoeFailed => write!(f, "VoE 操作失败"),
88 Self::InvalidParameter(msg) => write!(f, "无效参数: {}", msg),
89 Self::ConfigLoadFailed(code) => write!(f, "配置加载失败 (返回码: {})", code),
90 Self::NullPointer => write!(f, "DLL 返回空指针"),
91 Self::CiA402Failed(msg) => write!(f, "CiA 402 操作失败: {}", msg),
92 Self::EmcyFailed => write!(f, "EMCY 操作失败"),
93 Self::PdoFailed(msg) => write!(f, "PDO 操作失败: {}", msg),
94 Self::TopologyFailed => write!(f, "拓扑操作失败"),
95 Self::RedundancyFailed => write!(f, "冗余操作失败"),
96 Self::RegisterFailed => write!(f, "寄存器操作失败"),
97 Self::DiagnosticsFailed => write!(f, "诊断操作失败"),
98 Self::WdkFailed(msg) => write!(f, "WDK 操作失败: {}", msg),
99 Self::UdpFailed => write!(f, "UDP 操作失败"),
100 Self::Cancelled(reason) => write!(f, "异步操作被取消: {}", reason),
101 Self::Other(msg) => write!(f, "{}", msg),
102 }
103 }
104}
105
106impl std::error::Error for DarraError {}
107
108pub type Result<T> = std::result::Result<T, DarraError>;
109
110#[derive(Debug, Clone, Copy, PartialEq, Eq)]
111#[repr(u8)]
112pub enum EcState {
113
114 None = 0x00,
115
116 Init = 0x01,
117
118 PreOp = 0x02,
119
120 Boot = 0x03,
121
122 SafeOp = 0x04,
123
124 Operational = 0x08,
125}
126
127impl EcState {
128
129 pub fn from_raw(val: u8) -> Option<Self> {
130
131 match val & 0x0F {
132 0x00 => Some(Self::None),
133 0x01 => Some(Self::Init),
134 0x02 => Some(Self::PreOp),
135 0x03 => Some(Self::Boot),
136 0x04 => Some(Self::SafeOp),
137 0x08 => Some(Self::Operational),
138 _ => None,
139 }
140 }
141
142 pub fn has_error(raw: u8) -> bool {
143 (raw & 0x10) != 0
144 }
145
146 pub fn format(raw: u8) -> String {
147 let base = match raw & 0x0F {
148 0x00 => "None",
149 0x01 => "Init",
150 0x02 => "PreOp",
151 0x03 => "Boot",
152 0x04 => "SafeOp",
153 0x08 => "OP",
154 _ => "Unknown",
155 };
156 if (raw & 0x10) != 0 {
157 format!("{}+Error", base)
158 } else {
159 base.to_string()
160 }
161 }
162}
163
164impl fmt::Display for EcState {
165 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166 let name = match self {
167 Self::None => "None",
168 Self::Init => "Init",
169 Self::PreOp => "PreOp",
170 Self::Boot => "Boot",
171 Self::SafeOp => "SafeOp",
172 Self::Operational => "OP",
173 };
174 write!(f, "{}", name)
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq)]
179#[repr(u8)]
180pub enum EcSlaveStatus {
181
182 None = 0x00,
183
184 Init = 0x01,
185
186 PreOp = 0x02,
187
188 Boot = 0x03,
189
190 SafeOp = 0x04,
191
192 OP = 0x08,
193
194 ErrorFlag = 0x10,
195
196 InitFault = 0x11,
197
198 PreOpFault = 0x12,
199
200 BootFault = 0x13,
201
202 SafeOpFault = 0x14,
203
204 OpFault = 0x18,
205}
206
207impl EcSlaveStatus {
208
209 pub fn from_raw(raw: u8) -> Option<Self> {
210 match raw & 0x1F {
211 0x00 => Some(Self::None),
212 0x01 => Some(Self::Init),
213 0x02 => Some(Self::PreOp),
214 0x03 => Some(Self::Boot),
215 0x04 => Some(Self::SafeOp),
216 0x08 => Some(Self::OP),
217 0x10 => Some(Self::ErrorFlag),
218 0x11 => Some(Self::InitFault),
219 0x12 => Some(Self::PreOpFault),
220 0x13 => Some(Self::BootFault),
221 0x14 => Some(Self::SafeOpFault),
222 0x18 => Some(Self::OpFault),
223 _ => None,
224 }
225 }
226
227 pub fn from_raw_or_none(raw: u8) -> Self {
228 Self::from_raw(raw).unwrap_or(Self::None)
229 }
230
231 pub fn base_state(self) -> EcState {
232 let raw = (self as u8) & 0x0F;
233 EcState::from_raw(raw).unwrap_or(EcState::None)
234 }
235
236 pub fn has_fault(self) -> bool {
237 ((self as u8) & 0x10) != 0
238 }
239
240 pub fn is_running(self) -> bool {
241 matches!(self, Self::SafeOp | Self::OP)
242 }
243
244 pub fn is_op(self) -> bool {
245 matches!(self, Self::OP)
246 }
247
248 pub fn pretty(self) -> &'static str {
249 match self {
250 Self::None => "None",
251 Self::Init => "Init",
252 Self::PreOp => "PreOp",
253 Self::Boot => "Boot",
254 Self::SafeOp => "SafeOp",
255 Self::OP => "OP",
256 Self::ErrorFlag => "ErrorFlag",
257 Self::InitFault => "InitFault (Init+Error)",
258 Self::PreOpFault => "PreOpFault (PreOp+Error)",
259 Self::BootFault => "BootFault (Boot+Error)",
260 Self::SafeOpFault => "SafeOpFault (SafeOp+Error)",
261 Self::OpFault => "OpFault (OP+Error)",
262 }
263 }
264}
265
266impl fmt::Display for EcSlaveStatus {
267 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
268 write!(f, "{}", self.pretty())
269 }
270}
271
272#[derive(Debug, Clone, Copy, PartialEq, Eq)]
273#[repr(u8)]
274pub enum WcContribution {
275
276 NotContributed = 0,
277
278 Contributed = 1,
279
280 Unknown = 0xFF,
281}
282
283impl WcContribution {
284
285 pub fn from_raw(raw: u8) -> Self {
286 match raw {
287 1 => Self::Contributed,
288 0 => Self::NotContributed,
289 _ => Self::Unknown,
290 }
291 }
292
293 pub fn is_contributed(self) -> bool {
294 matches!(self, Self::Contributed)
295 }
296}
297
298impl fmt::Display for WcContribution {
299 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
300 let s = match self {
301 Self::Contributed => "Contributed",
302 Self::NotContributed => "NotContributed",
303 Self::Unknown => "Unknown",
304 };
305 write!(f, "{}", s)
306 }
307}
308
309#[derive(Debug, Clone, Copy, PartialEq, Eq)]
310pub struct SlaveAlMirror {
311
312 pub al_state: EcSlaveStatus,
313
314 pub al_status_code: u16,
315
316 pub raw: u16,
317}
318
319impl SlaveAlMirror {
320
321 pub fn from_raw(raw: u16) -> Self {
322 let state_byte = (raw & 0xFF) as u8;
323 let code = (raw >> 8) & 0xFF;
324 Self {
325 al_state: EcSlaveStatus::from_raw_or_none(state_byte),
326 al_status_code: code,
327 raw,
328 }
329 }
330
331 pub fn has_fault(self) -> bool {
332 self.al_state.has_fault()
333 }
334
335 pub fn is_unknown(self) -> bool {
336 self.raw == 0
337 }
338}
339
340impl fmt::Display for SlaveAlMirror {
341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342 if self.is_unknown() {
343 write!(f, "Unknown (no mirror)")
344 } else {
345 write!(f, "{} / AL Code 0x{:04X}", self.al_state, self.al_status_code)
346 }
347 }
348}
349
350#[derive(Debug, Clone, Copy, PartialEq, Eq)]
351#[repr(i32)]
352pub enum CiA402State {
353
354 NotReady = 0,
355
356 SwitchOnDisabled = 1,
357
358 ReadyToSwitchOn = 2,
359
360 SwitchedOn = 3,
361
362 OperationEnabled = 4,
363
364 QuickStopActive = 5,
365
366 FaultReaction = 6,
367
368 Fault = 7,
369
370 Unknown = 99,
371}
372
373impl CiA402State {
374
375 pub fn from_raw(val: i32) -> Self {
376 match val {
377 0 => Self::NotReady,
378 1 => Self::SwitchOnDisabled,
379 2 => Self::ReadyToSwitchOn,
380 3 => Self::SwitchedOn,
381 4 => Self::OperationEnabled,
382 5 => Self::QuickStopActive,
383 6 => Self::FaultReaction,
384 7 => Self::Fault,
385 _ => Self::Unknown,
386 }
387 }
388}
389
390#[derive(Debug, Clone, Copy, PartialEq, Eq)]
391#[repr(i8)]
392pub enum CiA402Mode {
393
394 PP = 1,
395
396 VL = 2,
397
398 PV = 3,
399
400 PT = 4,
401
402 HM = 6,
403
404 IP = 7,
405
406 CSP = 8,
407
408 CSV = 9,
409
410 CST = 10,
411}
412
413#[derive(Debug, Clone, Copy, PartialEq, Eq)]
414#[repr(u8)]
415pub enum LinkState {
416
417 Disconnected = 0,
418
419 Connected = 1,
420
421 Redundancy = 2,
422
423 PrimaryOnly = 3,
424
425 SecondaryOnly = 4,
426}
427
428impl LinkState {
429
430 pub fn from_raw(val: u8) -> Self {
431 match val {
432 0 => Self::Disconnected,
433 1 => Self::Connected,
434 2 => Self::Redundancy,
435 3 => Self::PrimaryOnly,
436 4 => Self::SecondaryOnly,
437 _ => Self::Disconnected,
438 }
439 }
440}
441
442#[derive(Debug, Clone, Copy, PartialEq, Eq)]
443#[repr(i32)]
444pub enum RedundancyState {
445
446 None = 0,
447
448 Primary = 1,
449
450 Secondary = 2,
451
452 Both = 3,
453}
454
455impl RedundancyState {
456
457 pub fn from_raw(val: i32) -> Self {
458 match val {
459 0 => Self::None,
460 1 => Self::Primary,
461 2 => Self::Secondary,
462 3 => Self::Both,
463 _ => Self::None,
464 }
465 }
466}
467
468#[derive(Debug, Clone, Copy, PartialEq, Eq)]
469#[repr(u16)]
470pub enum FoEErrorCode {
471
472 NotDefined = 0x8000,
473
474 NotFound = 0x8001,
475
476 AccessDenied = 0x8002,
477
478 DiskFull = 0x8003,
479
480 Illegal = 0x8004,
481
482 PacketNumberWrong = 0x8005,
483
484 AlreadyExists = 0x8006,
485
486 NoUser = 0x8007,
487
488 BootstrapOnly = 0x8008,
489
490 NotBootstrap = 0x8009,
491
492 NoRights = 0x800A,
493
494 ProgramError = 0x800B,
495}
496
497impl FoEErrorCode {
498
499 pub fn from_dll_error(dll_error_code: i32) -> Self {
500 let abs_code = dll_error_code.unsigned_abs();
501 match abs_code {
502 7 => FoEErrorCode::PacketNumberWrong,
503 10 => FoEErrorCode::NotFound,
504 12 => FoEErrorCode::AccessDenied,
505 13 => FoEErrorCode::DiskFull,
506 14 => FoEErrorCode::Illegal,
507 15 => FoEErrorCode::PacketNumberWrong,
508 16 => FoEErrorCode::AlreadyExists,
509 17 => FoEErrorCode::NoUser,
510 18 => FoEErrorCode::BootstrapOnly,
511 19 => FoEErrorCode::NotBootstrap,
512 20 => FoEErrorCode::NoRights,
513 21 => FoEErrorCode::ProgramError,
514 _ => FoEErrorCode::NotDefined,
515 }
516 }
517}
518
519#[derive(Debug, Clone, Copy, PartialEq, Eq)]
520#[repr(u16)]
521pub enum SoEErrorCode {
522
523 NoError = 0x0000,
524
525 NoIDN = 0x1001,
526
527 InvalidAccessToElement = 0x1009,
528
529 NoName = 0x2001,
530
531 NameTransmissionTooShort = 0x2002,
532
533 NameTransmissionTooLong = 0x2003,
534
535 NameCannotBeChanged = 0x2004,
536
537 NameWriteProtected = 0x2005,
538
539 AttributeTransmissionTooShort = 0x3002,
540
541 AttributeTransmissionTooLong = 0x3003,
542
543 AttributeCannotBeChanged = 0x3004,
544
545 AttributeWriteProtected = 0x3005,
546
547 NoUnits = 0x4001,
548
549 UnitTransmissionTooShort = 0x4002,
550
551 UnitTransmissionTooLong = 0x4003,
552
553 UnitCannotBeChanged = 0x4004,
554
555 UnitWriteProtected = 0x4005,
556
557 NoMinimumInputValue = 0x5001,
558
559 MinValueTooShort = 0x5002,
560
561 MinValueTooLong = 0x5003,
562
563 MinValueCannotBeChanged = 0x5004,
564
565 MinValueWriteProtected = 0x5005,
566
567 NoMaximumInputValue = 0x6001,
568
569 MaxValueTooShort = 0x6002,
570
571 MaxValueTooLong = 0x6003,
572
573 MaxValueCannotBeChanged = 0x6004,
574
575 MaxValueWriteProtected = 0x6005,
576
577 NoOperationData = 0x7001,
578
579 OpDataTooShort = 0x7002,
580
581 OpDataTooLong = 0x7003,
582
583 OpDataCannotBeChanged = 0x7004,
584
585 OpDataWriteProtected = 0x7005,
586
587 OpDataSmallerThanMin = 0x7006,
588
589 OpDataGreaterThanMax = 0x7007,
590
591 InvalidDriveNumber = 0x800A,
592
593 GeneralError = 0x800B,
594
595 NoElementAddressed = 0x800C,
596
597 Unknown = 0xFFFF,
598}
599
600#[derive(Debug, Clone, Copy)]
601pub struct SyncWindowStatus {
602
603 pub diff_ns: i32,
604
605 pub max_diff_ns: i32,
606
607 pub min_diff_ns: i32,
608
609 pub in_sync: bool,
610
611 pub out_of_sync_count: u32,
612}