Files
P4-USB-transfer/表情包持久化存储方案.md
zhengxinandCursor 851e347cf5 初始提交卡包 USB 工程
纳入固件源码、屏幕组件、nand_xfer 工具和文档。忽略本机构建产物、sdkconfig,以及含本机路径的依赖锁。

Co-authored-by: Cursor <[email protected]>
2026-10-13 21:54:50 +08:00

8.6 KiB
Raw Permalink Blame History

表情包持久化存储方案

一、需求分析

需要在掉电不丢失的存储中记录:

  1. 已使用的表情包系列:当前正在使用的表情包ID
  2. 已下载的表情包系列:所有已下载并安装的表情包ID列表

二、技术方案

2.1 存储介质选择

  • 使用ESP-IDF的NVS(Non-Volatile Storage)
  • 理由:
    • 项目已有NVS基础设施(main/NVS_FLASH/nvs_flash.c)
    • NVS支持掉电不丢失
    • 已有命名空间 emoji_config
    • 操作简单,性能可靠

2.2 数据结构设计

2.2.1 已使用的表情包

  • 存储方式:单个字符(char)
  • NVS键名:"using_pack"
  • 数据类型:NVS_TYPE_STR(存储单个字符字符串,如 "0", "A", "B", "C", "D")
  • 默认值:"0"(表示默认表情包)
  • 命名规则:支持字符命名,如 0, A, B, C, D 等

2.2.2 已下载的表情包列表

  • 存储方式:JSON字符串数组(推荐)或逗号分隔字符串
  • NVS键名:"downloaded_packs"
  • 数据类型:NVS_TYPE_STR(blob方式存储字符串)
  • 格式示例:
    • JSON格式:["0", "A", "B", "C", "D"] (推荐,易于解析和扩展)
    • 或简单格式:"0,A,B,C,D" (节省空间)
  • 命名规则:支持字符命名,如 0, A, B, C, D 等

2.3 功能接口设计

2.3.1 初始化接口

/**
 * @brief 从NVS加载表情包信息到内存
 * @return esp_err_t ESP_OK表示成功
 */
esp_err_t emoji_storage_load(void);

2.3.2 保存已使用的表情包

/**
 * @brief 保存当前使用的表情包ID到NVS
 * @param pack_id 表情包ID(字符,如'0', 'A', 'B', 'C', 'D'等)
 * @return esp_err_t ESP_OK表示成功
 */
esp_err_t emoji_storage_save_using_pack(char pack_id);

2.3.3 添加已下载的表情包

/**
 * @brief 添加已下载的表情包ID到列表并保存到NVS
 * @param pack_id 表情包ID(字符,如'0', 'A', 'B', 'C', 'D'等)
 * @return esp_err_t ESP_OK表示成功
 */
esp_err_t emoji_storage_add_downloaded_pack(char pack_id);

2.3.4 获取已使用的表情包

/**
 * @brief 获取当前使用的表情包ID
 * @return char 表情包ID,'0'表示默认表情包
 */
char emoji_storage_get_using_pack(void);

2.3.5 获取已下载的表情包列表

/**
 * @brief 获取已下载的表情包列表
 * @param packs 输出缓冲区,存储表情包ID数组(字符串形式,如"0,A,B")
 * @param max_len 缓冲区最大长度
 * @return int 实际返回的表情包数量,-1表示失败
 */
int emoji_storage_get_downloaded_packs(char *packs, int max_len);

2.3.6 检查表情包是否已下载

/**
 * @brief 检查指定表情包是否已下载
 * @param pack_id 表情包ID(字符)
 * @return true 已下载,false 未下载
 */
bool emoji_storage_is_downloaded(char pack_id);

2.3.7 删除已下载的表情包

/**
 * @brief 从列表中删除指定的表情包(可选功能)
 * @param pack_id 表情包ID(字符)
 * @return esp_err_t ESP_OK表示成功
 */
esp_err_t emoji_storage_remove_downloaded_pack(char pack_id);

三、实现细节

3.1 文件结构

main/
├── NVS_FLASH/
│   ├── nvs_flash.h          (已有,需要扩展)
│   └── nvs_flash.c          (已有,需要扩展)
└── EMOJI_STORAGE/           (新建模块)
    ├── emoji_storage.h      (新建)
    └── emoji_storage.c      (新建)

3.2 内存缓存设计

  • 在内存中维护缓存,避免频繁读写NVS
  • 系统启动时从NVS加载到内存
  • 每次更新时同步写入NVS

3.3 数据同步策略

  • 写操作:立即写入NVS(保证数据不丢失)
  • 读操作:优先从内存缓存读取(提高性能)
  • 初始化:系统启动时从NVS加载到内存

3.4 错误处理

  • NVS操作失败时记录日志
  • 读取失败时使用默认值('0'表示默认表情包)
  • 写入失败时重试机制

四、集成点

4.1 系统初始化

  • 在系统启动时调用 emoji_storage_load() 加载数据

4.2 表情包下载完成

  • 在下载成功回调中调用 emoji_storage_add_downloaded_pack()

