TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序

上次将can总线通讯的源代码简单地解读了一下,现在要考虑自己编写一个canbus收发程序,我认为应该要注意的几点有:

(1)如何检测can总线收到了数据,一般玩具程序会用while(1)轮询,但为了尽量优化程序减少开销,因此需要使用异步IO监控文件。

(2)高并发 发送数据情况下要保持有序发送,因此必须建立发送工作队列。

(3)高并发 数据接收情况下保证快速接收和不出错,因此采用异步IO进行接收的方法。

(4)由于canbus是半双工的,因此不能同时发送和接收因此发送和接收任务必须互斥!加互斥锁!

具体流程图如下:

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第1张图片


具体思路就是:将can-utils的源代码文件:cansend和candump直接拿来用,由于它俩是分别单独的应用,将其main函数修改,再自己写一个main,将发送任务作为一个单独的线程进行,将发送的消息的源代码cansend的main函数改写成canbus_send并将interface就是使用那个can外设如can0、can1作为参数1,将要发送的消息snd_msg作为参数2写入这个函数。自己编写一个工作队列,其实就是一个线性链表,将要发送的参数作为这个链表结构的成员,再开一个线程,这个线程工作原理如上图,这样就完成了发送。

之后就是接收,本来想做一个基于epoll的异步io接收程序,然后发现其实can-util中自己已经实现了异步接收机制,但是它采用的是select,select和epoll的对比直接如下:

select缺点:

  1. 最大并发数限制:使用32个整数的32位,即32*32=1024来标识fd,虽然可修改,但是有以下第二点的瓶颈;
  2. 效率低:每次都会线性扫描整个fd_set,集合越大速度越慢;
  3. 内核/用户空间内存拷贝问题。

epoll的提升:

  1. 本身没有最大并发连接的限制,仅受系统中进程能打开的最大文件数目限制;
  2. 效率提升:只有活跃的socket才会主动的去调用callback函数;
  3. 省去不必要的内存拷贝:epoll通过内核与用户空间mmap同一块内存实现。

当然,以上的优缺点仅仅是特定场景下的情况:高并发,且任一时间只有少数socket是活跃的。

如果在并发量低,socket都比较活跃的情况下,select就不见得比epoll慢了(就像我们常常说快排比插入排序快,但是在特定情况下这并不成立)。

查看candump的源代码:

(1)创建套接字

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第2张图片

(2)指定interface

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第3张图片

(3)绑定套接字

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第4张图片


(4)select机制下的异步io接收

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第5张图片

好的,基于伟大的开源精神和不重复造轮子的准则,我直接把candump的函数入口main改写成canrecv,将参数由字符串指针数组cahr **argv传递,由主线程来调用这个函数!这样canbus发送接收程序就完成了。

编写makefile:

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第6张图片

进行编译:

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第7张图片

编译完成,由于我手头没有具有can外设的开发板因此测试程序时提示:No such device 就是检测不到设备。。。

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第8张图片

由于接收函数是主进程调用的,发送错误后return,直接结束了整个程序。因此禁用接收,测试一下发送程序:

TX2平台下can总线收发功能的实现(三)——发送队列异步io接收程序_第9张图片

检测后程序如预期,报文出错时会提示报文错误,报文正确时提示找不到设备。那么整个canbus测试程序到此结束。

本测试程序源代码github:https://github.com/PearBlossomhuang/canbus-on-Linux


你可能感兴趣的:(Linux嵌入式)