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

常见的嵌入式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.
r_pic3.jpg

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),起始优先级,临界访问函数,信号量邮箱队列变量或结构的定义

ContractedBlock.gif ExpandedBlockStart.gif 代码
 
   
1 #define LWIP_TASK_MAX 2
2
3   #define LWIP_TASK_START_PRIO 8
4
5   #define SYS_ARCH_PROTECT(lev) OS_ENTER_CRITICAL()
6   #define SYS_ARCH_UNPROTECT(lev) OS_EXIT_CRITICAL()
7
8 typedef struct
9 {
10 OS_EVENT * pQ; // uCOSII中指向事件控制块的指针
11   void * pvQEntries[MAX_QUEUE_ENTRIES]; // MAX_QUEUE_ENTRIES消息队列中最多的队列数
12 } Q_DESCR, * Q_DESCRPt;
13
14
15 typedef OS_EVENT * sys_sem_t;
16 typedef Q_DESCRPt sys_mbox_t;
17 typedef INT8U sys_thread_t;

(2)sys_init()

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

(3)任务创建sys_thread_new
在我们的应用环境下,只创建了一个任务tcpip_thread,在tcpip.c中tcpip_init创建
sys_thread_new(tcpip_thread, NULL, TCPIP_THREAD_PRIO);

ContractedBlock.gif ExpandedBlockStart.gif sys_thread_new
 
   
1 sys_thread_t sys_thread_new( void ( * thread)( void * arg), void * arg, int prio)
2 {
3 u8_t CreatState,TaskPrio;
4 // 计算实际的优先级数值
5 // 这个值由起始优先级LWIP_TASK_START_PRIO,偏移量和参数传递的prio相加而得.
6 // 这里传递过来的是TCPIP_THREAD_PRIO(定义在opt.h,值为1)
7 // 其他任务定义的值也都为1(虽然这里并未创建其他任务),由于uCOSII不支持相同优先级
8 // 因此使用一个全局变量curr_prio_offset来累加,每创建一个任务,实际的优先级就加1
9 TaskPrio = LWIP_TASK_START_PRIO + curr_prio_offset + prio;
10 // 判断是否超过定义的最大任务数
11 if (curr_prio_offset < LWIP_TASK_MAX)
12 {
13 // 创建uCOSII任务
14 CreatState = OSTaskCreateExt(( void ( * )( void * )) thread,
15 ( void * ) 0 ,
16 (OS_STK * ) & LwipTaskStack[curr_prio_offset][LWIP_TASK_STK_SIZE - 1 ],
17 (INT8U ) TaskPrio,
18 (INT16U ) TaskPrio,
19 (OS_STK * ) & LwipTaskStack[ 0 ],
20 (INT32U ) LWIP_TASK_STK_SIZE,
21 ( void * ) 0 ,
22 (INT16U )(OS_TASK_OPT_STK_CHK | OS_TASK_OPT_STK_CLR));
23
24 // 创建失败
25 if (CreatState)
26 {
27 return 0 ;
28 }
29 // 打印调试信息, 优先级偏移量加1
30 print_string( " task prio = %d created...\r\n " ,TaskPrio);
31 curr_prio_offset ++ ;
32
33 }
34 else
35 {
36 print_string( " lwip task prio out of range ! error! " );
37 }
38 // 返回创建成功的任务优先级
39 return TaskPrio;
40 }

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

ContractedBlock.gif ExpandedBlockStart.gifsys_mbox_new 
 
   
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;
}
ContractedBlock.gif ExpandedBlockStart.gifsys_mbox_free 
 
   
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); // 把队列所占内存放入内存池
}
ContractedBlock.gif ExpandedBlockStart.gifsys_mbox_post 
 
   
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);
}
ContractedBlock.gif ExpandedBlockStart.gifsys_arch_mbox_fetch 
 
   
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]等待信号量

ContractedBlock.gif ExpandedBlockStart.gif sys_arch_sem_wait
 
   
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]设置超时事件

ContractedBlock.gif ExpandedBlockStart.gif sys_arch_timeouts
 
   
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)驱动了.

发表于 @ 2009年09月01日

转载于:https://www.cnblogs.com/shevsten/articles/1691531.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值