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

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

283 lines
8.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 表情包持久化存储方案
## 一、需求分析
需要在掉电不丢失的存储中记录:
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()`