host_can/adapter/pcan/
mod.rs1use std::ffi::c_int;
4use std::time::{Duration, Instant};
5use std::u32;
6
7use crate::adapter::Adapter;
8use crate::frame::{CanFrame, Frame};
9use crate::id;
10
11mod bind;
12use bind::{TPCANMsg, TPCANTimestamp, libPCBUSB};
13
14use super::{AdapterBaud, AdapterError};
15
16type PcanChannel = u16;
17type PcanBaud = u16;
18
19pub struct PcanAdapter {
20 lib: libPCBUSB,
21 channel: PcanChannel,
22 fd: c_int,
23}
24
25fn try_as_channel(name: &str) -> Result<PcanChannel, AdapterError> {
26 Ok(match name {
27 "" | "1" => bind::PCAN_USBBUS1 as PcanChannel,
28 "2" => bind::PCAN_USBBUS2 as PcanChannel,
29 "3" => bind::PCAN_USBBUS3 as PcanChannel,
30 "4" => bind::PCAN_USBBUS4 as PcanChannel,
31 "5" => bind::PCAN_USBBUS5 as PcanChannel,
32 "6" => bind::PCAN_USBBUS6 as PcanChannel,
33 "7" => bind::PCAN_USBBUS7 as PcanChannel,
34 "8" => bind::PCAN_USBBUS8 as PcanChannel,
35 _ => return Err(AdapterError::UnknownDevice),
36 })
37}
38
39fn try_as_baud(baud: u32) -> Result<PcanBaud, AdapterError> {
40 Ok(match baud {
41 10_000 => bind::PCAN_BAUD_10K as PcanBaud,
42 20_000 => bind::PCAN_BAUD_20K as PcanBaud,
43 50_000 => bind::PCAN_BAUD_50K as PcanBaud,
44 100_000 => bind::PCAN_BAUD_100K as PcanBaud,
45 125_000 => bind::PCAN_BAUD_125K as PcanBaud,
46 250_000 => bind::PCAN_BAUD_250K as PcanBaud,
47 500_000 => bind::PCAN_BAUD_500K as PcanBaud,
48 800_000 => bind::PCAN_BAUD_800K as PcanBaud,
49 1_000_000 => bind::PCAN_BAUD_1M as PcanBaud,
50 _ => return Err(AdapterError::UnsupportedBaud),
51 })
52}
53
54impl Default for TPCANMsg {
55 fn default() -> Self {
56 Self {
57 ID: 0,
58 MSGTYPE: 0,
59 LEN: 0,
60 DATA: [0; 8],
61 }
62 }
63}
64
65impl Default for TPCANTimestamp {
66 fn default() -> Self {
67 Self {
68 millis: 0,
69 millis_overflow: 0,
70 micros: 0,
71 }
72 }
73}
74
75impl PcanAdapter {
76 pub fn new(
80 name: &str,
81 baud: AdapterBaud,
82 ) -> Result<Self, Box<dyn std::error::Error>> {
83 let lib = unsafe { libPCBUSB::new("libPCBUSB.dylib") }?;
86
87 let channel = try_as_channel(name)?;
88
89 let status = unsafe {
90 lib.CAN_Initialize(
91 channel,
92 try_as_baud(baud)?,
93 bind::PCAN_USB as u8,
94 0,
95 0,
96 )
97 };
98 match status {
99 0 => {
100 let mut fd: c_int = 0;
101 let info_ptr: *mut c_int = &mut fd;
102 match unsafe {
103 lib.CAN_GetValue(
104 channel,
105 bind::PCAN_RECEIVE_EVENT as u8,
106 info_ptr as *mut ::std::os::raw::c_void,
107 4,
108 )
109 } {
110 bind::PCAN_ERROR_OK => Ok(Self { lib, fd, channel }),
111 _ => Err(Box::new(AdapterError::OpenFailed)),
112 }
113 }
114 _ => Err(Box::new(AdapterError::OpenFailed)),
115 }
116 }
117}
118
119impl Drop for PcanAdapter {
120 fn drop(&mut self) {
121 unsafe { self.lib.CAN_Uninitialize(self.channel.into()) };
122 }
123}
124
125impl Adapter for PcanAdapter {
126 fn send(&self, frame: &CanFrame) -> Result<(), Box<AdapterError>> {
127 let mut data: [u8; 8] = [0u8; 8];
128 data[..frame.dlc()].copy_from_slice(frame.data());
129
130 let mut msg = bind::TPCANMsg {
131 ID: id::raw_u32(frame.id()),
132 MSGTYPE: if frame.is_extended() {
133 bind::PCAN_MODE_EXTENDED
134 } else {
135 bind::PCAN_MODE_STANDARD
136 } as u8,
137 LEN: frame.dlc() as u8,
138 DATA: data,
139 };
140
141 let status = unsafe {
142 self.lib
143 .CAN_Write(self.channel.into(), &mut msg as *mut bind::TPCANMsg)
144 };
145 match status {
146 0 => Ok(()),
147 _ => Err(Box::new(AdapterError::WriteFailed)),
148 }
149 }
150
151 fn recv(
152 &self,
153 timeout: Option<Duration>,
154 ) -> Result<CanFrame, Box<AdapterError>> {
155 use nix::poll::{PollFd, PollFlags, PollTimeout, poll};
156 use std::os::unix::io::BorrowedFd;
157
158 let start_time = Instant::now();
159
160 let mut msg = bind::TPCANMsg::default();
161 let mut timestamp = TPCANTimestamp::default();
162
163 loop {
164 let status = unsafe {
165 self.lib.CAN_Read(
166 self.channel.into(),
167 &mut msg as *mut bind::TPCANMsg,
168 &mut timestamp as *mut bind::TPCANTimestamp,
169 )
170 };
171
172 match status {
173 bind::PCAN_ERROR_OK => {
174 let id = match msg.MSGTYPE as u32 {
175 bind::PCAN_MODE_STANDARD => {
176 id::new_standard(msg.ID as u16)
177 }
178 bind::PCAN_MODE_EXTENDED => id::new_extended(msg.ID),
179 _ => return Err(Box::new(AdapterError::ReadFailed)),
180 }
181 .ok_or(Box::new(AdapterError::ReadFailed))?;
182
183 let frame =
184 CanFrame::new(id, &msg.DATA[..msg.LEN as usize])
185 .ok_or(Box::new(AdapterError::ReadFailed))?;
186 return Ok(frame);
187 }
188
189 bind::PCAN_ERROR_QRCVEMPTY => {
195 let poll_interval = match timeout {
196 Some(t) => {
197 let now = Instant::now();
198 let end = start_time + t;
199 if now >= end {
200 return Err(Box::new(
201 AdapterError::ReadTimeout,
202 ));
203 }
204
205 let remaining = (end - now).as_millis();
206
207 if remaining < 1000 {
208 PollTimeout::from(remaining as u16)
209 } else {
210 PollTimeout::from(1000u16)
211 }
212 }
213 None => PollTimeout::from(1000u16),
214 };
215
216 let pollfd = PollFd::new(
217 unsafe { BorrowedFd::borrow_raw(self.fd) },
218 PollFlags::POLLIN,
219 );
220 if poll(&mut [pollfd], poll_interval).is_err() {
221 return Err(Box::new(AdapterError::ReadFailed));
222 }
223 }
224
225 _ => return Err(Box::new(AdapterError::ReadFailed)),
226 }
227 }
228 }
229}