can_aerospace_lite/types/
mod.rs

1//! # CANAerospace - Types
2//!
3//! All required types to implement CANAerospace protocol is defined in this module.
4
5use core::convert::TryInto;
6
7use crate::message::RawMessage;
8
9pub type MessageCode = u8;
10pub type ServiceCode = u8;
11pub type NodeId = u8;
12pub type IDSHeaderConfiguration = u8;
13
14#[derive(Clone, Copy, Debug)]
15pub struct IDSConfiguration(pub u8);
16
17#[derive(Clone, Copy, Debug)]
18pub struct HardwareRevision(pub u8);
19
20#[derive(Clone, Copy, Debug)]
21pub struct SoftwareRevision(pub u8);
22
23#[derive(Clone, Copy, Debug)]
24pub struct IDSResponse {
25    pub hw_rev: HardwareRevision,
26    pub sw_rev: SoftwareRevision,
27    pub configuration: IDSConfiguration,
28    pub header: IDSHeaderConfiguration,
29}
30
31#[derive(Clone, Copy, Debug, PartialEq)]
32pub enum ServiceCodeEnum {
33    /// Identification Service (0x0)
34    IDS,
35    /// Node Synchronisation Service (0x1)
36    NSS,
37    /// Data Download Service (0x2)
38    DDS,
39    /// Data Upload Service (0x3)
40    DUS,
41    /// Simulation Control Service (0x4)
42    SCS,
43    /// Transmission Interval Service (0x5)
44    TIS,
45    /// FLASH Programming Service (0x6)
46    FPS,
47    /// State Transmission Service (0x7)
48    STS,
49    /// Filter Setting Service (0x8)
50    FSS,
51    /// Test Control Service (0x9)
52    TCS,
53    /// CAN Baudrate Setting Service (0xA)
54    BSS,
55    /// NodeId Setting Service (0xB)
56    NIS,
57    /// Module Information Service (0xC)
58    MIS,
59    /// Module Configuration Service (0xD)
60    MCS,
61    /// CAN ID Setting Service (0xE)
62    CSS,
63    /// CAN ID Distribution Setting Service (0xF)
64    DSS,
65    /// User-Defined Service Code \[100, 254\]
66    CUSTOM(u8),
67    UNKNOWN,
68}
69
70impl ServiceCodeEnum {
71    /// Converts [ServiceCodeEnum] to u8
72    ///```
73    /// # use can_aerospace_lite::types::ServiceCodeEnum;
74    /// let mut custom_service = ServiceCodeEnum::CUSTOM(100);
75    /// assert_eq!(custom_service.as_u8(), 100);
76    /// custom_service = ServiceCodeEnum::UNKNOWN;
77    /// assert_eq!(custom_service.as_u8(), 0xFF);
78    /// custom_service = ServiceCodeEnum::IDS;
79    /// assert_eq!(custom_service.as_u8(), 0x0);
80    ///```
81    pub fn as_u8(&self) -> u8 {
82        u8::from(*self)
83    }
84}
85
86impl From<ServiceCodeEnum> for u8 {
87    /// Converts [ServiceCodeEnum] to u8
88    ///
89    ///```
90    /// # use can_aerospace_lite::types::ServiceCodeEnum;
91    /// let mut custom_service = ServiceCodeEnum::CUSTOM(100);
92    /// assert_eq!(u8::from(custom_service), 100);
93    /// custom_service = ServiceCodeEnum::UNKNOWN;
94    /// assert_eq!(u8::from(custom_service), 0xFF);
95    ///```
96    fn from(code: ServiceCodeEnum) -> Self {
97        match code {
98            ServiceCodeEnum::IDS => 0,
99            ServiceCodeEnum::NSS => 1,
100            ServiceCodeEnum::DDS => 2,
101            ServiceCodeEnum::DUS => 3,
102            ServiceCodeEnum::SCS => 4,
103            ServiceCodeEnum::TIS => 5,
104            ServiceCodeEnum::FPS => 6,
105            ServiceCodeEnum::STS => 7,
106            ServiceCodeEnum::FSS => 8,
107            ServiceCodeEnum::TCS => 9,
108            ServiceCodeEnum::BSS => 10,
109            ServiceCodeEnum::NIS => 11,
110            ServiceCodeEnum::MIS => 12,
111            ServiceCodeEnum::MCS => 13,
112            ServiceCodeEnum::CSS => 14,
113            ServiceCodeEnum::DSS => 15,
114            ServiceCodeEnum::UNKNOWN => 0xFF,
115            ServiceCodeEnum::CUSTOM(id) => id,
116        }
117    }
118}
119
120impl From<u8> for ServiceCodeEnum {
121    fn from(code: u8) -> Self {
122        match code {
123            code if code == ServiceCodeEnum::IDS.as_u8() => ServiceCodeEnum::IDS,
124            code if code == ServiceCodeEnum::NSS.as_u8() => ServiceCodeEnum::NSS,
125            code if code == ServiceCodeEnum::DDS.as_u8() => ServiceCodeEnum::DDS,
126            code if code == ServiceCodeEnum::DUS.as_u8() => ServiceCodeEnum::DUS,
127            code if code == ServiceCodeEnum::SCS.as_u8() => ServiceCodeEnum::SCS,
128            code if code == ServiceCodeEnum::TIS.as_u8() => ServiceCodeEnum::TIS,
129            code if code == ServiceCodeEnum::FPS.as_u8() => ServiceCodeEnum::FPS,
130            code if code == ServiceCodeEnum::STS.as_u8() => ServiceCodeEnum::STS,
131            code if code == ServiceCodeEnum::FSS.as_u8() => ServiceCodeEnum::FSS,
132            code if code == ServiceCodeEnum::TCS.as_u8() => ServiceCodeEnum::TCS,
133            code if code == ServiceCodeEnum::BSS.as_u8() => ServiceCodeEnum::BSS,
134            code if code == ServiceCodeEnum::NIS.as_u8() => ServiceCodeEnum::NIS,
135            code if code == ServiceCodeEnum::MIS.as_u8() => ServiceCodeEnum::MIS,
136            code if code == ServiceCodeEnum::MCS.as_u8() => ServiceCodeEnum::MCS,
137            code if code == ServiceCodeEnum::CSS.as_u8() => ServiceCodeEnum::CSS,
138            code if code == ServiceCodeEnum::DSS.as_u8() => ServiceCodeEnum::DSS,
139            code if (100..=254).contains(&code) => ServiceCodeEnum::CUSTOM(code),
140            _ => ServiceCodeEnum::UNKNOWN,
141        }
142    }
143}
144
145#[derive(Clone, Copy, Debug, PartialEq)]
146pub enum MessageType {
147    /// Emergency Event Data \[0,127\]
148    /// Transmitted asynchronously whenever a situation requiring immediate action occurs.
149    EED(u16),
150    /// High Priority Node Service Data \[128,199\]
151    /// Transmitted asynchronously or cyclic with defined transmission intervals for operational commands (36 channels)
152    NSH(u16),
153    /// High Priority User-Defined Data \[200,299\]
154    /// Message/data format and transmission intervals entirely user-defined
155    UDH(u16),
156    /// Normal Operation Data \[300,1799\]
157    /// Transmitted asynchronously or cyclic with defined transmission intervals for operational and status data.
158    NOD(u16),
159    /// Low Priority User-Defined Data \[1800,1899\]
160    /// Message/data format and transmission intervals entirely user-defined
161    UDL(u16),
162    /// Debug Service Data \[1900,1999\]
163    /// Transmitted asynchronously or cyclic for debug communication & software download actions.
164    DSD(u16),
165    /// Low Priority Node Service Data \[2000,2031\]
166    /// Transmitted asynchronously or cyclic for test & maintenance actions (16 channels).
167    NSL(u16),
168    INVALID,
169}
170
171impl MessageType {
172    pub fn id(&self) -> u16 {
173        match *self {
174            MessageType::EED(id) => {
175                if id > 0x7F {
176                    panic!("CANaerospace: Invalid Message ID({}) for EED Message.", id);
177                }
178                id
179            }
180            MessageType::NSH(id) => {
181                if !(0x80..=0xC7).contains(&id) {
182                    panic!("CANaerospace: Invalid Message ID({}) for NSH Message.", id);
183                }
184                id
185            }
186            MessageType::UDH(id) => {
187                if !(0xC8..=0x12B).contains(&id) {
188                    panic!("CANaerospace: Invalid Message ID({}) for UDH Message.", id);
189                }
190                id
191            }
192            MessageType::NOD(id) => {
193                if !(0x12C..=0x707).contains(&id) {
194                    panic!("CANaerospace: Invalid Message ID({}) for NOD Message.", id);
195                }
196                id
197            }
198            MessageType::UDL(id) => {
199                if !(0x708..=0x76B).contains(&id) {
200                    panic!("CANaerospace: Invalid Message ID({}) for UDL Message.", id);
201                }
202                id
203            }
204            MessageType::DSD(id) => {
205                if !(0x76C..=0x7CF).contains(&id) {
206                    panic!("CANaerospace: Invalid Message ID({}) for DSD Message.", id);
207                }
208                id
209            }
210            MessageType::NSL(id) => {
211                if !(0x7D0..=0x7EF).contains(&id) {
212                    panic!("CANaerospace: Invalid Message ID({}) for NSL Message.", id);
213                }
214                id
215            }
216            MessageType::INVALID => u16::MAX,
217        }
218    }
219}
220
221impl From<u16> for MessageType {
222    fn from(raw_id: u16) -> Self {
223        match raw_id {
224            0..=127 => MessageType::EED(raw_id),
225            128..=199 => MessageType::NSH(raw_id),
226            200..=299 => MessageType::UDH(raw_id),
227            300..=1799 => MessageType::NOD(raw_id),
228            1800..=1899 => MessageType::UDL(raw_id),
229            1900..=1999 => MessageType::DSD(raw_id),
230            2000..=2031 => MessageType::NSL(raw_id),
231            _ => MessageType::INVALID,
232        }
233    }
234}
235
236#[derive(Clone, Copy, Debug, PartialEq)]
237pub enum DataType {
238    NODATA,
239    ERROR(u32),
240    FLOAT(f32),
241    LONG(i32),
242    ULONG(u32),
243    BLONG(u32),
244    SHORT(i16),
245    USHORT(u16),
246    BSHORT(u16),
247    CHAR(i8),
248    UCHAR(u8),
249    BCHAR(u8),
250    SHORT2(i16, i16),
251    USHORT2(u16, u16),
252    BSHORT2(u16, u16),
253    CHAR4(i8, i8, i8, i8),
254    UCHAR4(u8, u8, u8, u8),
255    BCHAR4(u8, u8, u8, u8),
256    CHAR2(i8, i8),
257    UCHAR2(u8, u8),
258    BCHAR2(u8, u8),
259    MEMID(u32),
260    CHKSUM(u32),
261    ACHAR(u8),
262    ACHAR2(u8, u8),
263    ACHAR4(u8, u8, u8, u8),
264    CHAR3(i8, i8, i8),
265    UCHAR3(u8, u8, u8),
266    BCHAR3(u8, u8, u8),
267    ACHAR3(u8, u8, u8),
268    DOUBLEH(u32),
269    DOUBLEL(u32),
270    RESVD(u32),
271    UDEF { value: u32, type_id: u8 },
272}
273
274impl DataType {
275    pub fn type_id(&self) -> u8 {
276        match *self {
277            DataType::NODATA => 0x0,
278            DataType::ERROR(_) => 0x1,
279            DataType::FLOAT(_) => 0x2,
280            DataType::LONG(_) => 0x3,
281            DataType::ULONG(_) => 0x4,
282            DataType::BLONG(_) => 0x5,
283            DataType::SHORT(_) => 0x6,
284            DataType::USHORT(_) => 0x7,
285            DataType::BSHORT(_) => 0x8,
286            DataType::CHAR(_) => 0x9,
287            DataType::UCHAR(_) => 0xA,
288            DataType::BCHAR(_) => 0xB,
289            DataType::SHORT2(_, _) => 0xC,
290            DataType::USHORT2(_, _) => 0xD,
291            DataType::BSHORT2(_, _) => 0xE,
292            DataType::CHAR4(_, _, _, _) => 0xF,
293            DataType::UCHAR4(_, _, _, _) => 0x10,
294            DataType::BCHAR4(_, _, _, _) => 0x11,
295            DataType::CHAR2(_, _) => 0x12,
296            DataType::UCHAR2(_, _) => 0x13,
297            DataType::BCHAR2(_, _) => 0x14,
298            DataType::MEMID(_) => 0x15,
299            DataType::CHKSUM(_) => 0x16,
300            DataType::ACHAR(_) => 0x17,
301            DataType::ACHAR2(_, _) => 0x18,
302            DataType::ACHAR4(_, _, _, _) => 0x19,
303            DataType::CHAR3(_, _, _) => 0x1A,
304            DataType::UCHAR3(_, _, _) => 0x1B,
305            DataType::BCHAR3(_, _, _) => 0x1C,
306            DataType::ACHAR3(_, _, _) => 0x1D,
307            DataType::DOUBLEH(_) => 0x1E,
308            DataType::DOUBLEL(_) => 0x1F,
309            DataType::RESVD(_) => 0x20,
310            DataType::UDEF { value: _, type_id } => type_id,
311        }
312    }
313
314    pub fn is_empty(&self) -> bool {
315        *self == DataType::NODATA
316    }
317
318    pub fn len(&self) -> u8 {
319        match *self {
320            DataType::NODATA | DataType::RESVD(_) => 0,
321
322            DataType::ERROR(_)
323            | DataType::FLOAT(_)
324            | DataType::LONG(_)
325            | DataType::ULONG(_)
326            | DataType::BLONG(_)
327            | DataType::SHORT2(_, _)
328            | DataType::USHORT2(_, _)
329            | DataType::BSHORT2(_, _)
330            | DataType::CHAR4(_, _, _, _)
331            | DataType::UCHAR4(_, _, _, _)
332            | DataType::BCHAR4(_, _, _, _)
333            | DataType::MEMID(_)
334            | DataType::CHKSUM(_)
335            | DataType::ACHAR4(_, _, _, _)
336            | DataType::DOUBLEH(_)
337            | DataType::DOUBLEL(_) => 4,
338
339            DataType::SHORT(_)
340            | DataType::USHORT(_)
341            | DataType::BSHORT(_)
342            | DataType::CHAR2(_, _)
343            | DataType::UCHAR2(_, _)
344            | DataType::BCHAR2(_, _)
345            | DataType::ACHAR2(_, _) => 2,
346
347            DataType::CHAR(_) | DataType::UCHAR(_) | DataType::BCHAR(_) | DataType::ACHAR(_) => 1,
348
349            DataType::CHAR3(_, _, _)
350            | DataType::UCHAR3(_, _, _)
351            | DataType::BCHAR3(_, _, _)
352            | DataType::ACHAR3(_, _, _) => 3,
353
354            DataType::UDEF {
355                value: _,
356                type_id: _,
357            } => 4,
358        }
359    }
360
361    pub fn to_be_bytes(self) -> [u8; 4] {
362        match self {
363            DataType::NODATA => [0, 0, 0, 0],
364            DataType::ERROR(d) => d.to_be_bytes(),
365            DataType::FLOAT(d) => d.to_be_bytes(),
366            DataType::LONG(d) => d.to_be_bytes(),
367            DataType::ULONG(d) => d.to_be_bytes(),
368            DataType::BLONG(d) => d.to_be_bytes(),
369            DataType::SHORT(d) => {
370                let d_bytes = d.to_be_bytes();
371                [d_bytes[0], d_bytes[1], 0, 0]
372            }
373            DataType::USHORT(d) | DataType::BSHORT(d) => {
374                let d_bytes = d.to_be_bytes();
375                [d_bytes[0], d_bytes[1], 0, 0]
376            }
377            DataType::CHAR(d) => [d as u8, 0, 0, 0],
378            DataType::UCHAR(d) => [d, 0, 0, 0],
379            DataType::BCHAR(d) => [d, 0, 0, 0],
380            DataType::SHORT2(a, b) => {
381                let a_bytes = a.to_be_bytes();
382                let b_bytes = b.to_be_bytes();
383                [a_bytes[0], a_bytes[1], b_bytes[0], b_bytes[1]]
384            }
385            DataType::USHORT2(a, b) => {
386                let a_bytes = a.to_be_bytes();
387                let b_bytes = b.to_be_bytes();
388                [a_bytes[0], a_bytes[1], b_bytes[0], b_bytes[1]]
389            }
390            DataType::BSHORT2(a, b) => {
391                let a_bytes = a.to_be_bytes();
392                let b_bytes = b.to_be_bytes();
393                [a_bytes[0], a_bytes[1], b_bytes[0], b_bytes[1]]
394            }
395            DataType::CHAR4(a, b, c, d) => [a as u8, b as u8, c as u8, d as u8],
396            DataType::UCHAR4(a, b, c, d) => [a as u8, b as u8, c as u8, d as u8],
397            DataType::BCHAR4(a, b, c, d) => [a as u8, b as u8, c as u8, d as u8],
398            DataType::CHAR2(a, b) => [a as u8, b as u8, 0, 0],
399            DataType::UCHAR2(a, b) => [a as u8, b as u8, 0, 0],
400            DataType::BCHAR2(a, b) => [a as u8, b as u8, 0, 0],
401            DataType::MEMID(d) => d.to_be_bytes(),
402            DataType::CHKSUM(d) => d.to_be_bytes(),
403            DataType::ACHAR(a) => [a, 0, 0, 0],
404            DataType::ACHAR2(a, b) => [a, b, 0, 0],
405            DataType::ACHAR4(a, b, c, d) => [a, b, c, d],
406            DataType::CHAR3(a, b, c) => [a as u8, b as u8, c as u8, 0],
407            DataType::UCHAR3(a, b, c) => [a, b, c, 0],
408            DataType::BCHAR3(a, b, c) => [a, b, c, 0],
409            DataType::ACHAR3(a, b, c) => [a, b, c, 0],
410            DataType::DOUBLEH(d) => d.to_be_bytes(),
411            DataType::DOUBLEL(d) => d.to_be_bytes(),
412            DataType::RESVD(d) => d.to_be_bytes(),
413            DataType::UDEF { value, type_id: _ } => value.to_be_bytes(),
414        }
415    }
416}
417
418fn as_u32(arr: &[u8]) -> u32 {
419    u32::from_be_bytes(arr[..4].try_into().unwrap())
420}
421
422fn as_u16(arr: &[u8]) -> u16 {
423    u16::from_be_bytes(arr[..2].try_into().unwrap())
424}
425
426impl From<(u8, &[u8])> for DataType {
427    fn from(data: (u8, &[u8])) -> Self {
428        let (t, arr) = data;
429        match t {
430            0x0 => DataType::NODATA,
431            0x1 => DataType::ERROR(as_u32(arr)),
432            0x2 => DataType::FLOAT(as_u32(arr) as f32),
433            0x3 => DataType::LONG(as_u32(arr) as i32),
434            0x4 => DataType::ULONG(as_u32(arr)),
435            0x5 => DataType::BLONG(as_u32(arr)),
436            0x6 => DataType::SHORT(as_u16(arr) as i16),
437            0x7 => DataType::USHORT(as_u16(arr)),
438            0x8 => DataType::BSHORT(as_u16(arr)),
439            0x9 => DataType::CHAR(arr[0] as i8),
440            0xA => DataType::UCHAR(arr[0] as u8),
441            0xB => DataType::BCHAR(arr[0] as u8),
442            0xC => DataType::SHORT2(as_u16(arr) as i16, as_u16(&arr[2..]) as i16),
443            0xD => DataType::USHORT2(as_u16(arr), as_u16(arr)),
444            0xE => DataType::BSHORT2(as_u16(arr), as_u16(&arr[2..])),
445            0xF => DataType::CHAR4(arr[0] as i8, arr[1] as i8, arr[2] as i8, arr[3] as i8),
446            0x10 => DataType::UCHAR4(arr[0], arr[1], arr[2], arr[3]),
447            0x11 => DataType::BCHAR4(arr[0], arr[1], arr[2], arr[3]),
448            0x12 => DataType::CHAR2(arr[0] as i8, arr[1] as i8),
449            0x13 => DataType::UCHAR2(arr[0], arr[1]),
450            0x14 => DataType::BCHAR2(arr[0], arr[1]),
451            0x15 => DataType::MEMID(as_u32(arr)),
452            0x16 => DataType::CHKSUM(as_u32(arr)),
453            0x17 => DataType::ACHAR(arr[0]),
454            0x18 => DataType::ACHAR2(arr[0], arr[1]),
455            0x19 => DataType::ACHAR4(arr[0], arr[1], arr[2], arr[3]),
456            0x1A => DataType::CHAR3(arr[0] as i8, arr[1] as i8, arr[2] as i8),
457            0x1B => DataType::UCHAR3(arr[0], arr[1], arr[2]),
458            0x1C => DataType::BCHAR3(arr[0], arr[1], arr[2]),
459            0x1D => DataType::ACHAR3(arr[0], arr[1], arr[2]),
460            0x1E => DataType::DOUBLEH(as_u32(arr)),
461            0x1F => DataType::DOUBLEL(as_u32(arr)),
462            0x20 => DataType::RESVD(as_u32(arr)),
463            _ => DataType::UDEF {
464                value: as_u32(arr),
465                type_id: t,
466            },
467        }
468    }
469}
470
471impl From<&RawMessage> for DataType {
472    fn from(message: &RawMessage) -> Self {
473        DataType::from((message.data_type, &message.payload.data[..]))
474    }
475}