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