I am working on a custom embedded Linux system that needs to read and write messages on a CAN bus. SocketCAN is being used to accomplish this.
The CAN interface can0 is brought up on boot with a baudrate set to 500 kbps. I am using CANoe, cangen, and candump to test reception and transmission of messages. When CANoe is set to send messages to the embedded system, candump has no problem reading these messages on the embedded system. When cangen is set to send messages, CANoe has no problem reading the messages from the embedded system.
I wrote a small program to read messages from the can0 interface using the read() function. When the read() function is called to read a single CAN message, the function blocks and then never returns. I am certain that the CAN interface is receiving data since the number of received bytes reported by ifconfig increases as expected. Running candump concurrently with my program also shows that the interface is receiving CAN messages from the bus. Below is the relevant code for opening and reading the CAN interface. Error checking has been omitted.
Opening the socket:
int socketNum = 0;
char interface[10] = "can0";
struct sockaddr_can addr;
struct ifreq ifr;
memset(&addr, 0, sizeof(addr));
memset(&ifr, 0, sizeof(ifr));
socketNum = socket(PF_CAN, SOCK_RAW, CAN_RAW);
addr.can_family = AF_CAN;
strncpy(ifr.ifr_name, interface, sizeof(interface));
ioctl(socketNum, SIOCGIFINDEX, &ifr);
addr.can_ifindex = ifr.ifr_ifindex;
bind(socketNum, (struct sockaddr *)&addr, sizeof(addr));
Reading the socket:
struct can_frame frame;
int nbytes = 0;
memset(&frame, 0, sizeof(frame));
/* Never returns despite interface receiving messages */
nbytes = read(socketNum, &frame, sizeof(frame));
Am I missing something in my code or doing something wrong? Has anyone else encountered this issue and found a solution?
I have found a work-around for my issue.
The embedded platform I am working on uses an IMX 8 and an NXP driver for the FLEXCAN IP. My device tree is setup with the disable-fd-mode option. Even though FD mode should be disabled, I am required to "enable" FD mode with setsockopt:
canfd_enabled = 1;
error_code = setsockopt(socketNum, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_enabled, sizeof(int));
After adding these lines of code I can read and write from the socket as expected. I also read and write up to sizeof(canfd_frame) bytes instead of sizeof(can_frame) bytes. It is likely there is something wrong with the FLEXCAN driver. In my experience, this is not unusual for NXP drivers.