Raspberry Pi上で、C言語によるCAN通信の標準フレーム受信をします。
動作環境は、OS:raspbian jessie です。
CANデバイスは、まだCANモジュールが来ていないので、
以下のコマンドで作った仮想CANデバイス(vcan1)で受信します。
sudo modprobe vcan
sudo ip link add dev vcan1 type vcan
sudo ip link set vcan1 up
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <linux/can.h>
#include <linux/can/raw.h>
#define CAN_NAME "vcan1"
int canrecv_stdframe(unsigned short *p_id, unsigned char *p_dlc, unsigned char data[])
{
int ret;
int s;
fd_set rdfs;
struct ifreq ifr;
struct sockaddr_can addr;
struct timeval timeout;
struct can_frame frame;
int nbytes;
if((s = socket(PF_CAN, SOCK_RAW, CAN_RAW)) < 0)
{
perror("socket");
return -1;
}
memset(&ifr.ifr_name, 0, sizeof(ifr.ifr_name));
strncpy(ifr.ifr_name, CAN_NAME, sizeof(ifr.ifr_name));
ifr.ifr_ifindex = if_nametoindex(ifr.ifr_name);
if(! ifr.ifr_ifindex)
{
perror("if_nametoindex");
return -2;
}
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if(bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0)
{
perror("bind");
return -3;
}
while(1)
{
FD_ZERO(&rdfs);
FD_SET(s, &rdfs);
timeout.tv_sec = 1;
timeout.tv_usec = 0;
ret = select(s+1, &rdfs, NULL, NULL, &timeout);
if(ret < 0)
{
perror("select");
return -4;
}
else if(0 == ret)
{
continue;
}
else
{
break;
}
}
nbytes = read(s, &frame, sizeof(frame));
if(nbytes < 0)
{
perror("recv");
return -5;
}
if(nbytes == sizeof(frame))
{
*p_id = frame.can_id;
*p_dlc = frame.can_dlc;
memcpy(data, frame.data, CAN_MAX_DLEN);
}
else
{
fprintf(stderr, "recv size not std-frame.\n");
}
close(s);
return 0;
}
int main(int argc, char argv[])
{
unsigned short id;
unsigned char dlc;
unsigned char data[CAN_MAX_DLEN];
canrecv_stdframe(&id, &dlc, data);
printf("id=%x, dlc=%d, data=%.02x %.02x %.02x %.02x %.02x %.02x %.02x %.02x\n",
id, dlc, data[0], data[1], data[2], data[3], data[4], data[5], data[6], data[7]);
}
これで、標準フレームを1回受信し、表示して終わります。
CAN標準フレームの受信に必要な処理は、これでわかりました。
次は、これをpythonで実装します。