Skip to content

Commit

Permalink
0.96.0 - Implement shared hardware type and simplify errors
Browse files Browse the repository at this point in the history
  • Loading branch information
rnd-ash committed Jul 23, 2024
1 parent 890a6f0 commit ba4b56d
Show file tree
Hide file tree
Showing 4 changed files with 81 additions and 12 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "ecu_diagnostics"
version = "0.95.8"
version = "0.96.0"
authors = ["Ashcon Mohseninia <[email protected]>"]
edition = "2021"
description = "A rust crate for ECU diagnostic servers and communication APIs"
Expand Down
5 changes: 4 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
# Examples section

Each example here demonstates some feature of the ecu_diagnostic crate!
Each example here demonstates some feature of the ecu_diagnostic crate!

* kwp - Example of KWP Diagnostic server
* Peak - Example showing CAN Frame reading using PCAN-USB hardware + PCAN API under windows
9 changes: 0 additions & 9 deletions src/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,15 +58,6 @@ impl<T> From<PoisonError<T>> for ChannelError {
}
}

impl<T> From<PoisonError<T>> for HardwareError {
fn from(_x: PoisonError<T>) -> Self {
HardwareError::APIError {
code: 99,
desc: "PoisonError".into(),
}
}
}

impl From<mpsc::RecvError> for HardwareError {
fn from(e: mpsc::RecvError) -> Self {
HardwareError::APIError {
Expand Down
77 changes: 76 additions & 1 deletion src/hardware/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ pub mod passthru; // Not finished at all yet, hide from the crate

#[cfg(feature = "passthru")]
use std::sync::Arc;
use std::{any::{Any, TypeId}, fmt::Debug, sync::{Mutex, PoisonError, RwLock}};

#[cfg(all(feature="socketcan", target_os="linux"))]
pub mod socketcan;
Expand All @@ -21,7 +22,7 @@ pub type HardwareResult<T> = Result<T, HardwareError>;
/// The hardware trait defines functions supported by all adapter types,
/// as well as functions that can create abstracted communication channels
/// that can be used in diagnostic servers
pub trait Hardware: Clone {
pub trait Hardware {
/// Creates an ISO-TP channel on the devices.
/// This channel will live for as long as the hardware trait. Upon being dropped,
/// the channel will automatically be closed, if it has been opened.
Expand Down Expand Up @@ -56,6 +57,71 @@ pub trait Hardware: Clone {
fn is_connected(&self) -> bool;
}

#[derive(Clone)]
/// This is a simple wrapper around the [Hardware] data type that allows it to be cloned
/// and shared between multiple threads.
pub struct SharedHardware {
info: HardwareInfo,
hw: Arc<RwLock<Box<dyn Hardware>>>
}

impl SharedHardware {
/// Creates a new SharedHardware resource. Allowing the inner hardware to be cloned and passed around.
///
/// ## Panics
/// This function will panic if attempting to create a SharedHardware instance of a SharedHardware (Recursive creation)
pub fn new(t: Box<dyn Hardware>) -> Self {
if t.as_ref().type_id() == TypeId::of::<Self>() {
panic!("Attempting to create a SharedHardware instance of a SharedHardware!")
}
let info = t.get_info().clone();
Self {
info,
hw: Arc::new(RwLock::new(t))
}
}
}

impl Hardware for SharedHardware {
fn create_iso_tp_channel(&mut self) -> HardwareResult<Box<dyn IsoTPChannel>> {
self.hw.write()?.create_iso_tp_channel()
}

fn create_can_channel(&mut self) -> HardwareResult<Box<dyn CanChannel>> {
self.hw.write()?.create_can_channel()
}

fn is_iso_tp_channel_open(&self) -> bool {
self.hw.read().map(|x| x.is_iso_tp_channel_open()).unwrap_or(true)
}

fn is_can_channel_open(&self) -> bool {
self.hw.read().map(|x| x.is_can_channel_open()).unwrap_or(true)
}

fn read_battery_voltage(&mut self) -> Option<f32> {
self.hw.write().ok()?.read_battery_voltage()
}

fn read_ignition_voltage(&mut self) -> Option<f32> {
self.hw.write().ok()?.read_ignition_voltage()
}

fn get_info(&self) -> &HardwareInfo {
&self.info
}

fn is_connected(&self) -> bool {
self.hw.read().unwrap().is_connected()
}
}

impl Debug for SharedHardware {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_tuple("SharedHardware").finish()
}
}

#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
/// Device hardware info used by [HardwareScanner]
pub struct HardwareInfo {
Expand Down Expand Up @@ -112,6 +178,9 @@ pub enum HardwareError {
/// Function called on device that has not yet been opened
#[error("Device was not opened")]
DeviceNotOpen,
#[error("Device locked by another thread")]
/// Used by the [SharedHardware] structure, Indicates that a shared resource is locked by another thread
DeviceLockError,

/// Lib loading error
#[cfg(feature = "passthru")]
Expand All @@ -126,6 +195,12 @@ impl From<libloading::Error> for HardwareError {
}
}

impl<T> From<PoisonError<T>> for HardwareError {
fn from(_value: PoisonError<T>) -> Self {
Self::DeviceLockError
}
}

/// Contains details about what communication protocols
/// are supported by the physical hardware
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
Expand Down

0 comments on commit ba4b56d

Please sign in to comment.