CAN Generic: Difference between revisions

From embeddedTS Manuals
(Initial creation)
 
No edit summary
 
(2 intermediate revisions by 2 users not shown)
Line 3: Line 3:
   <0x7e9> [8] 04 41 0c 60 40 00 00 00  
   <0x7e9> [8] 04 41 0c 60 40 00 00 00  


In this case, columns 6 and 7 are the current RPM value.  This shows a simple way to prove out the communication before moving to another language.
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:
The following example sends the same packet  and parses the same response in C:
Line 88: Line 88:


See the Kernel's CAN documentation [https://www.kernel.org/doc/Documentation/networking/can.txt here].
See the Kernel's CAN documentation [https://www.kernel.org/doc/Documentation/networking/can.txt here].
Other languages have bindings to access CAN such as [https://bitbucket.org/hardbyte/python-can Python using C-types], [https://github.com/entropia/libsocket-can-java Java using JNI].
Other languages have bindings to access CAN such as [https://python-can.readthedocs.io/en/master/ Python], [https://github.com/entropia/libsocket-can-java Java using JNI].
 
In production use of CAN we also recommend setting a restart-ms for each active CAN port.
<source lang=bash>
ip link set can0 type can restart-ms 100
</source>
This allows the CAN bus to automatically recover in the event of a bus-off condition.

Latest revision as of 13:04, 31 March 2023

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.