# ESPRCCar - ESP32-S3 遥控设备固件

## 1. 项目用途

本项目是基于 ESP32-S3 的设备控制固件，**编译期三选一**链路模式（未选中的链路代码不会编入固件）：

| 模式 | menuconfig | 说明 |
|------|------------|------|
| **WiFi + MQTT** | `APP_LINK_WIFI` | STA + MQTT JSON；OTA 走 HTTPS |
| **BLE** | `APP_LINK_BLE` | NimBLE GATT JSON；OTA 走 0xFFE2 二进制流 |
| **UART** | `APP_LINK_UART` | UART1（GPIO17/18）JSON + `\n`；OTA 与 BLE 相同协议 |

设备控制指令统一由 `remote_control` 模块处理。Android 对接说明见 **`docs/Android端设备对接文档_v1.0.1.md`**（含 WiFi / BLE / UART 三章）。

## 2. 目录结构（核心）

- `main/main.c`：最小入口，仅调用 `app_run()`。
- `main/app`：应用流程与模式切换入口（`app_run()` 位于 `main/app/app_run.c`）。
- `main/core`：系统级初始化（NVS/SPIFFS/事件循环）与 FreeRTOS 任务统一管理（`task_manager.c`）。
- `main/provision`：配网/配参门户（SoftAP + HTTP + DNS 劫持）。
- `main/link_wifi`：MQTT 连接、心跳、消息处理（仅 `APP_LINK_WIFI` 编译）。
- `main/link_ble`：NimBLE 广播、连接、GATT 写入处理（仅 `APP_LINK_BLE` 编译）。
- `main/link_uart`：UART1 串口 JSON/OTA（仅 `APP_LINK_UART` 编译）。
- `main/protocol`：跨链路共用 JSON 协议解析与执行。
- `main/drivers`：驱动管理层与通用驱动能力。
- `main/drivers/gpiotrol/devices`：具体设备策略（按型号拆分）。
- `www`：配网页静态资源（SPIFFS 镜像来源）：`index.html`（WiFi）、`index_ble.html`（BLE）、`index_uart.html`（UART，仅设备号）。

### 2.1 FreeRTOS 任务统一管理

自建 FreeRTOS 任务统一在 `main/core/task_manager.c` 的任务表中维护：任务名、栈大小、优先级、核心绑定都集中在这里。业务模块只调用 `app_task_start(APP_TASK_xxx, task_entry, arg, handle)`，不要直接调用 `xTaskCreate()`。

当前已纳管任务包括：DNS、按键监控、BLE 心跳、MQTT 心跳、MQTT 初始化、MQTT 异常监控、OTA 信息延迟上报、UART 通信示例。NimBLE Host 任务通过 `app_task_start_nimble_host()` 统一从任务管理器启动。

## 3. 多设备扩展设计

为支持后续新增设备，项目按“内核分层”思路拆分为：

- `core`：系统初始化（类似内核 init）。
- `drivers`：驱动管理与硬件抽象（类似子系统层）。
- `drivers/.../devices`：具体设备实现（类似具体驱动）。
- `protocol/link/app`：协议、链路、业务层。

其中 `gpiotrol` 已拆分为“通用 PWM 底座 + 设备策略”：

- `main/drivers/gpiotrol/rc_pwm_control.c`：统一 RC 车 PWM 控制（含 6 路 50Hz 初始化、AUX 角色选择、PID 接口、策略分发）。
- `main/drivers/driver_manager/`：统一初始化并绑定设备策略（业务层不直接碰具体驱动细节）。
- `main/drivers/gpiotrol/device_drive.h`：设备策略接口定义（`stop/control/shot`）。
- `main/drivers/gpiotrol/devices/1101/`、`devices/1102/`：各车型控制映射。

当前统一引脚约定（均为 50Hz）：
- 驱动芯片1：`IO10`、`IO21`
- 驱动芯片2：`IO11`、`IO12`
- AUX：`IO15`、`IO16`（在 `menuconfig` 中分别选择舵机/电调）

`IO15/IO16` 初始化规则：
- 设为舵机：初始化到 90 度（1500us）
- 设为电调：初始化到 1500us 中位

新增设备建议流程：

1. 新建 `device_xxxx.c/.h`，实现 `device_xxxx_get_ops()`。
2. 在 `rc_pwm_control.c` 的型号选择逻辑里增加映射。
3. 在 `main/CMakeLists.txt` 加入对应源码文件。
4. 保持 `remote_control` 协议层不变，避免影响 App/BLE/WiFi 上层。

