μCOS II 下 LwIP 协议栈的移植和测试

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

1、引言
为了实现嵌入式系统终端连入互联网,而有必要为其引入了网络功能。

μC/OS II 是一个源代码开放的实时操作系统,但是它只是一个实时的任务调度及通信内核,并没有集成TCP/IP 通信协议,为了实现网络功能,需要在μC/OS II 移植一个轻量级的TCP/IP 通信协议LwIP。

本文主要论述μC/OS II 下通信协议LwIP 的移植以及测试。

2、LwIP 简介
LwIP ( light weight IP)是瑞士计算机科学院的Adam Dunkels 等开发的一套开放TCP/IP 协议栈源代码。

LwIP 既可以移植到操作系统上,又可以在无操作系统的情况下独立运行。

LwIP 实现的重点是在保持TCP/IP 协议主要功能的基础上减少对RAM 的占用,这使LwIP 适合在低端嵌入式系统中使用。

其主要特点如下:
(1)支持多网络接口下IP 转发;
(2)支持ICMP 协议;
(3)包括试验性扩展的UDP;
(4)包括简单的拥塞控制,RTT 估算和快速恢复和快速转发的TCP;
(5)提供专门的内部回调接口(Raw API)用于提高应用程序性能;
(6)可选择的Berkeley 接口API;
3、LwIP 协议栈移植到μC/OS II 操作系统的具体实现
3.1 嵌入式系统结构和LwIP 接口
整个嵌入式系统的结构如图 1 所示,由ARM 微处理器、网卡、网络设备驱动、μC/OS
II 操作系统、LwIP 协议栈和应用程序组成。

图 1 嵌入式系统结构图
LwIP 在设计时为了适应不同的操作系统,并没有在代码中使用和某个特定的操作系统相关的系统调用和数据结构,而是在LwIP 和操作系统之间提供了一个接口层(sys_arch interface),该接口主要实现的功能包括数据类型的定义、存储模式的选择、任务间的同步、时间和内存的管理等。

因此,完成LwIP 在μC/OS II 移植,我们就是要通过修改这个接口层来实现。

同时,还要根据自己所要实现的具体目的,可以对LwIP 协议栈进行一定的裁减。

3.2 和CPU 以及编译器相关的一些头文件
这些头文件包括cc.h、cpu.h、perf.h 等,在这里都定义了和使用的CPU 以及编译器相关的内容,如数据类型,存储模式的选择,这些和用户实现μC/OS II 时定义的数据类型等是一致的。

#define BYTE_ORDER LITTLE_ENDIAN //小端存储模式
typedef unsingned char u8_t; //数据类型定义
typedeg char s8_t;
typedef unsingned short u16_t;
typedef short s16_t;
typedef unsingned int u32_t;
typedef int s32_t;
3.3 和操作系统μC/OS II 相关的函数
与操作系统相关的函数主要是信号量、消息队列、定时器函数和创建新进程函数。

下面将逐一论述移植过程中对它们要求和实现。

3.3.1 LwIP 信号量的实现
LwIP 使用信号量实现进程间的通信,由于μC/OS II 中已经实现了信号量OS_EVENT 的各种操
作,并且可以满足LwIP 通信的要求,所以只需要在下面函数中封装相应μC/OS II 关于信号量的操作函数就可以了。

struct sys_sem_t //定义信号量结构sys_sem_new( ) //创建一个信号量结构sys_sem_free( ) //释放一个信号量结构sys_sem_signal( ) //发送信号量sys_arch_sem_wait( ) //请求信号量
下面给出它们与μC/OS II 对应的结构体和函数:
struct sys_sem_t →OS_EVENT sys_sem_new( ) →OSSemCreate( ) sys_sem_free( ) →OSSemDel( ) sys_sem_signal( ) →OSSemPost( ) sys_arch_sem_wait( ) →OSSemPend( )
3.3.2 LwIP 消息的实现
LwIP 使用消息队列来缓冲、传递数据报文。

μC/OS II 实现了消息队列结构OSQ 及其操作,但是μC/OS II 没有对消息队列中的消息进行管理,因此不能象信号量那样直接使用,而需要在μC/OS II 基础上重新实现。

定义的结构如下:
typedef struct{ OS_EVENT * pQ;
void * pvQEntries[MAX_QUEUE_ENTRIES];
}sys_mbox_t;
上面的结构中,包含了OS_EVENT 类型的队列指针pQ 和队列内的消息pvQEntries 两部分。

可见,对对列本身的管理利用μC/OS II 自己的OSQ 操作完成,使用μC/OS II 的内存管理模块实现对消息的创建、使用、删除和回收。

这样实现了LwIP 的消息队列功能。

