USB/HID設備報告描述符詳解 (3)

本文由小楠瓜餅從http://www.cnblogs.com/zsb517/archive/2012/06/03/2532408.html轉載

USB/HID設備報告描述符詳解 (3)

2012-06-03 00:24 by 細雨淅淅, 142 閱讀, 0 評論, 收藏編輯

USB描述符即USB設備的信息,系統設備列舉所要執行的工作之一,即是取得這些有關於設各的相關信息,之後設備才能被系統識別使用。

在圖的描述符中,設備描述符(device descriptor)、配置描述符(configurationdescriptor)、接口描述符(interface  descriptor)以及端點描述符(endpoint descriptor)是必須具有的。而其他的描述符,如字符串描述符(strtng descriptor)、 數種不同的羣組描述符(class descriptor)以及報告描述符(report descriptor)則可以根據不同的設備加以添加或刪減。

報告描述符是HID用來 數據傳輸(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 = ((lM-lm)/(PM-Pm))X10i Unit
其中lm = Logical Minimum,lM = Logical Maximum, pm = Physical Minimum,pM = Physical Maximum, = 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 未定義,則視爲= 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 方法,就是將低字節的值存於低地址值的內存空間,高字節之值存於高地址值處。

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