杰理 SDK 文档中心
首页
首页
  • SDK 概述与快速开始

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

UI 资源工程与打包

本文档说明 AC79NN AIoT SDK 中 UI 资源工程的目录约定、资源文件格式(.sty / .res / .str / .fon)、资源打包后在 Flash/SD 卡上的存放路径(RES_PATH 体系)、运行时加载流程以及相关的配置开关,帮助开发者理解「UI 工程如何被编译打包为资源文件、又如何被固件按路径加载」的完整链路。

Purpose and Scope

本页覆盖:

  • UI 资源在文件系统中的路径规划(RES_PATH、UPGRADE_PATH、FONT_PATH 的宏定义与四种存放策略);
  • UI 资源包的文件类型与二进制格式(.sty 工程描述文件中的 ui_file_head/window_head,.str 字符串文件中的 res_head_t/res_entry_t/res_infor_t);
  • UI 运行时如何打开与解析资源(ui_load_info_table、open_resource_file()、select_strfile()/select_resfile());
  • 与打包/升级相关的配置宏(TCFG_USE_SD_ADD_UI_FILE、CONFIG_UI_FILE_SAVE_IN_RESERVED_ZONE、UI_WATCH_RES_ENABLE、UI_UPGRADE_RES_ENABLE 等)。

本页不涉及 LCD 驱动寄存器配置(见 LCD 驱动 相关页面)、AWTK 等第三方 UI 框架(见其独立页面),也不展开具体表盘业务逻辑。

Overview

在 AC79NN 这类带屏 AIoT 芯片上,UI 开发遵循「资源与代码分离」的经典设计:界面布局、位图、多语言字符串、字库等数据由上位机 UI 工程工具编译打包为独立的资源文件,固件侧只保留一套 UI 引擎(apps/common/ui/),在运行时按固定路径从文件系统(Flash 或 SD 卡)打开资源文件并解析加载。

这一设计的核心价值:

  1. 固件与 UI 解耦:更换皮肤/布局/语言只需替换资源文件,无需重新编译固件;
  2. 多项目共存:一个固件可携带多个 UI 工程(如 JL、watch、watch1…watch5),通过 ui_load_info_table 按索引切换;
  3. 资源可升级:通过 UPGRADE_PATH(RES_PATH"ui_upgrade/")支持 UI 升级界面资源的热更新;
  4. 内存可控:资源按需打开、按窗口解析,配合 br23_malloc/br23_free 统一分配,便于统计 UI 内存占用。

资源路径的最终值由 res_config.h 中的条件编译宏决定,开发者根据量产方案(资源放 SD 卡、放 Flash 常规区、还是放保留区)选择不同的宏组合。

Architecture

flowchart TD
    subgraph sg_Config["资源配置层 res_config.h"]
        RES_PATH["RES_PATH 宏"]
        UPGRADE["UPGRADE_PATH (ui_upgrade/)"]
        FONT["FONT_PATH"]
    end

    subgraph sg_Storage["存储介质"]
        SD["SD 卡 ui_res/"]
        FLASH["Flash mnt/sdfile/res/ui_res/"]
        RZONE["保留区 uipackres/ui/"]
    end

    subgraph sg_Files["UI 资源包内容"]
        STY[".sty 工程描述"]
        RES[".res 位图/控件资源"]
        STR[".str 多语言字符串"]
        FON[".fon 字库"]
    end

    subgraph sg_Runtime["UI 运行时 ui_platform.c"]
        TABLE["ui_load_info_table"]
        OPEN["open_resource_file()"]
        PARSE["window_head / ui_file_head 解析"]
        MALLOC["br23_malloc / br23_free"]
    end

    RES_PATH --> SD
    RES_PATH --> FLASH
    RES_PATH --> RZONE
    SD --> STY
    FLASH --> STY
    RZONE --> STY
    STY --> TABLE
    TABLE --> OPEN
    OPEN --> PARSE
    PARSE --> MALLOC
    UPGRADE --> STY
    FONT --> FON

架构分层说明:

  • 资源配置层(res_config.h):唯一权威地定义资源在文件系统中的挂载根路径。它根据编译期宏选择 SD 卡、Flash 常规目录或保留分区目录,并派生升级路径与字库路径。
  • 存储介质层:资源包(ui_res/ 或 uipackres/ui/ 目录)实际存放的位置,由量产烧录/打包工具预先写入。
  • UI 资源包:同一工程在打包时产出 .sty(工程描述)、.res(图片/控件数据)、.str(多语言字符串)、.fon(字库)等文件,运行时按需分别打开。
  • UI 运行时(ui_platform.c):通过 ui_load_info_table 声明可加载的 .sty 工程列表,open_resource_file() 打开文件,解析 ui_file_head/window_head 后按窗口分配内存并注册到 UI 引擎。

