use std::io::ErrorKind;
use std::time::Duration;
use crate::bus::{CanBus, CanFrame, CanId};
use crate::error::{Error, Result};
use socketcan::{CanSocket, EmbeddedFrame, ExtendedId, Frame, Id, Socket, StandardId};
#[derive(Debug)]
pub struct SocketCanBus {
socket: CanSocket,
}
impl SocketCanBus {
pub fn open(interface: &str) -> Result<Self> {
let socket = CanSocket::open(interface).map_err(transport_error)?;
Ok(Self { socket })
}
pub const fn socket(&self) -> &CanSocket {
&self.socket
}
pub fn into_inner(self) -> CanSocket {
self.socket
}
}
impl CanBus for SocketCanBus {
fn send(&mut self, frame: &CanFrame) -> Result<()> {
let id = to_socketcan_id(frame.id())?;
let socket_frame = socketcan::CanFrame::new(id, frame.data())
.ok_or(Error::PayloadTooLong { len: frame.len() })?;
self.socket
.write_frame(&socket_frame)
.map_err(transport_error)
}
fn receive(&mut self, timeout: Duration) -> Result<Option<CanFrame>> {
match self.socket.read_frame_timeout(timeout) {
Ok(frame) => from_socketcan_frame(frame),
Err(err) if matches!(err.kind(), ErrorKind::WouldBlock | ErrorKind::TimedOut) => {
Ok(None)
}
Err(err) => Err(transport_error(err)),
}
}
}
fn to_socketcan_id(id: CanId) -> Result<Id> {
match id {
CanId::Standard(id) => StandardId::new(id)
.map(Id::Standard)
.ok_or_else(|| Error::InvalidCanId(u32::from(id))),
CanId::Extended(id) => ExtendedId::new(id)
.map(Id::Extended)
.ok_or(Error::InvalidCanId(id)),
}
}
fn from_socketcan_frame(frame: socketcan::CanFrame) -> Result<Option<CanFrame>> {
if frame.is_error_frame() || frame.is_remote_frame() {
return Ok(None);
}
let id = match frame.id() {
Id::Standard(id) => CanId::standard(id.as_raw())?,
Id::Extended(id) => CanId::extended(id.as_raw())?,
};
Ok(Some(CanFrame::new(id, frame.data())?))
}
fn transport_error(error: std::io::Error) -> Error {
Error::Transport(error.to_string())
}