本文讲述如何制造和观察CANopen中的错误帧(Error frame),以Linux下的"VCAN0"为CAN接口来做测试,所以事先要先创建vcan0
一 制造错误帧
首先安装python CAN,
bash
pip3 install python-can
然后参考python can的文档编写如下代码,保存为error_frame.py,
python
import can
# 连接vcan0
can_bus = can.Bus(channel='vcan0', interface='socketcan')
# 创建错误帧
err_frame = can.Message(arbitration_id=100, is_error_frame=True)
# 打印错误帧
print(err_frame)
# 向vcan0发送错误帧
can_bus.send(err_frame)
# 关闭连接
can_bus.shutdown()
二 观察错误帧
使用candump
candump是用来观察CAN消息的非常方便的工具,安装命令如下,
bash
sudo apt install can-utils
通过查看candump的help信息,有如下这段话,
我们平时用candump可能只是执行candump vcan0这样,或者偶尔加个过滤,而其提供的例子里已经告诉我们如何观察错误帧。下面让我们来观察错误帧。
首先打开一个终端,然后执行下面命令,
bash
candump any,0~0,#FFFFFFFF
接着打开另外一个终端运行第一节的python脚本,
python
python3 error_frame.py
此时可以在candump所在终端观察到如下信息,
使用C代码
下面是一段典型的C代码,
c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <arpa/inet.h>
#include <linux/can/raw.h>
#include <linux/can/error.h>
#include <linux/can.h>
#include <net/if.h>
int main(void) {
int s;
struct sockaddr_can addr;
struct ifreq ifr;
struct can_frame frame;
// 创建套接字
s = socket(PF_CAN, SOCK_RAW, CAN_RAW);
if (s == -1) {
perror("Socket creation failed");
exit(EXIT_FAILURE);
}
// 设置CAN设备
strcpy(ifr.ifr_name, "vcan0"); // 使用vcan0作为设备名
ioctl(s, SIOCGIFINDEX, &ifr);
can_err_mask_t err_mask = ( CAN_ERR_TX_TIMEOUT | CAN_ERR_BUSOFF );
setsockopt(s, SOL_CAN_RAW, CAN_RAW_ERR_FILTER, &err_mask, sizeof(err_mask));
// 绑定套接字到CAN设备
memset(&addr, 0, sizeof(addr));
addr.can_family = AF_CAN;
addr.can_ifindex = ifr.ifr_ifindex;
if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) != 0) {
perror("Bind failed");
close(s);
exit(EXIT_FAILURE);
}
// 接收数据
while (1) {
int len = recvfrom(s, &frame, sizeof(frame), 0, NULL, NULL);
if (len > 0) {
// 检查是否为错误帧
if ((frame.can_id & CAN_ERR_FLAG) != 0) {
printf("Error Frame received!\n");
} else {
printf("Standard Frame: ID=0x%03X DLC=%d\n", frame.can_id & CAN_SFF_MASK, frame.can_dlc);
for(int i = 0; i < frame.can_dlc; i++) {
printf("%02X ", frame.data[i]);
}
printf("\n");
}
}
}
close(s); // 不会执行到这里,因为上面的循环是无限的
return 0;
}
代码里使用setsockopt()设置了观察的错误帧类型,即CAN_ERR_TX_TIMEOUT 和CAN_ERR_BUSOFF,意思就是出现这2种错误帧才会去处理,这2个宏定义的值分别是0x1和0x40,而前面python脚本里的设置错误帧id是0x64,与0x40相与后不是0,所以会被认为是CAN_ERR_BUSOFF
编译这段C代码,然后运行,接着执行python脚本,这样就可以在C程序这边观察到打印,
可以试着把python脚本里的id改成别的值,可以不触发错误帧检测。
三 小结
本文讲述如何使用python can来制造错误帧,以及如何使用candump和C代码来观察错误帧,了解了这些知识后就可以随意制造想要的错误帧来做测试,非常方便。