Dzbj_ESP32-S3_Key/移植到Baji_Rtc_Toy_Key方案.md
Rdzleo 75586b3744 ESP32-S3按键版电子吧唧功能完整实现
1、按键驱动重构:从GPIO中断改为iot_button组件,支持BOOT/KEY2的单击/双击/长按6种事件;
2、新增按键导航管理器(key_nav):9种上下文状态机,统一分发按键事件到对应界面业务逻辑;
3、BLE模块改造:广播默认关闭由按键触发,新增设备间图片传输(GATT Client),支持扫描配对→MTU协商→分包发送;
4、新增6个UI界面:配对(Peiwang)、更新(Update)、发送等待(ImageShar)、接收等待(ImageReception)、发送中(Sharing)、接收中(Receiving);
5、新增电池指示器组件(battery_ui):支持多界面真实电量显示,3秒渐隐效果;
6、Home界面重构:移除手势事件,改为airhub背景图+电池指示器;
7、Img界面重构:移除触摸事件,新增删除二次确认边框机制;
8、禁用ScreenSet/ScreenChar界面(保留文件),禁用触摸初始化(保留代码可恢复);
9、sleep_mgr简化:移除ScreenSet亮度UI依赖,按键唤醒由key_nav统一处理;
10、新增9张图片资源(airhub背景、配对、传输状态、电池图标等);

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-26 17:35:05 +08:00

187 lines
7.2 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.

