原文链接: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" {
#endifint 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 100int 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;
}