对Socket CAN的理解(4)——【Socket CAN接收数据流程】

2023-05-16

转载请注明出处:http://blog.csdn.net/Righthek 谢谢!

          现在我们来分析一下CAN总线的接收数据流程,对于网络设备,数据接收大体上采用中断+NAPI机制进行数据的接收。同样,我们现在的CAN模块也是采用同样的方式进行数据的接收。由于我们只针对CAN总线接收数据这条主线进行分析。因些,会忽略一些针对CAN协议的设置及初始化等相关代码。

         在初始化CAN设备时,我们需要给CAN设备分配NAPI功能。我们通过netif_napi_add()函数将CAN设备添加到NAPI机制列表中。源码如下:

struct net_device *alloc_d_can_dev(intnum_objs)

{

         structnet_device *dev;

         structd_can_priv *priv;

         dev= alloc_candev(sizeof(struct d_can_priv), num_objs/2);

         if(!dev)

                   returnNULL;

         priv= netdev_priv(dev);

         netif_napi_add(dev, &priv->napi,d_can_poll, num_objs/2);

         priv->dev= dev;

         priv->can.bittiming_const= &d_can_bittiming_const;

         priv->can.do_set_mode= d_can_set_mode;

         priv->can.do_get_berr_counter= d_can_get_berr_counter;

         priv->can.ctrlmode_supported= (CAN_CTRLMODE_LOOPBACK |

                                               CAN_CTRLMODE_LISTENONLY|

                                               CAN_CTRLMODE_BERR_REPORTING|

                                               CAN_CTRLMODE_3_SAMPLES);

         returndev;

}

         以上将CAN设备添加到NAPI机制列表中后,那么如何去调用它呢?(关于NAPI机制,请查看文章《曾经的足迹——对CAN驱动中的NAPI机制的理解》)接下来就是中断做的事情了。在中断处理函数d_can_isr中,我们通过napi_schedule()函数调度已经在NAPI机制列表中的d_can_poll()函数。该函数会通过轮询的方式接收数据。而根据NAPI机制,当中断产生后,会调度轮询机制同时关闭所有的中断。流程如下图:

                                                           

static irqreturn_t d_can_isr(intirq, void *dev_id)

{

         structnet_device *dev = (struct net_device *)dev_id;

         structd_can_priv *priv = netdev_priv(dev);

         priv->irqstatus= d_can_read(priv, D_CAN_INT);

         if(!priv->irqstatus)

                   returnIRQ_NONE;

         /*disable all interrupts and schedule the NAPI */

         d_can_interrupts(priv,DISABLE_ALL_INTERRUPTS);

         napi_schedule(&priv->napi);

         returnIRQ_HANDLED;

}

         当中断产生时,会调用以下函数d_can_poll(),该函数即采用轮询的方式进行数据的接收。由于CAN总线状态中断具有最高优先权,在接收数据之前,需要对CAN总线的状态进行判断。而对于CAN总线错误状态有三种:

(1)      主动错误;

(2)      被动错误;

(3)      总线关闭;

static int d_can_poll(structnapi_struct *napi, int quota)

