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) -> Self {
95        use socketcan::{CanFilter, SocketOptions};
96
97        let can_socket = CanSocket::open(socket).unwrap();
98        let filter = CanFilter::new(0x7F0, 0x1FFFFFFF);
99        let _ = can_socket.set_filters(&[filter]);
100        Self { can_socket }
101    }
102
103    #[cfg(target_os = "windows")]
104    pub fn new() -> Self {
105        let can_socket = match UsbCanSocket::open(UsbBus::USB1, Baudrate::Baud500K) {
106            Ok(socket) => socket,
107            Err(e) => {
108                log::warn!("The PCAN initialize failed {:?}, just open", e);
109                UsbCanSocket::open_with_usb_bus(UsbBus::USB1)
110            }
111        };
112        Self { can_socket }
113    }
114
115    pub fn split(self) -> (UdsSocketTx, UdsSocketRx) {
116        let shared_socket = Arc::new(Mutex::new(self.can_socket));
117        let rx_socket = UdsSocketRx {
118            rx: shared_socket.clone(),
119        };
120        let tx_socket = UdsSocketTx {
121            tx: shared_socket.clone(),
122        };
123        (tx_socket, rx_socket)
124    }
125}
126
127// Specify the error type for `embedded_io_async`
128impl ErrorType for UdsSocket {
129    type Error = embedded_io_async::ErrorKind;
130}
131
132#[cfg(target_os = "linux")]
133impl Can for UdsSocket {
134    type Frame = CanFrame;
135
136    type Error = socketcan::Error;
137
138    fn transmit(&mut self, frame: &Self::Frame) -> nb::Result<Option<Self::Frame>, Self::Error> {
139        self.can_socket.transmit(frame)
140    }
141
142    fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
143        self.can_socket.receive()
144    }
145}
146
147#[cfg(target_os = "linux")]
148impl CanSocketTx for UdsSocketTx {
149    type Frame = CanFrame;
150    type Error = socketcan::Error;
151
152    async fn transmit(
153        &mut self,
154        frame: &Self::Frame,
155    ) -> nb::Result<Option<Self::Frame>, Self::Error> {
156        self.tx.lock().unwrap().transmit(frame)
157    }
158}
159
160#[cfg(target_os = "linux")]
161impl CanSocketRx for UdsSocketRx {
162    type Frame = CanFrame;
163    type Error = socketcan::Error;
164
165    async fn receive(&mut self) -> nb::Result<CanFrame, socketcan::Error> {
166        self.rx.lock().unwrap().receive()
167    }
168}
169
170#[cfg(target_os = "linux")]
171impl UdsSocketRx {
172    pub fn receive_with_timeout(&mut self, timeout: Duration) -> socketcan::IoResult<CanFrame> {
173        self.rx.lock().unwrap().read_frame_timeout(timeout)
174    }
175}
176
177#[cfg(target_os = "windows")]
178impl embedded_can::Error for WrappedPcanError {
179    fn kind(&self) -> embedded_can::ErrorKind {
180        match self.0 {
181            CanError::Overrun => embedded_can::ErrorKind::Overrun,
182            _ => embedded_can::ErrorKind::Other,
183        }
184    }
185}
186
187#[cfg(target_os = "windows")]
188impl embedded_can::Frame for WrappedCanFrame {
189    fn new(id: impl Into<embedded_can::Id>, data: &[u8]) -> Option<Self> {
190        let can_id: embedded_can::Id = id.into();
191        let raw_id = match can_id {
192            embedded_can::Id::Standard(standard_id) => standard_id.as_raw() as u32,
193            embedded_can::Id::Extended(extended_id) => extended_id.as_raw(),
194        };
195        match CanFrame::new(raw_id, MessageType::Extended, data) {
196            Ok(frame) => Some(WrappedCanFrame(frame)),
197            Err(_) => None,
198        }
199    }
200
201    fn id(&self) -> embedded_can::Id {
202        embedded_can::Id::Extended(ExtendedId::new(self.0.can_id()).unwrap())
203    }
204
205    fn data(&self) -> &[u8] {
206        self.0.data()
207    }
208
209    fn new_remote(id: impl Into<embedded_can::Id>, dlc: usize) -> Option<Self> {
210        let _ = dlc;
211        let _ = id;
212        todo!()
213    }
214
215    fn is_extended(&self) -> bool {
216        self.0.is_extended_frame()
217    }
218
219    fn is_remote_frame(&self) -> bool {
220        todo!()
221    }
222
223    fn dlc(&self) -> usize {
224        self.0.dlc() as usize
225    }
226
227    fn is_standard(&self) -> bool {
228        !self.0.is_extended_frame()
229    }
230
231    fn is_data_frame(&self) -> bool {
232        todo!()
233    }
234}
235
236#[cfg(target_os = "windows")]
237impl Can for UdsSocket {
238    type Frame = WrappedCanFrame;
239
240    type Error = WrappedPcanError;
241
242    fn transmit(&mut self, frame: &Self::Frame) -> nb::Result<Option<Self::Frame>, Self::Error> {
243        match self.can_socket.send(frame.0) {
244            Ok(_) => Ok(Some(Self::Frame::default())),
245            Err(e) => Err(nb::Error::Other(WrappedPcanError(e))),
246        }
247    }
248
249    fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
250        match self.can_socket.recv() {
251            Ok(f) => Ok(WrappedCanFrame(f.0)),
252            Err(e) => Err(nb::Error::Other(WrappedPcanError(e))),
253        }
254    }
255}
256
257#[cfg(target_os = "windows")]
258impl CanSocketTx for UdsSocketTx {
259    type Frame = WrappedCanFrame;
260
261    type Error = WrappedPcanError;
262
263    async fn transmit(
264        &mut self,
265        frame: &Self::Frame,
266    ) -> nb::Result<Option<Self::Frame>, Self::Error> {
267        match self.tx.lock().unwrap().send(frame.0) {
268            Ok(_) => Ok(Some(Self::Frame::default())),
269            Err(e) => Err(nb::Error::Other(WrappedPcanError(e))),
270        }
271    }
272}
273
274#[cfg(target_os = "windows")]
275impl CanSocketRx for UdsSocketRx {
276    type Frame = WrappedCanFrame;
277
278    type Error = WrappedPcanError;
279
280    async fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
281        match self.rx.lock().unwrap().recv() {
282            Ok(f) => Ok(WrappedCanFrame(f.0)),
283            Err(e) => Err(nb::Error::Other(WrappedPcanError(e))),
284        }
285    }
286}
287
288#[cfg(target_os = "windows")]
289impl UdsSocketRx {
290    pub fn receive_with_timeout(&mut self, timeout: Duration) -> Result<CanFrame, CanError> {
291        let start = chrono::Local::now();
292        while !self.rx.lock().unwrap().is_receiving()? {
293            if chrono::Local::now() > start + timeout {
294                return Err(CanError::Unknown);
295            }
296        }
297
298        self.rx.lock().unwrap().recv_frame()
299    }
300}