BLE HID

前言

市场上有很多的 HID 设备,包括键盘,鼠标,游戏手柄等。我也做过几个这方面的项目,但是感觉一知半解,仅仅做到了会使用完成了项目,但是遇到一些问题需要很长的时间来解决。因此在这里狠狠的总结了下,写的有问题的地方也希望大家指正,一起进步。

摘要

HID 全称 Human Interface Device,翻译为人类接口设备,该术语由微软 Mike Van Flandern 提出,USB 委员会创建了一个工作组(Human Input Device) 后该工作组更名为 Human Interface Device。所以可以在 USB 委员会查找协议相关的资料, 例如 HID Usage TablesDevice Class Definition for HID 1.11。在蓝牙中有了 BLE HID,但是BLE HID 是在 USB HID 规范的基础上又做了一个规范,设备的驱动还是使用 USB HID,仅仅是在蓝牙数据通信上做的规范,如遇到蓝牙部分比较深入的问题可以参考蓝牙规范

USB HID 简介

USB 角色

  • Host 主机角色。例如: 电脑,手机,PDA 等属于 host 角色
  • Device 设备角色。例如: 键盘,鼠标,游戏手柄等与人交互属于 device 角色

HID Channel

  • HID 有两个 Channel
  1. Control Channel

  2. Interrupt Channel

  • 在这两个通道上传输数据也有两个不同的名称
    • report 在 Control Channel 传输 称为 synchronous reports
    • report 在 Interrupt Channel 传输 称为 asynchronous reports

注意: Feature report 仅仅使用 synchronous reports

HID Reports

BLE 的 HID Reports 支持 3 种,以 Host 角色来看分为 3 种 Input,Output,Feature

USB HID 协议传输数据的两种方式

  • 中断方式

​ Device(键盘)按键按下后,发送数据给 Host(电脑)

​ Host(电脑)产生中断,收到数据,解析数据后执行按键的动作

  • 查询方式

​ Host(电脑) 发送控制传输(set report)给 Device(键盘)请求发送数据

​ Device(键盘)收到后发送自己的状态给 Host(电脑)

​ Host(电脑) 收到后回复一个状态给 Device(键盘) [0 字节表示成功]

HID Report Modes

hid report modes 有两种 boot protocol 和 report protocol

为什么有这两种模式那?

这要从 USB HID 中的这两种特殊的设备,鼠标和键盘

在电脑进入 BIOS 时,鼠标和键盘也要有作用,此时不用解析设备描述符,以固定的格式发送数据保证鼠标键盘正常使用,此时使用 boot protocol 来上报数据

电脑正常启动后会解析鼠标键盘的设备描述符,此时使用 report protocol 的方式来上报数据

注意: report protocol 方式比 boot protocol 多出更多的按键

代码中具体体现
请添加图片描述

设备描述符介绍

设备描述符主要用于 Host 一端解析 Device 端发送数据

分为两类:short items 和 long items

long items 不常使用,了解也不深。等到后续使用到了再补充,本文仅介绍 short items

下文截图采用了hid1_11.pdf 第六章节部分

short items

  • 长度 1-5bytes 包含 1 或 0byte 可选数据
    请添加图片描述
  • 结构
    这里注意 bSize 的长度只有 0,1,2,4Bytes
    请添加图片描述
    根据 bType 又分为 3 类,由于文档过长这里不做截图,做了一个表格方便大家查阅
item功能
Main Items用于定义或分组特定类型的数据字段报告的描述符。分两种类型
注意:由于 bSize 不确定所以最后两字节不确定这里用 ? 来表示 二进制用 n 来表示
1. 数据类型 eg: input,output,feature
2. 非数据类型 collection ,end collection

