lwIP移植工作

lwIP移植工作(一)cc.h 与CPU和编译器的相关接口

Lwip的移植主要是三个接口部分:

1、与CPU或编译器相关接口(include中cc.h文件)

2、与操作系统的接口;

3、与底层网卡驱动的接口。

一、与CPU或编译器相关接口

与CPU或编译器相关接口(include中cc.h文件),主要包括数据长度,字的高低位顺序,编译器对c语言中struct结构字节对齐问题(c语言中struct结构是四字节对对齐的,但lwip中是根据struct结构中不同数据的长度来读取数据的)

例如nios平台下的cc.h文件:

       /* FPAG-NIOS platform*/

#ifndef __ARCH_CC_H__

#define __ARCH_CC_H__

#include"errno.h"        //定义错误编码

#include "alt_types.h"    //定义NIOS数据类型

#include "lwipopts.h"     //

#define BYTE_ORDERLITTLE_ENDIAN          //字的高低位顺序

//数据长度

typedef alt_u8    u8_t;    //一个无符号字节类型,          8bits   0~~255

typedef alt_8    s8_t;    //一个有符号字节类型,         8 bits   -127~~-127

typedef alt_u16   u16_t;   //一个无符号字(=2个字节)类型,16 bits

typedef alt_16    s16_t;   //一个有符号字(=2个字节)类型,16 bits

typedef alt_u32   u32_t;   //一个无符号字节类型,          32 bits

typedef alt_32    s32_t;   //一个有符号字节类型,          32 bits

typedef u32_t mem_ptr_t;    //

#include

/* Plaform specific diagnostic output   与平台相关的调试输出 */

#define LWIP_PLATFORM_DIAG(x) {printf x;}

#define LWIP_PLATFORM_ASSERT(x) {printf("Assertion\"%s\" failed at line %d in %s\n", \

                                    x, __LINE__, __FILE__); while(1);}

//编译器对c语言中struct结构字节对齐

#define PACK_STRUCT_FIELD(x) x __attribute__((packed))

#define PACK_STRUCT_STRUCT __attribute__((packed))

#define PACK_STRUCT_BEGIN

#define PACK_STRUCT_END

#endif /* __ARCH_CC_H__ */

lwIP移植工作(二)sys_arch.h sys_arch.c 与操作系统的接口

与操作系统的接口,主要分为四个部分

1、sys_sem_t信号量: 在sys_arch中应实现如下sys_sem_t结构体和处理函数

       struct sys_sem_t

      sys_sem_new()            //创建一个信号量结构

      sys_sem_free()            //释放一个信号量结构

      sys_sem_signal()           //发送信号量

      sys_arch_sem_wait()     //请求信号量

UCOS中已经实现了信号量OS_EVENT的操作,且功能和LWIP上面几个函数的目标功能是完全一样的,所以只要把UCOS的相关函数包装成上面的函数就可以直接使用了。

2、sys_mbox_t消息:LwIP使用消息队列来缓冲、传递数据报文,在sys_arch中应实现如下sys_sem_t结构体和处理函数

       struct sys_mbox_t

      sys_mbox_new()   //创建一个消息队列

      sys_mbox_free()    //释放一个消息队列

      sys_mbox_post()   //向消息队列发送消息

      sys_arch_fetch()    //从消息队列中获取消息

由于UCOS中没有对消息队列中的消息进行管理,所以得另外定义一个消息队列结构:

       typeedef struct{

             OS_EVENT*pQ;                                            //队列指针

             Void* pvQEntries[MAX_QUEUE_ENTRIES]       //队列中的消息

             }sys_mbox_t

利用UC-OS的OSQ操作完成对队列的管理,利用UC-OS的内存管理模块完成队列的创建、使用、删除回收操作。

3、 sys_arch_timeout() 函数:LwIP中每个与外界网络连接的线程都有自己的timeout属性,即等待超时时间。这个属性表现为:每个线程都对应一个sys_timeout结 构体队列,包括这个线程的timeout时间长度,以及超时后应调用的timeout函数,该函数会释放连接和回收资源的工作。如果一个线程对应的sys_timeout为空(NULL),说明该线程对连接做永久的等待。

timeout结构体已经由LwIP在sys.h中定义好了,而 且对结构体队列的数据操作也由LwIP负责,我们所要实现的是如下函数:struct sys_timeouts* sys_arch_timouts(void),这个函数的功能是返回目前正处于运行态的线程所对应的timeout队列指针。timeout队列属于线 程的属性,因此是与OS相关的函数,只用由用户实现。例如nios中UCOS平台下的sys_arch_timeouts(void)函数:

struct sys_timeouts *

sys_arch_timeouts(void)

{

       INT8S currPrio;

       currPrio = (OSPrioCur-LWIP_START_PRIO);

       if((currPrio < 0)|| (currPrio >= LWIP_MAX_TASKS))

       {

             /* Error! */

          printf("sys_arch_timeouts: Prio not found\n");

             while(1);

       }

    return &timeoutlist[currPrio];

}

      

4、 sys_thread_new创建新线程函数:LwIP可以是单线程运行,即只有一个TCPIP线程(tcpip_thread),负责处理所有的 TCP/UDP连接,各种网络程序都通过TCPIP线程与网络交互。但LwIP也可以多线程运行,以提高效率,降低编程复杂度。这时需要用户实现创建新线程的函数:void sys_thread_new(void(*thread)(void* arg),void* arg);

       在UC-OS中,没有线程的概念,只有任务(task)。它已经提供了创建新任务的系统API调用OSTaskCreat,因此,只要把 OSTaskCreat封装一下,就可以实现sys_thread_new。需要注意的是,LwIP中的thread并没有UC-OS中优先级的概念,实现时,要由用户事先为LwIP中创建的线程分配好优先级。

例如nios中UCOS平台下的sys_thread_new函数:

sys_thread_t

sys_thread_new(void (* function)(void *arg), void *arg, intprio)

{

       INT8U bTemp;

       OS_STK * stack;

       if(sys_thread_no >=LWIP_MAX_TASKS)

       {

             printf("sys_thread_new: Max Sys. Tasks reached\n");

       }

       stack =sys_stack[sys_thread_no];

#if 0

    if(bTemp = OSTaskCreate( function, arg,(void *)&sys_stack[sys_thread_no][LWIP_STACK_SIZE - 1],LWIP_START_PRIO+sys_thread_no ))

    {

          printf("sys_thread_new: Task creation error [%d]\n",bTemp);

          while(1);

    }

#else

    if((bTemp = OSTaskCreateExt( function,arg, stack + LWIP_STACK_SIZE, LWIP_START_PRIO+prio, LWIP_START_PRIO+prio,stack, LWIP_STACK_SIZE, NULL, 0 )))

    {

          printf("sys_thread_new: Task creation error [%d]\n",bTemp);

          while(1);

    }

#endif

   

    ++sys_thread_no; /* next task createdwill be one lower to this one */

    return sys_thread_no;

}

nios平台下的整个sys_arch.h文件:

*********************************************************************************************************

*                                              UCOS-II Port

*

*                Target           : Anyprocessor

*                Put together by : Michael Anburaj

*                URL             : http://geocities.com/michaelanburaj/    Email : [email protected]

*

*********************************************************************************************************

*/

#ifndef __SYS_ARCH__H__

#define __SYS_ARCH__H__

#include    "os_cpu.h"

#include    "os_cfg.h"

#ifndef OS_VERSION

#include "ucos_ii.h"

#endif /* OS_VERSION */

#include "system.h"

#define LWIP_MAX_TASKS OS_LOWEST_PRIO /* Number of LwIPtasks */

#define LWIP_START_PRIO0          /* Defined the lowestLwIP task priority */

#ifndef LWIP_STACK_SIZE

#define LWIP_STACK_SIZE 2048

