use automotive_diag::uds::{UdsCommand, UdsError};
use super::{DiagError, PciType};
#[derive(Debug, Clone, thiserror::Error)]
pub enum FrameError {
#[error("Invalid UDS frame type.")]
InvalidFrameType,
#[error("Frame size is incorrect.")]
InvalidSize,
#[error("Invalid Service Identifier (SID).")]
InvalidSid,
#[error("Invalid Negative Response Code (NRC).")]
InvalidNrc,
#[error("Invalid CAN message length.")]
InvalidCanLength,
#[error("An unknown error occurred.")]
Others,
}
#[derive(Debug, Clone, PartialEq)]
pub enum UdsFrame {
Single(UdsSingleFrame),
First(UdsFirstFrame),
Consecutive(UdsConsecutiveFrame),
FlowControl(UdsFlowControlFrame),
}
impl Default for UdsFrame {
fn default() -> Self {
UdsFrame::Single(UdsSingleFrame {
size: 0,
sid: 0,
did: None,
payload: Vec::new(),
})
}
}
impl UdsFrame {
pub fn pci_type(&self) -> PciType {
match self {
UdsFrame::Single(_) => PciType::SingleFrame,
UdsFrame::First(_) => PciType::FirstFrame,
UdsFrame::Consecutive(_) => PciType::ConsecutiveFrame,
UdsFrame::FlowControl(_) => PciType::FlowControl,
}
}
pub fn is_single_frame(&self) -> bool {
matches!(self, UdsFrame::Single(_frame))
}
pub fn is_first_frame(&self) -> bool {
matches!(self, UdsFrame::First(_frame))
}
pub fn is_consecutive_frame(&self) -> bool {
matches!(self, UdsFrame::Consecutive(_frame))
}
pub fn is_flow_control_frame(&self) -> bool {
matches!(self, UdsFrame::FlowControl(_frame))
}
pub fn to_vec(&self) -> Result<Vec<u8>, DiagError> {
match self {
UdsFrame::Single(uds_single_frame) => uds_single_frame.to_vec(),
UdsFrame::First(uds_first_frame) => uds_first_frame.to_vec(),
UdsFrame::Consecutive(uds_consecutive_frame) => uds_consecutive_frame.to_vec(),
UdsFrame::FlowControl(uds_flow_control_frame) => uds_flow_control_frame.to_vec(),
}
}
pub fn from_vec(data: Vec<u8>) -> Result<Self, DiagError> {
let frame_type = data.first().map(|b| b >> 4).ok_or(DiagError::FrameError {
error: FrameError::InvalidCanLength,
})?;
match frame_type {
0x0 => {
let size = data[0] & 0x0F;
let sid = *data.get(1).ok_or(DiagError::FrameError {
error: FrameError::InvalidSize,
})?;
if sid == 0x7F {
let rsid =
UdsCommand::from_repr(*data.get(2).ok_or(DiagError::FrameError {
error: FrameError::InvalidSid,
})?)
.ok_or(DiagError::FrameError {
error: FrameError::InvalidSid,
})?;
let nrc = UdsError::from_repr(*data.get(3).ok_or(DiagError::FrameError {
error: FrameError::InvalidNrc,
})?)
.ok_or(DiagError::FrameError {
error: FrameError::InvalidNrc,
})?;
return Err(DiagError::ECUError {
code: nrc,
rsid,
def: None,
});
}
let did = if data.len() > 2 {
Some(u16::from_be_bytes([data[2], *data.get(3).unwrap_or(&0)]))
} else {
None
};
let payload_start = if did.is_some() { 4 } else { 2 };
let payload = data.get(payload_start..).unwrap_or(&[]).to_vec();
Ok(UdsFrame::Single(UdsSingleFrame {
size,
sid,
did,
payload,
}))
}
0x1 => {
let size = (((data[0] & 0x0F) as u16) << 8)
| (*data.get(1).ok_or(DiagError::FrameError {
error: FrameError::InvalidSize,
})? as u16);
let sid = *data.get(2).ok_or(DiagError::FrameError {
error: FrameError::InvalidSize,
})?;
let did = data
.get(3..5)
.map(|bytes| u16::from_be_bytes([bytes[0], bytes[1]]));
let payload_start = if did.is_some() { 5 } else { 3 };
let payload = data.get(payload_start..).unwrap_or(&[]).to_vec();
Ok(UdsFrame::First(UdsFirstFrame {
size,
sid,
did,
payload,
}))
}
0x2 => {
let seq_num = data[0] & 0x0F;
let payload = data.get(1..).unwrap_or(&[]).to_vec();
Ok(UdsFrame::Consecutive(UdsConsecutiveFrame {
seq_num,
payload,
}))
}
0x3 => {
let (flag, block_size, separation_time) = (
data[0] & 0x0F,
*data.get(1).ok_or(DiagError::FrameError {
error: FrameError::InvalidSize,
})?,
*data.get(2).ok_or(DiagError::FrameError {
error: FrameError::InvalidSize,
})?,
);
let padding = data.get(3..).unwrap_or(&[]).to_vec();
Ok(UdsFrame::FlowControl(UdsFlowControlFrame {
flag,
block_size,
separation_time,
padding,
}))
}
_ => Err(DiagError::FrameError {
error: FrameError::InvalidFrameType,
}),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct UdsSingleFrame {
pub size: u8,
pub sid: u8,
pub did: Option<u16>,
pub payload: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct UdsFirstFrame {
pub size: u16,
pub sid: u8,
pub did: Option<u16>,
pub payload: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct UdsConsecutiveFrame {
pub seq_num: u8,
pub payload: Vec<u8>,
}
#[derive(Debug, Clone, PartialEq)]
pub struct UdsFlowControlFrame {
pub flag: u8,
pub block_size: u8,
pub separation_time: u8,
pub padding: Vec<u8>,
}
impl UdsSingleFrame {
pub fn new(sid: u8, did: Option<u16>, payload: Vec<u8>) -> Result<Self, FrameError> {
if payload.len() > 7 {
return Err(FrameError::InvalidCanLength);
}
let size = if did.is_some() {
payload.len() + 3
} else {
payload.len() + 1
} as u8;
Ok(Self {
size,
sid,
did,
payload,
})
}
pub fn to_vec(&self) -> Result<Vec<u8>, DiagError> {
if self.payload.len() > 7 {
return Err(DiagError::FrameError {
error: FrameError::InvalidSize,
});
}
let mut frame = Vec::new();
frame.push(self.size & 0x0F); frame.push(self.sid);
if let Some(did) = self.did {
frame.extend_from_slice(&did.to_be_bytes());
}
frame.extend_from_slice(&self.payload);
Ok(frame)
}
}
impl UdsFirstFrame {
pub fn new(sid: u8, size: u16, did: Option<u16>, payload: Vec<u8>) -> Result<Self, FrameError> {
if payload.len() > 6 {
return Err(FrameError::InvalidCanLength);
}
Ok(Self {
size,
sid,
did,
payload,
})
}
pub fn to_vec(&self) -> Result<Vec<u8>, DiagError> {
if self.payload.len() > 6 {
return Err(DiagError::FrameError {
error: FrameError::InvalidSize,
});
}
let mut frame = Vec::new();
frame.push(0x10 | ((self.size >> 8) as u8 & 0x0F)); frame.push((self.size & 0xFF) as u8); frame.push(self.sid);
if let Some(did) = self.did {
frame.extend_from_slice(&did.to_be_bytes());
}
frame.extend_from_slice(&self.payload);
Ok(frame)
}
}
impl UdsConsecutiveFrame {
pub fn new(seq_num: u8, payload: Vec<u8>) -> Result<Self, FrameError> {
if payload.len() > 7 {
return Err(FrameError::InvalidCanLength);
}
Ok(Self { seq_num, payload })
}
pub fn to_vec(&self) -> Result<Vec<u8>, DiagError> {
if self.payload.len() > 7 {
return Err(DiagError::FrameError {
error: FrameError::InvalidSize,
});
}
let mut frame = Vec::new();
frame.push(0x20 | (self.seq_num & 0x0F)); frame.extend_from_slice(&self.payload);
Ok(frame)
}
}
impl UdsFlowControlFrame {
pub fn new(
flag: u8,
block_size: u8,
separation_time: u8,
padding: Vec<u8>,
) -> Result<Self, FrameError> {
if padding.len() > 5 {
return Err(FrameError::InvalidCanLength);
}
Ok(Self {
flag,
block_size,
separation_time,
padding,
})
}
pub fn to_vec(&self) -> Result<Vec<u8>, DiagError> {
let mut frame = vec![
0x30 | (self.flag & 0x0F), self.block_size,
self.separation_time,
];
frame.extend_from_slice(&self.padding);
Ok(frame)
}
}