283 lines
8.6 KiB
Markdown
283 lines
8.6 KiB
Markdown
# 表情包持久化存储方案
|
||||
|
|
|
|||
|
|
## 一、需求分析
|
|||
|
|
|
|||
|
|
需要在掉电不丢失的存储中记录:
|
|||
|
|
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()`
|