SocketCan 应用编程
SocketCan 应用编程
由于 Linux 系统将 CAN 设备作为网络设备进行管理,因此在 CAN 总线应用开发方面,Linux 提供了SocketCAN 应用编程接口,使得 CAN 总线通信近似于和以太网的通信,应用程序开发接口更加通用,也更加灵活。
SocketCAN 中大部分的数据结构和函数在头文件 linux/can.h 中进行了定义,所以,在我们的应用程序中一定要包含<linux/can.h>头文件。
创建 socket 套接字
CAN 总线套接字的创建采用标准的网络套接字操作来完成,网络套接字在头文件<sys/socket.h>中定义。
创建 CAN 套接字的方法如下:
int sockfd = -1; /* 创建套接字 */
sockfd = socket(PF_CAN, SOCK_RAW, CAN_RAW); if(0 > sockfd) { perror("socket error"); exit(EXIT_FAILURE); }
socket 函数在 30.2.1 小节中给大家详细介绍过,第一个参数用于指定通信域,在Socket Can中,通常将其设置为PF_CAN,指定为CAN通信协议;第二个参数用于指定套接字的类型,通常将其设置为SOCK_RAW;第三个参数通常设置为 CAN_RAW。
将套接字与 CAN 设备进行绑定
譬如,将创建的套接字与 can0 进行绑定,示例代码如下所示:
truct ifreq ifr = {0}; struct sockaddr_can can_addr = {0}; int ret; strcpy(ifr.ifr_name, "can0"); //指定名字 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);
}
bind()函数在 30.2.2 小节中给大家详细介绍过,这里不再重述!
这里出现了两个结构体:struct ifreq 和 struct sockaddr_can,其中 struct ifreq 定义在<net/if.h>头文件中,而 struct sockaddr_can 定义在<linux/can.h>头文件中,这些结构体就不给大家解释了,有兴趣的自己去查,笔者也不太懂!
设置过滤规则
在我们的应用程序中,如果没有设置过滤规则,应用程序默认会接收所有 ID 的报文;如果我们的应用程序只需要接收某些特定 ID 的报文(亦或者不接受所有报文,只发送报文),则可以通过 setsockopt 函数设置过滤规则,譬如某应用程序只接收 ID 为 0x60A 和 0x60B 的报文帧,则可将其它不符合规则的帧全部给过滤掉,示例代码如下所示:
struct can_filter rfilter[2]; //定义一个 can_filter 结构体对象 // 填充过滤规则,只接收 ID 为(can_id & can_mask)的报文 rfilter[0].can_id = 0x60A;
rfilter[0].can_mask = 0x7FF;
rfilter[1].can_id = 0x60B;
rfilter[1].can_mask = 0x7FF; // 调用 setsockopt 设置过滤规则 setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, &rfilter, sizeof(rfilter));
struct can_filter 结构体中只有两个成员,can_id 和 can_mask。
如果应用程序不接收所有报文,在这种仅仅发送数据的应用中,可以在内核中省略接收队列,以此减少CPU 资源的消耗。此时可将 setsockopt()函数的第 4 个参数设置为 NULL,将第 5 个参数设置为 0,如下所示:
setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_FILTER, NULL, 0);
数据发送/接收
在数据收发的内容方面,CAN 总线与标准套接字通信稍有不同,每一次通信都采用 struct can_frame 结构体将数据封装成帧。结构体定义如下:
示例代码 31.2.1 struct can_frame 结构体
struct can_frame { canid_t can_id; /* CAN 标识符 */ __u8 can_dlc; /* 数据长度(最长为 8 个字节) */ __u8 __pad; /* padding */ __u8 __res0; /* reserved / padding */ __u8 __res1; /* reserved / padding */ __u8 data[8]; /* 数据 */ };
can_id 为帧的标识符,如果是标准帧,就使用 can_id 的低 11 位;如果为扩展帧,就使用 0~28 位。can_id 的第 29、30、31 位是帧的标志位,用来定义帧的类型,定义如下:
/* special address description flags for the CAN_ID */ #define CAN_EFF_FLAG 0x80000000U /* 扩展帧的标识 */
#define CAN_RTR_FLAG 0x40000000U /* 远程帧的标识 */
#define CAN_ERR_FLAG 0x20000000U /* 错误帧的标识,用于错误检查 */ /* mask */ #define CAN_SFF_MASK 0x000007FFU /* <can_id & CAN_SFF_MASK>获取标准帧 ID */
#define CAN_EFF_MASK 0x1FFFFFFFU /* <can_id & CAN_EFF_MASK>获取标准帧 ID */
#define CAN_ERR_MASK 0x1FFFFFFFU /* omit EFF, RTR, ERR flags */
(1)、数据发送
对于数据发送,使用 write()函数来实现,譬如要发送的数据帧包含了三个字节数据 0xA0、0xB0 以及0xC0,帧 ID 为 123,可采用如下方法进行发送:
struct can_frame frame; //定义一个 can_frame 变量 int ret; frame.can_id = 123;//如果为扩展帧,那么 frame.can_id = CAN_EFF_FLAG | 123;
frame.can_dlc = 3; //数据长度为 3
frame.data[0] = 0xA0; //数据内容为 0xA0
frame.data[1] = 0xB0; //数据内容为 0xB0
frame.data[2] = 0xC0; //数据内容为 0xC0 ret = write(sockfd, &frame, sizeof(frame)); //发送数据 if(sizeof(frame) != ret) //如果 ret 不等于帧长度,就说明发送失败 perror("write error");
如果要发送远程帧(帧 ID 为 123),可采用如下方法进行发送:
struct can_frame frame; frame.can_id = CAN_RTR_FLAG | 123; write(sockfd, &frame, sizeof(frame));
(2)、数据接收
数据接收使用 read()函数来实现,如下所示:
struct can_frame frame; int ret = read(sockfd, &frame, sizeof(frame));
(3)、错误处理
当应用程序接收到一帧数据之后,可以通过判断 can_id 中的 CAN_ERR_FLAG 位来判断接收的帧是否为错误帧。如果为错误帧,可以通过 can_id 的其他符号位来判断错误的具体原因。错误帧的符号位在头文件<linux/can/error.h>中定义。
/* error class (mask) in can_id */ #define CAN_ERR_TX_TIMEOUT 0x00000001U /* TX timeout (by netdevice driver) */
#define CAN_ERR_LOSTARB 0x00000002U /* lost arbitration / data[0] */
#define CAN_ERR_CRTL 0x00000004U /* controller problems / data[1] */
#define CAN_ERR_PROT 0x00000008U /* protocol violations / data[2..3] */
#define CAN_ERR_TRX 0x00000010U /* transceiver status / data[4] */
#define CAN_ERR_ACK 0x00000020U /* received no ACK on transmission */
#define CAN_ERR_BUSOFF 0x00000040U /* bus off */
#define CAN_ERR_BUSERROR 0x00000080U /* bus error (may flood!) */
#define CAN_ERR_RESTARTED 0x00000100U /* controller restarted */
回环功能设置
在默认情况下,CAN 的本地回环功能是开启的,可以使用下面的方法关闭或开启本地回环功能:
int loopback = 0; //0 表示关闭,1 表示开启(默认) setsockopt(sockfd, SOL_CAN_RAW, CAN_RAW_LOOPBACK, &loopback, sizeof(loopback));
在本地回环功能开启的情况下,所有的发送帧都会被回环到与 CAN 总线接口对应的套接字上。
相关文章:
SocketCan 应用编程
SocketCan 应用编程 由于 Linux 系统将 CAN 设备作为网络设备进行管理,因此在 CAN 总线应用开发方面,Linux 提供了SocketCAN 应用编程接口,使得 CAN 总线通信近似于和以太网的通信,应用程序开发接口更加通用,也更加灵…...
从零学习python - 04函数方法与返回值
函数:Function-也称为方法,是组织好的、可重复使用的,用来实现指定功能的代码块。函数的定义与调用:创建函数目的是封装业务逻辑,实现代码复用# 创建函数关键字:def(definition)def fun1(x, y):print(x y)函数的参数:python函数中…...
MySQL实战之事务到底是隔离的还是不隔离的
1.前言 我们在MySQL实战之事务隔离:为什么你改了我还看不见讲过事务隔离级别的时候提到过,如果是可重复读隔离级别,事务T启动的时候会创建一个视图read-view,之后事务T执行期间,即使有其他事务修改了数据,事务T看到的…...
Elasticsearch:理解 Master,Elections,Quorum 及 脑裂
集群中的每个节点都可以分配多个角色:master、data、ingest、ml(机器学习)等。 我们在当前讨论中感兴趣的角色之一是 master 角色。 在 Elasticsearch 的配置中,我们可以配置一个节点为 master 节点。master 角色的分配表明该节点…...
【致敬女神】HTMLReport应用之Unittest+Python+Selenium+HTMLReport项目自动化测试实战
HTMLReport应用之UnittestPythonSeleniumHTMLReport项目自动化测试实战1 测试框架结构2 技术栈3 实现思路3.1 使用HtmlTestRunner3.2 使用HTMLReport4 TestRunner参数说明4.1 源码4.2 参数说明5 框架代码5.1 common/reportOut.py5.2 common/sendMain.py5.3 report5.3.1 xxx.htm…...
JAVA的16 个实用代码优化小技巧
一、类成员与方法的可见性最小化 举例:如果是一个private的方法,想删除就删除。 如果一个public的service方法,或者一个public的成员变量,删除一下,不得思考很多。 二、使用位移操作替代乘除法 计算机是使用二进制…...
并发编程的三大挑战之原子性及其解决方案
目录 一、原子性问题 1、带来原子性问题的原因 2、如何解决线程切换带来的原子问题 2.1、使用synchronized关键字来保证 2.2、使用CAS来保证原子性 2.3、使用lock锁来保证 一、原子性问题 1、带来原子性问题的原因 线程切换是带来原子的根本原因,java的并发程…...
QML动画(其他的动画)
PauseAnimation (暂停动画) 为动画提供暂停 Rectangle{id:rect1width: 100;height: 100;x:100;y:100color: "lightBlue"SequentialAnimation{running: trueColorAnimation {target: rect1;property: "color";…...
Spark 配置项
Spark 配置项硬件资源类CPU内存堆外内User Memory/Spark 可用内存Execution/Storage Memory磁盘ShuffleSpark SQLJoin 策略调整自动分区合并自动倾斜处理配置项分为 3 类: 硬件资源类 : 与 CPU、内存、磁盘有关的配置项Shuffle 类 : Shuffle 计算过程的配置项Spark SQL : Spar…...
掌握Vue3模板语法,助你轻松实现高效Web开发
Vue3作为前端开发中的一种主流框架,为我们提供了多种灵活的方式来处理模板语法。除了基础的模板语法,Vue3还提供了一些高级的语法,可以让我们更好地处理组件、响应式数据和UI逻辑等。在这篇博客中,我们将介绍Vue3中的一些高级模板…...
Jmeter+Ant+Jenkins接口自动化测试平台搭建
平台简介一个完整的接口自动化测试平台需要支持接口的自动执行,自动生成测试报告,以及持续集成。Jmeter支持接口的测试,Ant支持自动构建,而Jenkins支持持续集成,所以三者组合在一起可以构成一个功能完善的接口自动化测…...
ncnn部署(CMakelists.txt)
1. NCNN 环境安装 参考博客: 基于ncnn的yolov5模型部署 1. 1 protobuf编译 打开VS2013/VS2019的X64命令行(注意不是cmd),我这里以V32013环境进行编译 > cd <protobuf-root-dir> > mkdir build-vs2013 > cd build-vs2013 > cmake -G"NMake Makefil…...
SQL分库分表
什么是分库分表? 分库分表是两种操作,一种是分库,一种是分表。 分库分表又分为垂直拆分和水平拆分两种。 (1)分库:将原来存放在单个数据库中的数据,拆分到多个数据库中存放。 (2&…...
大数据分析案例-基于逻辑回归算法构建微博评论情感分类模型
🤵♂️ 个人主页:@艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+ 喜欢大数据分析项目的小伙伴,希望可以多多支持该系列的其他文章 大数据分析案例合集…...
0105深度优先搜索算法非递归2种实现对比-无向图-数据结构和算法(Java)
1 两种非递归实现 在前面我们解决无向图的单点通性和单点路径问题时,都用到了深度优先搜索算法。深度优先搜索算法可以用递归和非递归两种方式。这里讨论非递归实现。 无向图结构使用邻接表实现。 第一种非递归方法(推荐),代码如…...
传统手工数据采集耗时耗力?Smartbi数据填报实现数据收集分析自动化
企业在日常经营管理过程中,往往需要收集很多内外部的信息,清洗整理后再进行存储、分析、呈现、决策支持等各种作业,如何高效收集结构化数据是企业管理者经常要面对的问题。传统手工的数据采集方式不仅耗费了大量人力时间成本,还容…...
《Spring源码深度分析》第5章 Bean的加载
目录标题前言一、Bean加载入口与源码分析1、Bean加载的入口2、Bean加载源码二、FactoryBean的使用三、缓存中获取单例bean(待补充)前言 经过前面的分析,我们终于结束了对XML 配置文件的解析,接下来将会面临更大的挑战,就是对 bean 加载的探索…...
华为OD机试真题Java实现【求最大数字】真题+解题思路+代码(20222023)
求最大数字 题目 给定一个由纯数字组成以字符串表示的数值,现要求字符串中的每个数字最多只能出现2次,超过的需要进行删除;删除某个重复的数字后,其它数字相对位置保持不变。 如34533,数字3重复超过2次,需要删除其中一个3,删除第一个3后获得最大数值4533 请返回经过删…...
Java——异常机制
前言 随着对java的不断深入学习,在对语法以及编程思想有了一定的了解之后,在编程的过程中有可能会因为用户的输入不正确或者逻辑错误而出现异常或者错误,因此如何去捕捉与避免不应该出现的异常或者错误就变得十分重要。本文就介绍了java的异…...
【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(下)
系列文章目录 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(上) 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate)12.2实时异构同步Oracle数据部署方案(中) 【大数据实时数据同步】超级详细的生产环境OGG(GoldenGate…...
ESP32设备驱动-土壤湿度传感器驱动
土壤湿度传感器驱动 1、土壤湿度传感器介绍 土壤湿度传感器由两个探头组成,用于测量水的体积含量。 两个探头让电流通过土壤,然后得到电阻值来测量水分值。 当有更多的水时,土壤会传导更多的电,这意味着电阻会更小。 因此,水分含量会更高。 干燥的土壤导电性差,所以当…...
公网远程连接MongoDB数据库【内网穿透】
文章目录1. 安装数据库2. 内网穿透2.1 创建隧道映射2.2 测试随机公网地址远程连接3. 配置固定TCP端口地址3.1 保留一个固定的公网TCP端口地址3.2 配置固定公网TCP端口地址3.3 测试固定地址公网远程访问MongoDB是一个基于分布式文件存储的数据库。由C语言编写。旨在为WEB应用提供…...
SQL注入——floor报错注入
目录 一,涉及到的函数 rand() floor() concat_ws() as别名,group by分组 count() 报错原理 一,涉及到的函数 rand()函数:随机返回0~1间的小数 floor()函数:小数向…...
P6入门:在EPS下创建项目(P6Professional)
引言 在 Primavera P6 中,一旦创建了企业项目结构EPS,就可以开始向该结构添加项目。项目是一组活动和数据,它们构成了创建产品或服务的计划。项目有开始日期和结束日期,可以包括活动、资源、工作分解结构、组织分解结构、日历、关…...
Linux安装及管理应用和账号和权限管理 讲解
♥️作者:小刘在C站 ♥️个人主页:小刘主页 ♥️每天分享云计算网络运维课堂笔记,努力不一定有收获,但一定会有收获加油!一起努力,共赴美好人生! ♥️夕阳下,是最美的绽放࿰…...
【JDK1.8 新特性】Stream API
1. 前言 Java8中有两大最为重要的改变。第一个是 Lambda 表达式;另外一个则是 Stream API。Stream API ( java.util.stream) 把真正的函数式编程风格引入到Java中。这是目前为止对Java类库最好的补充,因为Stream API可以极大提供Java程序员的生产力&…...
Springboot Maven打包跳过测试的五种方式总结 -Dmaven.test.skip=true
使用Maven打包的时候,可能会因为单元测试打包失败,这时候就需要跳过单元测试。也为了加快打包速度,也需要跳过单元测试。 Maven跳过单元测试五种方法。 在正式环境中运行Springboot应用,需要先打包,然后使用java -ja…...
静态链接和动态链接的区别
链接即为编译(包含预编译,编译和汇编过程)完成之后的过程,此过程又分为静态链接和动态链接两种方式。 1、静态链接 静态链接就是在生成可执行文件的时候(链接阶段),把所有需要的函数的二进制代…...
MATLAB学习笔记1
MATLAB学习笔记1 - 向量和矩阵 Matlab的数组可以是行向量,列向量,矩阵形式等 1.利用[ ]创建数组 例:包含7和9的一个数组,使用空格或,为行 x [7 9]//x是一个1*2的矩阵 y[7,9]//y是一个1*2的矩阵例:包含7和…...
Gorm -- 查询记录
文章目录查询单条记录通过结构体查询对应表指定表并将查询一条记录结果放至字典中按照主键查询查询多行记录按照主键查询使用结构体查询指定表名查询并放至字典列表中指定查询字段查询条件Where 条件(、like、in)通过结构体或字典设置查询条件或非排序Li…...
wordpress popuppress/产品推广软文
2019独角兽企业重金招聘Python工程师标准>>> 下面主要从队列、消息发送、消息接收方面了解消息传递过的一些可靠性处理。 1、队列 消费者是无法订阅或者获取不存在的MessageQueue中信息。消息被Exchange接受以后,如果没有匹配的Queue,则会被…...
做瞹瞹嗳视频网站在线观看/网络营销招聘岗位有哪些
夜光序言: 即使身边满是凄荒、冷淡与麻木,风也会吹得柔和,心也能寻得一份温存 正文:接下来~~,实战项目:一个拥有答题页面的微信小程序 上图为实际效果图 那么如何制作出来呢~ 点击“开始测试”按钮&#x…...
网站制作建设是做什么/十大骗子教育培训机构
文章目录 前言I 使用catchTouchPoint 函数实现点坐标的获取II 使用iOS API获取在屏幕上的点击坐标2.1 创建`UIApplication` 子类,实现`sendEvent:`获取在屏幕上的点击坐标2.2 在main方法添加principalClassNamesee also前言 获取屏幕坐标的方式: LUA 函数touchDown(idx, x, …...
橙子落地页建站工具/网络营销企业网站优化
实验4 数 组姓名: 学号: 实验日期: 2013-11-17实验目的和要求(1)掌握一维数组与二维数组的定义、使用及初始化方法。(2)学习数组作为函数参数的用法。(3)掌握字符数组和字符串函数的使用方法。(4)掌握与数组有关的常用排序算法,进…...
前端做任务的网站/中超最新积分榜
1.1 指定运行级别运行级别说明: 0 : 关机 1 : 单用户[召回丢失密码] 2 : 多用户状态没有网络服务 3 : 多用户状态有网络服务 4 : 系统未使用保留给用户 5 : 图形界面 6 : 系统重启常用运行级别是 3 和 5 ,要修改默认的运行级别可改文件 /etc/inittab 的 id:5:initde…...
手机网站制作哪家公司好/目前好的推广平台
康拓展开: 求出当前排列是全排列中的第几个 Xa[n]*(n-1)!a[n-1]*(n-2)!...a[i]*(i-1)!...a[1]*0! 其中a[i]是当前位置后面有多少个比当前位置大的数, 可以看成是求当前位置的逆序。 int cantor(int n, int num[]){int c 0;int cnt 0;for(int i 0; i …...