mod context;
mod service;
mod session;
mod util;
use crate::{constants::LOG_TAG_SERVER, server::session::SessionManager, DoCanError, SecurityAlgo};
use iso14229_1::{response::SessionTiming, Configuration, DataIdentifier};
use rsutil::types::ByteOrder;
use serde::{Deserialize, Deserializer};
use std::collections::HashMap;
use iso14229_1::{
request::Request,
response::{Code, Response},
Iso14229Error, Service,
};
use iso15765_2::{
can::{Address, AddressType, CanIsoTp},
IsoTp, IsoTpError,
};
use rs_can::{CanDevice, CanFrame};
use std::{fmt::Display, sync::Arc};
use tokio::{spawn, task::JoinHandle};
pub type DidSaLevel = HashMap<DataIdentifier, u8>;
fn did_sa_level_deserialize<'de, D>(deserializer: D) -> Result<DidSaLevel, D::Error>
where
D: Deserializer<'de>,
{
let raw_map: HashMap<u16, u8> = HashMap::deserialize(deserializer)?;
let res = raw_map
.into_iter()
.map(|(k, v)| (DataIdentifier::from(k), v))
.collect::<HashMap<_, _>>();
Ok(res)
}
#[allow(unused)]
#[derive(Debug, Clone, Deserialize)]
pub struct Config {
pub(crate) address: Address,
pub(crate) timing: SessionTiming,
pub(crate) extend_sa_level: u8,
pub(crate) program_sa_level: u8,
pub(crate) seed_len: usize,
pub(crate) sa_salt: Vec<u8>,
pub(crate) cfg: Configuration,
#[serde(deserialize_with = "did_sa_level_deserialize")]
pub(crate) did_sa_level: DidSaLevel,
pub(crate) byte_order: ByteOrder,
}
#[async_trait::async_trait]
pub trait Server {
async fn update_address(&self, address: Address);
async fn update_security_algo(&self, algo: SecurityAlgo);
async fn service_forever(&mut self, interval_us: u64);
async fn service_stop(&mut self);
}
#[derive(Clone)]
pub struct DoCanServer<D, C, F> {
isotp: CanIsoTp<D, C, F>,
session: SessionManager,
context: context::Context,
handles: Vec<Arc<JoinHandle<()>>>,
}
impl<D, C, F> DoCanServer<D, C, F>
where
D: CanDevice<Channel = C, Frame = F> + Clone + Send + 'static,
C: Clone + Eq + Display + Send + Sync + 'static,
F: CanFrame<Channel = C> + Clone + Display + 'static,
{
pub async fn new(device: D, channel: C) -> Result<Self, DoCanError> {
let context = context::Context::new().await?;
Ok(Self {
isotp: CanIsoTp::new(device, channel, context.config.address, true).await,
session: SessionManager::new(None),
context,
handles: Default::default(),
})
}
#[inline(always)]
pub fn tp_layer(&mut self) -> CanIsoTp<D, C, F> {
self.isotp.clone()
}
async fn server(&mut self) {
loop {
let timing = self.context.get_active_timing().await;
let cfg = self.context.get_cfg().clone();
if let Ok(data) = self.isotp.wait_data(timing.p2_ms()).await {
match data.len() {
0 => {}
_ => match Service::try_from(data[0]) {
Ok(service) => match Request::try_from((service, &data[1..], &cfg)) {
Ok(req) => {
if let Err(e) = match service {
Service::SessionCtrl => {
self.session_ctrl(req, &cfg, timing.into()).await
}
Service::ECUReset => self.ecu_reset(req, &cfg).await,
Service::ClearDiagnosticInfo => {
self.clear_diagnostic_info(req, &cfg).await
}
Service::ReadDTCInfo => self.read_dtc_info(req, &cfg).await,
Service::ReadDID => self.read_did(req, &cfg).await,
Service::ReadMemByAddr => {
self.read_mem_by_addr(req, &cfg).await
}
Service::ReadScalingDID => {
self.read_scaling_did(req, &cfg).await
}
Service::SecurityAccess => {
self.security_access(req, &cfg).await
}
Service::CommunicationCtrl => {
self.communication_ctrl(req, &cfg).await
}
#[cfg(any(feature = "std2020"))]
Service::Authentication => self.authentication(req, &cfg).await,
Service::ReadDataByPeriodId => {
self.read_data_by_pid(req, &cfg).await
}
Service::DynamicalDefineDID => {
self.dynamically_define_did(req, &cfg).await
}
Service::WriteDID => self.write_did(req, &cfg).await,
Service::IOCtrl => self.io_ctrl(req, &cfg).await,
Service::RoutineCtrl => self.routine_ctrl(req, &cfg).await,
Service::RequestDownload => {
self.request_download(req, &cfg).await
}
Service::RequestUpload => self.request_upload(req, &cfg).await,
Service::TransferData => self.transfer_data(req, &cfg).await,
Service::RequestTransferExit => {
self.request_transfer_exit(req, &cfg).await
}
#[cfg(any(feature = "std2013", feature = "std2020"))]
Service::RequestFileTransfer => {
self.request_file_transfer(req, &cfg).await
}
Service::WriteMemByAddr => {
self.write_mem_by_addr(req, &cfg).await
}
Service::TesterPresent => self.tester_present(req, &cfg).await,
#[cfg(any(feature = "std2006", feature = "std2013"))]
Service::AccessTimingParam => {
self.access_timing_parameter(req, &cfg).await
}
Service::SecuredDataTrans => {
self.secured_data_trans(req, &cfg).await
}
Service::CtrlDTCSetting => {
self.ctrl_dtc_setting(req, &cfg).await
}
Service::ResponseOnEvent => {
self.response_on_event(req, &cfg).await
}
Service::LinkCtrl => self.link_ctrl(req, &cfg).await,
Service::NRC => {
self.negative_service(
Service::NRC.into(),
Code::ServiceNotSupported,
)
.await;
Ok(())
}
} {
self.process_uds_error(service, e).await;
}
}
Err(e) => {
rsutil::warn!(
"{} error: {} when data: {} to request",
LOG_TAG_SERVER,
e,
hex::encode(&data)
);
self.process_uds_error(service, e).await;
}
},
Err(_) => {
self.negative_service(data[0], Code::ServiceNotSupported)
.await
}
},
}
}
}
}
async fn negative_service(&self, service: u8, code: Code) {
let data = vec![Service::NRC.into(), service, code.into()];
if let Err(e) = self.isotp.transmit(AddressType::Physical, data).await {
rsutil::error!(
"{} can't transmit negative response, because of: {}",
LOG_TAG_SERVER,
e
);
}
}
async fn process_uds_error(&self, service: Service, e: Iso14229Error) {
let code = match e {
Iso14229Error::InvalidDataLength { .. } => Code::IncorrectMessageLengthOrInvalidFormat,
Iso14229Error::ServiceError(_) => Code::ConditionsNotCorrect,
_ => Code::GeneralReject, };
self.transmit_response(Response::new_negative(service, code), true)
.await;
}
pub(crate) async fn transmit_response(&self, resp: Response, flag: bool) {
let service = resp.service();
let data: Vec<_> = resp.into();
if let Err(e) = self.isotp.transmit(AddressType::Physical, data).await {
rsutil::warn!("{} transmit error: {:?}", LOG_TAG_SERVER, e);
if !flag {
return;
}
if let Some(code) = match e {
IsoTpError::EmptyPdu => Some(Code::IncorrectMessageLengthOrInvalidFormat),
IsoTpError::InvalidPdu(_) => Some(Code::GeneralReject),
IsoTpError::InvalidParam(_) => Some(Code::GeneralReject),
IsoTpError::InvalidDataLength { .. } => {
Some(Code::IncorrectMessageLengthOrInvalidFormat)
}
IsoTpError::LengthOutOfRange(_) => Some(Code::RequestOutOfRange),
IsoTpError::InvalidStMin(_) => Some(Code::GeneralReject),
IsoTpError::InvalidSequence { .. } => Some(Code::WrongBlockSequenceCounter),
IsoTpError::MixFramesError => Some(Code::GeneralReject),
IsoTpError::Timeout { .. } => Some(Code::GeneralReject),
IsoTpError::OverloadFlow => Some(Code::RequestOutOfRange),
_ => None,
} {
let resp = Response::new_negative(service, code);
Box::pin(self.transmit_response(resp, false)).await;
}
}
}
}
#[async_trait::async_trait]
impl<D, C, F> Server for DoCanServer<D, C, F>
where
D: CanDevice<Channel = C, Frame = F> + Clone + Send + 'static,
C: Clone + Eq + Display + Send + Sync + 'static,
F: CanFrame<Channel = C> + Clone + Display + 'static,
{
#[inline(always)]
async fn update_address(&self, address: Address) {
self.isotp.update_address(address).await;
}
#[inline(always)]
async fn update_security_algo(&self, algo: SecurityAlgo) {
self.context.set_security_algo(algo).await;
}
async fn service_forever(&mut self, interval_us: u64) {
self.isotp.start(interval_us).await;
let mut clone = self.clone();
let session = self.session.clone();
let handle = spawn(async move { session.work().await });
self.handles.push(Arc::new(handle));
let handle = spawn(async move { clone.server().await });
self.handles.push(Arc::new(handle));
}
async fn service_stop(&mut self) {
self.isotp.stop().await;
for handle in &self.handles {
handle.abort();
}
rsutil::info!("{} stopped", LOG_TAG_SERVER);
}
}