完善readme

This commit is contained in:
cuicuiV5 committed 2026-09-01 14:19:22 +08:00
1 parent 8ccf5f909d
commit 6975706f48
1 file changed
+189 -109
+189 -109
View File
@@ -1,8 +1,9 @@
# RemoteMapper-ESP32 开发者手册与技术全景文档
## 小米蓝牙语音遥控器 → USB 复合设备(免驱物理麦克风 + 独立多媒体键盘 + Web 可视化后台)
## 小米蓝牙语音遥控器 2 Pro (RC003) ➔ USB 复合硬件桥接固件
> **适用固件版本**:v1.0.0+
> **适用固件版本**:v1.0.0+ (Production Release)
> **目标主控硬件**:ESP32-S3-DevKitC-1 N16R8(16MB Octal SPI Flash + 8MB Octal SPI PSRAM)
> **适配遥控型号**:小米蓝牙语音遥控器 2 Pro(型号:RC003,铝合金金属机身款)
> **文档受众**:嵌入式开发者、代码维护者与后续 AI Agent 协作开发
---
@@ -12,20 +13,21 @@
2. [硬件选型与存储分区设计 (16MB Flash)](#二-硬件选型与存储分区设计-16mb-flash)
3. [BLE 与 ATVV 语音协议栈全流程解析](#三-ble-与-atvv-语音协议栈全流程解析)
4. [DSP 实时音频处理流水线算法设计](#四-dsp-实时音频处理流水线算法设计)
5. [按键映射手势状态机与键码转换](#五-按键映射手势状态机与键码转换)
6. [USB 复合设备架构 (UAC 1.0 + HID + CDC)](#六-usb-复合设备架构-uac-10--hid--cdc)
7. [Wi-Fi 双模网络与嵌入式 Web 控制台](#七-wi-fi-双模网络与嵌入式-web-控制台)
8. [RESTful API 完整接口规范](#八-restful-api-完整接口规范)
9. [源码文件索引与模块依赖关系](#九-源码文件索引与模块依赖关系)
10. [编译、烧录与测试指南](#十-编译烧录与测试指南)
11. [故障排查手册与常见问题 (Troubleshooting)](#十一-故障排查手册与常见问题-troubleshooting)
12. [未来扩展与演进路线 (Roadmap)](#十二-未来扩展与演进路线-roadmap)
5. [多触发按键映射状态机与键码引擎](#五-多触发按键映射状态机与键码引擎)
6. [Flash NVS 存储引擎与开机自愈容灾机制](#六-flash-nvs-存储引擎与开机自愈容灾机制)
7. [USB 复合设备架构 (UAC 1.0 + HID + CDC)](#七-usb-复合设备架构-uac-10--hid--cdc)
8. [Wi-Fi 双模网络与嵌入式 Web 控制台](#八-wi-fi-双模网络与嵌入式-web-控制台)
9. [PC 本地伴侣程序架构 (pc_companion)](#九-pc-本地伴侣程序架构-pc_companion)
10. [RESTful API 完整接口规范](#十-restful-api-完整接口规范)
11. [源码文件索引与模块依赖关系](#十一-源码文件索引与模块依赖关系)
12. [编译、烧录与测试指南](#十二-编译烧录与测试指南)
13. [故障排查手册与常见问题 (Troubleshooting)](#十三-故障排查手册与常见问题-troubleshooting)
---
# 一. 系统整体架构与多核任务分配
ESP32-S3 具有 Xtensa® 双核 32 位 LX7 微处理器(主频 240MHz)。为了保证音频实时解码不卡顿、USB Isochronous 报文不丢包、BLE 吞吐高响应,系统采用 **FreeRTOS 双核物理隔离调度架构**:
ESP32-S3 配备 Xtensa® 双核 32 位 LX7 微处理器(主频 240MHz)。为了保证实时音频解码 0 掉帧、USB Isochronous 报文 1000Hz 零抖动、BLE 协议栈秒级响应以及 Web 异步请求不卡顿,系统采用 **FreeRTOS 双核物理隔离调度架构**:
```text
┌────────────────────────────────────────────────────────────────────────────────────────┐
@@ -34,12 +36,13 @@ ESP32-S3 具有 Xtensa® 双核 32 位 LX7 微处理器(主频 240MHz)。为
│ Core 0 (专职蓝牙与 DSP) │ Core 1 (专职 USB、网络与业务) │
├───────────────────────────────────────────┼────────────────────────────────────────────┤
│ • NimBLE Central 协议栈 (扫描/连接/绑定) │ • TinyUSB 复合设备 (UAC Mic + HID + CDC) │
│ • HOGP 按键报文解析 (订阅 0x2A4D) │ • UAC 麦克风 1ms Isochronous 数据泵 (16kHz)│
│ • ATVV 语音握手 (0x0A/0x0C/0x0E/0x00) │ • KeyState 映射手势状态机 (单击/长按/连发) │
│ • 4-bit IMA-ADPCM 实时流式解码 │ • Wi-Fi 双模管理器 (AP 192.168.4.1 + STA) │
│ • Declip 尖峰消除 + 3-Tap FIR 低通平滑 │ • Captive Portal DNS 强制门户 (Port 53) │
│ • 动态 AGC 增益控制与软削波 │ • HTTP WebServer (Port 80 RESTful API) │
│ • 音频数据注入 SPSC 无锁环形缓冲区 │ • Serial / CDC CLI 控制台指令调度 │
│ • HOGP 原始报文解析 (订阅 0x2A4D) │ • UAC 麦克风 1ms Isochronous 数据泵 (16kHz)│
│ • ATVV 语音握手 (0x0A/0x0C/0x0E/0x00) │ • Multi-Trigger 状态机 (单击/长按/双击) │
│ • 4-bit IMA-ADPCM 实时流式解码 │ • Flash NVS 存储引擎 & 自愈容灾校验 │
│ • Declip 尖峰消除 + 3-Tap FIR 低通滤波 │ • Wi-Fi 双模管理器 (AP 192.168.4.1 + STA) │
│ • 动态 AGC 增益控制与软削波 │ • Captive Portal DNS 强制门户 (Port 53) │
│ • 音频数据注入 SPSC 无锁环形缓冲区 │ • HTTP WebServer (Port 80 RESTful API) │
│ • RGB 状态指示灯控制器 (WS2812 / GPIO48) │ • Serial / CDC CLI 控制台指令调度 │
└───────────────────────────────────────────┴────────────────────────────────────────────┘
│ ▲
└────── RingBuffer ───┘
@@ -51,12 +54,12 @@ ESP32-S3 具有 Xtensa® 双核 32 位 LX7 微处理器(主频 240MHz)。为
# 二. 硬件选型与存储分区设计 (16MB Flash)
### 1. 硬件连接规范
* **USB 接口**:必须连接 ESP32-S3 开发板的 **`USB/OTG` 接口**(对应 GPIO 19: D-,GPIO 20: D+),**不可连接 UART 口**;
* **天线**:板载 PCB 天线或 IPEX 外接天线;
* **供电**:USB 5V 直接供电,典型功耗约 120mA。
* **主控型号**:ESP32-S3-DevKitC-1 N16R8(16MB Flash + 8MB Octal PSRAM);
* **USB 接口**:必须连接 ESP32-S3 开发板的 **`USB/OTG` 接口**(对应内部硬件 GPIO 19: D-,GPIO 20: D+),**不可连接 UART 口**;
* **遥控器型号**:**小米蓝牙语音遥控器 2 Pro(型号:RC003)**。
* **供电**:USB 5V 直接供电,典型运行功耗约 110~130mA。
### 2. 16MB Flash 分区表 (`default_16MB.csv`)
为确保后续支持 OTA 无缝固件升级,Flash 分区规划如下:
| 分区名 | 类型 | 子类型 | 起始偏移 (Offset) | 大小 (Size) | 用途说明 |
| :--- | :--- | :--- | :--- | :--- | :--- |
@@ -72,15 +75,15 @@ ESP32-S3 具有 Xtensa® 双核 32 位 LX7 微处理器(主频 240MHz)。为
# 三. BLE 与 ATVV 语音协议栈全流程解析
### 1. GATT 服务与特征值定义
* **HOGP 规范服务**:UUID `0x1812` ➔ HID Report 特征值 `0x2A4D`(Notify,订阅捕获按键字节);
* **HOGP 规范服务**:UUID `0x1812` ➔ HID Report 特征值 `0x2A4D`(Notify,捕获按键原始报文);
* **ATVV 自定义服务**:UUID `ab5e0001-5a21-4f05-bc7d-af01f617b664`
* `ab5e0002-5a21-4f05-bc7d-af01f617b664` (**CMD 通道**,Write Without Response)
* `ab5e0003-5a21-4f05-bc7d-af01f617b664` (**AUDIO 通道**,Notify,接收 ADPCM 数据流)
* `ab5e0002-5a21-4f05-bc7d-af01f617b664` (**CMD 通道**,Write Without Response,下发握手指令)
* `ab5e0003-5a21-4f05-bc7d-af01f617b664` (**AUDIO 通道**,Notify,接收 120 字节 ADPCM 音频帧)
* `ab5e0004-5a21-4f05-bc7d-af01f617b664` (**CTL 通道**,Notify,接收语音启停状态)
### 2. ATVV 握手与语音状态机时序
```text
ESP32-S3 (Central) 小米遥控器 (Peripheral)
ESP32-S3 (Central) 小米遥控器 RC003 (Peripheral)
│ │
│── 1. 扫描匹配 "MI RC" 或 MAC 前缀 "c0:5d:39" ─────────────►│
│◄─ 2. 建立 BLE GATT 连接并启用 Bonding ─────────────────────│
@@ -108,7 +111,7 @@ ESP32-S3 (Central) 小米遥控器 (Periphe
│ ═════════════════ 用户松开遥控器语音键 ═════════════════ │
│◄─ 10. CTL 通道上报 AUDIO_STOP: [0x00, 0x02] ──────────────│
│ • 释放语音热键 │
│ • 停止麦克风推流,清空缓冲区 │
│ • 停止麦克风推流,清空环形缓冲区 │
│ • 重新发送 MIC_OPEN [0x0C, 0x00] 防御下次按键失效 │
```
@@ -117,9 +120,9 @@ ESP32-S3 (Central) 小米遥控器 (Periphe
# 四. DSP 实时音频处理流水线算法设计
### 1. 4-bit IMA-ADPCM 流式解码
- **采样参数**:16000 Hz 单声道 16-bit PCM;
- **帧规格**:BLE 传输每包 120 字节(Hi-nibble 高 4 位优先,低 4 位其次),对应解码出 240 个 PCM 采样点;
- **跨帧连续性**:Predictor(预测器)和 StepIndex(步长索引 [0, 88])在帧间保持连续,遇到 ATVV `0x0A` (`AUDIO_SYNC`) 指令时动态重置为同步点。
- **采样规格**:16000 Hz 单声道 16-bit PCM;
- **帧解析**:BLE 每帧 120 字节(高 4 位优先,低 4 位其次),对应解出 240 个 PCM 采样点;
- **跨帧连续性**:Predictor 与 StepIndex 在帧间保持连续,收到 `AUDIO_SYNC`(`0x0A`)时重置同步点。
### 2. Declip 单点尖峰消除
消除蓝牙丢包或电磁干扰引起的孤立单点脉冲毛刺:
@@ -131,142 +134,222 @@ $$y_i = \frac{x_{i-1} + 2x_i + x_{i+1}}{4}$$
### 4. 动态 AGC (自动增益控制)
- **目标电平**:`28000.0`
- **包络衰减率**:`0.9997`(约 144ms 慢释放,避免呼吸底噪)
- **最大增益限制**:`30.0` 倍(避免空闲无声时放大本底噪声)
- **软削波**:防止波形硬切顶产生破音。
- **包络衰减率**:`0.9997`(约 144ms 慢释放,避免呼吸底噪);
- **最大增益限制**:`30.0` 倍(避免空闲无声时放大本底噪声);
- **软削波**:防止波形硬切顶产生爆音。
---
# 五. 按键映射手势状态机与键码转换
# 五. 多触发按键映射状态机与键码引擎
### 1. 遥控器全按键物理编码转换表
| 遥控器物理按键 | 小米原始 HID 报文 | ESP32 输出的 USB 信号 | 功能效果 |
| :--- | :--- | :--- | :--- |
| **音量+** | `0x80` | `Consumer: Volume Up (0x00E9)` | Windows 系统原生主音量增加 (支持高速连发) |
| **音量-** | `0x81` | `Consumer: Volume Down (0x00EA)`| Windows 系统原生主音量减小 (支持高速连发) |
| **音量+** | `0x80` | `Consumer: Volume Up (0x00E9)` | Windows 原生系统全局音量增加 |
| **音量-** | `0x81` | `Consumer: Volume Down (0x00EA)`| Windows 原生系统全局音量减小 |
| **返回键** | `0xF1` | `Consumer: AC Back (0x0224)` | 浏览器/文件管理器后退、播放器退出全屏 |
| **语音键** | ATVV 事件 | **注入 `RAlt + ,` + UAC 麦克风** | 唤醒微信输入法语音并实时录音 |
| **电源键** | `0xFF` / `0x66` | **单击 `Alt + Tab` / 长按 `Sleep`** | 窗口切换 / 系统睡眠 |
| **主页键** | `0x24` / `0x4A` | `Keyboard: Win + D` | 一键返回桌面 |
| **菜单键** | `0x5D` / `0x65` | `Keyboard: Space` | 视频播放 / 暂停 |
| **直播/TV 键** | `0xC0` / `0x35` | `Keyboard: F8` | 自定义快捷键 |
| **电源键** | `0xFF` / `0x66` | **单击 `Alt + F4` / 长按 `Sleep (0x0032)`** | 关闭当前窗口 / 系统睡眠 |
| **主页键** | `0x24` | `Keyboard: Win + D` | 一键返回桌面 |
| **菜单键** | `0x5D` | `Keyboard: Space` | 视频播放 / 暂停 |
| **电视键 (TV)**| `0xC0` | `Keyboard: F8` | 自定义快捷键 / 触发伴侣脚本 |
| **方向上/下/左/右** | `0x52/51/50/4F`| `Keyboard: Up/Down/Left/Right` | 播放器快进快退调进度 |
| **确定键 (OK)** | `0x28` | `Keyboard: Return` | 确认 / 回车 |
### 2. 状态机手势逻辑
- **单击 (Tap)**:按键按下后在 `long_ms` (600ms) 内释放,无双击需求时立即派发;
- **长按 (Hold)**:按键持续按下超过 `long_ms` (600ms),触发长按动作(如关屏/睡眠),释放时不重复触发单击;
- **连发 (Repeat)**:首次按下延时 `350ms` 后,以 `70ms` 间隔持续发送(专用于音量键流畅调节)。
### 2. Multi-Trigger 三重触发状态机设计 (`key_state_machine.c`)
每个按键独立维护一个插槽状态结构体,支持 3 种互不干扰的手势:
* **单击(Click)**:瞬时点按或按下保持(Hold 直通);
* **长按(Long Press)**:按压时长超过 `long_ms`(默认 600ms,支持 200~2000ms 自定义),触发长按动作,松开时不触发短按;
* **双击(Double Click)**:按键在 `double_ms`(默认 250ms,支持 100~600ms 自定义)内再次按下,触发双击动作;
* **防卡键瞬时脉冲机制**:超时触发的长按操作,释放时会补发释放包,彻底杜绝键值卡死。
### 3. 全链路 16 进制 / 10 进制双模解析引擎
- 键码统一支持 `0x...` 标准 16 进制与 10 进制无缝互通;
- `parse_u32_or_hex()` 智能识别数字或 `"0x2C"` 字符串格式。
---
# 六. USB 复合设备架构 (UAC 1.0 + HID + CDC)
# 六. Flash NVS 存储引擎与开机自愈容灾机制
ESP32-S3 原生 USB OTG 控制器在枚举时向 Windows 呈现一个**复合多接口设备 (Composite Device)**:
为确保在 ESP32-S3 Flash 单扇区(4KB)限制下可靠持久化,存储系统采用分层加固设计:
1. **Interface 0 & 1:USB Audio Class 1.0 (麦克风)**
```text
┌────────────────────────────────────────────────────────┐
│ Flash NVS 存储安全防御体系 │
├────────────────────────────────────────────────────────┤
│ 1. 紧凑型 JSON 序列化 (未启用手势字段自动省略, < 1.4KB) │
│ 2. 局部原子事务 (Preferences.begin -> putString -> end) │
│ 3. 强制刷写提交 (nvs_flash_commit) │
│ 4. 开机自愈容灾 (校验失败/坏块自动降级为 13 键出厂默认) │
│ 5. 底层分区防误删 (phy / nimble_bond / net80211 只读保护)│
└────────────────────────────────────────────────────────┘
```
1. **紧凑型 JSON 压缩**:仅序列化启用的触发手势,13 键全部配置 3 触发时总数据量仅约 1.2KB(< 35% 扇区容量);
2. **开机自愈保护**:`key_config_storage_load()` 启动时严格校验 JSON 完整性,若异常断电损坏,自动恢复出厂默认值,杜绝系统变砖。
---
# 七. USB 复合设备架构 (UAC 1.0 + HID + CDC)
ESP32-S3 原生 USB OTG 在枚举时向操作系统呈现标准**复合多接口设备 (Composite Device)**:
1. **Interface 0 & 1:USB Audio Class 1.0 (物理麦克风)**
- 格式:PCM 16-bit Mono, 16000Hz;
- 端点:Isochronous IN 端点(采用降频设计:端点大小 64 字节,每 2ms 轮询一次);
- 设备名:`RemoteMapper Wireless Mic`。
> ⚠️ **开发踩坑警告 (The DWC2 Boundary Crossing Bug)**:
> 在 Arduino TinyUSB 预编译栈(无 SOF 中断)环境下开发 Isochronous 端点时,极易因任务相位漂移触发 DWC2 控制器的硬件 EONUM 奇偶边界跨越缺陷,导致 1000Hz 的物理帧降速为 500Hz 从而引发一半以上的音频丢包和重度锯齿音。
> **本固件通过合规的 `bInterval=2` 和 `wMaxPacketSize=64` 实现了完美的降频打包修复。**
> 详细复盘分析请参阅根目录独立文档:[USB_UAC_BUG_POSTMORTEM.md](./USB_UAC_BUG_POSTMORTEM.md)
- 端点:Isochronous IN 端点;
- 独创 **bInterval=2 / wMaxPacketSize=64** 降频缓冲设计,完美绕过 DWC2 控制器无 SOF 中断引起的 500Hz 丢帧魔咒;
- **硬件 SOF / DSTS 状态感知**:电脑休眠唤醒时自动重置 UAC 状态机。
2. **Interface 2:USB HID Keyboard**
- 标准 6KRO 键盘报文,负责发送 `Win+D`, `Alt+Tab`, `RAlt+,` 等修饰组合键。
- 标准 6KRO 键盘报文,负责发送 `Win+D`, `Alt+Tab`, `RAlt+,`, `F13~F24` 等修饰组合键。
3. **Interface 3:USB HID Consumer Control**
- 16-bit Usage 控制报文,负责发送系统音量与 AC 后退。
- 16-bit Usage 控制报文,负责发送原生系统音量(`0x00E9`/`0x00EA`)、静音(`0x00E2`)与 AC 后退(`0x0224`)。
4. **Interface 4:USB CDC Serial**
- 虚拟串口,用于串口监控与 JSON 命令行交互。
---
# 七. Wi-Fi 双模网络与嵌入式 Web 控制台
# 八. Wi-Fi 双模网络与嵌入式 Web 控制台
### 1. 网络拓扑
* **AP 模式(热点)**:
- SSID: `RemoteMapper-AP` (无密码)
* **AP 模式(配置热点)**:
- SSID: `RemoteMapper-AP` (开放免密)
- IP: `192.168.4.1` (子网掩码 `255.255.255.0`)
- DNS Captive Portal: 拦截所有未识别域名的 DNS 查询并重定向到 `192.168.4.1`。
* **STA 模式(局域网客户端)**:
- DNS Captive Portal: 自动拦截探测域名并重定向到 `192.168.4.1`。
* **STA 模式(局域网接入)**:
- 连接路由器 2.4GHz Wi-Fi;
- mDNS: 注册服务名 `remotemapper`,局域网访问地址为 **`http://remotemapper.local`**。
- mDNS: 局域网访问地址为 **`http://remotemapper.local`**。
### 2. Web 前端架构 (`src/web/web_ui.h`)
- **纯原生实现**:零外部 CDN、零 npm 依赖,HTML/CSS/JS 经 PROGMEM 嵌入 Flash;
- **响应式设计**:完美适配手机屏幕(触摸操作)与电脑宽屏浏览器;
- **暗黑科技主题**:高对比度仪表盘、实时 RSSI 状态指示条、自动滚动日志监视器。
- **纯原生单页架构**:HTML/CSS/JS 经 PROGMEM 嵌入 Flash,零外部 CDN 依赖;
- **1:1 遥控器仿真面板**:实体按键按下时界面实时高光联动;
- **敲击即录制**:改键窗口直接按下键盘即可自动识别并填入 HID 键码;
- **NVS 纯文本高级编辑器**:内置语法校验、格式化与一键备份导出/导入。
---
# 八. RESTful API 完整接口规范
# 九. PC 本地伴侣程序架构 (`pc_companion`)
为了弥补 USB HID 键盘无法直接执行本地程序/脚本的不足,随固件配备了独立的 Windows 伴侣守护进程:
```text
┌────────────────────────┐ USB HID Keycode (F13 ~ F24) ┌────────────────────────┐
│ │ ────────────────────────────────────► │ Windows 宿主机 PC │
│ ESP32-S3 硬件桥接器 │ │ │
│ (发送零冲突高阶 F 键) │ │ pc_companion 守护进程 │
└────────────────────────┘ │ (Win32 RegisterHotKey)│
└───────────┬────────────┘
│ 异步派发
▼
┌────────────────────────┐
│ • 打开网页 (抖音/Gemini)│
│ • 批处理 (.bat 切 PS5) │
│ • PowerShell / Python │
│ • 启动应用程序 (Steam) │
└────────────────────────┘
```
* **零冲突暗号**:使用 Windows 系统预留但物理键盘没有的 `F13 ~ F24` 键码;
* **极速无感**:原生 Win32 `RegisterHotKey` 消息循环,待机 CPU 0.0%,内存仅几 MB;
* **热重载配置**:修改 `config.json` 自动生效无需重启。
---
# 十. RESTful API 完整接口规范
| 请求方法 | 路由 Path | 描述 | 请求体示例 | 响应体示例 |
| :--- | :--- | :--- | :--- | :--- |
| `GET` | `/api/status` | 获取系统全量状态与遥测 | 无 | `{"version":"1.0.0","ble_state":3,"frames_decoded":1240,"free_heap":241500,"sta_ip":"192.168.1.108"}` |
| `GET` | `/api/logs` | 获取最近 60 条环形日志 | 无 | `{"logs":["[0012.340] [BLE] Connected","[0014.120] [VOICE] PRESSED"]}` |
| `POST` | `/api/logs/clear` | 清空内部日志环形缓冲 | 无 | `{"status":"cleared"}` |
| `GET` | `/api/status` | 获取系统全量运行状态与统计 | 无 | `{"version":"1.0.0","ble_state":3,"frames_decoded":1240,"free_heap":241500,"sta_ip":"192.168.2.179"}` |
| `GET` | `/api/logs` | 获取最近 250 行环形运行日志 | 无 | `{"logs":["[0012.340] [BLE] Connected","[0014.120] [VOICE] PRESSED"]}` |
| `POST`| `/api/logs/clear` | 清空运行日志缓冲区 | 无 | `{"status":"cleared"}` |
| `GET` | `/api/wifi/scan` | 扫描周围 2.4GHz Wi-Fi | 无 | `{"networks":[{"ssid":"Home-WiFi","rssi":-58,"secure":true}]}` |
| `POST`| `/api/wifi/config` | 配置并连接家庭 Wi-Fi | `{"ssid":"MyHome","pass":"12345678"}` | `{"status":"ok"}` |
| `GET` | `/api/keymap` | 获取当前按键映射 JSON | 无 | `{"ver":2,"bindings":[{"source_vk":102,"has_click":true,...}]}` |
| `POST`| `/api/keymap/save` | 保存按键映射到 Flash NVS | `{"ver":2,"bindings":[...]}` | `{"status":"saved"}` |
| `POST`| `/api/keymap/reset` | 重置按键映射为出厂默认 | 无 | `{"status":"reset_ok"}` |
| `POST`| `/api/ble/reconnect` | 触发重新扫描与连接遥控器 | 无 | `{"status":"reconnecting"}` |
| `POST`| `/api/system/restart` | 软重启 ESP32 | 无 | `{"status":"rebooting"}` |
| `GET` | `/api/keymap/telemetry`| 获取当前按键实时触发遥测 | 无 | `{"source_vk":102,"is_pressed":true,"duration_ms":120,"key_code":44}` |
| `GET` | `/api/ble/scan` | 扫描周围可连接的蓝牙设备 | 无 | `{"devices":[{"name":"Xiaomi Voice Remote","mac":"c0:5d:39:...","rssi":-45}]}` |
| `POST`| `/api/ble/connect` | 连接并绑定指定 MAC 遥控器 | `{"mac":"c0:5d:39:c3:94:ab"}` | `{"status":"connected"}` |
| `POST`| `/api/ble/unpair` | 解绑当前遥控器并清空 NVS | 无 | `{"status":"unpaired"}` |
| `GET` | `/api/ble/info` | 获取当前绑定的遥控器信息 | 无 | `{"name":"Xiaomi Voice Remote","mac":"c0:5d:39:...","bound":true}` |
| `POST`| `/api/ble/reconnect` | 手动触发重新扫描与连接 | 无 | `{"status":"reconnecting"}` |
| `GET` | `/api/nvs` | 获取全量 NVS 命名空间纯文本 | 无 | `{"wifi_conf":{"ssid":"..."},"keymap_conf":{"cfg_json":{...}}}` |
| `POST`| `/api/nvs/save` | 将编辑后的 JSON 写入 NVS | `{"keymap_conf":{"cfg_json":{...}}}` | `{"status":"saved","message":"NVS写入成功"}` |
| `POST`| `/api/nvs/reset` | 清空 NVS 扇区恢复出厂重启 | 无 | `{"status":"erased","message":"NVS已清空..."}` |
| `POST`| `/api/system/restart` | 软重启 ESP32-S3 | 无 | `{"status":"rebooting"}` |
---
# 九. 源码文件索引与模块依赖关系
# 十一. 源码文件索引与模块依赖关系
```text
D:\tool\RemoteMapper-ESP32/
├── platformio.ini # PlatformIO 构建配置文件 (Flash/PSRAM/编译选项)
├── platformio.ini # PlatformIO 构建配置文件 (Flash/PSRAM/编译宏)
├── default_16MB.csv # 16MB Flash 分区表
├── build.bat # 一键编译脚本
├── flash.bat # 一键烧录脚本
├── monitor.bat # 串口监视器脚本
├── test.bat # 单元测试运行脚本
├── include/
│ ├── app_config.h # 全局配置 (采样率、引脚、UUID、看门狗超时)
│ ├── app_config.h # 全局配置 (引脚、UUID、缓冲区与看门狗宏)
│ └── version.h # 固件版本号
├── src/
│ ├── main.cpp # 系统入口与 FreeRTOS 双核任务调度
│ ├── main.cpp # 系统主入口与 FreeRTOS 双核任务调度
│ ├── led_indicator.h/.cpp # WS2812 RGB 状态指示灯驱动 (蓝/绿/黄/红呼吸灯)
│ ├── log/
│ │ ├── app_log.h # 全局日志接口
│ │ └── app_log.cpp # 环形日志缓冲实现
│ ├── audio/ # DSP 音频流水线模块
│ │ ├── adpcm_decoder.h/.c # IMA-ADPCM 4-bit 解码器
│ │ ├── app_log.h # 全局格式化日志接口
│ │ └── app_log.cpp # 250 行环形内存日志缓冲区实现
│ ├── audio/ # DSP 实时音频处理流水线
│ │ ├── adpcm_decoder.h/.c # 4-bit IMA-ADPCM 流式解码器
│ │ ├── audio_filter.h/.c # Declip 尖峰消除与 3-Tap FIR 低通平滑
│ │ ├── audio_agc.h/.c # 动态 AGC 与软削波
│ │ ├── audio_agc.h/.c # 动态 AGC 增益控制与软削波
│ │ ├── audio_ring_buffer.h/.c # SPSC 无锁环形缓冲区
│ │ └── audio_pipeline.h/.c # 音频流水线协调器
│ │ └── audio_pipeline.h/.c # 音频流水线主协调器
│ ├── ble/ # 蓝牙与协议栈模块
│ │ ├── ble_remote_client.h # BLE Central 状态机
│ │ └── ble_remote_client.cpp # NimBLE 驱动、HOGP 按键与 ATVV 语音处理
│ │ ├── ble_remote_client.h # BLE Central 状态机接口
│ │ └── ble_remote_client.cpp # NimBLE 驱动、HOGP 监听与 ATVV 握手客户端
│ ├── usb/ # USB 复合设备模块
│ │ ├── usb_composite.h # USB 设备抽象接口
│ │ └── usb_composite.cpp # TinyUSB UAC 麦克风与 HID 键盘/多媒体派发
│ ├── keymap/ # 按键映射状态机
│ │ ├── key_definitions.h # 遥控器与 USB HID 键码映射表
│ │ ├── key_state_machine.h # 手势状态机接口
│ │ └── key_state_machine.c # 单击/长按/连发状态机实现
│ │ ├── usb_composite.h # TinyUSB 抽象接口
│ │ └── usb_composite.cpp # UAC 1.0 麦克风 + HID 键盘 + Consumer 控制器
│ ├── keymap/ # 按键映射与手势引擎
│ │ ├── key_definitions.h # 遥控器物理键码与 USB HID 键码定义表
│ │ ├── key_state_machine.h # Multi-Trigger 状态机接口
│ │ ├── key_state_machine.c # 单击/长按/双击手势引擎实现
│ │ ├── key_config_storage.h# 按键映射 Flash NVS 持久化接口
│ │ └── key_config_storage.cpp# 紧凑 JSON 序列化、自愈容灾与十六进制解析
│ ├── nvs/ # 底层 Flash 分区管理
│ │ ├── nvs_manager.h # NVS 遍历、读写与重置接口
│ │ └── nvs_manager.cpp # nvs_entry_find 动态扫描与安全防护
│ ├── wifi/ # 网络模块
│ │ ├── wifi_manager.h # Wi-Fi 管理接口
│ │ └── wifi_manager.cpp # AP/STA 双模、DNS 强制门户与 mDNS
│ ├── web/ # 嵌入式 Web 模块
│ │ ├── web_ui.h # 嵌入式 HTML/CSS/JS 单页应用
│ │ └── wifi_manager.cpp # AP 192.168.4.1、DNS 强制门户与 mDNS
│ ├── web/ # 嵌入式 Web 控制台
│ │ ├── web_ui.h # HTML/CSS/JS 单页应用 (PROGMEM 存储)
│ │ ├── web_server.h # WebServer 接口
│ │ └── web_server.cpp # RESTful API 路由处理
│ │ └── web_server.cpp # 18+ 条 RESTful API 路由处理
│ └── cli/ # 串口诊断模块
│ ├── cli_manager.h # CDC CLI 接口
│ └── cli_manager.cpp # JSON 格式命令行解析器
│ └── cli_manager.cpp # JSON 命令行解析器
├── pc_companion/ # PC 本地伴侣程序
│ ├── remotemapper_host.py # Win32 RegisterHotKey 高性能守护进程
│ ├── config.json # F13 ~ F24 本地脚本绑定配置文件
│ ├── start_companion.bat # 前台调试启动脚本
│ ├── silent_start.vbs # 后台静默启动脚本
│ ├── enable_autostart.bat # 注册 Windows 开机自启
│ └── build_exe.bat # PyInstaller 一键打包独立 EXE
└── test/
└── native/test_suite.py # Python 算法单元验证测试套件
└── native/test_suite.py # 原生算法单元验证测试套件
```
---
# 十. 编译、烧录与测试指南
# 十二. 编译、烧录与测试指南
### 1. 编译固件
```cmd
cd /d D:\tool\RemoteMapper-ESP32
build.bat
```
*(底层调用 `python -m platformio run -e esp32s3_n16r8`)*
@@ -277,7 +360,7 @@ build.bat
flash.bat
```
### 3. 查看串口监控日志
### 3. 查看实时串口调试日志
```cmd
monitor.bat
```
@@ -289,19 +372,19 @@ test.bat
---
# 十一. 故障排查手册与常见问题 (Troubleshooting)
# 十三. 故障排查手册与常见问题 (Troubleshooting)
### Q1: 遥控器按键没有反应,串口一直显示 `Scanning for Xiaomi Remote...`?
- **排查步骤**:
1. 遥控器是否已被电脑原本的蓝牙占用?请在 Windows 蓝牙设置中先点击「删除设备/断开连接」;
2. 同时按住遥控器的 **主页键 + 菜单键** 进行配对,直到遥控器指示灯闪烁并发出蜂鸣声;
3. 观察串口日志,ESP32 扫描到广播名含 `MI RC` 或 MAC `C0:5D:39` 会自动完成配对与服务绑定。
2. 同时按住遥控器的 **主页键 + 菜单键** 进行配对,直到遥控器指示灯快闪;
3. 网页后台进入「📡 蓝牙配对管理」,点击「🔍 扫描附近蓝牙设备」找到 `Xiaomi Voice Remote` 点击连接。
### Q2: 语音键按下后输入法唤醒了,但没有声音录入?
- **排查步骤**:
1. 打开 Windows「声音设置」➔「录音设备」,查看是否存在 `RemoteMapper Wireless Mic`;
2. 将微信输入法或讯飞输入法的麦克风直接选择为 `RemoteMapper Wireless Mic`;
3. 在 Web 控制台查看「已解码音频帧」数字是否在说话时实时增长。
1. 打开 Windows「声音设置」➔「录制设备」,查看是否存在 `RemoteMapper Mic`;
2. 将微信输入法或讯飞输入法的默认麦克风选择为 **`RemoteMapper Mic`**;
3. 确认输入法快捷键与 Web 控制台中语音键绑定的热键一致(默认为 `右Alt + 逗号`)。
### Q3: 手机连接 `RemoteMapper-AP` 后无法打开配置界面?
- **排查步骤**:
@@ -309,15 +392,12 @@ test.bat
2. 手动在手机浏览器地址栏输入 **`http://192.168.4.1`**;
3. 确保电脑/手机未开启全局代理或 VPN。
### Q4: 固件编译报错找不到 `NimBLEDevice.h` 或 `USBHIDKeyboard.h`?
### Q4: 音量加减在 Windows 下变成打开搜索栏?
- **排查步骤**:
1. 确保 `platformio.ini` 中的 `framework = arduino` 且 `lib_deps` 包含 `NimBLE-Arduino`;
2. 运行 `python -m platformio pkg install -e esp32s3_n16r8` 重新下载依赖库。
1. 检查 WebUI 下拉菜单或 NVS 中音量键的键码,音量加标准 USB Consumer 键码为 **`0x00E9` (233)**,音量减为 **`0x00EA` (234)**;切勿使用旧版错误的 `545`(`0x0221` 代表 AC Search 全局搜索)。
---
# 十二. 未来扩展与演进路线 (Roadmap)
## 📄 开源许可证
本项目遵循 [MIT License](./LICENSE) 开源许可协议。
1. **Web 端按键完全图形化拖拽自定义**:支持用户在浏览器中点击任意按键,弹出下拉框直接挑选 Windows 快捷键(如 `Ctrl+Alt+A` 截图、`Win+Shift+S` 等)并持久化到 NVS。
2. **WebSerial USB 离线免网改键**:通过浏览器 WebSerial API 直接走 USB 虚拟串口收发 JSON 改键指令,彻底无需 Wi-Fi。
3. **多设备配对管理与一键切换**:在 Web 端保存多个小米遥控器 MAC 地址并支持一键切换绑定。