觀前提示
警告 版權聲明
轉載此文內容時,請如實標明作者與網頁來源,對於層疊轉載的情形,請標明初始網址。創作不易,有部分內容使用了HTML代碼進行排版與呈現,用於優化閱讀體驗並提高閱讀理解效率,請尊重作者的意願並保護知識成果。
- 通過截取為圖片或保存為網頁副本/PDF文件的形式獲取內容均視作「轉載」。
- 禁止在轉載期間添加閱讀限制條件,如「必須關注轉載者方可觀看」。
- 同時禁止源自轉載平台施加的閱讀限制條件,如「需要登陸轉載平台賬戶方可觀看全文」。
- 禁止商用:轉載者或轉載平台要求用戶支付「會員費/贊助費」方可閱讀全文的情形等效於「商業用途」,此頁的編輯歷史亦可作為有效舉證材料。
此處記錄本人學習HID期間總結出來的知識點,這些知識點可以作為快速對照的手冊或解答學習期間疑惑的輔助文本。
必需文檔鏈接
- 對於電腦瀏覽器,建議新建窗口並以分屏形式打開方便學習;對於手機瀏覽器,建議直接下載到本地存儲器。
綜述
此處文檔均描述1.11版本的HID接口。開發HID接口所需的基礎知識點如下:
- Report_Descriptor(數據報表格式描述符,簡稱「報表描述符」)
- 設備項目/事件編碼的對照表(HID Usage Table)
- 數據端點組態與數據報表格式
- HID專項USB請求(控制指令)
HID接口的特點就是包羅萬象,上到鼠標鍵盤遊戲手柄、下到醫療設施鍵盤、盲文閱讀器、FIDO聯機身份驗證器都可以直接使用這個接口進行人機互動。
HID設備用於功能實現的基礎是「數據報表」,數據報表需要設備在配置期間聲明「數據報表格式」,配置結束後,就需要按照所聲明的格式,將對應數據通過「數據報表」與主機進行交換。
數據報表格式
序言
在USB主機枚舉Enumerate,主要軟件對目標設備或程序進行枚舉時,目標設備或程序會將需要使用的功能與可能用上的數據做成一個「執行列表」,隨後將「執行列表」發送至主要軟件中,讓主要軟件根據「執行列表」進行有序處理。一個HID設備時,設備需要在傳輸配置描述符之後,單獨根據USB請求傳輸「數據報表格式描述符」(亦稱「報告描述符」)。
數據報表格式描述符的作用看起來很簡單但實施起來困難,具體作用如下:
- 聲明人機互動設備可能響應或接受的事件編碼
- 聲明對應事件的數據組態(配置)格式
- 聲明一系列數據在報表上的分布
- 玩懂了數據報表格式描述符,才算玩懂了HID接口協議。拿別人的設計圖紙重複造輪子很簡單,輪到自己做出最佳空氣力學性能的輪子很難,但最為適配的輪子造出來,才能證明你是造輪子的大師。
報頭格式
數據報表格式描述符的基本組成格式為「報表格式項目」,報表項目有「長項目」和「短項目」兩種數據格式,但由於HID1.11從不使用「長項目」,所以只能學習「短項目」數據格式,且報表項目統一由「報頭」和「報文」構成。
短項目數據格式
(此處示例為2字節報文)
| 數據報送順序先報→後報 |
| 報頭 | 報文 |
| 報頭編碼 | 報頭分類 | 數據長度 | 報文第1字節 | 報文第0字節 |
| b7第7位 | b6第6位 | b5第5位 | b4第4位 | b3第3位 | b2第2位 | b1第1位 | b0第0位 | 01H | 00H |
按照現實生活類比,「報頭」表示特性類別,「報文」表示對應內容。
「報頭」內存行里的內容,不僅會決定報頭對應的屬性類別,還會決定報文的數據長度。
| 「內存行」名詞註解 |
|
學習HID乃至USB之前,必須精通數電基礎。
「內存」一般指DRAM緩存,「內存」所存放的數據「內存行」是其構建的基礎單位。
「內存行」表示存放對應數據的一組邏輯位,如無特殊說明,一行內存為1字節,占用8個邏輯位。- 在單片機中,「寄存器」是「內存行」的一種類型。
- 一個邏輯位只有高電平和低電平兩種狀態,各種電氣功能以及數據處理都要根據邏輯位的狀態發生改變。
- 一組邏輯位組成的「內存行」可以表示很多可能,比如一組8位的字節可以表示256種狀態。
- 不在對應內存行的數據或者超出有效狀態的數值均為無效內容。
- 錯誤管理內存行會導致「程序跑飛」,程序跑飛時必須緊急停機,否則會導致系統結構解體。
- Windows電腦突然呈現的「藍屏」(常見Windows版本)或者「綠屏」(測試版Windows,WIP),就是一種緊急停機的表現。
|
報文可能出現的格式
| 報文類型 | 原始數據 | 解析結果 |
| 空報文 | 0xC0, | END_COLLECTION |
| 1字節報文 | 0x05, 0x01, | USAGE_PAGE(Generic Desktop) |
| 2字節報文 | 0x26, 0x7F, 0xFF, | LOGICAL_MAXIMUM(32767) |
| 4字節報文 | 0x0B, 0x20, 0x00, 0xD0, 0xF1, | USAGE(0xF1D0:FIDO_Alliance, 0x0020:Input_Report_Data) |
數據長度效果
| 觀前提示 |
- 除了固定數據格式,單元內容必須從BE字節序轉為LE字節序,也就是說,字節順序必須逆向排布。
- 此處表格為轉換完成後的最終字節順序。
|
0字節 void | |
1字節 BYTE |
| 數據報送順序先報→後報 |
| 報頭 | 報文第0字節 |
| 00H | 01H |
|
2字節 WORD |
| 數據報送順序先報→後報 |
| 報頭 | 報文第1字節 | 報文第0字節 |
| 00H | 02H | 01H |
|
4字節 DWORD |
| 數據報送順序先報→後報 |
| 報頭 | 報文第3字節 | 報文第2字節 | 報文第1字節 | 報文第0字節 |
| 00H | 04H | 03H | 02H | 01H |
|
「報頭」由3個字段構成,總大小為1字節。4個邏輯位的「報頭聲明」、2個邏輯位的「報頭分類」和2個邏輯位的「數據長度」,且「數據長度」會影響「報文」的數據大小。
原始數據對應釋義
| 原始數據 | 報頭分類(翻譯)1 | 報文長度 | 注意事項 |
| 0x00 | MAIN/基礎功能 | 0字節 |
- 放置在不同位置的原始數據會出現不同釋義,如「0x01」放在「報頭分類」區域會編譯為「GLOBAL類項目」,「0x01」放在「報文長度」會表示「1字節報文」。
- 「短項目」報頭聲明會受到「報頭分類」的影響而受到不同制約。
- 若報頭分類為0x03時,請使用長項目數據格式,不能繼續使用「短項目」數據格式。
|
| 0x01 | GLOBAL/廣義聲明 | 1字節 |
| 0x02 | LOCAL/狹義聲明 | 2字節 |
| 0x03 | LONG/長項目修飾符2 | 3字節 |
報頭類別
報頭類型與編碼
(有效數據掩碼以字節形式表示數據的有效範圍,對應邏輯位為1時表示有效位,為0時表示無關位。為0xF0)
| 原始數據 | 報頭名稱 | 使用方法 |
MAIN / 基礎功能 控制HID解析器執行報表製成或分組 |
| 0x80 | INPUT 打包數據入表 |
- 3個報頭的報文大小均為1/2字節報文,組合內存行。
- 前述兩個報頭均為必需報頭,一個數據報表格式描述符需要至少一個這樣的報文,且三種報頭至少需要其一。
報表打包:根據修飾屬性和註冊的用途清單,創建對應內存行/寄存器。
- 數據輸入:將設備報告已觸發的事件在HID技術文檔中稱作「Usage」,直譯為「用途」。上傳至主機。必須有一個數據入點USB數據端點,傳輸方向為「輸入」,即「主機←設備」。以傳輸實時變化的數據報表。
- 數據輸出:將主機報告已觸發的事件下載至設備。可分配一個數據出點USB數據端點,傳輸方向為「輸出」,即「主機→設備」。以傳輸實時變化的數據報表,否則只通過控制端點USB數據端點,端點編號為0號,只能通過USB請求傳輸數據的SET_REPORT請求主機單獨下載數據報表到設備傳輸數據報表。
- 設備特性:在主機與設備的傳輸中交換設備特性,只能通過控制端點交換數據。
- 如果需要定義為「BUFFERED_BYTES」字節填充,必須使用2字節報文。
- 對應操作結束後會清空狹義聲明。
|
| 0x90 | OUTPUT 打包數據出表 |
| 0xB0 | FEATURE 打包設備特性表 |
| 0xA0 | COLLECTION 集合起始域 |
- COLLECTION報頭為1字節報文,無符號整數,END_COLLECTION報頭為無數據報頭。
- 前述兩個報頭均為必需報頭,一個數據報表格式描述符需要至少一組這樣成對的報文。
集合或分組:創建報文分組,提高HID解析器和電腦軟件的解析效率。
- 一個數據報表格式描述符需要至少一個最高級「APPLICATION」應用領域集合。同時具備多個HID標準類型的單個設備視作「多個應用領域」。
- 如果開發的1個非標設備不按現有標準製成的設備,有時又被稱作「自定義設備」或「客制化設備」。只有一個應用領域,可以不再對數據報表格式描述符進行分組。
- COLLECTION報頭和END_COLLECTION報頭必須成對出現,但是允許嵌套。
|
| 0xC0 | END_COLLECTION 集合結束域 |
- 基礎功能所生成的項目會受到廣義聲明和狹義聲明的調整。
|
GLOBAL / 廣義聲明 修飾一個數據報表的擴展屬性 |
| 0x00 | USAGE_PAGE 定位用途類別 |
- 1字節報文,部分用途類別需要2字節;不論字節大小均為無符號整數。
- 可選報頭1,根據USAGE報頭決定是否為必需報頭2。
用途註冊:向HID解析器添加可能會用到的用途。其中此報頭用於定位用途所在的類別表格編號。
- 此報頭可節省用途聲明所需的代碼,比如註冊同一類別表格下的零散用途。
- 對於工作在低速模式下的設備而言,由於控制端點字長為恆定8字節,此報頭為必需報頭。
- 如果數據報表格式描述符集合中,第一個USAGE_PAGE前面有USAGE報頭,HID解析器會將集合起始域後的第一個USAGE中的低16字節用作USAGE_PAGE.
|
| 0x10 | LOGICAL_MINIMUM 數字域最小值 |
- 4個報頭的報文大小可使用1/2/4字節的報文,並且均為有符號整數在單個字節的最高位(MSD)表示數字前面的符號,若該位為1,表示該數值為負數,負數情況下,取數字域最小值(負數最大值)加上剩餘位表示的數值算出最終結果。
以下例子介紹了1字節有符號整數對應的有效數據:- 「0x7F」→「+127」
- 「0x80」→「-128」
- 「0x81」→「-127」
- ……
- 「0xFF」→「-1」
實際算法: 「0xFF」↓ 「-1」↓ 「(-128)+127=-1」。
- 「數字域」相關報頭均為必需報頭1,一個數據報表格式描述符需要至少一個對應類別的報文2;「實體域」報頭為可選報頭3。
數據極值:劃定有效數據的最大值/最小值範圍。
- 「實體域數值」指的是設備在實際應用中對應的有效數據;「數字域數值」指的是數字信號傳輸過程中對應的等效數值;「極值」包含「最大值」和「最小值」。
- 未聲明極值時,對應的極值將取缺省值「0x00」;「數字域最大值」不能小於或等於「數字域最小值」。
- 極值以外的數值均視作NULL值無意義數值,一般用作「數據不可用」;「-2147483648(0x8000 0000)」為恆定NULL值,禁止用作極值。
- 「實體域」極值不被用作數據報表創建,僅供應用程序讀取相關內容以修改算法,比如「電子減速器」。
|
| 0x20 | LOGICAL_MAXIMUM 數字域最大值 |
| 0x30 | PHYSICAL_MINIMUM 實體域最小值 |
| 0x40 | PHYSICAL_MAXIMUM 實體域最大值 |
| 0x50 | UNIT_EXPONENT 實體域10乘倍數 |
- 「UNIT_EXPONENT」僅使用1字節的低4位1,「UNIT」為7組4位(組合內存),並且均為有符號整數。
- 前述兩個報頭均為可選報頭2。
實體域單位聲明:聲明數據對應的單位與10乘倍數。
“10乘倍数”算式效果为$1×10^x$。
- 「UNIT」報頭的數據結構很複雜,第0字節的低4位表示單位所使用的度量制(公制/英制)與坐標體系(直角坐標/極坐標),其餘分組的4位內存表示各單位的導數微積分數學的重要概念,在此處用於修飾單位的導函數或積分值,對應單位會隨着度量制的不同而發生改變。
- 該字節高4位沒有任何意義,恆定為0x0.
- 不被用作數據報表創建,僅供應用程序讀取相關內容以修改算法。
|
| 0x60 | UNIT 實體域單位與導數 |
| 0x80 | REPORT_ID 數據報表編號 |
- 1字節報文,無符號整數。「0x00」為NULL值。
多重數據報表:聲明對應報表所處的編號。
- 同時只能傳輸一整個數據報表,需要傳輸的報表編號可被設備輪換或主機控制。
|
| 0x70 | REPORT_SIZE 項目占用大小 |
- 前述兩個報頭均為1字節無符號整數,「0x00」為NULL值。
- 前述兩個報頭均為必需報頭,一個數據報表格式描述符需要至少一個對應類別的報文。
數據格式:聲明單次註冊(數據打包)所需要的項目數量與單個項目的占用大小。
- 「REPORT_SIZE」的單位不是1個字節而是1個邏輯位。「REPORT_COUNT」的單位為數量。
- 被註冊的內存將使用「REPORT_SIZE」×「REPORT_COUNT」個邏輯位,但打包成數據傳輸時,剩餘不滿1個字節的部分需要根據以下情形填充為整個字節:
- 如果在報表打包過程中聲明了「BUFFERED_BYTES」,不需要填充字節,但此情形僅用於一個特殊事件(項目),這種特殊項目占用的位大小為字節的整數倍。
- 剩餘未使用的邏輯位以1個「無意義項目」的形式打包成聲明「CONSTANT」的數據。
- 單個項目占用的數據長度上限為32個邏輯位。
|
| 0x90 | REPORT_COUNT 打包所需項目個數 |
| 0xA0 | PUSH 廣義聲明存檔 |
- 前述兩個報頭均為無數據報頭。
- 前述兩個報頭均為可選報頭。
廣義聲明緩存區:用於快速複製廣義聲明修飾的屬性
- 緩存區只有一倍大小的空間,使用範圍不受「COLLECTION」類報頭影響,全局有效。
- 連續使用PUSH會替換舊內存,不論多少次使用POP都只會讀取當次POP前最後一次PUSH的內存。
|
| 0xB0 | POP 廣義聲明讀檔 |
- 一個廣義聲明報頭的影響範圍會從本身開始,截至下一個同類廣義聲明。📽️沒有編譯呈現效果,請先完成代碼填入以編譯對應效果。
|
LOCAL / 狹義聲明 具有限定範圍的屬性修飾符 |
- 一個狹義聲明報頭經過聲明後,其影響範圍會從本身開始截至下一個「MAIN」類報頭,多個狹義聲明報頭共存且互不干擾。
|
報頭用法
數據組態
應用例
標準USB鍵盤