资源路径体系(RES_PATH)

RES_PATH 是整套资源打包与加载约定的核心宏,位于 res_config.h:

#if TCFG_USE_SD_ADD_UI_FILE
#define RES_PATH   CONFIG_ROOT_PATH"ui_res/"
#else     //USE_FLASH_ADD_UI_FILE

#if defined CONFIG_UI_FILE_SAVE_IN_RESERVED_EXPAND_ZONE
#define RES_PATH   "mnt/sdfile/EXT_RESERVED/uipackres/ui/"
#elif defined CONFIG_UI_FILE_SAVE_IN_RESERVED_ZONE
#define RES_PATH   "mnt/sdfile/app/uipackres/ui/"
#else
#define RES_PATH   "mnt/sdfile/res/ui_res/"
#endif

#endif//TCFG_USE_SD_ADD_UI_FILE

#define UPGRADE_PATH   RES_PATH"ui_upgrade/"
#define FONT_PATH RES_PATH

Source: res_config.h

设计意图与选择依据:

  • TCFG_USE_SD_ADD_UI_FILE 置 1 时,资源放在 SD 卡 CONFIG_ROOT_PATH"ui_res/" 下,适合资源量大、需要用户可替换的场景(如 TF 卡升级皮肤);
  • 资源放 Flash 时,默认落在 mnt/sdfile/res/ui_res/(普通文件系统目录);
  • 若定义 CONFIG_UI_FILE_SAVE_IN_RESERVED_ZONE,则打包资源写入 Flash 的保留分区 mnt/sdfile/app/uipackres/ui/——uipackres 即 "UI pack resources"(UI 打包资源),量产时作为独立分区镜像烧录,避免与固件升级区互相覆盖;
  • 若定义 CONFIG_UI_FILE_SAVE_IN_RESERVED_EXPAND_ZONE,则使用扩展保留区 mnt/sdfile/EXT_RESERVED/uipackres/ui/,适用于保留区容量不足、需要外扩分区的方案;
  • UPGRADE_PATH 固定为资源根下的 ui_upgrade/ 子目录,配合 UI_UPGRADE_RES_ENABLE 宏实现升级界面资源,使「升级动画/文案」也能作为资源随包更新;
  • FONT_PATH 与 RES_PATH 相同,字库文件与 UI 资源同目录存放,fontinit.c 通过包含 res_config.h 来定位字库。

UI 资源文件格式

.sty 工程描述文件

.sty 是每个 UI 工程的「入口描述文件」,由上位机工具打包生成。运行时通过 open_resource_file() 打开后,按以下两个结构体解析,定义于 ui_platform.c:

struct window_head {
    u32 offset;
    u32 len;
    u32 ptr_table_offset;
    u16 ptr_table_len;
    u16 crc_data;
    u16 crc_table;
    u16 crc_head;
};

struct ui_file_head {
    u8  res[16];
    u8 type;
    u8 window_num;
    u16 prop_len;
    u8 rotate;
    u8 rev[3];
};

Source: ui_platform.c

字段含义与设计意图:

  • ui_file_head:文件级头部。res[16] 为资源标识/校验串,type 区分资源类型,window_num 声明本工程包含的窗口数量,prop_len 为属性段长度,rotate 记录默认旋转方向,rev[3] 保留字节用于版本兼容。
  • window_head:窗口级头部。offset/len 定位该窗口数据在文件中的位置与长度;ptr_table_offset/ptr_table_len 定位窗口内控件指针表;三个 CRC 字段(crc_data、crc_table、crc_head)分别对数据段、指针表和头部做校验,保证资源文件在传输/烧录过程中未损坏——这是资源热替换场景下的关键可靠性设计。

.res 位图/控件资源与 .str 多语言字符串

.res(图片资源)与 .str(字符串资源)同样遵循「文件头 + 条目表 + 数据区」的布局。字符串文件在 lcd_simple/ui.c 中被定位读取:

res_infor_t  stringinfor;
...
fseek(file, sizeof(res_head_t) + 2 * sizeof(res_entry_t) + BMPID_SUM * sizeof(res_infor_t) + ((StringID - 1)*LANGUAGEID_SUM + LanguageMode - 1)*sizeof(res_infor_t), SEEK_SET);
fread(file, (u8 *)&stringinfor, sizeof(res_infor_t));

Source: lcd_simple/ui.c