#endif /* LWIP_STACK_SIZE */

/*#define LWIP_STACK_SIZE2048        Stack size for LwIP tasks */

/* Note:

   Task priorities, LWIP_START_PRIO through(LWIP_START_PRIO+LWIP_MAX_TASKS-1) must be reserved

   for LwIP and must not used by otherapplications outside. */

#define LWIP_Q_SIZE10             /* LwIP queue size */

#define LWIP_MAX_QS50             /* Max. LwIP queues */

#define SYS_MBOX_NULL   NULL

#define SYS_SEM_NULL    NULL

typedef struct {

    OS_EVENT*   pQ;

   void*       pvQEntries[LWIP_Q_SIZE];

} TQ_DESCR, *PQ_DESCR;

   

typedef OS_EVENT* sys_sem_t;

typedef PQ_DESCR sys_mbox_t;

typedef INT8U     sys_thread_t;

#endif /* __SYS_ARCH__H__ */

/* 相关函数原型说明 */

/*------------------- 信号量相关函数-------------------*/

sys_sem_t sys_sem_new(u8_tcount);        //建立并返回一个新的信号量

void sys_sem_signal(sys_sem_tsem);       //释放一个信号量

void sys_sem_free(sys_sem_tsem);         //删除一个信号量   (注意:此函数调用的OSSemDel( )函数UCOS不提供)

u32_t sys_arch_sem_wait(sys_sem_t sem, u32_t timeout); //等待由信号sem并阻塞线程,timeout为等待超时

sys_mbox_tsys_mbox_new(void);         

void sys_mbox_free(sys_mbox_tmbox);    

void sys_mbox_post(sys_mbox_t mbox, void *msg);

u32_t sys_arch_mbox_fetch(sys_mbox_t mbox, void **msg,u32_t timeout);

sys_thread_t sys_thread_new(void (* function)(void *arg),void *arg, int prio);

void sys_init(void);   //建立邮箱及其链表

struct sys_timeouts * sys_arch_timeouts(void);

Lib_arch中库函数的实现:

LwIP中用到了8个外部函数,这些函数与用户用到的编译器或系统CPU有关:

       u16_t htons(u16_tn);    //16位数据高低字节交换;

       u16_t ntohs(u16_tn);    //

       u32_t htons(u32_tn);    //32位数据高低字节交换;

       u32_t ntohs(u32_tn);    //

      

       int strlen(const char*str );    //返回字符串长度

       int strncmp(constchar* str1, const char* str2, int len);     //字符串比较

       void bcopy(const void*src,void* dest, int len);   //内存数据块之间的相互拷贝

       void bzero(void*data,int len);       //内存块中指定长度的数据清零

lwIP移植工作(三)ethernet.c网卡驱动程序

网卡驱动程序

       LwIP的网络驱动有一定的模型,/src/netif/ethernetif.c文件即为驱动的模版,用户为自己的网络设备实现驱动时应参照此模块。在 LwIP中可以有多个网络接口,每个网络接口都对应了一个struct netif。这个netif包含了相应网络接口的属性、收发函数。LwIP通过调用netif的方法netif->input()及 netif->output()进行以太网packet的收发等操作。在驱动中主要做的就是,实现网络接口的收发、初始化以及中断处理函数。驱动程序工作在IP协议模型的网络接口层,它提供给上层(IP层)的接口函数如下:

void ethernetif_init(struct netif* netif)   //网卡初始化函数

void ethernetif_input(struct netif*netif)       //网卡接收函数,从网络接口接收以太网数据包,并把其中的IP报文向IP层发送,在中断//方式下向网卡ISR调用

ett_t ethernetif_output(struct netif* netif,struct pbuf*p,struct ip_addr* ipaddr)       //网卡发送函数,给IP层传过来的IP报文加上以太网//包头,并通过网络接口发送

void ethernetif_isr(void) //网卡中断处理函数ISR

 

你可能感兴趣的:(lwip)