LWIP的底层结构(物理层)
LWIP的底层结构(物理层)
转自:http://bluefish.blog.51cto.com/214870/158418
我们前面讲到说是ip层的发送和接收都是直接调用了底层,也就是设备驱动层的函数实现,在这里暂且称之为物理层吧。下面就接着ip层的讲,不过由于这里的设备驱动各平台的都不一样,为此,我们选择ARM9_STR91X_IAR这个Demo作为实例,该平台的网络设备驱动在\library\source\91x_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。
LWIP的底层结构(物理层)的更多相关文章
- V7000存储数据恢复_底层结构原理拆解及Mdisk磁盘掉线数据恢复方法
Storwize V7000(也就是我们常说的V7000)是新推出的一款中端存储系统,这款系统的定位虽然在中端,但是Storwize V7000提供有存储管理功能,这一功能以前只有高端存储才拥有(例如 ...
- [转]谈NAND Flash的底层结构和解析
这里我想以一个纯玩家的角度来谈谈关于NAND Flash的底层结构和解析,可能会有错误的地方,如果有这方面专家强烈欢迎指正. NAND Flash作为一种比较实用的固态硬盘存储介质,有自己的一些物理特 ...
- HP-lefthand底层结构具体解释及存储灾难数据恢复
HP-lefthand底层结构具体解释及存储灾难数据恢复 一.HP-lefthand的特点 HP-lefhand是一款很不错的SAN存储,使用iscsi协议为client分配空间. 它支持RAID5. ...
- Redis底层结构全了解
第一篇文章,思来想去,写一写Redis吧,最近在深入研究它. 一丶Redis底层结构 1. redis 存储结构 redis的存储结构从外层往内层依次是redisDb.dict.dictht.dict ...
- String,StringBuffer,StringBuillder的底层结构
一:StringBuffer的底层 (1)线程安全的字符串操作类 (2)通过synchronized关键字声明同步方法,保证多线程环境下数据安全 public synchronized StringB ...
- java集合专题 (ArrayList、HashSet等集合底层结构及扩容机制、HashMap源码)
一.数组与集合比较 数组: 1)长度开始时必须指定,而且一旦指定,不能更改 2)保存的必须为同一类型的元素 3)使用数组进行增加/删除元素-比较麻烦 集合: 1)可以动态保存任意多个对象,使用比较方便 ...
- Lwip与底层的接口
Lwip有三套api,分别是: raw api:使用方法为使用回调函数,即先注册一个函数,当接受到数据之后调用这个函数.缺点是对于数据连续处理不好. Lwip api:把接收与处理放在一个线程里面.因 ...
- Java程序猿从笨鸟到菜鸟之(九十二)深入java虚拟机(一)——java虚拟机底层结构具体解释
本文来自:曹胜欢博客专栏.转载请注明出处:http://blog.csdn.net/csh624366188 在曾经的博客里面,我们介绍了在java领域中大部分的知识点,从最基础的java最基本的语法 ...
- HashMap底层结构、原理、扩容机制
https://www.jianshu.com/p/c1b616ff1130 http://youzhixueyuan.com/the-underlying-structure-and-princip ...
随机推荐
- 深入详解WPF ControlTemplate
WPF包含数据模板和控件模板,其中控件模板又包括ControlTemplate和ItemsPanelTemplate,这里讨论一下WPF ControlTemplate. 其实WPF的每一个控件都有一 ...
- ios --转载 在mac上安装让rvm及cocoa pods详解
先安装rvm: 打开终端: $ curl -L https://get.rvm.io | bash -s stable (期间可能会问你sudo管理员密码,以及自动通过homebrew安装依赖包,等待 ...
- 初识python轻量web框架flask
1.使用pip安装Python包 大多数Python包都使用pip实用工具安装,使用pyvenv创建的虚拟环境会自动安装pip. 1.使用pip安装Flask(其它Python包同理) pip ins ...
- [ACM] HDU 1533 Going Home (二分图最小权匹配,KM算法)
Going Home Time Limit: 10000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others) Tota ...
- 【BZOJ4966】总统选举 线段树+随机化
[BZOJ4966]总统选举 Description 黑恶势力的反攻计划被小C成功摧毁,黑恶势力只好投降.秋之国的人民解放了,举国欢庆.此时,原秋之国总统因没能守护好国土,申请辞职,并请秋之国人民的大 ...
- Git with SVN
1)GIT是分布式的,SVN不是: 这 是GIT和其它非分布式的版本控制系统,例如SVN,CVS等,最核心的区别.好处是跟其他同事不会有太多的冲突,自己写的代码放在自己电脑上,一段时间后再提交.合并, ...
- 【题解】[CF718C Sasha and Array]
[题解]CF718C Sasha and Array 对于我这种喜欢写结构体封装起来的选手这道题真是太对胃了\(hhh\) 一句话题解:直接开一颗线段树的矩阵然后暴力维护还要卡卡常数 我们来把\(2 ...
- Flask:工厂函数和蓝本
我们用pycharm去新建Flask项目的时候,会默认生成开发文件.如下,其中包括static,templates,flask1_prj.py文件 在最初开始的时候,我们的app等声明都是在flask ...
- Error: Failed to fetch plugin E:_My_File______workMyCodemyCodecordova-workspaceplugman-testMyMath via registry. Probably this is either a connection problem, or plugin spec is incorrect.
$ cordova plugin add E:\_My_File_____\_work\MyCode\myCode\cordova-workspace\plugman-test\MyMath --sa ...
- Oracle伪列rownum
Oracle基础知识:伪列rownum,伪列就像表中的列一样,但是在表中并不存储.伪列只能查询,不能进行增删改操作. 在查询的结果集中,ROWNUM为结果集中每一行标识一个行号,第一行返回1,第二行返 ...