HID 報告描述 2


1、樣例解讀

下面是一個僞代碼描述的樣例,其中涉及到的頁碼可查看第 5 段用途表:

Usage Page (Generic Desktop), //定位到Generic Desktop頁,這個相當於指針跳轉一樣的東西

Usage (Mouse), //指定Generic Desktop裏的mouse,表示這是一個鼠標

Collection (Application), // Collection Application,是對Mouse的解釋

 Usage (Pointer), //表示指針形式

Collection (Physical), // Collection Physical,是對Pointer的解釋

  Report ID (0A), //id爲0x0A的報告

  Usage (X), Usage (Y), //上報X,Y兩個數據

  Logical Minimum (-127), //Report data values range from -127

  Logical Maximum (127), //X,Y的取值範圍是-127~127

  Report Size (8), Report Count (2), //總共要上報2個字節,即x一個字節,y一個字節

  Input (Data, Variable, Relative), //將X,Y這兩個字節添加到0x0A的報告裏,且這兩個值是可寫並且是相對的

  Logical Minimum (0),

  Logical Maximum (1), //下面Button的取值範圍是0~1

  Report Size (1), Report Count (3), //3個1位的數據

  Usage Page (Button Page),//是一個BUTTON

  Usage Minimum (1),

  Usage Maximum (3),//共有 BUTTON1~BUTTON3,即總共有 3 個 BUTTON

Input (Data, Variable, Absolute),//將3個分別代表的BUTTON1,BUTTON2,BUTTON3的位添加到0x0A的報告

Report Size (5),

Input (Constant), //增加5個無效的位與上面3位湊成一個字節

End Collection,

End Collection


綜上所示,上面樣例所表達的意思就是下圖所示的:



這裏先簡單介紹用圖表(鼠標):具體看 HID Usage Tables 1.12(用圖表).pdf ,或下一章

0x05, 0x01, // Usage Page (Generic Desktop)


0x09, 0x02, // Usage (Mouse)



再 舉 一 個 實 際 的 例 子 進 行 解 讀 , 下 面 是 摘 自 TI CC2540/CC2541 SDK 裏 的BLE-CC254x_v1.4.0\Projects\ble\Profiles\HIDDevKbM\hidkbmservice.c

static CONST uint8 hidReportMap[] =
{

0x05, 0x01, // Usage Page (Generic Desktop)

0x09, 0x02, // Usage (Mouse)

0xA1, 0x01, // Collection (Application)

0x85, 0x01, // Report Id (1)

0x09, 0x01, // Usage (Pointer)

0xA1, 0x00, // Collection (Physical)

0x05, 0x09, // Usage Page (Buttons)

0x19, 0x01, // Usage Minimum (01) - Button 1

0x29, 0x03, // Usage Maximum (03) - Button 3

0x15, 0x00, // Logical Minimum (0)

0x25, 0x01, // Logical Maximum (1)

0x75, 0x01, // Report Size (1)

0x95, 0x03, // Report Count (3)

0x81, 0x02, // Input (Data, Variable,Absolute) - Button states

0x75, 0x05, // Report Size (5)

0x95, 0x01, // Report Count (1)

0x81, 0x01, // Input (Constant) - Padding or Reserved bits

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, Variable, Relative) - X & Y coordinate

0xC0, // End Collection

0xC0, // End Collection


0x05, 0x01, // Usage Pg (Generic Desktop)

0x09, 0x06, // Usage (Keyboard)

0xA1, 0x01, // Collection: (Application)

0x85, 0x02, // Report Id (2)

0x05, 0x07, // Usage Pg (Key Codes)

0x19, 0xE0, // Usage Min (224)

0x29, 0xE7, // Usage Max (231)

0x15, 0x00, // Log Min (0)

0x25, 0x01, // Log Max (1)

// Modifier byte

0x75, 0x01, // Report Size (1)

0x95, 0x08, // Report Count (8)

0x81, 0x02, // Input: (Data, Variable,Absolute)

// Reserved byte

0x95, 0x01, // Report Count (1)

0x75, 0x08, // Report Size (8)

