您的位置:首页 > 其它

SMARTARM2200 ADS工程在IAR EWARM 5.3上的移植(6)-LwIP 1.2的移植(uCOSII部分)

2009-09-01 11:53 483 查看
常见的嵌入式TCPIP协议栈有LwIP,uIP,uC/TCPIP,TinyTcp等,相对来说LwIP功能较uIP(uIP更多用在8位51上),TinyTCP强点,但代码量小于uC-TCPIP,之前也尝试过移植uC-TCPIP,不过一直有点问题,当然uC-TCPIP还不是免费的.加上网上关于LwIP的资料也比较多.

1.LwIP简介
LwIP是瑞士计算机科学院(Swedish Institute of Computer Science)的Adam Dunkels等开发的一套用于嵌入式系统的开放源代码TCP/IP协议栈。LwIP的含义是Light Weight(轻型)IP协议,相对于uip。LwIP可以移植到操作系统上,也可以在无操作系统的情况下独立运行。LwIP TCP/IP实现的重点是在保持TCP协议主要功能的基础上减少对RAM的占用,一般它只需要几十K的RAM和40K左右的ROM就可以运行,这使LwIP协议栈适合在低端嵌入式系统中使用。LwIP的特性如下:支持多网络接口下的IP转发,支持ICMP协议 ,包括实验性扩展的的UDP(用户数据报协议),包括阻塞控制,RTT估算和快速恢复和快速转发的TCP(传输控制协议),提供专门的内部回调接口(Raw API)用于提高应用程序性能,并提供了可选择的Berkeley接口API。http://www.sics.se/~adam/lwip/http://savannah.nongnu.org/projects/lwip/

2.采用LwIP1.2,1.3的接口函数有些不一样,为了移植的方便还是使用1.2,毕竟基于1.2的参考资料更多些,移植的很多代码参考并借用了网上的例子,在此表示感谢!
更详细的信息可以参考我上传的工程http://download.csdn.net/source/1661278
将LwIP1.2加入到我们的IAR工程中,因为我们并不需要SLIP,PPP以及IPv6的支持,这些相关代码就不必加入到工程里了,将头文件路径添加到IAR include directories.



3.添加移植代码,如cc.h, lwipopts.h, sys_arch.h, sys_arch.c, 网卡驱动等
cc.h:定义数据类型,大小端格式等
lwipopts.h:lwip的配置文件
sys_arch.h/c:实现lwip与操作系统(这里是uCOSII)的接口,如任务创建,信号量邮箱操作等
rtl8019.h/c:网卡驱动程序,SMARTARM2200使用的网卡芯片是RTL8019AS

cc.h和lwipopts.h的内容就不详细介绍了,具体内容可参考上面链接给的工程,都是些宏定义,配置定义等

4.操作系统模拟层的实现(sys_arch.c)
因为我们使用操作系统,因此在sys_arch.c中需要实现任务,信号量,邮箱操作的函数.LwIP提供了这样的接口以供不同的操作系统去实现.
(1)sys_arch.h
头文件定义了LwIP最大任务数(其实LwIP只创建了一个任务tcpip_thread),起始优先级,临界访问函数,信号量邮箱队列变量或结构的定义
#define LWIP_TASK_MAX         2

#define LWIP_TASK_START_PRIO  8

#define SYS_ARCH_PROTECT(lev)   OS_ENTER_CRITICAL()
#define SYS_ARCH_UNPROTECT(lev) OS_EXIT_CRITICAL()

typedef struct
{
OS_EVENT * pQ; //uCOSII中指向事件控制块的指针
void * pvQEntries[MAX_QUEUE_ENTRIES];  //MAX_QUEUE_ENTRIES消息队列中最多的队列数
}  Q_DESCR, *Q_DESCRPt;

typedef OS_EVENT*  sys_sem_t;
typedef Q_DESCRPt  sys_mbox_t;
typedef INT8U      sys_thread_t;

(2)sys_init()

void sys_init(void)
{
//初始化了一个内存缓冲池,用于放MAX_QUEUES个ucosii的消息队列。
unsigned char err;
QueueMemPt = OSMemCreate((void *)QueueMemoryPool, MAX_QUEUES, sizeof(Q_DESCR), &err);
curr_prio_offset = 0;
}

(3)任务创建sys_thread_new
在我们的应用环境下,只创建了一个任务tcpip_thread,在tcpip.c中tcpip_init创建
sys_thread_new(tcpip_thread, NULL, TCPIP_THREAD_PRIO);
sys_thread_t sys_thread_new(void (* thread)(void *arg), void *arg, int prio)
{
u8_t CreatState,TaskPrio;
//计算实际的优先级数值
//这个值由起始优先级LWIP_TASK_START_PRIO,偏移量和参数传递的prio相加而得.
//这里传递过来的是TCPIP_THREAD_PRIO(定义在opt.h,值为1)
//其他任务定义的值也都为1(虽然这里并未创建其他任务),由于uCOSII不支持相同优先级
//因此使用一个全局变量curr_prio_offset来累加,每创建一个任务,实际的优先级就加1
TaskPrio = LWIP_TASK_START_PRIO+curr_prio_offset+prio;
//判断是否超过定义的最大任务数
if(curr_prio_offset < LWIP_TASK_MAX)
{
//创建uCOSII任务
CreatState = OSTaskCreateExt((void (*)(void *)) thread,
(void           *) 0,
(OS_STK         *) &LwipTaskStack[curr_prio_offset][LWIP_TASK_STK_SIZE - 1],
(INT8U           ) TaskPrio,
(INT16U          ) TaskPrio,
(OS_STK         *)&LwipTaskStack[0],
(INT32U          ) LWIP_TASK_STK_SIZE,
(void           *) 0,
(INT16U          )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));

//创建失败
if(CreatState)
{
return 0;
}
//打印调试信息, 优先级偏移量加1
print_string("task prio = %d created.../r/n",TaskPrio);
curr_prio_offset++;

}
else
{
print_string(" lwip task prio out of range ! error! ");
}
//返回创建成功的任务优先级
return TaskPrio;
}

