文章目录
原创声明
本文为 HinGwenWoong 原创,如果这篇文章对您有帮助,欢迎转载,转载请阅读文末的【授权须知】,感谢您对 HinGwenWoong 文章的认可!
前言
嵌入式设备里面,都是有很多个模块相互构成的,如果只是将 Log
直接 printf
打印出来,会导致满屏都是 Log
的信息,让你眼花缭乱,而且很多不重要信息输出,让你拿不定轻重,我搭建了一个 LogUltra
模块,:一个可以开启、关闭某一个模块的打印信息,并且可以将该模块的主次信息选择打印的 LOG 模块。
我这里使用了 SEGGER RTT
来进行输出,如何使用 SEGGER RTT
神器实现输出,请看我这篇文章 【嵌入式小技巧】stm32 实现 Segger RTT 打印(超详细)
我是 HinGwenWoong,一个有着清晰目标不停奋斗的程序猿,热爱技术,喜欢分享,码字不易,如果帮到您,请帮我在屏幕下方点赞 👍 ,您的点赞可以让技术传播得更远更广,谢谢!
一、LogUltra 流程图
1.1 LogUltra 初始化流程
1.2 LogUltra 打印流程
二、演示 Demo
int main(void)
{
//这里注册 LOG_SRC_APP_1 和 LOG_SRC_APP_2 的打印信息,打印标识 <= LOG_LEVEL_INFO 的信息
__LOG_INIT(LOG_SRC_APP_1 | LOG_SRC_APP_2, LOG_LEVEL_INFO, LOG_CALLBACK_DEFAULT);
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "----- Demo A Start !-----\n");
//因为上面注册了 LOG_SRC_APP_1 和 LOG_SRC_APP_2 的打印信息,打印标识 <= LOG_LEVEL_INFO 的信息,
//下面只会打印 1 & 2 的信息
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "App 1 LOG : LOG_LEVEL_INFO !\n");
__LOG(LOG_SRC_APP_2, LOG_LEVEL_INFO, "App 2 LOG : LOG_LEVEL_INFO !\n");
__LOG(LOG_SRC_APP_3, LOG_LEVEL_INFO, "App 3 LOG : LOG_LEVEL_INFO !\n");
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "===\n"); //换行
Delay_MS(1000);
//因为上面注册了 LOG_LEVEL_INFO 标识是 4,而 LOG_LEVEL_ASSERT 的标识是 0,所以会打印 1 & 2 的信息
__LOG(LOG_SRC_APP_1, LOG_LEVEL_ASSERT, "App 1 LOG : LOG_LEVEL_ASSERT !\n");
__LOG(LOG_SRC_APP_2, LOG_LEVEL_ASSERT, "App 2 LOG : LOG_LEVEL_ASSERT !\n");
__LOG(LOG_SRC_APP_3, LOG_LEVEL_ASSERT, "App 3 LOG : LOG_LEVEL_ASSERT !\n");
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "===\n"); //换行
Delay_MS(1000);
//因为上面注册了 LOG_LEVEL_INFO 标识是 4,而 LOG_LEVEL_ASSERT 的标识是 11,不会打印下面的信息
__LOG(LOG_SRC_APP_1, EVT_LEVEL_DATA, "App 1 LOG : EVT_LEVEL_DATA !\n");
__LOG(LOG_SRC_APP_2, EVT_LEVEL_DATA, "App 2 LOG : EVT_LEVEL_DATA !\n");
__LOG(LOG_SRC_APP_3, EVT_LEVEL_DATA, "App 3 LOG : EVT_LEVEL_DATA !\n");
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "...\n"); //标识
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "===\n"); //换行
Delay_MS(1000);
//重新注册 LOG_SRC_APP_1 和 LOG_SRC_APP_2 | LOG_SRC_APP_3 的打印信息,打印标识 <= EVT_LEVEL_DATA 的信息
__LOG_INIT(LOG_SRC_APP_1 | LOG_SRC_APP_2 | LOG_SRC_APP_3 , EVT_LEVEL_DATA, LOG_CALLBACK_DEFAULT);
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "----- Demo B Start !-----\n");
//下面 3 条都会打印
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "App 1 LOG : LOG_LEVEL_INFO !\n");
__LOG(LOG_SRC_APP_2, LOG_LEVEL_INFO, "App 2 LOG : LOG_LEVEL_INFO !\n");
__LOG(LOG_SRC_APP_3, LOG_LEVEL_INFO, "App 3 LOG : LOG_LEVEL_INFO !\n");
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "===\n"); //换行
Delay_MS(1000);
//下面 3 条都会打印
__LOG(LOG_SRC_APP_1, LOG_LEVEL_ASSERT, "App 1 LOG : LOG_LEVEL_ASSERT !\n");
__LOG(LOG_SRC_APP_2, LOG_LEVEL_ASSERT, "App 2 LOG : LOG_LEVEL_ASSERT !\n");
__LOG(LOG_SRC_APP_3, LOG_LEVEL_ASSERT, "App 3 LOG : LOG_LEVEL_ASSERT !\n");
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "===\n"); //换行
Delay_MS(1000);
//下面 3 条都会打印
__LOG(LOG_SRC_APP_1, EVT_LEVEL_DATA, "App 1 LOG : EVT_LEVEL_DATA !\n");
__LOG(LOG_SRC_APP_2, EVT_LEVEL_DATA, "App 2 LOG : EVT_LEVEL_DATA !\n");
__LOG(LOG_SRC_APP_3, EVT_LEVEL_DATA, "App 3 LOG : EVT_LEVEL_DATA !\n");
__LOG(LOG_SRC_APP_1, LOG_LEVEL_INFO, "----- Demo Array Start !-----\n");
//打印 16进制数组的字符串
uint8_t array[10] = {0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A};
__LOG_XB(LOG_SRC_APP_1, EVT_LEVEL_DATA, "Array = ", array, sizeof(array));
}
三、效果
下面的效果图对应的是上面的 二、演示 Demo
里面的 C代码。
四、LogUltra 实现
4.1 LogUltra.c
/*======================================================================================*
* 文件名 : LogUltra .c
* 描述 : 一个可以开启、关闭某一个模块的打印信息,并且可以将该模块的主次信息选择打印的 LOG 模块。
* 日期 : 2020.09.08
* 作者 : HinGwenWoong
*=====================================================================================*/
/* segger rtt includes. */
#include <SEGGER_RTT.h>
/* lib includes. */
#include <stdarg.h>
#include <stdint.h>
#include "log_ultra.h"
const char * g_log_hex_digits = "0123456789ABCDEF";
uint8_t g_segger_init_flag = 0;
uint32_t g_log_dbg_msk = LOG_MSK_DEFAULT;
int32_t g_log_dbg_lvl = LOG_LEVEL_DEFAULT;
log_callback_t m_log_callback = LOG_CALLBACK_DEFAULT;
/**
* Gets a timestamp to use with the log functions.
*
* @return A timestamp to use with the log functions.
*/
__weak uint32_t log_timestamp_get(void)
{
// Overwrite with your own time function
return 0;
}
void log_callback_rtt(uint32_t dbg_level, const char * p_filename, uint16_t line,
uint32_t timestamp, const char * format, va_list arguments)
{
SEGGER_RTT_printf(0, "<t: %10u>, %s, %4d, ",timestamp, p_filename, line);
SEGGER_RTT_vprintf(0, format, &arguments);
}
/**
* Initializes the logging module.
*
* @param[in] mask Mask specifying which modules to log information from.
* @param[in] level Maximum log level to print messages from.
* @param[in] callback Callback function for printing log strings.
*/
void log_init(uint32_t mask, uint32_t level, log_callback_t callback)
{
if(g_segger_init_flag == 0)
{
SEGGER_RTT_Init();
g_segger_init_flag = 1;
}
g_log_dbg_msk = mask;
g_log_dbg_lvl = level;
m_log_callback = callback;
}
/**
* Sets the log callback function.
*
* The callback function is called to print strings from the logging module.
* An application that is interested in internal logging can set this function
* in order to print the log information in an application-specific way.
*
* @param[in] callback The callback function to use for printing log information.
*/
void log_set_callback(log_callback_t callback)
{
m_log_callback = callback;
}
/**
* Prints log data.
* This function is used by the logging macros, but can also be called directly
* if desired.
*
* @param[in] dbg_level The debugging level to print the message as.
* @param[in] p_filename Name of the file in which the log call originated.
* @param[in] line Line number where the function was called.
* @param[in] timestamp Timestamp for when the log function was called.
* @param[in] format Format string, printf()-compatible.
*
* @see log_vprintf()
*/
void log_printf(uint32_t dbg_level, const char * p_filename, uint16_t line,
uint32_t timestamp, const char * format, ...)
{
va_list arguments; /*lint -save -esym(530,arguments) Symbol arguments not initialized. */
va_start(arguments, format);
log_vprintf(dbg_level, p_filename, line, timestamp, format, arguments);
va_end(arguments); /*lint -restore */
}
void log_vprintf(uint32_t dbg_level, const char * p_filename, uint16_t line,
uint32_t timestamp, const char * format, va_list arguments)
{
if (m_log_callback != NULL)
{
m_log_callback(dbg_level, p_filename, line, timestamp, format, arguments);
}
}
4.2 LogUltra.h
/*======================================================================================*
* 文件名 : LogUltra.h
* 描述 : 一个可以开启、关闭某一个模块的打印信息,并且可以将该模块的主次信息选择打印的 LOG 模块。
* 日期 : 2020.09.08
* 作者 : HinGwenWoong
*=====================================================================================*/
#ifndef __LOG_ULTRA_H
#define __LOG_ULTRA_H
/*-----------------------------------------------------------
* Includes files
*----------------------------------------------------------*/
#include <stdarg.h>
#include <stddef.h>
#include <stdint.h>
#include <string.h>
/*-----------------------------------------------------------
* Exported constants
*----------------------------------------------------------*/
/*-----------------------------------------------------------
* Exported macro
*----------------------------------------------------------*/
/**
* @defgroup Log module configuration
* @{
*/
/** Enable logging module. */
#define LOG_ENABLE 1
/** Default log level. Messages with lower criticality is filtered. */
#define LOG_LEVEL_DEFAULT LOG_LEVEL_WARN
/** Default log mask. Messages with other sources are filtered. */
#define LOG_MSK_DEFAULT LOG_GROUP_STACK
/** Enable logging with RTT callback. */
#define LOG_ENABLE_RTT 1
/** The default callback function to use. */
#define LOG_CALLBACK_DEFAULT log_callback_rtt
/** @} end of MESH_CONFIG_LOG */
/** Maximum number of array elements to print in the @ref __LOG_XB macro. */
#define LOG_ARRAY_LEN_MAX 128
/**
* @defgroup LOG_SOURCES Log sources
* Defines various sources for logging messages. This can be used in __LOG_INIT() to
* filter events from different modules.
* @{
*/
#define LOG_SRC_APP_1 (1 << 0) /**< Receive logs from the app 1. */
#define LOG_SRC_APP_2 (1 << 1) /**< Receive logs from the app 2. */
#define LOG_SRC_APP_3 (1 << 2) /**< Receive logs from the app 3. */
/** Group for receiving logs from the core stack. */
#define LOG_GROUP_STACK (LOG_SRC_APP_1 | LOG_SRC_APP_2)
/** @} */
/**
* @defgroup LOG_LEVELS Log levels
* Defines possible criticality levels for logged messages. This can be used in
* __LOG_INIT() to filter events by criticality.
* @{
*/
#define LOG_LEVEL_ASSERT ( 0) /**< Log level for assertions */
#define LOG_LEVEL_ERROR ( 1) /**< Log level for error messages. */
#define LOG_LEVEL_WARN ( 2) /**< Log level for warning messages. */
#define LOG_LEVEL_REPORT ( 3) /**< Log level for report messages. */
#define LOG_LEVEL_INFO ( 4) /**< Log level for information messages. */
#define LOG_LEVEL_DBG1 ( 5) /**< Log level for debug messages (debug level 1). */
#define LOG_LEVEL_DBG2 ( 4) /**< Log level for debug messages (debug level 2). */
#define LOG_LEVEL_DBG3 ( 7) /**< Log level for debug messages (debug level 3). */
#define EVT_LEVEL_BASE ( 8) /**< Base level for event logging. For internal use only. */
#define EVT_LEVEL_ERROR ( 9) /**< Critical error event logging level. For internal use only. */
#define EVT_LEVEL_INFO (10) /**< Normal event logging level. For internal use only. */
#define EVT_LEVEL_DATA (11) /**< Event data logging level. For internal use only. */
/** @} */
/** Filename macro used when printing. Provides the filename of the input file without any directory prefix. */
#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : strrchr(__FILE__, '\\') ? strrchr(__FILE__, '\\') + 1 : __FILE__)
/*-----------------------------------------------------------
* Exported function
*----------------------------------------------------------*/
#if LOG_ENABLE
/** Global debug mask. The value of this variable is used to filter the log messages being printed. */
extern uint32_t g_log_dbg_msk;
/** Global log level. The value of this variable is used to filter the log messages being printed. */
extern int32_t g_log_dbg_lvl;
/** Callback function used for printing log strings. */
typedef void (*log_callback_t)(uint32_t dbg_level, const char * p_filename, uint16_t line,
uint32_t timestamp, const char * format, va_list arguments);
/** Callback function for printing debug information over RTT. */
void log_callback_rtt(uint32_t dbg_level, const char * p_filename, uint16_t line,
uint32_t timestamp, const char * format, va_list arguments);
/**
* Initializes the logging module.
*
* @param[in] mask Mask specifying which modules to log information from.
* @param[in] level Maximum log level to print messages from.
* @param[in] callback Callback function for printing log strings.
*/
void log_init(uint32_t mask, uint32_t level, log_callback_t callback);
/**
* Sets the log callback function.
*
* The callback function is called to print strings from the logging module.
* An application that is interested in internal logging can set this function
* in order to print the log information in an application-specific way.
*
* @param[in] callback The callback function to use for printing log information.
*/
void log_set_callback(log_callback_t callback);
/**
* Gets a timestamp to use with the log functions.
*
* @return A timestamp to use with the log functions.
*/
uint32_t log_timestamp_get(void);
/**
* Prints log data.
* This function is used by the logging macros, but can also be called directly
* if desired.
*
* @param[in] dbg_level The debugging level to print the message as.
* @param[in] p_filename Name of the file in which the log call originated.
* @param[in] line Line number where the function was called.
* @param[in] timestamp Timestamp for when the log function was called.
* @param[in] format Format string, printf()-compatible.
*
* @see log_vprintf()
*/
void __attribute((format(printf, 5, 6))) log_printf(
uint32_t dbg_level, const char * p_filename, uint16_t line, uint32_t timestamp, const char * format, ...);
/**
* Prints log data.
* This function is used by the logging macros, but can also be called directly
* if desired.
*
* @param[in] dbg_level The debugging level to print the message as.
* @param[in] p_filename Name of the file in which the log call originated.
* @param[in] line Line number for where the log function was called.
* @param[in] timestamp Timestamp for when the log function was called.
* @param[in] format Format string, printf()-compatible.
* @param[in] arguments Arguments according to the @c format string.
*
* @see log_printf()
*/
void log_vprintf(uint32_t dbg_level, const char * p_filename, uint16_t line, uint32_t timestamp,
const char * format, va_list arguments);
/*-----------------------------------------------------------
* Exported function macro
*----------------------------------------------------------*/
/*lint -emacro(506, MIN) */ /* Suppress "Constant value Boolean */
#define MIN(a, b) ((a) < (b) ? (a) : (b))
/**
* Initializes the logging framework.
* @param[in] msk Log mask
* @param[in] level Log level
* @param[in] callback Log callback
*/
#define __LOG_INIT(msk, level, callback) log_init(msk, level, callback)
/**
* Prints a log message.
* @param[in] source Log source
* @param[in] level Log level
* @param[in] ... Arguments passed on to the callback (similar to @c printf)
*/
#define __LOG(source, level, ...) \
if ((source & g_log_dbg_msk) && level <= g_log_dbg_lvl) \
{ \
log_printf(level, __FILENAME__, __LINE__, log_timestamp_get(), __VA_ARGS__); \
}
/**
* Prints an array with a message.
* @param[in] source Log source
* @param[in] level Log level
* @param[in] msg Message string
* @param[in] array Pointer to array
* @param[in] len Length of array (in bytes)
*/
#define __LOG_XB(source, level, msg, array, array_len) \
if ((source & g_log_dbg_msk) && (level <= g_log_dbg_lvl)) \
{ \
unsigned _array_len = array_len; \
_array_len = MIN(_array_len, LOG_ARRAY_LEN_MAX); \
char array_text[LOG_ARRAY_LEN_MAX * 2 + 1]; \
for(unsigned _i = 0; _i < _array_len; ++_i) \
{ \
extern const char * g_log_hex_digits; \
uint8_t array_elem = array[_i]; \
array_text[_i * 2] = g_log_hex_digits[(array_elem >> 4) & 0xf]; \
array_text[_i * 2 + 1] = g_log_hex_digits[array_elem & 0xf]; \
} \
array_text[_array_len * 2] = 0; \
log_printf(level, __FILENAME__, __LINE__, log_timestamp_get(), "%s: %s\n", msg, array_text); \
}
#else /* NRF_MESH_LOG_ENABLE == 0*/
#define __LOG_INIT(...)
#define __LOG(...)
#define __LOG_XB(...)
#ifndef LOG_CALLBACK_DEFAULT
/** Default log callback. */
#define LOG_CALLBACK_DEFAULT NULL
#endif
#endif /* LOG_ENABLE */
/** @} */
#endif /* __LOG_ULTRA_H */
总结
以上是 LogUltra
模块:一个可以开启、关闭某一个模块的打印信息,并且可以将该模块的主次信息选择打印的 LOG 模块 的实现,希望能够帮到您。
我是 HinGwenWoong,一个有着清晰目标不停奋斗的程序猿,热爱技术,喜欢分享,码字不易,如果帮到您,请帮我在屏幕下方点赞 👍 ,您的点赞可以让技术传播得更远更广,谢谢!
- 【嵌入式实战】STM32 Bootloader 快速实现(超详细)
- 【嵌入式实战】STM32+Lwip 实现 MQTT(超详细步骤+代码注释,内含避坑提示)
- 【嵌入式实战】STM32+Lwip 实现 DHCP+HostName(超详细) : 在 DHCP 的基础上 Ping 域名的方式获取 DHCP 的 IP
- 【嵌入式实战】STM32+Lwip 实现 SNTP 网络授时(超详细)
- 【嵌入式实战】STM32+FreeRTOS+LWIP+WolfSSL 实现 HTTPS(超详细)
- 【嵌入式小技巧】STM32 实现 SEGGER RTT 打印(超详细)
授权须知
- 原创文章在推送两天后才可进行转载
- 转载文章,禁止声明原创
- 不允许直接二次转载,转载请根据原文链接联系作者
- 若无需改版,在文首清楚标注作者及来源/原文链接,并删除【原创声明】,即可直接转载。
但对于未注明转载来源/原文链接的文章,我将保留追述的权利。
作者:HinGwenWoong
一个有着清晰目标不停奋斗的程序猿,热爱技术,喜欢分享,共同进步!
CSDN: HinGwenWoong
原文链接:【嵌入式实战】LOG 输出信息让你眼花缭乱?这里一招帮你解决!
- 若需要修改文章的排版,请根据原文链接联系作者
- 再次感谢您的认可,转载请遵守如上转载须知!