前言
本文对lwip中debug.h
文件里的调试相关宏进行分析。
正文
debug.h中有3个重要的调试相关宏:
LWIP_ASSERT(message, assertion)
LWIP_ERROR(message, expression, handler)
LWIP_DEBUGF(debug, message)
断言
LWIP_ASSERT(message, assertion)
源代码为:
#define LWIP_ASSERT(message, assertion) do { if (!(assertion)) { \
LWIP_PLATFORM_ASSERT(message); }} while(0)
message
为断言触发时输出的字符串,assertion
为一个布尔值,展开后:
if (!(assertion))
{
printf("Assertion \"%s\" failed at line %d in %s\n",
message, __LINE__, __FILE__);
fflush(NULL); //更新文件系统
abort(); //程序中止运行
}
当判断条件不为真时,打印断言原因,输出断言所在文件名和文件中行数,更新文件系统 ,中止程序运行。
例子:
err_t
ethernetif_init(struct netif *netif)
{
struct ethernetif *ethernetif;
LWIP_ASSERT("netif != NULL", (netif != NULL));
。。。。。。
/* initialize the hardware */
low_level_init(netif);
return ERR_OK;
}
网卡初始化部分代码,当传入指针为空时,触发断言。
错误处理
LWIP_ERROR(message, expression, handler)
源码为:
#define LWIP_ERROR(message, expression, handler) do { if (!(expression)) { \
LWIP_PLATFORM_ERROR(message); handler;}} while(0)
message
为一段错误发生时输出的字符串,expression
为错误判断条件,handler
为一段代码,展开如下:
if (!(expression)
{
printf(message);
handler;
}
当判断条件不为真后,输出错误原因,执行错误处理代码handler
。
例子:
err_t
netconn_getaddr(struct netconn *conn, ip_addr_t *addr, u16_t *port, u8_t local)
{
API_MSG_VAR_DECLARE(msg);
err_t err;
LWIP_ERROR("netconn_getaddr: invalid conn", (conn != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid addr", (addr != NULL), return ERR_ARG;);
LWIP_ERROR("netconn_getaddr: invalid port", (port != NULL), return ERR_ARG;);
。。。。。。
return err;
}
传入指针为空,打印错误原因,返回ERR_ARG
错误码。
调试打印
LWIP_DEBUGF(debug, message)
源码为:
#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)
debug
包含了多个用于控制调试行为的位标志。message
是要调试打印的字符串。
展开后:
if (((debug) & LWIP_DBG_ON) &&
((debug) & LWIP_DBG_TYPES_ON)) &&
((signed short)((debug) & LWIP_DBG_MASK_LEVEL) >= LWIP_DBG_MIN_LEVEL))
{
printf(message);
if ((debug) & LWIP_DBG_HALT)
{
while(1);
}
}
其中:
#define LWIP_DBG_TYPES_ON LWIP_DBG_ON
/** flag for LWIP_DEBUGF to enable that debug message */
#define LWIP_DBG_ON 0x80U
/** flag for LWIP_DEBUGF to disable that debug message */
#define LWIP_DBG_OFF 0x00U
可见LWIP_DBG_TYPES_ON
与LWIP_DBG_ON
是一样的,都是0x80U
当debug
的第15位置1时,开启调试打印。
#define LWIP_DBG_MASK_LEVEL 0x03
表示debug
的低两位是调式等级。
#define LWIP_DBG_MIN_LEVEL LWIP_DBG_LEVEL_ALL
/** Debug level: ALL messages*/
#define LWIP_DBG_LEVEL_ALL 0x00
/** Debug level: Warnings. bad checksums, dropped packets, ... */
#define LWIP_DBG_LEVEL_WARNING 0x01
/** Debug level: Serious. memory allocation failures, ... */
#define LWIP_DBG_LEVEL_SERIOUS 0x02
/** Debug level: Severe */
#define LWIP_DBG_LEVEL_SEVERE 0x03
表示有4个调试等级。
当debug
低两位表示的调式等级高于LWIP_DBG_MIN_LEVEL
时,开启调试打印。
#define LWIP_DBG_HALT 0x08U
表示当debug
的第3为置1时,打印调试信息后,进入while循环中止程序运行。
在opt.h文件中包含了lwip所有的调试标志,如下:
#define ETHARP_DEBUG LWIP_DBG_OFF
#define NETIF_DEBUG LWIP_DBG_OFF
#define PBUF_DEBUG LWIP_DBG_OFF
#define API_LIB_DEBUG LWIP_DBG_OFF
#define API_MSG_DEBUG LWIP_DBG_OFF
#define SOCKETS_DEBUG LWIP_DBG_OFF
。。。。。。
表示这些调试打印都关闭了,如果把LWIP_DBG_OFF
换成LWIP_DBG_ON
则开启对应的调试打印。
例子:
err_t
ethernetif_init(struct netif *netif)
{
struct ethernetif *ethernetif;
ethernetif = mem_malloc(sizeof(struct ethernetif));
if (ethernetif == NULL)
{
LWIP_DEBUGF(NETIF_DEBUG, ("ethernetif_init: out of memory\n"));
return ERR_MEM;
}
。。。。。。
return ERR_OK;
}
当opt.h
文件中NETIF_DEBUG
宏定义为LWIP_DBG_ON
时,则运行到这里时打印后面的字符串。