0x81, 0x01, // Input: (Constant)

// LED report

0x95, 0x05, // Report Count (5)

0x75, 0x01, // Report Size (1)

0x05, 0x08, // Usage Pg (LEDs)

0x19, 0x01, // Usage Min (1)

0x29, 0x05, // Usage Max (5)

0x91, 0x02, // Output: (Data, Variable,Absolute)

// LED report padding

0x95, 0x01, // Report Count (1)

0x75, 0x03, // Report Size (3)

0x91, 0x01, // Output: (Constant)

// Key arrays (6 bytes)

0x95, 0x06, // Report Count (6)

0x75, 0x08, // Report Size (8)

0x15, 0x00, // Log Min (0)

0x25, 0x65, // Log Max (101)

0x05, 0x07, // Usage Pg (Key Codes)

0x19, 0x00, // Usage Min (0)

0x29, 0x65, // Usage Max (101)

0x81, 0x00, // Input: (Data, Array)

0xC0, // End Collection


0x05, 0x0C, // Usage Pg (Consumer Devices)

0x09, 0x01, // Usage (Consumer Control)

0xA1, 0x01, // Collection (Application)

0x85, 0x03, // Report Id (3)

0x09, 0x02, // Usage (Numeric Key Pad)

0xA1, 0x02, // Collection (Logical)

0x05, 0x09, // Usage Pg (Button)

0x19, 0x01, // Usage Min (Button 1)

0x29, 0x0A, // Usage Max (Button 10)

0x15, 0x01, // Logical Min (1)

0x25, 0x0A, // Logical Max (10)

0x75, 0x04, // Report Size (4)

0x95, 0x01, // Report Count (1)

0x81, 0x00, // Input (Data,Ary,Abs)

0xC0, // End Collection

0x05, 0x0C, // Usage Pg (Consumer Devices)

0x09, 0x86, // Usage (Channel)

0x15, 0xFF, // Logical Min (-1)

0x25, 0x01, // Logical Max (1)

0x75, 0x02, // Report Size (2)

0x95, 0x01, // Report Count (1)

0x81, 0x46, // Input (Data, Var, Rel, Null)

0x09, 0xE9, // Usage (Volume Up)

0x09, 0xEA, // Usage (Volume Down)

0x15, 0x00, // Logical Min (0)

0x75, 0x01, // Report Size (1)

0x95, 0x02, // Report Count (2)

0x81, 0x02, // Input (Data, Var,Abs)

0x09, 0xE2, // Usage (Mute)

0x09, 0x30, // Usage (Power)

0x09, 0x40, // Usage (Menu)

0x09, 0xB1, // Usage (Pause)

0x09, 0xB2, // Usage (Record)

0x0a, 0x23, 0x02, // Usage (Home)

0x0a, 0x24, 0x02, // Usage (Back)

0x09, 0xB3, // Usage (Fast Forward)

0x09, 0xB4, // Usage (Rewind)

0x09, 0xB5, // Usage (Scan Next)

0x09, 0xB6, // Usage (Scan Prev)

0x09, 0xB7, // Usage (Stop)

0x15, 0x01, // Logical Min (1)

0x25, 0x0C, // Logical Max (12)

0x75, 0x04, // Report Size (4)

0x95, 0x01, // Report Count (1)

0x81, 0x00, // Input (Data, Ary,Abs)

0x09, 0x80, // Usage (Selection)

0xA1, 0x02, // Collection (Logical)

0x05, 0x09, // Usage Pg (Button)

0x19, 0x01, // Usage Min (Button 1)

0x29, 0x03, // Usage Max (Button 3)

0x15, 0x01, // Logical Min (1)

0x25, 0x03, // Logical Max (3)

0x75, 0x02, // Report Size (2)

0x81, 0x00, // Input (Data,Ary,Abs)

0xC0, // End Collection

0x81, 0x03, // Input (Const, Var,Abs)

0xC0 // End Collection
};


上面用紅藍綠區分出三大應用功能,分別鼠標、鍵盤和 Consumer,每個應用功能都是用CollectionApplication 括起來的。




我們先來解析鼠標的報告描述:

