cantact/
lib.rs

1//! This crate provides a userspace driver for the CANtact family of
2//! Controller Area Network (CAN) devices.
3//!
4//! The rust library provided by this crate can be used directly to build
5//! applications for CANtact. The crate also provides bindings for other
6//! langauges.
7
8#![warn(missing_docs)]
9
10use std::fmt;
11use std::sync::{Arc, RwLock};
12use std::thread;
13use std::time;
14
15use crossbeam_channel::RecvError;
16
17use serde::{Deserialize, Serialize};
18
19mod device;
20use device::gsusb::*;
21use device::*;
22
23pub mod c;
24/// Implementation of Python bindings
25#[cfg(feature = "python")]
26pub mod python;
27
28/// Errors generated by this library
29#[derive(Debug)]
30pub enum Error {
31    /// Errors from device interaction.
32    DeviceError(device::Error),
33    /// The device could not be found, or the user does not have permissions to access it.
34    DeviceNotFound,
35    /// Timeout while communicating with the device.
36    Timeout,
37    /// Attempted to perform an action on a device that is running when this is not allowed.
38    Running,
39    /// Attempted to perform an action on a device that is not running when this is not allowed.
40    NotRunning,
41    /// Requested channel index does not exist on device.
42    InvalidChannel,
43    /// The requested bitrate cannot be set within an acceptable tolerance
44    InvalidBitrate(u32),
45    /// The requested set of features is not supported by the device
46    UnsupportedFeature(&'static str),
47}
48impl From<device::Error> for Error {
49    fn from(e: device::Error) -> Error {
50        // TODO
51        // this could do a much better job of converting
52        Error::DeviceError(e)
53    }
54}
55
56/// Controller Area Network Frame
57#[derive(Debug, Clone)]
58pub struct Frame {
59    /// CAN frame arbitration ID.
60    pub can_id: u32,
61
62    /// CAN frame Data Length Code (DLC).
63    pub can_dlc: u8,
64
65    /// Device channel used to send or receive the frame.
66    pub channel: u8,
67
68    /// Frame data contents.
69    pub data: Vec<u8>,
70
71    /// Extended (29 bit) arbitration identifier if true,
72    /// standard (11 bit) arbitration identifer if false.
73    pub ext: bool,
74
75    /// CAN Flexible Data (CAN-FD) frame flag.
76    pub fd: bool,
77
78    /// CAN-FD Bit Rate Switch (BRS) flag.
79    pub brs: bool,
80
81    /// CAN-FD Error State Indicator (ESI) flag.
82    pub esi: bool,
83
84    /// Loopback flag. When true, frame was sent by this device/channel.
85    /// False for received frames.
86    pub loopback: bool,
87
88    /// Error frame flag.
89    pub err: bool,
90
91    /// Remote Transmission Request (RTR) flag.
92    pub rtr: bool,
93
94    /// Timestamp when frame was received
95    pub timestamp: Option<time::Duration>,
96}
97impl Frame {
98    fn data_as_array(&self) -> [u8; 64] {
99        let mut data = [0u8; 64];
100        data[..64].clone_from_slice(&self.data[..64]);
101        data
102    }
103    // convert to a frame format expected by the device
104    fn to_host_frame(&self) -> HostFrame {
105        // if frame is extended, set the extended bit in host frame CAN ID
106        let mut can_id = if self.ext {
107            self.can_id | GSUSB_EXT_FLAG
108        } else {
109            self.can_id
110        };
111        // apply RTR and ERR flags
112        can_id = if self.rtr {
113            can_id | GSUSB_RTR_FLAG
114        } else {
115            can_id
116        };
117        can_id = if self.err {
118            can_id | GSUSB_ERR_FLAG
119        } else {
120            can_id
121        };
122
123        HostFrame {
124            echo_id: 1,
125            flags: 0,
126            reserved: 0,
127            can_id,
128            can_dlc: self.can_dlc,
129            channel: self.channel,
130            data: self.data_as_array(),
131        }
132    }
133    /// Returns a default CAN frame with all values set to zero/false.
134    pub fn default() -> Frame {
135        Frame {
136            can_id: 0,
137            can_dlc: 0,
138            data: vec![0; 64],
139            channel: 0,
140            ext: false,
141            fd: false,
142            loopback: false,
143            rtr: false,
144            brs: false,
145            esi: false,
146            err: false,
147            timestamp: None,
148        }
149    }
150    fn from_host_frame(hf: HostFrame) -> Frame {
151        // check the extended bit of host frame
152        // if set, frame is extended
153        let ext = (hf.can_id & GSUSB_EXT_FLAG) > 0;
154        // check the RTR and ERR bits of host frame ID
155        let rtr = (hf.can_id & GSUSB_RTR_FLAG) > 0;
156        let err = (hf.can_id & GSUSB_ERR_FLAG) > 0;
157        // remove flags from CAN ID
158        let can_id = hf.can_id & 0x1FFF_FFFF;
159        // loopback frame if echo_id is not -1
160        let loopback = hf.echo_id != GSUSB_RX_ECHO_ID;
161        // apply FD flags
162        let fd = (hf.flags & GS_CAN_FLAG_FD) > 0;
163        let brs = (hf.flags & GS_CAN_FLAG_BRS) > 0;
164        let esi = (hf.flags & GS_CAN_FLAG_ESI) > 0;
165
166        Frame {
167            can_id,
168            can_dlc: hf.can_dlc,
169            data: hf.data.to_vec(),
170            channel: hf.channel,
171            ext,
172            loopback,
173            rtr,
174            fd,
175            brs,
176            esi,
177            err,
178            timestamp: None,
179        }
180    }
181
182    /// Return the length of data in this frame. This is the DLC for non-FD frames.
183    pub fn data_len(&self) -> usize {
184        match self.can_dlc {
185            0..=8 => self.can_dlc as usize,
186            9 => 12,
187            10 => 16,
188            11 => 20,
189            12 => 24,
190            13 => 32,
191            14 => 48,
192            15 => 64,
193            16..=u8::MAX => panic!("invalid DLC value"),
194        }
195    }
196}
197
198/// Configuration for a device's CAN channel.
199#[derive(Debug, Serialize, Deserialize, Clone)]
200pub struct Channel {
201    /// Bitrate of the channel in bits/second
202    pub bitrate: u32,
203    /// When true, channel should be enabled when device starts
204    pub enabled: bool,
205    /// When true, device is configured in hardware loopback mode
206    pub loopback: bool,
207    /// When true, device will not transmit on the bus.
208    pub monitor: bool,
209    /// When true, CAN FD is enabled for the device
210    pub fd: bool,
211    /// CAN FD data bitrate of the channel in bits/second
212    pub data_bitrate: u32,
213}
214
215/// Interface for interacting with CANtact devices
216pub struct Interface {
217    dev: Device,
218    running: Arc<RwLock<bool>>,
219
220    can_clock: u32,
221    // zero indexed (0 = 1 channel, 1 = 2 channels, etc...)
222    channel_count: usize,
223    sw_version: u32,
224    hw_version: u32,
225    features: u32,
226
227    channels: Vec<Channel>,
228}
229
230impl fmt::Debug for Interface {
231    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
232        f.debug_struct("Interface")
233            .field("running", &(*self.running.read().unwrap()))
234            .field("can_clock", &self.can_clock)
235            .field("channel_count", &self.channel_count)
236            .field("sw_version", &self.sw_version)
237            .field("hw_version", &self.hw_version)
238            .field("channels", &self.channels)
239            .finish()
240    }
241}
242
243impl Interface {
244    /// Creates a new interface. This always selects the first device found by
245    /// libusb. If no device is found, Error::DeviceNotFound is returned.
246    pub fn new() -> Result<Interface, Error> {
247        let mut dev = match Device::new(UsbContext::new()) {
248            Ok(d) => d,
249            Err(_) => return Err(Error::DeviceNotFound),
250        };
251
252        let dev_config = dev.get_device_config()?;
253        let bt_consts = dev.get_bit_timing_consts()?;
254
255        let channel_count = dev_config.icount as usize;
256
257        let mut channels = Vec::new();
258        // note: channel_count is zero indexed
259        for _ in 0..(channel_count + 1) {
260            channels.push(Channel {
261                bitrate: 0,
262                enabled: true,
263                loopback: false,
264                monitor: false,
265                fd: false,
266                data_bitrate: 0,
267            });
268        }
269
270        let i = Interface {
271            dev,
272            running: Arc::new(RwLock::from(false)),
273
274            channel_count,
275            can_clock: bt_consts.fclk_can,
276            sw_version: dev_config.sw_version,
277            hw_version: dev_config.hw_version,
278            features: bt_consts.feature,
279
280            channels,
281        };
282
283        Ok(i)
284    }
285
286    /// Start CAN communication on all configured channels.
287    ///
288    /// After starting the device, `Interface.send` can be used to send frames.
289    /// For every received frame, the `rx_callback` closure will be called.
290    pub fn start(
291        &mut self,
292        mut rx_callback: impl FnMut(Frame) + Sync + Send + 'static,
293    ) -> Result<(), Error> {
294        // tell the device to go on bus
295        for (i, ch) in self.channels.iter().enumerate() {
296            let mut flags = 0;
297            // for each mode flag, check that the feature is supported before applying feature
298            // this is necessary since the feature flags are pub
299            if ch.monitor {
300                if (self.features & GS_CAN_FEATURE_LISTEN_ONLY) == 0 {
301                    return Err(Error::UnsupportedFeature("Monitor"));
302                }
303                flags |= GS_CAN_MODE_LISTEN_ONLY;
304            }
305            if ch.loopback {
306                if (self.features & GS_CAN_FEATURE_LOOP_BACK) == 0 {
307                    return Err(Error::UnsupportedFeature("Loopback"));
308                }
309                flags |= GS_CAN_MODE_LOOP_BACK;
310            }
311            if ch.fd {
312                if !self.supports_fd() {
313                    return Err(Error::UnsupportedFeature("FD"));
314                }
315                flags |= GS_CAN_MODE_FD;
316            }
317
318            let mode = Mode {
319                mode: CanMode::Start as u32,
320                flags,
321            };
322            if ch.enabled {
323                self.dev.set_mode(i as u16, mode).unwrap();
324            }
325        }
326
327        {
328            *self.running.write().unwrap() = true;
329        }
330
331        // rx callback thread
332        let can_rx = self.dev.can_rx_recv.clone();
333        let running = Arc::clone(&self.running);
334        let start_time = time::Instant::now();
335        thread::spawn(move || {
336            while *running.read().unwrap() {
337                match can_rx.recv() {
338                    Ok(hf) => {
339                        let mut f = Frame::from_host_frame(hf);
340                        f.timestamp = Some(time::Instant::now().duration_since(start_time));
341                        rx_callback(f)
342                    }
343                    Err(RecvError) => {
344                        // channel disconnected
345                        break;
346                    }
347                }
348            }
349        });
350
351        self.dev.start_transfers().unwrap();
352        Ok(())
353    }
354
355    /// Stop CAN communication on all channels.
356    pub fn stop(&mut self) -> Result<(), Error> {
357        // TODO multi-channel
358        for (i, ch) in self.channels.iter().enumerate() {
359            let mode = Mode {
360                mode: CanMode::Reset as u32,
361                flags: 0,
362            };
363            if ch.enabled {
364                self.dev.set_mode(i as u16, mode).unwrap();
365            }
366        }
367
368        self.dev.stop_transfers().unwrap();
369        *self.running.write().unwrap() = false;
370        Ok(())
371    }
372
373    /// Set bitrate for specified channel to requested bitrate value in bits per second.
374    pub fn set_bitrate(&mut self, channel: usize, bitrate: u32) -> Result<(), Error> {
375        if channel > self.channel_count {
376            return Err(Error::InvalidChannel);
377        }
378
379        let bt = calculate_bit_timing(self.can_clock, bitrate)?;
380        self.dev
381            .set_bit_timing(channel as u16, bt)
382            .expect("failed to set bit timing");
383
384        self.channels[channel].bitrate = bitrate;
385        Ok(())
386    }
387
388    /// Set CAN FD data bitrate for specified channel to requested bitrate value in bits per second.
389    pub fn set_data_bitrate(&mut self, channel: usize, bitrate: u32) -> Result<(), Error> {
390        if !self.supports_fd() {
391            return Err(Error::UnsupportedFeature("FD"));
392        }
393
394        if channel > self.channel_count {
395            return Err(Error::InvalidChannel);
396        }
397
398        let bt = calculate_bit_timing(self.can_clock, bitrate)?;
399        self.dev
400            .set_data_bit_timing(channel as u16, bt)
401            .expect("failed to set bit timing");
402
403        self.channels[channel].data_bitrate = bitrate;
404        Ok(())
405    }
406
407    /// Set a custom bit timing for the specified channel.
408    pub fn set_bit_timing(
409        &mut self,
410        channel: usize,
411        brp: u32,
412        phase_seg1: u32,
413        phase_seg2: u32,
414        sjw: u32,
415    ) -> Result<(), Error> {
416        let bt = BitTiming {
417            brp,
418            prop_seg: 0,
419            phase_seg1,
420            phase_seg2,
421            sjw,
422        };
423        self.dev
424            .set_bit_timing(channel as u16, bt)
425            .expect("failed to set bit timing");
426        Ok(())
427    }
428
429    /// Enable or disable a channel's listen only mode. When this mode is enabled,
430    /// the device will not transmit any frames, errors, or acknowledgements.
431    pub fn set_monitor(&mut self, channel: usize, enabled: bool) -> Result<(), Error> {
432        if self.features & GS_CAN_FEATURE_LISTEN_ONLY == 0 {
433            return Err(Error::UnsupportedFeature("Monitor"));
434        }
435        if channel > self.channel_count {
436            return Err(Error::InvalidChannel);
437        }
438        if *self.running.read().unwrap() {
439            return Err(Error::Running);
440        }
441
442        self.channels[channel].monitor = enabled;
443        Ok(())
444    }
445
446    /// Enable or disable a channel's listen only mode. When this mode is enabled,
447    /// the device will not transmit any frames, errors, or acknowledgements.
448    pub fn set_enabled(&mut self, channel: usize, enabled: bool) -> Result<(), Error> {
449        if channel > self.channel_count {
450            return Err(Error::InvalidChannel);
451        }
452        if *self.running.read().unwrap() {
453            return Err(Error::Running);
454        }
455
456        self.channels[channel].enabled = enabled;
457        Ok(())
458    }
459
460    /// Enable or disable a channel's loopback mode. When this mode is enabled,
461    /// frames sent by the device will be received by the device
462    /// *as if they had been sent by another node on the bus*.
463    ///
464    /// This mode is primarily intended for device testing!
465    pub fn set_loopback(&mut self, channel: usize, enabled: bool) -> Result<(), Error> {
466        if self.features & GS_CAN_FEATURE_LOOP_BACK == 0 {
467            return Err(Error::UnsupportedFeature("Loopback"));
468        }
469        if channel > self.channel_count {
470            return Err(Error::InvalidChannel);
471        }
472        if *self.running.read().unwrap() {
473            return Err(Error::Running);
474        }
475
476        self.channels[channel].loopback = enabled;
477        Ok(())
478    }
479
480    /// Enable or disable CAN FD support for a channel
481    pub fn set_fd(&mut self, channel: usize, enabled: bool) -> Result<(), Error> {
482        if !self.supports_fd() {
483            return Err(Error::UnsupportedFeature("FD"));
484        }
485        if channel > self.channel_count {
486            return Err(Error::InvalidChannel);
487        }
488        if *self.running.read().unwrap() {
489            return Err(Error::Running);
490        }
491
492        self.channels[channel].fd = enabled;
493        Ok(())
494    }
495
496    /// Returns true if device suports CAN-FD operation, false otherwise.
497    pub fn supports_fd(&self) -> bool {
498        (self.features & GS_CAN_FEATURE_FD) > 0
499    }
500
501    /// Send a CAN frame using the device
502    pub fn send(&mut self, f: Frame) -> Result<(), Error> {
503        if !*self.running.read().unwrap() {
504            return Err(Error::NotRunning);
505        }
506
507        self.dev.send(f.to_host_frame()).unwrap();
508        Ok(())
509    }
510
511    /// Returns the number of channels this Interface has
512    pub fn channels(&self) -> usize {
513        self.channel_count + 1
514    }
515}
516
517fn calculate_bit_timing(clk: u32, bitrate: u32) -> Result<BitTiming, Error> {
518    let max_brp = 32;
519    let min_seg1 = 3;
520    let max_seg1 = 18;
521    let min_seg2 = 2;
522    let max_seg2 = 8;
523    let tolerances = vec![0.0, 0.1 / 100.0, 0.5 / 100.0];
524
525    for tolerance in tolerances {
526        let tmp = clk as f32 / bitrate as f32;
527        for brp in 1..(max_brp + 1) {
528            let btq = tmp / brp as f32;
529            let btq_rounded = btq.round() as u32;
530
531            if (4..=32).contains(&btq_rounded) {
532                let err = ((btq / (btq_rounded as f32) - 1.0) * 10000.0).round() / 10000.0;
533                if err.abs() > tolerance {
534                    // error is not acceptable
535                    continue;
536                }
537            }
538
539            for seg1 in min_seg1..max_seg1 {
540                // subtract 1 from seg2 to account for propagation phase
541                let seg2 = btq_rounded - seg1 - 1;
542                if seg2 < min_seg2 || seg2 > max_seg2 {
543                    // invalid seg2 value
544                    continue;
545                }
546                // brp, seg1, and seg2 are all valid
547                return Ok(BitTiming {
548                    brp,
549                    prop_seg: 0,
550                    phase_seg1: seg1,
551                    phase_seg2: seg2,
552                    sjw: 1,
553                });
554            }
555        }
556    }
557    Err(Error::InvalidBitrate(bitrate))
558}
559
560#[allow(dead_code)]
561fn effective_bitrate(clk: u32, bt: BitTiming) -> u32 {
562    clk / bt.brp / (bt.prop_seg + bt.phase_seg1 + bt.phase_seg2 + 1)
563}
564
565#[cfg(test)]
566mod tests {
567    use super::*;
568    #[test]
569    fn test_bit_timing() {
570        let clk = 24000000;
571        let bitrates = vec![1000000, 500000, 250000, 125000, 33333];
572        for b in bitrates {
573            let bt = calculate_bit_timing(clk, b).unwrap();
574
575            // ensure error < 0.5%
576            println!("{:?}", &bt);
577            let err = 100.0 * (1.0 - (effective_bitrate(clk, bt) as f32 / b as f32).abs());
578            println!("{:?}", err);
579            assert!(err < 0.5);
580        }
581    }
582}