Protocols / CAN
Examples
Linux talks CAN through SocketCAN: the interface
behaves like a network device (can0), and frames are sent
with ordinary socket() calls using the AF_CAN
address family — not a character device like
spidev or
i2c-dev.
Bringing the interface up
# set the bitrate and bring the interface up (needs CAP_NET_ADMIN)
sudo ip link set can0 type can bitrate 500000
sudo ip link set can0 up
# for CAN FD, also set a data-phase bitrate
sudo ip link set can0 type can bitrate 500000 dbitrate 2000000 fd on
sudo ip link set can0 up
Command-line send and receive — can-utils
# watch every frame arriving on can0
candump can0
# send a frame with ID 0x123 and 3 data bytes
cansend can0 123#AABBCC
# send a CAN FD frame (## instead of #, with flags)
cansend can0 123##1AABBCCDDEEFF0011
C — sending a frame with SocketCAN
#include <linux/can.h>
#include <linux/can/raw.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <sys/socket.h>
int s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
struct ifreq ifr;
strcpy(ifr.ifr_name, "can0");
ioctl(s, SIOCGIFINDEX, &ifr);
struct sockaddr_can addr = {0};
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
bind(s, (struct sockaddr *)&addr, sizeof(addr));
struct can_frame frame = {0};
frame.can_id = 0x123;
frame.can_dlc = 3;
frame.data[0] = 0xAA;
frame.data[1] = 0xBB;
frame.data[2] = 0xCC;
write(s, &frame, sizeof(frame));
C — receiving frames
struct can_frame frame;
while (1) {
int nbytes = read(s, &frame, sizeof(frame));
if (nbytes < 0) continue;
printf("id=0x%03X dlc=%d data=", frame.can_id, frame.can_dlc);
for (int i = 0; i < frame.can_dlc; i++)
printf("%02X ", frame.data[i]);
printf("\n");
}
What I learned
Because SocketCAN treats can0 as a network interface,
the usual network debugging habits apply directly —
ip -details link show can0 shows the bus state
(error-active/passive/bus-off) and bitrate, and a bus-off interface
needs the link cycled down and back up to recover, the same shape as
recovering a jammed Ethernet link.