对Socket CAN的理解(4)——【Socket CAN接收数据流程】
转载请注明出处: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
&"a > 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接收数据流程】的更多相关文章
- SOCKET CAN的理解
转载请注明出处:http://blog.csdn.net/Righthek 谢谢! CAN总线原理 由于Socket CAN涉及到CAN总线协议.套接字.Linux网络设备驱动等.因此,为了能够全面地 ...
- Web性能优化之-深入理解TCP Socket
什么是Socket? 大家都用电脑上网,当我们访问运维社区https://www.unixhot.com的时候,我们的电脑和运维社区的服务器就会创建一条Socket,我们称之为网络套接字.那么既 ...
- socket 进程通讯理解
[转]https://blog.csdn.net/andrewgithub/article/details/81613120 正如可以给fopen的传入不同参数值,以打开不同的文件.创建socket的 ...
- flash as3 socket安全服务网关(socket policy file server)
关键字: SecurityErrorEvent socket as3 flash有着自己的一套安全处理模式,在socket方面,我这样的菜鸟无法理解他的好处:一句话,不怀好意的人如果想用flash写一 ...
- Windows socket之最简单的socket程序
原文:Windows socket之最简单的socket程序 最简单的服务器的socket程序流程如下(面向连接的TCP连接 ): 1. WSAStartup(); 初始化网络库的使用. 2. soc ...
- python 全栈开发,Day33(tcp协议和udp协议,互联网协议与osi模型,socket概念,套接字(socket)初使用)
先来回顾一下昨天的内容 网络编程开发架构 B/S C/S架构网卡 mac地址网段 ip地址 : 表示了一台电脑在网络中的位置 子网掩码 : ip和子网掩码按位与得到网段 网关ip : 内置在路由器中的 ...
- [C#]Socket通信BeginReceive异步接收数据何时回调Callback
原文地址:http://www.cnblogs.com/wangtonghui/p/3277303.html 最近在做服务器压力测试程序. 接触了一段时间Socket异步通讯,发现自己对BeginRe ...
- socket 中午吃的啥 socket 并发服务器 fork
http://www.cnblogs.com/thinksasa/archive/2013/02/26/2934206.html zh.wikipedia.org/wiki/網路插座 在作業系統中,通 ...
- 为什么有监听socket和连接socket,为什么产生两个socket
为什么有监听socket和连接socket,为什么产生两个socket 先看一半的socket建立连接的双方的过程: 客户端: socket()---->创建出 active_socket_fd ...
随机推荐
- 分布式缓存系统Memcached[分享]
个人网站:http://www.51pansou.com memcached视频下载:memcached视频教程 memcached源码下载:memcached源码 Memcached是什么? Mem ...
- golang tar gzip 压缩,解压(含目录文件)
tar是用于文件归档,gzip用于压缩.仅仅用tar的话,达不到压缩的目的.我们常见的tar.gz就是用gzip压缩生成的tar归档文件. go实现tar压缩与解压与zip类似,区别在于tar需要使用 ...
- jstree -- 使用JSON 数据组装成树
概述: 前面主要是html数据,这里主要是json数组 1.格式 jsTree需要一个具体格式JSON数据,在标准的语法没有那个字段是必须的-而是那些是你需要的.请记住你可以获取任何你请求的其他属性, ...
- MySql学习笔记(四) —— 数据的分组
前面介绍的聚集函数只是用来计算行数,平均数,最大值,最小值而不用检索所有数据.通过count()函数,我们可以计算生产商1003提供的产品数目,但如果我要查询所有生产商提供的商品数,这就需要进行分组查 ...
- wparam , lparam 传递消息
01.WM_PAINT消息 LOWORD(lParam)是客户区的宽,HIWORD(lParam)是客户区的高 02.滚动条WM_VSCROLL或WM_HSCROLL消息 LOWORD(wParam) ...
- Spring框架系列(七)--Spring常用注解
Spring部分: 1.声明bean的注解: @Component:组件,没有明确的角色 @Service:在业务逻辑层使用(service层) @Repository:在数据访问层使用(dao层) ...
- position的简单用法实例 ----- 方框里图片放对应的角标
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html> <hea ...
- ubuntu安装nvidia驱动以及cuda教程
最近尝试在ubuntu中安装nvidia的显卡驱动以及cuda.花了近三天时间,真的如网上所说错误百出,期间甚至重装了一次ubuntu系统,搞到怀疑人生,整个都是泪- -.最终经过百般“磨难”总算安装 ...
- CSS 嵌入,及其选择器
CSS 1. CSS样式表的几种使用方式 1.元素内嵌 <p style="font-size"></p> 2.内部文档内嵌 <style type= ...
- Moving Tables POJ - 1083 (思维)
题目大意 在一层楼上推桌子,每个空间一次只能推1种桌子,且消耗十分钟.可以同时推多个桌子,但是他们所占的空间不能是相交的如图 解法 真的很考验思维能力,首先考虑到这个走廊是有两排的,我瞬间想到了宿舍楼 ...