# 编译类型与 UART 模式配置指南

本文档说明如何使用项目的 **Release/Debug 构建类型** 和 **调试串口复用** 功能。

> **安装、烧录、三种链路模式选择与 SoftAP 配网**（含 UART 仅填设备号）见 **[`安装与配网指南.md`](安装与配网指南.md)**。  
> 本文中的「UART」若未特别说明，指 **UART0 调试口（GPIO43/44）**；与业务链路 **`APP_LINK_UART`（UART1，GPIO17/18）** 不是同一路。

---

## 0. 串口是什么？和板子上的 RX1、TX1 是什么关系？

日常说的 **「串口」** 一般指 **UART**（异步串行口）：用一根 **TX（发）** 和一根 **RX（收）** 加上地线，按约定波特率（如 115200）收发字节流。

### 本项目使用 UART0（默认调试串口）

| 项目 | 值 | 说明 |
|------|-----|------|
| **UART** | UART0 | ESP32-S3 默认下载/调试串口 |
| **TX** | GPIO43 | 固定引脚，不可更改 |
| **RX** | GPIO44 | 固定引脚，不可更改 |
| **用途** | 调试打印 / 普通通信 | Release 模式下可切换 |

**UART0 是 ESP32-S3 的默认串口**，用于：
- 固件下载（boot 模式）
- `ESP_LOG` / `printf` 调试输出
- 本项目 Release 模式下可选为普通通信串口

---

## 1. 功能概述

通过 `menuconfig` 可以选择：

1. **Debug 构建**（默认）：-Og 优化，完整调试日志输出
2. **Release 构建**：-Os 优化，最小代码体积，可选将 **指定 UART** 用作通信串口

---

## 2. 配置方法

### 2.0 PowerShell 提示找不到 `...\esp\esp-idf\tools\idf.py`

说明当前终端里 **`IDF_PATH` 或 `idf.py` 启动方式仍指向不存在的目录**（常见为旧路径 `C:\Users\<你>\esp\esp-idf`），而本机 ESP-IDF 实际在 **`...\esp\v5.5.1\esp-idf`**（与 `.vscode/settings.json` 中 **`idf.espIdfPathWin`** 一致）。

**处理**：在 Windows **用户环境变量**中将 **`IDF_PATH`** 改为上述真实 **`esp-idf` 根目录**；打开「开始菜单」里的 **「ESP-IDF PowerShell / CMD」**（随 ESP-IDF 安装生成）再执行 `idf.py`，或删除 PATH 里指向旧 `esp-idf` 的重复项后重开终端。Cursor/VS Code 也可用扩展命令 **「ESP-IDF: Open ESP-IDF Terminal」**。

### 2.1 使用 Menuconfig（推荐开发时使用）

```bash
idf.py menuconfig
# → robot-esp32s3
#   → 编译优化级别
#       - Debug（Og 优化，调试）
#       - Release（Os 优化，最小体积）
#
# 选择 Release 后会出现额外选项：
#   → 调试打印串口作为普通通信串口使用（仅 Release 有效）
```

### 2.2 使用 SDKCONFIG 覆盖文件（推荐 CI/CD 使用）

**Debug 版本：**
```bash
# 使用默认 sdkconfig.defaults
idf.py build
```

**Release 版本：**
```bash
# 方式1：在 menuconfig 中选择 Release 后保存
idf.py build

# 方式2：使用覆盖文件（自动化构建）
idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.release" build
```

---

## 3. Release 模式下 UART 串口两种工作模式

### 3.1 模式 A：Release 默认（无 UART 日志，BLE 转发 W/E）

**配置：**
- `ROBO_APP_FW_RELEASE=y`
- 使用 `sdkconfig.defaults.release`（含 **`CONFIG_ESP_CONSOLE_NONE=y`**）
- `APP_UART_MODE_DEBUG=n`（默认）

**行为：**
- **不向串口输出** `ESP_LOG`（避免无人读取时阻塞 BLE）
- `ESP_LOGW` / `ESP_LOGE` 在 BLE 已连接时经 **0xFFE3 Notify** 推送（`message_type` 4/5，见 `docs/Android端设备对接文档_v1.0.1.md` §3.5-B）
- 周期心跳仍为 **0xFFE3**，约 3s，`message_type` 1

### 3.2 模式 B：UART0 转为普通通信串口

**配置：**
- `ROBO_APP_FW_RELEASE=y`（menuconfig 中「编译优化级别」选 Release）
- `APP_UART_MODE_DEBUG=y`（启用此选项）

**行为：**
- **UART0** 由 `uart_comm` 接管做普通收发（GPIO43/44）
- `ESP_LOG` / `printf` 等日志输出不可用（没有日志输出）
- 代码中使用 `uart_comm.h` 接口进行数据传输
- 固件下载仍使用 UART0（bootrom 固定）

**完整配置步骤：**
```bash
idf.py menuconfig
# 1. robot-esp32s3 → 编译优化级别 → Release
# 2. robot-esp32s3 → 调试打印串口作为普通通信串口使用 → 启用
# 3. Component config → ESP System Settings → Channel for console output → None
# 保存并退出
```

---

## 4. 代码中的条件编译

项目提供了 `build_config.h` 头文件，包含预定义的宏：

### 4.1 头文件位置

```c
#include "core/build_config.h"
```

### 4.2 可用宏定义

