diff --git a/example/stub_main.c b/example/stub_main.c index b6fa831b..81ac6cf3 100644 --- a/example/stub_main.c +++ b/example/stub_main.c @@ -155,11 +155,13 @@ static __attribute__((unused)) int handle_test1(va_list ap) STUB_LOG("stub command test:%c\n", 'A'); STUB_LOG("stub command test:%l\n", 10); // not supported - STUB_LOGE("stub command test\n"); - STUB_LOGW("stub command test\n"); - STUB_LOGI("stub command test\n"); - STUB_LOGD("stub command test\n"); - STUB_LOGV("stub command test\n"); + STUB_LOGE("This is an error message\n"); + STUB_LOGW("This is a warning message\n"); + STUB_LOGI("This is an info message\n"); + + stub_lib_log_set_level(STUB_LOG_LEVEL_V); + STUB_LOGD("This is a debug message\n"); + STUB_LOGV("This is a verbose message\n"); STUB_LOG_TRACE(); STUB_LOG_TRACEF("foo:%u\n", 0x2A); @@ -230,7 +232,7 @@ int stub_main(int cmd, ...) va_start(ap, cmd); - STUB_LOG_INIT(); + STUB_LOG_INIT(STUB_LIB_LOG_LEVEL); STUB_LOGI("Command: 0x%x\n", cmd); diff --git a/include/esp-stub-lib/log.h b/include/esp-stub-lib/log.h index de3dbc5c..e4e4b760 100644 --- a/include/esp-stub-lib/log.h +++ b/include/esp-stub-lib/log.h @@ -6,26 +6,71 @@ #pragma once +typedef enum { + STUB_LOG_LEVEL_NONE = 0, + STUB_LOG_LEVEL_E = 1, + STUB_LOG_LEVEL_W = 2, + STUB_LOG_LEVEL_I = 3, + STUB_LOG_LEVEL_D = 4, + STUB_LOG_LEVEL_T = 5, + STUB_LOG_LEVEL_TRACE = STUB_LOG_LEVEL_T, + STUB_LOG_LEVEL_V = 6, +} stub_lib_log_level_t; + +#if !defined(STUB_LIB_LOG_LEVEL) +#define STUB_LIB_LOG_LEVEL STUB_LOG_LEVEL_I +#endif + #if defined(STUB_LOG_ENABLED) #ifdef __cplusplus extern "C" { #endif // __cplusplus -void stub_lib_log_init(); +/** + * @brief Initialize logging backend and set the initial log level. + * + * @param level Initial log level. + */ +void stub_lib_log_init(stub_lib_log_level_t level); + +/** + * @brief Set the current runtime log level. + * + * @param level New log level. + */ +void stub_lib_log_set_level(stub_lib_log_level_t level); + +/** + * @brief Check whether a log level is currently enabled. + * + * @param level Log level to check. + * @return Non-zero if enabled, zero otherwise. + */ +int stub_lib_log_level_enabled(stub_lib_log_level_t level); + +/** + * @brief Print a formatted log message. + * + * @param fmt Format string. + * + * @note Supported format specifiers are: `%s`, `%d`, `%u`, `%x`, `%X`, `%c`. + * Other specifiers are not supported. + */ void stub_lib_log_printf(const char *fmt, ...); #ifdef __cplusplus } #endif // __cplusplus -#define STUB_LOG_INIT() stub_lib_log_init() -#define STUB_LOG(fmt, ...) stub_lib_log_printf(fmt, ##__VA_ARGS__) +#define STUB_LOG_INIT(level) stub_lib_log_init(level) +#define STUB_LOG(fmt, ...) stub_lib_log_printf(fmt, ##__VA_ARGS__) #else // defined(STUB_LOG_ENABLED) -#define STUB_LOG_INIT() \ +#define STUB_LOG_INIT(level) \ do { \ + (void)(level); \ } while (0) #define STUB_LOG(fmt, ...) \ do { \ @@ -33,12 +78,25 @@ void stub_lib_log_printf(const char *fmt, ...); #endif // defined(STUB_LOG_ENABLED) -#define STUB_LOGE(fmt, ...) STUB_LOG("STUB_E: " fmt, ##__VA_ARGS__) -#define STUB_LOGW(fmt, ...) STUB_LOG("STUB_W: " fmt, ##__VA_ARGS__) -#define STUB_LOGI(fmt, ...) STUB_LOG("STUB_I: " fmt, ##__VA_ARGS__) -#define STUB_LOGD(fmt, ...) STUB_LOG("STUB_D: " fmt, ##__VA_ARGS__) -#define STUB_LOGV(fmt, ...) STUB_LOG("STUB_V: " fmt, ##__VA_ARGS__) +#if defined(STUB_LOG_ENABLED) +#define STUB_LOG_AT_LEVEL(level, fmt, ...) \ + do { \ + if (stub_lib_log_level_enabled(level)) { \ + STUB_LOG(fmt, ##__VA_ARGS__); \ + } \ + } while (0) +#else +#define STUB_LOG_AT_LEVEL(level, fmt, ...) \ + do { \ + } while (0) +#endif + +#define STUB_LOGE(fmt, ...) STUB_LOG_AT_LEVEL(STUB_LOG_LEVEL_E, "STUB_E: " fmt, ##__VA_ARGS__) +#define STUB_LOGW(fmt, ...) STUB_LOG_AT_LEVEL(STUB_LOG_LEVEL_W, "STUB_W: " fmt, ##__VA_ARGS__) +#define STUB_LOGI(fmt, ...) STUB_LOG_AT_LEVEL(STUB_LOG_LEVEL_I, "STUB_I: " fmt, ##__VA_ARGS__) +#define STUB_LOGD(fmt, ...) STUB_LOG_AT_LEVEL(STUB_LOG_LEVEL_D, "STUB_D: " fmt, ##__VA_ARGS__) +#define STUB_LOGV(fmt, ...) STUB_LOG_AT_LEVEL(STUB_LOG_LEVEL_V, "STUB_V: " fmt, ##__VA_ARGS__) // trace only function name -#define STUB_LOG_TRACE() STUB_LOG("STUB_T: %s()\n", __func__) +#define STUB_LOG_TRACE() STUB_LOG_AT_LEVEL(STUB_LOG_LEVEL_T, "STUB_T: %s()\n", __func__) // trace with format -#define STUB_LOG_TRACEF(fmt, ...) STUB_LOG("STUB_T: %s(): " fmt, __func__, ##__VA_ARGS__) +#define STUB_LOG_TRACEF(fmt, ...) STUB_LOG_AT_LEVEL(STUB_LOG_LEVEL_T, "STUB_T: %s(): " fmt, __func__, ##__VA_ARGS__) diff --git a/src/log_buf.c b/src/log_buf.c index a93adc8b..91a66493 100644 --- a/src/log_buf.c +++ b/src/log_buf.c @@ -26,7 +26,7 @@ static void stub_lib_log_buf_write_char(char c) g_stub_lib_log_buf.count = (g_stub_lib_log_buf.count + 1) % STUB_LIB_LOG_BUF_SIZE; } -void stub_lib_log_init() +void stub_lib_log_backend_init(void) { ets_install_putc1(stub_lib_log_buf_write_char); ets_install_putc2(NULL); diff --git a/src/log_common.c b/src/log_common.c index b467be1e..baa39cc4 100644 --- a/src/log_common.c +++ b/src/log_common.c @@ -5,7 +5,41 @@ */ #include +#include + extern void ets_printf(const char *fmt, ...); +extern void stub_lib_log_backend_init(void); + +static stub_lib_log_level_t g_stub_lib_log_level = STUB_LIB_LOG_LEVEL; + +static stub_lib_log_level_t stub_lib_log_level_normalize(stub_lib_log_level_t level) +{ + if (level < STUB_LOG_LEVEL_NONE) { + return STUB_LOG_LEVEL_NONE; + } + + if (level > STUB_LOG_LEVEL_V) { + return STUB_LOG_LEVEL_V; + } + + return level; +} + +void stub_lib_log_set_level(stub_lib_log_level_t level) +{ + g_stub_lib_log_level = stub_lib_log_level_normalize(level); +} + +int stub_lib_log_level_enabled(stub_lib_log_level_t level) +{ + return g_stub_lib_log_level >= level; +} + +void stub_lib_log_init(stub_lib_log_level_t level) +{ + stub_lib_log_set_level(level); + stub_lib_log_backend_init(); +} // This function is designed to avoid implementing vprintf() to reduce code size. // It only supports a subset of format specifiers: %s, %d, %u, %x, %X, %c. diff --git a/src/log_uart.c b/src/log_uart.c index d0ad8d00..01ce10b1 100644 --- a/src/log_uart.c +++ b/src/log_uart.c @@ -12,7 +12,7 @@ extern void ets_install_putc1(void (*p)(char c)); extern void ets_install_putc2(void (*p)(char c)); extern void ets_install_uart_printf(void); -void stub_lib_log_init() +void stub_lib_log_backend_init(void) { stub_target_uart_init(0); ets_install_putc1(NULL);