Skip to main content

Crate socketcan

Crate socketcan 

Source
Expand description

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 CAN Flexible Data-Rate (CAN FD) standard extended the data payload up to 64 bytes and added the ability to increase the the bitrate for the data bit in the frame.

The Linux socketcan subsystem makes the CAN bus available as a regular networking device. Opening a network interface allows an application to receive all CAN messages from the bus and/or to filter for specific messages based on the CAN ID field. 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 (see section 2.4) is one of many ways to get started.

§RawFd and OwnedFd

Raw access to the underlying file descriptor and construction through one is available through the AsRawFd, IntoRawFd and FromRawFd, and similar implementations.

§Other CAN protocols: J1939, ISO-TP, BCM

The socket types here speak CAN_RAW, reading and writing whole CAN frames. The kernel’s other CAN protocols are not frame-shaped — an ISO-TP or J1939 socket carries a reassembled payload, a BCM socket its own message structs — so this crate does not wrap them: a socket type built around CanFrame would misread every message.

What it does provide is the pieces a separate crate needs to implement one of them:

  • CanAddr builds any sockaddr_can, the J1939 and ISO-TP fields included, and hands it to the kernel as a socket2::SockAddr (into_sock_addr()), a pointer (as_sockaddr_ptr()) or a byte slice (as_bytes()).
  • Accessors — j1939_name(), tp_rx_id() and friends — read an address back without touching the union yourself, which is what inspecting a recvfrom() peer needs.
  • The protocol numbers (CAN_J1939, CAN_ISOTP, CAN_BCM), the SOL_CAN_J1939 option level, and the J1939 “unset” markers (J1939_NO_ADDR and company).
  • SocketOptions is implementable by your own socket type — one empty impl given AsRawFd — for setsockopt/getsockopt on the protocol’s own options.
  • timespec_to_system_time() and timespec_to_duration() convert the timestamps in an SCM_TIMESTAMPNS/SCM_TIMESTAMPING control message, for code running its own recvmsg(), into a CanTimestamps.
  • And if you implement the transport over CAN_RAW yourself rather than using the kernel module — a common choice for J1939, since it puts the segmentation under your control — then the frame, identifier, filter and error-decoding types here are the whole toolkit already.

Opening such a socket is three steps: create it with the protocol you want, as a datagram socket, and bind the address.

use socket2::{Domain, Protocol, Socket, Type};
use socketcan::{
    CanAddr,
    addr::{AF_CAN, J1939_NO_ADDR, J1939_NO_NAME, J1939_NO_PGN},
    socket::CAN_J1939,
};

let addr = CanAddr::from_iface_j1939("can0", J1939_NO_NAME, J1939_NO_PGN, J1939_NO_ADDR)?;

let sock = Socket::new_raw(
    Domain::from(AF_CAN),
    Type::DGRAM,
    Some(Protocol::from(CAN_J1939)),
)?;
sock.bind(&addr.into_sock_addr())?;

From there the protocol is yours: its socket options, its ancillary data, and reads that yield payloads rather than frames.

§Crate Features

§Default

  • netlink - Whether to include programmable CAN interface configuration capabilities based on netlink kernel communications. This brings in the neli library and its dependencies.

  • dump - Whether to include candump parsing capabilities.

§Non-default

  • enumerate - Include the enumerate module which can be used to get a list of the CANbus network interfaces attached to the host. This brings in the dependency for udev

  • utils - Whether to build command-line utilities. This brings in additional dependencies like anyhow and clap

  • tokio - Include support for async/await using tokio.

  • smol - Include support for async/await using smol.

  • serde - Implement serde’s Serialize and Deserialize for frames, identifiers, filters, timestamps, the error types, candump records, and the netlink interface configuration types. Useful in particular for keeping interface configuration in a JSON or TOML file.

§Test Features

Additional test can be built and run, but have requirements:

  • vcan_tests - Requires a virtual CAN interface to be installed on the host. This can be done by running the vcan.sh script included with the crate.

  • netlink_tests - Requires superuser privileges to run/pass.

Re-exports§

pub use errors::CanError;
pub use errors::CanErrorDecodingFailure;
pub use errors::ConstructionError;
pub use errors::Error;
pub use errors::ErrorCause;
pub use errors::IoError;
pub use errors::IoErrorKind;
pub use errors::IoResult;
pub use errors::Result;
pub use addr::CanAddr;
pub use id::CanId;
pub use frame::CanAnyFrame;
pub use frame::CanDataFrame;
pub use frame::CanErrorFrame;
pub use frame::CanFdFrame;
pub use frame::CanFrame;
pub use frame::CanRawFrame;
pub use frame::CanRemoteFrame;
pub use frame::Frame;
pub use socket::CanFdSocket;
pub use socket::CanFilter;
pub use socket::CanSocket;
pub use socket::ShouldRetry;
pub use socket::Socket;
pub use socket::SocketOptions;
pub use timestamp::CanTimestamps;
pub use nl::CanCtrlMode;netlink
pub use nl::CanInterface;netlink
pub use nl::InterfaceCanParams;netlink
pub use nl::NlError;netlink
pub use enumerate::available_interfaces;enumerate
pub use embedded_can;

Modules§

addr
SocketCAN address type.
dumpdump
candump format parsing
enumerateenumerate
SocketCAN interface enumeration.
errors
CAN bus errors.
frame
CAN bus frames.
id
Implementation of CANbus standard and extended identifiers.
nlnetlink
CAN Netlink access
smolsmol
Optional support for smol runtime. Bindings to smol for CANbus 2.0 and FD sockets using SocketCAN on Linux.
socket
Implementation of sockets for CANbus 2.0 and FD for SocketCAN on Linux.
timestamp
Timestamp support for SocketCAN sockets.
tokiotokio
Optional support for tokio runtime.

Structs§

ExtendedId
Extended 29-bit CAN Identifier (0..=1FFF_FFFF).
StandardId
Standard 11-bit CAN Identifier (0..=0x7FF).

Enums§

Id
A CAN Identifier (standard or extended).

Constants§

CAN_BUS_OFF_THRESHOLD
The error counter value at which a controller goes bus-off. Compare against the counters from ErrorCause::Counters.
CAN_ERROR_PASSIVE_THRESHOLD
The error counter value at which a controller enters the “error passive” state. Compare against the counters from ErrorCause::Counters.
CAN_ERROR_WARNING_THRESHOLD
The error counter value at which a controller enters the “error warning” state. Compare against the counters from ErrorCause::Counters.

Traits§

BlockingCan
A blocking CAN interface that is able to transmit and receive frames.
EmbeddedFrame
A CAN2.0 Frame
NonBlockingCan
A CAN interface that is able to transmit and receive frames.