2011年10月21日 星期五

V-USB hid-data 範例解說

承上篇,這篇將摘要說明 V-USB hid-data 範例程式。

hid-data 分成韌體和指令列工具 (commandline) 兩個部份。

韌體

usbconfig.h

底下是 hid-data 對 usbconfig.h 所做的調整:

  • USB_CFG_IOPORTNAME, USB_CFG_DMINUS_BIT 與 USB_CFG_DPLUS_BIT

這些設定 USB bus D+ 和 D- 所用的接腳。預設是:

#define USB_CFG_IOPORTNAME      D
#define USB_CFG_DMINUS_BIT      4
#define USB_CFG_DPLUS_BIT       2

  • #define USB_CFG_HAVE_INTRIN_ENDPOINT    1

這個設定 interrupt-in endpoint 1,這是 HID device 的必要選項。

  • #define USB_CFG_INTR_POLL_INTERVAL      100

這個設定 interrupt-in endpoint 1 的 poll interval,單位為 miliseconds,不能小於 10 ms。

  • USB_CFG_VENDOR_ID 與 USB_CFG_DEVICE_ID

這些設定 VID 和 PID。預設是:

#define  USB_CFG_VENDOR_ID       0xc0, 0x16
#define  USB_CFG_DEVICE_ID       0xdf, 0x05

資料表示方式是 low byte first,VID 0x16c0 和 PID 0x05df 是 obdev 提供的共享 VID/PID。

  • USB_CFG_DEVICE_NAME and USB_CFG_DEVICE_NAME_LEN

這些設定 Device Name 和資料長度,hid-data 把 Device Name 設成 "DataStore",資料長度是 9:

#define USB_CFG_DEVICE_NAME     'D', 'a', 't', 'a', 'S', 't', 'o', 'r', 'e'
#define USB_CFG_DEVICE_NAME_LEN 9

  • USB_CFG_DEVICE_CLASS 與 USB_CFG_INTERFACE_CLASS

這些設定 Device Class 和 Interface Class。hid-mouse 的設定為:

#define USB_CFG_DEVICE_CLASS        0
#define USB_CFG_INTERFACE_CLASS     3

USB 有定義一些常用的 device class,可在 USB Class Codes 這個頁面中找到,0 代表由 interface 指定。而 interface class 定義 3 代表這個是 HID Class。

  • #define USB_CFG_HID_REPORT_DESCRIPTOR_LENGTH    22

這個設定 HID report descriptor 的資料長度。你必須在程式裏定義一個叫 usbHidReportDescriptor 的陣列,用來存放 report descriptor,而且陣列 size 要跟這個設定一致為 22 bytes 才行。

  • USB_CFG_IMPLEMENT_FN_READ 與 USB_CFG_IMPLEMENT_FN_WRITE  

這會設定呼叫 usbFunctionWrite() 來處理 control-out transfer,而用 usbFunctionRead() 來處理 control-in transfer:

#define USB_CFG_IMPLEMENT_FN_WRITE      1
#define USB_CFG_IMPLEMENT_FN_READ       1

main.c

主程式分成 main() 和 usbFunctionSetup() 兩個函式。關於 main() 和 usbFunctionSetup() 兩個函式的說明,請參考「V-USB custom-class 範例解說」一文。

在這個範例程式中,main loop 的工作很單純,只是不斷呼叫 usbPoll() 讓 driver 處理工作。根據 V-USB 的說明,usbPoll() 至少每 50 ms 要跑一次。

底下是 hid-data的 usbFunctionSetup():

程式的邏輯是透過 bRequestRequest 判斷是不是 class request,假如是,再依 bRequest 判斷是哪一種 class request (Get Report, Set Report, Get Idle, Set Idle, Get Protocol 或 Set Protocol)。hid-data 只處 Get Report 和 Set Report 兩個 requests。在這個範例中,Get Report 是傳回 feature report 給 Host,而 Set Report 則是接收來自 host 端的 feature report。因為只有一個 feature report,所以 Get/Set Reports 沒有進一步判斷 ReportType (wValue high byte) 和 Report ID (wValue low byte)。

當收到 Get Report 或 Set Report 的 request 時,usbFunctionSet() 並沒有馬上把資料傳給 Host,而是回傳 USB_NO_MSG 讓 V-USB Driver 呼叫 usbFunctionRead() 和 usbFunctionWrite() 來處理。

usbFunctionRead() 的實作如下:

只是單純從 eeprom 讀取一塊資料 (data chunk) 並放到 buffer 給 Driver 處理。

而 usbFunctionWrite() 的實作如下:

也只是單純把從 host 收到的一塊資料 (data chunk) 寫到 eeprom。

HID Report  Descriptor

底下是 hid-data 所定義的 HID Report Descriptor:

上列定義一個 Feature Report,資料長度為 128 bytes。

指令列工具 (commandline)

指令列工具包含 hiddata.c 和 hidtool.c。hid-data 把開啟 USB device 以及 Get Report 和 Set Report 的功能集中到 hiddata.c。

主程式 hidtool.c 只是間接呼叫 hiddata.c 中的 usbhidGetReport() 和 usbhidSetReport(),假如是 usbhidGetReport() 會將收到的資料以 hex format 印出,除此之外,沒有值得一提的地方。

hid-data 利用 usb_control_msg() 發送 control message,usb_control_msg() 的原型為:

int usb_control_msg(usb_dev_handle *dev, int requesttype, int request, int value, int index, char *bytes, int size, int timeout);

以 Get Feature Report 為例,呼叫方法為:

其中 USB_TYPE_CLASS 指定 Class request,USB_RECIP_DEVICE 指定接收者為 Device,而 USB_ENDPOINT_IN 則是指定 Control-IN transfer。USBRQ_HID_GET_REPORT 表示 Get Report 的 request,而 wValue 高位元組為 USB_HID_REPORT_TYPE_FEATURE 表示要取 Feature Report,而低元組是 report number,在此為 0。

而 Set Feature Report 的呼叫方法則為:

其中 USB_ENDPOINT_OUT 指定 Control-OUT transfer。

延伸閱讀

0 意見: