轉自:http://group.ednchina.com/93/198.aspx。
參考:USB HID usage table
概述:
報告在這里意思是數據傳輸(data transfer),而報告描述符是對這些傳輸的數據作用途(usage)上的說明。
USB通訊協議的規范是以1ms產生一個USB幀(frame),USB設備可以每一個幀中發送和接收一個交換(transaction)。交換是由幾個封包(packet)組成,而傳輸是由一個或幾個交換來完成傳送一口中有效的數據。在這里,傳輸和報告的意思相類似。傳輸方式有四種,初始學一般只要了解控制型傳輸(control transfer)和中斷型傳輸(interrupt transfer)即可。控制型傳輸是當需要時才執行傳輸要求,是最一般的傳輸方式,組態、命令和狀態的通訊都可以使用控制型傳輸;控制型傳輸主要用於消息型數據(message-type data)。中斷型傳輸目的在做重復的數據更新(recurring data)傳輸,精確一點而言,即是在每個有限有周期內(bounded period)作至少一次的小量數據發送或接收;所以適用於流動型數據(stream-type data),注意這里所謂的周期時間就是在端點描述符中的輪詢間隔時間。
報告有三種:input,output,和Feature.后面將作進一步介紹。
中斷型輸入管線(interrupt in pipe)僅可以傳送input報告;
中斷型輸出管線(interrupt out pipe)僅可以傳送output報告;
但是控制型管線(control pipe)可以傳送input,output和feature報告。端點描述符有聲明所使用的端點為何種管線。
數據本身沒有任何意義,要賦於用途才能明確其為控制什么(control);例如設備上的按鈕指示燈和X與Y軸的位移等都通稱控制,數據則為按鈕和指示燈的開關狀態或X與Y軸的位移量。為了這個目的應運而生報告描述符,其將數據的操控與它的用途作一對一的對應,所以解讀報告后就可以知道每個數據作何種操作。所以“傳輸的數據”和“操作”只是一事件的兩種描述方式。
用途是以一個32位卷標(稱作usage tag)來表示,高16位稱作usage page(用途類頁),低16位稱為usage ID(用途識別名):
Usage = (usage page:usage ID)
舉例說明:二個字節分別為x和y軸的位移數據,因此第一個字節的usage=(generic desktop:X),而第二個字節的usage = (generic desktop:Y),其中generic desktop為用途的大類別(稱作用途類頁)之一,x和y軸的操作用途屬於此用途類頁。文件universal serial Bus HID Usage Table完整列出所有的usage pages(用途類頁)和usage ID(用途識別名),使用者必須遵照文件的規范來聲明操作的用途。該文件的附錄A有十多個報告描述符的范例,值得研究下。
表1、報告描述符的標簽
主項目
|
全域項目
|
區域項目
|
|||
標簽
|
代碼
|
標簽
|
代碼
|
標簽
|
代碼
|
Input
|
X08?
|
Usage Page
|
0x0?
|
Usage
|
0x0?
|
Output
|
0x9?
|
Logical Minimum
|
0x1?
|
Usage Minimum
|
0x1?
|
Feature
|
0x0b?
|
Logical Maximum
|
0x2?
|
Usage Maximum
|
0x2?
|
|
Physical Minimum
|
0x3?
|
Designator Minimum
|
0x3?
|
|
Collection
|
0xa1
|
Physical Maximum
|
0x4?
|
Designator Minimum
|
0x4?
|
End Collection
|
0xc0
|
Unit Exponent
|
0x5?
|
Designator Maximum
|
0x5?
|
|
|
Unit
|
0x6?
|
String
|
0x7?
|
|
|
Report Size
|
0x7?
|
Sreing Minimum
|
0x8?
|
|
|
Report ID
|
0x8?
|
String Maximum
|
0x9?
|
|
|
Report Coumt
|
0x9?
|
Delimiter
|
0xa?
|
|
|
Push
|
0xA?
|
|
|
|
|
Pop
|
0xb?
|
|
|
標簽:
用途卷標只是報告描述符諸多標簽的一個。表1列出所有的卷標,利用這些卷標取可以清楚完整的描述符操作的用途。報告描述符的語法不同於USB標准描述符,它是以項目(items)方式排列而成,無一定的長度;項目有一個前輟(prefix),然后跟着一個括號,內為該項目的數據:item = prefix(data)。
項目分成三種類別:主項目,全局項目,區域項目。主項目中的input,ouput,feature三個卷標用來表示報告中數據的種類,這些是報告描述符中最主要的項目,其他項目都是用來修飾這三種項目。主要項目中其他二個卷標后面再作詳細的介紹。
>> Input 項:表示設備操作輸入到主機的數據模式。這個數據格式就形成一個輸入報告,雖然輸入報告可以用控制型管線以get report(input)來傳輸,但是通常用中斷型輸入管線來傳輸以確保在每一固定周期內都能將更新的輸入報告傳給主機。
>> Output項:表示由主機輸出到裝置操作的數據格式。這個數據格式就形成一個輸出報告。輸出報告通常不適用輪詢的方式來傳送給設備,而是由應用軟件依實際需求以傳令方式要求送出輸出報告,所以大多用控制型管線以set report(output)指令來將報告送到設備。當然也可以選擇用中斷型輸出管線來傳送,只是通常不建議這樣用。
>> Feature項:表示由主機送到設備的組態所需數據的數據格式。這個數據模式就形成一個特征報告。特征報告只能用控制型管線以get report(feature)和set report(feature)指令分別來取得和設定設備的特征值。
>> 范例:考慮一個2X16字的顯示裝置,它的列數、行數、字寬、和字高為固定值屬於feature報告;顯示狀態例如“就緒”和“輸入字錯誤”則屬於input報告;光標位置和顯示的字需可讀寫,所以屬於另一個feature報告;更新顯示的字則為output報告。為了區別兩個deatures,要用到全局項目中的report ID,每個feature報告有一個不同的report ID,因而主機請求指令要加上report ID的值:get report(feature,report ID)和Set report(feature,report ID)。
主項目用來定義報告中數據的種類和格式,而說明主項目之意義與用途為全局
項 目和區域項目。顧名思義,區域性項目只能適用於列於其下的第一個主項目,不適用於其他主項目,若一個主項目之上有幾個不同的卷標的區域性項目,則這些區域性項目皆適用於描述該主項目。相反,全局性項目適用於其下方的所有主項目,除非另一個相同卷標的全局性項目出現。為了清楚說明報告描述符,將使用“項目狀 態表”(item state table)用來表示在某位址處適用的全局性項目的組合。圖1顯示全局性項目和區域性項目與所描述的主項目之對應關系。
區域性項目卷標:
簡單地說,區域性項目(見表1)只是說明用途而已。Designator是要搭配實體描述符使用的,這里不對實體描述符進行介紹,所以略過這些designator標簽。
標簽Usage 實際上應該稱作Usage ID,它搭配全域項目的Usage Page 卷標才形成前文所定義的用途{usage}﹔但是報告描述符允許在區域項目的Usage 卷標直接用32位的方式來指定用途,這種方式稱作擴充式用途指定法(extended usage)以示區別。例如:Usage(Generic Desktop:Mouse),Usage Minimum(Keyboard:0),和Usage Maximum(Keyboard:101)。很明顯的,擴充式用途指定法會取代『項目狀態表』中的Usage Page。還有,使用擴充式用途指定法時,數據的高16 個位為用途類頁Usage Page,低16 個位則為用途識別名Usage ID。往往一個報告數據會對應到幾個操作,因而會有幾個用途,例如101 按鍵的鍵盤利用不同代碼代表不同的鍵,每一個鍵是一個操作,有自己的用途,要將所有Usage ID 列出不太現實,所以就需要Usage Minimum 和Usage Maximum 二個標簽。以鍵盤為例,主項目之上只要二個區域項目:Usage Minimum (0), Usage Maximum (101)。如此一來,則無鍵按下(Usage ID 為0)和101 鍵中任一鍵被按下(Usage ID 為1 至101)的用途都被賦於到一個報告數據上,后面會有一個范例進一步解說。
卷標String Index 類似卷標Usage,而卷標String Minimum 和String Maximum 則類似標簽Usage Minimum 和Usage Maximum。如果希望某個操作對應到一個字串,則用String Index 來描述該操控的報告數據,這個字符串在字符串描述符中,StringIndex (data)項目中的data 是這個字符串在字符串描述符中的位置索引。如果需要用到幾個字符串,則可以使用String Minimum 來指向字符串描述符中被用到字符串的最先位置索引,和String Maximum 來指向最后位置索引。
標簽Delimiter 很少用到,請參考Universal Serial Bus HID Usage Tables 文件中Appendix B 的范例詳細說明。
全局項目卷標
全局項目的卷標事實上只要Usage Page,Logical Minimum,Logical Maximum,
Report Size,Report ID,Report Count 就足夠了。表2 列了二個音量操作的例子(音量增減鍵和音量旋鈕)將用來輔助說明這些卷標,不過主項目括號內的數據會在后文中再做說明。
表2、音量操作舉例
音量減鍵
|
音量旋鈕
|
Usage Page(consumer)
|
Usage Page(Consumer)
|
Usage(Volume)
|
Usage(Volume)
|
Logical Minimum(-1)
|
Logical Minimum(0)
|
Logical Maximum(-1)
|
Logical Maximum(100)
|
Report Size(2)
|
Report Size(7)
|
Report Count(1)
|
Report Count(1)
|
Input(Data,Variable,Relative)
|
Input(Data,Variable,Absolute,No Wrap,Linear,No Relative)
|
查閱Universal Serial Bus HID Usage Tables 文檔,這兩個例子的用途需要令為(Consumer: Volume)。Usage Page 前面已經介紹過了。Report Size 用來設定主項目(Input,Output,Feature)的報告字段大小,它的單位是位。主項目會對每個操作產生一個報告字段,字段大小則由Report Size 決定。而Report Count 用來設定主項目之報告字段的數目,其等於操作的數目。音量增減鍵的例子中ReportCount (1)表示主項目Input 只產生一個字段,所以可知只有一個音量增減鍵﹔而Report Size (2)表示這個字段為2 位。另一個音量旋鈕例子也是只有一個旋鈕,所以用Report Count (1)﹔但是因為Report Size (7),所以該旋鈕的數據字段為7位,可以表示0到127之數值。再舉一例,如果是鼠標的三個按鍵,每個按鍵占用一個一位的字段,則Report Size (1), Report Count (3)﹔那么這個報告長度為三個位,可以同時呈現出三個按鍵的狀態(原狀或被按下)。
Logical Minimum 和Logical Maximum 在說明每個報告字段的數值范圍,這是純數值所以稱為邏輯數值(logical value)。音量增減鍵的例子中Logical Minimum (-1),Logical Maximum (1)表示只會出現-1, 0, 1 三種數值,所以用到二位(即ReportSize(2)),0b11 代表-1,0b00 代表0,0b01 代表1。在音量旋鈕例子中,雖然用7 位作一字段,但是旋鈕僅會產生0 到100 的數值,因為Logical Minimum (0)和Logical Maximum (100)。假如實體程序錯誤產生超出邏輯數值的范圍,則主機將會忽略該數值,這種數值稱作null value。
當要將同一種報告分成數個部分,則每一個部分要給予一個識別值,這時就需用到卷標Report ID,其數據值必須從1起算,不可使用0。沒有賦予Report ID 標簽的報告,主機有可能會將其Report ID 視為0,所以Report ID (0)被要求不能使用。這個標簽對控制型管線才有意義,因為它可以在請求報告時指定Report ID的值。對於中斷型管線,其為周期性傳輸報告,所以每次都會將所屬報告傳完,沒有僅傳輸部分之必要,所以Report ID 標簽就無意義。
其它的全局項目卷標可分為輔助工具(Push 和Pop)和物理量說明(Physical Minimum,Physical Maximum,Unit Exponent,和Unit)。Push 卷標將『項目狀態表』存放到緩存器(stack),而Pop 卷標反過來將緩存器最頂層的『項目狀態表』取回來取代目前之狀態表。這二個標簽對很長的報告描述符才有用處,因為其可以節省多列一些全局項目。讀者當要使用到時,參考Universal Serial Bus HIDUsage Tables 文件的Appendix A.7 節中范例則可獲得正確使用方式。
不同廠家的鼠標有不同的分辨率,若要讓主機知道鼠標的分辨率,就必須用到物理量的標簽。不使用也不會影響到鼠標的功能,只是使用者無法由主機的驅動程式得知分辨率而已。但是量測裝置(例如溫度計)的應用程序必須知道物理量,則這些標簽就必備了。分辨率r 的算法如下
r = ((lM-lm)/(PM-Pm))X10iUnit
其中lm = Logical Minimum,lM = Logical Maximum, pm = Physical Minimum,pM = Physical Maximum,i = Unit Exponent。以400-dpi 的鼠標為例如表3。
表3:解析度的范例
Logical Minimum(-127)
|
R = ((127-(-127))/(3175-(-3175))X10-4
= 400counts per inch
|
Logical Minimum(127)
|
|
Physical Minimum(-3175)
|
|
Physical Minimum(3175)
|
給定Logical值,計算出physical值:
((PM-Pm)/2)/10i=((127-(-127))/400)/2=0.3173
à|PM|=|Pm|=3175,i=4
|
Unit Exponent(-4)
|
|
Unit(inch)
|
注意,若是Unit Exponent 未定義,則視為i = 0﹔若是Physical Minimum和Physical Maximum有一個以上未定義,則視為PM=lM和pm=lm。所以標簽Physical Minimum和Physical Maximum 一定要同時定義,否則無意義。這些卷標的括號內數字為有符號的整數,可以是一個字節或二至四個字節,字節數目會在卷標代碼的最低二位定義,詳情后文會敘述。卷標Unit 的括號內數據比較復雜,總共用了7 個四位(nibbles)來描述,各個四位之意義如表4,其中第8 個四位
未被使用到。
表4:標簽Unit的信息格式
Nibbe
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
|
0
|
Luminous Intensity
|
Current
|
Temperature
|
Time
|
Mass
|
Length
|
System
|
HID 共享了四種單位系統,最低的四位就是決定使用的單位系統(System),不同的系統中當然物理量的單位也不一樣。單位和系統間的對應關系如表5。
表5:物理量的單位之編碼法
|
None
|
SI Linear
|
SI Rotation
|
English Linear
|
English Rotation
|
System
|
0x0
|
0x1
|
0x2
|
0x3
|
0x4
|
Length
|
None
|
公分
|
徑度
|
英寸
|
角度
|
Mass
|
None
|
公克
|
公克
|
Slug
|
Slug
|
Time
|
None
|
秒
|
秒
|
秒
|
秒
|
Temperature
|
None
|
凱氏(絕對溫度)
|
凱氏(絕對溫度)
|
華氏
|
華氏
|
Current
|
None
|
安培
|
安培
|
安培
|
安培
|
Luminous intensity
|
None
|
Candela
|
Candela
|
Candela
|
Candela
|
除了最低四位的值用來選擇單位系統外,其余每個四位皆表示該單位的冪次方,每個四位(nibble)都是有符號的整數,可表示的范圍為-8 至+7:
-8
|
-7
|
-6
|
-5
|
-4
|
-3
|
-2
|
-1
|
0
|
1
|
2
|
3
|
4
|
5
|
6
|
7
|
08h
|
09h
|
0ah
|
0bh
|
0ch
|
0dh
|
0eh
|
0fh
|
00h
|
01h
|
02h
|
03h
|
04h
|
05h
|
06h
|
07h
|
因此長度的單位若為公分則Unit (data)中data 的碼為0x11,若為英吋則為0x13,這二者中Length 的四位值皆為1 表示幕次方為1,即cm1 或in1 。質量單位為公克之碼為0x0101,加速度單位為公分除以平方秒之碼為0xE011,其中E 代表-2。所以力量單位為質量(公克)乘於加速度(公分/平方秒)的碼為0xE111。能量單位焦爾為力量乘於長度之碼為0xE121,其等義於s−2g cm2 和單位系統為SI Linear。
主項目
主項目中產生報告數據格式的三個卷標(Input,Output,和Feature)具有共通的數據定義,這些數據和其代碼列於表6中。目前用到9個位來表示這些數據。如果第九位(bit 8)為0,則僅需用一個字節來表示該數據,即忽略第九位。如果第九位為1,就需用到二個字節來表示該數據。
表6:主項目的信息代碼
Bit
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
Bit Field
|
Non Volatile
|
No Null Position
|
Preferred State
|
Linear
|
No Wrap
|
Absolute
|
Array
|
Data
|
1
|
Buffered Bytes
|
Volatile
|
Null State
|
No Preferred
|
Non Linear
|
Wrap
|
Relative
|
Variable
|
Constant
|
Data/Constant:主項目之數據為可變值(設為Data),或為固定不可變值(設為Constant)。Constant 都用於Feature 的報告,或是用於填充位(padding),使報告長度以字節為單位。
Array/Variable:主項目之數據的每個字段可以表示幾個不同的操作的其中一個被觸發(設為Array),或是每個字段僅表示一個操作(設為Variable)。如果是Variable,則Report Count 的數據值等於報告數據的字段數。若是Array,則Report Count 的數據值表示可以同時被觸發的最多操作數目。后文中鍵盤之例會解說Array 的用法。
Absolute/Relative:主項目的數據是以相對於固定的基准點方式提供絕對數值(設為Absolute),或是提供相對於前次報告的相對值(設為Relative)。
【范例說明】前文中的音量操控范例,因為都是Data 和Variable,二者的操作值皆為變化值,且一個字段僅表示一個操作。但是音量增減鍵的例子為Relative,所以若報告值由0 變成+1,則音量增大一個刻度,反之由0 變作-1 則音量減小一個刻度,因而音量大小因輸入值而作相對的變化。然而音量旋鈕的例子為Absolute,當輸入值為最小值0 時,為靜音,而輸入值為最大值100 時,為最大音量,其余值作百分比的音量調整,輸入值和音量成絕對關系。
No Wrap/Wrap:主項目的數據值達到極值后會轉為極低值,反之亦同,稱作卷繞(設為Wrap)。例如一個轉鈕可以做360°旋轉,輸出值從0 至10,若設定為Wrap,則值達10 后,在同方向旋轉則值變為0,反之若達到0,再轉就得到10。
Linear/Nonlinear:主項目的數據與操作刻度為線性關系(設為Linear),或為非線性(設為Nonlinear)。
Preferred State/No Preferred:主項目對應的操作再不被觸發時會自動恢復到初始狀態(設為Preferred State),或是不會恢復原狀(設為No Preferred)。例如鍵盤的按鍵和會自動置中(self-centering)的游戲桿,皆為Preferred State。
【范例說明】再以音量操作為例,音量增減鍵的例子都沒標注No Wrap,Linear,Preferred State,但是沒有標注即認定其屬於默認值,所以等同於是這些設定,只是這些設定對此例的操作無意義,所以不標出。音量旋鈕的例子明確指出其為No Wrap, Linear, No Preferred,可見旋鈕不是循環旋轉,輸出值與旋轉角呈線性關系,旋鈕釋放開時會停留在釋放前位置(因為No Preferred)。
No Null Position/Null State:主項目對應的操和有一個狀態,其不會送出有意義的數據,即數據將不在Logical Minimum 和Logical Maximum 之間,這種操控要標注Null State,否則為No Null Position。例如幾個按鍵,而無鍵被按下的用途沒有聲明在Usage 之列,則可以在主項目的數據中設Null State,將無鍵被按下的狀態排除在Logical Minimum 和Logical Maximum區間之外,進一步請參看Universal Serial Bus HID Usage Tables 文件的Appendix A.3 節中范例。
Non Volatile/Volatile:主項目Feature 的數據不允許被主機改變(設為Non Volatile),或是允許被主機改變(設為Volatile)。注意主項目Input 和Output,此標注設定無意義,所以bit 7 的代碼必須為0。
Bit Field/Buffered Bytes:主項目的數據格式要以字節為單位,不足構成字節時自動填充成字節則設Buffered Bytes。
最后來談談主項目的其它二個卷標:Collection 和End Collection。以鼠標而言,在實體上是一個指針(pointer),只是應用為計算機鼠標﹔而這個指針含有三個按鍵和二個平移軸X 和Y。所以指針的報告是由不同格式的數據所構成,因而需要用到Collection 和End Collection 將幾個Input 項目集結成一組,其用途為指針,再用Collection 和End Collection 將指針括起來說明其應用為鼠標。
卷標End Collection 沒有跟隨任何資料。但是卷標Collection 跟隨一個字節的數據,例如指針的數據名為Physical,而鼠標的為Application。所有Collection的數據名稱與代碼如表7:
表7:報告集合的名稱與代碼
|
Physical
|
Application
|
Logical
|
Report
|
Named Arrary
|
Usage Modifier
|
Usage Switch
|
Reserved
|
Vendor-defined
|
代碼
|
0x00
|
0x01
|
0x02
|
0x03
|
0x04
|
0x05
|
0x06
|
0x07-0x7f
|
0x80-0xff
|
用途
|
CP
|
CA
|
CL
|
|
Nary
|
US
|
UM
|
|
|
Collection 的數據名稱很難有一個准則來給定,Universal Serial Bus HID Usage Tables文檔中將各種用途的用途種類(usage type)列出,使用者必須依據用途種類來指定Collection 的數據名稱,例如鼠標,鍵盤和游戲桿的用途種類為CA,所以要用Collection (Application),而指針為CP,所以用Collection (Physical)。
編碼
報告描述符的項目編碼有二種:短項目和長項目。長項目僅是保留給未來使用,所以不作介紹。短項目的編碼形式如下:
Bits 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
[data]
|
[data]
|
bTag
|
bType
|
bSize
|
Bytes 2 1 0
最低字節分別標注項目大小(bSize),項目類別(bType),和項目卷標(bTag)﹔
其中bTag 占4個位,其余二者各占2個位。BSize 用來指出項目的數據所需字節的數目,該數目僅可以為0(當bSize=0),1(當bSize=1),2(當bSize=2),和4(當bSize=3)﹔注意不可以為3個字節。大部分的卷標僅需一個字節的數據﹔全局項目的卷標Unit 比較特殊有可能最多用到4 個字節來表示其資料。
標簽代碼bTag 已經於前章的表1 中描述,例如Input 的標簽代碼『0x8?』中8 即為bTag 之值﹔再如標簽Feature 之bTag=11,而Unit 之bTag=6。主項目之bType=0,全局項目之bType=1,而區域項目之bType= 2。所以在前章的表1 中的主項目卷標代碼中的『?』可以改為『00nnB』,全局項目的可以改為『01nnB』,而區域項目的可以改為『10nnB』,其中nn 代表bSize。
實際范例
這里舉一個Device Class Definition for Human Interface Device 文件的附錄E 中的整合鼠標的鍵盤裝置的范例。這個裝置只有一個組態描述符,但是這個組態具有二個接口,一個為鍵盤接口(接口編號為0x00),另一個為鼠標接口(接口編號為0x01)。每一個接口都有一個自己的中斷型輸入端點,輸出則都靠內定的控制型端點0。這個整合鼠標的鍵盤裝置的標准描述符,請參考附件中的『USB 標准描述符之技巧』文件。在該文中所使用的范例即為整合鼠標的鍵盤裝置,只是僅列出一個接口描述符(即編號為0x00 的鍵盤接口),另一個編號為0x01 的鼠標接口在該文中沒有列出,讀者可以自行參考本文所附的描述符程序代碼descriptor.asm(即在標記為interface_descriptor01,hid_descriptor01,和endpoint_descriptor01 處)。
表8:范例的輸入報告格式
鍵盤(輸入報告)
|
鼠標(輸入報告)
|
||||||||||||||||
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
Modifier keys
|
0
|
Pad
|
Buttons
|
|||||||||||||
1
|
Reserved
|
1
|
X displacement
|
||||||||||||||
2
|
Keycode 1
|
2
|
Y displacement
|
||||||||||||||
3
|
Keycode 2
|
|
|
||||||||||||||
4
|
Keycode 3
|
|
|
||||||||||||||
5
|
Keycode 4
|
|
|
||||||||||||||
6
|
Keycode 5
|
|
|
||||||||||||||
7
|
Keycode 6
|
|
|
表9:范例的輸出報告格式
鍵盤輸出報告
|
||||||||
Byte
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
0
|
Pad
|
LED’s
|
這個范例有輸入報告和輸出報告,其中輸入報告有二組,一組屬於鍵盤接口,另一組屬於鼠標接口。表8 列出輸入報告的數據格式。而輸出報告只有鍵盤接口需要,表9 為輸出報告的數據格式。因為有二個接口,所以有二個報告描述符,分屬於不同的界面,二個報告描述元都列於表10 中。鍵盤的報告描述元中整個報告集合的用途為(Generic Desktop: Keyboard),由於鍵盤用途屬於應用性,所以標簽Collection 的資料名為Application。由於單獨鍵本身的用途類頁不再是Generic Destop,而是Keyboard(注意Keyboard 也可為用途類頁),所以在項目Collection(Application)下重新聲明用途頁Usage Page (Keyboard)。根據Universal Serial Bus HID Usage Tables 文件,鼠標是指針的一種,只是應用為計算機的鼠標,所以報告的內層集合的用途為(Generic Desktop: Pointer),外層的應用性集合的用途為(Generic Desktop: Mouse)。注意鼠標的按鈕和位移軸又分屬不同的用途類頁,所以在內層集合中還要重新聲明用途類頁。按鈕的用途類業為Buttons,而二個位移軸所屬的用途類業為Generic Desktop。
表10:報告描述符范例
鍵 盤
|
鼠 標
|
||
項 目
|
編 碼
|
項 目
|
編 碼
|
Usage Page (Generic Desktop),
|
0x0105
|
Usage Page (Generic Desktop),
|
0x0105
|
Usage (Keyboard),
|
0x0609
|
Usage (Mouse),
|
0x0209
|
Collection (Application),
|
0x01A1
|
Collection (Application),
|
0x01A1
|
Usage Page (Keyboard),
|
0x0705
|
Usage (Pointer),
|
0x0109
|
Usage Minimum (224),
|
0xE019
|
Collection (Physical),
|
0x00A1
|
Usage Maximum (231),
|
0xE729
|
Usage Page (Buttons),
|
0x0905
|
Logical Minimum (0),
|
0x0015
|
Usage Minimum (1),
|
0x0119
|
Logical Maximum (1),
|
0x0125
|
Usage Maximum (3),
|
0x0329
|
Report Size (1),
|
0x0175
|
Logical Minimum (0),
|
0x0015
|
Report Count (8),
|
0x0895
|
Logical Maximum (1),
|
0x0125
|
Input (Data, Variable, Absolute),
|
0x0281
|
Report Size (1),
|
0x0175
|
Report Size (8),
|
0x0875
|
Report Count (3),
|
0x0395
|
Report Count (1),
|
0x0195
|
Input (Data, Variable, bsolute),
|
0x0281
|
Input (Constant),
|
0x0181
|
Report Size (5),
|
0x0575
|
Usage Minimum (0),
|
0x0019
|
Report Count (1),
|
0x0195
|
Usage Maximum (101),
|
0x6529
|
Input (Constant),
|
0x0181
|
Logical Minimum (0),
|
0x0015
|
Usage Page (Generic Desktop),
|
0x0105
|
Logical Maximum (101),
|
0x6525
|
Usage (X),
|
0x3009
|
Report Size (8),
|
0x0875
|
Usage (Y),
|
0x3109
|
Report Count (6),
|
0x0695
|
Logical Minimum (-127),
|
0x8115
|
Input (Data, Array),
|
0x0081
|
Logical Maximum (127),
|
0x7F25
|
Usage Page (LEDs),
|
0x0805
|
Report Size (8),
|
0x0875
|
Usage Minimum (1),
|
0x0119
|
Report Count (2),
|
0x0295
|
Usage Maximum (5),
|
0x0529
|
Input (Data, Variable, Relative),
|
0x0681
|
Logical Minimum (0),
|
0x0015
|
End Collection,
|
0xC0
|
Logical Maximum (1),
|
0x0125
|
End Collection
|
0xC0
|
Report Size (1),
|
0x0175
|
|
|
Report Count (5),
|
0x0595
|
|
|
Output (Data, Variable,Absolute),
|
0x0291
|
|
|
Report Size (3),
|
0x0375
|
|
|
Report Count (1),
|
0x0195
|
|
|
Output (Constant),
|
0x0191
|
|
|
End Collection
|
0xC0
|
|
|
從表8 看出,鍵盤的輸入報告中最低的8位分別代表鍵盤上的8個修飾鍵(亦即左和右邊的Control 鍵、Shift 鍵、Alt 鍵、和Windows 鍵),平常每位的值為0,當對應的修飾鍵被壓下時則位值為1。鍵盤報告描述符中第一個Input 項目必須聲明這8位的格式。這8個修飾鍵為用途類頁Key Codes 中的第224 個鍵到第231 鍵,所以用Usage Minimum (224)和Usage Maximum (231)來聲明。每一個按鍵的邏輯值不是0 就是1,所以用Logical Minimum(0)和Logical Maximum (1)
來聲明。很顯然的,每一個鍵占用一個數據位,而共需8個位,因此ReportSize ( 1),而Report Count (8)。請特別注意,最低位對應到Usage Minimum 的聲明,而最高位所對應的為Usage Maximum 的數據內容。這8 個位值是可變的數據,每一個位是獨立的變量,提供的值不須與前次的值有相對關系。總結而言,該8位的主項目必須為Input (Data, Variable, Absolute)。
鍵盤的輸入報告中次高的字節被保留,該字節的值無意義,也不需更新,所以用Input (Constant)來填充(padding)。而最高的6 個字節則是最近同時被壓下的6 個按鍵之代碼。這個鍵盤裝置有101 個鍵,而報告格式的最高的6 個位組中任何一個字節都可以代表101 個鍵之任一鍵,所以這101 鍵再加上無鍵被壓下狀態(代碼為0x00)構成一組操作數組,這個裝置允許同時壓下6個鍵。
鍵盤報告描述符中Input (Data, Array)即在聲明這6個字節的數據格式,注意這個數據格式的邏輯值聲明和用途代碼聲明具有相同的數據值(即0 和101)。
鍵盤有一個輸出報告,長度為1個字節,但是只用到最低5個位來代表五個LED 的操控,所以最高的3個位需要用Output (Constant)項目來填充。輸出報告的用途類頁不再是Key Codes,而是Page of LEDs,所以要重新聲明Usage Page,而主項目為Output (Data, Variable, Absolute)。這個項目的數據內容如同輸入報告的最低8位所聲明的主項目之數據內容,不再作說明。因為鍵盤接口的端點描述符只有聲明一個中斷型輸入端點,所以輸出報告需要依賴內定控制型端點0來傳送。輸入報告由聲明的輸入端點作中斷型輸入傳輸,當然也可以依需要用內定控制型端點0來作控制型讀入傳輸。
鼠標的報告描述符的輸入數據格式中最低的一個字節只有最低3個位有意義,其分別對應到鼠標上的三個按鈕,用途類頁為Buttons。其它二個字節的用途為(Generic Desktop: X)和(Generic Desktop: X),分別對應到鼠標X 軸和Y 軸的位移操控。這二個位移值得邏輯范圍為-127 到127,即一個字節可以表示最大范圍。位移的數值是相對值,所以主項目為Input (Data, Variable, Relative)。
HID 描述符編輯工具
USB 協會提供了一個HID 描述符編輯工具稱作HID Descriptor Tool,其執行程序為DT.exe。這個工具軟件可以在USB 網站上取得。雖然稱作HID 描述符工具,事實上,僅提供編撰報告描述符之用。執行DT.exe 后會出現如圖2 之窗口,小內窗口HID Items 列出所有報告描述符的標簽。以前面所舉的實際范例中鍵盤的報告描述符為例,首先點選[USAGE_PAGE],后會出現一個次窗口列出所有的Usage Page 的選項,這個例子要選[Generic Desktop],按[OK]后則次窗口消失,DT 的主窗口中的右邊小內窗口Report Descriptor 就出現Usage Page(Generic Desktop)並跟隨着該項目的編碼05 01(低字節在左邊),也就是這個工具可以幫助作自動編碼的工作。程序員只要輸入項目的卷標和內容,則可以由這個工具軟件提供報告描述符的程序代碼。接着,當點選第二個項目[USAGE]時,DT 軟件會根據前面的編簽Usage Page 的內容Generic Desktop,而產生一個次窗口列出Generic Desktop 包含的所有Usage 選項。同樣道理,當選完Usage Page
(Keyboard),再要編撰Usage Minimum 和Usage Maximum 時,所出現的次窗口則為Usage Page (Keyboard)所包含的全部Usage 選項,選第224 個為Left Control鍵當用途范圍的最小者,再選第231 個為Right GUI 鍵當用途范圍的最大者。其他項目的編撰以此類推。
在主窗口下,點選下拉選項[File]中的[Info],則會出現訊息窗口,告知編撰的描述符中項目的個數和描述符長度所需字節的數目。編撰報告描述符完成后,還要做語法檢驗,這時點選下拉選項[Parse Descriptor],則DT 軟件會告知檢查的結果,並提供錯誤原因與更改的建議。

總結
最后一個問題是如何將報告描述符加入微控器的匯編程序。對於任何一種描述符,都是以匯編語言中的一個標記來分辨,例如第一個接口的報告描述符的標記就稱作hid_report_descriptor00;同樣的,第二個界面的就稱作hid_report_descriptor01。記得在報告描述符結束處也加上一個標記,如end_hid_report_descriptor00 和end_ hid_report_descriptor01。這個結束標記除了有助於閱讀程序外,其最主要的用處是可以用來計算描述符的長度(即字節數)。例如使用dwl end_hid_report_descriptor00 - hid_report_descriptor00組譯器就會自動算出第一個報告描述符的長度,這個長度以二個字節來記載。“dwl”為匯編語言的指示,在於儲存二個字節的數據,儲存的方式為little Endian。所謂little Endian 方法,就是將低字節的值存於低地址值的內存空間,高字節之值存於高地址值處。