OpenHarmony海思WS63星闪平台:EasyLogger 移植到海思 WS63 平台完整指南

文章目录

    • 前言
    • [1. WS63 平台与典型软件栈](#1. WS63 平台与典型软件栈)
    • [2. EasyLogger 简介](#2. EasyLogger 简介)
      • [2.1 项目背景与许可](#2.1 项目背景与许可)
      • [2.2 架构分层(理解移植要改哪里)](#2.2 架构分层(理解移植要改哪里))
    • [3. 本仓库目录与编译单元](#3. 本仓库目录与编译单元)
    • [4. WS63 移植层实现要点(`elog_port.c`)](#4. WS63 移植层实现要点(elog_port.c))
      • [4.1 为何使用 CMSIS-RTOS2](#4.1 为何使用 CMSIS-RTOS2)
      • [4.2 `printf` 与 UART](#4.2 printf 与 UART)
      • [4.3 时间戳与内核 Tick](#4.3 时间戳与内核 Tick)
    • [5. 配置说明(`elog_cfg.h`)](#5. 配置说明(elog_cfg.h))
      • [5.1 输出总开关与静态级别](#5.1 输出总开关与静态级别)
      • [5.2 缓冲区](#5.2 缓冲区)
      • [5.3 缓冲模式(`elog_buf`)](#5.3 缓冲模式(elog_buf))
      • [5.4 颜色与格式](#5.4 颜色与格式)
      • [5.5 不要在本平台打开的宏](#5.5 不要在本平台打开的宏)
    • [6. 编译系统集成](#6. 编译系统集成)
      • [6.1 CMake(本仓库已集成示例)](#6.1 CMake(本仓库已集成示例))
      • [6.2 GN(OpenHarmony 风格)](#6.2 GN(OpenHarmony 风格))
    • [7. 初始化与运行期 API](#7. 初始化与运行期 API)
      • [7.1 推荐启动顺序](#7.1 推荐启动顺序)
      • [7.2 常用输出方式](#7.2 常用输出方式)
      • [7.3 过滤与格式(运行期)](#7.3 过滤与格式(运行期))
    • [8. RAM、线程与实时性建议](#8. RAM、线程与实时性建议)
    • [9. 可选插件:Flash / 文件后端](#9. 可选插件:Flash / 文件后端)
    • [10. 常见问题排查](#10. 常见问题排查)
    • [11. 参考与延伸](#11. 参考与延伸)
    • 总结

前言

海思 WS63 一类 Wi-Fi / 星闪 SoC 上跑应用时,调试与现场排障高度依赖 串口日志 :既要能在多线程环境下 安全打印 ,又希望 尽量少占 RAM 、不把 UART 写操作拖慢业务线程。EasyLogger 是嵌入式领域常用的轻量级日志库,通过 可裁剪的配置异步输出 能较好平衡这些需求。

本文面向在本仓库(xiaohong + WS63 SDK)或同类 OpenHarmony / LiteOS + CMSIS-RTOS2 工程中的集成者,说明:

  • EasyLogger 是什么、适合什么场景
  • 如何在本工程形态下完成移植与编译集成
  • elog_cfg.helog_port.c 在 WS63 上的注意点
  • 初始化顺序、常用 API、RAM/线程/UART 与常见问题

文中路径以本仓库为准:src/easylogger/。若你使用其他目录,请自行替换。


1. WS63 平台与典型软件栈

WS63 为海思面向 IoT 连接场景的芯片平台,常见配套包括:

  • 实时内核:LiteOS-M / 兼容层;
  • RTOS API :多通过 CMSIS-RTOS2cmsis_os2.h)封装信号量、线程等;
  • 日志出口 :调试阶段多为 UART + printf 重定向,或 SDK 提供的打印接口。

本仓库的 BUILD.gn 通过 ws63_sdk.gni 引入 SDK 头文件与驱动;板级示例为 xiaohong_ws63_v1(宏 BOARD_XH_WS63_V1)。EasyLogger 的移植层必须与当前工程实际使用的 RTOS API 一致 ------本工程采用的是 CMSIS-RTOS2 ,而不是 POSIX pthread


2. EasyLogger 简介

2.1 项目背景与许可

EasyLogger (简称 elog )由 Armink 维护,源码采用 MIT 许可,仓库与文档可在 GitHub / Gitee 检索 EasyLogger 获取原版说明。其核心目标是在 资源受限 MCU 上提供:

  • 分级日志(Assert / Error / Warn / Info / Debug / Verbose);
  • 按标签(tag)、关键字、级别过滤
  • 可选颜色(ANSI 转义序列,终端支持时便于区分级别);
  • 可选异步输出(业务线程只写缓冲,专用线程或回调做 UART 输出);
  • 可选缓冲输出(合并多次写入,减少碎片输出)。

本仓库内置版本在 elog.h 中标记为 ELOG_SW_VERSION "2.2.99"(与上游版本号可能随合并略有差异,以头文件为准)。

github地址https://github.com/armink/EasyLogger

2.2 架构分层(理解移植要改哪里)

层次 作用 WS63 上谁实现
核心 elog.c 格式化、过滤、调用输出链路 一般不改
工具 elog_utils.c 字符串与内存辅助 一般不改
异步 elog_async.c 环形缓冲、异步策略 一般不改(通过宏选 pthread 或自定义 notice)
缓冲 elog_buf.c 缓冲刷新策略 一般不改
移植层 elog_port.c 锁、输出、时间、线程名、异步线程 必须按平台实现

所有与板级相关的行为都集中在 elog_port.c (以及可选插件的 *_port.c)。


3. 本仓库目录与编译单元

建议保持如下布局(与当前工程一致):

text 复制代码
src/easylogger/
├── inc/
│   ├── elog.h          # 对外 API 与 log_x 宏
│   └── elog_cfg.h      # 功能开关与缓冲区尺寸(移植时最常改)
├── port/
│   └── elog_port.c     # WS63 / CMSIS-RTOS2 移植实现
├── src/
│   ├── elog.c
│   ├── elog_utils.c
│   ├── elog_async.c
│   └── elog_buf.c
└── plugins/            # 可选:Flash / 文件后端(默认未编入本工程 CMake)
    ├── flash/
    └── file/

建议编入的 C 文件 (与 CMakeLists.txt 中一致):

  • elog_port.c
  • elog.c
  • elog_utils.c
  • elog_buf.c
  • elog_async.c

头文件搜索路径需包含:src/easylogger/inc

说明 :当前仓库的 BUILD.gn 静态库 xiaohong 未列出上述 EasyLogger 源文件 ;若你仅在 GN 构建 下编译,需要在 sources 中自行追加同等列表,并保证能包含 cmsis_os2.hstdio.hprintf)。


4. WS63 移植层实现要点(elog_port.c

本工程 elog_port.c 已实现下列 移植接口(函数名由 EasyLogger 约定,不可随意改名):

接口 职责 本工程实现摘要
elog_port_init 初始化锁、异步所需信号量与线程 osSemaphoreNew;异步模式下 osThreadNew(async_output, ...)
elog_port_deinit 释放信号量 释放 output_lock / output_notice未终止异步线程(若需完整 deinit 可自行扩展)
elog_port_output 将已格式化的日志写出 printf("%.*s", (int)size, log)
elog_port_output_lock / unlock 多线程互斥 二值信号量 osSemaphoreAcquire / Release
elog_port_get_time 时间戳字符串 osKernelGetTickCount() 换算为 秒.毫秒 形式
elog_port_get_p_info 进程信息 固定返回 "app"
elog_port_get_t_info 线程信息 osThreadGetName 或回退 t<id>
elog_async_output_notice 通知异步输出线程取日志 osSemaphoreRelease(output_notice)(仅 ELOG_ASYNC_OUTPUT_ENABLE 时)

4.1 为何使用 CMSIS-RTOS2

WS63 SDK 工程通常已链接 CMSIS-RTOS2 适配层,与 LiteOS 线程模型一致。EasyLogger 官方示例里异步模式常见 POSIX pthreadELOG_ASYNC_OUTPUT_USING_PTHREAD);在 WS63 上 不要打开该宏,而应像本工程一样:

  • elog_port.c 内实现 elog_async_output_notice
  • 使用 osThreadNewasync_output 循环,从 elog_async_get_line_log / elog_async_get_log 取数据再 printf

这样避免引入 pthreadsemaphore.h 等与当前 SDK 不完全一致的依赖。

4.2 printf 与 UART

elog_port_output 使用 printf 。请确保在 WS63 工程中 printf 已重定向到所用调试 UART (例如通过 SDK 的 consoleuart 适配)。若 printf 未初始化或阻塞时间过长,会表现为 日志卡顿或早期启动无输出

4.3 时间戳与内核 Tick

elog_port_get_time 中当前实现假设 Tick 周期为 1 msticks/1000 为秒)。若你的 osKernelGetTickFreq() 与 1000 Hz 不一致,应改为按 实际 Tick 频率 换算,否则时间戳会偏差。


5. 配置说明(elog_cfg.h

以下为 本仓库当前配置 的语义说明(具体数值以文件为准,移植时可按 RAM 预算调整)。

5.1 输出总开关与静态级别

  • ELOG_OUTPUT_ENABLE :关闭后所有 elog_* / log_* 宏为空操作。
  • ELOG_OUTPUT_LVL :编译期静态裁剪,高于该级别的宏不生成代码(例如设为 ELOG_LVL_INFO 则 Debug/Verbose 宏为空)。

5.2 缓冲区

  • ELOG_LINE_BUF_SIZE :单行上限(含前缀);本工程可设为 128 省 RAM,超长截断。开目录/颜色时前缀易占满,可关 ELOG_COLOR_ENABLEELOG_FMT_USING_DIR 或加大本值。
  • ELOG_ASYNC_OUTPUT_ENABLE:启用异步环形缓冲与后台输出。
  • ELOG_ASYNC_OUTPUT_BUF_SIZE :异步环缓大小;本工程由 ELOG_ASYNC_RING_LINE_SLOTS (默认 3 )× ELOG_LINE_BUF_SIZE 得出,RAM 极紧时槽位过小会在日志突发时更易丢尾。
  • ELOG_ASYNC_LINE_OUTPUT :按行从环缓取出,便于一行一行 printf
  • ELOG_ASYNC_OUTPUT_LVL :与 elog_async.clevel >= OUTPUT_LVL 走异步 的逻辑配合使用(级别数值越小表示越"严重":Assert 为 0,Verbose 为 5)。设为 ELOG_LVL_ASSERT 时,所有级别 均满足 >= 0,一般会 全部走异步 ;若希望低级别同步、高级别异步,可改为例如 ELOG_LVL_INFO(需对照业务理解同步/异步划分)。

5.3 缓冲模式(elog_buf

  • ELOG_BUF_OUTPUT_ENABLEELOG_BUF_OUTPUT_BUF_SIZE:在异步之外再叠一层缓冲,减少零碎写;RAM 紧张时可评估是否关闭。

5.4 颜色与格式

  • ELOG_COLOR_ENABLE:ANSI 颜色;部分串口终端支持,纯 UART 工具可能显示转义字符,可按需关闭。
  • ELOG_FMT_USING_DIR / FUNC / LINE:控制是否输出文件名、函数名、行号(会增大日志体积与格式化开销)。

5.5 不要在本平台打开的宏

  • ELOG_ASYNC_OUTPUT_USING_PTHREAD :应保持注释;WS63 本工程使用 CMSIS 线程 + elog_async_output_notice 方案。

6. 编译系统集成

6.1 CMake(本仓库已集成示例)

在父级 CMakeLists.txt 中已包含类似片段(路径按仓库实际为准):

  • PRIVATE_SOURCES 增加:elog_port.celog.celog_utils.celog_buf.celog_async.c
  • include 增加:src/easylogger/inc

6.2 GN(OpenHarmony 风格)

若目标产物通过 BUILD.gn 构建:

  1. static_library("xiaohong")(或你的模块名)的 sources加入与 CMake 相同的 5 个 .c 文件
  2. include_dirs 中加入 src/easylogger/inc(或 //vendor/.../xiaohong/src/easylogger/inc 等 GN 绝对路径写法);
  3. 确认 cmsis_os2.h 所在路径已被该模块引用(本仓库 BUILD.gn 已包含 kernel/osal 等目录时可与现有模块对齐)。

7. 初始化与运行期 API

7.1 推荐启动顺序

内核与线程环境已就绪UART/printf 可用 之后调用:

c 复制代码
#include "elog.h"

void app_log_init(void)
{
    if (elog_init() != ELOG_NO_ERR) {
        /* 处理错误:信号量/线程创建失败等 */
        return;
    }
    elog_start();   /* 打开输出,启用 async/buf 等 */
}
  • elog_init() :内部调用 elog_port_init()elog_async_init(),并设置默认过滤与格式。
  • elog_start() :使能输出及异步/缓冲模块(与 elog_cfg.h 宏相关)。

结束或重启前可调用 elog_stop()elog_deinit()(注意异步线程与资源释放策略,见下文「常见问题」)。

7.2 常用输出方式

方式 A:带 tag 的宏(推荐)

c 复制代码
#define LOG_TAG "wifi"
#define LOG_LVL ELOG_LVL_INFO
#include "elog.h"

void foo(void)
{
    log_i("connected, rssi=%d", rssi);
    log_e("assoc failed, code=%u", code);
}

方式 B:显式 tag

c 复制代码
elog_i("net", "ip=" IPSTR, IP2STR(&ip));

原始输出(不经完整格式前缀时可用)

c 复制代码
elog_raw_output("boot stage %d\r\n", stage);

十六进制 dump

c 复制代码
elog_hexdump("buf", 16, data, len);

7.3 过滤与格式(运行期)

c 复制代码
elog_set_filter_lvl(ELOG_LVL_WARN);           /* 全局级别 */
elog_set_filter_tag("noisy_mod");             /* 只输出某 tag */
elog_set_filter_tag_lvl("spi", ELOG_LVL_INFO); /* 按 tag 设级别 */
elog_set_fmt(ELOG_LVL_INFO, ELOG_FMT_LVL | ELOG_FMT_TAG | ELOG_FMT_TIME);

8. RAM、线程与实时性建议

项目 说明
异步线程栈 ELOG_PORT_ASYNC_STACK_SIZE (默认 768 );poll_get_buf 为 static。栈不够再加大。
环缓大小 ELOG_ASYNC_OUTPUT_BUF_SIZE 过小易丢日志或阻塞格式化路径,过大占 RAM;WS63 小 RAM 场景建议实测峰值打印速率。
锁与优先级 输出互斥使用信号量;异步线程优先级为 osPriorityBelowNormal,避免抢占关键实时任务,但若日志洪峰仍可能占用 CPU,需配合 ELOG_OUTPUT_LVL 与过滤。
启动早期 osKernel 未就绪时调用 osKernelGetTickCount / 创建线程可能失败;应将 elog_init 放在 RTOS 已启动之后 的应用入口。

9. 可选插件:Flash / 文件后端

仓库 plugins/flashplugins/file 提供 将日志写入 Flash 或文件系统 的扩展,需额外:

  • 编译对应 elog_flash.c / elog_file.c 及各自 *_port.c
  • elog_flash_cfg.h / elog_file_cfg.h 中配置分区或路径;
  • 在业务中调用插件初始化与 flush 策略。

默认 CMake 列出的 5 个文件不包含插件 ;若 WS63 上已使用 LittleFS,可在此基础上评估 文件日志 是否与现有 FS 线程安全策略一致。


10. 常见问题排查

  1. 编译找不到 cmsis_os2.h

    检查 GN/CMake 的 include_dirs 是否包含 OSAL / CMSIS-RTOS2 头路径。

  2. 无串口输出

    确认 printf 重定向、UART 初始化顺序早于 elog_start,以及线波特率与 PC 终端一致。

  3. 异步模式无输出

    确认 elog_port_initosThreadNew 成功 ,且 elog_async_output_noticeelog_async.c 中被调用(ELOG_ASYNC_OUTPUT_ENABLE 打开)。

  4. 颜色乱码

    关闭 ELOG_COLOR_ENABLE,或换支持 ANSI 的终端。

  5. 时间戳不准

    osKernelGetTickFreq() 修正 elog_port_get_time 的换算。

  6. elog_port_deinit 与异步线程

    已在 elog_port_deinitosThreadTerminate(async_thread_id) 后再删除信号量;elog_deinit 时请先 elog_stop,避免业务线程与析构竞态。


11. 参考与延伸

  • 上游 EasyLogger 官方文档与示例(检索 armink EasyLogger)。
  • 本仓库 RTOS 相关BUILD.gnws63_sdk_pathkernel/osal 等 include,便于对齐与你 SDK 版本一致的头文件。
  • 同仓库内 另一套日志方案src/ulog/ 及《ulog 日志库移植到海思 WS63 平台》类文档,可按项目规范 二选一或分层使用(避免混用两套宏导致风格分裂)。

总结

EasyLogger 在 WS63 上的移植核心是:用 CMSIS-RTOS2 实现 elog_port.c 的锁、时间与异步通知线程 ,保证与 LiteOS 线程模型一致;通过 elog_cfg.h 在 RAM 与实时性之间做裁剪依赖已就绪的 printf/UART 作为最终输出 。本仓库已提供 可直接参考的 elog_port.c 与 CMake 集成列表 ;若使用 GN 构建,只需将相同源文件与头路径补进模块即可。

按本文完成集成后,建议在 多线程压力场景 下做一次 日志洪峰测试 ,根据是否丢日志、栈是否溢出,微调 ELOG_ASYNC_OUTPUT_BUF_SIZE、异步栈大小与输出级别 ,使 WS63 小内存环境下的日志既 可用可控

相关推荐
国医中兴4 小时前
ClickHouse监控与运维策略:从告警到故障处理
flutter·harmonyos·鸿蒙·openharmony
国医中兴4 小时前
云原生存储的实践与挑战:从容器到 Kubernetes
flutter·harmonyos·鸿蒙·openharmony
国医中兴5 小时前
ClickHouse 生态系统的深度解析:从核心到周边
flutter·harmonyos·鸿蒙·openharmony
国医中兴5 小时前
ClickHouse 在高并发写入场景下的性能优化实践
flutter·harmonyos·鸿蒙·openharmony
研究点啥好呢5 小时前
3月26日Github热榜推荐 | AI代理工具链专栏
人工智能·驱动开发·python·ai
路溪非溪15 小时前
Linux下蓝牙框架的数据流
linux·arm开发·驱动开发
钛态16 小时前
Flutter for OpenHarmony:mockito 单元测试的替身演员,轻松模拟复杂依赖(测试驱动开发必备) 深度解析与鸿蒙适配指南
服务器·驱动开发·安全·flutter·华为·单元测试·harmonyos
国医中兴1 天前
ClickHouse的数据模型设计:从理论到实践
flutter·harmonyos·鸿蒙·openharmony
特立独行的猫a1 天前
OpenHarmony海思WS63星闪平台:LVGL UI框架底层显示驱动移植指南
ui·lvgl·移植·openharmony·驱动·ws63