• LWIP的底层结构(物理层)


    LWIP的底层结构(物理层)

    转自:http://bluefish.blog.51cto.com/214870/158418

    我们前面讲到说是ip层的发送和接收都是直接调用了底层,也就是设备驱动层的函数实现,在这里暂且称之为物理层吧。下面就接着ip层的讲,不过由于这里的设备驱动各平台的都不一样,为此,我们选择ARM9_STR91X_IAR这个Demo作为实例,该平台的网络设备驱动在librarysource91x_enet.c文件中。而ethernetif.c文件就是我们需要的,它是连接设备驱动程序与ip层的桥梁。

           Ethernetif.c文件中提供的函数主要有以下这么几个:

    (1)    low_level_init

    (2)    low_level_input

    (3)    low_level_output

    (4)    ethernetif_init

    (5)    ethernetif_input

    (6)    ethernetif_output

    这里对外的接口只有ethernetif_init函数,它是main函数中通过

    netif_add( &EMAC_if, &xIpAddr, &xNetMast, &xGateway, NULL, ethernetif_init, tcpip_input );来被调用的。我们可以清楚的看到,tcpip_input的使用,它就是被用来当有数据接收的时候被调用的以使接收到的数据进入tcpip协议栈。

           netif_add函数中,我们可以看到

    netif->input = input;

    if (init(netif) != ERR_OK)

    {

        return NULL;

    }

     

    Ok,从这里就进入到ethernetif_init函数了,在这个函数中,我们主要看以下几句:

    netif->output = ethernetif_output;

    netif->linkoutput = low_level_output;

    low_level_init(netif);

    etharp_init();

    可以看到,netif->output 和netif->linkoutput被赋值了,这个很重要的,等会再说。

    好,再接着看low_level_init函数

    s_pxNetIf = netif;//对全局变量s_pxNetIf 赋初值

    ENET_InitClocksGPIO();

    ENET_Init();

    ENET_Start();//这3句是对网络设备的寄存等的配置

    xTaskCreate( ethernetif_input, ( signed portCHAR * ) "ETH_INT", netifINTERFACE_TASK_STACK_SIZE, NULL, netifINTERFACE_TASK_PRIORITY, NULL );

    ethernet_input创建task,这个函数也很有意思,首先可以看到的是一个无限循环,在循环体中有以下调用:

    p = low_level_input( s_pxNetIf );

    s_pxNetIf->input(p, s_pxNetIf);//tcpip_input

    虽然有了这两句,还不是很清楚,可以确定的是后一句是把接收到的数据送入tcpip协议栈处理,为此,我们想到上一句是从硬件读出数据。看下具体的low_level_input函数实现:

    len = ENET_HandleRxPkt(s_rxBuff);

    这个函数很好理解,主要的是上面的那一句。

    /******************************************************************************

    * Function Name  : ENET_HandleRxPkt

    * Description    : receive a packet and copy it to memory pointed by ppkt.

    * Input          : ppkt: pointer on application receive buffer.

    * Output         : None

    * Return         : ENET_NOK - If there is no packet

    *                : ENET_OK  - If there is a packet

    ******************************************************************************/

    u32 ENET_HandleRxPkt ( void *ppkt)

    {

    ENET_DMADSCRBase *pDescr;

    u16 size;

    static int iNextRx = 0;

     

           if( dmaRxDscrBase[ iNextRx ].dmaPackStatus &

    DMA_DSCR_RX_STATUS_VALID_MSK )

           {

                  return 0;

           }

     

           pDescr = &dmaRxDscrBase[ iNextRx ];

     

           /*Get the size of the packet*/

           size = ((pDescr->dmaPackStatus & 0x7ff) - 4);

     

           //MEMCOPY_L2S_BY4((u8*)ppkt, RxBuff, size); /*optimized memcopy function*/

           memcpy(ppkt, RxBuff[iNextRx], size);   //string.h library*/

     

           /* Give the buffer back to ENET */

           pDescr->dmaPackStatus = DMA_DSCR_RX_STATUS_VALID_MSK;

     

           iNextRx++;

     

           if( iNextRx >= ENET_NUM_RX_BUFFERS )

           {

                  iNextRx = 0;

           }

     

           /* Return no error */

           return size;

    }

    这个函数也很好理解,是从DMA中直接拷贝数据到指定的pBuf。至此,input过程完事了,从代码调用流程上看真是千回百转,一会low_level,一会ethernetif。不过,总体来说是系统通过一个task(ethernetif_input)轮询检查DMA控制器的状态以判断是否有数据接收到。

           下面再研究下output过程。Output过程是由应用程序以主动方式触发的,经过前面几篇的介绍,我们知道发送的数据后来被传递给了ip_output_if函数。我们就接着这个函数看,它直接调用了netif->output函数,刚才我们看到在ethernetif_init中有对这个变量【函数指针】赋值,它就是ethernetif_output。它倒是简单,直接return etharp_output();而它有在最后调用了etharp_send_ip,在这个函数的最后调用了return netif->linkoutput(netif, p);好了终于找到根了这里的linkoutput函数也就是low_level_output,果然有如下调用:

    memcpy(&TxBuff[l], (u8_t*)q->payload, q->len);

           还记得ENET_Init嘛,它的函数实现中有如下两句调用:

    ENET_TxDscrInit();

    ENET_RxDscrInit();

    它们就是初始化DMA发送和接收的地址的,也就是上面所说的TxBuff和RxBuff。


  • 相关阅读:
    Python 文件操作
    Python 操作 sqlite
    Python中的random模块
    Linux系统下的/etc/nsswitch.conf文件
    Python 列表/元组/字典总结
    快斗之翼:python2的print和python3的print()
    田小计划:图解Python深拷贝和浅拷贝
    Python 自省指南
    Python运算符优先级
    tc: 模拟网络异常的工具
  • 原文地址:https://www.cnblogs.com/alan666/p/8312148.html
Copyright © 2020-2023  润新知