## 4. 构建类型与优化选项（Debug / Release）

本项目支持两种构建类型，通过 `menuconfig` → `robot-esp32s3` → **编译优化级别** 选择：

| 构建类型 | 优化级别 | 日志输出 | 适用场景 |
|----------|----------|----------|----------|
| **Debug** | -Og | 完整 ESP_LOG 输出 | 开发调试 |
| **Release** | -Os | **默认关闭 UART 控制台**；W/E 经 BLE **0xFFE3** Notify | 量产发布 |

### 4.1 配置说明

```bash
idf.py menuconfig
# → robot-esp32s3 → 编译优化级别
#   - Debug（Og 优化，调试）
#   - Release（Os 优化，最小体积）
```

### 4.2 Release 模式下串口使用选项

Release 默认（`sdkconfig.defaults.release`）：**`CONFIG_ESP_CONSOLE_NONE`**，不向 UART 打印；告警/错误通过 **0xFFE3** 即时 Notify（见 BLE 文档 §3.5）。

仅在 **Release** 构建时可选手动启用：

> **调试打印串口作为普通通信串口使用（仅 Release 有效）**
> - 默认：未选中 → 无 UART 日志（推荐量产）
> - 选中 → **UART0** 由 `uart_comm` 接管做普通收发

本项目使用 **UART0**（默认下载/调试串口）：
- TX = GPIO43，RX = GPIO44（ESP32-S3 固定）
- Debug 模式：正常打印日志
- Release + 通信模式：UART0 转为普通通信口，可用 `uart_comm.h` 收发数据

### 4.3 构建命令示例

**Debug 版本（默认）：**
```bat
idf.py build
```

**Release 版本（Os 优化）：**
```bat
# 方式1：在 menuconfig 中选择 Release，然后构建
idf.py build

# 方式2：使用 Release 配置覆盖文件（CI/CD 推荐）
idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.release" build
```

## 5. 文档索引（docs/）

项目文档统一放在 `docs/` 目录，按需查阅：

| 文档 | 内容 |
|------|------|
| [`安装与配网指南.md`](docs/安装与配网指南.md) | **安装必读**：环境、编译烧录、三种模式配网页与按键配网、量产包 |
| [`Android端设备对接文档_v1.0.1.md`](docs/Android端设备对接文档_v1.0.1.md) | **Android 必读**（固件 **1.0.1**）：**WiFi/MQTT** §8、**BLE** §2～§6、**UART** §7 |
| `Android端蓝牙对接文档.md` | 旧名索引，请改用 `Android端设备对接文档_v1.0.1.md` |
| `firmware/README.md` | **Git 发布固件包**：OTA 用 `ESPRCCar.bin`、量产烧录用 `factory/` 全套 bin（无需克隆者本地编译） |
| `编译类型与UART模式配置指南.md` | Debug/Release 构建、UART0 调试口复用、日志配置 |

### 5.1 BLE 功能速查（基于 NimBLE）

- **0xFFE1**：UTF-8 JSON 控制通道（与 MQTT 共用 `remote_control` 协议）
- **0xFFE2**：OTA 固件二进制流（opcode: 0x01 开始、0x02 数据、0x03 结束），受 `APP_BLE_OTA` 控制
- **0xFFE3**：心跳（`message_type=1`，约 3s）+ 告警/错误（`4`/`5`，出现时即时 Notify）
- **0xFFE4**：OTA 状态 JSON（Read + Notify，每包应答进度）

> 详见 `docs/Android端设备对接文档_v1.0.1.md` §3.2 ~ §3.6

## 6. 构建与烧录（Windows）

完整步骤（环境、链路模式、配网、量产）见 **[`docs/安装与配网指南.md`](docs/安装与配网指南.md)**。

```bat
cd /d C:\Users\17122\esp\v5.5.1\esp-idf
call export.bat
cd /d d:\myproject\esp32project\Android_control_driver
idf.py build
idf.py -p COM16 flash
```

默认链路为 **UART**（`sdkconfig.defaults` 中 `CONFIG_APP_LINK_UART=y`）。切换模式后建议 `idf.py fullclean` 再编译。

如串口连接失败，请优先检查：数据线、端口号、下载模式（BOOT/RESET）。

## 7. 配网速查

| 模式 | 热点页 | 必填 |
|------|--------|------|
| WiFi | `index.html` | WiFi SSID/密码 + 设备 ID |
| BLE | `index_ble.html` | 设备 ID + 蓝牙广播名 |
| UART | `index_uart.html` | **仅设备 ID** |

