1use std::ffi::CString;
6
7use crate::bus::UsbBus;
8use crate::channel::Channel;
9use crate::df::{
10 HasAcceptanceFilter11Bit, HasAcceptanceFilter29Bit, HasAllowEchoFrames, HasAllowErrorFrames,
11 HasAllowRTRFrames, HasAllowStatusFrames, HasMessageFilter, HasReceiveStatus,
12 HasSetAcceptanceFilter11Bit, HasSetAcceptanceFilter29Bit, HasSetAllowEchoFrames,
13 HasSetAllowErrorFrames, HasSetAllowRTRFrames, HasSetAllowStatusFrames, HasSetMessageFilter,
14 HasSetReceiveStatus,
15};
16use crate::error::{CanError, CanOkError};
17use crate::hw::{
18 HasChannelIdentifying, HasControllerNumber, HasDeviceId, HasDevicePartNumber, HasHardwareName,
19 HasSetControllerNumber, HasSetDeviceId,
20};
21use crate::info::{
22 HasBitrateInfo, HasChannelFeatures, HasChannelVersion, HasDataBusSpeed, HasFirmwareVersion,
23 HasNominalBusSpeed,
24};
25use crate::io::{
26 HasAnalogValue, HasDigitalConfiguration, HasDigitalValue, HasSetDigitalClear,
27 HasSetDigitalConfiguration, HasSetDigitalSet, HasSetDigitalValue,
28};
29use crate::peak_lib;
30use crate::socket::{Baudrate, CanBitTiming, CanFdBitTiming, HasRecvCan, HasRecvCanFd, HasSendCan, HasSendCanFd, Socket};
31use crate::special::{
32 HasBusOffAutoreset, HasFiveVoltsPower, HasInterframeDelay, HasListenOnly,
33 HasSetBusOffAutoreset, HasSetFiveVoltsPower, HasSetInterframeDelay, HasSetListenOnly,
34};
35use crate::trace::{
36 HasSetTraceConfigure, HasSetTraceLocation, HasSetTraceSize, HasSetTraceStatus,
37 HasTraceConfigure, HasTraceLocation, HasTraceSize, HasTraceStatus,
38};
39
40const CANFD_CLOCK_HZ: u32 = 80_000_000;
46
47fn calculate_btr0btr1(timing: &CanBitTiming) -> u16 {
49 ((((timing.tseg2 - 1) & 0x07) as u16) << 4)
50 | (((timing.tseg1 - 1) & 0x0F) as u16)
51 | ((((timing.prescaler - 1) & 0x3F) as u16) << 8)
52 | ((((timing.sjw - 1) & 0x03) as u16) << 14)
53}
54
55fn build_timing_string(timing: &CanFdBitTiming) -> String {
57 format!(
58 "f_clock={},nom_brp={},nom_tseg1={},nom_tseg2={},nom_sjw={},data_brp={},data_tseg1={},data_tseg2={},data_sjw={}",
59 CANFD_CLOCK_HZ,
60 timing.nom_prescaler,
61 timing.nom_tseg1,
62 timing.nom_tseg2,
63 timing.nom_sjw,
64 timing.data_prescaler,
65 timing.data_tseg1,
66 timing.data_tseg2,
67 timing.data_sjw,
68 )
69}
70
71#[derive(Debug, PartialEq)]
72pub struct UsbCanSocket {
73 handle: u16,
74}
75
76impl UsbCanSocket {
77 pub fn open(bus: UsbBus, baud: Baudrate) -> Result<UsbCanSocket, CanError> {
94 let handle = bus.into();
95 let code = unsafe { peak_lib()?.CAN_Initialize(handle, baud.into(), 0, 0, 0) };
96
97 match CanOkError::try_from(code) {
98 Ok(CanOkError::Ok) => Ok(UsbCanSocket { handle }),
99 Ok(CanOkError::Err(err)) => Err(err),
100 Err(_) => Err(CanError::Unknown),
101 }
102 }
103
104 pub fn open_with_usb_bus(bus: UsbBus) -> UsbCanSocket {
105 let handle = bus.into();
106 UsbCanSocket { handle }
107 }
108
109 pub fn open_with_timing(bus: UsbBus, timing: &CanBitTiming) -> Result<UsbCanSocket, CanError> {
124 let handle = bus.into();
125 let btr0btr1 = calculate_btr0btr1(timing);
126 let code = unsafe { peak_lib()?.CAN_Initialize(handle, btr0btr1, 0, 0, 0) };
127
128 match CanOkError::try_from(code) {
129 Ok(CanOkError::Ok) => Ok(UsbCanSocket { handle }),
130 Ok(CanOkError::Err(err)) => Err(err),
131 Err(_) => Err(CanError::Unknown),
132 }
133 }
134
135 pub fn open_fd_with_timing(bus: UsbBus, timing: &CanFdBitTiming) -> Result<UsbCanSocket, CanError> {
151 let handle = bus.into();
152 let timing_str = build_timing_string(timing);
153
154 let mut timing_bytes = CString::new(timing_str)
155 .map_err(|_| CanError::Unknown)?
156 .into_bytes_with_nul();
157
158 let code = unsafe { peak_lib()?.CAN_InitializeFD(handle, timing_bytes.as_mut_ptr().cast()) };
159
160 match CanOkError::try_from(code) {
161 Ok(CanOkError::Ok) => Ok(UsbCanSocket { handle }),
162 Ok(CanOkError::Err(err)) => Err(err),
163 Err(_) => Err(CanError::Unknown),
164 }
165 }
166}
167
168impl Drop for UsbCanSocket {
171 fn drop(&mut self) {
172 let Ok(peak_lib) = peak_lib() else {
173 return;
174 };
175 unsafe { peak_lib.CAN_Uninitialize(self.handle) };
176 }
177}
178
179impl Socket for UsbCanSocket {
182 fn handle(&self) -> u16 {
183 self.handle
184 }
185}
186
187impl Channel for UsbCanSocket {
190 fn channel(&self) -> u16 {
191 self.handle
192 }
193}
194
195impl HasRecvCan for UsbCanSocket {}
198impl HasSendCan for UsbCanSocket {}
199
200impl HasRecvCanFd for UsbCanSocket {}
201impl HasSendCanFd for UsbCanSocket {}
202
203impl HasChannelIdentifying for UsbCanSocket {}
206
207impl HasDeviceId for UsbCanSocket {}
208impl HasSetDeviceId for UsbCanSocket {}
209
210impl HasHardwareName for UsbCanSocket {}
211
212impl HasControllerNumber for UsbCanSocket {}
213impl HasSetControllerNumber for UsbCanSocket {}
214
215impl HasDevicePartNumber for UsbCanSocket {}
216
217impl HasChannelVersion for UsbCanSocket {}
220
221impl HasChannelFeatures for UsbCanSocket {}
222
223impl HasBitrateInfo for UsbCanSocket {}
224
225impl HasNominalBusSpeed for UsbCanSocket {}
226
227impl HasDataBusSpeed for UsbCanSocket {}
228
229impl HasFirmwareVersion for UsbCanSocket {}
230
231impl HasFiveVoltsPower for UsbCanSocket {}
234impl HasSetFiveVoltsPower for UsbCanSocket {}
235
236impl HasBusOffAutoreset for UsbCanSocket {}
237impl HasSetBusOffAutoreset for UsbCanSocket {}
238
239impl HasListenOnly for UsbCanSocket {}
240impl HasSetListenOnly for UsbCanSocket {}
241
242impl HasInterframeDelay for UsbCanSocket {}
243impl HasSetInterframeDelay for UsbCanSocket {}
244
245impl HasMessageFilter for UsbCanSocket {}
248impl HasSetMessageFilter for UsbCanSocket {}
249
250impl HasReceiveStatus for UsbCanSocket {}
251impl HasSetReceiveStatus for UsbCanSocket {}
252
253impl HasAllowStatusFrames for UsbCanSocket {}
254impl HasSetAllowStatusFrames for UsbCanSocket {}
255
256impl HasAllowRTRFrames for UsbCanSocket {}
257impl HasSetAllowRTRFrames for UsbCanSocket {}
258
259impl HasAllowErrorFrames for UsbCanSocket {}
260impl HasSetAllowErrorFrames for UsbCanSocket {}
261
262impl HasAllowEchoFrames for UsbCanSocket {}
263impl HasSetAllowEchoFrames for UsbCanSocket {}
264
265impl HasAcceptanceFilter11Bit for UsbCanSocket {}
266impl HasSetAcceptanceFilter11Bit for UsbCanSocket {}
267
268impl HasAcceptanceFilter29Bit for UsbCanSocket {}
269impl HasSetAcceptanceFilter29Bit for UsbCanSocket {}
270
271impl HasTraceLocation for UsbCanSocket {}
274impl HasSetTraceLocation for UsbCanSocket {}
275
276impl HasTraceStatus for UsbCanSocket {}
277impl HasSetTraceStatus for UsbCanSocket {}
278
279impl HasTraceSize for UsbCanSocket {}
280impl HasSetTraceSize for UsbCanSocket {}
281
282impl HasTraceConfigure for UsbCanSocket {}
283impl HasSetTraceConfigure for UsbCanSocket {}
284
285impl HasDigitalConfiguration for UsbCanSocket {}
288impl HasSetDigitalConfiguration for UsbCanSocket {}
289
290impl HasDigitalValue for UsbCanSocket {}
291impl HasSetDigitalValue for UsbCanSocket {}
292
293impl HasSetDigitalSet for UsbCanSocket {}
294
295impl HasSetDigitalClear for UsbCanSocket {}
296
297impl HasAnalogValue for UsbCanSocket {}
298#[cfg(test)]
299mod tests {
300 use super::*;
301
302 #[test]
303 fn btr0btr1_encoding() {
304 let test_cases = vec![
306 ((1, 1, 1, 1), 0x0000), ((64, 4, 16, 8), 0xFF7F), ((8, 1, 13, 2), 0x071C), ((32, 1, 13, 2), 0x1F1C), ((4, 1, 13, 2), 0x031C), ];
312
313 for ((prescaler, sjw, tseg1, tseg2), expected) in test_cases {
314 let timing = CanBitTiming::new(prescaler, sjw, tseg1, tseg2).unwrap();
315 let btr0btr1 = calculate_btr0btr1(&timing);
316 assert_eq!(btr0btr1, expected,
317 "Failed for prescaler={}, sjw={}, tseg1={}, tseg2={}",
318 prescaler, sjw, tseg1, tseg2);
319 }
320
321 let timing = CanBitTiming::new(64, 4, 16, 8).unwrap();
323 let btr0btr1 = calculate_btr0btr1(&timing);
324 assert_eq!(btr0btr1 & 0x000F, 15); assert_eq!((btr0btr1 >> 4) & 0x07, 7); assert_eq!((btr0btr1 >> 8) & 0x3F, 63); assert_eq!((btr0btr1 >> 14) & 0x03, 3); }
329
330 #[test]
331 fn fd_timing_string_format() {
332 let test_cases = vec![
334 (
335 (1, 1, 1, 1, 1, 1, 1, 1),
336 "f_clock=80000000,nom_brp=1,nom_tseg1=1,nom_tseg2=1,nom_sjw=1,data_brp=1,data_tseg1=1,data_tseg2=1,data_sjw=1"
337 ),
338 (
339 (1024, 128, 256, 128, 1024, 16, 32, 16),
340 "f_clock=80000000,nom_brp=1024,nom_tseg1=256,nom_tseg2=128,nom_sjw=128,data_brp=1024,data_tseg1=32,data_tseg2=16,data_sjw=16"
341 ),
342 (
343 (10, 4, 13, 2, 5, 2, 6, 1), "f_clock=80000000,nom_brp=10,nom_tseg1=13,nom_tseg2=2,nom_sjw=4,data_brp=5,data_tseg1=6,data_tseg2=1,data_sjw=2"
345 ),
346 (
347 (5, 2, 13, 2, 2, 2, 13, 2), "f_clock=80000000,nom_brp=5,nom_tseg1=13,nom_tseg2=2,nom_sjw=2,data_brp=2,data_tseg1=13,data_tseg2=2,data_sjw=2"
349 ),
350 ];
351
352 for ((nom_brp, nom_sjw, nom_tseg1, nom_tseg2, data_brp, data_sjw, data_tseg1, data_tseg2), expected) in test_cases {
353 let timing = CanFdBitTiming::new(nom_brp, nom_sjw, nom_tseg1, nom_tseg2, data_brp, data_sjw, data_tseg1, data_tseg2).unwrap();
354 let actual = build_timing_string(&timing);
355 assert_eq!(actual, expected);
356 }
357 }
358
359 #[test]
360 fn fd_timing_string_structure() {
361 let timing = CanFdBitTiming::new(10, 4, 13, 2, 5, 2, 6, 1).unwrap();
362 let timing_str = build_timing_string(&timing);
363
364 assert_eq!(timing_str.matches(',').count(), 8);
366 assert!(!timing_str.contains(' '));
367 assert!(timing_str.starts_with("f_clock=80000000,"));
368 assert!(timing_str.ends_with("data_sjw=2"));
369 assert!(!timing_str.contains(|c: char| c.is_control()));
370
371 let parts: Vec<&str> = timing_str.split(',').collect();
373 assert_eq!(parts.len(), 9);
374 assert!(parts[0].starts_with("f_clock="));
375 assert!(parts[1].starts_with("nom_brp="));
376 assert!(parts[4].starts_with("nom_sjw="));
377 assert!(parts[5].starts_with("data_brp="));
378 assert!(parts[8].starts_with("data_sjw="));
379 }
380}