zoukankan      html  css  js  c++  java
  • 对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 ");

                                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 ");

                                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 ");

                                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 ");

                                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 ");

                                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 谢谢!




  • 相关阅读:
    python PyQt5
    传入一张图,生成它的油画版!(python实现)(转 )
    Python——画一棵漂亮的樱花树(不同种樱花+玫瑰+圣诞树喔)(转)
    Python3.7实现自动刷博客访问量(只需要输入用户id)(转)
    Python3 多线程的两种实现方式
    图片生成字符
    SqlServer性能优化 通过压缩与计算列提高性能(十一)
    json与bson的区别
    浅析Redis 和MongoDB
    Solr DocValues详解
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/7120075.html
Copyright © 2011-2022 走看看