LWIP提供了观察和调试协议栈内部的方法。LWIP关于调试的内容在debug.h和stats.h文件中可见。
为了实现重定向 printf()函数,我们需要重写 fputc() 这个 c 标准库函数,因为 printf()在 c 标准库函数中实质是一个宏,最终是调用了 fputc()这个函数的。重定向的这部分工作,由 usart.c 文件中的 fputc(int ch, FILE *f) 这个函数来完成。
#define LWIP_ERROR(message, expression, handler) \
do { if (!(expression)) { \
LWIP_PLATFORM_ASSERT(message); handler;}} while(0)
实际就是
LWIP_ERROR(message, expression, handler)
{
if (!(expression))
{
LWIP_PLATFORM_ASSERT(message);
handler;
}
}
而LWIP_PLATFORM_ASSERT(message)在cc.h中定义
#define LWIP_PLATFORM_ASSERT(x) \
do \
{ printf("Assertion \"%s\" failed at line %d in %s\n",\ x, __LINE__, __FILE__); \
} while(0)
#endif
当expression不成立,则输出出错位置的行号与文件。同时调用处理函数函数。在lwip中
handler一般为 return sth;
#define LWIP_DEBUGF(debug, message) do { \
if ( \
((debug) & LWIP_DBG_ON) && \
((debug) & LWIP_DBG_TYPES_ON) && \
((s16_t)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_ MIN_LEVEL)) { \
LWIP_PLATFORM_DIAG(message); \
if ((debug) & LWIP_DBG_HALT) { \
while(1); \
} \
} \
} while(0)
//---LWIP_DEBUGF(debug, message)为debug.h中实现的宏定义。
//---实际就是
LWIP_DEBUGF(debug, message)
{
if (((debug) & LWIP_DBG_ON) && ((debug) & LWIP_DBG_TYPES_ON) &&
((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL))
{
LWIP_PLATFORM_DIAG(message);
if ((debug) & LWIP_DBG_HALT)
{
while(1);
}
}
}
1)调试系统有三个开关
LWIP_DBG_ON 调试总开关
LWIP_DBG_TYPES_ON 调试类型开关
LWIP_DBG_MASK_LEVEL 调试水平
* - 0 all
* - 1 warning
* - 2 serious
* - 3 severe
2)LWIP_PLATFORM_DIAG(message)函数在cc.h定义
#define LWIP_PLATFORM_DIAG(x) do {printf x;} while(0)
#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
LWIP_PLATFORM_ASSERT(message); } while(0)
LWIP_PLATFORM_ASSERT(message)在cc.h文件由用户定义
#define LWIP_ASSERT(message, assertion) do { if(!(assertion)) \
LWIP_PLATFORM_ASSERT(message); } while(0)
在stat.c文件中定义了如下统计信息
struct stats_ {
#if LINK_STATS
struct stats_proto link;
#endif
#if ETHARP_STATS
struct stats_proto etharp;
#endif
#if IPFRAG_STATS
struct stats_proto ip_frag;
#endif
#if IP_STATS
struct stats_proto ip;
#endif
#if ICMP_STATS
struct stats_proto icmp;
#endif
#if IGMP_STATS
struct stats_igmp igmp;
#endif
#if UDP_STATS
struct stats_proto udp;
#endif
#if TCP_STATS
struct stats_proto tcp;
#endif
#if MEM_STATS
struct stats_mem mem;
#endif
#if MEMP_STATS
struct stats_mem memp[MEMP_MAX];
#endif
#if SYS_STATS
struct stats_sys sys;
#endif
};
上述统计信息,除stats_sys,其余在相应宏开关打开后,统计信息由协议栈自动完成,而对于stats_sys统计信息的实现,可在sys_arch关于信号量和有限的申请释放函数中实现。
1、在stats.h 添加如下代码,/—add sun—/便是添加的代码
#if SYS_STATS
#define SYS_STATS_INC(x) STATS_INC(sys.x)
#define SYS_STATS_DEC(x) STATS_DEC(sys.x)
#define SYS_STATS_DISPLAY() stats_display_sys(&lwip_stats.sys)
/*---add sun---*/
#define SYS_STATS_SEM_AVAIL(t,x) (lwip_stats.sys.sem.t=x)
#define SYS_STATS_MBOX_AVAIL(t,x) (lwip_stats.sys.mbox.t=x)
#define SYS_STATS_INC_USED(t) do { ++lwip_stats.sys.t.used; \
if (lwip_stats.sys.t.max < lwip_stats.sys.t.used) { \
lwip_stats.sys.t.max = lwip_stats.sys.t.used; \
} \
} while(0)
/*---add sun---*/
#else
#define SYS_STATS_INC(x)
#define SYS_STATS_DEC(x)
#define SYS_STATS_DISPLAY()
/*---add sun---*/
#define SYS_STATS_INC_USED(t,x)
#define SYS_STATS_SEM_AVAIL(t,x)
#define SYS_STATS_MBOX_AVAIL(t,x)
/*---add sun---*/
#endif
struct stats_syselem { //---添加变量avail表示协议栈总共多少个信号量
/*---add sun---*/
STAT_COUNTER avail;
/*---add sun---*/
STAT_COUNTER used;
STAT_COUNTER max;
STAT_COUNTER err;
};
struct stats_syselem { //---添加变量avail表示协议栈总共多少个邮箱
/*---add sun---*/
STAT_COUNTER avail;
/*---add sun---*/
STAT_COUNTER used;
STAT_COUNTER max;
STAT_COUNTER err;
};
2、在stats.c中stats_display_sys()添加如下代码,显示协议栈总共的邮箱和信号量个数。
LWIP_PLATFORM_DIAG(("sem.avail: %"U32_F"\n\t", (u32_t)sys->sem.avail));
LWIP_PLATFORM_DIAG(("mbox.avail: %"U32_F"\n\t", (u32_t)sys->mbox.avail));
3、在sys_arch.c
3.1 sys_init函数添加关于信号量和邮箱统计信息的初始化
SYS_STATS_MBOX_AVAIL(avail,OS_MAX_QS);
SYS_STATS_MBOX_AVAIL(used,0);
SYS_STATS_MBOX_AVAIL(max,0);
SYS_STATS_MBOX_AVAIL(err,0);
SYS_STATS_SEM_AVAIL(avail,OS_MAX_EVENTS-OS_MAX_FLAGS);
SYS_STATS_SEM_AVAIL(used,0);
SYS_STATS_SEM_AVAIL(max,0);
SYS_STATS_SEM_AVAIL(err,0);
3.2 mbox分配与释放
在邮箱分配成功后添加:
SYS_STATS_INC_USED(mbox);
在邮箱释放成功后:
SYS_STATS_DEC(mbox.used);
3.3 sem分配与释放
在信号量分配成功后添加:
SYS_STATS_INC_USED(sem);
在信号量释放成功后:
SYS_STATS_DEC(sem.used);
4、在lwipopts.h打开相应宏开关,并在任务中调用相关stats_display()函数就可在串口调试中看到LWIP的统计信息了。
5、在LWIP的1.4版本中提供了shell.c代码
代码运行界面如图所示
其中的stat的命令也同样可查询lwip状态。
shell里面的功能暂时还不怎么会用!