该 fseek 偏移表达式揭示了 .str 文件的完整布局(顺序排列):

  1. res_head_t:一个文件头;
  2. 2 * sizeof(res_entry_t):两个条目表项(通常为「资源表」与「字符串表」两个 entry);
  3. BMPID_SUM * sizeof(res_infor_t):位图信息表,每个位图一条 res_infor_t;
  4. 随后通过 (StringID-1)*LANGUAGEID_SUM + LanguageMode-1 计算出「第 StringID 条字符串 × 第 LanguageMode 种语言」的线性偏移,直接 fread 出该字符串的 res_infor_t(内含偏移/长度/属性)。

这种「一次 fseek + 一次 fread」的随机访问方式,避免把整个字符串文件载入内存,符合资源常驻 Flash、按需读取的嵌入式设计原则。

运行时加载流程

ui_load_info_table:工程清单

UI 平台层用一个静态表声明「当前固件可加载哪些 UI 工程」,定义于 ui_platform.c:

struct ui_load_info ui_load_info_table[] = {
    {1, NULL, NULL},
    {2, RES_PATH"prj2.sty", NULL},//by yyj
    {-1, NULL, NULL},
};

Source: ui_platform.c

  • 每个表项包含 {id, 路径, 附加信息};-1 作为表结束哨兵;
  • 路径统一由 RES_PATH 前缀拼接,因此只要 RES_PATH 编译正确,表项无需随存放介质改动;
  • res_config.h 中被注释掉的 UI_STY_CHECK_PATH/UI_RES_CHECK_PATH/UI_STR_CHECK_PATH 展示了多工程(JL、watch、watch1…watch5)同时存在时的扩展写法:每个工程一组 .sty/.res/.str 路径,运行时按索引切换。

打开与解析序列

sequenceDiagram
    participant APP as 应用初始化
    participant PLAT as ui_platform.c
    participant FS as 文件系统
    participant UI as UI 引擎

    APP->>PLAT: 初始化 UI 平台
    PLAT->>PLAT: 遍历 ui_load_info_table
    PLAT->>FS: open(RES_PATH + "prj2.sty")
    FS-->>PLAT: FILE*
    PLAT->>FS: fread(ui_file_head)
    PLAT->>FS: fread(window_head)
    PLAT->>PLAT: 校验 CRC / 按窗口分配内存
    PLAT->>UI: 注册窗口与控件
    APP->>PLAT: select_strfile(语言索引)
    PLAT->>FS: fseek 到字符串表偏移
    FS-->>PLAT: res_infor_t 数据
    PLAT-->>APP: 字符串/位图句柄

关键函数(声明见 ui_platform.c):

  • open_resource_file():静态函数,负责按 ui_load_info_table 打开工程文件并解析头部;
  • select_strfile(u8 index):按索引切换字符串资源文件(多语言切换入口);
  • select_resfile(u8 index):按索引切换图片资源文件。

内存管理

UI 引擎的所有动态内存统一经由平台层封装,见 ui_platform.c:

void *br23_malloc(int size)
{
    void *buf;
    malloc_cnt++;
    buf = (void *)malloc(size);
#ifdef UI_BUF_CALC
    struct buffer *new = (struct buffer *)malloc(sizeof(struct buffer));
    new->buf = buf;
    new->size = size;
    list_add_tail(new, &buffer_used);
    printf("platform_malloc : 0x%x, %d\n", buf, size);
    ...
#endif
    return buf;
}

Source: ui_platform.c

设计要点:

  • 通过 malloc_cnt 统计未释放次数,可快速发现内存泄漏;
  • 定义 UI_BUF_CALC 后,每次分配/释放都会把缓冲区登记到链表并打印累计占用,用于调试 UI 内存峰值——这是资源包较大时评估 RAM 预算的标准手段;
  • 资源按窗口加载、窗口切换即释放,使多个工程的资源可以分时复用同一块内存,而不是同时常驻。

Configuration Options

UI 资源工程与打包相关的全部配置集中在 res_config.h 与工程级 app_config.h 中,以编译期宏的形式生效:

