# 表情包持久化存储方案 ## 一、需求分析 需要在掉电不丢失的存储中记录: 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 初始化接口 ```c /** * @brief 从NVS加载表情包信息到内存 * @return esp_err_t ESP_OK表示成功 */ esp_err_t emoji_storage_load(void); ``` #### 2.3.2 保存已使用的表情包 ```c /** * @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 添加已下载的表情包 ```c /** * @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 获取已使用的表情包 ```c /** * @brief 获取当前使用的表情包ID * @return char 表情包ID,'0'表示默认表情包 */ char emoji_storage_get_using_pack(void); ``` #### 2.3.5 获取已下载的表情包列表 ```c /** * @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 检查表情包是否已下载 ```c /** * @brief 检查指定表情包是否已下载 * @param pack_id 表情包ID(字符) * @return true 已下载,false 未下载 */ bool emoji_storage_is_downloaded(char pack_id); ``` #### 2.3.7 删除已下载的表情包 ```c /** * @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格式示例 ```json { "using_pack": "A", "downloaded_packs": ["0", "A", "B", "C", "D"] } ``` ### 5.3 蓝牙发送格式示例 ```json { "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 下载表情包后保存 ```c // 下载表情包成功后 emoji_storage_add_downloaded_pack('A'); // 添加表情包A到已下载列表 ``` #### 8.2.3 切换表情包时保存 ```c // 切换到表情包B emoji_storage_save_using_pack('B'); ``` #### 8.2.4 查询正在使用的表情包 ```c char using_pack = emoji_storage_get_using_pack(); // 返回 '0', 'A', 'B' 等 ``` #### 8.2.5 查询已下载的表情包列表 ```c char packs[256]; int count = emoji_storage_get_downloaded_packs_json(packs, sizeof(packs)); // packs 内容: ["0","A","B","C"] ``` #### 8.2.6 蓝牙连接时自动发送 蓝牙连接成功时,系统会自动发送正在使用的表情包信息: ```json { "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()`