| 宏 | 含义 |
|----|------|
| `BUILD_IS_RELEASE` | 1=Release 构建，0=Debug 构建 |
| `BUILD_IS_DEBUG` | 1=Debug 构建，0=Release 构建 |
| `UART_MODE_COMMUNICATION` | 1=UART 作为通信串口，0=默认 |
| `UART_MODE_DEBUG` | 1=调试串口模式，0=通信模式 |
| `BUILD_SERIAL_LOG_ENABLED` | 1=可向 UART 打日志，0=Release 默认关闭 |

### 4.3 条件日志宏

无论何种模式，都可以使用统一的日志宏：

```c
LOG_I(TAG, "信息日志");    // Info 级别
LOG_W(TAG, "警告日志");    // Warning 级别
LOG_E(TAG, "错误日志");    // Error 级别
LOG_D(TAG, "调试日志");    // Debug 级别
```

在 **Release + UART 通信模式** 下，这些宏自动展开为空操作（不输出任何内容）。

在其他模式下，这些宏等价于 `ESP_LOGI` / `ESP_LOGW` / `ESP_LOGE` / `ESP_LOGD`。

### 4.4 UART 通信 API（仅在 Release+通信模式下有效）

```c
#include "drivers/uart_comm/uart_comm.h"

/* 初始化（波特率，0 表示使用默认值 115200） */
esp_err_t err = uart_comm_init(115200);

/* 发送数据 */
uart_comm_send((uint8_t*)data, len);

/* 发送字符串 */
uart_comm_send_string("Hello\r\n");

/* 接收数据（非阻塞，timeout_ms 超时） */
uint8_t buf[256];
int len = uart_comm_receive(buf, sizeof(buf), 100);  // 100ms 超时

/* 反初始化 */
uart_comm_deinit();
```

在非 Release+通信模式下，这些函数返回 `ESP_ERR_NOT_SUPPORTED` 或 -1。

---

## 5. 完整示例代码

### 5.1 条件编译示例

```c
#include "core/build_config.h"
#include "drivers/uart_comm/uart_comm.h"

void my_init(void)
{
#if BUILD_IS_RELEASE
    #if UART_MODE_COMMUNICATION
        /* Release + 通信模式：初始化 UART 通信 */
        uart_comm_init(115200);
        uart_comm_send_string("System started\r\n");
    #else
        /* Release + 调试模式：减少日志输出 */
        ESP_LOGI(TAG, "Release build started");
    #endif
#else
    /* Debug 模式：完整日志 */
    ESP_LOGI(TAG, "Debug build started");
#endif
}
```

### 5.2 使用统一日志宏（推荐）

```c
#include "core/build_config.h"

void my_function(void)
{
    /* 在任何构建类型下都可以使用，自动适配 */
    LOG_I(TAG, "This is info message");
    LOG_W(TAG, "This is warning message");
    LOG_E(TAG, "This is error message");
}
```

---

## 6. 构建输出对比

### 6.1 Debug 构建

```
[1/1] Linking project.elf
构建完成，固件大小约：
  - .bin 文件：~2.5MB
  - 内存占用：~180KB
```

### 6.2 Release 构建

```
[1/1] Linking project.elf
构建完成，固件大小约：
  - .bin 文件：~2.1MB（减少约 15-20%）
  - 内存占用：~150KB
```

---

## 7. 注意事项

### 7.1 从 Debug 切换到 Release 时

1. 执行完整清理：
   ```bash
   idf.py fullclean
   ```

2. 如果使用 `sdkconfig.defaults.release`，确保重新生成 `sdkconfig`：
   ```bash
   rm sdkconfig
   idf.py -DSDKCONFIG_DEFAULTS="sdkconfig.defaults;sdkconfig.defaults.release" build
   ```

### 7.2 UART 通信模式下的调试

启用 `APP_UART_MODE_DEBUG` 后：
- **无法使用 `idf.py monitor` 查看日志**（因为没有日志输出）
- **烧录时仍然使用 UART0**，请确保外部设备在烧录时不会干扰
- 建议在开发阶段先用 **模式 A（调试打印）** 验证功能，再切换到 **模式 B（通信）**

### 7.3 推荐的开发流程

```
阶段1：功能开发
  → 使用 Debug 构建，完整日志输出
  
阶段2：性能优化
  → 使用 Release + 调试打印模式
  → 验证功能正确性，检查是否有 Release 模式特有 bug
  
阶段3：量产准备
  → 使用 Release + UART 通信模式（如需要）
  → 最终验证，关闭所有调试功能
```

---

## 8. 故障排除

### Q: 切换到 Release 后代码运行异常？

A: 检查是否有以下问题：
- 断言被禁用导致错误未捕获（`CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT=y`）
- 代码依赖 Debug 模式下的未初始化变量清零（Debug 模式通常内存初始化为 0）
- 优化导致的时序问题（如未加 `volatile` 的硬件寄存器访问）

### Q: 启用 UART 通信模式后无法烧录？

A: 正常现象。启用 `CONFIG_ESP_CONSOLE_UART_NONE` 后固件启动时不会占用 UART0，但 **esptool 烧录过程不受影响**。烧录时确保：
- 外部设备未连接 UART0，或已断开
- 正确进入下载模式（BOOT 按钮）

### Q: 如何临时恢复日志输出进行调试？

A: 在 `menuconfig` 中：
1. 关闭 **调试打印串口作为普通通信串口使用**
2. 或重新选择 **Debug** 构建类型

---

**文档版本**：1.1  
**最后更新**：2026年5月
