use std::io;
use std::time::{Duration, Instant};
use socketcan::frame::CanAnyFrame;
use socketcan::{CanFdSocket, Socket, SocketOptions};
use can_hal::channel::{Receive, ReceiveFd, Transmit, TransmitFd};
use can_hal::filter::{Filter, Filterable};
use can_hal::frame::{CanFdFrame, CanFrame, Frame, Timestamped};
use crate::convert;
use crate::error::SocketCanError;
pub struct SocketCanChannel {
socket: CanFdSocket,
nonblocking: bool,
}
impl SocketCanChannel {
pub fn open(ifname: &str) -> Result<Self, SocketCanError> {
let socket = CanFdSocket::open(ifname)?;
Ok(Self {
socket,
nonblocking: false,
})
}
pub fn open_iface(ifindex: u32) -> Result<Self, SocketCanError> {
let socket = CanFdSocket::open_iface(ifindex)?;
Ok(Self {
socket,
nonblocking: false,
})
}
fn ensure_blocking(&mut self) -> Result<(), SocketCanError> {
if self.nonblocking {
self.socket.set_nonblocking(false)?;
self.nonblocking = false;
}
Ok(())
}
fn ensure_nonblocking(&mut self) -> Result<(), SocketCanError> {
if !self.nonblocking {
self.socket.set_nonblocking(true)?;
self.nonblocking = true;
}
Ok(())
}
}
impl Transmit for SocketCanChannel {
type Error = SocketCanError;
fn transmit(&mut self, frame: &CanFrame) -> Result<(), Self::Error> {
let sc_frame = convert::to_socketcan_data_frame(frame)?;
self.socket.write_frame(&sc_frame)?;
Ok(())
}
}
impl Receive for SocketCanChannel {
type Error = SocketCanError;
type Timestamp = Instant;
fn receive(&mut self) -> Result<Timestamped<CanFrame, Instant>, Self::Error> {
self.ensure_blocking()?;
loop {
let any_frame = self.socket.read_frame()?;
let now = Instant::now();
if let CanAnyFrame::Normal(data_frame) = any_frame {
let frame = convert::from_socketcan_data_frame(&data_frame)?;
return Ok(Timestamped::new(frame, now));
}
}
}
fn try_receive(&mut self) -> Result<Option<Timestamped<CanFrame, Instant>>, Self::Error> {
self.ensure_nonblocking()?;
loop {
match self.socket.read_frame() {
Ok(CanAnyFrame::Normal(data_frame)) => {
let now = Instant::now();
let frame = convert::from_socketcan_data_frame(&data_frame)?;
return Ok(Some(Timestamped::new(frame, now)));
}
Ok(_) => {} Err(e) if e.kind() == io::ErrorKind::WouldBlock => return Ok(None),
Err(e) => return Err(SocketCanError::Io(e)),
}
}
}
fn receive_timeout(
&mut self,
timeout: Duration,
) -> Result<Option<Timestamped<CanFrame, Instant>>, Self::Error> {
self.ensure_blocking()?;
self.socket.set_read_timeout(timeout)?;
let deadline = Instant::now() + timeout;
let result = loop {
match self.socket.read_frame() {
Ok(CanAnyFrame::Normal(data_frame)) => {
let now = Instant::now();
break convert::from_socketcan_data_frame(&data_frame)
.map(|f| Some(Timestamped::new(f, now)));
}
Ok(_) => {
let now = Instant::now();
if now >= deadline {
break Ok(None);
}
self.socket.set_read_timeout(deadline - now).ok();
}
Err(e)
if e.kind() == io::ErrorKind::WouldBlock
|| e.kind() == io::ErrorKind::TimedOut =>
{
break Ok(None);
}
Err(e) => break Err(SocketCanError::Io(e)),
}
};
self.socket.set_read_timeout(None).ok();
result
}
}
impl TransmitFd for SocketCanChannel {
type Error = SocketCanError;
fn transmit_fd(&mut self, frame: &CanFdFrame) -> Result<(), Self::Error> {
let sc_frame = convert::to_socketcan_fd_frame(frame)?;
self.socket.write_frame(&sc_frame)?;
Ok(())
}
}
impl ReceiveFd for SocketCanChannel {
type Error = SocketCanError;
type Timestamp = Instant;
fn receive_fd(&mut self) -> Result<Timestamped<Frame, Instant>, Self::Error> {
self.ensure_blocking()?;
loop {
let any_frame = self.socket.read_frame()?;
let now = Instant::now();
if let Ok(frame) = convert::from_socketcan_any_frame(any_frame) {
return Ok(Timestamped::new(frame, now));
}
}
}
fn try_receive_fd(&mut self) -> Result<Option<Timestamped<Frame, Instant>>, Self::Error> {
self.ensure_nonblocking()?;
match self.socket.read_frame() {
Ok(any_frame) => {
let now = Instant::now();
Ok(convert::from_socketcan_any_frame(any_frame)
.ok()
.map(|frame| Timestamped::new(frame, now)))
}
Err(e) if e.kind() == io::ErrorKind::WouldBlock => Ok(None),
Err(e) => Err(SocketCanError::Io(e)),
}
}
fn receive_fd_timeout(
&mut self,
timeout: Duration,
) -> Result<Option<Timestamped<Frame, Instant>>, Self::Error> {
self.ensure_blocking()?;
self.socket.set_read_timeout(timeout)?;
let deadline = Instant::now() + timeout;
let result = loop {
match self.socket.read_frame() {
Ok(any_frame) => {
let now = Instant::now();
if let Ok(frame) = convert::from_socketcan_any_frame(any_frame) {
break Ok(Some(Timestamped::new(frame, now)));
}
if now >= deadline {
break Ok(None);
}
self.socket.set_read_timeout(deadline - now).ok();
}
Err(e)
if e.kind() == io::ErrorKind::WouldBlock
|| e.kind() == io::ErrorKind::TimedOut =>
{
break Ok(None);
}
Err(e) => break Err(SocketCanError::Io(e)),
}
};
self.socket.set_read_timeout(None).ok();
result
}
}
impl Filterable for SocketCanChannel {
type Error = SocketCanError;
fn set_filters(&mut self, filters: &[Filter]) -> Result<(), Self::Error> {
if filters.is_empty() {
return self.clear_filters();
}
let sc_filters: Vec<_> = filters.iter().map(convert::to_socketcan_filter).collect();
self.socket.set_filters(&sc_filters)?;
Ok(())
}
fn clear_filters(&mut self) -> Result<(), Self::Error> {
self.socket.set_filter_accept_all()?;
Ok(())
}
}