Skip to main content

uds_client/socket_can/
mod.rs

1//! CAN Socket Communication for UDS Protocol (Universal Diagnostic Services)
2//!
3//! This module provides abstractions for CAN bus communication using the UDS (Unified Diagnostic Services) protocol.
4//! It supports both Windows and Linux platforms with platform-specific implementations for CAN socket communication.
5//!
6//! Key Features:
7//! - Cross-platform support for CAN communication using either `socketcan` (Linux) or `peak_can` (Windows).
8//! - Provides `UdsSocket` struct for both transmitting and receiving CAN frames.
9//! - Implements `CanSocketTx` and `CanSocketRx` traits for asynchronous transmission and reception of CAN frames.
10//! - Includes `UdsSocketTx` and `UdsSocketRx` types for managing transmission and reception sockets separately.
11//! - Supports raw data transmission and receiving UDS frames with a response.
12//! - Wraps error handling for both platforms (Linux and Windows) with appropriate error types.
13//!
14//! The module is designed to facilitate diagnostic communication over CAN, such as in automotive or embedded systems.
15
16#[cfg(target_os = "windows")]
17use embedded_can::ExtendedId;
18use embedded_can::{Frame, nb::Can};
19use embedded_io_async::ErrorType;
20#[cfg(target_os = "windows")]
21use peak_can::{
22    bus::UsbBus,
23    df::ReceiveStatus,
24    error::CanError,
25    socket::usb::UsbCanSocket,
26    socket::{Baudrate, RecvCan, SendCan},
27    socket::{CanFrame, MessageType},
28};
29#[cfg(target_os = "linux")]
30use socketcan::{CanFrame, CanSocket, Socket};
31use std::{
32    sync::{Arc, Mutex},
33    time::Duration,
34};
35
36#[cfg(target_os = "windows")]
37#[derive(Default, Clone, Copy)]
38pub struct WrappedCanFrame(pub CanFrame);
39#[cfg(target_os = "windows")]
40#[derive(Debug)]
41pub struct WrappedPcanError(pub CanError);
42
43pub trait CanSocketTx {
44    /// Associated frame type.
45    type Frame: Frame;
46
47    /// Associated error type.
48    type Error: embedded_can::Error;
49
50    // The transmit function
51    fn transmit(
52        &mut self,
53        frame: &Self::Frame,
54    ) -> impl std::future::Future<Output = nb::Result<Option<Self::Frame>, Self::Error>> + Send;
55}
56
57#[allow(dead_code)]
58pub trait CanSocketRx {
59    /// Associated frame type.
60    type Frame: Frame;
61
62    /// Associated error type.
63    type Error: embedded_can::Error;
64
65    // The receive function
66    fn receive(
67        &mut self,
68    ) -> impl std::future::Future<Output = nb::Result<Self::Frame, Self::Error>>;
69}
70
71pub struct UdsSocket {
72    #[cfg(target_os = "linux")]
73    can_socket: CanSocket,
74    #[cfg(target_os = "windows")]
75    can_socket: UsbCanSocket,
76}
77
78pub struct UdsSocketTx {
79    #[cfg(target_os = "linux")]
80    tx: Arc<Mutex<CanSocket>>,
81    #[cfg(target_os = "windows")]
82    tx: Arc<Mutex<UsbCanSocket>>,
83}
84
85pub struct UdsSocketRx {
86    #[cfg(target_os = "linux")]
87    rx: Arc<Mutex<CanSocket>>,
88    #[cfg(target_os = "windows")]
89    rx: Arc<Mutex<UsbCanSocket>>,
90}
91
92impl UdsSocket {
93    #[cfg(target_os = "linux")]
94    pub fn new(socket: &str, server_id: u32) -> Self {
95        use socketcan::{CanFilter, SocketOptions};
96
97        let can_socket = CanSocket::open(socket).unwrap();
98        let filter = CanFilter::new(server_id, 0x1FFFFFFF);
99        let _ = can_socket.set_filters(&[filter]);
100        Self { can_socket }
101    }
102
103    #[cfg(target_os = "windows")]
104    pub fn new(server_id: u32) -> Self {
105        use peak_can::df::SetAcceptanceFilter29Bit;
106
107        let can_socket = match UsbCanSocket::open(UsbBus::USB1, Baudrate::Baud500K) {
108            Ok(socket) => socket,
109            Err(e) => {
110                log::warn!("The PCAN initialize failed {:?}, just open", e);
111                UsbCanSocket::open_with_usb_bus(UsbBus::USB1)
112            }
113        };
114        can_socket
115            .set_acceptance_filter_29bit(&[server_id])
116            .unwrap();
117        Self { can_socket }
118    }
119
120    pub fn split(self) -> (UdsSocketTx, UdsSocketRx) {
121        let shared_socket = Arc::new(Mutex::new(self.can_socket));
122        let rx_socket = UdsSocketRx {
123            rx: shared_socket.clone(),
124        };
125        let tx_socket = UdsSocketTx {
126            tx: shared_socket.clone(),
127        };
128        (tx_socket, rx_socket)
129    }
130}
131
132// Specify the error type for `embedded_io_async`
133impl ErrorType for UdsSocket {
134    type Error = embedded_io_async::ErrorKind;
135}
136
137#[cfg(target_os = "linux")]
138impl Can for UdsSocket {
139    type Frame = CanFrame;
140
141    type Error = socketcan::Error;
142
143    fn transmit(&mut self, frame: &Self::Frame) -> nb::Result<Option<Self::Frame>, Self::Error> {
144        self.can_socket.transmit(frame)
145    }
146
147    fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
148        self.can_socket.receive()
149    }
150}
151
152#[cfg(target_os = "linux")]
153impl CanSocketTx for UdsSocketTx {
154    type Frame = CanFrame;
155    type Error = socketcan::Error;
156
157    async fn transmit(
158        &mut self,
159        frame: &Self::Frame,
160    ) -> nb::Result<Option<Self::Frame>, Self::Error> {
161        self.tx.lock().unwrap().transmit(frame)
162    }
163}
164
165#[cfg(target_os = "linux")]
166impl CanSocketRx for UdsSocketRx {
167    type Frame = CanFrame;
168    type Error = socketcan::Error;
169
170    async fn receive(&mut self) -> nb::Result<CanFrame, socketcan::Error> {
171        self.rx.lock().unwrap().receive()
172    }
173}
174
175#[cfg(target_os = "linux")]
176impl UdsSocketRx {
177    pub fn receive_with_timeout(&mut self, timeout: Duration) -> socketcan::IoResult<CanFrame> {
178        self.rx.lock().unwrap().read_frame_timeout(timeout)
179    }
180}
181
182#[cfg(target_os = "windows")]
183impl embedded_can::Error for WrappedPcanError {
184    fn kind(&self) -> embedded_can::ErrorKind {
185        match self.0 {
186            CanError::Overrun => embedded_can::ErrorKind::Overrun,
187            _ => embedded_can::ErrorKind::Other,
188        }
189    }
190}
191
192#[cfg(target_os = "windows")]
193impl embedded_can::Frame for WrappedCanFrame {
194    fn new(id: impl Into<embedded_can::Id>, data: &[u8]) -> Option<Self> {
195        let can_id: embedded_can::Id = id.into();
196        let raw_id = match can_id {
197            embedded_can::Id::Standard(standard_id) => standard_id.as_raw() as u32,
198            embedded_can::Id::Extended(extended_id) => extended_id.as_raw(),
199        };
200        match CanFrame::new(raw_id, MessageType::Extended, data) {
201            Ok(frame) => Some(WrappedCanFrame(frame)),
202            Err(_) => None,
203        }
204    }
205
206    fn id(&self) -> embedded_can::Id {
207        embedded_can::Id::Extended(ExtendedId::new(self.0.can_id()).unwrap())
208    }
209
210    fn data(&self) -> &[u8] {
211        self.0.data()
212    }
213
214    fn new_remote(id: impl Into<embedded_can::Id>, dlc: usize) -> Option<Self> {
215        let _ = dlc;
216        let _ = id;
217        todo!()
218    }
219
220    fn is_extended(&self) -> bool {
221        self.0.is_extended_frame()
222    }
223
224    fn is_remote_frame(&self) -> bool {
225        todo!()
226    }
227
228    fn dlc(&self) -> usize {
229        self.0.dlc() as usize
230    }
231
232    fn is_standard(&self) -> bool {
233        !self.0.is_extended_frame()
234    }
235
236    fn is_data_frame(&self) -> bool {
237        todo!()
238    }
239}
240
241#[cfg(target_os = "windows")]
242impl Can for UdsSocket {
243    type Frame = WrappedCanFrame;
244
245    type Error = WrappedPcanError;
246
247    fn transmit(&mut self, frame: &Self::Frame) -> nb::Result<Option<Self::Frame>, Self::Error> {
248        match self.can_socket.send(frame.0) {
249            Ok(_) => Ok(Some(Self::Frame::default())),
250            Err(e) => Err(nb::Error::Other(WrappedPcanError(e))),
251        }
252    }
253
254    fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
255        match self.can_socket.recv() {
256            Ok(f) => Ok(WrappedCanFrame(f.0)),
257            Err(e) => Err(nb::Error::Other(WrappedPcanError(e))),
258        }
259    }
260}
261
262#[cfg(target_os = "windows")]
263impl CanSocketTx for UdsSocketTx {
264    type Frame = WrappedCanFrame;
265
266    type Error = WrappedPcanError;
267
268    async fn transmit(
269        &mut self,
270        frame: &Self::Frame,
271    ) -> nb::Result<Option<Self::Frame>, Self::Error> {
272        match self.tx.lock().unwrap().send(frame.0) {
273            Ok(_) => Ok(Some(Self::Frame::default())),
274            Err(e) => Err(nb::Error::Other(WrappedPcanError(e))),
275        }
276    }
277}
278
279#[cfg(target_os = "windows")]
280impl CanSocketRx for UdsSocketRx {
281    type Frame = WrappedCanFrame;
282
283    type Error = WrappedPcanError;
284
285    async fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
286        match self.rx.lock().unwrap().recv() {
287            Ok(f) => Ok(WrappedCanFrame(f.0)),
288            Err(e) => Err(nb::Error::Other(WrappedPcanError(e))),
289        }
290    }
291}
292
293#[cfg(target_os = "windows")]
294impl UdsSocketRx {
295    pub fn receive_with_timeout(&mut self, timeout: Duration) -> Result<CanFrame, CanError> {
296        let start = chrono::Local::now();
297        while !self.rx.lock().unwrap().is_receiving()? {
298            if chrono::Local::now() > start + timeout {
299                return Err(CanError::Unknown);
300            }
301        }
302
303        self.rx.lock().unwrap().recv_frame()
304    }
305}