HID报文讲解
HID報文講解
1 什么是HID?
HID全稱Human Interface Device,人機接口設備,具體指鍵盤鼠標,藍牙和USB都采用相同的報文協議,https://www.usb.org/sites/default/files/documents/hid1_11.pdf 協議里有詳細描述。
2 什么是HID報文?
HID報文全稱為HID Report Description,是一段用指令和數值來描述通信數據結構的數據組,定義了由設備發給PC或手機的數據包里的數據所表示的意思,比如哪個數據是按鍵,這個是什么按鍵。
3 報文結構
Collection的意思是集合,如上圖,一個Application集用于表示一個虛擬設備,可以包含多個集合和多個報文,一個集合可以包含多個報文,報文描述的是發往PC或手里的數據的意義,也就是描述這個數據表示什么按鍵。
4 指令和數據
集合和報文是通過指令和數據來描述的,指令為一個字節,后面根據bSize跟著數據,指令結構如下:
Tag標簽,Type類型,Size表示數據的個數。
Type值有:
0 = Main
1 = Global
2 = Local
3 = Reserved
根據Type值,在不同的表格里,找Tag的意義
Main類的Tag:
Global類的Tag:
Local類的Tag:
例子:0x05, 0x01
0x09, 0x06
0x05是指令,0x01表示數據
0x05分解開,Tag=0000,Type=01,Size=01
Type=01表示Global類,然后從Global表里找到Tag=0的意思是Usage,即用例,然后在《6 用途表》里找到Global的Usage表,在根據Usage表找到數據值0x01的意思為:Generic Desktop Controls
所以,0x05, 0x01的意思是這是一個普通桌面控制器。
0x09是指令,0x06表示數據
0x09分解開,Tag=0000,Type=10,Size=01
Type=10表示Local類,然后從Local表里找到Tag=0的意思是Usage,即用例然后在《6 用途表》里,去找上面Global指定的子表Generic Desktop表,找到數據值0x06的意思為:Keyboard
所以,0x09, 0x06的意思是這是一個鍵盤。
通過上面的例子可以知道,Global即父類,Local為子類,先定義父類表包含了各子類表的名稱,子類表包含了具體的意思。
5 用途表
https://www.usb.org/sites/default/files/hut1_21_0.pdf
HID 報告描述_sK.坤-CSDN博客_hid用途表
6 簡單例子
這是一個只有一個按鍵的例子:
static uint8_t report_map_data[] =
????{
????????0x05, 0x01, ??????// Usage Page (Generic Desktop)
????????0x09, 0x06, ??????// Usage (Keyboard)
????????0xA1, 0x01, ??????// Collection (Application)
?0x85, 0x01, ??????// id?= 1
????????0x05, 0x07, ??????// Usage Page (Key codes)
????????0x09, 0x29, ??????// Usage Esc
0x15, 0x01, ??????// Logical Minimum (1)
????????0x25, 0x01, ??????// Logical Maximum (1)
????????0x95, 0x01, ??????// Report Count (1)
????????0x75, 0x08, ??????// Report Size (8)
????????0x81, 0x00, ??????// Input (Data, Array)
????????0xC0 ?????????????// End Collection (Application)
}
0x05, 0x01, ??????// Usage Page (Generic Desktop)
0x09, 0x06, ??????// Usage (Keyboard)
從父類表Usage里找到0x01,表示普通桌面控制器
從子類表Generic Desktop Page里找到0x06,表示鍵盤
0x05和0x09基本是配合使用的,先定位父表,再定位子表。
0xA1, 0x01, ??????// Collection (Application)
...
0xC0 ?????????????// End Collection (Application)
一個集合的開始和結束
0x85, 0x01, ??????// id?= 1
報文ID=1,當有多個集合時,每個集合需要分配不同的ID
0x05, 0x07, ??????// Usage Page (Key codes)
0x09, 0x29, ??????// Usage Esc
從父類表Usage里找到0x07,表示Keyboard
從子類表Keyboard/Keypad Page里找到0x29,表示鍵盤碼0x29為Esc鍵
這里定義了哪些數據要傳給PC或手機
0x15, 0x01, ??????// Logical Minimum (1)
0x25, 0x01, ??????// Logical Maximum (1)
定義傳給PC或手機的數據取值范圍,有兩種取值方式,Array和Variable,比如定義了3個按鍵,如果三個按鍵都要發出去,那么選Variable,Logical Minimum 取0,Logical Maximum 取1,0表示沒按下,1表示按下;如果只發出哪個按鍵按下,可以選Array,Logical Minimum取值1,Logical Maximum取值3,表示3個按鍵索引,發1表示第一個按鍵,發2表示第二個按鍵。
0x95, 0x01, ??????// Report Count (1)
0x75, 0x08, ??????// Report Size (8)
0x95和0x75用來表示用到多少字節,Size = 8,即一個鍵值用到8位,用1個字節來存索引,Count = 1,表示只傳一個鍵值,如果想一次傳多個鍵,則Count可以是2,3,4...。
0x81, 0x00, ??????// Input (Data, Array)
0x81, 0x00用來表示數值的意義,根據Main表,值0x00,第0位是0對應的是Data,第1位是0?對應的是Array,第二位是0對應的是Absolute,所以它是一個Data、Variable、 Absolute的類型。
Array 表示上報的值是索引,也就是說,報文的數據由1個字節組成,這個字節的值如果是1,即表示Esc鍵按下。
從上面例子可以知道,報文描述的結構是:
定義設備類型
集合{
定義報文ID
報文內容量
報文數據值
報文字節數
數據是Arrary還是Variable
???}
Arrary 表示上報1個或幾個內容,Variable表示字節數與內容量要一致,可以是位或字節量與內容量相等。
7 鍵盤例子
下面是一個鍵盤描述:
static uint8_t report_map_data[] =
????{
????????0x05, 0x01, ??????// Usage Page (Generic Desktop)
????????0x09, 0x06, ??????// Usage (Keyboard)
????????0xA1, 0x01, ??????// Collection (Application)
?0x85, 0x01, ??????// id
????????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)
????????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(1?byte)
?0xC0
}
0x05, 0x01, ??????// Usage Page (Generic Desktop)
0x09, 0x06, ??????// Usage (Keyboard)
定義設備類型
0xA1, 0x01, ??????// Collection (Application)
定義設備類型
0x85, 0x01, ??????// id
定義報文ID為1
0x05, 0x07, ??????// Usage Page (Key Codes)
0x19, 0xe0, ??????// Usage Minimum (224)
0x29, 0xe7, ??????// Usage Maximum (231)
用到按鍵碼:224、225、226、227、228、229、230、231,這些按鍵碼對應CTRL,ALT,SHIFT等按鍵
0x15, 0x00, ??????// Logical Minimum (0)
0x25, 0x01, ??????// Logical Maximum (1)
取值范圍:0和1,0表示未按下,1表示按下
0x75, 0x01, ??????// Report Size (1)
0x95, 0x08, ??????// Report Count (8)
用1位表示1個按鍵,8位表示上面8個按鍵
0x81, 0x02, ??????// Input (Data, Variable, Absolute)
一個字節表示8個按鍵狀態,即上報全部按鍵,所以選用Variable數據類型。
0x95, 0x01, ??????// Report Count (1)
0x75, 0x08, ??????// Report Size (8)
用到1個字節
0x15, 0x00, ??????// Logical Minimum (0)
0x25, 0x65, ??????// Logical Maximum (101)
取值范圍:0~101
0x05, 0x07, ??????// Usage Page (Key codes)
0x19, 0x00, ??????// Usage Minimum (0)
0x29, 0x65, ??????// Usage Maximum (101)
對應按鍵碼0~101
0x81, 0x00, ??????// Input (Data, Array) Key array(1?byte)
只上報1個按鍵,1個字節表示一個按鍵,0對應0按鍵碼,101對應101按鍵碼。
由上可知,集合里有兩部分,第一部分是CTRL、SHIFT等功能鍵,第二部分是0~101鍵碼等普通鍵,由這兩部分組合成了組合鍵,也就是說,報文是由2個字節構成,第1字節是功能鍵,第2字節是普通鍵。
8 鼠標例子
下面是一個鼠標描述:
static uint8_t report_map_data[] =
????{
0x05, 0x01, // USAGE_PAGE (Generic Desktop)
0x09, 0x02, // USAGE (Mouse)
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x02, //Report ID (2)
0x09, 0x01, // ??USAGE (Pointer)
0xa1, 0x00, // ??COLLECTION (Physical)
0x05, 0x09, // ????USAGE_PAGE (Button)
0x19, 0x01, // ????USAGE_MINIMUM (Button 1)
0x29, 0x03, // ????USAGE_MAXIMUM (Button 3)
0x15, 0x00, // ????LOGICAL_MINIMUM (0)
0x25, 0x01, // ????LOGICAL_MAXIMUM (1)
0x95, 0x03, // ????REPORT_COUNT (3)
0x75, 0x01, // ????REPORT_SIZE (1)
0x81, 0x02, // ????INPUT (Data,Var,Abs)
0x95, 0x01, // ????REPORT_COUNT (1)
0x75,?0x05, // ????REPORT_SIZE (5)
0x81, 0x03, // ????INPUT (Cnst,Var,Abs)
0x05, 0x01, // ????USAGE_PAGE (Generic Desktop)
0x09, 0x30, // ????USAGE (X)
0x09, 0x31, // ????USAGE (Y)
0x09, 0x38, // ????USAGE (Wheel)
0x15, 0x81, // ????LOGICAL_MINIMUM (-127)
0x25, 0x7f, // ????LOGICAL_MAXIMUM (127)
0x75, 0x08, // ????REPORT_SIZE (8)
0x95, 0x03, // ????REPORT_COUNT (3)
0x81, 0x06, // ????INPUT (Data,Var,Rel)
0xc0, 0xc0
}
上報4個字節的數據,第1個字節表示鼠標左鍵、右鍵和中鍵。第2個字節鼠標X偏移,第3個字節Y偏移,第4個字節中間滾輪偏移。
9 鍵盤和鼠標合一
鍵盤和鼠標合一有兩種方式,1 是都合到同一個Application集合里,2 分兩個Application集合。
從上面的分析可以知道,一個Application集合對應一個報文ID,相當于一個設備,所以兩個Application集合就是兩個設備,是USB設備的話則對應2個端點,是BLE設備的話,對應兩個特征。
方式1
static uint8_t report_map_data[] =
{
0x05, 0x01, ??????// Usage Page (Generic Desktop)
0x09, 0x06, ??????// Usage (Keyboard)
0xA1, 0x01, ??????// Collection (Application)
0x85, 0x01, ??????// id
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)
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(1?byte)
0x05, 0x01, // ? USAGE_PAGE (Generic Desktop)
0x09, 0x01, // ? USAGE (Pointer)
0xa1, 0x00, // ? COLLECTION (Physical)
0x05, 0x09, // ????USAGE_PAGE (Button)
0x19, 0x01, // ????USAGE_MINIMUM (Button 1)
0x29, 0x03, // ????USAGE_MAXIMUM (Button 3)
0x15, 0x00, // ????LOGICAL_MINIMUM (0)
0x25, 0x01, // ????LOGICAL_MAXIMUM (1)
0x95, 0x03, // ????REPORT_COUNT (3)
0x75, 0x01, // ????REPORT_SIZE (1)
0x81, 0x02, // ????INPUT (Data,Var,Abs)
0x95, 0x01, // ????REPORT_COUNT (1)
0x75,?0x05, // ????REPORT_SIZE (5)
0x81, 0x03, // ????INPUT (Cnst,Var,Abs)
0x05, 0x01, // ????USAGE_PAGE (Generic Desktop)
0x09, 0x30, // ????USAGE (X)
0x09, 0x31, // ????USAGE (Y)
0x09, 0x38, // ????USAGE (Wheel)
0x15, 0x81, // ????LOGICAL_MINIMUM (-127)
0x25, 0x7f, // ????LOGICAL_MAXIMUM (127)
0x75, 0x08, // ????REPORT_SIZE (8)
0x95, 0x03, // ????REPORT_COUNT (3)
0x81, 0x06, // ????INPUT (Data,Var,Rel)
0xC0,
0xC0
}
方式2
static uint8_t report_map_data[] =
{
0x05, 0x01, ??????// Usage Page (Generic Desktop)
0x09, 0x06, ??????// Usage (Keyboard)
0xA1, 0x01, ??????// Collection (Application)
0x85, 0x01, ??????// id
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)
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(1?byte)?
0xC0
0xa1, 0x01, // COLLECTION (Application)
0x85, 0x02, //Report ID (2)
0xa1, 0x00, // ??COLLECTION (Physical)
0x05, 0x09, // ????USAGE_PAGE (Button)
0x19, 0x01, // ????USAGE_MINIMUM (Button 1)
0x29, 0x03, // ????USAGE_MAXIMUM (Button 3)
0x15, 0x00, // ????LOGICAL_MINIMUM (0)
0x25, 0x01, // ????LOGICAL_MAXIMUM (1)
0x95, 0x03, // ????REPORT_COUNT (3)
0x75, 0x01, // ????REPORT_SIZE (1)
0x81, 0x02, // ????INPUT (Data,Var,Abs)
0x95, 0x01, // ????REPORT_COUNT (1)
0x75,?0x05, // ????REPORT_SIZE (5)
0x81, 0x03, // ????INPUT (Cnst,Var,Abs)
0x05, 0x01, // ????USAGE_PAGE (Generic Desktop)
0x09, 0x30, // ????USAGE (X)
0x09, 0x31, // ????USAGE (Y)
0x09, 0x38, // ????USAGE (Wheel)
0x15, 0x81, // ????LOGICAL_MINIMUM (-127)
0x25, 0x7f, // ????LOGICAL_MAXIMUM (127)
0x75, 0x08, // ????REPORT_SIZE (8)
0x95, 0x03, // ????REPORT_COUNT (3)
0x81, 0x06, // ????INPUT (Data,Var,Rel)
0xc0, 0xc0
}
總結
- 上一篇: 合工大苍穹战队视觉组培训Day9——相机
- 下一篇: http请求 状态码204