转载请注明出处: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 谢谢!

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

  1. SOCKET CAN的理解

    转载请注明出处:http://blog.csdn.net/Righthek 谢谢! CAN总线原理 由于Socket CAN涉及到CAN总线协议.套接字.Linux网络设备驱动等.因此,为了能够全面地 ...

  2. Web性能优化之-深入理解TCP Socket

    什么是Socket?    大家都用电脑上网,当我们访问运维社区https://www.unixhot.com的时候,我们的电脑和运维社区的服务器就会创建一条Socket,我们称之为网络套接字.那么既 ...

  3. socket 进程通讯理解

    [转]https://blog.csdn.net/andrewgithub/article/details/81613120 正如可以给fopen的传入不同参数值,以打开不同的文件.创建socket的 ...

  4. flash as3 socket安全服务网关(socket policy file server)

    关键字: SecurityErrorEvent socket as3 flash有着自己的一套安全处理模式,在socket方面,我这样的菜鸟无法理解他的好处:一句话,不怀好意的人如果想用flash写一 ...

  5. Windows socket之最简单的socket程序

    原文:Windows socket之最简单的socket程序 最简单的服务器的socket程序流程如下(面向连接的TCP连接 ): 1. WSAStartup(); 初始化网络库的使用. 2. soc ...

  6. python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)

    先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...

  7. [C#]Socket通信BeginReceive异步接收数据何时回调Callback

    原文地址:http://www.cnblogs.com/wangtonghui/p/3277303.html 最近在做服务器压力测试程序. 接触了一段时间Socket异步通讯,发现自己对BeginRe ...

  8. socket 中午吃的啥 socket 并发服务器 fork

    http://www.cnblogs.com/thinksasa/archive/2013/02/26/2934206.html zh.wikipedia.org/wiki/網路插座 在作業系統中,通 ...

  9. 为什么有监听socket和连接socket,为什么产生两个socket

    为什么有监听socket和连接socket,为什么产生两个socket 先看一半的socket建立连接的双方的过程: 客户端: socket()---->创建出 active_socket_fd ...

随机推荐

  1. 对比hive和mysql查询汇总

    由于底层的处理机制大不相同,hive和mysql在查询上还是有较大差异的! 单个表的select操作 最简单的查询 ,字段2 frome 表名 where 字段 [not]in(元素1,元素2): 例 ...

  2. Verilog之event

    1 Explicit event The value changes on nets and variable can be used as events to trigger the executi ...

  3. x86汇编之十(使用字符串)

    x86汇编之十(使用字符串) 转自网络,出处不详 一.传送字符串 Intel提供了完整的字符串传送指令,就像是MOV指令一样. 1.MOVS指令 1)movs指令格式 把字符串从一个位内存位置传送到另 ...

  4. CAD把一个dwg文件,或者图像文件当着一个背景导入(com接口VB语言)

    主要用到函数说明: MxDrawXCustomFunction::Mx_OpenBackgroundFile 把一个dwg文件,或者图像文件当着一个背景导入.详细说明如下: 参数 说明 CString ...

  5. <东方梦符祭> N2无尽40波通关

    先上图吧 阵容:纯粹 + 伪魔法队 主C:神妈 露米娅(我觉得不厉害了) 灵梦 控制:琪露诺 + 蕾蒂 永江依玖(听说很厉害 没培育满 没看到效果) 挂件:铃仙挂机 帕秋莉 大妖精(链神妈) 圣今天才 ...

  6. Linux常用命令——压缩与解压缩命令

    常用压缩格式:  .zip   .gz   .bz2   .tar.gz   .tar.bz2 1..zip格式压缩 zip 压缩文件名 源文件 压缩文件 zip -r 压缩文件名 源目录 压缩目录 ...

  7. Extjs查询实现

    效果图如上: 页面代码: Ext.QuickTips.init(); //放在图标上会自动提示信息 Ext.define('ExtApp.view.StudentList' , { extend : ...

  8. 【转】精选十二款餐饮、快递、票务行业微信小程序源码demo推荐

    微信小程序的初衷是为了线下实体业服务的,必须有实体相结合才能显示小程序的魅力.个人认为微信小程序对于餐饮业和快递业这样业务比较单一的行业比较有市场,故整理推荐12款餐饮业和快递业微信小程序源码demo ...

  9. 如何通过js在子页面调用父页面元素的click事件

    //获取父页面的某个元素var node = window.parent.document.getElementById("btnReturn");//调用该元素的Click事件 ...

  10. Apache 流框架 Flink,Spark Streaming,Storm对比分析(2)

    此文已由作者岳猛授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 2.Spark Streaming架构及特性分析 2.1 基本架构 基于是spark core的spark s ...