4.3 表情包切换

  • 在切换表情包时调用 emoji_storage_save_using_pack()

4.4 查询已下载表情包

  • 在 BLE_SEND_DOWNLOADED_PACKS 处理中调用 emoji_storage_get_downloaded_packs()

4.5 查询正在使用表情包

  • 在 BLE_SEND_EMOJI_USING 处理中调用 emoji_storage_get_using_pack()

4.6 蓝牙连接时发送正在使用的表情包

  • 重要:在蓝牙连接成功时(BLE_CONNECTED_BIT 事件),除了发送版本信息,还要发送正在使用的表情包系列
  • 在 main.c 的 main_task 中,处理 BLE_CONNECTED_BIT 时,同时触发 BLE_SEND_EMOJI_USING
  • 在 ble.c 的 notification_task 中,处理 BLE_SEND_EMOJI_USING 时,发送JSON格式的表情包信息

五、数据格式示例

5.1 NVS存储示例

命名空间: "emoji_config"
键值对:
  - "using_pack" = "A"          (当前使用表情包A)
  - "downloaded_packs" = "[\"0\",\"A\",\"B\",\"C\"]"  (已下载0,A,B,C)

5.2 JSON格式示例

{
  "using_pack": "A",
  "downloaded_packs": ["0", "A", "B", "C", "D"]
}

5.3 蓝牙发送格式示例

{
  "action": "emoji_using_info",
  "data": {
    "pack_id": "A"
  }
}

六、优势

  1. 可靠性:使用NVS保证掉电不丢失
  2. 性能:内存缓存减少NVS读写次数
  3. 扩展性:JSON格式易于扩展字段
  4. 兼容性:复用现有NVS基础设施
  5. 可维护性:独立模块,接口清晰

七、注意事项

  1. NVS空间限制:注意NVS分区大小,避免存储过多数据
  2. 线程安全:如果多线程访问,需要添加互斥锁保护
  3. 数据迁移:如果后续需要修改数据结构,考虑版本兼容
  4. 默认值处理:首次使用时需要初始化默认值

八、实现完成情况

8.1 已实现的功能

✅ 创建了 EMOJI_STORAGE 模块

  • emoji_storage.h - 接口定义
  • emoji_storage.c - 实现代码

✅ 核心功能实现

  • emoji_storage_load() - 从NVS加载数据(系统启动时自动调用)
  • emoji_storage_save_using_pack() - 保存正在使用的表情包
  • emoji_storage_add_downloaded_pack() - 添加已下载的表情包
  • emoji_storage_get_using_pack() - 获取正在使用的表情包
  • emoji_storage_get_downloaded_packs_json() - 获取JSON格式的已下载列表
  • emoji_storage_get_downloaded_packs() - 获取逗号分隔的已下载列表
  • emoji_storage_is_downloaded() - 检查是否已下载
  • emoji_storage_remove_downloaded_pack() - 删除已下载的表情包

✅ 集成到现有代码

  • 在 ble_main() 中自动加载表情包数据
  • 在 main.c 中,蓝牙连接时发送正在使用的表情包
  • 在 ble.c 中,添加了 BLE_SEND_EMOJI_USING 的处理逻辑
  • 更新了 CMakeLists.txt,添加新模块到编译列表

8.2 使用示例

8.2.1 系统启动时自动加载

系统启动时,在 ble_main() 中会自动调用 emoji_storage_load() 加载数据。

8.2.2 下载表情包后保存

// 下载表情包成功后
emoji_storage_add_downloaded_pack('A');  // 添加表情包A到已下载列表

8.2.3 切换表情包时保存

// 切换到表情包B
emoji_storage_save_using_pack('B');

8.2.4 查询正在使用的表情包

char using_pack = emoji_storage_get_using_pack();  // 返回 '0', 'A', 'B' 等

8.2.5 查询已下载的表情包列表

char packs[256];
int count = emoji_storage_get_downloaded_packs_json(packs, sizeof(packs));
// packs 内容: ["0","A","B","C"]

8.2.6 蓝牙连接时自动发送

蓝牙连接成功时,系统会自动发送正在使用的表情包信息:

{
  "action": "emoji_using_info",
  "data": {
    "pack_id": "A"
  }
}

8.3 数据格式

NVS存储格式

  • 命名空间: "emoji_config"
  • "using_pack": 字符串,如 "A", "B", "0" 等
  • "downloaded_packs": JSON字符串,如 "[\"0\",\"A\",\"B\",\"C\"]"

默认值

  • 首次使用时,using_pack 默认为 "0"(默认表情包)
  • downloaded_packs 默认为 "[\"0\"]"(只有默认表情包)

九、后续优化建议

  1. 添加数据版本号,支持数据结构升级
  2. 添加数据校验(CRC或校验和)
  3. 支持表情包元数据存储(名称、大小、下载时间等)
  4. 支持表情包使用统计(使用次数、最后使用时间等)
  5. 在下载表情包成功后自动调用 emoji_storage_add_downloaded_pack()
  6. 在切换表情包时自动调用 emoji_storage_save_using_pack()