本文记录了在 rtthread 上移植 NimBLE 1.5.0 日志系统的过程,包括需要注意的关键点。
NimBLE 日志模块
NimBLE 供移植的日志系统都在下列文件里:
- porting/
- nimble/
- include/
- log/
- log.h # 无用文件
- log_common/
- ignore.h # 定义了 IGNORE() 宏,用于忽略宏参数
- log_common.h # 定义了一些日志帮助宏
- logcfg/
- logcfg.h # 配置 NimBLE host,mesh,default 模块的日志宏
- modlog/
- modlog.h # 基于 printf 的简易日志库
浏览一遍上述文件后,可以知道最重要的就只有两个文件:
logcfg.h:协议栈日志配置接口。modlog.h:协议栈自带的基于 printf 的简易日志库。
查看 logcfg.h 文件:
#include "modlog/modlog.h"
#include "log_common/log_common.h"
#define BLE_HS_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define BLE_HS_LOG_INFO(...) MODLOG_INFO(4, __VA_ARGS__)
#define BLE_HS_LOG_WARN(...) MODLOG_WARN(4, __VA_ARGS__)
#define BLE_HS_LOG_ERROR(...) MODLOG_ERROR(4, __VA_ARGS__)
#define BLE_HS_LOG_CRITICAL(...) MODLOG_CRITICAL(4, __VA_ARGS__)
#define BLE_HS_LOG_DISABLED(...) MODLOG_DISABLED(4, __VA_ARGS__)
#define DFLT_LOG_DEBUG(...) IGNORE(__VA_ARGS__)
#define DFLT_LOG_INFO(...) MODLOG_INFO(0, __VA_ARGS__)
#define DFLT_LOG_WARN(...) MODLOG_WARN(0, __VA_ARGS__)
#define DFLT_LOG_ERROR(...) MODLOG_ERROR(0, __VA_ARGS__)
#define DFLT_LOG_CRITICAL(...) MODLOG_CRITICAL(0, __VA_ARGS__)
#define DFLT_LOG_DISABLED(...) MODLOG_DISABLED(0, __VA_ARGS__)
该文件内部默认使用协议栈自带的 modlog 日志库,并且提供了 BLE_HS_LOG_*() 和 DFLT_LOG_*(),一个用于 Host 协议栈日志,另一个用于默认模块日志。
在 nimble/host/include/ble_hs_log.h 文件里包含了 Host 协议栈的日志接口,简化了上述接口:
#include "modlog/modlog.h"
#include "log/log.h"
/* Only include the logcfg header if this version of newt can generate it. */
#if MYNEWT_VAL(NEWT_FEATURE_LOGCFG)
#include "logcfg/logcfg.h"
#endif
#define BLE_HS_LOG(lvl, ...) \
BLE_HS_LOG_ ## lvl(__VA_ARGS__)
这样协议栈内部的日志才能看懂:BLE_HS_LOG(INFO, "duration=forever");
并且只有在 MYNEWT_VAL(NEWT_FEATURE_LOGCFG) 宏为 1 时才允许发送日志,默认为 1 。
日志模块移植
如果仅仅想使用协议栈自带的日志功能,将 MYNEWT_VAL(NEWT_FEATURE_LOGCFG) 宏配置为 1,并且定义日志级别 MYNEWT_VAL(LOG_LEVEL) 即可,该日志是静态编译生效的。在 modlog.h 文件里定义了相关条件编译宏。
#if MYNEWT_VAL(LOG_LEVEL) <= LOG_LEVEL_DEBUG
#define MODLOG_DEBUG(ml_mod_, ml_msg_, ...) \
printf((ml_msg_), ##__VA_ARGS__)
#else
#define MODLOG_DEBUG(ml_mod_, ...) IGNORE(__VA_ARGS__)
#endif
若是想对接其他的日志库,以 rtthread 的 rtdbg 日志模块为例,至少需要将 BLE_HS_LOG_*() 和 MODLOG_DFLT_*() 这两个对接。
在 porting/npl/rtthread/include/ 目录下创建 logcfg/logcfg.h 文件,并填充日志模块对接内容。
#define DBG_TAG "nimble"
#define DBG_LVL DBG_INFO
#include "rtdbg.h"
#define BLE_HS_LOG_DEBUG(...) LOG_D(__VA_ARGS__)
#define BLE_HS_LOG_INFO(...) LOG_I(__VA_ARGS__)
#define BLE_HS_LOG_WARN(...) LOG_W(__VA_ARGS__)
#define BLE_HS_LOG_ERROR(...) LOG_E(__VA_ARGS__)
#define BLE_HS_LOG_CRITICAL(...) LOG_E(__VA_ARGS__)
#define BLE_HS_LOG_DISABLED(...) IGNORE(__VA_ARGS__)
注意:此时编译系统内有两个 logcfg/logcfg.h 头文件,而 nimble/host/include/ble_hs_log.h 文件里仅仅 #include "logcfg/logcfg.h",怎么确定它包含的是哪个头文件呢?
在编译构建脚本里,我们在导入头文件时需要将移植目录头文件路径 porting/npl/rtthread/include/ 放在系统自带目录之前 /porting/nimble/include 。
path = [
cwd + '/porting/npl/rtthread/include',
cwd + '/porting/nimble/include'
]
完整的移植信息参考:https://github.com/Jackistang/nimble/commit/f03bde795fc05489da007b714070154d554c482e