1、说明
通过日志等级的宏定义,来控制打印函数
2、源码
2.1 .h文件
//打印等级
#define LOG_LEVEL_NONE 0
#define LOG_LEVEL_ERROR 1
#define LOG_LEVEL_INFO 2
#define LOG_LEVEL_DBG 3
#define LOG_LEVEL_CONFIG LOG_LEVEL_INFO
#if (LOG_LEVEL_CONFIG > LOG_LEVEL_NONE)
#define LOG(TAG, ...) debug_level_printf(TAG, ##__VA_ARGS__)
#define LOGH(a, b) debug_level_hexdump(a, b)
#else
#define LOG(TAG, ...) do { (void)TAG; } while (0)
#define LOGH(a, b) do { (void)a; (void)b; } while (0)
#endif
2.2 .c文件
补充说明:串口打印显示的本质都是显示字符串,当显示HEX值的时候,即通过把一个字节的HEX值,拆分成高低4位,高4位用一个字符显示,低4位也用一个字符显示;例如当一个hex值为0xAB时,即串口要传输的值为 ' A '、' B ',共两个字节
#if (LOG_LEVEL_CONFIG != LOG_LEVEL_NONE)
void debug_level_printf(const char *fmt, ...);
void debug_level_hexdump(uint8_t *data_buf, uint32_t data_len);
#else
#define debug_level_printf(a, ...)
#define debug_level_hexdump(a, b)
#if (LOG_LEVEL_CONFIG != LOG_LEVEL_NONE)
#define LOG_LEVEL_CONFIG 1024 //LOG缓冲区的最大长度
uint8_t m_log_buf[LOG_LEVEL_CONFIG] = {0}; //缓冲区
//打印字符串
void debug_level_printf(const char *fmt, ...)
{
va_list arg_ptr;
memset(m_log_buf, 0, sizeof(m_log_buf));
va_start(arg_ptr, fmt);
vsprintf((char *)m_log_buf, fmt, arg_ptr);
va_end(arg_ptr);
m_log_buf[LOG_BUFFER_SIZE-1] = 0; //末尾补‘\0’
UART_Send(m_log_buf, strlen((char *)m_log_buf));
}
//========================================================================
//函数: hex_2_ASCII
//功能: 十六进制转换成ASCII
//========================================================================
static void hex_2_ASCII(const uint8_t *hex_buf, uint8_t *asc_buf, uint32_t hex_len)
{
uint8_t half_byte = 0x00;
for(uint32_t i = 0; i < hex_len; i++)
{
//高四位的值转成ASCII字符,0-9 A-Z
half_byte = (hex_buf[i] & 0xF0)>>4;
if( half_byte > 0x09 )
{
asc_buf[i*3+0] = half_byte - 0x0A + 'A';
}
else
{
asc_buf[i*3+0] = half_byte + '0';
}
//低四位的值转成ASCII字符,0-9 A-Z
half_byte = hex_buf[i] & 0x0F;
if( half_byte > 0x09 )
{
asc_buf[i*3+1] = half_byte - 0x0A + 'A';
}
else
{
asc_buf[i*3+1] = half_byte + '0';
}
asc_buf[i*3+2] = 0x20; //补空格符号
/* 以下是不带空格符号的
//高四位的值转成ASCII字符,0-9 A-Z
half_byte = (hex_buf[i] & 0xF0)>>4;
if( half_byte > 0x09 )
{
asc_buf[i*2+0] = half_byte - 0x0A + 'A';
}
else
{
asc_buf[i*2+0] = half_byte + '0';
}
//低四位的值转成ASCII字符,0-9 A-Z
half_byte = hex_buf[i] & 0x0F;
if( half_byte > 0x09 )
{
asc_buf[i*2+1] = half_byte - 0x0A + 'A';
}
else
{
asc_buf[i*2+1] = half_byte + '0';
}
*/
}
}
//打印HEX
void debug_level_hex(uint8_t *data_buf, uint32_t data_len)
{
memset(m_log_buf, 0, sizeof(m_log_buf));
//前n-1个hex值都需要3个字符表示(其中一个是空格),第n个hex不需要空格,但末尾需要跟上‘\0’(防止strlen越界)
if(data_len > LOG_LEVEL_CONFIG/3)
{
return;
}
hex_2_ASCII(data_buf, m_log_buf, data_len);
m_log_buf[LOG_BUFFER_SIZE-1] = 0; //末尾补‘\0’
UART_Send(m_log_buf, strlen((char *)m_log_buf));
}
#endif
3、小tips
学会使用标签,即在每条日志报文前面附带标签语 "[ INFO ]"、"[ ERROR ]",方便我们在查完问题时,清晰知道每条日志的类型;同样的,我们也可以在一个项目中,通过不用标签代表这是不同模组输出的日志,如 [ 4G INFO ]、[ WIFI INFO]、[ETH INFO]等
[4G_INFO] :一般指4G模组的过程行为信息打印的标签
[4G_ERROR]:一般出现故障时用的标签
[4G_RX]:一般指4G模组收到的原报文内容,一般用hex显示
[4G_TX]:一般指4G模组收到的发送的原报文内容,一般用hex显示