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}