手机连热点 `esp32-apconfig` → 打开 **http://192.168.4.1**。UART 模式长按 **GPIO4** 约 2 秒可重新配网。

## 8. 固件文件与烧录方式

### 8.1 编译生成的文件

执行 `idf.py build` 后，`build/` 目录生成关键文件：

| 文件 | 说明 | 用途 |
|------|------|------|
| `ESPRCCar.bin` | **应用固件**（6MiB 以内） | **BLE OTA 使用此文件**；串口烧录也用它 |
| `ESPRCCar.elf` | ELF 调试文件 | GDB 调试、崩溃分析 |
| `bootloader/bootloader.bin` | 启动引导程序 | 串口烧录时需要 |
| `partition_table/partition-table.bin` | 分区表 | 串口烧录时需要 |
| `flash_args` / `flasher_args.json` | 烧录参数 | 内含各文件地址 |

> 项目名 `ESPRCCar` 来自 `CMakeLists.txt` 中的 `project(ESPRCCar)`

### 8.2 串口烧录（USB 线刷）

**方式1：idf.py（推荐开发阶段）**

```bat
idf.py -p COM16 flash           :: 烧录应用 + 分区表 + bootloader
idf.py -p COM16 flash_app       :: 只烧应用（保留原分区表）
idf.py -p COM16 flash_monitor   :: 烧录并打开串口监控
```

**方式2：esptool.py（生产/离线烧录）**

```bat
:: 整片烧录（含 bootloader、分区表、应用）
esptool.py --chip esp32s3 --port COM16 write_flash 0x0 build/ESPRCCar.bin

:: 或按分区烧录（参考 build/flash_args 中的地址）
esptool.py --chip esp32s3 --port COM16 write_flash \
    0x1000 build/bootloader/bootloader.bin \
    0x8000 build/partition_table/partition-table.bin \
    0x20000 build/ESPRCCar.bin
```

**进入下载模式**：
- 按住 **BOOT** 键 → 按 **RESET** 键 → 松开 **BOOT** 键
- 或 ESP32-S3 某些开发板自动进下载模式

### 8.3 OTA 升级

本项目支持 **BLE GATT OTA**（通过手机 App）：

| 方式 | 通道 | 文件 | 说明 |
|------|------|------|------|
| BLE OTA | 0xFFE2 | `firmware/release/ota/ESPRCCar.bin`（或本地 `build/ESPRCCar.bin`） | 手机分包推送，设备写入 OTA 分区后重启 |

**BLE OTA 流程**（手机端）：
1. 连接设备 → 使能 0xFFE4 Notify（进度/状态）
2. 发送 `0x01` + 4字节固件长度（小端）
3. 循环发送 `0x02` + 数据包（每包 ≤511 字节）
4. 发送 `0x03` 结束，设备校验后自动重启

> 详细协议见 `docs/Android端设备对接文档_v1.0.1.md` **§3.4～3.4.11**（含 MTU、ATT 错误、排错）及 **§5.7**（Android 测试步骤）；UART 见 **§7**；WiFi/MQTT 见 **§8**

**注意**：
- OTA 文件必须是 **应用镜像**（`.bin`），不是合并后的整片 flash 镜像
- 文件大小必须 ≤ 分区表中的 OTA 分区大小（当前 6MiB）
- 当前 BLE OTA 开关由 `APP_BLE_OTA` 控制（默认启用）

### 8.4 生产烧录建议

**批量烧录方案**（推荐直接使用仓库内已编译包，见 `firmware/README.md`）：

1. **从 Git 下载** `firmware/release/factory/` 下全部 `.bin`，或克隆仓库后进入该目录。
2. **Flash Download Tools**（乐鑫官方 GUI 工具）
   - 加载 `bootloader.bin`、`partition-table.bin`、`ESPRCCar.bin`、`ota_data_initial.bin`、`storage.bin`
   - 地址见 `firmware/release/factory/flash_args.txt`（与 `build/flash_args` 一致，Bootloader 在 `0x0`）
3. **乐鑫 Flash Download Tools**：加载 `firmware/release/factory/` 下各 bin，地址见 `flash_args.txt` 或 `firmware/README.md`
4. **更新 Git 上的 bin**：`idf.py build` 后双击或运行 `scripts\copy_firmware_release.bat`（**不会**在每次编译时自动执行），核对 `firmware/release/VERSION.txt` 与 `manifest.json` 再提交

3. **JTAG 烧录**（Debug 调试时）
   - 使用 ESP-Prog 或内置 JTAG
   - `idf.py gdb` / `idf.py openocd`