(4)邮箱操作sys_mbox_new(),sys_mbox_free(),sys_mbox_post(),sys_arch_mbox_fetch()
这里邮箱实际上用到的是uCOSII中的消息队列,邮箱只能存放一个消息,而消息队列可以存放多个消息
sys_mbox_t sys_mbox_new(void)
{
unsigned char err;
Q_DESCRPt	QDescPt;

QDescPt = OSMemGet(QueueMemPt, &err);	//在内存池中分配出一个队列结构的空间,并将此空间赋成这个结构。
if(err == OS_NO_ERR){
QDescPt->pQ = OSQCreate(&(QDescPt->pvQEntries[0]), MAX_QUEUE_ENTRIES);	//创建队列,但是队列只是lwip队列结构的一个成员。
if(QDescPt->pQ != NULL){
return QDescPt;
}
}
return SYS_MBOX_NULL;
}

void sys_mbox_free(sys_mbox_t mbox)
{
unsigned char err;

OSQFlush( mbox->pQ );	//清除队列事件
OSQDel( mbox->pQ, OS_DEL_NO_PEND, &err);	//删除队列
err = OSMemPut( QueueMemPt, mbox);	//把队列所占内存放入内存池
}

void sys_mbox_post(sys_mbox_t mbox, void *data)
//由于lwip会发空消息,而ucosii对空消息会当错处理,所以我们把lwip的空做成ucosii的一个特定值。
{
unsigned char err;
if(!data)
data = (void *)0xffffffff;
err = OSQPost(mbox->pQ, data);
}

unsigned long sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg, unsigned long timeout)
{
unsigned char err;
unsigned short ucos_timeout = 0;

/*由于lwip中的timeout时间是ms,而ucosii的是timer tick,所以要转换,将timeout转换成ucos_timeout*/
//首先确保输入参数的合理性
if(timeout){
ucos_timeout = (timeout * OS_TICKS_PER_SEC)/1000;
if(ucos_timeout < 1)
ucos_timeout = 1;
}

if(!mbox)
return SYS_ARCH_TIMEOUT;
//因为OSQPend()有返回值,则看有没有可返回的地址,有则返回,无则不返回。
if(msg != NULL){
*msg = OSQPend(mbox->pQ, (unsigned short)ucos_timeout, &err);
}
else{
OSQPend(mbox->pQ, (unsigned short)ucos_timeout, &err);
}

if(err == OS_TIMEOUT){
timeout = SYS_ARCH_TIMEOUT;
}
else{
if(*msg == (void *)0xffffffff)
*msg = NULL;
timeout = (ucos_timeout - err) * (1000/OS_TICKS_PER_SEC);
}
return timeout;
}

(5)信号量操作sys_sem_new(),sys_sem_free,sys_sem_signal(),sys_arch_sem_wait()
[1]创建信号量
sys_sem_t sys_sem_new(unsigned char count)
{
sys_sem_t SemPt;
SemPt = OSSemCreate(count);
if(SemPt != NULL)
return SemPt;
return SYS_SEM_NULL;
}

[2]删除信号量
void sys_sem_free(sys_sem_t sem)
{
unsigned char	err;
OSSemDel((OS_EVENT *)sem, OS_DEL_NO_PEND, &err );
}

[3]发送信号量
void sys_sem_signal(sys_sem_t sem)
{
OSSemPost((OS_EVENT *)sem);
}

[4]等待信号量
unsigned long  sys_arch_sem_wait(sys_sem_t sem, unsigned long  timeout)	//同队列
{
unsigned char err;
unsigned short ucos_timeout = 0;

/*由于lwip中的timeout时间是ms,而ucosii的是timer tick,所以要转换,将timeout转换成ucos_timeout*/
//首先确保输入参数的合理性
if(timeout){
ucos_timeout = (timeout * OS_TICKS_PER_SEC)/1000;
if(ucos_timeout < 1)
ucos_timeout = 1;
}

OSSemPend ((OS_EVENT *)sem,(u16_t)ucos_timeout, (u8_t *)&err);

if(err == OS_TIMEOUT){
return 0;
}
else{
return 1;
}
}

[5]设置超时事件
struct sys_timeouts *sys_arch_timeouts(void)
{
unsigned char CurrPrio;
signed short err, offset;
OS_TCB	CurrTaskPcb;

NullTimeouts.next = NULL;

err = OSTaskQuery(OS_PRIO_SELF, &CurrTaskPcb);

CurrPrio = CurrTaskPcb.OSTCBPrio;

offset = CurrPrio - LWIP_TASK_START_PRIO;

if(offset<0 || offset >= LWIP_TASK_MAX){
return &NullTimeouts;
}
return &LwipTimeouts[offset];
}

至此,LwIP与uCOSII相关的部分就移植完成了,下一步就是实现网卡(RTL8019AS)驱动了.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