基于μC/OS-Ⅲ的LwIP协议栈的移植与实现(2)
- UID
- 1029342
- 性别
- 男
|
基于μC/OS-Ⅲ的LwIP协议栈的移植与实现(2)
1.1.3 编写源文件sys_arch.c
sys_arch.c文件要求实现操作系统模拟层的接口函数,主要包括对信号量和邮箱等数据结构的操作以及LwIP线程的操作。
LwIP的信号量用于进程间的通信,相关操作主要包括以下几个函数:
sys_sem_new() //新建信号量
sys_sem_free() //释放信号量
sys_sem_signal() //发送信号量
sys_arch_sem_wait() //阻塞进程,等待指定信号量
sys_sem_valid() //检查信号量可用性
sys_sem_set_invalid() //设置信号量不可用
LwIP的邮箱用于缓存和传递数据报文,相关操作主要包括以下几个函数:
sys_mbox_new() //新建邮箱
sys_mbox_free() //删除邮箱
sys_mbox_post() //阻塞进程,投递消息至邮箱
sys_mbox_trypost() //投递消息至邮箱,仅一次操作
sys_arch_mbox_fetch() //阻塞进程,从邮箱中提取消息
sys_arch_mbox_tryfetch() //从邮箱中提取消息,仅一次操作
sys_mbox_valid() //检查邮箱可用性
sys_mbox_set_invalid() //设置邮箱不可用
LwIP使用了μC/OS-Ⅲ中的信号量OS_SEM和消息队列OS_Q结构,以上函数的实现调用了μC/OS-Ⅲ的操作函数,包括OS?Create()、OS?Del()、OS?Post()和OS?Pend()。在实现sys_?_new()和sys_?_free()函数时,需加入临界段代码保护以确保OS?Create()和OS?Del()在执行时不被打断,可避免出现系统资源管理错误。
err_t sys_?_new(……)
{
OS_ERR err;
CPU_SR_ALLOC(); //临界代码保护开始
CPU_CRITICAL_ENTER();
OS?Create(……,&err);
CPU_CRITICAL_EXIT(); //临界代码保护结束
return err;
}
void sys_?_free(……)
{
OS_ERR err;
CPU_SR_ALLOC(); //临界代码保护开始
CPU_CRITICAL_ENTER();
OS?Del(……, &err );
CPU_CRITICAL_EXIT(); //临界代码保护结束
}
LwIP 1.4.0版本新添加了sys_?_valid()和sys_?_set_
invalid(),这两个函数的实现无需调用操作系统内部的函数,可由开发者根据实际需求实现。另外,二值信号量替换了互斥信号量,相关的操作函数也无需在此文件内实现。在LwIP内核中的sys.h文件给出了详细的宏定义:
#if LWIP_COMPAT_MUTEX
#define sys_mutex_t sys_sem_t
#define sys_mutex_new(mutex) sys_sem_new(mutex, 1)
#define sys_mutex_lock(mutex) sys_sem_wait(mutex)
#define sys_mutex_unlock(mutex) sys_sem_signal(mutex)
#define sys_mutex_free(mutex) sys_sem_free(mutex)
#define sys_mutex_valid(mutex) sys_sem_valid(mutex)
#define sys_mutex_set_invalid(mutex) \
sys_sem_set_invalid(mutex)
LwIP建立新进程的接口函数sys_thread_new()要求成功建立一个任务并返回任务优先级。μC/OS-Ⅲ中加入了时间片轮转调度功能,使得同一优先级可建立多个任务,避免了优先级重复导致任务建立失败的情况。相比于使用μC/OS-Ⅱ或其他不支持同级任务的操作系统,sys_thread_new()的实现仅调用OSTaskCreate()即可,省略了一些查找可用优先级的容错操作。
操作系统模拟层的初始化函数sys_init()由开发者根据实际情况进行编写,没有固定的规范要求。该函数可不执行任何操作,但必须在文件内实现。
1.2 硬件驱动层的编写
LwIP内核文件中给出了驱动文件的参考模板ethernetif.c,开发者可根据其模板的架构结合实际使用的网络控制芯片来编写驱动。
以low_level为前缀的函数均为网络控制芯片相关的接口函数,主要包含初始化、接收、发送等操作。LM3S9B95的以太网控制器模块包含了MAC层和物理层,有别于传统的MCU+PHY芯片的结构。因此,实现驱动函数时可直接对相应的寄存器进行操作,无需再次封装PHY芯片的操作函数。
以ethernetif为前缀的函数要求开发者实现底层硬件与上层协议间的接口函数,包括底层设备描述结构体的相关操作、LwIP主线程和以太网中断服务函数等。
1.3 LwIP功能裁剪和定制
LwIP为开发者提供了一个功能定制的接口文件lwipopt.h,可根据系统实际需求定义宏的值、裁剪功能和配置参数。例如使用TCP和UDP功能,则需添加下列定义:
#define LWIP_TCP 1
#define LWIP_UDP 1
内核文件opt.h是lwipopt.h的设计模板,包含了所有LwIP功能配置的宏。opt.h文件对宏定义均采用了#ifndef预编译判断,当开发者在lwipopt.h中没有对某个宏给出定义时,该文件会定义一个默认值。
虽然修改opt.h中的宏定义和在lwipopt.h中编写宏定义均可实现剪裁和定制LwIP的功能,但由于修改内核文件会破坏协议栈的封装性,为今后的应用程序移植和维护造成隐患,所以开发者不应直接修改opt.h内的宏定义。
开发者在编写lwipopt.h时,由于每个宏的默认值并不能保证LwIP的正确运行,所以应对opt.h中给出的所有宏进行定义。例如opt.h中对于TCP的一些宏定义如下:
#ifndef TCPIP_THREAD_STACKSIZE
#define TCPIP_THREAD_STACKSIZE 0
#endif
#ifndef TCPIP_MBOX_SIZE
#define TCPIP_MBOX_SIZE 0
#endif
LwIP默认的TCPIP进程堆栈空间为0,TCPIP使用的邮箱空间为0。若开发者在lwipopt.h中不对这些宏进行定义,当tcpip_init()对LwIP进行初始化时,就会出现错误致使LwIP无法正确运行。 |
|
|
|
|
|