LWIP v1.4.1和v2.1.2的对比以及升级过程

1.根目录对比情况

根目录对比

从解压出来的文件来看,在文件结构上来看,两个版本并没有很大的区别,2.1.2版本多了FEATURESCMakeList.txt两个文件。(是因为后续的版本都采用git的缘故)。这篇文章,主要是针对两个版本的源文件的不同进行分析。

2.src源文件目录

从文件夹的结构来看,2.1.2版本的源文件比1.4.1的多了一个apps的文件夹。在2.1.2中,lwip增加了很多上层的应用,方便开发者直接使用。主要包括常见的应用程序,如 httpd、 mqtt、tftp、 sntp、 snmp 等。

2.1 netif文件夹比较

文件夹里面是与网卡移植有关的文件, 这些文件为我们移植网卡提供了模板,我们可以直接使用。在1.4.1中提供了ethernetif.c源文件,该文件是主要跟网卡底层驱动相关的,在2.1.2中该文件以及不提供在lwip源码里面了,它被挪到了contrib-2.1.0.zip包里,这个在官网也提供了,目前版本更新到了2.1.0。包里面装的主要是 LwIP 内核的源码文件,而 contrib 包里面装的是移植和应用 LwIP 的一些 demo,即应用示例。 contrib 包不属于 LwIP 内核的一部分,里面的很多内容来自开源社区的贡献。

2.2 include文件夹比较

该文件夹是LwIP 所有模块对应的头文件,1.4.2的ipv6ipv4文件夹已经归并在include目录下的lwip
compat主要是跟不同的操作系统提供的一些兼容的头文件。

2.3 core文件夹比较

从本质上来说,这部分内核要实现的功能是大体一致的。

2.4 api文件夹比较

api 文件夹里面装的是 NETCONN API 和 Socket API 相关的源文件,只有在操作系统的环境中,才能被编译。如果跑lwip不用说操作系统的话,这个文件夹里面的内容其实是不用添加的。

3.从1.4.1升级到2.1.2,该怎么做?

这里的话,只是针对带操作系统的平台进行分析,仅以开发板的网络Demo进行讲解,这里的硬件平台为stm32f407+lan8720,操作系统为ucos。

1.准备工作,将开发板中的1.4.1工程拷贝出来。工程示意如下:

2.在工程中删除上述文件(注意保留跟操作系统和硬件接口相关的文件,sys_arch.c/.h,ethernetif.c,cc.h,pref.h),红色框框里全部是跟lwip相关的。现在我们要将它们替换成2.1.2版本的。

在工程里添加头文件

其中cc.h,perf.h是从contrib-2.1.0包拷贝而来的。

对于原始工程1.4.1的来说,cc.h主要是定义数据类型,在新版本中已经arch.h中进行定义

所以我们要注销这部分代码

1.4.1版本cc.h源代码

#ifndef __CC_H__
#define __CC_H__


#include <stdio.h>     //使用printf函数,需包含stdio.h
#include "includes.h"  //使用UCOS 要添加此头文件!

#define BYTE_ORDER LITTLE_ENDIAN   //小端模式

#define LWIP_PROVIDE_ERRNO 1       //使用lwip/arch.h头文件来定义这些编码

//LwIP使用的数据类型定义――u8_t, s8_t, u16_t,s16_t,u32_t,s32_t,mem_ptr_t。
typedef unsigned   char    u8_t;
typedef signed     char    s8_t;
typedef unsigned   short   u16_t;
typedef signed     short   s16_t;
typedef unsigned   long    u32_t;
typedef signed     long    s32_t;
typedef u32_t mem_ptr_t;

//与编译器相关的LwIP结构体宏
#if defined (__ICCARM__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT 
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES

#elif defined (__CC_ARM)

#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT 
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#elif defined (__GNUC__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#elif defined (__TASKING__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#endif


//  与平台相关的调试输,使用printf函数
#ifndef LWIP_PLATFORM_ASSERT
#define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0)
#endif

#ifndef LWIP_PLATFORM_DIAG
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#endif

#if OS_CRITICAL_METHOD == 3  
#define SYS_ARCH_DECL_PROTECT(lev)	u32_t lev
#define SYS_ARCH_PROTECT(lev)		    lev = OS_CPU_SR_Save() 	//UCOS II中进入临界区,关中断
#define SYS_ARCH_UNPROTECT(lev)		  OS_CPU_SR_Restore(lev)	//UCOS II中退出A临界区,开中断 
#endif

#endif /* __CC_H__ */

2.1.2中cc.h的源码,只需要在1.4.1中的代码基础上,注销掉以下代码即可

