CAN总线应用开发接口
大家好,又见面了,我是你们的朋友全栈君。
由于系统将CAN设备作为网络设备进行管理,因此在CAN总线应用开发方面,Linux提供了SocketCAN接口,使得CAN总线通信近似于和以太网的通信,应用程序开发接口更加通用,也更加灵活。
此外,通过https://gitorious.org/linux-can/can-utils网站发布的基于SocketCAN的can-utils工具套件,也可以实现简易的CAN总线通信。
下面具体介绍使用SocketCAN实现通信时使用的应用程序开发接口。
1. 初始化
SocketCAN中大部分的数据结构和函数在头文件linux/can.h 中进行了定义。CAN总线套接字的创建采用标准的网络套接字操作来完成。网络套接字在头文件sys/socket.h中定义。套接字的初始化方法如下:
int s; struct sockaddr_can addr; struct ifreq ifr; s = socket(PF_CAN, SOCK_RAW, CAN_RAW); //创建SocketCAN套接字 strcpy(ifr.ifr_name, "can0" ); ioctl(s, SIOCGIFINDEX, &ifr); //指定can0设备 addr.can_family = AF_CAN; addr.can_ifindex = ifr.ifr_ifindex; bind(s, (struct sockaddr *)&addr, sizeof(addr)); //将套接字与can0绑定
2. 数据发送
在数据收发的内容方面,CAN总线与标准套接字通信稍有不同,每一次通信都采用can_ frame结构体将数据封装成帧。结构体定义如下:
struct can_frame { canid_t can_id; //CAN标识符 __u8 can_dlc; //数据场的长度 __u8 data[8]; //数据 };
can_id为帧的标识符,如果发出的是标准帧,就使用can_id的低11位;如果为扩展帧,就使用0~28位。can_id的第29、30、31位是帧的标志位,用来定义帧的类型,定义如下:
#define CAN_EFF_FLAG 0x80000000U //扩展帧的标识 #define CAN_RTR_FLAG 0x40000000U //远程帧的标识 #define CAN_ERR_FLAG 0x20000000U //错误帧的标识,用于错误检查
数据发送使用write函数来实现。如果发送的数据帧(标识符为0x123)包含单个字节(0xAB)的数据,可采用如下方法进行发送:
struct can_frame frame; frame.can_id = 0x123; //如果为扩展帧,那么frame.can_id = CAN_EFF_FLAG | 0x123; frame.can_dlc = 1; //数据长度为1 frame.data[0] = 0xAB; //数据内容为0xAB int nbytes = write(s, &frame, sizeof(frame)); //发送数据 if (nbytes != sizeof(frame)) //如果nbytes不等于帧长度,就说明发送失败 printf("Error\n!");
如果要发送远程帧(标识符为0x123),可采用如下方法进行发送:
struct can_frame frame; frame.can_id = CAN_RTR_FLAG | 0x123; write(s, &frame, sizeof(frame));
3. 数据接收
数据接收使用read函数来完成,实现如下:
struct can_frame frame; int nbytes = read(s, &frame, sizeof(frame));
当然,套接字数据收发时常用的send、sendto、sendmsg以及对应的recv函数也都可以用于CAN总线数据的收发。
4. 错误处理
当帧接收后,可以通过判断can_id中的CAN_ERR_FLAG位来判断接收的帧是否为错误帧。如果为错误帧,可以通过can_id的其他符号位来判断错误的具体原因。
错误帧的符号位在头文件linux/can/error.h中定义。
5. 过滤规则设置
在数据接收时,系统可以根据预先设置的过滤规则,实现对报文的过滤。过滤规则使用can_filter结构体来实现,定义如下:
struct can_filter { canid_t can_id; canid_t can_mask; };
过滤的规则为:
接收到的数据帧的can_id & mask == can_id & mask
通过这条规则可以在系统中过滤掉所有不符合规则的报文,使得应用程序不需要对无关的报文进行处理。在can_filter结构的can_id中,符号位CAN_INV_FILTER在置位时可以实现can_id在执行过滤前的位反转。
用户可以为每个打开的套接字设置多条独立的过滤规则,使用方法如下:
struct can_filter rfilter[2]; rfilter[0].can_id = 0x123; rfilter[0].can_mask = CAN_SFF_MASK; //#define CAN_SFF_MASK 0x000007FFU rfilter[1].can_id = 0x200; rfilter[1].can_mask = 0x700; setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter)); //设置规则
在极端情况下,如果应用程序不需要接收报文,可以禁用过滤规则。这样的话,原始套接字就会忽略所有接收到的报文。在这种仅仅发送数据的应用中,可以在内核中省略接收队列,以此减少CPU资源的消耗。禁用方法如下:
setsockopt(s, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0); //禁用过滤规则
通过错误掩码可以实现对错误帧的过滤,例如:
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));
在默认情况下,本地回环功能是开启的,可以使用下面的方法关闭回环/开启功能:
int loopback = 0; // 0表示关闭, 1表示开启(默认) setsockopt(s, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
在本地回环功能开启的情况下,所有的发送帧都会被回环到与CAN总线接口对应的套接字上。默认情况下,发送CAN报文的套接字不想接收自己发送的报文,因此发送套接字上的回环功能是关闭的。可以在需要的时候改变这一默认行为:
int ro = 1; // 0表示关闭(默认), 1表示开启
setsockopt(s, SOL_CAN_RAW, CAN_RAW_RECV_OWN_MSGS, &ro, sizeof(ro));
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/151112.html原文链接:https://javaforall.cn
相关文章
- 利用QQ空间查询接口的网页小应用
- 重磅!信号分析新方法fCWT处理速度提高100倍,可应用于脑机接口,Nature子刊
- java 上传文件接口_Java接口实现文件上传
- 计算机应用网线接口亮红灯,网线插在电脑上网口灯不亮是为什么?
- 接口的应用
- Go 编程 | 连载 18 - 接口 Interface
- 接口01_精通Postman接口测试基础应用
- python调用webservice接口_webservice应用实例
- 测试之路--随手记:接口自动化的应用
- Postman之接口关联
- 接口测试|postman的介绍和安装
- 应用移动端银行卡识别接口,实现手机拍照录入银行卡号
- 脑机接口新应用,无声语音信号解码
- 【Android 应用开发】 自定义组件 宽高适配方法, 手势监听器操作组件, 回调接口维护策略, 绘制方法分析 -- 基于 WheelView 组件分析自定义组件
- 初学者不会写接口怎么办?微软Visual Studio 2022无脑式API接口创建——Swagger一键导入APIKit快速测试
- PHP写接口需要注意的问题详解编程语言
- 0Linux环境下的eth0接口使用秘籍(linuxeth)
- 构建高效实时应用接口整合Redis缓存(接口整合redis缓存)
- Redis默认的数据接口简介(redis默认的数据接口)
- 开发Oracle POF接口技术实现快速灵活的应用开发(oracle pof接口)
- 脑机接口人体实验首度成功,它用 50 年把科幻电影变为现实
- Linux中BSD套接口开发的基础介绍
- php学习笔记面向对象中[接口]与[多态性]的应用
- 解析二进制流接口应用实例pack、unpack、ord函数使用方法
- 百度实时推送api接口应用示例