{

         intlec_type = 0;

         intwork_done = 0;

         structnet_device *dev = napi->dev;

         structd_can_priv *priv = netdev_priv(dev);

         if(!priv->irqstatus)

                   gotoend;

         /*status events have the highest priority */

         if(priv->irqstatus == STATUS_INTERRUPT) {

                   priv->current_status= d_can_read(priv, D_CAN_ES);

                   /*handle Tx/Rx events */

                   if(priv->current_status & D_CAN_ES_TXOK)

                            d_can_write(priv,D_CAN_ES,

                                               priv->current_status& ~D_CAN_ES_TXOK);

                   if(priv->current_status & D_CAN_ES_RXOK)

                            d_can_write(priv,D_CAN_ES,

                                               priv->current_status& ~D_CAN_ES_RXOK);

                   /*handle state changes */

                   if((priv->current_status & D_CAN_ES_EWARN) &&

                                     (!(priv->last_status& D_CAN_ES_EWARN))) {

                            netdev_dbg(dev,"entered error warning state\n");

                            work_done+= d_can_handle_state_change(dev,

                                                        D_CAN_ERROR_WARNING);

                   }

                   if((priv->current_status & D_CAN_ES_EPASS) &&

                                     (!(priv->last_status& D_CAN_ES_EPASS))) {

                            netdev_dbg(dev,"entered error passive state\n");

                            work_done+= d_can_handle_state_change(dev,

                                                        D_CAN_ERROR_PASSIVE);

                   }

                   if((priv->current_status & D_CAN_ES_BOFF) &&

                                     (!(priv->last_status& D_CAN_ES_BOFF))) {

                            netdev_dbg(dev,"entered bus off state\n");

                            work_done +=d_can_handle_state_change(dev,

                                                        D_CAN_BUS_OFF);

                   }

                   /*handle bus recovery events */

                   if((!(priv->current_status & D_CAN_ES_BOFF)) &&

                                     (priv->last_status& D_CAN_ES_BOFF)) {

                            netdev_dbg(dev,"left bus off state\n");

                            priv->can.state= CAN_STATE_ERROR_ACTIVE;

                   }

                   if((!(priv->current_status & D_CAN_ES_EPASS)) &&

                                     (priv->last_status& D_CAN_ES_EPASS)) {

                            netdev_dbg(dev,"left error passive state\n");

                            priv->can.state= CAN_STATE_ERROR_ACTIVE;

                   }

                   priv->last_status= priv->current_status;

                   /*handle lec errors on the bus */

                   lec_type= d_can_has_handle_berr(priv);

                   if(lec_type)

                            work_done+= d_can_handle_bus_err(dev, lec_type);

         }else if ((priv->irqstatus >= D_CAN_MSG_OBJ_RX_FIRST) &&

                            (priv->irqstatus<= D_CAN_MSG_OBJ_RX_LAST)) {

                   /*handle events corresponding to receive message objects */

                   work_done+= d_can_do_rx_poll(dev, (quota - work_done));

         }else if ((priv->irqstatus >= D_CAN_MSG_OBJ_TX_FIRST) &&

                            (priv->irqstatus<= D_CAN_MSG_OBJ_TX_LAST)) {

                   /*handle events corresponding to transmit message objects */

                   d_can_do_tx(dev);

         }

end:

         if(work_done < quota) {

                   napi_complete(napi);

                   /*enable all IRQs */

                   d_can_interrupts(priv,ENABLE_ALL_INTERRUPTS);

         }

         returnwork_done;

}

          当总线状态数据状态正常时,进行数据的接收。

static int d_can_do_rx_poll(structnet_device *dev, int quota)

