# HID Over I2C Protocol
## INTRODUCTION
HID 最簡單的定義: 人可以控制的計算機系統設備。 市面上最常見的 HID 裝置如下
1. Pointing device(TP,Screen,Stylus)
2. Keyboard
3. Bar-code reader
4. VR
HID 協定是屬於<u>非同步</u>,溝通的規則上會有<u>**HOST**</u>和<u>**DEVICE**</u>。 協定中為 DEVICE 定義一種格式(Descriptors),以向 HOST 描述其能力。 一旦 HOST 理解了與 DEVICE 的通信格式,就會對 DEVICE 進行認證流程,以便DEVICE將數據發送回 HOST。
HID protocol spec 由以下幾點所代出:
1. Scenarios
A.**Touchpad**
B.**Sensor**
C.TouchScreen
D.Stylus
2. Descriptors
3. Reports
4. Requests
5. Power Management Error Correction
## I2C SPECIFIC DETAILS
### BUS SPEEDS
| Mode | Speeds |
| -------- | -------- |
| Standard Mode | 100 kbit/s |
| <font color=#0000FF>**Fast Mode** </font>|<font color=#0000FF> **400 kbit/s** </font>|
| Fast Mode Plus | 1 Mbit/s |
| High Speed Mode | 3.4 Mbit/s |
### INTERFACE LAYOUT

