uds_client/uds_client/frame.rs
1use automotive_diag::uds::{UdsCommand, UdsError};
2
3/// Represents errors that can occur while processing UDS frames.
4#[derive(Debug)]
5pub enum FrameError {
6 /// The frame type is not recognized.
7 InvalidFrameType,
8 /// The frame size is invalid or too small.
9 InvalidSize,
10 /// The Service Identifier (SID) is invalid.
11 InvalidSid,
12 /// The Negative Response Code (NRC) is invalid.
13 InvalidNrc,
14 /// The CAN message length is invalid.
15 InvalidCanLength,
16 /// Other unspecified errors.
17 Others,
18}
19
20impl std::fmt::Display for FrameError {
21 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
22 let msg = match self {
23 FrameError::InvalidFrameType => "Invalid UDS frame type.",
24 FrameError::InvalidSize => "Frame size is incorrect.",
25 FrameError::InvalidSid => "Invalid Service Identifier (SID).",
26 FrameError::InvalidNrc => "Invalid Negative Response Code (NRC).",
27 FrameError::InvalidCanLength => "Invalid CAN message length.",
28 FrameError::Others => "An unknown error occurred.",
29 };
30 write!(f, "{}", msg)
31 }
32}
33
34/// UDS frame types:
35/// - Single Frame (SF)
36/// - First Frame (FF)
37/// - Consecutive Frame (CF)
38/// - Flow Control Frame (FC)
39/// - Negative Response Frame (NRC)
40#[derive(Debug, Clone, PartialEq)]
41pub enum UdsFrame {
42 Single(UdsSingleFrame),
43 First(UdsFirstFrame),
44 Consecutive(UdsConsecutiveFrame),
45 FlowControl(UdsFlowControlFrame),
46 NegativeResp(UdsNegativeResponse),
47}
48
49impl UdsFrame {
50 /// verify if the frame is negative response frame.
51 pub fn is_negative_frame(&self) -> bool {
52 matches!(self, UdsFrame::NegativeResp(_frame))
53 }
54
55 /// verify if the frame is single frame.
56 pub fn is_single_frame(&self) -> bool {
57 matches!(self, UdsFrame::Single(_frame))
58 }
59
60 /// verify if the frame is first frame.
61 pub fn is_first_frame(&self) -> bool {
62 matches!(self, UdsFrame::First(_frame))
63 }
64
65 /// verify if the frame is consecutive frame.
66 pub fn is_consecutive_frame(&self) -> bool {
67 matches!(self, UdsFrame::Consecutive(_frame))
68 }
69
70 /// verify if the frame is flow control frame.
71 pub fn is_flow_control_frame(&self) -> bool {
72 matches!(self, UdsFrame::FlowControl(_frame))
73 }
74
75 pub fn to_vec(&self) -> Result<Vec<u8>, FrameError> {
76 match self {
77 UdsFrame::Single(uds_single_frame) => uds_single_frame.to_vec(),
78 UdsFrame::First(uds_first_frame) => uds_first_frame.to_vec(),
79 UdsFrame::Consecutive(uds_consecutive_frame) => uds_consecutive_frame.to_vec(),
80 UdsFrame::FlowControl(uds_flow_control_frame) => uds_flow_control_frame.to_vec(),
81 UdsFrame::NegativeResp(uds_negative_response) => Ok(uds_negative_response.to_vec()),
82 }
83 }
84
85 pub fn from_vec(data: Vec<u8>) -> Result<Self, FrameError> {
86 let frame_type = data
87 .first()
88 .map(|b| b >> 4)
89 .ok_or(FrameError::InvalidCanLength)?;
90
91 match frame_type {
92 0x0 => {
93 // Single Frame
94 let size = data[0] & 0x0F;
95 let sid = *data.get(1).ok_or(FrameError::InvalidSize)?;
96
97 if sid == 0x7F {
98 let rsid = UdsCommand::from_repr(*data.get(2).ok_or(FrameError::InvalidSid)?)
99 .ok_or(FrameError::InvalidSid)?;
100 let nrc = UdsError::from_repr(*data.get(3).ok_or(FrameError::InvalidNrc)?)
101 .ok_or(FrameError::InvalidNrc)?;
102 return Ok(UdsFrame::NegativeResp(UdsNegativeResponse {
103 size,
104 rsid,
105 nrc,
106 }));
107 }
108
109 let did = if data.len() > 2 {
110 Some(u16::from_be_bytes([data[2], *data.get(3).unwrap_or(&0)]))
111 } else {
112 None
113 };
114
115 let payload_start = if did.is_some() { 4 } else { 2 };
116 let payload = data.get(payload_start..).unwrap_or(&[]).to_vec();
117
118 Ok(UdsFrame::Single(UdsSingleFrame {
119 size,
120 sid,
121 did,
122 payload,
123 }))
124 }
125 0x1 => {
126 // First Frame
127 let size = (((data[0] & 0x0F) as u16) << 8)
128 | (*data.get(1).ok_or(FrameError::InvalidSize)? as u16);
129 let sid = *data.get(2).ok_or(FrameError::InvalidSize)?;
130
131 let did = data
132 .get(3..5)
133 .map(|bytes| u16::from_be_bytes([bytes[0], bytes[1]]));
134 let payload_start = if did.is_some() { 5 } else { 3 };
135 let payload = data.get(payload_start..).unwrap_or(&[]).to_vec();
136
137 Ok(UdsFrame::First(UdsFirstFrame {
138 size,
139 sid,
140 did,
141 payload,
142 }))
143 }
144 0x2 => {
145 // Consecutive Frame
146 let seq_num = data[0] & 0x0F;
147 let payload = data.get(1..).unwrap_or(&[]).to_vec();
148 Ok(UdsFrame::Consecutive(UdsConsecutiveFrame {
149 seq_num,
150 payload,
151 }))
152 }
153 0x3 => {
154 // Flow Control Frame
155 let (flag, block_size, separation_time) = (
156 data[0] & 0x0F,
157 *data.get(1).ok_or(FrameError::InvalidSize)?,
158 *data.get(2).ok_or(FrameError::InvalidSize)?,
159 );
160 let padding = data.get(3..).unwrap_or(&[]).to_vec();
161 Ok(UdsFrame::FlowControl(UdsFlowControlFrame {
162 flag,
163 block_size,
164 separation_time,
165 padding,
166 }))
167 }
168 _ => Err(FrameError::InvalidFrameType),
169 }
170 }
171}
172
173/// Represents a UDS Negative Response frame.
174/// This frame is sent by the ECU when a UDS request fails.
175#[derive(Debug, Clone, PartialEq)]
176pub struct UdsNegativeResponse {
177 /// Size of the payload (only 4 bits are used, max value is 7).
178 pub size: u8,
179 /// Service Identifier (SID) that caused the negative response.
180 pub rsid: UdsCommand,
181 /// Negative Response Code (NRC) indicating the reason for failure.
182 pub nrc: UdsError,
183}
184
185/// Represents a UDS Single Frame.
186/// This frame is used when the total payload fits within a single CAN frame.
187#[derive(Debug, Clone, PartialEq)]
188pub struct UdsSingleFrame {
189 /// Size of the payload (only 4 bits are used, max value is 7).
190 pub size: u8,
191 /// Service Identifier (SID) for the request or response.
192 pub sid: u8,
193 /// Optional Diagnostic Identifier (DID), used in certain services.
194 pub did: Option<u16>,
195 /// The actual payload data for the request or response.
196 pub payload: Vec<u8>,
197}
198
199/// Represents a UDS First Frame.
200/// This frame is sent when the payload is too large for a single frame.
201/// It contains the total size of the payload and the initial data.
202#[derive(Debug, Clone, PartialEq)]
203pub struct UdsFirstFrame {
204 /// Total size of the payload (only 12 bits are used).
205 pub size: u16,
206 /// Service Identifier (SID) for the request or response.
207 pub sid: u8,
208 /// Optional Diagnostic Identifier (DID), used in certain services.
209 pub did: Option<u16>,
210 /// The first portion of the payload.
211 pub payload: Vec<u8>,
212}
213
214/// Represents a UDS Consecutive Frame.
215/// This frame is used for multi-frame transmissions after the First Frame.
216#[derive(Debug, Clone, PartialEq)]
217pub struct UdsConsecutiveFrame {
218 /// Sequence number (4 bits, values range from 0 to 15).
219 pub seq_num: u8,
220 /// The next portion of the payload.
221 pub payload: Vec<u8>,
222}
223
224/// Represents a UDS Flow Control Frame.
225/// This frame is sent by the receiver to control the flow of multi-frame transmissions.
226#[derive(Debug, Clone, PartialEq)]
227pub struct UdsFlowControlFrame {
228 /// Flow control flag:
229 /// - `0x00` = Continue to send (CTS)
230 /// - `0x01` = Wait (WT)
231 /// - `0x02` = Overflow/abort (OVFLW)
232 pub flag: u8,
233 /// The number of Consecutive Frames the sender can transmit before waiting.
234 pub block_size: u8,
235 /// Minimum separation time (ST) in milliseconds between transmitted frames.
236 pub separation_time: u8,
237 /// Optional padding bytes (if required for 8-byte CAN frames).
238 pub padding: Vec<u8>,
239}
240
241impl UdsNegativeResponse {
242 /// Creates a new UDS Negative Response frame.
243 ///
244 /// # Parameters:
245 /// - `rsid`: The requested service identifier that failed.
246 /// - `nrc`: The negative response code indicating the failure reason.
247 /// - `size`: Size of the response payload (max 7).
248 ///
249 /// # Returns:
250 /// - A `UdsNegativeResponse` instance.
251 pub fn new(rsid: UdsCommand, nrc: UdsError, size: u8) -> Self {
252 Self { size, rsid, nrc }
253 }
254
255 /// Converts the negative response frame into a CAN frame byte vector.
256 ///
257 /// # Returns:
258 /// - `Vec<u8>`: A byte array representing the negative response frame.
259 pub fn to_vec(&self) -> Vec<u8> {
260 vec![self.size & 0x0F, 0x7F, self.rsid.into(), self.nrc.into()]
261 }
262}
263
264impl UdsSingleFrame {
265 /// Creates a new UDS Single Frame.
266 ///
267 /// # Parameters:
268 /// - `sid`: Service Identifier.
269 /// - `did`: Optional Diagnostic Identifier.
270 /// - `payload`: The payload data (max 7 bytes).
271 ///
272 /// # Returns:
273 /// - `Ok(UdsSingleFrame)`: If the payload size is valid.
274 /// - `Err(FrameError)`: If the payload exceeds 7 bytes.
275 pub fn new(sid: u8, did: Option<u16>, payload: Vec<u8>) -> Result<Self, FrameError> {
276 if payload.len() > 7 {
277 return Err(FrameError::InvalidCanLength);
278 }
279
280 let size = if did.is_some() {
281 payload.len() + 3
282 } else {
283 payload.len() + 1
284 } as u8;
285
286 Ok(Self {
287 size,
288 sid,
289 did,
290 payload,
291 })
292 }
293
294 /// Converts the single frame into a CAN frame byte vector.
295 ///
296 /// # Returns:
297 /// - `Ok(Vec<u8>)`: The CAN frame representation.
298 /// - `Err(FrameError)`: If the payload size exceeds 7 bytes.
299 pub fn to_vec(&self) -> Result<Vec<u8>, FrameError> {
300 if self.payload.len() > 7 {
301 return Err(FrameError::InvalidSize);
302 }
303
304 let mut frame = Vec::new();
305 frame.push(self.size & 0x0F); // PCI byte (first nibble is 0 for Single Frame)
306 frame.push(self.sid);
307 if let Some(did) = self.did {
308 frame.extend_from_slice(&did.to_be_bytes());
309 }
310 frame.extend_from_slice(&self.payload);
311
312 Ok(frame)
313 }
314}
315
316impl UdsFirstFrame {
317 /// Creates a new UDS First Frame for multi-frame communication.
318 ///
319 /// # Parameters:
320 /// - `sid`: Service Identifier.
321 /// - `size`: Total payload size.
322 /// - `did`: Optional Diagnostic Identifier.
323 /// - `payload`: Initial chunk of the payload (max 6 bytes).
324 ///
325 /// # Returns:
326 /// - `Ok(UdsFirstFrame)`: If the payload size is valid.
327 /// - `Err(FrameError)`: If the payload exceeds 6 bytes.
328 pub fn new(sid: u8, size: u16, did: Option<u16>, payload: Vec<u8>) -> Result<Self, FrameError> {
329 if payload.len() > 6 {
330 return Err(FrameError::InvalidCanLength);
331 }
332
333 Ok(Self {
334 size,
335 sid,
336 did,
337 payload,
338 })
339 }
340
341 /// Converts the first frame into a CAN frame byte vector.
342 ///
343 /// # Returns:
344 /// - `Ok(Vec<u8>)`: The CAN frame representation.
345 /// - `Err(FrameError)`: If the payload size exceeds 6 bytes.
346 pub fn to_vec(&self) -> Result<Vec<u8>, FrameError> {
347 if self.payload.len() > 6 {
348 return Err(FrameError::InvalidSize);
349 }
350
351 let mut frame = Vec::new();
352 frame.push(0x10 | ((self.size >> 8) as u8 & 0x0F)); // PCI first byte
353 frame.push((self.size & 0xFF) as u8); // PCI second byte
354 frame.push(self.sid);
355 if let Some(did) = self.did {
356 frame.extend_from_slice(&did.to_be_bytes());
357 }
358 frame.extend_from_slice(&self.payload);
359
360 Ok(frame)
361 }
362}
363
364impl UdsConsecutiveFrame {
365 /// Creates a new UDS Consecutive Frame.
366 ///
367 /// # Parameters:
368 /// - `seq_num`: Sequence number (0-15).
369 /// - `payload`: Payload data (max 7 bytes).
370 ///
371 /// # Returns:
372 /// - `Ok(UdsConsecutiveFrame)`: If the payload size is valid.
373 /// - `Err(FrameError)`: If the payload exceeds 7 bytes.
374 pub fn new(seq_num: u8, payload: Vec<u8>) -> Result<Self, FrameError> {
375 if payload.len() > 7 {
376 return Err(FrameError::InvalidCanLength);
377 }
378
379 Ok(Self { seq_num, payload })
380 }
381
382 /// Converts the consecutive frame into a CAN frame byte vector.
383 ///
384 /// # Returns:
385 /// - `Ok(Vec<u8>)`: The CAN frame representation.
386 /// - `Err(FrameError)`: If the payload size exceeds 7 bytes.
387 pub fn to_vec(&self) -> Result<Vec<u8>, FrameError> {
388 if self.payload.len() > 7 {
389 return Err(FrameError::InvalidSize);
390 }
391
392 let mut frame = Vec::new();
393 frame.push(0x20 | (self.seq_num & 0x0F)); // PCI byte
394 frame.extend_from_slice(&self.payload);
395
396 Ok(frame)
397 }
398}
399
400impl UdsFlowControlFrame {
401 /// Creates a new UDS Flow Control Frame.
402 ///
403 /// # Parameters:
404 /// - `flag`: Flow control flag (0=CTS, 1=Wait, 2=Overflow).
405 /// - `block_size`: Number of consecutive frames before next flow control.
406 /// - `separation_time`: Time delay (in ms) between frames.
407 /// - `padding`: Optional padding data (max 5 bytes).
408 ///
409 /// # Returns:
410 /// - `Ok(UdsFlowControlFrame)`: If the padding size is valid.
411 /// - `Err(FrameError)`: If the padding exceeds 5 bytes.
412 pub fn new(
413 flag: u8,
414 block_size: u8,
415 separation_time: u8,
416 padding: Vec<u8>,
417 ) -> Result<Self, FrameError> {
418 if padding.len() > 5 {
419 return Err(FrameError::InvalidCanLength);
420 }
421 Ok(Self {
422 flag,
423 block_size,
424 separation_time,
425 padding,
426 })
427 }
428
429 /// Converts the flow control frame into a CAN frame byte vector.
430 ///
431 /// # Returns:
432 /// - `Ok(Vec<u8>)`: The CAN frame representation.
433 pub fn to_vec(&self) -> Result<Vec<u8>, FrameError> {
434 let mut frame = vec![
435 0x30 | (self.flag & 0x0F), // PCI byte
436 self.block_size,
437 self.separation_time,
438 ];
439
440 // Append padding if any
441 frame.extend_from_slice(&self.padding);
442
443 Ok(frame)
444 }
445}