配置宏类型默认值说明
TCFG_USE_SD_ADD_UI_FILE开关宏0(未定义)置 1 时 UI 资源从 SD 卡 CONFIG_ROOT_PATH"ui_res/" 加载,否则从 Flash 加载
CONFIG_UI_FILE_SAVE_IN_RESERVED_ZONE开关宏未定义资源打包写入 Flash 保留分区 mnt/sdfile/app/uipackres/ui/
CONFIG_UI_FILE_SAVE_IN_RESERVED_EXPAND_ZONE开关宏未定义资源打包写入扩展保留区 mnt/sdfile/EXT_RESERVED/uipackres/ui/
UPGRADE_PATH派生宏RES_PATH"ui_upgrade/"UI 升级界面资源的存放目录
FONT_PATH派生宏RES_PATH字库文件存放目录(与 UI 资源同目录)
UI_UPGRADE_RES_ENABLE开关宏未定义(注释态)使能升级界面资源功能
UI_WATCH_RES_ENABLE开关宏未定义(注释态)使能表盘功能(watch face),见 lcd_ui_api.c 中的使用
UI_USED_DOUBLE_BUFFER开关宏未定义(注释态)使能双缓冲推屏,改善刷新流畅度
UI_BUF_CALC调试宏未定义使能 UI 内存分配/释放追踪打印

路径选择优先级(互斥组合)说明:当 TCFG_USE_SD_ADD_UI_FILE 未定义(即 USE_FLASH_ADD_UI_FILE)时,再按「扩展保留区 → 保留区 → 普通目录」的顺序条件编译确定 RES_PATH。选择保留区方案时,量产工具需将 uipackres/ui/ 打包为独立分区镜像,与固件区分离,从而支持 UI 资源单独升级而不触碰固件。

API Reference

以下为 UI 平台层暴露给上层/UI 引擎的关键接口(原型见 ui_platform.c):

void select_strfile(u8 index)

按索引切换当前使用的多语言字符串资源文件。

参数:

  • index(u8):字符串资源文件在工程清单中的索引(对应语言/字符串表编号)。

说明: 用于多语言切换;切换后对 select_strfile 的调用会配合 LanguageMode 重算 .str 文件中的字符串偏移。

void select_resfile(u8 index)

按索引切换当前使用的图片/控件资源文件。

参数:

  • index(u8):资源文件在工程清单中的索引。

static int open_resource_file()

按 ui_load_info_table 打开当前选中的 .sty 工程文件并解析文件头/窗口头。

返回:

  • 0 表示成功,非零表示打开或解析失败(文件不存在、头部 CRC 校验失败等)。

说明: 为静态函数,仅平台层内部调用;ui_load_info_table 中 {1, NULL, NULL} 等空路径表项用于占位或跳过加载。

void *br23_malloc(int size) / void br23_free(void *buf)

平台层统一内存分配/释放接口,供 UI 引擎所有动态对象使用。

参数:

  • size(int):申请字节数;buf(void *):待释放指针。

说明: 内部维护 malloc_cnt 计数;定义 UI_BUF_CALC 时登记 struct buffer 链表并打印每次分配/释放及累计占用,用于内存峰值与泄漏分析。

Usage Examples

示例 1:配置资源存放介质(工程配置)

在工程 app_config.h 中选择 SD 卡方案,并开启保留区打包:

#define TCFG_USE_SD_ADD_UI_FILE   1          // UI 资源放 SD 卡
// 或(Flash 方案)
// #define CONFIG_UI_FILE_SAVE_IN_RESERVED_ZONE   1   // 打包到保留分区 uipackres/ui/

Source: res_config.h

示例 2:注册/更换 UI 工程清单

在 ui_load_info_table 中追加新的 .sty 工程,实现一固件多主题:

struct ui_load_info ui_load_info_table[] = {
    {1, NULL, NULL},
    {2, RES_PATH"prj2.sty", NULL},//by yyj
    {-1, NULL, NULL},
};

Source: ui_platform.c

示例 3:运行时按偏移读取某语言的字符串

fseek 直接定位到 (StringID, LanguageMode) 对应条目,只读一条 res_infor_t:

res_infor_t  stringinfor;
...
fseek(file, sizeof(res_head_t) + 2 * sizeof(res_entry_t) + BMPID_SUM * sizeof(res_infor_t) + ((StringID - 1)*LANGUAGEID_SUM + LanguageMode - 1)*sizeof(res_infor_t), SEEK_SET);
fread(file, (u8 *)&stringinfor, sizeof(res_infor_t));

Source: lcd_simple/ui.c

Failure Modes, Edge Cases & Concurrency

资源文件缺失或路径不匹配

  • 现象:open_resource_file() 打开 RES_PATH"prj2.sty" 失败。
  • 根因:最常见是 RES_PATH 编译宏与量产烧录布局不一致——例如固件按 TCFG_USE_SD_ADD_UI_FILE 编译但资源实际烧在 Flash,或保留区方案下分区未写入 uipackres/ui/。
  • 处理:ui_load_info_table 用 {1, NULL, NULL} 空项占位、-1 结束,加载失败时引擎可跳过该工程回退到默认界面;排查时应先确认 RES_PATH 展开值与实际文件系统路径完全一致。