目前的DEVICE HW設計是I2C BUS Controller(<font color=#FF0000>SDA、SCL</font>) + GPIO Controller(<font color=#FF0000>INT</font>)。 INT是當DEVICE需要將資料傳給HOST時,將電壓 pull low,已通知HOST,HOST 才開始震動CLK,來讓DEVICE 透過SDA傳送由1bit組成的資料。
### Byte Ordering
傳送所有封包(Descriptors、Requests、Responses)是以<font color=#FF0000>Little endiend</font>方式→
LSB先,接著是MSB。
假設Device傳送 X軸資料 0x05,0xE1,收到後要轉換成 0xE105。
### SLAVE ADDRESS
每個裝置 or Sensor的datasheet都會說明自己的address。
實作時,雙方coder(Device and Host)要溝通好是<font color=#FF0000>7 or 8 </font>bits address。
LSB bit是表示這次的通訊資料,是Read or Write,所以address最多還是7-bit。
7bit

8bit

#### 科普小教室:傳統I2C
1.沒有INT pin
2.一條I2C Bus上面有多種Device
3.HOST Always Polling
## DESCRIPTORS
### HID Descriptor
目前介紹的是<font color=#FF0000>I2C</font>的HID Descriptor,USB HID Descriptor會不一樣。
#### HOST to DEVICE Command:
| Address | HID Desc Addr-LSB | HID Desc Addr-MSB |
| -------- | -------- | -------- |
| SLAVE Addr | 0x01 or 0x00 | 0x00 |
回覆封包的<font color=#FF0000>固定長度為30 bytes</font>,第一筆封包固定為0x1E。 資訊如下列
| Field | Byte Offset | Size(Bytes) | Example |
| ------------------ | ----------- | -- | -- |
| HIDDescLength | Index 0 | 2 | 0x001E |
| bcdVersion | Index 2 | 2 | 0x0000 |
| ReportDescLength | Index 4 | 2 | 0x0A30 |
| ReportDescRegister | Index 6 | 2 |0x0002 |
| InputRegister | Index 8 | 2 | 0x0003 |
| MaxInputLength | Index 10 | 2 | 0x0010 |
| OutputRegister | Index 12 | 2 | 0x0000 |
| MaxOutputLength | Index 14 | 2 | 0x0000 |
| CommandRegister | Index 16 | 2 | 0x0000 |
| DataRegister | Index 18 | 2 | 0x0000 |
| VendorID | Index 20 | 2 | 0x0000 |
| ProductID | Index 22 | 2 | 0x0000 |
| VersionID | Index 24 | 2 | 0x0000 |
| Reserved | Index 26 | 4 | 0x0000 |
Input、Output 、Feature Command 都會依照宣告的HID Descritpor執行。
Note:
以下必須唯一:
**1. ReportDescRegister
2. InputRegister
3. OutputRegister
4. CommandRegister
5. DataRegister**
### Report Descriptor
ReportDescRegister與ReportDescLength是透過`Device Descriptor`得知。並非固定值。
意即DEVICE的**自我介紹**,讓HOST了解此DEVICE。
1. 哪一類的HID CLASS
2. Raw Data每一個byte所代表的意義,更可以細分成每一個bit。
PS.須以<font color=#FF0000>1bytes</font>為單位,意即定義bits要補齊成1bytes。
#### HOST to DEVICE Command:
| Address | Report Desc Addr-LSB | Report Desc Addr-MSB |
| -------- | -------- | -------- |
| SLAVE Addr | ReportDescRegister LSB | ReportDescRegister MSB |
#### 如何建立一個合格的Report Descriptor
1.[HID Descriptor tool 輔助工具](https://www.usb.org/document-library/hid-descriptor-tool)(From USB.Org, 年代久遠,Usage部分很久沒更新)
2.自己寫
[教學](https://hackmd.io/tvH-lr4tRJOoj5Q4OzpkOQ?both)
#### 專案上遇到的問題
1. Yellow Band(YB)的發生,大部分都會在Report Desc,因為長度較長,且有Power State切換的過程。
## REPORT PROTOCOL
HOST與DEVICE之間,透過三種Report方式做傳遞資料。資料長度 與 Report方式是透過 Report Descritpor去定義的。
1. Input Reports: DEVICE -> HOST , 單方向。
2. Output Reports: HOST -> DEVICE , 單方向。
3. Feature Report: HOST <-> DEVICE , 雙方向。
### Input Reports and Output Reports
資料的長度是透過HID Descriptor得知(wMaxInputLength,wMaxOutputLength)
根據Report Descriptor的Collection 宣告的方式,分成
1. SINGLE TOP LEVEL COLLECTION
2. MULTIPLE TOP LEVEL COLLECTIONS。
如果有多個DEVICE宣告下,每個DEVICE都需要一個REPORT ID,讓HOST知道是哪個DEVICE的資料。
#### SINGLE TOP LEVEL COLLECTION
| Length| Report |
| -------- | -------- |
| 2 Unsigned Bytes | .... |
#### MULTIPLE TOP LEVEL COLLECTION
| Length| Report ID | Report |
| -------- | -------- | -------- |
| 2 Unsigned Bytes| 1 Byte | .... |
### Feature Reports
HOST只需要少許的資料長度,即可得到DEVICE設定或狀態。並且有以下特點
1. 不需要判斷INT pin的狀態。
2. 只能透過GET_REPORT,SET_REPORT的"Request"來處理。
#### 科普小教室: I2C over HID and USB 封包
1. USB:<font color=#FF0000>不</font>需要長度封包
2. I2C over HID:需要長度封包→MaxInputLength要包含長度2bytes
#### 專案上遇到的問題
假設HID Descriptor Max Input Len ,超過Report Desc的定義的長度,是否會有問題?
## REQUEST
HOST透過Command and Data Registers, 來管理DEVICE跟Info or 狀態為何。
### Command Register
除了Register之外,還須包含2 bytes value。Command Register只能透過HOST寫入,並由DEVICE讀取。
Data Value的定義
MSB

LSB

* Reserved必須填0
* Repor Type的表示value如下:
* 00 - Reserved
* 01 - Input
* 02 - Output
* 11 - Feature
* Reprot ID是Report Descriptor定義的Feature Report ID。
### Data Register
要詢問DEVICE的Info或狀態,就要使用到,不能單獨使用,必須接在Command Register後面。Data Register的後面2bytes,必須包含長度(2bytes)
,再計算長度時,也需要將長度計算進去。
意即,長度後面有5bytes,長度必須為5+2=7。
### 常用到的Request
#### 1.RESET
有兩種RESETs方式:
1. HOST initiated Reset(HIR)
2. Device initiated Reset(DIR)
##### HIR
HOST可以隨時要求DEVICE進行initial,DEVICE須回到初始狀態

當HOST執行了此REQUEST,DEVICE需在<font color=#FF0000>5secs</font>內,將INT pull low,並且將2bytes 0x00回覆給HOST。不然HOST就不會將Input Report Data往<font color=#FF0000>Inbox Driver</font>送。
##### RESET Command:
| Command Register-LSB | Command Register-MSB | Command Value-LSB | Command Value-MSB |
| -------- | -------- | -------- | -------- |
| Command Register LSB |Command Register MSB | 0x00 | 0x01 |
##### DIR
如果DEVICE遭遇到下列情況,也可以透過Input Report方式,將2bytes 0x00回覆給HOST,告知HOST 自己已經Reset了
1. ESD 打到Reset
2. 跑到錯誤的State Machine、無窮迴圈,執行了watch dog(Software Reset)
###### 專案上遇到的問題
1. HIR Reset CMD沒有回覆2bytes 0x00,是否會YB(Yellow Band)?
---
#### SET POWER
告知DEVICE,需要將Power State切成 Enable or Sleep。

Power State Value:
* 00 - ON
* 01 - SLEEP
* 1X - RESERVED
#### SET POWER ENABLE Command:
| Command Register-LSB | Command Register-MSB | Command Value-LSB | Command Value-MSB |
| -------- | -------- | -------- | -------- |
| Command Register LSB | Command Register MSB | 0x00 | 0x08 |
#### SET POWER SLEEP Command:
| Command Register-LSB | Command Register-MSB | Command Value-LSB | Command Value-MSB |
| -------- | -------- | -------- | -------- |
| Command Register LSB | Command Register MSB | 0x01 | 0x08 |
#### SET REPORT
使用SET "FEATURE" REPORT的情況有兩種
1. 讓DEVICE執行對應的設定,與Driver or AP互相搭配。ex:進入update、Lid off sleep mode 等等
2. 請DEVICE"準備"回覆目前對應的狀態,不可以直接回傳,在Get Report之前。
ex: PID、IC Type、IC Status、Setting 跳頻 Threshold 等等。

按照上述所提到的<font color=#FF0000>Data Register</font>,此時就要派他上場了。
#### SET FEATURE REPORT Command:(Feature Report 4 bytes,且 Get VID為例)
| Command Register-LSB | Command Register-MSB | Command Value-LSB | Command Value-MSB | Data Register-LSB | Data Register-MSB | Length-LSB | Length-MSB |Report ID | Extension Register-LSB | Extension Register-MSB | Extension Value-LSB | Extension Value-MSB |
| -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- | -- |
| Command Register LSB | Command Register MSB | 0x30 + Report ID | 0x03 | Data Register LSB | Data Register MSB | 0x07 | 0x00 | Report ID | 0x05 | 0x03 | 0xA0 | 0x01 |
#### GET REPORT
透過SET "FEATURE" REPORT準備好資料,接著等待HOST使用GET "FEATURE" REPORT來回覆DEVICE的狀態與資訊。

#### GET FEATURE REPORT Command:
| Command Register-LSB | Command Register-MSB | Command Value-LSB | Command Value-MSB | Data Register-LSB | Data Register-MSB |
| -- | -- | -- | -- |-- |-- |
| Command Register LSB | Command Register MSB | 0x30 + Report ID | 0x02 | Data Register LSB | Data Register MSB |
回覆 GET FEATURE REPORT: (Feature Report 4 bytes,且 Get VID為例)
| Length-LSB | Length-MSB |Report ID | Extension Value-LSB | Extension Value-MSB | Reply Value-LSB | Reply Value-MSB |
| -- | -- | -- | -- | -- | -- | --|
| 0x07 | 0x00 | Report ID | 0xA0 | 0x01 | 0x05 | 0x0B |
#### 實例
##### SET REPORT(PTP 切 mode)

##### GET REPORT(Get VID)

## DEVICE INITIAL 流程
HOST依序對DEVICE下此一連串Command:
Device Desc→ Set Power ON→ Reset→ Report Desc
