注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

我心飞翔

我有一个梦想,……

 
 
 

日志

 
 
 
 

uIP: 嵌入式TCP/IP协议栈  

2008-12-25 19:49:07|  分类: 嵌入式开发 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

转自:http://blog.zhaoke.com/64.html

uIP开源项目介绍

uIP是专为8位和16位的嵌入式微控制器设计的微型TCP/IP协议栈, 它采用BSD授权(这里可以获得完整的BSD许可证), 具有良好的互操作性, 并遵循RFC标准.

uIP提供了网络通信所必须的协议, 本身代码和占用的内存数都非常少 - uIP的源代码只有几KB, RAM占用仅几百字节.

uIP是一个完全由C语言编写的开源软件, 它的文档和源代码可用于商业和非商业用途, 它已经移植到了大部分的8位微控制器, 而且已在很多的嵌入式产品和项目中使用. (比如卫星, Cisco路由器. 查阅Links页面的几个例子)

uIP具有如下功能:
.良好的文档和源代码注释 - 几乎每一行代码都有注释.
.代码非常少.
.占用非常少的内存, 在编译时候可以设置.
.支持ARP, SLIP, IP, UDP, ICMP(ping)和TCP协议.
.提供一套实例程序: web服务器, web客户端, 电子邮件发送程序(SMTP客户端), Telnet服务器, DNS主机名解析程序.
.同时活动的TCP链接数没有限制, 在编译时候可以设置.
.可免费用于商业和非商业用途.
.TCP和IP协议遵循RFC标准, 包括流控制, 片断分割和重传超时估算.

uIP由瑞典计算机科学学院(网络嵌入式系统小组)的Adam Dunkels开发.

uIP的代码大小和RAM占用

下面表格显示了uIP的代码大小和RAM占用. 代码使用gcc 3.3在8位的Atmel AVR架构上编译并使用代码大小优化(-Os).

uIP在Atmel AVR平台上的代码大小和RAM占用, 单位字节

总的内存占用将依赖: 分配了多少个TCP链接数, 分配了多少个ARP表项, 分配了多大的包缓冲. 这些在编译时候可以设置. 每一个正在监听的TCP端口增加额外的2个字节内存. 下面是uIP的一个配置实例: 一个正在监听的TCP端口, 10个TCP连接数, 10个ARP表项, 一个400字节大小的包缓冲和一个简单的HTTP服务器.

配置实例

对上图做一点补充, 注意uIP的设计使用了非常少的堆栈内存. uIP的调用视图非常窄, main函数和应用函数之间只有单个函数调用. 大多应用程序使用uIP函数作为C Macro, 因此不需要使用调用栈.

uIP文档

uIP文档1.0提供两种格式下载: HTML和PDF(uip-1.0-refman.pdf, 1.4MB, 261页)

发表论文:

1. Adam Dunkels, “Full TCP/IP for 8-Bit Architectures“. In Proceedings of the first international conference on mobile applications, systems and services (MOBISYS 2003), San Francisco, May 2003.
描述了uIP和IwIP相关的TCP/IP标准和其它TCP/IP实现.

2. Adam Dunkels, Oliver Schmidt, Thiemo Voigt, and Muneeb Ali. Protothreads: Simplifying Event-Driven Programming of Memory-Constrained Embedded Systems. In Proceedings of the Fourth ACM Conference on Embedded Networked Sensor Systems (SenSys 2006), Boulder, Colorado, USA, November 2006.
描述和评测了支持uIP protosocket库的超轻量级protothreads.

3. Adam Dunkels, Juan Alonso, and Thiemo Voigt, “Making TCP/IP Viable for Wireless Sensor Networks“, the First European Workshop on Wireless Sensor Networks (EWSN 2004), work-in-progress session.
正在撰写的论文: 讨论在无线传感器网络中使用TCP/IP和uIP.

平台移植:

快速向导: 移植uIP到其它的平台

实际的TCP/IP代码无需任何修改, 但是目标网络设备的驱动程序(以太网控制器/串口/其它)和实际的系统集成部分(比如, 主控制循环, 当数据到达或定期时钟超时需调用uIP函数)需要重写.

移植步骤:

