- 新增docs/device_communication_protocol_v1.md文档,定义V1修订版协议 - CDC和BLE GATT均改为直接传输业务消息,去掉外层协议封装 - BLE改为使用NUS(Nordic UART Service)替代原有GATT服务 - 统一键盘位图为29字节格式,FunctionKeyEvent改为上报全键盘位图 - 顶层消息增加msg_id和reply_to字段用于请求响应匹配 - Ack和Error合并为统一Response消息类型 - CDC和NUS均增加统一外层帧格式:magic(2) + len(1) + protobuf - 添加Proto frame常量定义及长度验证逻辑 - 更新proto文件定义,包含DeviceMessage统一信封和ResponseCode枚举 - 重构hid_flowctrl_module.c中的上下文访问方式,统一使用ctx前缀
9.1 KiB
9.1 KiB
下位机通信协议 v1 修订版
本版基于原 device_communication_protocol_v1.md 修订,变更点如下:
CDC去掉外层协议,直接传业务消息BLE GATT改为使用NUS (Nordic UART Service)Bitmap统一为 29 字节键盘位图格式FunctionKeyEvent不再上报单键按下/释放,改为上报全键盘位图,格式与Bitmap一致- 顶层消息增加
msg_id/reply_to Ack与Error合并为统一ResponseCDC与NUS均增加统一外层帧:magic(2) + len(1) + protobuf
1. 总体原则
- 标准键盘输入继续走
HID / BLE HID,不变。 - 私有通信继续保留两条通道:
USB:走CDCBLE:走NUS
- 两条通道统一承载同一套
protobuf业务消息。 CDC与NUS均使用完全相同的外层帧格式,帧内承载protobuf业务消息。- 当前版本不做应用层分片。
说明:
- 顶层
protobuf消息名改为DeviceMessage,表示独立于具体传输通道的统一业务信封。 - 当前版本使用统一外层帧,
CDC与NUS都按完整帧进行发送与解析。
2. 共享业务消息
统一的 protobuf 业务消息为 DeviceMessage,内部 oneof body 可取以下类型:
| 消息 | 方向 | 说明 |
|---|---|---|
HelloReq |
Host -> Device | 握手请求 |
HelloRsp |
Device -> Host | 握手响应 |
Bitmap |
Host -> Device | 下发功能键位图配置 |
FunctionKeyEvent |
Device -> Host | 上报当前全键盘状态位图 |
LedState |
Device -> Host | 上报键盘 LED 状态 |
TimeSync |
Host -> Device | 下发时间同步 |
ThemeRgb |
Host -> Device | 下发主题颜色 |
Response |
Device -> Host | 控制命令统一响应 |
顶层公共字段:
| 字段 | 类型 | 说明 |
|---|---|---|
msg_id |
uint32 |
当前消息 ID;0 表示未使用 |
reply_to |
uint32 |
当前消息响应的请求 ID;0 表示不是响应 |
规则:
- Host 发起的请求消息应填写唯一
msg_id。 HelloRsp与Response应填写reply_to = 原请求.msg_id。FunctionKeyEvent、LedState等异步上报消息应设置reply_to = 0。- 当前版本建议每条链路同一时刻仅保留
1条 in-flight 控制请求。
3. CDC 协议
CDC 在线路上的真实字节格式如下:
magic(2B) + len(1B) + protobuf(DeviceMessage)
约束:
magic固定为0xAA55,按小端发送,即线路字节序为0x55 0xAA。len为后续protobuf(DeviceMessage)的字节长度,范围0..64。- Host -> Device 与 Device -> Host 都发送完整帧。
- 当前版本要求单条业务消息一次完整发送,不做应用层分片与重组。
4. NUS 协议
BLE 私有通信改为使用 NUS (Nordic UART Service)。
NUS 线路上的真实字节格式如下:
magic(2B) + len(1B) + protobuf(DeviceMessage)
方向定义:
- Host -> Device:向
RX特征写入完整帧 - Device -> Host:通过
TX Notify上报完整帧
5. NUS 服务定义
Service UUID:
6E400001-B5A3-F393-E0A9-E50E24DCCA9E
Characteristic 定义:
| 名称 | UUID | 属性 | 用途 |
|---|---|---|---|
RX |
6E400002-B5A3-F393-E0A9-E50E24DCCA9E |
Write, Write Without Response |
Host -> Device |
TX |
6E400003-B5A3-F393-E0A9-E50E24DCCA9E |
Notify |
Device -> Host |
约束:
- 连接后主机必须先订阅
TX。 - 当前版本不做应用层分片。
- 因为增加了
magic + len外层帧,建议协商ATT_MTU >= 64,保证完整帧可一次发送。
6. 外层帧定义
外层帧字段如下:
| 字段 | 大小 | 说明 |
|---|---|---|
magic |
2 字节 |
固定 0xAA55,线路字节序 55 AA |
len |
1 字节 |
protobuf(DeviceMessage) 长度,最大 64 |
payload |
len 字节 |
protobuf(DeviceMessage) |
7. protobuf 字段定义
以下是业务字段语义。
HelloReq
| 字段 | 类型 | 说明 |
|---|---|---|
protocol_version |
uint32 |
当前固定为 1 |
HelloRsp
| 字段 | 类型 | 说明 |
|---|---|---|
protocol_version |
uint32 |
当前固定为 1 |
vendor_id |
uint32 |
当前建议 0x1209 |
product_id |
uint32 |
当前建议 0x0001 |
firmware_major |
uint32 |
固件主版本 |
firmware_minor |
uint32 |
固件次版本 |
capability_flags |
uint32 |
能力位 |
Bitmap
| 字段 | 类型 | 说明 |
|---|---|---|
usage_bitmap |
bytes |
固定 29 字节,表示功能键配置位图 |
语义:
Bitmap.usage_bitmap长度固定为29字节。- 第
0字节表示0xE0到0xE7这 8 个控制键。 - 第
1到第28字节表示0x00到0xDF。 - 位值为
1表示该 usage 被配置为功能键。 - 位值为
0表示该 usage 不是功能键,继续按普通键处理。
位映射规则:
- 第
0字节:bit0 -> 0xE0bit1 -> 0xE1- ...
bit7 -> 0xE7
- 第
1字节:bit0 -> 0x00bit1 -> 0x01- ...
bit7 -> 0x07
- 第
2字节:bit0 -> 0x08- ...
bit7 -> 0x0F
- 依此类推。
- 第
28字节:bit0 -> 0xD8- ...
bit7 -> 0xDF
FunctionKeyEvent
| 字段 | 类型 | 说明 |
|---|---|---|
usage_bitmap |
bytes |
固定 29 字节,表示当前全键盘状态位图 |
语义:
FunctionKeyEvent不再使用usage + action的单键事件格式。FunctionKeyEvent.usage_bitmap长度固定为29字节。- 位图编码方式与
Bitmap.usage_bitmap完全一致。 - 位值为
1表示该 usage 当前处于按下状态。 - 位值为
0表示该 usage 当前处于释放状态。 - 该消息表示一次完整键盘状态快照,而不是单个按键变化。
LedState
| 字段 | 类型 | 说明 |
|---|---|---|
led_mask |
uint32 |
NumLock/CapsLock 等位掩码 |
TimeSync
| 字段 | 类型 | 说明 |
|---|---|---|
version |
uint32 |
当前固定 1 |
flags |
uint32 |
标志位 |
timezone_min |
sint32 |
时区偏移,单位分钟 |
utc_ms |
fixed64 |
UTC 毫秒时间戳 |
accuracy_ms |
fixed32 |
精度,毫秒 |
ThemeRgb
| 字段 | 类型 | 说明 |
|---|---|---|
red |
uint32 |
0..255 |
green |
uint32 |
0..255 |
blue |
uint32 |
0..255 |
Response
| 字段 | 类型 | 说明 |
|---|---|---|
error_code |
enum ResponseCode |
响应结果;OK 表示成功,其余表示失败原因 |
8. 枚举定义
ResponseCode
| 值 | 含义 |
|---|---|
0 |
OK |
1 |
UNKNOWN_TYPE |
2 |
INVALID_LENGTH |
3 |
INVALID_PARAM |
4 |
NOT_READY |
说明:
- 原
KeyAction枚举已不再使用,因为FunctionKeyEvent改为完整位图上报。
9. CapabilityFlags 定义
HelloRsp.capability_flags 先按以下位定义:
| Bit | 含义 |
|---|---|
0 |
支持功能位图配置 |
1 |
支持时间同步 |
2 |
支持主题切换 |
3 |
支持 LED 状态上报 |
4 |
支持全键盘位图事件上报 |
当前建议最小返回值:
- 若仅先做握手:可先返回
0 - 若
Bitmap可用:打开bit0 - 若
FunctionKeyEvent全键盘位图上报可用:打开bit4
10. 握手流程
CDC 握手
- Host 打开串口
- Host 发送
magic + len + protobuf(DeviceMessage{hello_req}) - Device 解析外层帧与
protobuf(DeviceMessage) - Device 取出
hello_req - Device 返回
magic + len + protobuf(DeviceMessage{hello_rsp})
NUS 握手
- Host 连接 BLE
- Host 发现
NUS Service - Host 订阅
TX Notify - Host 向
RX写入完整帧 - Device 解析外层帧与
protobuf(DeviceMessage) - Device 通过
TX Notify发回完整帧
说明:
- 文中
protobuf(HelloReq)/protobuf(HelloRsp)指业务上发送对应的DeviceMessage消息,其oneof body分别为hello_req/hello_rsp。
11. 设备行为规则
- 上电默认所有按键都是普通键。
- 普通键的标准输入行为继续走
HID / BLE HID,不变。 - 收到
Bitmap后,位图中标记为功能键的按键按功能键逻辑处理。 FunctionKeyEvent上报的是当前全键盘状态快照,编码格式与Bitmap一致。LedState在 LED 状态变化时上报。TimeSync收到后更新时间管理模块。ThemeRgb收到后更新主题模块。- 控制类请求处理完成后统一返回
Response。 - 不支持的消息类型也应返回
Response { error_code = UNKNOWN_TYPE },不得静默丢弃。
12. Response 规则
HelloReq不返回Response,而是直接返回HelloRsp,且reply_to = HelloReq.msg_id。Bitmap、TimeSync、ThemeRgb处理完成后应返回Response。Response.error_code = OK表示成功。- 不支持的消息类型返回
Response { error_code = UNKNOWN_TYPE }。 - 长度错误、参数错误、模块未就绪时分别返回
INVALID_LENGTH、INVALID_PARAM、NOT_READY。
示例:
- 收到
Bitmap成功处理
返回Response { error_code = OK } - 收到
ThemeRgb参数非法
返回Response { error_code = INVALID_PARAM }