原文链接:https://blog.csdn.net/xiandang8023/article/details/127990159
在Linux上能使用虚拟CAN接口之前,需要在终端执行以下三个步骤:
加载vcan内核模块: sudo modprobe vcan
创建虚拟CAN接口: sudo ip link add dev vcan0 type vcan
将虚拟CAN接口处于在线状态: sudo ip link set up vcan0 或 sudo ip link set dev vcan0 up
将虚拟CAN接口处于离线状态: sudo ip link set down vcan0 或 sudo ip link set dev vcan0 down
删除虚拟CAN接口: sudo ip link del dev vcan0
然后,通过命令ip addr | grep "can" 来验证是否可用并处于在线状态
创建一个vcan.sh文件。然后将其标记为可执行文件: chmod +x ~/vcan.sh,之后执行这个文件 ./vcan.sh
#!/bin/bash
# Make sure the script runs with super user priviliges.
[ "$UID" -eq 0 ] || exec sudo bash "$0" "$@"
# Load the kernel module.
modprobe vcan
# Create the virtual CAN interface.
ip link add dev vcan0 type vcan
# Bring the virutal CAN interface online.
ip link set up vcan0
接下来我们要基于上面创建的虚拟CAN接口,来测试一下CAN通信情况。工具包 can-utils 是一个命令行工具,可以完美的满足我们的需求。我们只需要在电脑上安装一下这个工具包即可:
Ubuntu/Debian: sudo apt install can-utils
接下来,我们打开两个终端窗口,一个是用来查看所有的CAN消息,另一个是用来发送CAN消息。
在用来查看CAN消息的终端中执行以下命令:
candump -tz vcan0
在用来发送CAN消息的终端中,模拟发送CAN请求:
cansend vcan0 123#00FFAA5501020304
在发送完CAN请求后,就会在第一个查看CAN消息的终端中看到发送的CAN消息:
melvyn@melvyn:~$ cansend vcan0 123#00FFAA5501020304
melvyn@melvyn:~$ cansend vcan0 123#00FFAA5501020304
(000.000000) vcan0 123 [8] 00 FF AA 55 01 02 03 04
(001.919922) vcan0 123 [8] 00 FF AA 55 01 02 03 04
从上面的输出可以验证使用新创建的vcan0虚拟CAN接口可以正常进行CAN通信。
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
struct can_frame frame = {0};
int sockfd = -1;
int i;
int ret;
/* 打开套接字 */
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if(0 > sockfd) {
perror("socket error");
exit(EXIT_FAILURE);
}
/* 指定can0设备 */
strcpy(ifr.ifr_name, "vcan0");
ioctl(sockfd, SIOCGIFINDEX, &ifr);
can_addr.can_family = AF_CAN;
can_addr.can_ifindex = ifr.ifr_ifindex;
/* 将can0与套接字进行绑定 */
ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (0 > ret) {
perror("bind error");
close(sockfd);
exit(EXIT_FAILURE);
}
/* 设置过滤规则 */
//setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
/* 接收数据 */
for ( ; ; ) {
if (0 > read(sockfd, &frame, sizeof(struct can_frame))) {
perror("read error");
break;
}
/* 校验是否接收到错误帧 */
if (frame.can_id & CAN_ERR_FLAG) {
printf("Error frame!\n");
break;
}
/* 校验帧格式 */
if (frame.can_id & CAN_EFF_FLAG) //扩展帧
printf("扩展帧 <0x%08x> ", frame.can_id & CAN_EFF_MASK);
else //标准帧
printf("标准帧 <0x%03x> ", frame.can_id & CAN_SFF_MASK);
/* 校验帧类型:数据帧还是远程帧 */
if (frame.can_id & CAN_RTR_FLAG) {
printf("remote request\n");
continue;
}
/* 打印数据长度 */
printf("[%d] ", frame.can_dlc);
/* 打印数据 */
for (i = 0; i < frame.can_dlc; i++)
printf("%02x ", frame.data[i]);
printf("\n");
}
/* 关闭套接字 */
close(sockfd);
exit(EXIT_SUCCESS);
}
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main(void)
{
struct ifreq ifr = {0};
struct sockaddr_can can_addr = {0};
struct can_frame frame = {0};
int sockfd = -1;
int ret;
/* 打开套接字 */
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if(0 > sockfd) {
perror("socket error");
exit(EXIT_FAILURE);
}
/* 指定can0设备 */
strcpy(ifr.ifr_name, "vcan0");
ioctl(sockfd, SIOCGIFINDEX, &ifr);
can_addr.can_family = AF_CAN;
can_addr.can_ifindex = ifr.ifr_ifindex;
/* 将can0与套接字进行绑定 */
ret = bind(sockfd, (struct sockaddr *)&can_addr, sizeof(can_addr));
if (0 > ret) {
perror("bind error");
close(sockfd);
exit(EXIT_FAILURE);
}
/* 设置过滤规则:不接受任何报文、仅发送数据 */
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
/* 发送数据 */
frame.data[0] = 0xA0;
frame.data[1] = 0xB0;
frame.data[2] = 0xC0;
frame.data[3] = 0xD0;
frame.data[4] = 0xE0;
frame.data[5] = 0xF0;
frame.can_dlc = 6; //一次发送6个字节数据
frame.can_id = 0x123;//帧ID为0x123,标准帧
for ( ; ; ) {
ret = write(sockfd, &frame, sizeof(frame)); //发送数据
if(sizeof(frame) != ret) { //如果ret不等于帧长度,就说明发送失败
perror("write error");
goto out;
}
sleep(1); //一秒钟发送一次
}
out:
/* 关闭套接字 */
close(sockfd);
exit(EXIT_SUCCESS);
}
可以使用ip命令来查看或设置CAN,使用ifconfig或ip命令来开启/关闭CAN,canconfig工具来配置和调试CAN,cansend 和 candump用于收发CAN报文。
#ifconfig -a //查到当前can网络 can0 can1,包括收发包数量、是否有错误等等
#ip link set vcan0 down //关闭can设备;或使用ifconfig canX down
#ip link set vcan0 up //开启can设备;或使用ifconfig canX up
#ip -details link show vcan0 //显示can设备详细信息;
#ip link set vcan0 up type can bitrate 250000 //设置can波特率
#canconfig vcan0 ctrlmode loopback on //回环测试;
#canconfig vcan0 restart // 重启can设备;
#canconfig vcan0 stop //停止can设备;
#canecho vcan0 //查看can设备总线状态;
#candump vcan0 //接收can总线发来的数据;
#cansend vcan0 --identifier=ID+数据 //发送数据;
#candump vcan0 --filter=ID:mask//使用滤波器接收ID匹配的数据
原文链接:https://zhuanlan.zhihu.com/p/429616854
#ifndef _CAN_H_
#define _CAN_H_
#ifdef __cplusplus
extern "C" {
#endif
int iface_is_up(char *iface);
int can_iface_down(char *iface);
int can_iface_up(char *iface, int baudrate, int fdon, int dbaudrate);
int can_open(char *iface, int canid, int canfd_on);
int can_send(int sock, int canid, unsigned char *data, int len);
int canfd_send(int sock, int canid, unsigned char *data, int len);
int can_recv(int sock, unsigned char *data, int len, int *canid);
int canfd_recv(int sock, unsigned char *data, int len, int *canid);
int can_close(int sock);
#ifdef __cplusplus
}
#endif
#endif
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "can.h"
#define CAN_IFACE_TXQUEUELEN 100
int iface_is_up(char *iface)
{
int sock;
struct ifreq ifr;
int ret;
sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (sock < 0) {
perror("socket err.\n");
return 0;
}
strcpy(ifr.ifr_name, iface);
ioctl(sock, SIOCGIFFLAGS, &ifr);
if (ifr.ifr_ifru.ifru_flags & IFF_RUNNING) {
ret = 1;
} else {
ret = 0;
}
close(sock);
return ret;
}
int can_iface_down(char *iface)
{
char cmd[128];
snprintf(cmd, sizeof(cmd), "sudo ifconfig %s down", iface);
system(cmd);
return 0;
}
int can_iface_up(char *iface, int baudrate, int fdon, int dbaudrate)
{
char cmd[256];
int len = 0;
if (iface_is_up(iface)) {
printf("Can Iface [%s] is up\n", iface);
return 0;
}
printf("Try to Start Can Iface [%s]...\n", iface);
len += snprintf(cmd + len, sizeof(cmd) - len, "sudo ip link set %s up type can bitrate %d ", iface, baudrate);
if (fdon) {
len += snprintf(cmd + len, sizeof(cmd) - len, " fd on dbitrate %d ", dbaudrate);
} else {
// len += snprintf(cmd + len, sizeof(cmd) - len, " fd off");
}
system(cmd);
sleep(1);
len = snprintf(cmd, sizeof(cmd), "sudo ifconfig %s txqueuelen %d", iface, CAN_IFACE_TXQUEUELEN);
system(cmd);
printf("Can Iface [%s] start finish.\n", iface);
return 0;
}
int can_open(char *iface, int canid, int canfd_on)
{
int sock;
struct ifreq ifr;
struct sockaddr_can addr;
struct can_filter rfilter[1];
if (!iface_is_up(iface)) {
perror("iface err..\n");
return -1;
}
sock = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (sock < 0) {
perror("socket err.\n");
return -1;
}
strcpy(ifr.ifr_name, iface);
ioctl(sock, SIOCGIFINDEX, &ifr);
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(sock, (struct sockaddr *)&addr, sizeof(addr))) {
perror("bind err.\n");
return -1;
}
if (canid > 0) {
rfilter[0].can_id = canid;
rfilter[0].can_mask = CAN_SFF_MASK;
if (setsockopt(sock, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter))) {
perror("setsockopt [SOL_CAN_RAW/CAN_RAW_FILTER] err.\n");
return -1;
}
}
if (canfd_on > 0) {
if (setsockopt(sock, SOL_CAN_RAW, CAN_RAW_FD_FRAMES, &canfd_on, sizeof(canfd_on))) {
perror("setsockopt [SOL_CAN_RAW/CAN_RAW_FD_FRAMES] err.\n");
return -1;
}
}
/* int loopback = 0;
if (setsockopt(sock, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback))) {
perror("setsockopt [SOL_CAN_RAW/CAN_RAW_LOOPBACK] err.\n");
return -1;
} */
return sock;
}
int can_send(int sock, int canid, unsigned char *data, int len)
{
int nr;
struct can_frame frame;
if (len > sizeof(frame.data)) {
printf("can_send: len more than 8 is not support.\n");
return -1;
}
frame.can_dlc = len;
frame.can_id = canid;
memcpy(frame.data, data, len);
nr = write(sock, &frame, sizeof(struct can_frame));
if (nr != sizeof(struct can_frame)) {
printf("can_send: write ret=%d[%s].\n", nr, strerror(errno));
return -1;
}
return frame.can_id;
}
int can_recv(int sock, unsigned char *data, int len, int *canid)
{
int nr;
struct can_frame frame;
nr = read(sock, &frame, sizeof(struct can_frame));
if (nr < 0) {
// perror("can_recv: read err.\n");
return -1;
}
if (nr == 0) {
perror("can_recv: read ret 0, peer may closed.\n");
return -1;
}
if (canid) {
*canid = frame.can_id;
}
if (len < frame.can_dlc) {
printf("can_recv: recv data buffer too small, data has trunced.\n");
memcpy(data, frame.data, len);
return len;
} else {
memcpy(data, frame.data, frame.can_dlc);
}
return frame.can_dlc;
}
int canfd_send(int sock, int canid, unsigned char *data, int len)
{
int nr;
struct canfd_frame frame;
if (len > sizeof(frame.data)) {
printf("can_send: len more than 8 is not support.\n");
return -1;
}
frame.len = len;
frame.can_id = canid;
frame.flags = 0xF;
memcpy(frame.data, data, len);
nr = write(sock, &frame, sizeof(struct canfd_frame));
if (nr != sizeof(struct canfd_frame)) {
perror("can_send: write err.\n");
return -1;
}
return frame.can_id;
}
int canfd_recv(int sock, unsigned char *data, int len, int *canid)
{
int nr;
struct canfd_frame frame;
nr = read(sock, &frame, sizeof(struct canfd_frame));
if (nr < 0) {
//perror("can_recv: read err.\n");
return -1;
}
if (nr == 0) {
perror("can_recv: read ret 0, peer may closed.\n");
return -1;
}
if (len < frame.len) {
printf("can_recv: recv data buffer too small, data has trunced.\n");
memcpy(data, frame.data, len);
return len;
} else {
memcpy(data, frame.data, frame.len);
}
if (canid) {
*canid = frame.can_id;
}
return frame.len;
}
int can_close(int sock)
{
return close(sock);
}
#include "can.h"
#include
#include
#include
#include
#include
#include
unsigned char sent_data[8];
void show_hex(unsigned char * data, int len)
{
int i = 0;
while(i < len)
{
if(!(i % 16))
{
printf("0x%08x ", i);
}
printf("%02x ", data[i]);
if(i % 16 == 15)
{
printf("\n");
}
i = i + 1;
}
printf("\n\n");
}
void * can_aux_loop(int sock_)
{
int nr, canid, i, failure = 0;
unsigned char data[8];
while(true)
{
usleep(100);
nr = can_recv(sock_, data, sizeof(data), &canid);
if(nr > 0)
{
printf("can_recv canid: %03x.\n", canid);
show_hex(data, nr);
}
else
{
failure = failure + 1;
if(failure > 20)
{
break;
}
continue;
}
i = 0;
while(i < 8)
{
if(data[i] != sent_data[i])
{
break;
}
i = i + 1;
}
if(i == 8)
{
break;
}
else
{
failure = failure + 1;
if(failure > 20)
{
break;
}
}
}
}
void * can_send_loop(int sock0, int sock_, int send_canid)
{
fcntl(sock_, F_SETFL, fcntl(sock_, F_GETFL, 0) | O_NONBLOCK);
int nr, i;
time_t t;
srand((unsigned) time(&t));
unsigned char send_byte, data[8];
while(true)
{
send_byte = rand() % 256;
memset(data, send_byte, sizeof(data));
nr = can_send(sock0, send_canid, data, sizeof(data));
if(nr < 0)
{
continue;
}
printf("can_send [8 byte of '%02x'] canid: %03x.\n\n", send_byte, send_canid);
i = 0;
while(i < 8)
{
sent_data[i] = data[i];
i = i + 1;
}
can_aux_loop(sock_);
}
can_close(sock0);
can_close(sock_);
}
void * can_recv_loop(int sock1)
{
int nr, canid;
unsigned char data[8];
while(true)
{
nr = can_recv(sock1, data, sizeof(data), &canid);
if(nr > 0)
{
printf("can_recv canid: %03x.\n", canid);
show_hex(data, nr);
}
}
can_close(sock1);
}
int main(int argc, char ** argv)
{
char * can_device = argv[2];
int send_canid = 0x20C, recv_canid = 0x000, baudrate = 1000000, fd = 0, dbaudrate = 4000000;
can_iface_up(can_device, baudrate, fd, dbaudrate);
if(strcmp(argv[1], "send") == 0)
{
int sock0 = can_open(can_device, send_canid, fd), sock_ = can_open(can_device, send_canid, fd);
if(sock0 < 0)
{
printf("can_app: open can_device [%s] failed.\n", can_device);
return -1;
}
can_send_loop(sock0, sock_, send_canid);
}
else if(strcmp(argv[1], "recv") == 0)
{
int sock1 = can_open(can_device, recv_canid, fd);
if(sock1 < 0)
{
printf("can_app: open can_device [%s] failed.\n", can_device);
return -1;
}
can_recv_loop(sock1);
}
return 0;
}