use std::{
borrow::BorrowMut,
sync::{Arc, Mutex},
};
use crate::{
channel::IsoTPSettings,
dtc::DTC,
hardware::Hardware,
kwp2000::{self, Kwp2000DiagnosticServer, Kwp2000ServerOptions, Kwp2000VoidHandler},
uds::{UDSSessionType, UdsDiagnosticServer, UdsServerOptions, UdsVoidHandler},
DiagError, DiagServerResult, DiagnosticServer,
};
#[derive(Debug)]
pub struct DynamicDiagSession {
session: DynamicSessionType,
}
#[derive(Debug)]
enum DynamicSessionType {
Kwp(Kwp2000DiagnosticServer),
Uds(UdsDiagnosticServer),
}
impl DynamicDiagSession {
#[allow(unused_must_use, unused_assignments)]
pub fn new_over_iso_tp<C>(
hw_device: Arc<Mutex<C>>,
channel_cfg: IsoTPSettings,
tx_id: u32,
rx_id: u32,
) -> DiagServerResult<Self>
where
C: Hardware + 'static,
{
let mut last_err: Option<DiagError>;
let mut iso_tp_channel = Hardware::create_iso_tp_channel(hw_device.clone())?;
match Kwp2000DiagnosticServer::new_over_iso_tp(
Kwp2000ServerOptions {
send_id: tx_id,
recv_id: rx_id,
read_timeout_ms: 1500,
write_timeout_ms: 1500,
global_tp_id: 0x00,
tester_present_interval_ms: 2000,
tester_present_require_response: true,
},
iso_tp_channel,
channel_cfg,
Kwp2000VoidHandler {},
) {
Ok(mut kwp) => {
if kwp
.set_diagnostic_session_mode(kwp2000::SessionType::ExtendedDiagnostics)
.is_ok()
{
kwp.set_diagnostic_session_mode(kwp2000::SessionType::Normal);
return Ok(Self {
session: DynamicSessionType::Kwp(kwp),
});
} else {
last_err = Some(DiagError::NotSupported)
}
}
Err(e) => {
last_err = Some(e);
}
}
iso_tp_channel = Hardware::create_iso_tp_channel(hw_device)?;
match UdsDiagnosticServer::new_over_iso_tp(
UdsServerOptions {
send_id: tx_id,
recv_id: rx_id,
read_timeout_ms: 1500,
write_timeout_ms: 1500,
global_tp_id: 0x00,
tester_present_interval_ms: 2000,
tester_present_require_response: true,
},
iso_tp_channel,
channel_cfg,
UdsVoidHandler {},
) {
Ok(mut uds) => {
if uds.set_session_mode(UDSSessionType::Extended).is_ok() {
uds.set_session_mode(UDSSessionType::Default);
return Ok(Self {
session: DynamicSessionType::Uds(uds),
});
} else {
last_err = Some(DiagError::NotSupported)
}
}
Err(e) => {
last_err = Some(e);
}
}
Err(last_err.unwrap())
}
pub fn as_kwp_session(&'_ mut self) -> Option<&'_ mut Kwp2000DiagnosticServer> {
if let DynamicSessionType::Kwp(kwp) = self.session.borrow_mut() {
Some(kwp)
} else {
None
}
}
pub fn with_kwp<T, F: Fn(&mut Kwp2000DiagnosticServer) -> DiagServerResult<T>>(
&'_ mut self,
f: F,
) -> DiagServerResult<T> {
if let DynamicSessionType::Kwp(kwp) = self.session.borrow_mut() {
f(kwp)
} else {
Err(DiagError::NotSupported)
}
}
pub fn with_uds<T, F: Fn(&mut UdsDiagnosticServer) -> DiagServerResult<T>>(
&'_ mut self,
f: F,
) -> DiagServerResult<T> {
if let DynamicSessionType::Uds(uds) = self.session.borrow_mut() {
f(uds)
} else {
Err(DiagError::NotSupported)
}
}
pub fn as_uds_session(&'_ mut self) -> Option<&'_ mut UdsDiagnosticServer> {
if let DynamicSessionType::Uds(uds) = self.session.borrow_mut() {
Some(uds)
} else {
None
}
}
pub fn enter_extended_diagnostic_mode(&mut self) -> DiagServerResult<()> {
match self.session.borrow_mut() {
DynamicSessionType::Kwp(k) => {
k.set_diagnostic_session_mode(kwp2000::SessionType::ExtendedDiagnostics)
}
DynamicSessionType::Uds(u) => u.set_session_mode(UDSSessionType::Extended),
}
}
pub fn enter_default_diagnostic_mode(&mut self) -> DiagServerResult<()> {
match self.session.borrow_mut() {
DynamicSessionType::Kwp(k) => {
k.set_diagnostic_session_mode(kwp2000::SessionType::Normal)
}
DynamicSessionType::Uds(u) => u.set_session_mode(UDSSessionType::Default),
}
}
pub fn read_all_dtcs(&mut self) -> DiagServerResult<Vec<DTC>> {
match self.session.borrow_mut() {
DynamicSessionType::Kwp(k) => k.read_stored_dtcs(kwp2000::DTCRange::All),
DynamicSessionType::Uds(u) => u.get_dtcs_by_status_mask(0xFF),
}
}
pub fn clear_all_dtcs(&mut self) -> DiagServerResult<()> {
match self.session.borrow_mut() {
DynamicSessionType::Kwp(k) => k.clear_dtc_range(kwp2000::ClearDTCRange::AllDTCs),
DynamicSessionType::Uds(u) => u.clear_diagnostic_information(0x00FFFFFF),
}
}
pub fn send_bytes_with_response(&mut self, payload: &[u8]) -> DiagServerResult<Vec<u8>> {
match self.session.borrow_mut() {
DynamicSessionType::Kwp(k) => k.send_byte_array_with_response(payload),
DynamicSessionType::Uds(u) => u.send_byte_array_with_response(payload),
}
}
pub fn send_bytes(&mut self, payload: &[u8]) -> DiagServerResult<()> {
match self.session.borrow_mut() {
DynamicSessionType::Kwp(k) => k.send_byte_array(payload),
DynamicSessionType::Uds(u) => u.send_byte_array(payload),
}
}
}
impl From<Kwp2000DiagnosticServer> for DynamicDiagSession {
fn from(s: Kwp2000DiagnosticServer) -> Self {
Self {
session: DynamicSessionType::Kwp(s),
}
}
}
impl From<UdsDiagnosticServer> for DynamicDiagSession {
fn from(s: UdsDiagnosticServer) -> Self {
Self {
session: DynamicSessionType::Uds(s),
}
}
}