0x05, 0x01, // Usage Page (Generic Desktop)

0x04 代表是 Global 類的 Usage Page 功能,最位 2 位表示帶多少個字節的數據,因爲只帶1 個數據,所以是 1,跟 0x04 組合起來就是 0x05 了。其他名稱的意思都差不多,數值可以參照上一章的Generic Item Format

0x09, 0x02, // Usage (Mouse)

表示這是一個鼠標, Usage 是爲了給對方解析數據時有個參照

0xA1, 0x01, // Collection (Application)

0xA1, 0x01 表示 CollectionApplication ; 0xA1, 0x00 表示 Collection Physical.表示下面所包含的是對 Mouse 的解釋

0x85, 0x01, // Report Id (1)

該報告對應的 ID 是 1

0x09, 0x01, // Usage (Pointer)

這是個指針形式

0xA1, 0x00, // Collection (Physical)

下面所包含的是對指針的解釋

0x05, 0x09, // Usage Page (Buttons)

下面定義的是按鍵

0x19, 0x01, // Usage Minimum (01) - Button 1

0x29, 0x03, // Usage Maximum (03) - Button 3

總共有 3 個按鍵

0x15, 0x00, // Logical Minimum (0)

0x25, 0x01, // Logical Maximum (1)

按鍵的值是 0 和 1,表示放開和按下

0x75, 0x01, // Report Size (1)

0x95, 0x03, // Report Count (3)

有 3 個 1 位,即用 3bits 分別對應三個按鍵

0x81, 0x02, // Input (Data, Variable,Absolute) - Button states

將這三個位加入本報告的數據中,這三位是可讀寫的絕對值

0x75, 0x05, // Report Size (5)

0x95, 0x01, // Report Count (1)

定義 1 個 5 位的數據

0x81, 0x01, // Input (Constant) - Padding or Reserved bits

將這個數據添加到本報告的數據中,主要是與前面 3 位組成一個字節,這 5 位是 Constant數據

0x05, 0x01, // Usage Page (Generic Desktop)

0x09, 0x30, // Usage (X)

0x09, 0x31, // Usage (Y)

0x09, 0x38, // Usage (Wheel)

下面定義的是 X,Y,Wheel 三個功能

0x15, 0x81, // Logical Minimum (-127)

0x25, 0x7F, // Logical Maximum (127)

X,Y,Wheel 的取值範圍是-127~127

0x75, 0x08, // Report Size (8)

0x95, 0x03, // Report Count (3)

用三個字節來表示 x,y,wheel

0x81, 0x06, // Input (Data, Variable, Relative) - X & Y coordinate

將這三個字節添加到本報告中

0xC0, // End Collection

0xC0, // End Collection


上面解析出來的數據格式如下:


我們來看一下,如果要發一個鼠標的座標,該如何發:

static void hidEmuKbdSendMouseReport( uint8 buttons )

{

uint8 buf[HID_MOUSE_IN_RPT_LEN];

buf[0] = buttons; // Buttons

buf[1] = 0; // X

buf[2] = 0; // Y

buf[3] = 0; // Wheel

HidDev_Report( HID_RPT_ID_MOUSE_IN, HID_REPORT_TYPE_INPUT,

HID_MOUSE_IN_RPT_LEN, buf );

}

從上面函數可以看到,X,Y 在第 2、3 個字節,結合上面的數據格式圖可以看出,正好是對應的。



我們接着解析鍵盤的報告描述:

0x05, 0x01, // Usage Pg (Generic Desktop)

0x09, 0x06, // Usage (Keyboard)

這是一個鍵盤

0xA1, 0x01, // Collection: (Application)

0x85, 0x02, // Report Id (2)

本報告的 ID 是 2

0x05, 0x07, // Usage Pg (Key Codes)

下面定義的是按鍵碼

0x19, 0xE0, // Usage Min (224)

0x29, 0xE7, // Usage Max (231)

按鍵碼分別是 224~231,共總有 8 個按鍵碼

0x15, 0x00, // Log Min (0)

0x25, 0x01, // Log Max (1)

