#![deny(
missing_docs,
missing_debug_implementations,
missing_copy_implementations,
trivial_casts,
trivial_numeric_casts,
unstable_features,
unused_imports,
unused_import_braces,
unused_qualifications
)]
use channel::ChannelError;
use hardware::HardwareError;
pub mod channel;
pub mod dtc;
pub mod dynamic_diag;
pub mod hardware;
pub mod kwp2000;
pub mod obd2;
pub mod uds;
mod helpers;
pub type DiagServerResult<T> = Result<T, DiagError>;
#[derive(Debug)]
pub enum DiagError {
NotSupported,
ECUError {
code: u8,
def: Option<String>,
},
EmptyResponse,
WrongMessage,
ServerNotRunning,
InvalidResponseLength,
ParameterInvalid,
ChannelError(ChannelError),
NotImplemented(String),
HardwareError(HardwareError),
MismatchedResponse(String),
}
impl std::fmt::Display for DiagError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match &self {
DiagError::NotSupported => write!(f, "request not supported"),
DiagError::ECUError { code, def } => {
if let Some(d) = def {
write!(f, "ECU error 0x{:02X} ({})", code, d)
} else {
write!(f, "ECU error 0x{:02X}", code)
}
}
DiagError::EmptyResponse => write!(f, "ECU provided an empty response"),
DiagError::WrongMessage => write!(f, "ECU response message did not match request"),
DiagError::ServerNotRunning => write!(f, "diagnostic server not running"),
DiagError::ParameterInvalid => write!(f, "a parameter provided was invalid"),
DiagError::InvalidResponseLength => {
write!(f, "ECU response message was of invalid length")
}
DiagError::ChannelError(err) => write!(f, "underlying channel error: {}", err),
DiagError::NotImplemented(s) => {
write!(f, "server encountered an unimplemented function: {}", s)
}
DiagError::HardwareError(e) => write!(f, "Hardware error: {}", e),
DiagError::MismatchedResponse(e) => write!(f, "Param mismatched response: {}", e),
}
}
}
impl std::error::Error for DiagError {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match &self {
DiagError::ChannelError(e) => Some(e),
DiagError::HardwareError(e) => Some(e),
_ => None,
}
}
}
impl From<ChannelError> for DiagError {
fn from(x: ChannelError) -> Self {
Self::ChannelError(x)
}
}
impl From<HardwareError> for DiagError {
fn from(x: HardwareError) -> Self {
Self::HardwareError(x)
}
}
#[derive(Debug)]
pub enum ServerEvent<'a, SessionState> {
CriticalError {
desc: String,
},
ServerStart,
ServerExit,
DiagModeChange {
old: SessionState,
new: SessionState,
},
Request(&'a [u8]),
Response(&'a DiagServerResult<Vec<u8>>),
TesterPresentError(DiagError),
InterfaceCloseOnExitError(ChannelError),
}
unsafe impl<'a, SessionType> Send for ServerEvent<'a, SessionType> {}
unsafe impl<'a, SessionType> Sync for ServerEvent<'a, SessionType> {}
pub trait ServerEventHandler<SessionState>: Send + Sync {
fn on_event(&mut self, e: ServerEvent<SessionState>);
}
pub trait DiagnosticServer<CommandType> {
fn execute_command(&mut self, cmd: CommandType, args: &[u8]) -> DiagServerResult<()>;
fn execute_command_with_response(
&mut self,
cmd: CommandType,
args: &[u8],
) -> DiagServerResult<Vec<u8>>;
fn send_byte_array(&mut self, bytes: &[u8]) -> DiagServerResult<()>;
fn send_byte_array_with_response(&mut self, bytes: &[u8]) -> DiagServerResult<Vec<u8>>;
fn is_server_running(&self) -> bool;
fn set_repeat_count(&mut self, count: u32);
fn set_repeat_interval_count(&mut self, interval_ms: u32);
}
pub trait BaseServerSettings {
fn get_write_timeout_ms(&self) -> u32;
fn get_read_timeout_ms(&self) -> u32;
}
pub trait BaseServerPayload {
fn get_payload(&self) -> &[u8];
fn get_sid_byte(&self) -> u8;
fn to_bytes(&self) -> &[u8];
fn requires_response(&self) -> bool;
}
pub fn bcd_decode(input: u8) -> String {
format!("{}{}", (input & 0xF0) >> 4, input & 0x0F)
}
pub fn bcd_decode_slice(input: &[u8], sep: Option<&str>) -> String {
let mut res = String::new();
for (pos, x) in input.iter().enumerate() {
res.push_str(bcd_decode(*x).as_str());
if let Some(separator) = sep {
if pos != input.len() - 1 {
res.push_str(separator)
}
}
}
res
}