# USB CDC 串口通信协议规范
## 概述
本协议定义了上位机(PC)与设备之间通过USB CDC进行音频数据传输和命令控制的通信格式。协议采用二进制帧格式,支持命令、音频数据和MD5校验等功能。
## 协议版本
- 版本号:1.0
- 更新日期:2026-01-07
## 帧格式
### 基本帧结构
```
+--------+--------+--------+--------+--------+--------+
| Magic | Type | Length | Data | Check |
| 2 Bytes| 1 Byte | 4 Bytes | N Bytes| 1 Byte |
+--------+--------+--------+--------+--------+--------+
```
**注意:** 音频数据帧(Type=0x03)的Check字段固定填充为0x00,不进行实际校验计算,保持协议格式一致性。
### 字段说明
| 字段 | 长度 | 说明 |
|------|------|------|
| Magic | 2 字节 | 魔数,固定为 `0xAA55`(大端序),用于帧同步 |
| Type | 1 字节 | 数据类型,见下表 |
| Length | 4 字节 | 数据长度(小端序),仅指Data字段的长度
**命令/响应/MD5帧**: ≤64字节
|
| Data | N 字节 | 实际数据内容,长度由Length字段指定 |
| Check | 1 字节 | 校验和,对整个帧(除Check字段外)进行XOR校验
**音频帧固定填充0x00** |
**数据长度限制说明:**
- 命令请求/响应/MD5帧的Data字段最大64字节
- 这种区分设计可节省非音频帧的内存占用
### 数据类型(Type)
| 类型值 | 名称 | 方向 | 说明 |
|--------|------|------|------|
| 0x01 | CMD_REQUEST | PC → 设备 | 命令请求 |
| 0x02 | CMD_RESPONSE | 设备 → PC | 命令响应 |
| 0x03 | AUDIO_DATA | 设备 → PC | 音频数据 |
| 0x04 | MD5_DATA | 设备 → PC | MD5校验值 |
## 命令定义
### 命令码
| 命令码 | 名称 | 说明 |
|--------|------|------|
| 0x01 | CMD_START_RECORD | 开始录音 |
| 0x02 | CMD_STOP_RECORD | 停止录音 |
| 0x03 | CMD_QUERY_STATUS | 查询状态 |
### 命令请求格式(CMD_REQUEST)
**Data字段格式:**
```
+--------+--------+
| CmdID | Params |
| 1 Byte | N Bytes|
+--------+--------+
```
- **CmdID**: 命令码
- **Params**: 命令参数(可选,长度根据具体命令而定)
### 命令响应格式(CMD_RESPONSE)
**Data字段格式:**
```
+--------+--------+--------+
| CmdID | Status | Data |
| 1 Byte | 1 Byte | N Bytes|
+--------+--------+--------+
```
- **CmdID**: 对应的命令码
- **Status**: 状态码(0x00=成功,0x01=失败,0x02=忙碌,0x03=不支持)
- **Data**: 响应数据(可选)
### 状态码定义
| 状态码 | 名称 | 说明 |
|--------|------|------|
| 0x00 | STATUS_OK | 命令执行成功 |
| 0x01 | STATUS_ERROR | 命令执行失败 |
| 0x02 | STATUS_BUSY | 设备忙碌 |
| 0x03 | STATUS_UNSUPPORTED | 不支持的命令 |
## 数据格式
### 音频数据(AUDIO_DATA)
**Data字段格式:**
```
+--------+--------+
| SeqNum | PCM |
| 4 Bytes| N Bytes|
+--------+--------+
```
- **SeqNum**: 序列号(小端序),用于检测丢包,从0开始递增
- **PCM**: 原始PCM音频数据
**注意:** 音频数据帧保留Check校验字节,但固定填充为0x00,不进行实际校验计算。这样保持协议格式一致性,数据完整性由最终的MD5校验保证。
### MD5数据(MD5_DATA)
**Data字段格式:**
```
+--------+
| MD5 |
|16 Bytes|
+--------+
```
- **MD5**: 音频数据的MD5哈希值(128位)
## 通信流程
### 开始录音流程
```
PC 设备
| |
|---- CMD_START_RECORD ---->|
| | 开始录音
|<--- CMD_RESPONSE(OK) -----|
| |
|<--- AUDIO_DATA(SeqNum=0)--|
|<--- AUDIO_DATA(SeqNum=1)--|
|<--- AUDIO_DATA(SeqNum=2)--|
| ... |
```
### 停止录音流程
```
PC 设备
| |
|---- CMD_STOP_RECORD ----->|
| | 停止录音
|<--- AUDIO_DATA(last) -----|
|<--- MD5_DATA -------------|
|<--- CMD_RESPONSE(OK) -----|
| |
```
### 查询状态流程
```
PC 设备
| |
|---- CMD_QUERY_STATUS ---->|
| |
|<--- CMD_RESPONSE ---------|
| (Status + Data) |
| |
```
**查询状态响应Data格式:**
```
+--------+--------+--------+--------+
| State | TotalBytes | SeqNum |
| 1 Byte | 4 Bytes | 4 Bytes|
+--------+--------+--------+--------+
```
- **State**: 当前状态(0x00=空闲,0x01=正在录音)
- **TotalBytes**: 已传输的总字节数(小端序)
- **SeqNum**: 当前序列号(小端序)
## 校验算法
### XOR校验
对除Check字段外的所有字节进行XOR运算:
```c
uint8_t calculate_checksum(uint8_t *data, uint32_t len) {
uint8_t checksum = 0;
for (uint32_t i = 0; i < len; i++) {
checksum ^= data[i];
}
return checksum;
}
```
### MD5校验
使用标准MD5算法对所有音频数据进行校验:
1. 设备端:对发送的所有PCM数据进行MD5计算
2. 停止录音后,设备发送MD5_DATA帧
3. PC端:对接收的所有PCM数据进行MD5计算并与设备端发送的MD5对比
## 示例
### 示例1:开始录音命令
**PC发送:**
```
AA 55 01 01 00 00 00 01 FA
```
解析:
- Magic: `AA 55`
- Type: `01` (CMD_REQUEST)
- Length: `01 00 00 00` (1字节,小端序)
- Data: `01` (CMD_START_RECORD)
- Check: `FA` (XOR校验)
**设备响应:**
```
AA 55 02 02 00 00 00 01 00 F8
```
解析:
- Magic: `AA 55`
- Type: `02` (CMD_RESPONSE)
- Length: `02 00 00 00` (2字节)
- Data: `01 00` (CmdID=0x01, Status=0x00成功)
- Check: `F8`
### 示例2:音频数据
**设备发送:**
```
AA 55 03 08 00 00 00 00 00 00 00 XX XX XX XX
```
解析:
- Magic: `AA 55`
- Type: `03` (AUDIO_DATA)
- Length: `08 00 00 00` (8字节)
- Data: `00 00 00 00 XX XX XX XX` (SeqNum=0, PCM数据4字节)
- Check: **无** (音频帧不包含校验字节)
### 示例3:MD5数据
**设备发送:**
```
AA 55 04 10 00 00 00 [16字节MD5] XX
```
解析:
- Magic: `AA 55`
- Type: `04` (MD5_DATA)
- Length: `10 00 00 00` (16字节)
- Data: 16字节MD5值
- Check: `XX`
## 错误处理
### 帧错误
1. **魔数错误**:丢弃当前字节,继续搜索魔数
2. **校验错误**:丢弃整个帧,请求重传(可选)
3. **长度异常**:丢弃整个帧
### 超时处理
- **命令超时**:PC端发送命令后,2秒内未收到响应视为超时
- **数据超时**:录音过程中,5秒内未收到数据视为断连
### 序列号检查
- PC端应检查音频数据的SeqNum是否连续
- 如果发现跳号,说明有数据丢失
## 实现注意事项
### 设备端(C语言)
1. **内存管理**:使用环形缓冲区管理数据帧
2. **多线程**:命令处理和数据发送应分开不同任务
3. **优先级**:命令处理优先级应高于音频数据发送
4. **MD5计算**:使用增量方式计算MD5,避免一次性读取所有数据
### PC端(Python)
1. **异步接收**:使用独立线程接收数据
2. **帧解析**:实现状态机进行帧解析,处理粘包/拆包
3. **超时机制**:实现命令超时和数据超时检测
4. **MD5对比**:实时计算接收数据的MD5,录音结束后对比
## 扩展性
协议预留了扩展空间:
1. **命令扩展**:可以添加新的命令码(0x04-0xFF)
2. **数据类型扩展**:可以添加新的数据类型(0x05-0xFF)
3. **参数扩展**:每个命令的Params字段可以自定义格式
## 参考实现
- 设备端实现:[src/middleware/usb/app_usb_cdc.c](../src/middleware/usb/app_usb_cdc.c)
- PC端实现:[tools/audio/serial_capture.py](../tools/audio/serial_capture.py)
- 协议库:[src/middleware/usb/cdc_protocol.c](../src/middleware/usb/cdc_protocol.c)
## 版本历史
| 版本 | 日期 | 说明 |
|------|------|------|
| 1.0 | 2026-01-07 | 初始版本,定义基本协议格式和命令 |
## 联系方式
如有问题或建议,请联系开发团队。