按鍵碼的值是 0 和 1,分別代表放開和按下

// Modifier byte

0x75, 0x01, // Report Size (1)

0x95, 0x08, // Report Count (8)

用 8 個 bit 分別表示 8 個按鍵的狀態

0x81, 0x02, // Input: (Data, Variable,Absolute)

將這 8 個 bit 添加到本報告中

// Reserved byte

0x95, 0x01, // Report Count (1)

0x75, 0x08, // Report Size (8)

0x81, 0x01, // Input: (Constant)

另外再預留 8 個 bit 備用,暫時沒用

// LED report

0x95, 0x05, // Report Count (5)

0x75, 0x01, // Report Size (1)

定義 5 個 1bit

0x05, 0x08, // Usage Pg (LEDs)

這是 LED

0x19, 0x01, // Usage Min (1)

0x29, 0x05, // Usage Max (5)

5 個 bit 分別對應 LED1~LED5

0x91, 0x02, // Output: (Data, Variable,Absolute)

將這 5 個 bit 添加到本報告中,LED 需要作爲 OUT

// LED report padding

0x95, 0x01, // Report Count (1)

0x75, 0x03, // Report Size (3)

0x91, 0x01, // Output: (Constant)

再增加 3 個 bit,與上面 5 個 bit 組成一個字節

// Key arrays (6 bytes)

0x95, 0x06, // Report Count (6)

0x75, 0x08, // Report Size (8)

定義 6 個字節

0x15, 0x00, // Log Min (0)

0x25, 0x65, // Log Max (101)

每個字節的取值範圍是 0~101

0x05, 0x07, // Usage Pg (Key Codes)

這個也是鍵盤碼

0x19, 0x00, // Usage Min (0)

0x29, 0x65, // Usage Max (101)

分別是鍵盤碼 0~鍵盤碼 101

0x81, 0x00, // Input: (Data, Array)

將這 6 個字節添加到本報告中,表示同時可產生 6 個鍵值。

0xC0, // End Collection

上面解析出來的數據格式如下:


Input 和 Out 是不同的兩條通道。現在我們來看一下,如果要發一個按鍵 K0~K101,需要怎麼發,如下:

static void hidEmuKbdSendReport( uint8 keycode )

{

uint8 buf[HID_KEYBOARD_IN_RPT_LEN];

buf[0] = 0; // Modifier keys

buf[1] = 0; // Reserved

buf[2] = keycode; // Keycode 1

buf[3] = 0; // Keycode 2

buf[4] = 0; // Keycode 3

buf[5] = 0; // Keycode 4

buf[6] = 0; // Keycode 5

buf[7] = 0; // Keycode 6

HidDev_Report( HID_RPT_ID_KEY_IN, HID_REPORT_TYPE_INPUT,

HID_KEYBOARD_IN_RPT_LEN, buf );

}

上面函數可以看到,它是放在第 3 個字節,結合數據格式圖可以看出,第 3 個字節開始,剛好是在 K0~K101 的按鍵區。



我們最後來解析 Consumer 的報告描述:

0x05, 0x0C, // Usage Pg (Consumer Devices)

0x09, 0x01, // Usage (Consumer Control)

這是個 Consumer 控制

0xA1, 0x01, // Collection (Application)

0x85, 0x03, // Report Id (3)

本報告 ID 爲 3

0x09, 0x02, // Usage (Numeric Key Pad)

下面定義的是數字鍵盤

0xA1, 0x02, // Collection (Logical)

0x05, 0x09, // Usage Pg (Button)

下面定義的是按鍵

0x19, 0x01, // Usage Min (Button 1)

0x29, 0x0A, // Usage Max (Button 10)

分別是 Button1~Button10

0x15, 0x01, // Logical Min (1)

0x25, 0x0A, // Logical Max (10)

每個按鍵的取值範圍爲 1~10

0x75, 0x04, // Report Size (4)

0x95, 0x01, // Report Count (1)

1 個 4bit 的值,來表示鍵值 1~10,這個值是哪個就表示哪個鍵按下。

0x81, 0x00, // Input (Data,Ary,Abs)

將這 4bit 添加到本報告中

