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 位相對應。