1. 阅读上面提供的文档.
2. 在uip-1.0/目录下为你的端口创建新的目录(选择一个简短的CPU架构名称, 比如i386, 用于C编译器).
3. 从unix/子目录拷贝uip_arch.c文件到新创建的目录. ls包含了一个普通的C校验算法实现, 是一个32位的函数).
4. 从unix/子目录拷贝uipopt.h文件.
5. 根据你的项目编辑uipopt.h文件(文件是自描述型的).
6. 为你的硬件写设备驱动.(这大概是最难的部分.) 查阅unix/tapdev.c和uip/slipdev.c实例了解设备驱动如何实现.
7. 写好主控制循环, 然后调用uIP函数. 查阅unix/main.c实例了解主控制循环如何实现. 通过unix/main.c主循环实例了解如何使用ARP协议.
8. 写makefile文件, 然后编译代码. 确认你的项目(在你子目录中的.c文件)包含了../uip/uip.c文件. 如果你正使用web服务器程序, 请记住包含文件../apps/httpd/httpd.c ../apps/httpd/cgi.c ../apps/httpd/fs.c. 如果需支持ARP, 请包含文件 ../uip/uip_arp.c.
9. 发现和纠正所有的程序错误. (这是平台移植中最需技巧的部分:)

uIP程序下载
uip 1.0

相关网站
IwIP: 更强大的嵌入式TCP/IP协议栈.
Contiki: 使用uIP的嵌入式操作系统.
Protothreads: 超轻量级的无堆栈线程.
Miniweb: 30字节大小的TCP/IP协议栈和Web服务器原型.

参考
The uIP TCP-IP Stack for Embedded Microcontrollers

 

 

以下转自:http://www.gd-emb.org/detail/id-723.html

源码公开的TCP/IP协议栈在远程监测中的应用
来源:单片机及嵌入式系统应用 作者:张懿慧 陈泉林 时间:2005-12-01 发布人:admin
目前,随着互联网的发展,越来越多的工业测控设备已经将网络接入功能作为其默认配置,以实现设备的远程监控和信息分布式处理。笔者曾参与某发电机射频监测仪的开发,该设备主要用于诊断和预警发电机早期故障,并通过RS232接口定时输出电平和状态数据,现场专门设一台PC作接收、显示及存储。每年都要有专家到各发电厂对以往数据作检查和诊断,不胜其烦。因此有必要设计一个RS232到Internet的数据传输模块,以便对发电机的运行状况作远程监测。设计该模块的关键在于如何实现一个嵌入式TCP/IP协议栈,根据以往的经验,自己设计一个协议栈的难度很可能超过应用本身,而采用商业的协议栈似乎又无必要(功能过于复杂),最后笔者选用一种功能简易的免费TCP/IP协议栈uIP 0.9作为设计核心。

1 嵌入式TCP/IP协议栈

目前,市场上几乎所有的嵌入式TCP/IP协议栈都是根据BSD版的TCP/IP协议栈改写的。在商业嵌入式TCP/IP协议栈大都相当昂贵的情况下,很多人转而使用一些源代码公开的免费协议栈,并加以改造应用。目前较为著名的免费协议栈有:

lwIP(Light weight TCP/IP Stack)——支持的协议比较完整,一般需要多任务环境支持,代码占用ROM>40KB,不适合8位机系统,没有完整的应用文档;

uC/IP(TCP/IP stack for uC/OS)—基于uC/OS的任务管理,接口较复杂,没有说明文档。

笔者采用的协议栈系瑞典计算机科学研究所Adam Dunkels开发的uIP0.9。其功能特性总结如下:

*完整的说明文档和公开的源代码(全部用C语言编写,并附有详细注释);

*极少的代码占用量和RAM资源要求,尤其适用于8/16位单片机(见表1);

*高度可配置性,以适应不同资源条件和应用场合;

*支持ARP、IP、ICMP、TCP、UDP(可选)等必要的功能特性;

*支持多个主动连接和被动连接并发,支持连接的动态分配和释放;

*简易的应用层接口和设备驱动层接口;

*完善的示例程序和应用协议实现范例。

表1 uIP在ATMEL AVR上代码和RAM占用情况

协议模块 代码大小/B 使用的RAM/B 
ARP 1324 118 
IP/ICMP/TCP 3304 360 
HTTP 994 110 
校验和函数 636 0 
数据包缓存 0 400 
总和 6258 988 

注:配置为1个TCP听端口,10个连接,10个ARP表项,400字节数据包缓存。

正是由于uIP所具有的显著特点,自从0.6版本以来就被移植到多种处理器上,包括MSP430、AVR和Z80等。笔者使用的uIP0.9是2003年11月发布的版本。目前,笔者已将它成功移植到MCS-51上了。

2 uIP0.9的体系结构

