use std::{
borrow::BorrowMut,
sync::{mpsc, Arc, Mutex, PoisonError},
};
#[cfg(all(feature="socketcan", target_os="linux"))]
use socketcan::{EmbeddedFrame, Id, ExtendedId, StandardId, CanDataFrame};
use crate::hardware::HardwareError;
pub type ChannelResult<T> = Result<T, ChannelError>;
#[derive(Debug, Clone, thiserror::Error)]
pub enum ChannelError {
#[error("Device IO error")]
IOError(#[from] #[source] Arc<std::io::Error>),
#[error("Write timeout")]
WriteTimeout,
#[error("Read timeout")]
ReadTimeout,
#[error("No data in receive buffer")]
BufferEmpty,
#[error("Send buffer is full")]
BufferFull,
#[error("Device unsupported request")]
UnsupportedRequest,
#[error("Interface was not opened before request")]
InterfaceNotOpen,
#[error(transparent)]
HardwareError(#[from] HardwareError),
#[error("Channel configuration error")]
ConfigurationError,
#[error("Unknown channel error: {0}")]
Other(String),
}
impl<T> From<PoisonError<T>> for ChannelError {
fn from(err: PoisonError<T>) -> Self {
ChannelError::HardwareError(HardwareError::from(err))
}
}
impl From<mpsc::RecvError> for HardwareError {
fn from(e: mpsc::RecvError) -> Self {
HardwareError::APIError {
code: 98,
desc: e.to_string(),
}
}
}
impl From<mpsc::RecvError> for ChannelError {
fn from(err: mpsc::RecvError) -> Self {
ChannelError::HardwareError(HardwareError::from(err))
}
}
impl From<mpsc::RecvTimeoutError> for ChannelError {
fn from(_err: mpsc::RecvTimeoutError) -> Self {
ChannelError::WriteTimeout }
}
impl<T> From<mpsc::SendError<T>> for HardwareError {
fn from(e: mpsc::SendError<T>) -> Self {
HardwareError::APIError {
code: 98,
desc: e.to_string(),
}
}
}
impl<T> From<mpsc::SendError<T>> for ChannelError {
fn from(err: mpsc::SendError<T>) -> Self {
ChannelError::HardwareError(HardwareError::from(err))
}
}
pub trait PayloadChannel: Send + Sync {
fn open(&mut self) -> ChannelResult<()>;
fn close(&mut self) -> ChannelResult<()>;
fn set_ids(&mut self, send: u32, recv: u32) -> ChannelResult<()>;
fn read_bytes(&mut self, timeout_ms: u32) -> ChannelResult<Vec<u8>>;
fn write_bytes(
&mut self,
addr: u32,
ext_id: Option<u8>,
buffer: &[u8],
timeout_ms: u32,
) -> ChannelResult<()>;
fn read_write_bytes(
&mut self,
addr: u32,
ext_id: Option<u8>,
buffer: &[u8],
write_timeout_ms: u32,
read_timeout_ms: u32,
) -> ChannelResult<Vec<u8>> {
self.write_bytes(addr, ext_id, buffer, write_timeout_ms)?;
self.read_bytes(read_timeout_ms)
}
fn clear_rx_buffer(&mut self) -> ChannelResult<()>;
fn clear_tx_buffer(&mut self) -> ChannelResult<()>;
}
pub trait IsoTPChannel: PayloadChannel {
fn set_iso_tp_cfg(&mut self, cfg: IsoTPSettings) -> ChannelResult<()>;
}
pub trait PacketChannel<T: Packet>: Send + Sync {
fn open(&mut self) -> ChannelResult<()>;
fn close(&mut self) -> ChannelResult<()>;
fn write_packets(&mut self, packets: Vec<T>, timeout_ms: u32) -> ChannelResult<()>;
fn read_packets(&mut self, max: usize, timeout_ms: u32) -> ChannelResult<Vec<T>>;
fn clear_rx_buffer(&mut self) -> ChannelResult<()>;
fn clear_tx_buffer(&mut self) -> ChannelResult<()>;
}
pub trait CanChannel: PacketChannel<CanFrame> {
fn set_can_cfg(&mut self, baud: u32, use_extended: bool) -> ChannelResult<()>;
}
impl<T: PayloadChannel + ?Sized> PayloadChannel for Box<T> {
fn open(&mut self) -> ChannelResult<()> {
T::open(self)
}
fn close(&mut self) -> ChannelResult<()> {
T::close(self)
}
fn set_ids(&mut self, send: u32, recv: u32) -> ChannelResult<()> {
T::set_ids(self, send, recv)
}
fn read_bytes(&mut self, timeout_ms: u32) -> ChannelResult<Vec<u8>> {
T::read_bytes(self, timeout_ms)
}
fn write_bytes(
&mut self,
addr: u32,
ext_id: Option<u8>,
buffer: &[u8],
timeout_ms: u32,
) -> ChannelResult<()> {
T::write_bytes(self, addr, ext_id, buffer, timeout_ms)
}
fn clear_rx_buffer(&mut self) -> ChannelResult<()> {
T::clear_rx_buffer(self)
}
fn clear_tx_buffer(&mut self) -> ChannelResult<()> {
T::clear_tx_buffer(self)
}
}
impl<T: IsoTPChannel + ?Sized> IsoTPChannel for Box<T> {
fn set_iso_tp_cfg(&mut self, cfg: IsoTPSettings) -> ChannelResult<()> {
T::set_iso_tp_cfg(self, cfg)
}
}
impl<X: Packet, T: PacketChannel<X> + ?Sized> PacketChannel<X> for Box<T> {
fn open(&mut self) -> ChannelResult<()> {
T::open(self)
}
fn close(&mut self) -> ChannelResult<()> {
T::close(self)
}
fn write_packets(&mut self, packets: Vec<X>, timeout_ms: u32) -> ChannelResult<()> {
T::write_packets(self, packets, timeout_ms)
}
fn read_packets(&mut self, max: usize, timeout_ms: u32) -> ChannelResult<Vec<X>> {
T::read_packets(self, max, timeout_ms)
}
fn clear_rx_buffer(&mut self) -> ChannelResult<()> {
T::clear_rx_buffer(self)
}
fn clear_tx_buffer(&mut self) -> ChannelResult<()> {
T::clear_tx_buffer(self)
}
}
impl<T: CanChannel + ?Sized> CanChannel for Box<T> {
fn set_can_cfg(&mut self, baud: u32, use_extended: bool) -> ChannelResult<()> {
T::set_can_cfg(self, baud, use_extended)
}
}
impl<T: PayloadChannel + ?Sized> PayloadChannel for Arc<Mutex<T>> {
fn open(&mut self) -> ChannelResult<()> {
T::open(self.lock()?.borrow_mut())
}
fn close(&mut self) -> ChannelResult<()> {
T::close(self.lock()?.borrow_mut())
}
fn set_ids(&mut self, send: u32, recv: u32) -> ChannelResult<()> {
T::set_ids(self.lock()?.borrow_mut(), send, recv)
}
fn read_bytes(&mut self, timeout_ms: u32) -> ChannelResult<Vec<u8>> {
T::read_bytes(self.lock()?.borrow_mut(), timeout_ms)
}
fn write_bytes(
&mut self,
addr: u32,
ext_id: Option<u8>,
buffer: &[u8],
timeout_ms: u32,
) -> ChannelResult<()> {
T::write_bytes(self.lock()?.borrow_mut(), addr, ext_id, buffer, timeout_ms)
}
fn clear_rx_buffer(&mut self) -> ChannelResult<()> {
T::clear_rx_buffer(self.lock()?.borrow_mut())
}
fn clear_tx_buffer(&mut self) -> ChannelResult<()> {
T::clear_tx_buffer(self.lock()?.borrow_mut())
}
}
impl<T: IsoTPChannel + ?Sized> IsoTPChannel for Arc<Mutex<T>> {
fn set_iso_tp_cfg(&mut self, cfg: IsoTPSettings) -> ChannelResult<()> {
T::set_iso_tp_cfg(self.lock()?.borrow_mut(), cfg)
}
}
impl<X: Packet, T: PacketChannel<X> + ?Sized> PacketChannel<X> for Arc<Mutex<T>> {
fn open(&mut self) -> ChannelResult<()> {
T::open(self.lock()?.borrow_mut())
}
fn close(&mut self) -> ChannelResult<()> {
T::close(self.lock()?.borrow_mut())
}
fn write_packets(&mut self, packets: Vec<X>, timeout_ms: u32) -> ChannelResult<()> {
T::write_packets(self.lock()?.borrow_mut(), packets, timeout_ms)
}
fn read_packets(&mut self, max: usize, timeout_ms: u32) -> ChannelResult<Vec<X>> {
T::read_packets(self.lock()?.borrow_mut(), max, timeout_ms)
}
fn clear_rx_buffer(&mut self) -> ChannelResult<()> {
T::clear_rx_buffer(self.lock()?.borrow_mut())
}
fn clear_tx_buffer(&mut self) -> ChannelResult<()> {
T::clear_tx_buffer(self.lock()?.borrow_mut())
}
}
impl<T: CanChannel + ?Sized> CanChannel for Arc<Mutex<T>> {
fn set_can_cfg(&mut self, baud: u32, use_extended: bool) -> ChannelResult<()> {
T::set_can_cfg(self.lock()?.borrow_mut(), baud, use_extended)
}
}
pub trait Packet: Send + Sync + Sized {
fn get_address(&self) -> u32;
fn get_data(&self) -> &[u8];
fn set_address(&mut self, address: u32);
fn set_data(&mut self, data: &[u8]);
}
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct CanFrame {
id: u32,
dlc: u8,
data: [u8; 8],
ext: bool,
}
unsafe impl Sync for CanFrame {}
unsafe impl Send for CanFrame {}
impl CanFrame {
pub fn new(id: u32, data: &[u8], is_ext: bool) -> Self {
let max = std::cmp::min(8, data.len());
let mut tmp = [0u8; 8];
tmp[0..max].copy_from_slice(&data[0..max]);
Self {
id,
dlc: max as u8,
data: tmp,
ext: is_ext,
}
}
pub fn is_extended(&self) -> bool {
self.ext
}
}
impl Packet for CanFrame {
fn get_address(&self) -> u32 {
self.id
}
fn get_data(&self) -> &[u8] {
&self.data[0..self.dlc as usize]
}
fn set_address(&mut self, address: u32) {
self.id = address
}
fn set_data(&mut self, data: &[u8]) {
let max = std::cmp::min(8, data.len());
self.data[0..max].copy_from_slice(&data[0..max]);
self.dlc = max as u8;
}
}
#[cfg(all(feature="socketcan", target_os="linux"))]
impl From<CanDataFrame> for CanFrame {
fn from(value: CanDataFrame) -> Self {
let (id, ext) = match value.id() {
Id::Standard(id) => (id.as_raw() as u32, true),
Id::Extended(id) => (id.as_raw(), false),
};
CanFrame::new(id, value.data(), ext)
}
}
#[cfg(all(feature="socketcan", target_os="linux"))]
impl Into<CanDataFrame> for CanFrame {
fn into(self) -> CanDataFrame {
let id = match self.ext {
true => Id::Extended(ExtendedId::new(self.get_address()).unwrap()),
false => Id::Standard(StandardId::new(self.get_address() as u16).unwrap())
};
CanDataFrame::new(id, self.get_data()).unwrap()
}
}
#[derive(Debug, Copy, Clone)]
#[repr(C)]
pub struct IsoTPSettings {
pub block_size: u8,
pub st_min: u8,
pub extended_addresses: Option<(u8, u8)>,
pub pad_frame: bool,
pub can_speed: u32,
pub can_use_ext_addr: bool,
}
impl Default for IsoTPSettings {
fn default() -> Self {
Self {
block_size: 8,
st_min: 20,
extended_addresses: None,
pad_frame: true,
can_speed: 500_000,
can_use_ext_addr: false,
}
}
}