Files
blinky/docs/device_communication_protocol_v1.md
skiinder 3971d7c4b2 feat(proto): 添加设备通信协议v1修订版及统一帧格式
- 新增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前缀
2026-04-24 10:54:14 +08:00

9.1 KiB
Raw Blame History

下位机通信协议 v1 修订版

本版基于原 device_communication_protocol_v1.md 修订,变更点如下:

  • CDC 去掉外层协议,直接传业务消息
  • BLE GATT 改为使用 NUS (Nordic UART Service)
  • Bitmap 统一为 29 字节键盘位图格式
  • FunctionKeyEvent 不再上报单键按下/释放,改为上报全键盘位图,格式与 Bitmap 一致
  • 顶层消息增加 msg_id / reply_to
  • AckError 合并为统一 Response
  • CDCNUS 均增加统一外层帧:magic(2) + len(1) + protobuf

1. 总体原则

  • 标准键盘输入继续走 HID / BLE HID,不变。
  • 私有通信继续保留两条通道:
    • USB:走 CDC
    • BLE:走 NUS
  • 两条通道统一承载同一套 protobuf 业务消息。
  • CDCNUS 均使用完全相同的外层帧格式,帧内承载 protobuf 业务消息。
  • 当前版本不做应用层分片。

说明:

  • 顶层 protobuf 消息名改为 DeviceMessage,表示独立于具体传输通道的统一业务信封。
  • 当前版本使用统一外层帧,CDCNUS 都按完整帧进行发送与解析。

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 当前消息 ID0 表示未使用
reply_to uint32 当前消息响应的请求 ID0 表示不是响应

规则:

  • Host 发起的请求消息应填写唯一 msg_id
  • HelloRspResponse 应填写 reply_to = 原请求.msg_id
  • FunctionKeyEventLedState 等异步上报消息应设置 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 -> DeviceRX 特征写入完整帧
  • 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 字节表示 0xE00xE7 这 8 个控制键。
  • 1 到第 28 字节表示 0x000xDF
  • 位值为 1 表示该 usage 被配置为功能键。
  • 位值为 0 表示该 usage 不是功能键,继续按普通键处理。

位映射规则:

  • 0 字节:
    • bit0 -> 0xE0
    • bit1 -> 0xE1
    • ...
    • bit7 -> 0xE7
  • 1 字节:
    • bit0 -> 0x00
    • bit1 -> 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 握手

  1. Host 打开串口
  2. Host 发送 magic + len + protobuf(DeviceMessage{hello_req})
  3. Device 解析外层帧与 protobuf(DeviceMessage)
  4. Device 取出 hello_req
  5. Device 返回 magic + len + protobuf(DeviceMessage{hello_rsp})

NUS 握手

  1. Host 连接 BLE
  2. Host 发现 NUS Service
  3. Host 订阅 TX Notify
  4. Host 向 RX 写入完整帧
  5. Device 解析外层帧与 protobuf(DeviceMessage)
  6. 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
  • BitmapTimeSyncThemeRgb 处理完成后应返回 Response
  • Response.error_code = OK 表示成功。
  • 不支持的消息类型返回 Response { error_code = UNKNOWN_TYPE }
  • 长度错误、参数错误、模块未就绪时分别返回 INVALID_LENGTHINVALID_PARAMNOT_READY

示例:

  • 收到 Bitmap 成功处理
    返回 Response { error_code = OK }
  • 收到 ThemeRgb 参数非法
    返回 Response { error_code = INVALID_PARAM }