CAN Generic

From embeddedTS Manuals

The above example packet is designed to work with the Ozen Elektronik myOByDic 1610 ECU simulator to read the RPM speed. In this case, the ECU simulator would return data from candump with:

 <0x7e8> [8] 04 41 0c 60 40 00 00 00 
 <0x7e9> [8] 04 41 0c 60 40 00 00 00 

In the output above, columns 6 and 7 are the current RPM value. This shows a simple way to prove out the communication before moving to another language.

The following example sends the same packet and parses the same response in C:

#include <stdio.h>
#include <pthread.h>
#include <net/if.h>
#include <string.h>
#include <unistd.h>
#include <net/if.h>
#include <sys/ioctl.h>
#include <assert.h>
#include <linux/can.h>
#include <linux/can/raw.h>

int main(void)
{
	int s;
	int nbytes;
	struct sockaddr_can addr;
	struct can_frame frame;
	struct ifreq ifr;
	struct iovec iov;
	struct msghdr msg;
	char ctrlmsg[CMSG_SPACE(sizeof(struct timeval)) + CMSG_SPACE(sizeof(__u32))];
	char *ifname = "can0";
 
	if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0) {
		perror("Error while opening socket");
		return -1;
	}
 
	strcpy(ifr.ifr_name, ifname);
	ioctl(s, SIOCGIFINDEX, &ifr);
	addr.can_family  = AF_CAN;
	addr.can_ifindex = ifr.ifr_ifindex;
 
	if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
		perror("socket");
		return -2;
	}
 
 	/* For the ozen myOByDic 1610 this requests the RPM guage */
	frame.can_id  = 0x7df;
	frame.can_dlc = 3;
	frame.data[0] = 3;
	frame.data[1] = 1;
	frame.data[2] = 0x0c;
 
	nbytes = write(s, &frame, sizeof(struct can_frame));
	if(nbytes < 0) {
		perror("write");
		return -3;
	}

	iov.iov_base = &frame;
	msg.msg_name = &addr;
	msg.msg_iov = &iov;
	msg.msg_iovlen = 1;
	msg.msg_control = &ctrlmsg;
	iov.iov_len = sizeof(frame);
	msg.msg_namelen = sizeof(struct sockaddr_can);
	msg.msg_controllen = sizeof(ctrlmsg);  
	msg.msg_flags = 0;

	do {
		nbytes = recvmsg(s, &msg, 0);
		if (nbytes < 0) {
			perror("read");
			return -4;
		}

		if (nbytes < (int)sizeof(struct can_frame)) {
			fprintf(stderr, "read: incomplete CAN frame\n");
		}
	} while(nbytes == 0);

	if(frame.data[0] == 0x4)
		printf("RPM at %d of 255\n", frame.data[3]);
 
	return 0;
}

See the Kernel's CAN documentation here. Other languages have bindings to access CAN such as Python, Java using JNI.

In production use of CAN we also recommend setting a restart-ms for each active CAN port.

ip link set can0 type can restart-ms 100

This allows the CAN bus to automatically recover in the event of a bus-off condition.