dbc_rs/message/impls.rs
1use super::{Message, Signals};
2use crate::compat::Name;
3
4impl Message {
5 pub(crate) fn new(id: u32, name: Name, dlc: u8, sender: Name, signals: Signals) -> Self {
6 // Validation should have been done prior (by builder or parse)
7 Self {
8 id,
9 name,
10 dlc,
11 sender,
12 signals,
13 }
14 }
15
16 /// Returns the CAN message ID.
17 ///
18 /// This returns the raw CAN ID as it would appear on the bus (11-bit or 29-bit).
19 /// For extended (29-bit) IDs, the internal flag bit is stripped.
20 /// Use [`is_extended()`](Self::is_extended) to check if this is an extended ID.
21 ///
22 /// # Examples
23 ///
24 /// ```rust,no_run
25 /// use dbc_rs::Dbc;
26 ///
27 /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 256 EngineData : 8 ECM"#)?;
28 /// let message = dbc.messages().at(0).unwrap();
29 /// assert_eq!(message.id(), 256);
30 /// # Ok::<(), dbc_rs::Error>(())
31 /// ```
32 #[inline]
33 #[must_use = "return value should be used"]
34 pub fn id(&self) -> u32 {
35 self.id & Self::MAX_EXTENDED_ID
36 }
37
38 /// Returns the raw internal ID including any extended ID flag.
39 ///
40 /// This is primarily for internal use. Most users should use [`id()`](Self::id) instead.
41 #[inline]
42 #[must_use = "return value should be used"]
43 pub(crate) fn id_with_flag(&self) -> u32 {
44 self.id
45 }
46
47 /// Returns `true` if this message uses an extended (29-bit) CAN ID.
48 ///
49 /// Standard CAN uses 11-bit identifiers (0-2047), while extended CAN uses 29-bit
50 /// identifiers (0-536870911).
51 ///
52 /// # Examples
53 ///
54 /// ```rust,no_run
55 /// use dbc_rs::Dbc;
56 ///
57 /// // Standard 11-bit ID
58 /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 256 EngineData : 8 ECM"#)?;
59 /// let message = dbc.messages().at(0).unwrap();
60 /// assert!(!message.is_extended());
61 ///
62 /// // Extended 29-bit ID (with flag bit set: 0x80000000 | 0x18DAF115)
63 /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 2564485397 OBD2 : 8 ECM"#)?;
64 /// let message = dbc.messages().at(0).unwrap();
65 /// assert!(message.is_extended());
66 /// assert_eq!(message.id(), 0x18DAF115);
67 /// # Ok::<(), dbc_rs::Error>(())
68 /// ```
69 #[inline]
70 #[must_use = "return value should be used"]
71 pub fn is_extended(&self) -> bool {
72 (self.id & Self::EXTENDED_ID_FLAG) != 0
73 }
74
75 /// Returns the message name.
76 ///
77 /// # Examples
78 ///
79 /// ```rust,no_run
80 /// use dbc_rs::Dbc;
81 ///
82 /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 256 EngineData : 8 ECM"#)?;
83 /// let message = dbc.messages().at(0).unwrap();
84 /// assert_eq!(message.name(), "EngineData");
85 /// # Ok::<(), dbc_rs::Error>(())
86 /// ```
87 #[inline]
88 #[must_use = "return value should be used"]
89 pub fn name(&self) -> &str {
90 self.name.as_str()
91 }
92
93 /// Returns the Data Length Code (DLC) in bytes.
94 ///
95 /// DLC specifies the size of the message payload. For classic CAN, this is 1-8 bytes.
96 /// For CAN FD, this can be up to 64 bytes.
97 ///
98 /// # Examples
99 ///
100 /// ```rust,no_run
101 /// use dbc_rs::Dbc;
102 ///
103 /// let dbc = Dbc::parse(r#"VERSION "1.0"\n\nBU_: ECM\n\nBO_ 256 EngineData : 8 ECM"#)?;
104 /// let message = dbc.messages().at(0).unwrap();
105 /// assert_eq!(message.dlc(), 8);
106 /// # Ok::<(), dbc_rs::Error>(())
107 /// ```
108 #[inline]
109 #[must_use = "return value should be used"]
110 pub fn dlc(&self) -> u8 {
111 self.dlc
112 }
113
114 /// Get the sender node name for this message.
115 ///
116 /// The sender is the node that transmits this message on the CAN bus.
117 ///
118 /// # Examples
119 ///
120 /// ```rust,no_run
121 /// use dbc_rs::Dbc;
122 ///
123 /// let dbc = Dbc::parse(r#"VERSION "1.0"
124 ///
125 /// BU_: ECM TCM
126 ///
127 /// BO_ 256 Engine : 8 ECM
128 /// SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" *
129 /// "#)?;
130 ///
131 /// let message = dbc.messages().iter().next().unwrap();
132 /// assert_eq!(message.sender(), "ECM");
133 /// # Ok::<(), dbc_rs::Error>(())
134 /// ```
135 #[inline]
136 #[must_use = "return value should be used"]
137 pub fn sender(&self) -> &str {
138 self.sender.as_str()
139 }
140
141 /// Returns a reference to the signals collection for this message.
142 ///
143 /// The [`Signals`] collection provides methods to iterate, search, and access signals by index.
144 ///
145 /// # Examples
146 ///
147 /// ```rust,no_run
148 /// use dbc_rs::Dbc;
149 ///
150 /// let dbc = Dbc::parse(r#"VERSION "1.0"
151 ///
152 /// BU_: ECM
153 ///
154 /// BO_ 256 Engine : 8 ECM
155 /// SG_ RPM : 0|16@1+ (0.25,0) [0|8000] "rpm" ECM
156 /// SG_ Torque : 16|16@1+ (0.1,0) [0|500] "Nm" ECM
157 /// "#)?;
158 ///
159 /// let message = dbc.messages().find("Engine").unwrap();
160 /// let signals = message.signals();
161 /// assert_eq!(signals.len(), 2);
162 /// assert!(signals.find("RPM").is_some());
163 /// # Ok::<(), dbc_rs::Error>(())
164 /// ```
165 #[inline]
166 #[must_use = "return value should be used"]
167 pub fn signals(&self) -> &Signals {
168 &self.signals
169 }
170}
171
172#[cfg(test)]
173mod tests {
174 use super::*;
175 use crate::{Parser, Signal};
176
177 #[test]
178 fn test_message_getters_edge_cases() {
179 // Test with minimum values
180 let data = b"BO_ 0 A : 1 B";
181 let mut parser = Parser::new(data).unwrap();
182 let signals: &[Signal] = &[];
183 let message = Message::parse(&mut parser, signals).unwrap();
184
185 assert_eq!(message.id(), 0);
186 assert_eq!(message.name(), "A");
187 assert_eq!(message.dlc(), 1);
188 assert_eq!(message.sender(), "B");
189 }
190}