Skip to main content

zencan_common/
socketcan.rs

1use std::sync::Arc;
2
3use crate::{
4    messages::{CanError, CanId, CanMessage},
5    traits::{AsyncCanReceiver, AsyncCanSender, CanSendError},
6};
7use snafu::{ResultExt, Snafu};
8use socketcan::{CanFrame, CanSocket, EmbeddedFrame, Frame, ShouldRetry, Socket};
9use tokio::io::{unix::AsyncFd, Interest};
10
11fn socketcan_id_to_zencan_id(id: socketcan::CanId) -> CanId {
12    match id {
13        socketcan::CanId::Standard(id) => CanId::std(id.as_raw()),
14        socketcan::CanId::Extended(id) => CanId::extended(id.as_raw()),
15    }
16}
17
18fn zencan_id_to_socketcan_id(id: CanId) -> socketcan::CanId {
19    match id {
20        CanId::Extended(id) => socketcan::ExtendedId::new(id).unwrap().into(),
21        CanId::Std(id) => socketcan::StandardId::new(id).unwrap().into(),
22    }
23}
24
25fn socketcan_frame_to_zencan_message(frame: socketcan::CanFrame) -> Result<CanMessage, CanError> {
26    let id = socketcan_id_to_zencan_id(frame.can_id());
27
28    match frame {
29        CanFrame::Data(frame) => Ok(CanMessage::new(id, frame.data())),
30        CanFrame::Remote(_) => Ok(CanMessage::new_rtr(id)),
31        CanFrame::Error(frame) => Err(CanError::from_raw(frame.error_bits() as u8)),
32    }
33}
34
35fn zencan_message_to_socket_frame(frame: CanMessage) -> socketcan::CanFrame {
36    let id = zencan_id_to_socketcan_id(frame.id());
37
38    if frame.is_rtr() {
39        socketcan::CanFrame::new_remote(id, 0).unwrap()
40    } else {
41        socketcan::CanFrame::new(id, frame.data()).unwrap()
42    }
43}
44
45/// A handle to a socketcan CAN socket implementing AsyncCanReceiver.
46#[derive(Debug, Clone)]
47pub struct SocketCanReceiver {
48    socket: Arc<AsyncCanSocket>,
49}
50
51#[derive(Debug, Snafu)]
52pub enum ReceiveError {
53    Io { source: socketcan::IoError },
54    Can { source: CanError },
55}
56
57#[derive(Debug, Snafu)]
58pub struct SendError {
59    source: socketcan::IoError,
60    message: CanMessage,
61}
62
63impl CanSendError for SendError {
64    fn into_can_message(self) -> CanMessage {
65        self.message
66    }
67
68    fn message(&self) -> String {
69        self.source.to_string()
70    }
71}
72
73/// Create an Async socket around a socketcan CanSocket. This is just a reimplemenation of the tokio
74/// socket in the `socketcan` crate, but with support for `try_read_frame` and `try_write_frame`
75/// added.
76#[derive(Debug)]
77struct AsyncCanSocket(AsyncFd<CanSocket>);
78
79#[allow(dead_code)]
80impl AsyncCanSocket {
81    pub fn new(inner: CanSocket) -> Result<Self, std::io::Error> {
82        inner.set_nonblocking(true)?;
83        Ok(Self(AsyncFd::new(inner)?))
84    }
85
86    pub fn open(ifname: &str) -> Result<Self, std::io::Error> {
87        let socket = CanSocket::open(ifname)?;
88        socket.set_nonblocking(true)?;
89        Ok(Self(AsyncFd::new(socket)?))
90    }
91
92    /// Attempt to read a CAN frame from the socket without blocking
93    ///
94    /// If no message is immediately available, a WouldBlock error is returned.
95    pub fn try_read_frame(&self) -> Result<CanFrame, std::io::Error> {
96        self.0.get_ref().read_frame()
97    }
98
99    /// Read a CAN frame from the socket asynchronously
100    pub async fn read_frame(&self) -> Result<CanFrame, std::io::Error> {
101        self.0
102            .async_io(Interest::READABLE, |inner| inner.read_frame())
103            .await
104    }
105
106    pub async fn write_frame(&self, frame: &CanFrame) -> Result<(), std::io::Error> {
107        self.0
108            .async_io(Interest::WRITABLE, |inner| inner.write_frame(frame))
109            .await
110    }
111
112    /// Attempt to write a CAN frame to the socket without blocking
113    pub fn try_write_frame(&self, frame: CanFrame) -> Result<(), std::io::Error> {
114        self.0.get_ref().write_frame(&frame)
115    }
116}
117
118impl AsyncCanReceiver for SocketCanReceiver {
119    type Error = ReceiveError;
120
121    fn try_recv(&mut self) -> Option<CanMessage> {
122        match self.socket.try_read_frame() {
123            Ok(frame) => Some(socketcan_frame_to_zencan_message(frame).unwrap()),
124            _ => None,
125        }
126    }
127
128    async fn recv(&mut self) -> Result<CanMessage, ReceiveError> {
129        loop {
130            match self.socket.read_frame().await {
131                Ok(frame) => return socketcan_frame_to_zencan_message(frame).context(CanSnafu),
132                Err(e) => {
133                    if !e.should_retry() {
134                        return Err(ReceiveError::Io { source: e });
135                    }
136                }
137            }
138        }
139    }
140}
141
142/// A handle to a socketcan CAN socket implementing AsyncCanSender.
143#[derive(Debug, Clone)]
144pub struct SocketCanSender {
145    socket: Arc<AsyncCanSocket>,
146}
147
148impl AsyncCanSender for SocketCanSender {
149    type Error = SendError;
150    async fn send(&mut self, msg: CanMessage) -> Result<(), Self::Error> {
151        let socketcan_frame = zencan_message_to_socket_frame(msg);
152
153        self.socket
154            .write_frame(&socketcan_frame)
155            .await
156            .context(SendSnafu { message: msg })
157    }
158}
159
160/// Open a socketcan device and split it into a sender and receiver object for use with zencan
161/// library
162///
163/// # Arguments
164/// * `device` - The name of the socketcan device to open, e.g. "vcan0", or "can0"
165///
166/// A key benefit of this is that by creating both sender and receiver objects from a shared socket,
167/// the receiver will not receive messages sent by the sender.
168#[cfg_attr(docsrs, doc(cfg(feature = "socketcan")))]
169pub fn open_socketcan<S: AsRef<str>>(
170    device: S,
171) -> Result<(SocketCanSender, SocketCanReceiver), socketcan::IoError> {
172    let device: &str = device.as_ref();
173    let socket = Arc::new(AsyncCanSocket::open(device)?);
174    let receiver = SocketCanReceiver {
175        socket: socket.clone(),
176    };
177    let sender = SocketCanSender { socket };
178    Ok((sender, receiver))
179}