1use std::time::Duration;
6use thiserror::Error;
7
8pub use piper_protocol::PiperFrame;
10
11#[cfg(all(
14 not(feature = "mock"), any(
16 feature = "socketcan", all(feature = "auto-backend", target_os = "linux") )
19))]
20pub mod socketcan;
21
22#[cfg(all(
23 not(feature = "mock"),
24 any(
25 feature = "socketcan",
26 all(feature = "auto-backend", target_os = "linux")
27 )
28))]
29pub use socketcan::SocketCanAdapter;
30
31#[cfg(all(
32 not(feature = "mock"),
33 any(
34 feature = "socketcan",
35 all(feature = "auto-backend", target_os = "linux")
36 )
37))]
38pub use socketcan::split::{SocketCanRxAdapter, SocketCanTxAdapter};
39
40#[cfg(all(
43 not(feature = "mock"), any(
45 feature = "gs_usb", feature = "auto-backend" )
48))]
49pub mod gs_usb;
50
51#[cfg(all(
52 not(feature = "mock"),
53 any(feature = "gs_usb", feature = "auto-backend")
54))]
55pub use gs_usb::GsUsbCanAdapter;
56
57pub mod gs_usb_udp;
60
61#[cfg(all(
63 not(feature = "mock"),
64 any(feature = "gs_usb", feature = "auto-backend")
65))]
66pub use gs_usb::split::{GsUsbRxAdapter, GsUsbTxAdapter};
67
68#[cfg(feature = "mock")]
70pub mod mock;
71
72#[cfg(feature = "mock")]
73pub use mock::MockCanAdapter;
74
75#[derive(Error, Debug)]
77pub enum CanError {
78 #[error("IO Error: {0}")]
79 Io(#[from] std::io::Error),
80 #[error("Device Error: {0}")]
81 Device(#[from] CanDeviceError),
82 #[error("Read timeout")]
83 Timeout,
84 #[error("Buffer overflow")]
85 BufferOverflow,
86 #[error("Bus off")]
87 BusOff,
88 #[error("Device not started")]
89 NotStarted,
90}
91
92#[derive(Debug, Clone, Copy, PartialEq, Eq)]
94pub enum CanDeviceErrorKind {
95 Unknown,
96 NotFound,
97 NoDevice,
98 AccessDenied,
99 Busy,
100 UnsupportedConfig,
101 InvalidResponse,
102 InvalidFrame,
103 Backend,
104}
105
106#[derive(Error, Debug, Clone)]
108#[error("{kind:?}: {message}")]
109pub struct CanDeviceError {
110 pub kind: CanDeviceErrorKind,
111 pub message: String,
112}
113
114impl CanDeviceError {
115 pub fn new(kind: CanDeviceErrorKind, message: impl Into<String>) -> Self {
116 Self {
117 kind,
118 message: message.into(),
119 }
120 }
121
122 pub fn is_fatal(&self) -> bool {
123 matches!(
124 self.kind,
125 CanDeviceErrorKind::NoDevice
126 | CanDeviceErrorKind::AccessDenied
127 | CanDeviceErrorKind::NotFound
128 )
129 }
130}
131
132impl From<String> for CanDeviceError {
133 fn from(message: String) -> Self {
134 Self::new(CanDeviceErrorKind::Unknown, message)
135 }
136}
137
138impl From<&str> for CanDeviceError {
139 fn from(message: &str) -> Self {
140 Self::new(CanDeviceErrorKind::Unknown, message)
141 }
142}
143
144pub trait CanAdapter {
145 fn send(&mut self, frame: PiperFrame) -> Result<(), CanError>;
146 fn receive(&mut self) -> Result<PiperFrame, CanError>;
147 fn set_receive_timeout(&mut self, _timeout: Duration) {}
148 fn receive_timeout(&mut self, timeout: Duration) -> Result<PiperFrame, CanError> {
149 self.set_receive_timeout(timeout);
150 self.receive()
151 }
152 fn try_receive(&mut self) -> Result<Option<PiperFrame>, CanError> {
153 match self.receive_timeout(Duration::ZERO) {
154 Ok(frame) => Ok(Some(frame)),
155 Err(CanError::Timeout) => Ok(None),
156 Err(e) => Err(e),
157 }
158 }
159 fn send_timeout(&mut self, frame: PiperFrame, _timeout: Duration) -> Result<(), CanError> {
160 self.send(frame)
161 }
162}
163
164pub trait RxAdapter {
165 fn receive(&mut self) -> Result<PiperFrame, CanError>;
166}
167
168pub trait TxAdapter {
169 fn send(&mut self, frame: PiperFrame) -> Result<(), CanError>;
170}
171
172pub trait SplittableAdapter: CanAdapter {
173 type RxAdapter: RxAdapter;
174 type TxAdapter: TxAdapter;
175 fn split(self) -> Result<(Self::RxAdapter, Self::TxAdapter), CanError>;
176}