{

         structd_can_priv *priv = netdev_priv(dev);

         unsignedint msg_obj, mctrl_reg_val;

         u32num_rx_pkts = 0;

         u32intpnd_x_reg_val;

         u32intpnd_reg_val;

         for(msg_obj = D_CAN_MSG_OBJ_RX_FIRST; msg_obj <= D_CAN_MSG_OBJ_RX_LAST

                                     &&quota > 0; msg_obj++) {

                   intpnd_x_reg_val= D_CAN_GET_XREG_NUM(priv, D_CAN_INTPND_X);

                   intpnd_reg_val= d_can_read(priv,

                                               D_CAN_INTPND(intpnd_x_reg_val));

                   /*

                    * as interrupt pending register's bit n-1corresponds to

                    * message object n, we need to handle the sameproperly.

                    */

                   if(intpnd_reg_val & (1 << (msg_obj - 1))) {

                            d_can_object_get(dev,D_CAN_IF_RX_NUM, msg_obj,

                                               D_CAN_IF_CMD_ALL&

                                               ~D_CAN_IF_CMD_TXRQST);

                            mctrl_reg_val= d_can_read(priv,

                                               D_CAN_IFMCTL(D_CAN_IF_RX_NUM));

                            if(!(mctrl_reg_val & D_CAN_IF_MCTL_NEWDAT))

                                     continue;

                            /*read the data from the message object */

                            d_can_read_msg_object(dev, D_CAN_IF_RX_NUM,

                                                        mctrl_reg_val);

                            if(mctrl_reg_val & D_CAN_IF_MCTL_EOB)

                                     d_can_setup_receive_object(dev,D_CAN_IF_RX_NUM,

                                               D_CAN_MSG_OBJ_RX_LAST,0, 0,

                                               D_CAN_IF_MCTL_RXIE| D_CAN_IF_MCTL_UMASK

                                               |D_CAN_IF_MCTL_EOB);

                            if(mctrl_reg_val & D_CAN_IF_MCTL_MSGLST) {

                                     d_can_handle_lost_msg_obj(dev,D_CAN_IF_RX_NUM,

                                               msg_obj);

                                     num_rx_pkts++;

                                     quota--;

                                     continue;

                            }

                            if(msg_obj < D_CAN_MSG_OBJ_RX_LOW_LAST)

                                     d_can_mark_rx_msg_obj(dev,D_CAN_IF_RX_NUM,

                                                        mctrl_reg_val,msg_obj);

                            else if (msg_obj >D_CAN_MSG_OBJ_RX_LOW_LAST)

                                     /*activate this msg obj */

                                     d_can_activate_rx_msg_obj(dev,D_CAN_IF_RX_NUM,

                                                        mctrl_reg_val,msg_obj);

                            elseif (msg_obj == D_CAN_MSG_OBJ_RX_LOW_LAST)

                                     /*activate all lower message objects */

                                     d_can_activate_all_lower_rx_msg_objs(dev,

                                                        D_CAN_IF_RX_NUM,mctrl_reg_val);

                            num_rx_pkts++;

                            quota--;

                   }

         }

         returnnum_rx_pkts;

}

          以下函数是从CAN模块的接收寄存器中接收数据。

static int d_can_read_msg_object(structnet_device *dev, int iface, int ctrl)

{

         inti;

         u32dataA = 0;

         u32dataB = 0;

         unsignedint arb_val;

         unsignedint mctl_val;

         structd_can_priv *priv = netdev_priv(dev);

         structnet_device_stats *stats = &dev->stats;

         structsk_buff *skb;

         structcan_frame *frame;

         skb= alloc_can_skb(dev, &frame);

         if(!skb) {

                   stats->rx_dropped++;

                   return-ENOMEM;

         }

         frame->can_dlc= get_can_dlc(ctrl & 0x0F);

         arb_val= d_can_read(priv, D_CAN_IFARB(iface));

         mctl_val= d_can_read(priv, D_CAN_IFMCTL(iface));

         if(arb_val & D_CAN_IF_ARB_MSGXTD)

                   frame->can_id= (arb_val & CAN_EFF_MASK) | CAN_EFF_FLAG;

         else

                   frame->can_id= (arb_val >> 18) & CAN_SFF_MASK;

         if(mctl_val & D_CAN_IF_MCTL_RMTEN)

                   frame->can_id|= CAN_RTR_FLAG;

         else{

                   dataA= d_can_read(priv, D_CAN_IFDATA(iface));

                   dataB= d_can_read(priv, D_CAN_IFDATB(iface));

                   for(i = 0; i < frame->can_dlc; i++) {

                            /*Writing MO higher 4 data bytes to skb */

                            if(frame->can_dlc <= 4)

                                     frame->data[i]= dataA >> (8 * i);

                            else{

                                     if(i < 4)

                                               frame->data[i]= dataA >> (8 * i);

                                     else

                                              frame->data[i] = dataB >> (8 *(i-4));

                            }

                   }

         }

         netif_receive_skb(skb);

         stats->rx_packets++;

         stats->rx_bytes+= frame->can_dlc;

         return0;

}

          以上是对底层CAN接收数据的分析,并没有涉及到用户空间的调用。


转载请注明出处:http://blog.csdn.net/Righthek 谢谢!



本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

