1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
//! SocketCAN support.
//!
//! The Linux kernel supports using CAN-devices through a network-like API
//! (see <https://www.kernel.org/doc/Documentation/networking/can.txt>). This
//! crate allows easy access to this functionality without having to wrestle
//! libc calls.
//!
//! # An introduction to CAN
//!
//! The CAN bus was originally designed to allow microcontrollers inside a
//! vehicle to communicate over a single shared bus. Messages called
//! *frames* are multicast to all devices on the bus.
//!
//! Every frame consists of an ID and a payload of up to 8 bytes. If two
//! devices attempt to send a frame at the same time, the device with the
//! higher ID will notice the conflict, stop sending and reattempt to sent its
//! frame in the next time slot. This means that the lower the ID, the higher
//! the priority. Since most devices have a limited buffer for outgoing frames,
//! a single device with a high priority (== low ID) can block communication
//! on that bus by sending messages too fast.
//!
//! The Linux socketcan subsystem makes the CAN bus available as a regular
//! networking device. Opening an network interface allows receiving all CAN
//! messages received on it. A device CAN be opened multiple times, every
//! client will receive all CAN frames simultaneously.
//!
//! Similarly, CAN frames can be sent to the bus by multiple client
//! simultaneously as well.
//!
//! # Hardware and more information
//!
//! More information on CAN [can be found on Wikipedia](). When not running on
//! an embedded platform with already integrated CAN components,
//! [Thomas Fischl's USBtin](http://www.fischl.de/usbtin/) (see
//! [section 2.4](http://www.fischl.de/usbtin/#socketcan)) is one of many ways
//! to get started.
//!
//! # RawFd
//!
//! Raw access to the underlying file descriptor and construction through
//! is available through the `AsRawFd`, `IntoRawFd` and `FromRawFd`
//! implementations.
//!
//! # Crate Features
//!
//! ### Default
//!
//! * **netlink** -
//!   Whether to include programmable CAN interface configuration capabilities
//!   based on netlink kernel communications. This brings in the
//!   [neli](https://docs.rs/neli/latest/neli/) library and its dependencies.
//!
//! ### Non-default
//!
//! * **utils** -
//!   Whether to build command-line utilities. This brings in additional
//!   dependencies like [anyhow](https://docs.rs/anyhow/latest/anyhow/) and
//!   [clap](https://docs.rs/clap/latest/clap/)
//!

// clippy: do not warn about things like "SocketCAN" inside the docs
#![allow(clippy::doc_markdown)]

mod err;
pub use err::{CanError, CanErrorDecodingFailure, CanSocketOpenError, ConstructionError};

mod frame;
pub use frame::CanFrame;

pub mod constants;

mod socket;
pub use socket::{CanSocket, CanFilter, ShouldRetry};

pub mod dump;

mod util;

#[cfg(feature = "netlink")]
mod nl;

#[cfg(feature = "netlink")]
pub use nl::CanInterface;

use std::io::ErrorKind;


impl embedded_hal::can::blocking::Can for CanSocket {
    type Frame = CanFrame;
    type Error = CanError;

    fn receive(&mut self) -> Result<Self::Frame, Self::Error> {
        match self.read_frame() {
            Ok(frame) => {
                if !frame.is_error() {
                    Ok(frame)
                } else {
                    Err(frame.error().unwrap_or(CanError::Unknown(0)))
                }
            },
            Err(e) => {
                let code = e.raw_os_error().unwrap_or(0);
                Err(CanError::Unknown(code as u32))
            },
        }
    }

    fn transmit(&mut self, frame: &Self::Frame) -> Result<(), Self::Error> {
        match self.write_frame_insist(frame) {
            Ok(_) => Ok(()),
            Err(e) => {
                let code = e.raw_os_error().unwrap_or(0);
                Err(CanError::Unknown(code as u32))
            },
        }
    }
}

impl embedded_hal::can::nb::Can for CanSocket {
    type Frame = CanFrame;
    type Error = CanError;

    fn receive(&mut self) -> nb::Result<Self::Frame, Self::Error> {
        match self.read_frame() {
            Ok(frame) => {
                if !frame.is_error() {
                    Ok(frame)
                } else {
                    let can_error = frame.error().unwrap_or(CanError::Unknown(0));
                    Err(nb::Error::Other(can_error))
                }
            },
            Err(e) => {
                let e = match e.kind() {
                    ErrorKind::WouldBlock => nb::Error::WouldBlock,
                    _ => {
                        let code = e.raw_os_error().unwrap_or(0);
                        nb::Error::Other(CanError::Unknown(code as u32))
                    }
                };
                Err(e)
            }
        }
    }

    fn transmit(&mut self, frame: &Self::Frame) -> nb::Result<Option<Self::Frame>, Self::Error> {
        match self.write_frame(&frame) {
            Ok(_) => Ok(None),
            Err(e) => {
                match e.kind() {
                    ErrorKind::WouldBlock => Err(nb::Error::WouldBlock),
                    // TODO: How to indicate buffer is full?
                    // ErrorKind::StorageFull => Ok(frame),
                    _ => {
                        let code = e.raw_os_error().unwrap_or(0);
                        Err(nb::Error::Other(CanError::Unknown(code as u32)))
                    }
                }
            }
        }
    }
}