oze_canopen/
message_parsed.rs

1use crate::{
2    canopen::{NodeId, RxMessage},
3    proto::CobId,
4};
5
6/// Enumeration representing the type of a received CANopen message.
7///
8/// This enum is used to classify the different types of CANopen messages that can be received.
9/// Each variant corresponds to a specific type of CANopen message, as indicated by the COB-ID
10/// (Communication Object Identifier).
11#[derive(Clone, Debug, Copy, PartialEq, Eq)]
12pub enum RxMessageType {
13    /// Service Data Object Transmit (SDO Tx)
14    ///
15    /// Represents an SDO message sent from the server (node) to the client.
16    SdoTx,
17
18    /// Service Data Object Receive (SDO Rx)
19    ///
20    /// Represents an SDO message sent from the client to the server (node).
21    SdoRx,
22
23    /// Process Data Object (PDO)
24    ///
25    /// Represents any PDO message or Timestamp with COB-ID in the range 0x100 to 0x57F.
26    Pdo,
27
28    /// Synchronization (SYNC)
29    ///
30    /// Represents a SYNC message with COB-ID 0x80.
31    Sync,
32
33    /// Network Management (NMT)
34    ///
35    /// Represents an NMT message.
36    Nmt,
37
38    /// Layer Setting Services (LSS)
39    ///
40    /// Represents an LSS message.
41    Lss,
42
43    /// Node Guarding
44    ///
45    /// Represents a Node Guarding message.
46    Guarding,
47
48    /// Emergency (EMCY)
49    ///
50    /// Represents an EMCY message.
51    Emcy,
52
53    /// Unknown Message Type
54    ///
55    /// Represents a message type that could not be determined.
56    Unknown,
57}
58
59/// Struct representing a parsed received CANopen message, including its type and optional node ID.
60#[derive(Clone, Debug, Copy)]
61pub struct RxMessageParsed {
62    /// The parsed type of the received message.
63    pub parsed_type: RxMessageType,
64    /// The parsed node ID from the message, if applicable.
65    pub parsed_node_id: Option<NodeId>,
66    /// The original received message.
67    pub msg: RxMessage,
68}
69
70impl RxMessageParsed {
71    /// Creates a new `RxMessageParsed` instance by parsing the given received message.
72    ///
73    /// # Arguments
74    ///
75    /// * `msg` - The received CANopen message to be parsed.
76    ///
77    /// # Returns
78    ///
79    /// A new `RxMessageParsed` instance with the parsed type and node ID.
80    ///
81    /// # Examples
82    ///
83    /// ```
84    /// use oze_canopen::RxMessageParsed;
85    ///
86    /// let rx_message = RxMessage { /* fields */ };
87    /// let parsed_message = RxMessageParsed::new(rx_message);
88    /// ```
89    pub fn new(msg: RxMessage) -> Self {
90        Self {
91            parsed_type: Self::parse_type(msg.cob_id),
92            parsed_node_id: Self::parse_node_id(msg.cob_id),
93            msg,
94        }
95    }
96
97    /// Parses the type of a received message based on its COB ID.
98    ///
99    /// # Arguments
100    ///
101    /// * `cob_id` - The COB ID of the received message.
102    ///
103    /// # Returns
104    ///
105    /// The parsed type of the message as an `RxMessageType`.
106    ///
107    /// # Examples
108    ///
109    /// ```
110    /// use oze_canopen::RxMessageParsed;
111    ///
112    /// let message_type = RxMessageParsed::parse_type(0x580);
113    /// assert_eq!(message_type, RxMessageType::SdoTx);
114    /// ```
115    pub fn parse_type(cob_id: CobId) -> RxMessageType {
116        match cob_id {
117            0x0..=0x7F => RxMessageType::Nmt,
118            0x80 => RxMessageType::Sync,
119            0x100..=0x57F => RxMessageType::Pdo,
120            0x580..=0x5FF => RxMessageType::SdoTx,
121            0x600..=0x67F => RxMessageType::SdoRx,
122            0x81..=0xFF => RxMessageType::Emcy,
123            0x680..=0x6FF => RxMessageType::Unknown,
124            0x700..=0x77F => RxMessageType::Guarding,
125            0x780..=0x7FF => RxMessageType::Lss,
126            0x800.. => RxMessageType::Unknown,
127        }
128    }
129
130    /// Parses the node ID from a received message based on its COB ID.
131    ///
132    /// # Arguments
133    ///
134    /// * `cob_id` - The COB ID of the received message.
135    ///
136    /// # Returns
137    ///
138    /// The parsed node ID as an `Option<NodeId>`.
139    ///
140    /// # Examples
141    ///
142    /// ```
143    /// use oze_canopen::RxMessageParsed;
144    ///
145    /// let node_id = RxMessageParsed::parse_node_id(0x580);
146    /// assert_eq!(node_id, Some(0x0));
147    /// ```
148    pub fn parse_node_id(cob_id: CobId) -> Option<NodeId> {
149        match cob_id {
150            0x00..=0x80 => None,                                 // NMT, SYNC
151            0x81..=0xFF => NodeId::try_from(cob_id - 0x80).ok(), // EMCY
152            0x100..=0x57F => {
153                let mut node_id = cob_id;
154                while node_id >= 0x80 {
155                    node_id -= 0x80;
156                }
157                NodeId::try_from(node_id).ok()
158            } // PDO
159            0x580..=0x5FF => NodeId::try_from(cob_id - 0x580).ok(), // SDO Transmit
160            0x600..=0x67F => NodeId::try_from(cob_id - 0x600).ok(), // SDO Receive
161            0x680..=0x6FF => None,                               // ???
162            0x700..=0x77F => NodeId::try_from(cob_id - 0x700).ok(), // Node Guarding
163            0x780..=0x7FF => None,                               // Lss
164            0x800.. => None,                                     // not possible ???
165        }
166    }
167}
168
169impl RxMessageType {
170    pub fn to_string(&self) -> &str {
171        match &self {
172            RxMessageType::SdoTx => "↓SDO S->C",
173            RxMessageType::SdoRx => "↑SDO C->S",
174            RxMessageType::Pdo => "PDO",
175            RxMessageType::Sync => "SYNC",
176            RxMessageType::Nmt => "NMT",
177            RxMessageType::Unknown => "?",
178            RxMessageType::Emcy => "EMCY",
179            RxMessageType::Guarding => "Guard",
180            RxMessageType::Lss => "LSS",
181        }
182    }
183}