对Socket CAN的理解(4)——【Socket CAN接收数据流程】 的相关文章

  • 电池充放电自动测试系统介绍

    电池是国民经济的基础产品 广泛运用在交通运输 通讯 电力 铁路 国防 计算机 应急设备等各个领域 传统电池检测生产方式已经很难满足电池产品的市场需求 那么如何高效快速的进行电池产品的性能检测呢 今天就给大家介绍一款全能型电池测试系统 电池充
  • 读书笔记_《Linux高性能服务器编程》_第 5 章:网络编程基础API

    第 5 章 Linux网络编程基础API 知识要点 socket 地址 API socket 基础 API 网络信息 API 1 socket 地址API 主机字节序和网络字节序 CPU 32位 的累加器一次至少可以装载 4 字节 即一个整
  • ‘windows socket error:由于目标机器积极拒绝,无法连接。(10061),on API 'connect'的错误?

    1 gt 连接时出现 windows socket error 10061 on API connect 是SOCKET没有启动 SCKTSRVR EXE 或者无法连接到服务器 端口等 使用socketconnect很简单 只要在应用服务器
  • CAN/CANFD 总线负载率及计算(源码和工具)

    CAN BUS的总线负载率是CAN总线架构协议设计时的一个重要的指标 一般建议负载率峰值不要高于80 平均负载率不要超过50 当然这只是一般建议 具体根据使用场景和系统设计而定 负载率定义 关于CAN负载率的定义和计算 很多文章写得不求甚解
  • 带外数据

    定义带 外 数据 想 像一下在银行人们排起队等待处理他们的帐单 在这个队伍中每个人最后都会移到前面由出纳员进行服务 现在想像一下一个走入银行 越过整个队伍 然后用枪抵 住出纳员 这个就可以看作为带 外 数据 这个强盗越过整个队伍 是因为这把
  • JDK8 网络Net包研究(一)

    网络基础 1 国际标准化组织的OSI 开放式系统互联模型 七层模型 2 TCP IP协议 组 四层模型 3 TCP IP协议组 一组包括TCP协议和IP协议 UDP协议 ICMP协议和其他一些协议的协议组 网络层 IP协议 gt 网络互连协
  • 如何实现在一个 Socket 应用程序中同时支持 IPv4 和 IPv6

    如何实现在一个 Socket 应用程序中同时支持 IPv4 和 IPv6 如何巧妙地设计代码结构 陈 鲁 软件工程师 IBM 孙 妍 软件工程师 IBM 简介 当今的网络主流是 IPv4 网络 但随着 IP 地址的日益短缺 IPv6 网络开
  • 计算机网络-----网络编程

    网络编程 实战 网络基础 1 什么是计算机网络 2 什么是网络编程 3 网络编程中的主要问题 4 网络通信要素 5 通信协议分层思想 IP和端口号 1 IP 1 1定义 1 2IP的分类 2 端口号 2 1定义 2 2端口号的分类 网络通信
  • 解决java.net.SocketException: No buffer space available (maximum connections reach

    严重 Catalina stop java net SocketException No buffer space available maximum connections reached JVM Bindat java net Plai
  • 使用socket判断http请求或http响应的传输结束

    使用socket判断http请求或http响应的传输结束 先把header直到 r n r n整个地收下来 1 传输完毕就关闭connection 即recv收到0个字节 2 有内容 if Transfer Encoding chunked
  • 推荐七种开源免费的C/C++网络库

    1 ACE 庞大 复杂 适合大型项目 开源 免费 不依赖第三方库 支持跨平台 2 Asio Asio基于Boost开发的异步IO库 封装了Socket 简化基于socket程序的开发 开源 免费 支持跨平台 3 POCO POCO C Li
  • Java Socket聊天室

    Socket聊天室 1 创建登录判断类UserLogin 2 创建登录服务器LoginServer 3 创建聊天服务器ChatServer 4 创建客户端Client 5 创建服务器用于处理聊天的线程类ChatThread 6 创建客户端C
  • C# 网络编程之Tcp实现客户端和服务器聊天

    最近使用Socket网络套接字编程中 在同步与异步通讯中客户端与服务器总是无法响应 但在学习Tcp协议编程中完成了通讯聊天功能 下面简单讲讲我最近学到的及Tcp聊天的源代码及详细注释 Tcp协议是一个传输层的协议 在Tcp协议编程中它通常使
  • 【小练习】windows与linux进行socket文件传输

    在Windows与Linux使用socket通信基础上 添加文件传输功能 需要进行简单的交互 目录 程序效果 实现流程 样例代码 测试用例 参考资料 程序效果 Windows客户端可以从Linux服务器端索要文件 也可以发送文件至Linux
  • Java中的NIO和IO的对比分析

    总的来说 java中的IO和NIO主要有三点区别 IO NIO 面向流 面向缓冲 阻塞IO 非阻塞IO 无 选择器 Selectors 1 面向流与面向缓冲 Java NIO和IO之间第一个最大的区别是 IO是面向流的 NIO是面向缓冲区的
  • linux 系统调用列表 /usr/include/asm/unistd.h

    一 进程控制 fork 创建一个新进程 clone 按指定条件创建子进程 execve 运行可执行文件 exit 中止进程 exit 立即中止当前进程 getdtablesize 进程所能打开的最大文件数 getpgid 获取指定进程组标识
  • QT进程间通信 详细介绍

    在QT中 信号和槽的机制取代了这种繁杂的 易崩溃的对象通信机制 信号是当对象状态改变时所发出的 槽是用来接收发射的信号并响应相应事件的类的成员函数 信号和槽的连接是通过connect 函数来实现的 AD 1 QT通信机制 为了更好的实现QT
  • c#Socket 异步通讯(客户端与服务端)

    c Socket 异步通讯 多个客户端与服务端 最近公司有个项目 涉及到的通讯对象有点多 就拿其中一个库的通讯来说就用到了3个PLC 这里就涉及了一个服务器与多个客户端之间的通讯了 同时上位机既需要做客户端 也需要做服务端 因为跟PLC之间
  • UDP服务recvfrom函数设置非阻塞

    基本概念 其实UDP的非阻塞也可以理解成和TCP是一样的 都是通过socket的属性去做 方法一 通过fcntl函数将套接字设置为非阻塞模式 方法二 通过套接字选项SO RECVTIMEO设置超时 方法一源码 编译 g udp server
  • linux send recv函数详解

    2009 05 10 21 55 int send SOCKET s const char FAR buf int len int flags 不论是客户还是服务器应用程序都用send函数来向TCP连接的另一端发送数据 客户程序一般用sen

随机推荐

  • JVM (Micrometer)-4701面板参数介绍

    文章目录 Quick Facts 概览 堆和非堆内存有以下几个概念 I O Overview xff08 服务黄金指标 xff09 JVM Memory xff08 JVM内存 xff09 JVM Misc xff08 JVM负载 xff0
  • curl文件传输命令

    CURL curl transfer a URL curl 是一个利用URL语法在命令行下工作的文件传输工具 支持文件上传和下载 格式 curl options URLs URL xff1a 通过大括号指定多个url 示例 xff1a cu
  • RS-485信号解析

    这次来看看RS 485信号 使用绿联的USB转RS485模块 线用的颜色不对 xff0c 类型也不对 xff0c 实际使用中请用带屏蔽层的双绞线 示波器CH1是R xff08 B xff09 示波器CH2是R 43 xff08 A xff0
  • T t与T t = T()的区别

    主要的区别就是默认构造函数对内置类型的初始化上 如果没有T中没有定义构造函数 xff0c 则对于 T t xff0c 并不会对 t 中内置类型设置初始值 xff0c 是一个随机值 但对于 T t 61 T xff0c 对 t 中内置类型会设
  • Effective STL:杂记(一)

    1 避免使用vector lt bool gt vector lt bool gt 实际上并不能算是一个STL容器 xff0c 实际上也并不存储bool 因为一个对象要成为STL容器 xff0c 就必须满足C 43 43 标准的第23 1节
  • 限制长度双向链表的插入操作

    面试遇到的问题 xff0c 一开始面试官是问我有什么方案可以实现排行榜 xff0c 当时给出了两个方案 后面面试官又在我的其中一种方案上让我手写代码实现排序双线链表的插入 xff0c 根据score值插入 xff0c 并且链表长度限制在10
  • SYD8821 IIC模块使用说明

    SYD8821是具有全球领先低功耗 RX 2 4mA 64 94 5dBm灵敏度 xff0c TX 4 3mA 64 0dBm输出功率 的蓝牙低功耗SOC芯片 xff0c 在极低电流下实现了优异的射频性能 xff0c 搭配176kB SRA
  • Python下载文件时出现乱码的解决方法之一:Content-Encoding: gzip

    之前写过一个简单的爬虫程序 xff0c 这次想试着再写一个下载固定文件的爬虫程序 写完之后发现下载的文件 xff0c 有些是可以正常打开的 xff0c 而有些是提示了编码错误 xff0c 用wireshark抓包 xff0c 过滤出http
  • Python爬虫判断url链接的是下载文件还是html文件

    最近在写一个网络爬虫的代码 xff0c 提供命令行来下载文件或者是打印根域名下指定节点及深度的子节点 用的是urllib2库 xff0c 算是比较简单 xff0c 但是功能并没有很强大 说重点吧 xff0c 在实际爬网页的过程中 xff0c
  • recvmsg和sendmsg函数

    在unp第14章讲了这两个函数 xff0c 但是只是讲了两个数据结构及参数而已 xff0c 所以自己想根据介绍来重构udp回射的客户端程序 但是sendmsg和recvmsg都遇到了问题 xff0c 并且纠结了很久 xff0c 所以在此记录
  • STL中map的[]运算导致程序挂掉的问题

    在项目的开发中 xff0c 使用 设置map变量时 xff0c 出现了Segment Fault的问题 xff0c 使用GDB bt命令得到调用栈 xff08 中间部分被我去掉了 xff09 如下 xff1a 0 0x00000000008
  • 结构体的vector resize()与初始化

    转自 xff1a https www cnblogs com kongse qi p 6798873 html 序 xff1a 我们在使用vector的时候可以自定义里面的数据类型 例如这样 xff1a struct Edge int fr
  • new(p) T1(value) 的操作

    最近开始看 STL源码剖析 xff0c 看到空间配置器的时候 xff0c 发现这么一段代码 xff1a template lt class T1 class T2 gt inline void construct T1 p const T2
  • Protobuf 编码及序列化的记录

    工作中用到了protobuf xff0c 然后之前在面试的时候面试官就问了一个问题 xff0c 如果将int32类型的字段的值设置为0 xff0c 那还会将该值进行序列化吗 xff1f 当时是懵了的 xff0c 因为自己还没有研究这部分 当
  • STM32驱动lcd1602,并口8位 6800时序

    STM32驱动lcd1602 xff0c 并口8位 6800时序 一 LCD1602 xff08 3 3V硬件版本 xff09 简介 1 1 引脚 引脚 xff0c lcd1602采用标准接口 xff0c 6800时序8位并行数据传输 第
  • CAN总线详解

    1 简介 CAN是控制器局域网络 Controller Area Network CAN 的简称 xff0c 是一种能够实现分布式实时控制的串行通信网络 优点 xff1a 传输速度最高到1Mbps xff0c 通信距离最远到10km xff
  • VS C#工程三【使用配置文件保存应用程序里的配置数据】[Resources找不到][打印log到VS窗口]【安全从工程删除图片】[发布exe并附带动态链接库dll]

    SYD8801是一款低功耗高性能蓝牙低功耗SOC xff0c 集成了高性能2 4GHz射频收发机 32位ARM Cortex M0处理器 128kB Flash存储器 以及丰富的数字接口 SYD8801片上集成了Balun无需阻抗匹配网络
  • 对Socket CAN的理解(2)——【Socket的原理及使用】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 为了能够对Socket CAN的深入理解 xff0c 我们需要了解Socket的机制 Socket的中文翻译为 插座 xff0c 在计算机
  • 对Socket CAN的理解(3)——【Socket CAN发送数据流程】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 对于本文 xff0c 我们将从用户层使用Socket CAN进行数据发送时 xff0c 数据从用户空间到底层驱动的整个通信流程 xff0c
  • 对Socket CAN的理解(4)——【Socket CAN接收数据流程】

    转载请注明出处 xff1a http blog csdn net Righthek 谢谢 xff01 现在我们来分析一下CAN总线的接收数据流程 xff0c 对于网络设备 xff0c 数据接收大体上采用中断 43 NAPI机制进行数据的接收