# 按键版电子吧唧移植到 Baji_Rtc_Toy_Key 方案
## 一、目标项目分析
### 1.1 项目架构
`Baji_Rtc_Toy_Key` 是 AI 对话 + 电子吧唧双模式项目,通过 NVS 存储的 `device_mode` 切换:
- **AI 模式** (`DEVICE_MODE_AI`): 火山引擎 RTC 语音对话 + GIF 表情
- **电子吧唧模式** (`DEVICE_MODE_BADGE`): 图片浏览 + BLE 传图(当前仍为触屏版)
### 1.2 目标项目已有的吧唧模块(`main/dzbj/` 目录)
| 文件 | 功能 | 状态 |
|------|------|------|
| `dzbj_ble.c` | GATT ServerAPP 传图) | ✅ 已有,仅 Server |
| `dzbj_button.c` | ISR 轮询按键 | ⚠️ 需替换为 iot_button |
| `dzbj_battery.c` | 电池 ADC 采样 | ✅ 已有 |
| `sleep_mgr.c` | 休眠管理 | ✅ 已有 |
| `fatfs.c` | FatFS 图片存储 | ✅ 已有(本项目用 SPIFFS |
| `pages.c` | 图片列表管理 | ✅ 已有 |
| `lcd.c` | LCD 驱动 | ✅ 已有 |
| UI 界面 | ScreenHome/Img/Set/Peiwang/Update | ✅ 已有(触屏版) |
### 1.3 目标项目缺失的模块
| 模块 | 说明 |
|------|------|
| **key_nav** | 按键导航管理器(上下文状态机 + 事件分发) |
| **ble_transfer** | 设备间 BLE 图片传输GATT Client 扫描/连接/发送) |
| **4 个新界面** | ScreenImageShar / ScreenImageReception / ScreenSharing / ScreenReceiving |
| **battery_ui** | 电池指示器 show-briefly + fade-out 动画 |
| **两步删除确认** | ScreenImg 的 ContainerDle 重设计 + NAV_CTX_IMG_DELETE_CONFIRM |
---
## 二、架构差异与适配策略
### 2.1 按键驱动差异
| 维度 | 本项目 (Dzbj_ESP32_S3_Key) | 目标项目 (Baji_Rtc_Toy_Key) |
|------|---------------------------|---------------------------|
| 组件 | iot_button (ESP Component Registry) | ISR 轮询(自定义 dzbj_button.c |
| 语言 | 纯 C | C++ (Application 框架) |
| 事件 | 单击/双击/长按 × 2 键 | 仅按下/释放 |
| 回调线程 | esp_timer 任务 | ISR 中断 |
**适配策略**:
- 在吧唧模式下添加 iot_button 依赖,替换 `dzbj_button.c` 的 ISR 实现
- 或在 `dzbj_button.c` 中增加双击/长按检测逻辑(不引入新依赖,但开发量大)
- **推荐**: 引入 iot_button仅在吧唧模式下初始化
### 2.2 模式隔离
目标项目已有模式隔离框架:
```cpp
// main/main.cc
if (device_mode_is_badge()) {
dzbj_app_main(); // 吧唧模式入口
} else {
// AI 模式入口
}
```
**适配策略**:
- key_nav 模块仅在 `dzbj_app_main()` 中初始化
- iot_button 的按键回调仅注册吧唧模式的处理函数
- AI 模式的按键处理保持不变ISR 方式)
### 2.3 存储差异
| 维度 | 本项目 | 目标项目 |
|------|--------|---------|
| 文件系统 | SPIFFS | FatFS |
| 图片管理 | `init_spiffs_image_list()` | `fatfs` 模块 |
**适配策略**:
- key_nav 中的 `init_spiffs_image_list()` 替换为目标项目的 FatFS 图片列表接口
- ble_transfer 中的图片保存路径适配 FatFS 挂载点
---
## 三、移植步骤(共 7 步)
### 步骤 1: 添加 iot_button + 适配按键驱动
**操作**:
1. `main/idf_component.yml` 添加 `button: ">=3.2.0"`
2. 新建 `main/dzbj/dzbj_button_nav.c`(或修改 `dzbj_button.c`
3. 实现 6 种事件回调接口,参数照搬本项目的 `button.c`
**注意**:
- AI 模式下不初始化 iot_button避免资源浪费
- 确认 iot_button 和现有 ISR 按键不冲突(同一 GPIO 不要双重处理)
### 步骤 2: 移植 key_nav 模块
**操作**:
1. 复制 `main/key_nav/` 目录到目标项目 `main/dzbj/key_nav/`
2. 适配 include 路径ui 头文件路径可能不同)
3. 适配 LVGL 锁:确认目标项目的 `lvgl_port_lock()` 接口一致
4. 替换 SPIFFS 相关调用为 FatFS 接口
**关键修改点**:
```c
// 本项目
#include "ui/ui.h"
#include "ui/screens/ui_ScreenHome.h"
init_spiffs_image_list();
// 目标项目适配
#include "dzbj_ui.h" // 或目标项目实际的 UI 头文件路径
init_fatfs_image_list(); // 或目标项目的图片列表初始化函数
```
### 步骤 3: 移植 ble_transfer 模块
**操作**:
1. 复制 `main/ble/ble_transfer.c``main/ble/include/ble_transfer.h`
2. 适配 BLE 初始化:目标项目的 `dzbj_ble.c` 已有 GATT Server需新增 GATT Client 能力
3. 适配图片保存SPIFFS → FatFS 路径
4. 适配界面跳转:确认目标项目的 `_ui_screen_change()` 接口
**注意**:
- 目标项目的 BLE 在 AI 模式下可能有不同用途,确保吧唧模式的 ble_transfer 不影响 AI 模式
- `ble_start()` / `ble_stop()` 需适配到 `dzbj_ble.c` 的广播控制
### 步骤 4: 移植 4 个新 UI 界面
**操作**:
1. 复制以下文件到目标项目的 UI 目录:
- `ui_ScreenImageShar.c/.h`
- `ui_ScreenImageReception.c/.h`
- `ui_ScreenSharing.c/.h`
- `ui_ScreenReceiving.c/.h`
2. 复制 4 张图片资源文件(`ui_img_*_png.c`
3. 在目标项目的 `ui.h` 中添加 include 和 `LV_IMG_DECLARE`
4. 在 CMakeLists.txt 中添加编译
### 步骤 5: 移植 battery_ui 模块
**操作**:
1. 复制 `main/ui/battery_ui.c``main/ui/battery_ui.h`
2. 在 ScreenHome 和 ScreenImg 的 `screen_init` 中调用 `battery_ui_add_to_screen()`
3. 在 SCREEN_LOADED 事件中调用 `battery_ui_show_briefly()`
4.`dzbj_battery.c` 的电量更新回调中调用 `battery_ui_update_level()`
### 步骤 6: 适配 ScreenImg 删除确认 UI
**操作**:
1. 将目标项目的 `ui_ScreenImg.c` 中的 ContainerDle 改为 220×220 底部半圆设计
2. ui_ImageDel 改为 68×68 正圆容器 + S13 图片居中
3. 添加白色边框显示/隐藏函数
4. key_nav 中已包含两步删除逻辑,无需额外修改
### 步骤 7: 适配 main 入口和手势移除
**操作**:
1.`dzbj_app_main()` 中添加 `key_nav_init()` 调用
2. 移除吧唧模式下各界面的触摸手势事件回调
3. 保留 `LV_EVENT_SCREEN_LOADED` 延迟加载逻辑
4. 适配 sleep_mgr 的唤醒回调(由 key_nav 统一管理)
---
## 四、风险评估
| 风险 | 影响 | 缓解措施 |
|------|------|---------|
| iot_button 与 AI 模式按键冲突 | GPIO 双重处理导致崩溃 | 模式隔离:吧唧模式用 iot_buttonAI 模式保持 ISR |
| BLE Client + Server 同时运行 | 资源不足或状态冲突 | ble_transfer 使用独立的 GATT App ID |
| FatFS vs SPIFFS 接口差异 | 图片路径/文件操作不兼容 | 统一封装图片读写接口 |
| UI 头文件路径差异 | 编译错误 | 系统性检查所有 #include 路径 |
| C++ 框架与纯 C 模块交互 | 链接/调用约定问题 | key_nav 等 C 模块用 `extern "C"` 包裹头文件 |
---
## 五、预估工作量
| 步骤 | 复杂度 | 说明 |
|------|--------|------|
| 步骤 1: 按键驱动 | 中 | 需处理模式隔离和 GPIO 冲突 |
| 步骤 2: key_nav | 低 | 主要是路径适配 |
| 步骤 3: ble_transfer | 高 | BLE Client 集成到已有 BLE 框架最复杂 |
| 步骤 4: 新界面 | 低 | 直接复制 + 适配路径 |
| 步骤 5: battery_ui | 低 | 直接复制 + 接入电量回调 |
| 步骤 6: 删除确认 | 低 | UI 修改量小 |
| 步骤 7: 入口适配 | 中 | 需仔细处理手势移除和模式切换 |
**总结**: 移植可行性高。核心难点在 ble_transfer 的集成(步骤 3和按键驱动的模式隔离步骤 1其余模块可直接复制适配。建议按步骤顺序执行每步编译验证。