# 按键版电子吧唧移植到 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 Server（APP 传图） | ✅ 已有，仅 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_button，AI 模式保持 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），其余模块可直接复制适配。建议按步骤顺序执行，每步编译验证。