0xC0, // End Collection

0x05, 0x0C, // Usage Pg (Consumer Devices)

0x09, 0x86, // Usage (Channel)

這裏定義的是頻道

0x15, 0xFF, // Logical Min (-1)

0x25, 0x01, // Logical Max (1)

頻道值範圍是-1~1,這裏應該只用到-1 和 1,表示頻道+和-

0x75, 0x02, // Report Size (2)

0x95, 0x01, // Report Count (1)

用一個 2bit 來表示,第 1 個 bit 表示頻道+,第二個表示頻道-

0x81, 0x46, // Input (Data, Var, Rel, Null)

將這個 2bit 加到本報告中

0x09, 0xE9, // Usage (Volume Up)

0x09, 0xEA, // Usage (Volume Down)

定義兩個按鍵,音量加和音量減

0x15, 0x00, // Logical Min (0)

按鍵值爲 0~1,這裏少了 Logical Max,繼承上面的 Logical Max=1

0x75, 0x01, // Report Size (1)

0x95, 0x02, // Report Count (2)

定義 2 個 1bit,每個 bit 代表一個鍵

0x81, 0x02, // Input (Data, Var,Abs)

將 2 個 1bit 添加到本報告中

0x09, 0xE2, // Usage (Mute)

0x09, 0x30, // Usage (Power)

0x09, 0x40, // Usage (Menu)

0x09, 0xB1, // Usage (Pause)

0x09, 0xB2, // Usage (Record)

0x0a, 0x23, 0x02, // Usage (Home)

0x0a, 0x24, 0x02, // Usage (Back)

0x09, 0xB3, // Usage (Fast Forward)

0x09, 0xB4, // Usage (Rewind)

0x09, 0xB5, // Usage (Scan Next)

0x09, 0xB6, // Usage (Scan Prev)

0x09, 0xB7, // Usage (Stop)

定義 12 個按鍵

0x15, 0x01, // Logical Min (1)

0x25, 0x0C, // Logical Max (12)

0x75, 0x04, // Report Size (4)

0x95, 0x01, // Report Count (1)

用一個 4 位來存儲 1~12,1 表示 Mute … 12 表示 Stop

0x81, 0x00, // Input (Data, Ary,Abs)

將這個 4bit 添加到報告中

0x09, 0x80, // Usage (Selection)

0xA1, 0x02, // Collection (Logical)

0x05, 0x09, // Usage Pg (Button)

這是按鍵

0x19, 0x01, // Usage Min (Button 1)

0x29, 0x03, // Usage Max (Button 3)

分別是 Button1~Button3

0x15, 0x01, // Logical Min (1)

0x25, 0x03, // Logical Max (3)

每個按鍵取值範圍是 1~3

0x75, 0x02, // Report Size (2)

這裏缺少了 Report Count,繼承上面的 Report Count =1,也就是用 1 個 2bit 來存儲 1~3

0x81, 0x00, // Input (Data,Ary,Abs)

將 1 個字節添加到本報告中

0xC0, // End Collection

0x81, 0x03, // Input (Const, Var,Abs)

再補充 2 個 bit 將上面的湊成一個字節,Report Size=2 和 Report Count =1 繼承上面的。

0xC0 // End Collection


修改後,解析出來的數據格式如下:


我們來看一下,如果要發音量+/-鍵該怎麼發:

static void hidCCSendReport( uint8 cmd, bool keyPressed )

{

// Only send the report if something meaningful to report

uint8 buf[HID_CC_IN_RPT_LEN] = { 0, 0 };

// No need to include Report Id

if ( keyPressed )

{

hidCCBuildReport( buf, cmd );

}

HidDev_Report( HID_RPT_ID_CC_IN, HID_REPORT_TYPE_INPUT,

HID_CC_IN_RPT_LEN, buf );

}

在 hidCCBuildReport 對音量加減解析出來是:

音量加是:buf[0] = 0x40, buf[1] = 0x00

音量減是:buf[0] = 0x80, buf[1] = 0x00

正好與數據格式圖中第一個字節的第 6 位和第 7 位相對應。





















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章