Input: 0x8? 1000 00nn 比如按键
Output:0x9? 1001 00nn 比如键盘灯
Feature:0xb? 1011 00nn 描述可以发送到设备的配置信息
Collection: 0xa? 1010 00nn 和 End Collection 是一个组合比如把键盘的 input 和 output 设备描述符作为一个集合
End Collection: 0xc? 1100 00nn
Global Items用来选择用途页,定义数据域的长度、数量、报告 ID 等
Global Items 出现后对所有的 Mian Items 都有效,除非遇到另外一个 Global Items 来改变他
Usage Page: 0x0? 0000 01nn 用途页
Logical Minimum:0x1? 0001 01nn 逻辑最小值
Logical Maximum:0x2? 0010 01nn 逻辑最大值
Physical Minimum: 0x3? 0011 01nn 物理最小值
Physical Maxmum: 0x4? 0100 01nn 物理最大值
Unit Exponent: 0x5? 0101 01nn 以 10 为单位指数值
Unit : 0x6? 0110 01nn unit 值
Report Size: 0x7? 0111 01nn 上报数据的大小单位 bit
Report ID : 0x8? 1000 01nn 上报数据的 ID 比如鼠标键盘一起可以用 ID 区分上报的为鼠标还是键盘
Report Count: 0x9? 1001 01nn 上报数据的个数,和 report 组合可得出上报的字节大小
Push: 0xa? 1010 01nn 将 global items 放在堆栈上
Pop: 0xb? 1011 01nn 用堆栈顶部数据替换 items
Local Items定义了控件的特征,只在局部有效,遇到下一个 Main Items 有效结束
Usage: 0x0? 0000 10nn 用途
Usage Minimum: 0x1? 0001 10nn 用途最小值
Usage Maximum: 0x2? 0010 10nn 用途最大值
Designator Index: 0x3? 0011 10nn
Designator Minimum: 0x4? 0100 10nn
Designator Maximum: 0x5? 0101 10nn
String Index: 0x7?: 0111 10nn
String Minimum: 0x8? 1000 10nn
String Maxmum: 0x9? 1001 10nn
Delimiter: 0xa? 1010 10nn
  • main items 参数介绍

    Input Reports 表示 Device 上报给 Host 比如键盘按下的动作

    Onput Reports 表示 Host 发送数据给 Device
    比如键盘灯在小写状态下按下 Caps Lock 后会发送按键消息给 Host
    Host 收到后启用大写功能,发送控制键盘 LED 点亮给到键盘
    键盘收到后点亮 LED,并回复设备状态给 Host [0 字节表示成功]

    Feature Reports 表示 Host 专属双向数据通道
    USB 中只能通过 Host 控制 Device 来双向传输数据
    1.通过 get_report 来获取 Device 数据
    2.通过 set_report 来发送数据到 Device

    Collection 集合的开始相当于 (

    End Collection 集合结束相当于 )

  • main items 值介绍
    具体参见 hid1_11.pdf 30页

bit876543210
0此 bit 为 0 用一个字节表示 bit filenon-volatileno null positionpreferred statelinerano wrapabsolutearray(可以同时被触发)data(可变值)
1此 bit 为 1 用2个字节表示
buffered bytes
volatilenull stateno perferredno nlinerawraprelativevariable(只能触发一个)constant(不可变值)

0: 表示上面的属性,1:表示下面的属性
eg: 0x81 0x02

0x02 表示的属性为 data,variable,absolute, no wrap,linera, perferred state,no null position, non-volatile
请添加图片描述
请添加图片描述

long items

todo

HID 实例设备描述符解析

  • Nordic sdk17.1.0

  • ble_app_hids_keyboard 历程

  • 设备描述符代码片段截取