资源损坏与 CRC 校验

.sty 的 window_head 内置 crc_data/crc_table/crc_head 三份校验值。资源在传输、OTA、SD 卡热插拔过程中损坏时,解析层应校验失败并拒绝加载该窗口,避免脏数据进入 UI 引擎导致花屏或越界。.res/.str 文件头同样通过 res_head_t/res_entry_t 的条目表约束长度,读取越界前应做边界检查。

字符串越界与语言回退

.str 文件按「(StringID-1)*LANGUAGEID_SUM + LanguageMode-1」线性寻址,若打包时 LANGUAGEID_SUM(语言总数)与实际写入的语言数不一致,或传入非法 LanguageMode,fseek 会落在错误偏移。设计上要求打包工具与固件保持同一组 BMPID_SUM/LANGUAGEID_SUM 常量;运行时建议对 LanguageMode 做范围钳制并回退到默认语言(如 LanguageMode = 1)。

并发与中断上下文

  • UI 渲染与资源加载运行在主线程/UI 任务中,lcd_ui_api.c 在 UI_WATCH_RES_ENABLE 场景下使用 local_irq_disable() 保护关键段(见 lcd_ui_api.c),表盘唤醒/休眠切换时短暂关中断防止推屏撕裂;
  • 资源文件句柄(ui_file/ui_file1/ui_file2)为全局静态变量,多任务同时访问时需串行化,避免 fseek/fread 交错导致文件指针错乱;
  • 内存分配集中在 br23_malloc/br23_free,若 UI 任务与其它任务共享堆,需保证堆互斥(SDK 默认内存管理已加锁)。

Performance & Operational Notes

  • 按需随机读取而非整体载入:.str 字符串、.res 位图均通过 fseek + fread 定位读取,资源常驻 Flash,RAM 只保存当前窗口数据;因此资源包大小主要受限于 Flash 容量而非 RAM。
  • 内存峰值评估:开发阶段打开 UI_BUF_CALC,利用 br23_malloc 的链表登记打印(used buffer size:%d)统计各窗口切换时的内存水位,为窗口数/位图尺寸的设计提供依据。
  • 双缓冲与旋转:UI_USED_DOUBLE_BUFFER 与 ui_file_head.rotate/ui_rotate 配合决定推屏方式与方向,开启双缓冲会增加一份屏幕尺寸的 RAM 开销,需在流畅度与内存之间权衡。
  • 多工程资源分时复用:ui_load_info_table 多表项方案下,切换工程会释放旧窗口资源再加载新窗口,同一时刻仅一个工程常驻,这是多主题方案能跑在小内存 MCU 上的关键。
  • 打包与升级:UI 升级资源存放于 UPGRADE_PATH(ui_upgrade/),UI_UPGRADE_RES_ENABLE 使能后升级界面文案/动画可随升级包替换,不影响主 UI 资源。

Extension Points

  • 新增 UI 工程/主题:在 ui_load_info_table 追加 {id, RES_PATH"xxx.sty", NULL} 表项,并将 xxx.sty/.res/.str 按 RES_PATH 布局打包即可,无需改动引擎代码。
  • 多语言扩展:调整打包工具侧的 LANGUAGEID_SUM,同时保持固件侧常量一致,即可在 .str 中增加语言列。
  • 字库替换:FONT_PATH 指向资源根目录,替换/新增字库文件(fontinit.c 按 res_config.h 定位)即可实现字体升级。
  • UI 升级资源:通过 UI_UPGRADE_RES_ENABLE + UPGRADE_PATH 扩展升级流程界面;表盘功能通过 UI_WATCH_RES_ENABLE 扩展(配合 ui_show_main/ui_hide_curr_main 的页面生命周期管理)。
  • 调试扩展:UI_BUF_CALC 提供内存追踪钩子,可在此基础上扩展为按窗口统计的资源占用报表。

Related Links

  • res_config.h(资源配置头文件)
  • ui_platform.c(UI 平台层:资源打开/解析/内存管理)
  • lcd_simple/ui.c(.str 字符串资源定位读取)
  • lcd_ui_api.c(UI 显示生命周期与表盘/升级界面控制)
  • fontinit.c(字库初始化,依赖 FONT_PATH)
  • 相关目录:LCD 驱动配置与移植见 LCD 驱动页面;AWTK 等第三方 UI 框架见其独立文档页。
Prev
公共示例工程
Next
SDK 辅助工具与脚本