相应的处理函数如下:sys_mbox_new( ) //创建一个消息队列sys_mbox_free( ) //释放一个消息队列sys_mbox_post( ) //向消息队列发送消息sys_arch_mbox_fetch( ) //从消息队列中读取消息
3.3.3 定时器函数sys_arch_timeouts( )
LwIP 的每个线程都有自己的超时等待属性,为每一个线程都分配了一个超时等待的数据结构sys_timeout,并把这个数据结构存放于链表sys_timeouts 中。

通过μC/OS II 的任务查询机制来获得一个指向当前线程使用的sys_timeouts 结构的指针。

如若某一个sys_timeout 结构为空,说明对应的线程作永久的等待。

超时等待的数据结构sys_timeout 包括,指向链表中下个sys_timeout 结构的指针、线程超时等待的长度和定时时间到后用以处理的函数等内容。

而sys_timeouts 结构只包含指向sys_timeout 结构的指针。

这两个数据结构都已经在LwIP 源代码的sys.h 头文件中给予定义,我们要做的是,实现找到当前线程使用的sys_timeouts 结构指针的函数sys_arch_timeouts( )。

定义的结构和函数如下:
struct sys_timeout {
struct sys_timeout *next; u32_t time; sys_timeout_handler h; void *arg;
};
struct sys_timeouts {
struct sys_timeout *next;
};
struct sys_timeouts *sys_arch_timeouts( )
3.3.4 创建新线程函数sys_thread_new( )
在μC/OS II 中,没有线程(thread)的概念,只有任务(task)的概念,创建一个新的线程就是创建一个新的任务。

又由于,在μC/OS II 中已经提供了创建新任务的函数OSTaskCreste( ),因此把函数OSTaskCreste( )进行封装,就可以实现创建新线程函数sys_thread_new( )。

但由
于LwIP 中的线程没有μC/OS II 中优先级的概念,实现时需要有用户事先为LwIP 中创建的线程分配好优先级。

函数如下:
sys_thread_t sys_thread_new(void(*thread)(void *arg), void *arg, int prio)
其中thread 是新线程的入口地址,arg 是传递给新线程的参数,prio 是由LwIP 指定的新线程的优先级
3.4 网络设备驱动程序
在ISO 参考模型中,数据链路层的逻辑链路控制子层的部分工作有网络接口芯片驱动程序完成的,其他部分则集成在网络接口芯片中由硬件实现。

本文所用开发板上的网络接口芯片为RTL8019AS,它是8/16 位ISA 总线的网卡,遵循IEEE802.3 协议。

在LwIP 中每个网络接口都对应一个数据结构struct netif,如下:
struct netif {
struct netif *next;
struct ip_addr ip_addr; struct ip_addr netmask; struct ip_addr gw;
err_t (* input)(struct pbuf *p, struct netif *inp);
err_t (* output)(struct netif *netif, struct pbuf *p,struct ip_addr *ipaddr); ......
};
在该数据结构中定义了指向下个网络接口的指针、IP 地址、网络掩码、网关以及用于实现以太网接收、发送数据包的函数等内容。

对于网络接口芯片的驱动程序,用户可以根据自己的网络设备参照LwIP 的网络驱动模板,/src/netif/ethernetif.c 文件。

4、移植测试
在完成上述的移植工作后,在μC/OS II 操作系统中初始化LwIP,创建TCP 和UDP 的任务。

LwIP 的初始化必须在μC/OS II 完全启动之后,因为它初始化用到了信号量等和操作系统相关的操作。

μC/OS II 的主函数如下:
main( ){ OSInit( );
OSTaskCreate(lwip_init_task,(void*)&id2,&lwip_init_stk[TASK_STA_SIZE-1],2); OSStart( );
}
在主程序中创建了任务lwip_init_task( ),它的功能除了初始化硬件时钟和LwIP 外,还要创建测试要用的两个线程,tcpip_thread( )和tcpecho_thread( )。

tcpip_thread( )是LwIP 任务的主线程,tcpecho_thread( )是用来测试ICMP、ARP、IP、TCP 协议的功能是否实现。

经编译下载后,设定好开发板的IP 地址,利用Ping 命令,可以得到ICMP reply 响应。

测试表明,移植后实现了TCP/IP 基本功能。

5、结束语
由于μC/OS II 操作系统本身缺少TCP/IP 协议栈,LwIP 移植到μC/OS II 操作系统实现了嵌入式系统上的TCP/IP 协议栈,完成了嵌入式系统基本的网络通信功能。

从宿主机和开发板的网络通信测试结果来看,移植取得了实效。

本文作者创新点:根据要实现的基本功能,通过对LwIP 的研究和优化精简,对代码容量减少和通用型较好都能兼顾,可以在不同的不同的硬件平台上运行,便于移植。

相关文档
最新文档