uIP0.9是一个适用于8/16位机上的小型嵌入式TCP/IP协议栈,简单易用,资源占用少是它的设计特点。它去掉了许多全功能协议栈中不常用的功能,而保留网络通信所必要的协议机制。其设计重点放在IP、ICMP和TCP协议的实现上,将这三个模块合为一个有机的整体,而将UDP和ARP协议实现作为可选模块。UIP0.9的体系结构如图1所示。

UIP0.9处于网络通信的中间层,其上层协议在这里被称之为应用程序,而下层硬件或固件被称之为网络设备驱动。显然,uIP0.9并不是仅仅针对以太网设计的,以具有媒体无关性。

为了节省资源占用,简化应用接口,uIP0.9在内部实现上作了特殊的处理。

①注意各模块的融合,减少处理函数的个数和调用次数,提高代码复用率,以减少ROM占用。

②基于单一全局数组的收发数据缓冲区,不支持内存动态分配,由应用负责处理收发的数据。

③基于事件驱动的应用程序接口,各并发连接采用轮循处理,仅当网络事件发生时,由uIP内核唤起应用程序处理。这样,uIP用户只须关注特定应用就可以了。传统的TCP/IP实现一般要基于多任务处理环境,而大多数8位机系统不具备这个条件。

④应用程序主动参与部分协议栈功能的实现(如TCP的重发机制,数据包分段和流量控制),由uIP内核设置重发事件,应用程序重新生成数据提交发送,免去了大量内部缓存的占用。基于事件驱动的应用接口使得这些实现较为简单。

3 uIP的设备驱动程序接口

uIP内核中有两个函数直接需要底层设备驱动程序的支持。

一是uip_input()。当设置驱动程序从网络层收到的一个数据包时要调用这个函数,设备驱动程序必须事先将数据包存入到uip_buf[]中,包长放到uip_len,然后交由uip_input()处理。当函数返回时,如果uip_len不为0,则表明有带外数据(如SYN,ACK等)要发送。当需要ARP支持时,还需要考虑更新ARP表示或发出ARP请求和回应,示例如下:

#define BUF((struct uip_eth_hdr*)&uip_buf[0])

uip_len=ethernet_devicedriver_poll(); //接收以太网数据包(设备驱动程序)

