ethercat_types/
lib.rs

1#[macro_use]
2extern crate num_derive;
3
4use std::{convert::TryFrom, fmt, num::TryFromIntError};
5
6mod value;
7
8pub use self::value::*;
9
10/// EtherCAT Slave Position
11#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
12pub struct SlavePos(u16);
13
14impl SlavePos {
15    pub const fn new(p: u16) -> Self {
16        Self(p)
17    }
18}
19
20impl From<u16> for SlavePos {
21    fn from(pos: u16) -> Self {
22        Self(pos)
23    }
24}
25
26impl From<SlavePos> for u16 {
27    fn from(pos: SlavePos) -> Self {
28        pos.0
29    }
30}
31
32impl From<SlavePos> for usize {
33    fn from(pos: SlavePos) -> Self {
34        u16::from(pos) as usize
35    }
36}
37
38/// Object Directory Index
39#[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
40pub struct Idx(u16);
41
42impl Idx {
43    pub const fn new(i: u16) -> Self {
44        Self(i)
45    }
46}
47
48impl From<u16> for Idx {
49    fn from(idx: u16) -> Self {
50        Self(idx)
51    }
52}
53
54impl From<Idx> for u16 {
55    fn from(idx: Idx) -> Self {
56        idx.0
57    }
58}
59
60impl fmt::Debug for Idx {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        write!(f, "Idx(0x{:04X})", self.0)
63    }
64}
65
66/// Object Directory Sub-index
67#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
68pub struct SubIdx(u8);
69
70impl SubIdx {
71    pub const fn new(i: u8) -> Self {
72        Self(i)
73    }
74}
75
76impl From<u8> for SubIdx {
77    fn from(sub: u8) -> Self {
78        Self(sub)
79    }
80}
81
82impl From<SubIdx> for u8 {
83    fn from(sub: SubIdx) -> Self {
84        sub.0
85    }
86}
87
88/// SDO Position
89#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
90pub struct SdoPos(u16);
91
92impl SdoPos {
93    pub const fn new(p: u16) -> Self {
94        Self(p)
95    }
96}
97
98impl From<u16> for SdoPos {
99    fn from(pos: u16) -> Self {
100        Self(pos)
101    }
102}
103
104impl From<SdoPos> for u16 {
105    fn from(pos: SdoPos) -> Self {
106        pos.0
107    }
108}
109
110/// PDO Position
111#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
112pub struct PdoPos(u8);
113
114impl PdoPos {
115    pub const fn new(p: u8) -> Self {
116        Self(p)
117    }
118}
119
120impl From<u8> for PdoPos {
121    fn from(pos: u8) -> Self {
122        Self(pos)
123    }
124}
125
126impl From<PdoPos> for u8 {
127    fn from(pos: PdoPos) -> Self {
128        pos.0
129    }
130}
131
132/// PDO Entry Position
133#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
134pub struct PdoEntryPos(u8);
135
136impl PdoEntryPos {
137    pub const fn new(p: u8) -> Self {
138        Self(p)
139    }
140}
141
142impl From<u8> for PdoEntryPos {
143    fn from(pos: u8) -> Self {
144        Self(pos)
145    }
146}
147
148impl From<PdoEntryPos> for u8 {
149    fn from(pos: PdoEntryPos) -> Self {
150        pos.0
151    }
152}
153
154/// SDO Index
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
156pub struct SdoIdx {
157    pub idx: Idx,
158    pub sub_idx: SubIdx,
159}
160
161impl SdoIdx {
162    pub const fn new(idx: u16, sub: u8) -> Self {
163        Self {
164            idx: Idx::new(idx),
165            sub_idx: SubIdx::new(sub),
166        }
167    }
168}
169
170/// SDO Meta Information
171#[derive(Debug, Clone, PartialEq)]
172pub struct SdoInfo {
173    pub pos: SdoPos, // TODO: do we need this info here?
174    pub idx: Idx,
175    pub max_sub_idx: SubIdx,
176    pub object_code: Option<u8>,
177    pub name: String,
178}
179
180/// SDO Entry Information
181#[derive(Debug, Clone, PartialEq)]
182pub struct SdoEntryInfo {
183    pub data_type: DataType,
184    pub bit_len: u16,
185    pub access: SdoEntryAccess,
186    pub description: String,
187}
188
189/// SDO Entry Address
190#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
191pub enum SdoEntryAddr {
192    ByPos(SdoPos, SubIdx),
193    ByIdx(SdoIdx),
194}
195
196/// SDO Entry Access
197#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
198pub struct SdoEntryAccess {
199    pub pre_op: Access,
200    pub safe_op: Access,
201    pub op: Access,
202}
203
204/// PDO Index
205#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
206pub struct PdoIdx(u16);
207
208impl PdoIdx {
209    pub const fn new(idx: u16) -> Self {
210        Self(idx)
211    }
212}
213
214impl From<u16> for PdoIdx {
215    fn from(idx: u16) -> Self {
216        Self(idx)
217    }
218}
219
220/// PDO Meta Information
221#[derive(Debug, Clone, PartialEq)]
222pub struct PdoInfo {
223    pub sm: SmIdx,
224    pub pos: PdoPos,
225    pub idx: Idx,
226    pub entry_count: u8,
227    pub name: String,
228}
229
230/// PDO Entry Meta Information
231#[derive(Debug, Clone, PartialEq)]
232pub struct PdoEntryInfo {
233    pub pos: PdoEntryPos,
234    pub entry_idx: PdoEntryIdx,
235    pub bit_len: u8,
236    pub name: String,
237}
238
239impl From<PdoIdx> for u16 {
240    fn from(idx: PdoIdx) -> Self {
241        idx.0
242    }
243}
244
245/// PDO Entry Index
246#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
247pub struct PdoEntryIdx {
248    pub idx: Idx,
249    pub sub_idx: SubIdx,
250}
251
252impl PdoEntryIdx {
253    pub const fn new(idx: u16, sub: u8) -> Self {
254        Self {
255            idx: Idx::new(idx),
256            sub_idx: SubIdx::new(sub),
257        }
258    }
259}
260
261/// Domain Index
262#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
263pub struct DomainIdx(usize);
264
265impl DomainIdx {
266    pub const fn new(idx: usize) -> Self {
267        Self(idx)
268    }
269}
270
271impl From<usize> for DomainIdx {
272    fn from(idx: usize) -> Self {
273        Self(idx)
274    }
275}
276
277impl From<DomainIdx> for usize {
278    fn from(idx: DomainIdx) -> Self {
279        idx.0
280    }
281}
282
283impl TryFrom<DomainIdx> for u32 {
284    type Error = TryFromIntError;
285    fn try_from(idx: DomainIdx) -> Result<Self, Self::Error> {
286        u32::try_from(idx.0)
287    }
288}
289
290impl TryFrom<DomainIdx> for u64 {
291    type Error = TryFromIntError;
292    fn try_from(idx: DomainIdx) -> Result<Self, Self::Error> {
293        u64::try_from(idx.0)
294    }
295}
296
297/// Sync Master Index
298#[derive(Debug, Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)]
299pub struct SmIdx(u8);
300
301impl SmIdx {
302    pub const fn new(idx: u8) -> Self {
303        Self(idx)
304    }
305}
306
307impl From<u8> for SmIdx {
308    fn from(idx: u8) -> Self {
309        Self(idx)
310    }
311}
312
313impl From<SmIdx> for u8 {
314    fn from(idx: SmIdx) -> Self {
315        idx.0
316    }
317}
318
319/// Data Access Type
320#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
321pub enum Access {
322    /// Read only
323    ReadOnly,
324    /// Read write
325    ReadWrite,
326    /// Write only
327    WriteOnly,
328    /// Unknown access
329    Unknown,
330}
331
332/// Data Type
333#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, FromPrimitive)]
334pub enum DataType {
335    /// BIT
336    Bool = 0x001,
337    /// BYTE
338    Byte = 0x01E,
339
340    /// SINT
341    I8 = 0x0002,
342    /// INT
343    I16 = 0x0003,
344    /// DINT
345    I32 = 0x0004,
346    /// LINT
347    I64 = 0x0015,
348
349    /// USINT
350    U8 = 0x0005,
351    /// UINT
352    U16 = 0x0006,
353    /// UDINT
354    U32 = 0x0007,
355    /// ULINT
356    U64 = 0x001B,
357
358    /// REAL
359    F32 = 0x0008,
360    /// LREAL
361    F64 = 0x0011,
362
363    /// STRING(n) a.k.a. visiable string
364    String = 0x0009,
365
366    /// ARRAY of BYTE a.k.a. Octet String
367    U8Array = 0x000A,
368
369    /// ARRAY of UINT a.k.a. Unicode String
370    U16Array = 0x000B,
371
372    I24 = 0x0010,
373    I40 = 0x0012,
374    I48 = 0x0013,
375    I56 = 0x0014,
376
377    U24 = 0x0016,
378    U40 = 0x0018,
379    U48 = 0x0019,
380    U56 = 0x001A,
381
382    /// BIT 1
383    Bit1 = 0x0030,
384    /// BIT 2
385    Bit2 = 0x0031,
386    /// BIT 3
387    Bit3 = 0x0032,
388    /// BIT 4
389    Bit4 = 0x0033,
390    /// BIT 5
391    Bit5 = 0x0034,
392    /// BIT 6
393    Bit6 = 0x0035,
394    /// BIT 7
395    Bit7 = 0x0036,
396    /// BIT 8
397    Bit8 = 0x0037,
398
399    /// Time of Day
400    TimeOfDay = 0x000C,
401    /// Time Difference
402    TimeDifference = 0x000D,
403
404    /// Domain
405    Domain = 0x000F,
406
407    Raw = 0xFFFF,
408}
409
410/// Offset of a PDO entry in the domain image.
411#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
412pub struct Offset {
413    pub byte: usize,
414    pub bit: u32,
415}
416
417/// ESM states
418#[derive(Debug, Clone, Copy, PartialEq)]
419pub enum AlState {
420    Boot = 0x3,
421    Init = 0x1,
422    PreOp = 0x2,
423    SafeOp = 0x4,
424    Op = 0x8,
425}
426
427#[derive(Debug)]
428pub struct InvalidAlStateError;
429
430impl TryFrom<u8> for AlState {
431    type Error = InvalidAlStateError;
432    fn try_from(st: u8) -> Result<Self, Self::Error> {
433        match st {
434            1 => Ok(AlState::Init),
435            2 => Ok(AlState::PreOp),
436            3 => Ok(AlState::Boot),
437            4 => Ok(AlState::SafeOp),
438            8 => Ok(AlState::Op),
439            _ => Err(InvalidAlStateError),
440        }
441    }
442}
443
444impl From<AlState> for u8 {
445    fn from(st: AlState) -> Self {
446        st as u8
447    }
448}
449
450/// Sync Master Type
451#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
452pub enum SmType {
453    /// Unused
454    Unused = 0,
455    /// Mailbox Write
456    MbxWr = 1,
457    /// Mailbox Read
458    MbxRd = 2,
459    /// Outputs
460    Outputs = 3,
461    /// Inputs
462    Inputs = 4,
463}
464
465#[derive(Debug)]
466pub struct InvalidSmTypeError;
467
468impl TryFrom<u8> for SmType {
469    type Error = InvalidSmTypeError;
470    fn try_from(st: u8) -> Result<Self, Self::Error> {
471        match st {
472            0 => Ok(SmType::Unused),
473            1 => Ok(SmType::MbxWr),
474            2 => Ok(SmType::MbxRd),
475            3 => Ok(SmType::Outputs),
476            4 => Ok(SmType::Inputs),
477            _ => Err(InvalidSmTypeError),
478        }
479    }
480}
481
482impl From<SmType> for u8 {
483    fn from(st: SmType) -> Self {
484        st as u8
485    }
486}
487
488#[cfg(test)]
489mod tests {
490    use super::*;
491
492    #[test]
493    fn u8_from_al_state() {
494        assert_eq!(u8::from(AlState::Init), 1);
495        assert_eq!(u8::from(AlState::PreOp), 2);
496        assert_eq!(u8::from(AlState::Boot), 3);
497        assert_eq!(u8::from(AlState::SafeOp), 4);
498        assert_eq!(u8::from(AlState::Op), 8);
499    }
500
501    #[test]
502    fn try_al_state_from_u8() {
503        assert_eq!(AlState::try_from(1).unwrap(), AlState::Init);
504        assert_eq!(AlState::try_from(2).unwrap(), AlState::PreOp);
505        assert_eq!(AlState::try_from(3).unwrap(), AlState::Boot);
506        assert_eq!(AlState::try_from(4).unwrap(), AlState::SafeOp);
507        assert_eq!(AlState::try_from(8).unwrap(), AlState::Op);
508        assert!(AlState::try_from(0).is_err());
509        assert!(AlState::try_from(5).is_err());
510        assert!(AlState::try_from(6).is_err());
511        assert!(AlState::try_from(7).is_err());
512    }
513
514    #[test]
515    fn try_sm_type_from_u8() {
516        assert_eq!(SmType::try_from(0).unwrap(), SmType::Unused);
517        assert_eq!(SmType::try_from(1).unwrap(), SmType::MbxWr);
518        assert_eq!(SmType::try_from(2).unwrap(), SmType::MbxRd);
519        assert_eq!(SmType::try_from(3).unwrap(), SmType::Outputs);
520        assert_eq!(SmType::try_from(4).unwrap(), SmType::Inputs);
521        assert!(AlState::try_from(5).is_err());
522    }
523
524    #[test]
525    fn u8_from_sm_type() {
526        assert_eq!(u8::from(SmType::Unused), 0);
527        assert_eq!(u8::from(SmType::MbxWr), 1);
528        assert_eq!(u8::from(SmType::MbxRd), 2);
529        assert_eq!(u8::from(SmType::Outputs), 3);
530        assert_eq!(u8::from(SmType::Inputs), 4);
531    }
532
533    #[test]
534    fn debug_idx() {
535        assert_eq!(format!("{:?}", Idx::new(0)), "Idx(0x0000)");
536        assert_eq!(format!("{:?}", Idx::new(u16::MAX)), "Idx(0xFFFF)");
537    }
538}