static uint8_t                     report_map_data[] =
    {
        0x05, 0x01,       // Usage Page (Generic Desktop)
        0x09, 0x06,       // Usage (Keyboard)
        0xA1, 0x01,       // Collection (Application)
        0x05, 0x07,       // Usage Page (Key Codes)
        0x19, 0xe0,       // Usage Minimum (224)
        0x29, 0xe7,       // Usage Maximum (231)
        0x15, 0x00,       // Logical Minimum (0)
        0x25, 0x01,       // Logical Maximum (1)
        0x75, 0x01,       // Report Size (1)
        0x95, 0x08,       // Report Count (8)
        0x81, 0x02,       // Input (Data, Variable, Absolute)

        0x95, 0x01,       // Report Count (1)
        0x75, 0x08,       // Report Size (8)
        0x81, 0x01,       // Input (Constant) reserved byte(1)

        0x95, 0x05,       // Report Count (5)
        0x75, 0x01,       // Report Size (1)
        0x05, 0x08,       // Usage Page (Page# for LEDs)
        0x19, 0x01,       // Usage Minimum (1)
        0x29, 0x05,       // Usage Maximum (5)
        0x91, 0x02,       // Output (Data, Variable, Absolute), Led report
        0x95, 0x01,       // Report Count (1)
        0x75, 0x03,       // Report Size (3)
        0x91, 0x01,       // Output (Data, Variable, Absolute), Led report padding

        0x95, 0x06,       // Report Count (6)
        0x75, 0x08,       // Report Size (8)
        0x15, 0x00,       // Logical Minimum (0)
        0x25, 0x65,       // Logical Maximum (101)
        0x05, 0x07,       // Usage Page (Key codes)
        0x19, 0x00,       // Usage Minimum (0)
        0x29, 0x65,       // Usage Maximum (101)
        0x81, 0x00,       // Input (Data, Array) Key array(6 bytes)

        0x09, 0x05,       // Usage (Vendor Defined)
        0x15, 0x00,       // Logical Minimum (0)
        0x26, 0xFF, 0x00, // Logical Maximum (255)
        0x75, 0x08,       // Report Size (8 bit)
        0x95, 0x02,       // Report Count (2)
        0xB1, 0x02,       // Feature (Data, Variable, Absolute)

        0xC0              // End Collection (Application)
    };
  • 设备描述符详解
    下表查询文档为 hut1_4.pdf文档1 表示 hid1_11.pdf文档2 表示

    源数据条目二进制格式解析内容解析说明
    0x05,0x010000 0101
    bTag: 0000 Usage Page 用途页
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x01: 查文档1第三部分(17页) Usage Pages
    为 Generic Desktop Page
    条目类型: Global
    用途页:Usage Pages
    具体用途: Generic Desktop Page 桌面应用
    0x09, 0x060000 1001
    bTag: 0000 Usage 描述用途
    bType: 10 Local 类型
    bSize: 01 数据长度 1
    0x06: 查文档1第四部分(32页) Generic Desktop Page
    为 Keyboard
    条目类型: Local
    用途页:Usage
    具体用途: Generic Desktop Page 桌面应用
    的 Keyboard 应用
    0xA1, 0x011010 0001
    bTag: 1010 Collection
    bType: 00 Main 类型
    bSize: 01 数据长度 1
    01: 查文档2 33页 和文档1 3.4.3 (26页)
    为 Application
    条目类型: Main
    开集合:Collection
    具体用途: Application
    0x05, 0x070000 0101
    bTag: 0000 Usage Page 用途页
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x07: 查文档1第三部分(17页) Usage Pages
    为 Keyboard/Keypad Page
    条目类型: Global
    用途页:Usage Pages
    具体用途: Keyboard/Keypad Page
    0x19, 0xe00001 1001
    bTag: 0001 Usage Minimum 用途最小值
    bType: 10 Local 类型
    bSize: 01 数据长度 1
    0xE0: 查文档1第十部分(94页) Keyboard LeftControl
    为键盘功能按键 左 CTRL
    条目类型: Local
    用途最小值 :Usage Minimum
    具体用途: 从 Keyboard LeftControl
    开始,往往配合 Usage Maximum 用途最大值规定用途的范围
    0x29, 0xe70010 1001
    bTag: 0010 Usage Maximum 用途最小值
    bType: 10 Local 类型
    bSize: 01 数据长度 1
    0xE7: 查文档1第十部分(95页) Keyboard Right GUI
    条目类型: Local
    用途最小值 :Usage Maximum
    具体用途: 到 Keyboard Right GUI
    结束,往往配合 Usage Minimum 用途最小值规定用途的范围
    0x15, 0x000001 0101
    bTag: 0001 Logical Minimum 逻辑最小值
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x00: 逻辑最小值 0
    文档2 35页
    条目类型: Global
    逻辑最小值 :Logical Minimum
    值: 0
    0x25, 0x010010 0101
    bTag: 0010 Logical Maximum 逻辑最大值
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x01: 逻辑最大值 1
    文档2 35页
    条目类型: Global
    逻辑最大值 :Logical Maximum
    值: 1
    0x75, 0x010111 0101
    bTag: 0111 Report Size
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x01: 上报数据的大小(单位 bit)
    文档2 35页
    条目类型: Global
    上报数据大小 :Report Size
    值: 1
    这里可以解释为 1bit 代表一个按键
    结合上文为 1 bit 表示 0xE0 - 0xE7
    8 个功能按键中的一个按顺序来
    0x95, 0x081001 0101
    bTag: 1001 Report Count
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x08: 上报数据的个数 8
    文档2 36页
    条目类型: Global
    上报数据个数 :Report Count
    值: 8
    0x81, 0x021001 0001
    bTag: 1001 Input
    bType: 01 Main 类型
    bSize: 01 数据长度 1
    0x02: 这里太多了就不一一注明
    文档2 30页
    条目类型: Main
    Input
    值: 0x02
    根据 main items 值介绍 章节部分详细解释 3 bit
    data:数值可变
    variable: 一次只能触发一个
    absolute: 绝对数值
    根据前面的描述符可以解释为
    键盘的功能键 0xE0 - 0xE7 8 个功能键,一次只能触发一个,数值是可变的
    数据补齐
    0x95, 0x011001 0101
    bTag: 1001 Report Count
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x01: 上报数据的个数 1
    文档2 36页
    条目类型: Global
    上报数据个数 :Report Count
    值: 1
    0x75, 0x080111 0101
    bTag: 0111 Report Size
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x08: 上报数据的大小(单位 bit)
    文档2 35页
    条目类型: Global
    上报数据大小 :Report Size
    值: 8
    0x81, 0x011000 0001
    bTag: 1000 Input
    bType: 01 Main 类型
    bSize: 01 数据长度 1
    0x01: 属性
    文档2 30页
    条目类型: Main
    Input
    值: 0x01
    constant 值不可变字节补齐用,无实际意义
    键盘 led
    0x95, 0x051001 0101
    bTag: 1001 Report Count
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x05: 上报数据的个数 5
    文档2 36页
    条目类型: Global
    上报数据个数 :Report Count
    值: 5
    0x75, 0x010111 0101
    bTag: 0111 Report Size
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x01: 上报数据的大小(单位 bit)
    文档2 35页
    条目类型: Global
    上报数据大小 :Report Size
    值: 1
    0x05, 0x080000 0101
    bTag: 0000 Usage Page 用途页
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x08: 查文档1第三部分(17页) Usage Pages
    为 LED Page
    条目类型: Global
    用途页:Usage Pages
    具体用途: LED Page
    0x19, 0x010001 1001
    bTag: 0001 Usage Minimum
    bType: 10 Local 类型
    bSize: 01 数据长度 1
    0x01: 用途最小值 1
    Num Lock
    文档1 97 页
    条目类型: Local
    用途:Usage Minimum
    最小值: 1
    0x29, 0x050010 1001
    bTag: 0001 Usage Maximum
    bType: 10 Local 类型
    bSize: 01 数据长度 1
    0x05: 用途最大值 5
    Compose
    文档1 97 页
    条目类型: Local
    用途:Usage Maximum
    最大值: 5
    0x91, 0x021001 0001
    bTag: 1001 Output
    bType: 10 Main 类型
    bSize: 01 数据长度 1
    0x02: 查文档2 30页条目类型: Main
    Output
    值: 0x02 led 部分属性描述
    0x95, 0x011001 0101
    bTag: 1001 Report Count
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x01: 上报数据的个数 1
    文档2 36页
    条目类型: Global
    上报数据个数 :Report Count
    值: 1
    0x75, 0x030111 0101
    bTag: 0111 Report Size
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x03: 上报数据的大小(单位 bit)
    文档2 35页
    条目类型: Global
    上报数据大小 :Report Size
    值: 3
    0x91, 0x011001 0001
    bTag: 1001 Output
    bType: 10 Main 类型
    bSize: 01 数据长度 1
    0x01: 查文档2 30页条目类型: Main
    Output
    值: 0x01 属性描述和前面键盘灯 5bit + 此处 3bit 字节补齐使用无实际意义
    0x95, 0x06001 0101
    bTag: 1001 Report Count
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x06: 上报数据的个数 6
    文档2 36页
    条目类型: Global
    上报数据个数 :Report Count
    值: 6
    0x75, 0x080111 0101
    bTag: 0111 Report Size
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x08: 上报数据的大小(单位 bit)
    文档2 35页
    条目类型: Global
    上报数据大小 :Report Size
    值: 8
    0x15, 0x000001 0101
    bTag: 0001 Logical Minimum 逻辑最小值
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x00: 逻辑最小值 0
    文档2 35页
    条目类型: Global
    逻辑最小值 :Logical Minimum
    值: 0
    0x25, 0x650010 0101
    bTag: 0010 Logical Maximum 逻辑最大值
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x65: 逻辑最大值 101
    文档2 35页
    条目类型: Global
    逻辑最大值 :Logical Maximum
    值: 101
    0x05, 0x070000 0101
    bTag: 0000 Usage Page 用途页
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x07: 查文档1第三部分(17页) Usage Pages
    为 Keyboard/Keypad Page
    条目类型: Global
    用途页:Usage Pages
    具体用途: Keyboard/Keypad Page
    0x19, 0x000001 1001
    bTag: 0001 Usage Minimum
    bType: 10 Local 类型
    bSize: 01 数据长度 1
    0x00: 用途最小值 0
    文档1第十部分(89页)
    未定义,
    条目类型: Local
    用途:Usage Minimum
    最小值: 0
    0x29, 0x650010 1001
    bTag: 0001 Usage Maximum
    bType: 10 Local 类型
    bSize: 01 数据长度 1
    0x65: 用途最大值 101
    文档1第十部分(89页) 数字表示的按键含义
    条目类型: Local
    用途:Usage Maximum
    最大值: 101
    0x81, 0x001000 0001
    bTag: 1000 Input
    bType: 01 Main 类型
    bSize: 01 数据长度 1
    0x00: 属性
    文档2 30页
    条目类型: Main
    Input
    值: 0x00
    array 方式可组合按键
    0x09, 0x050000 1001
    bTag: 0000 Usage 用途
    bType: 10 Local 类型
    bSize: 01 数据长度 1
    0x05: 查文档1第十部分(95页) keyboard b 和 B 按键
    这部分不理解 Nordic 为什么这么做
    条目类型: Local
    Usage
    值: 0x05
    0x15, 0x000001 0101
    bTag: 0001 Logical Minimum 逻辑最小值
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x00: 逻辑最小值 0
    文档2 35页
    条目类型: Global
    逻辑最小值 :Logical Minimum
    值: 0
    0x26, 0xFF, 0x00010 0110
    bTag: 0010 Logical Maximum 逻辑最大值
    bType: 01 Global 类型
    bSize: 10 数据长度 2
    0x00FF: 逻辑最大值 255
    文档2 35页
    条目类型: Global
    逻辑最大值 :Logical Maximum
    值: 256
    0x75, 0x080111 0101
    bTag: 0111 Report Size
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x08: 上报数据的大小(单位 bit)
    文档2 35页
    条目类型: Global
    上报数据大小 :Report Size
    值: 8
    0x95, 0x021001 0101
    bTag: 1001 Report Count
    bType: 01 Global 类型
    bSize: 01 数据长度 1
    0x02: 上报数据的个数 2
    文档2 36页
    条目类型: Global
    上报数据个数 :Report Count
    值: 2
    0xB1, 0x021011 0001
    bTag: 1011 Feature
    bType: 00 Main类型
    bSize: 01 数据长度 1
    0x02: 属性
    文档2 30页
    条目类型: Main
    Feature
    值: 0x02
    0xC01100 0000
    bTag: 1100 End Collection
    bType: 00 Main类型
    bSize: 00 数据长度 0
    条目类型: Main
    End Collection
    集合结束
  • usb 实用小工具 hid-descriptor-tool

demo 工程

  • nordic sdk17.1.0 裁剪后的 ble_uart 历程
  • 编译环境 armgcc
  • 工程链接
  • 注意事项
    • 广播中需要添加 hid 设备信息的内容
    • 需要添加配对绑定才能和手机系统蓝牙连接
    • 设备描述符中 input 和 output report 的个数按照 Byte 计算
    • 发送数据的格式按照设备描述符的格式来
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值