if(uip_len>0){ //收到数据

if(BUF->type= =HTONS(UIP_ETHTYPE_IP)){//是IP包吗?

uip_arp_ipin(); //去除以太网头结结,更新ARP表

uip_input(); //IP包处理

if(uip_len>0){ //有带外回应数据

uip_arp_out(); //加以太网头结构,在主动连接时可能要构造ARP请求

ethernet_devicedriver_send(); //发送数据到以太网(设备驱动程序)

}

}else if(BUF->type==HTONS(UIP_ETHTYPE_ARP)){

//是ARP请求包

uip_arp_arpin(); //如是是ARP回应,更新ARP表;如果是请求,构造回应数据包

if(uip_len>0){ //是ARP请求,要发送回应

ethernet_devicedriver_send(); //发ARP回应到以太网上

}

}

另一个需要驱动程序支持的函数是uip_periodie(conn)。这个函数用于uIP内核对各连接的定时轮循,因此需要一个硬件支持的定时程序周期性地用它轮循各连接,一般用于检查主机是否有数据要发送,如有,则构造IP包。使用示例如下:

for(i=0;i
uip_periodic(i);

if(uip_len>0){

uip_arp_out();

ethernet_devicedriver_send();

}

}

从本质上来说,uip_input()和uip_periodic()在内部是一个函数,即uip_process(u8t flag),UIP的设计者将uip_process(UIP_DATA)定义成uip_input(),而将uip_process(UIP_TIMER)定义成uip_periodic(),因此从代码实现上来说是完全复用的。

4 uIP的应用程序接口

为了将用户的应用程序挂接到uIP中,必须将宏UIP_APPCALL()定义成实际的应用程序函数名,这样每当某个uIP事件发生时,内核就会调用该应用程序进行处理。如果要加入应用程序状态的话,必须将宏UIP_APPSTATE_SIZE定义成应用程序状态结构体的长度。在应用程序函数中,依靠uIP事件检测函数来决定处理的方法,另外可以通过判断当前连接的端口号来区分处理不同的连接。下面的示例程序是笔者实现的一个Web服务器应用的框架。

#define UIP_APPCALL uip51_appcall

#define UIP_APPSTATE_SIZE sizeof(struct uip51app_state)

struct uip51app_state{

unsigned char * dataptr;

unsigned int dataleft;

};

void uip51_initapp{ //设置主机地址

u16_t ipaddr[2];

uip_ipaddr(ipaddr,202,120,127,192);

uip_sethostaddr(ipaddr);

uip_listen(HTTP_PORT); //HTTP WEB PORT(80);

}

void uip51_appcall(void){

struct uip51app_state *s;

s=(struct uip51lapp_state *)uip_conn->appstate; //获取当前连接状态指针

if(uip_connected()){

… //有一个客户机连上

}

if(uip_newdat()||uip_rexmit()){ //收到新数据或需要重发

if(uip_datalen()>0){

if(uip_conn->lport==80){ //收到GET HTTP请求

update_table_data();//根据电平状态数据表动态生成网页

s->dataptr=newpage;

s->dataleft=2653;

uip_send(s->dataptr,s->dataleft); //发送长度为2653B的网页

}

}

}

if(uip_acked()){ //收到客户机的ACK

if(s->dataleft>uip_mss()&&uip_conn->lport==80){ //发送长度>最大段长时

s->dataptr+=uip_conn->len; //继续发送剩下的数据

s->dataleft-=uip-conn->len;

uip_send(s->dataptr,s->dataleft);

}

return;

}

if(uip_poll())

{… //将串口缓存的数据复制到电平状态数据表

return;

}

if(uip_timedout()|| //重发确认超时

uip_closed()|| //客户机关闭了连接

uip_aborted()){ //客户机中断连接

return;}

}

5 uIP0.9在电机远程监测系统中的应用

笔者设计了一个嵌入式Web模块UIPWEB51,用于将发电机射频监测仪串口输出的数据上网,以实现对发电机工作状态的远程监测,目前已获得初步成功。该模块的硬件框图如图2所示。

单片机采用的是Atmel的AT89C55WD,它内置20KB程序Flash,512字节RAM,3个这时器/计数器,工作在22.1184MHz时具有约2MIPS的处理速度。网卡芯片同样采用的是低成本的RTL8019AS,是一款NE2000兼容的网卡芯片,系统外扩了32KB的SRAM,用于串口数据和网络数据的缓冲,另外还存放了uIP的许多全局变量。

UIPWEB51的主程序采用中断加轮循的方式,用中断触发的方式接收发电机射频监测仪发出的数据,开设置了一个接收队列暂存这些数据。在程序中轮循有无网络数据包输入,如有则调用uIP的相关处理函数(如上uip_input()使用示例);如无则检测定时轮循中断是否发生。这里将T2设为uIP的定时轮循计数器,在T2中断中设置轮循标志,一旦主程序检测到这一标志就调用uip_periodic()轮循各连接(如上uip_periodic()使用示例)。

UIPWeb51的应用程序(如uIP的应用程序接口示例),这个Web服务器首先打开80端口的监听,一旦有客户机要求连上,uIP内部会给它分配一个连接项,接着等收到客户机IE浏览器发出的“GET HTTP……”请求后,将发电机电平与状态数据队列中的数据填入网页模板,生成一幅新的网页发给客户机。因为这幅网页的大小已经超过uIP的最大段长(MSS),因此在uIP内核第一次实际只发出了MSS个字节,在连接处于空闲的时候(uip_poll()),应用程序可以从串口队列中读出原始数据,经格式处理后再存到电机电平与状态数据队列中,而在这个队列中保存着当前1min的设备工作数据,以便下次更新网页时使用。在网页中添加了更新按钮,一旦浏览器用户占击了按钮,浏览器会自动发出CGI请求,UIPWEB51收到后,立即发送包含最新数据的网页。如果uIP接收ACK超时,它会自动设置重发标志,应用程序中可以用uip_rexmit()来检测这个标志,重新生成网页并发送。一旦用户关闭了浏览器,uIP也会自动检测到这一事件(应用程序中可以用uip_closed()来检测),并且释放掉这个连接项。

6 测试结果

将uIP0.9配置成允许4个并发连接,1个监听端,10端个ARP表项,去掉UDP支持,UIP_ZBUFSIZE=1500和其它优化选项。用KEIL C编译,整个uIP0.9内核模式代码量小于8KB(含Web应用程序),内核对RAM的占用小于2KB(不含网页)。整个系统程序的代码量小于12KB,占用的RAM小于10KB。另外,在公网上测试了该模式的传输速度,大于20Kbps,对于此项应用已达到要求。目前,该模块正准备应用于新一代的发电机射频监测系统中。 
  评论这张
 
阅读(2000)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017