2015年1月20日 星期二

HID over I2C Device

如果一個I2C Device是相容於HID規範的話,從Register 0位置便可讀取出HID Descriptor。
這邊有個範例,讀出來的資料如下:
1E 00 00 01 A0 03 02 00 03 00 2A 00 00 00 00 00
04 00 05 00 AA AA BB BB 11 00 00 00 00 00

在此可對應到此表格:
Byte OffsetFieldSize(Bytes)Example
0wHIDDescLength21E
2bcdVersion201
4wReportDescLength23A0
6wReportDescRegister202
8wInputRegister203
10wMaxInputLength22A
12wOutputRegister20
14wMaxOutputLength20
16wCommandRegister204
18wDataRegister205
20wVendorID2AAAA
22wProductID2BBBB
24wVersionID211
26RESERVED40

此Table為Device的Information,除了最基本的VID、DID外,還有各個Register的Index指出Data該從哪邊讀與該從哪邊寫。
而wReportDescRegister是Report Descriptor的Index,從此Index將會讀取出一大串的Data,可參考wReportDescLength先配置好存放這些Data的記憶體空間。
關於一個Device的所支援的各種Type都會在這個Descriptor裡面,而一個Descriptor可能會有好幾組Usage Page與Report ID。
例如一個Touch Panel可能會支援Finger與Pen,而這兩個所使用的Report ID是不同的,所以需要去解析每個Report,去取得所要的資料。

Report Descriptor

這邊將探討如何去解析Report Descriptor。
Report Descriptor裡面是由一個個Item所組成的,可分為Short Items與Long Items,通常使用Long Items的情況為,需要存放額外的大量資料時才使用Long Items,否則一般都是用Short Items,長度為1到5 bytes。

可以先判斷一個Item是Short Item或Long Item:
Short Items:
 

先看第一個Byte (Offset 0),可以分成三個部分並對應到下表:
bSizeNumeric expression specifying size of data
00 bytes
11 bytes
22 bytes
34 bytes

bTypeNumeric expression identifying type of item where
0Main
1Global
2Local
3Reserved

bTagNumeric expression specifying the function of the item
[data]Optional data

Data長度可參考bSize,對Short Item來說最多就是4個Bytes。

Long Items:


如果第一個Byte (Offset 0)是0xFE,那這個便是Long Item,而第二個Byte就用來表示整個Data Size,第三個Byte為其Tag,而後面就是整個Data部分。

在此簡單舉一個例子:
05 0D 09 04 A1 01 85 0C 95 01 75 08 26 FF 00 15
00 81 03
09 54 81 02 05 0D 09 22 A1 02 09 42 15
00 25 01 75 01 95 01 81 02 81 03 09 47 81 02 95
05 81 03 75 10 09 51 95 01 81 02 05 01 75 10 95
01 55 0E 65 11 09 30 26 0C 28 35 00 46 03 0A 81
02 46 A2 05 09 31 26 88 16 81 02 C0 05 0D 09 22

這是一部分的Report Descriptor,從第一個Byte開始。
05: 00000101b Tag: 0000b Type: 01b Size: 01b
Type: 01b (Global Items)
Tag: 0000b (Usage Page)
Data: 0D (Digitizer)

09: 00001001b Tag: 0000b Type: 10b Size: 01b
Type: 10b (Local Items)
Tag: 0000b (Usage)
Data: 04 (Touch Screen)

A1: 10100001b Tag: 1010b Type: 00b Size: 01b
Type: 00b (Main Items)
Tag: 1010b (Collection)
Data: 01 (Application)

85: 10000101b Tag: 1000b Type: 01b Size: 01b
Type: 01b (Global Items)
Tag: 1000b (Report ID)
Data: 0C

95: 10010101b Tag: 1001b Type: 01b Size: 01b
Type: 01b (Global Items)
Tag: 1001b (Report Count)
Data: 01

75: 01110101b Tag: 0111b Type: 01b Size: 01b
Type: 01b (Global Items)
Tag: 0111b (Report Size)
Data: 08

26: 00100110b Tag: 0010b Type: 01b Size: 10b
Type: 01b (Global Items)
Tag: 0010b (Logical Maximum)
Data: 00FF

15: 00010101b Tag: 0010b Type: 01b Size: 01b
Type: 01b (Global Items)
Tag: 0010b (Logical Minimum)
Data: 00

81: 10000001b Tag: 1000b Type: 00b Size: 01b
Type: 00b (Main Items)
Tag: 1000b (Input)
Data: 03

以此類推,可以看到每個Item就是這樣串起來的。
解析整個Report Descriptor並不難,但需要一直對照Spec,可參考HID1_11.pdf。

Input Register


Input Register可從wInputRegister這個位置讀出來,但還是必須先做一些前置處理,否則會不知道它的Layout(每個資料所在的Offset,如X、Y軸)。
這部分的資訊可從Report Descriptor取得。
Example:(這不是一個完整的Report Descriptor)
Usage Page (Digitizer)
Usage (Touch Screen)
Collection (Application)
  Report ID (0x0C)
  Report Count (1)
  Report Size (8)

  Input (0x03)
  Usage (Reserved)
  Input (0x02)
  Usage Page (Digitizer)
  Usage (Finger)
  Collection (Logical)
    Usage (Tip Switch)
    Report Size (1)
    Report Count (1)

    Input (0x02)
    Input (0x03)
    Usage (Reserved)
    Input (0x02)
    Report Count (5)
    Input (0x03)
    Report Size (16)
    Usage (Reserved)
    Report Count (1)
    Input (0x02)
    Usage Page (Generic Desktop Controls)
    Report Size (16)
    Report Count (1)

    Usage (X)
    Input (0x02)
    Usage (Y)
    Input (0x02)
  End Collection ()

上面共有9個Input,首先可以注意在Input前面有Report Count與Report Size,每看到一個新的Report Count或Report Size,就以新的值來取代。
所以上面的例子:
Input 1st Length: 8 bits
Input 2nd Length: 8 bits
Input 3rd Length: 1 bits
Input 4th Length: 1 bits
Input 5th Length: 1 bits
Input 6th Length: 5 bits
Input 7th Length: 16 bits
Input 8th Length: 16 bits
Input 9th Length: 16 bits

而在第8個Input前的Usage (X)是Usage Page (Generic Desktop Controls)的X座標值,第9個Input前的Usage (Y)為Y的座標值。

以下為從Input Register讀出來的資料:
2A 00 0C 00 01 05 01 00 81 00 2B 01 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 1C A9

前面兩個Byte為整個資料的長度:2A (42個Bytes)
0C為對應的Report ID,代表讀回來的Register是對應到這個Report。
前面有提到一個Panel可能有支援Finger與Pen等。所以從Device讀出來的Report Descriptor會有好幾組Usage Page,每一組可能都會有對應的Report ID。
所以讀回來的Input Register會處理前,要先比對一下是不是相同的ID,不是的話就再換下一個Usage Page。

而在這3個Bytes後面就是實際上要使用的Data,可以從剛剛上面的Input,來推算出對應的Usage的Offset。
Usage (Tip Switch)的值: 05 (bit 0)
Usage (X)的值: 0081
Usage (Y)的值: 012B