TS-4710 CAN: Difference between revisions

From embeddedTS Manuals
No edit summary
No edit summary
Line 1: Line 1:
The CAN controller is compatible with the register interface for the SJA1000.  This is implemented using either SocketCAN, or tsctl.  See the [[tsctl]] page for more information about our CAN API.  The SocketCAN API is used by default, but further documentation and example code is still being developed.
The CAN controller contained in the FPGA is compatible with the register interface for the SJA1000.  This is implemented using either SocketCAN, or [[tsctl]]Typically new development is done using SocketCAN, but tsctl provides compatibility on older products which used CAN before Socketcan was created.  The [[tsctl]] API provides compatibility with the older canctl API, or [[tsctl]]'s API.
 
Before proceeding with the examples, see the Kernel's CAN documentation [https://www.kernel.org/doc/Documentation/networking/can.txt here].
 
This board comes preinstalled with can-utils which can be used to communicate over a CAN network without writing any code.  The candump utility can be used to dump all data on the network
 
<source lang=bash>
## First, set the baud rate and bring up the device:
ip link set can0 type can bitrate 250000
ip link set can0 up
 
## Dump data & errors:
candump -cae can0,0:0,#FFFFFFFF &
 
## Send the packet with:
#can_id = 0x7df
#data 0 = 0x3
#data 1 = 0x1
#data 2 = 0x0c
cansend can0 7Df#03010c
</source lang=bash>
 
This example packet is designed to work with the Ozen Elektronik myOByDic 1610 ECU simulator to read the RPM speed.  This device will return data from candump with:
  can0  7DF  [3] 03 01 0C                  '...'
  can0  7E8  [8] 04 41 0C 2F C0 00 00 00  '.A./....'
  can0  7E9  [8] 04 41 0C 2F 80 00 00 00  '.A./....'
 
In this case, 0x2f is the current RPM value.  This shows a simple way you can prove out the communication before moving to another language, but this next example sends the same packet and parses the same response in C:
<source lang=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;
}
</source>
 
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].

Revision as of 15:20, 29 April 2014

The CAN controller contained in the FPGA is compatible with the register interface for the SJA1000. This is implemented using either SocketCAN, or tsctl. Typically new development is done using SocketCAN, but tsctl provides compatibility on older products which used CAN before Socketcan was created. The tsctl API provides compatibility with the older canctl API, or tsctl's API.

Before proceeding with the examples, see the Kernel's CAN documentation here.

This board comes preinstalled with can-utils which can be used to communicate over a CAN network without writing any code. The candump utility can be used to dump all data on the network

## First, set the baud rate and bring up the device:
ip link set can0 type can bitrate 250000
ip link set can0 up

## Dump data & errors:
candump -cae can0,0:0,#FFFFFFFF &

## Send the packet with:
#can_id = 0x7df
#data 0 = 0x3
#data 1 = 0x1
#data 2 = 0x0c
cansend can0 7Df#03010c
</source lang=bash>

This example packet is designed to work with the Ozen Elektronik myOByDic 1610 ECU simulator to read the RPM speed.  This device will return data from candump with:
  can0  7DF  [3] 03 01 0C                  '...'
  can0  7E8  [8] 04 41 0C 2F C0 00 00 00   '.A./....'
  can0  7E9  [8] 04 41 0C 2F 80 00 00 00   '.A./....'

In this case, 0x2f is the current RPM value.  This shows a simple way you can prove out the communication before moving to another language, but this next example sends the same packet and parses the same response in C:
<source lang=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;
}

Other languages have bindings to access CAN such as Python using C-types, Java using JNI.