注销的代码段已经在arch.h文件中进行定义了

#ifndef __CC_H__
#define __CC_H__


#include <stdio.h>     //使用printf函数,需包含stdio.h
#include "includes.h"  //使用UCOS 要添加此头文件!

#define BYTE_ORDER LITTLE_ENDIAN   //小端模式

#define LWIP_PROVIDE_ERRNO 1       //使用lwip/arch.h头文件来定义这些编码

// 2.1.2的库已经在arch.h中进行定义,这里的注销掉就好了
//LwIP使用的数据类型定义――u8_t, s8_t, u16_t,s16_t,u32_t,s32_t,mem_ptr_t。
//typedef unsigned   char    u8_t;
//typedef signed     char    s8_t;
//typedef unsigned   short   u16_t;
//typedef signed     short   s16_t;
//typedef unsigned   long    u32_t;
//typedef signed     long    s32_t;
//typedef u32_t mem_ptr_t;

//与编译器相关的LwIP结构体宏
#if defined (__ICCARM__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT 
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x
#define PACK_STRUCT_USE_INCLUDES

#elif defined (__CC_ARM)

#define PACK_STRUCT_BEGIN __packed
#define PACK_STRUCT_STRUCT 
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#elif defined (__GNUC__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT __attribute__ ((__packed__))
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#elif defined (__TASKING__)

#define PACK_STRUCT_BEGIN
#define PACK_STRUCT_STRUCT
#define PACK_STRUCT_END
#define PACK_STRUCT_FIELD(x) x

#endif


//  与平台相关的调试输,使用printf函数
#ifndef LWIP_PLATFORM_ASSERT
#define LWIP_PLATFORM_ASSERT(x) do { if(!(x)) while(1); } while(0)
#endif

#ifndef LWIP_PLATFORM_DIAG
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#endif

#if OS_CRITICAL_METHOD == 3  
#define SYS_ARCH_DECL_PROTECT(lev)	u32_t lev
#define SYS_ARCH_PROTECT(lev)		    lev = OS_CPU_SR_Save() 	//UCOS II中进入临界区,关中断
#define SYS_ARCH_UNPROTECT(lev)		  OS_CPU_SR_Restore(lev)	//UCOS II中退出A临界区,开中断 
#endif

#endif /* __CC_H__ */

perf.h文件,实际上没有用到

ethernetif.c和sys_arch.c/sys_arch.h从本质上没有太大变化,只是在实际编译的过程中会出现一个错误

Error: L6218E: Undefined symbol sys_mbox_trypost_fromisr (referred from tcpip.o).

这个是因为在2.1.2.版本中新增加一个在中断中进行邮箱的发送,我们只需要重新编写一下这个函数即可

源码如下:

//向一个消息邮箱发送消息(发送一次,成功与否都不阻塞进程)
//*mbox:消息邮箱
//*msg:要发送的消息
//返回值:ERR_OK,发送OK
// 	     ERR_MEM,发送失败
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
{ 
    if((OSQPost((*mbox)->pst, msg))!=OS_ERR_NONE)return ERR_MEM;
    return ERR_OK;
}
//新版本2.1.2增加在中断中发送邮箱的函数,我们需要对该函数进行实现
//直接跟 sys_mbox_trypost 函数一样实现即可。
err_t sys_mbox_trypost_fromisr(sys_mbox_t *mbox, void *msg)
{ 
    if((OSQPost((*mbox)->pst, msg))!=OS_ERR_NONE)return ERR_MEM;
    return ERR_OK;
}

整个过程大概就是这样了。顺便说一下移植过程中,编译出现的问题

1.V1.4.1中的struct ip_addr在新版中改为ip_addr_t,此处要作相应修改

2.这个是因为LWIP_RAND在V1.4.1中是常量宏,定义在lwipopts.h中,而到了V2.1.2,它是宏函数的形式LWIP_RAND(),定义在cc.h中,所以出现这么个提示。本例在sys_arch.c中定义了_LWIP_RAND(),使用系统的tick计数作为随机数,因此在cc.h中定义#define LWIP_RAND() _LWIP_RAND() 即可。另外一种解决办法就是不用DNS.

3.因为没有实现互斥锁带来的问题

4.Error: L6218E: Undefined symbol errno (referred from if_api.o).

ethernetif.c中定义即可。

后续工作:

将操作ucos替换成rt-thread的。

参考文档:

《野火lwip应用开发指南》

发布了7 篇原创文章 · 获赞 3 · 访问量 3788

猜你喜欢

转载自blog.csdn.net/u011522841/article/details/102779759