#![allow(unused_imports, clippy::non_minimal_cfg)]
mod session_ctrl; pub use session_ctrl::*;
mod ecu_reset; pub use ecu_reset::*;
mod security_access; pub use security_access::*;
mod communication_ctrl; pub use communication_ctrl::*;
#[cfg(any(feature = "std2020"))]
mod authentication; #[cfg(any(feature = "std2020"))]
pub use authentication::*;
mod tester_present; pub use tester_present::*;
#[cfg(any(feature = "std2006", feature = "std2013"))] mod access_timing_param; #[cfg(any(feature = "std2006", feature = "std2013"))] pub use access_timing_param::*;
mod secured_data_trans; pub use secured_data_trans::*;
mod ctrl_dtc_setting; pub use ctrl_dtc_setting::*;
mod response_on_event; pub use response_on_event::*;
mod link_ctrl; pub use link_ctrl::*;
mod read_did; pub use read_did::*;
mod read_mem_by_addr; pub use read_mem_by_addr::*;
mod read_scaling_did; pub use read_scaling_did::*;
mod read_data_by_pid; pub use read_data_by_pid::*;
mod dynamically_define_did; pub use dynamically_define_did::*;
mod write_did; pub use write_did::*;
mod write_mem_by_addr; pub use write_mem_by_addr::*;
mod clear_diagnostic_info; pub use clear_diagnostic_info::*;
mod read_dtc_info; pub use read_dtc_info::*;
mod io_ctrl; pub use io_ctrl::*;
mod routine_ctrl; pub use routine_ctrl::*;
mod request_download; pub use request_download::*;
mod request_upload; pub use request_upload::*;
mod transfer_data; pub use transfer_data::*;
mod request_transfer_exit; pub use request_transfer_exit::*;
#[cfg(any(feature = "std2013", feature = "std2020"))]
mod request_file_transfer; #[cfg(any(feature = "std2013", feature = "std2020"))]
pub use request_file_transfer::*;
mod code;
pub use code::Code;
use crate::{
constant::POSITIVE_OFFSET, error::Error, response, utils, Configuration, ECUResetType,
ResponseData, Service,
};
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct SubFunction(u8);
impl SubFunction {
pub fn new(function: u8) -> Self {
Self(function)
}
#[inline]
pub fn origin(&self) -> u8 {
self.0
}
#[inline]
pub fn function<T: TryFrom<u8, Error = Error>>(&self) -> Result<T, Error> {
T::try_from(self.0)
}
}
impl Into<u8> for SubFunction {
#[inline]
fn into(self) -> u8 {
self.0.into()
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Response {
service: Service,
negative: bool,
sub_func: Option<SubFunction>,
data: Vec<u8>, }
impl Response {
pub fn new<T: AsRef<[u8]>>(
service: Service,
sub_func: Option<u8>,
data: T,
cfg: &Configuration,
) -> Result<Self, Error> {
match service {
Service::SessionCtrl => SessionCtrl::new_response(data, sub_func, cfg),
Service::ECUReset => ECUReset::new_response(data, sub_func, cfg),
Service::ClearDiagnosticInfo => ClearDiagnosticInfo::new_response(data, sub_func, cfg),
Service::ReadDTCInfo => DTCInfo::new_response(data, sub_func, cfg),
Service::ReadDID => ReadDID::new_response(data, sub_func, cfg),
Service::ReadMemByAddr => ReadMemByAddr::new_response(data, sub_func, cfg),
Service::ReadScalingDID => ReadScalingDID::new_response(data, sub_func, cfg),
Service::SecurityAccess => SecurityAccess::new_response(data, sub_func, cfg),
Service::CommunicationCtrl => CommunicationCtrl::new_response(data, sub_func, cfg),
#[cfg(any(feature = "std2020"))]
Service::Authentication => Authentication::new_response(data, sub_func, cfg),
Service::ReadDataByPeriodId => ReadDataByPeriodId::new_response(data, sub_func, cfg),
Service::DynamicalDefineDID => DynamicallyDefineDID::new_response(data, sub_func, cfg),
Service::WriteDID => WriteDID::new_response(data, sub_func, cfg),
Service::IOCtrl => IOCtrl::new_response(data, sub_func, cfg),
Service::RoutineCtrl => RoutineCtrl::new_response(data, sub_func, cfg),
Service::RequestDownload => RequestDownload::new_response(data, sub_func, cfg),
Service::RequestUpload => RequestUpload::new_response(data, sub_func, cfg),
Service::TransferData => TransferData::new_response(data, sub_func, cfg),
Service::RequestTransferExit => RequestTransferExit::new_response(data, sub_func, cfg),
#[cfg(any(feature = "std2013", feature = "std2020"))]
Service::RequestFileTransfer => RequestFileTransfer::new_response(data, sub_func, cfg),
Service::WriteMemByAddr => WriteMemByAddr::new_response(data, sub_func, cfg),
Service::TesterPresent => TesterPresent::new_response(data, sub_func, cfg),
#[cfg(any(feature = "std2006", feature = "std2013"))]
Service::AccessTimingParam => AccessTimingParameter::new_response(data, sub_func, cfg),
Service::SecuredDataTrans => SecuredDataTrans::new_response(data, sub_func, cfg),
Service::CtrlDTCSetting => CtrlDTCSetting::new_response(data, sub_func, cfg),
Service::ResponseOnEvent => ResponseOnEvent::new_response(data, sub_func, cfg),
Service::LinkCtrl => LinkCtrl::new_response(data, sub_func, cfg),
Service::NRC => {
let data = data.as_ref();
if sub_func.is_some() {
return Err(Error::SubFunctionError(service));
}
utils::data_length_check(data.len(), 2, true)?;
let nrc_service = Service::try_from(data[0])?;
let data = data[1..].to_vec();
Ok(Self {
service: nrc_service,
negative: true,
sub_func: None,
data,
})
}
}
}
pub fn new_negative(service: Service, code: Code) -> Self {
match code {
Code::Positive => Self {
service,
negative: false,
sub_func: None,
data: vec![],
},
_ => Self {
service,
negative: true,
sub_func: None,
data: vec![code.into()],
},
}
}
#[inline]
pub fn service(&self) -> Service {
self.service
}
#[inline]
pub fn sub_function(&self) -> Option<SubFunction> {
self.sub_func
}
#[inline]
pub const fn is_negative(&self) -> bool {
self.negative
}
#[inline]
pub fn nrc_code(&self) -> Result<Code, Error> {
if !self.negative {
return Err(Error::OtherError("get NRC from positive".into()));
}
if self.data.len() != 1 {
return Err(Error::OtherError(
"invalid data length when getting NRC".into(),
));
}
Ok(Code::from(self.data[0]))
}
#[inline]
pub fn raw_data(&self) -> &[u8] {
self.data.as_slice()
}
#[inline]
pub fn data<T>(&self, cfg: &Configuration) -> Result<T, Error>
where
T: ResponseData,
{
T::try_from((self, cfg))
}
#[inline]
fn new_sub_func<T: AsRef<[u8]>>(
data: T,
service: Service,
cfg: &Configuration,
) -> Result<Self, Error> {
let data = data.as_ref();
let data_len = data.len();
let mut offset = 0;
utils::data_length_check(data_len, offset + 1, false)?;
let sub_func = data[offset];
offset += 1;
let data = data[offset..].to_vec();
Self::new(service, Some(sub_func), data, cfg)
}
}
impl From<Response> for Vec<u8> {
fn from(mut v: Response) -> Self {
let mut result = Vec::new();
let service: u8 = v.service.into();
match v.negative {
true => {
result.push(Service::NRC.into());
result.push(service);
}
false => {
result.push(service | POSITIVE_OFFSET);
if let Some(sub_func) = v.sub_func {
result.push(sub_func.into());
}
}
}
result.append(&mut v.data);
result
}
}
impl<T: AsRef<[u8]>> TryFrom<(Service, T, &Configuration)> for Response {
type Error = Error;
fn try_from((service, data, cfg): (Service, T, &Configuration)) -> Result<Self, Self::Error> {
match service {
Service::SessionCtrl
| Service::ECUReset
| Service::SecurityAccess
| Service::CommunicationCtrl
| Service::ReadDTCInfo
| Service::RoutineCtrl
| Service::CtrlDTCSetting
| Service::TesterPresent
| Service::LinkCtrl
| Service::DynamicalDefineDID => Self::new_sub_func(data, service, cfg),
#[cfg(any(feature = "std2006", feature = "std2013"))]
Service::AccessTimingParam => Self::new_sub_func(data, service, cfg),
#[cfg(any(feature = "std2020"))]
Service::Authentication => Self::new_sub_func(data, service, cfg),
#[cfg(any(feature = "std2013", feature = "std2020"))]
Service::RequestFileTransfer => Self::new_sub_func(data, service, cfg),
Service::ClearDiagnosticInfo
| Service::ReadDID
| Service::ReadMemByAddr
| Service::ReadScalingDID
| Service::ReadDataByPeriodId
| Service::WriteDID
| Service::IOCtrl
| Service::RequestDownload
| Service::RequestUpload
| Service::TransferData
| Service::RequestTransferExit
| Service::WriteMemByAddr
| Service::SecuredDataTrans
| Service::ResponseOnEvent => Self::new(service, None, data, cfg),
Service::NRC => {
let data = data.as_ref();
let data_len = data.len();
let mut offset = 0;
utils::data_length_check(data_len, offset + 2, true)?;
let nrc_service = Service::try_from(data[offset])?;
offset += 1;
let data = data[offset..].to_vec();
Ok(Self {
service: nrc_service,
negative: true,
sub_func: None,
data,
})
}
}
}
}
impl<T: AsRef<[u8]>> TryFrom<(T, &Configuration)> for Response {
type Error = Error;
fn try_from((data, cfg): (T, &Configuration)) -> Result<Self, Self::Error> {
let data = data.as_ref();
let data_len = data.len();
utils::data_length_check(data_len, 1, false)?;
let mut offset = 0;
let service = data[offset];
let service = if service == Service::NRC as u8 {
Ok(Service::NRC)
} else {
Service::try_from(service & !POSITIVE_OFFSET)
}?;
offset += 1;
Self::try_from((service, &data[offset..], cfg))
}
}