Skip to main content

darra_ethercat/data/
error.rs

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}