use crate::{
socket_can::CanSocketTx,
uds_client::{DiagError, PciByte, Response, UdsClient, response::UdsResponse},
};
use automotive_diag::uds::UdsCommand;
use log::info;
#[repr(u8)]
#[derive(Debug)]
pub enum RealTimeType {
SlowRate = 0x01, MediumRate = 0x02, FastRate = 0x03, Stop = 0x04, }
impl From<RealTimeType> for u8 {
fn from(rt_type: RealTimeType) -> Self {
rt_type as u8
}
}
impl TryFrom<i32> for RealTimeType {
type Error = ();
fn try_from(rt_type: i32) -> Result<Self, Self::Error> {
match rt_type as u8 {
0x01 => Ok(RealTimeType::SlowRate),
0x02 => Ok(RealTimeType::MediumRate),
0x03 => Ok(RealTimeType::FastRate),
0x04 => Ok(RealTimeType::Stop),
_ => Err(()),
}
}
}
#[allow(dead_code)]
impl<T: CanSocketTx> UdsClient<'_, T> {
pub async fn uds_real_time_data_slow(&mut self) -> Result<(), DiagError> {
dbg!("UDS: send realtime data request (slow mode)");
let pci_byte = PciByte::new(crate::uds_client::PciType::SingleFrame, 3);
let re = self
.send_command_with_response(
pci_byte,
UdsCommand::ReadDataByPeriodicIdentifier,
&[0x01, 0xB0],
)
.await?;
self.real_time_data_process(re).await?;
Ok(())
}
pub async fn uds_real_time_data_medium(&mut self) -> Result<(), DiagError> {
dbg!("UDS: send realtime data request (medium mode)");
let pci_byte = PciByte::new(crate::uds_client::PciType::SingleFrame, 3);
let re = self
.send_command_with_response(
pci_byte,
UdsCommand::ReadDataByPeriodicIdentifier,
&[0x02, 0xB0],
)
.await?;
self.real_time_data_process(re).await?;
Ok(())
}
pub async fn uds_real_time_data_fast(&mut self) -> Result<(), DiagError> {
dbg!("UDS: send realtime data request (fast mode)");
let pci_byte = PciByte::new(crate::uds_client::PciType::SingleFrame, 3);
let re = self
.send_command_with_response(
pci_byte,
UdsCommand::ReadDataByPeriodicIdentifier,
&[0x03, 0xB0],
)
.await?;
self.real_time_data_process(re).await?;
Ok(())
}
pub async fn uds_real_time_data_stop(&mut self) -> Result<(), DiagError> {
dbg!("UDS: stop realtime data");
let pci_byte = PciByte::new(crate::uds_client::PciType::SingleFrame, 3);
self.send_command_with_response(
pci_byte,
UdsCommand::ReadDataByPeriodicIdentifier,
&[0x04, 0xB0],
)
.await?;
Ok(())
}
async fn real_time_data_process(&mut self, response: UdsResponse) -> Result<(), DiagError> {
let mut remain;
if let UdsResponse::First(size, did, sub_id, iden, data) = response {
let pci_byte = PciByte::new(crate::uds_client::PciType::FlowControl, 0);
self.send_command(pci_byte, 0x00, &[0x00])?;
info!(
"UDS received first frame: \n\t\tsize {:02X}\t\tdid {:02X}\t\tsub_id {:02X}\t\tident: {:02X}\t\tdata {:?}",
size, did, sub_id, iden, data
);
remain = size as usize - data.len();
let mut pre_idx = 0;
while let Response::Ok(uds_frame) = self.receive().await {
match uds_frame {
UdsResponse::Consecutive(idx, uds_data) => {
remain -= uds_data.len();
if idx != if pre_idx == 15 { 0 } else { pre_idx + 1 } {
return Err(DiagError::InvalidResponseLength);
}
pre_idx = idx;
info!("UDS received: {}, data: {:?}", idx, uds_data);
}
UdsResponse::First(size, did, sub_id, iden, data) => {
info!(
"UDS received first frame: \n\t\tsize {:02X}\t\tdid {:02X}\t\tsub_id {:02X}\t\tident: {:02X}\t\tdata {:?}",
size, did, sub_id, iden, data
);
let pci_byte = PciByte::new(crate::uds_client::PciType::FlowControl, 0);
self.send_command(pci_byte, 0x00, &[0x00])?;
remain = size as usize - data.len();
pre_idx = 0;
}
_ => {}
}
}
} else {
return Err(DiagError::WrongMessage);
}
if remain == 0 {
Ok(())
} else {
Err(DiagError::InvalidResponseLength)
}
}
}