這篇將摘要說明 V-USB custom-class 範例的程式碼。要讀這篇,讀者必須對 USB 有足夠的認識。
customer-class 分成兩個部份:韌體和 PC 端的指令列工具 (commandline)
韌體
usbconfig.h
usbconfig.h 是 V-USB 的設定檔,每個 V-USB 的程式都會從 V-USB 的 usbconfig-prototype.h 複製過來並改名為 usbconfig.h 然後根據自己的硬體調整設定。
底下是 custom-class 對 usbconfig.h 所做的調整:
- USB_CFG_IOPORTNAME, USB_CFG_DMINUS_BIT and 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
- USB_CFG_VENDOR_ID and USB_CFG_DEVICE_ID
這些設定 VID 和 PID。預設是:
#define USB_CFG_VENDOR_ID 0xc0, 0x16
#define USB_CFG_DEVICE_ID 0xdc, 0x05資料表示方式是 low byte first,VID 0x16c0 和 PID 0x05dc 是 obdev 提供的共享 VID/PID。
- USB_CFG_DEVICE_NAME and USB_CFG_DEVICE_NAME_LEN
這些設定 Device Name 和資料長度,custom-class 把 Device Name 設成 "LEDControl",資料長度是 10:
#define USB_CFG_DEVICE_NAME 'L', 'E', 'D', 'C', 'o', 'n', 't', 'r', 'o', 'l'
#define USB_CFG_DEVICE_NAME_LEN 10
- USB_CFG_DEVICE_CLASS = 0xff
這個設定 Device Class。USB 定義了一些常用的 device class,你可以在 USB Class Codes 這個頁面中找到。0xff 代表的是 "Vendor Specific",也就是廠商自行定義的 function。
request.h
這個檔案由 host software 和 device firmware 所共享,它定義 host 和 device 之間通訊的 request number。
custom-class 共定義了三個 request numbers:
- #define CUSTOM_RQ_ECHO 0
這是對 device 要求送回 wValue 和 wIndex 的 request (Control-IN),用來測試通訊的可靠度。wValue 和 wIndex 只有在 USB Specficication 或 device class specification 有定義時才有意義。對於 Vendor request 而言,可以送任意的資料。
- #define CUSTOM_RQ_SET_STATUS 1
設定 LED 狀態 (Control-OUT)。要求的 LED 狀態會放在 control transfer 的 wValue 欄位中,wValue 低位元組 Bit 0 用來控制 LED 的開關,1 是開,0 是關。control transfer 的 data stage 實際上沒有送出 OUT data (zero length data)。
- #define CUSTOM_RQ_GET_STATUS 2
取得 LED 目前的狀態 (Control-IN)。這個 control transfer 在 data stage 中 device 會送 1 個 byte 的資料給 host,LED 的狀態會儲存在 data byte 的 BIT 0。
main.c
主程式分成 main() 和 usbFunctionSetup() 兩個函式。
main() 的邏輯很簡單,首先呼叫 usbInit() 初始化 V-USB driver,接著先做一個強迫 USB enumeration 的動作,然後呼叫 sei() 啟用中斷並進入 main loop。main loop 是一個無窮迴圈,在 main loop 中,必須呼叫 usbPoll() 讓 driver 處理工作。根據 V-USB 的說明,usbPoll() 至少每 50 ms 要跑一次。
usbFunctionSetup() 用來處理 endpoint 0 的 control message 中屬於 vendor 或 class 的 requests。它有一個參數: 一個指向 8 bytes 的 setup data 的指標。使用者必須檢查 request 種類並接收 (Control-OUT ) 或回傳 (Control-IN) 資料給 host。
這 8 bytes 的 setup data 的結構型別是 usbRequest_t,定義在 usbdrv.h:
最基本的 usbFunctionSetup() 是根據 wValue 的 request number 打開或關閉 LED,底下用 request number 1 示範:
底下是 custom-class的 usbFunctionSetup():
如你所見,程式邏輯只是透過 bRequest 判斷是哪一個 request number,然後再依 request number 執行對應的動作,看是要設定 LED 狀態、取得 LED 狀態或是做 ECHO Test,就這麼簡單。關於 request number,請參考前面 request.h 的說明。
指令列工具 (commandline)
指令列工具包含 opendevice.c 和 set-led.c。custom-class 把開啟 USB device 的功能集中到 opendevice.c。
要打開指定 VID/PID 的 USB device,只要呼叫 usbOpenDevice() 函式即可,如下:
custom-class 利用 libusb 的 usb_control_msg() 發送 control message,邏輯主要都寫在 set-led.c。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);
以打開或關閉 LED 的 request 為例,呼叫方法為:
其中 USB_TYPE_VENDOR 指定 Vendor request,USB_RECIP_DEVICE 指定接收者為 Device,而 USB_ENDPOINT_OUT 則是指定傳輸型態為 Control-OUT transfer。isOn 為 1 代表開 LED,0 代表關 LED。
而查詢 LED 狀態的 request 為:
其中 USB_ENDPOINT_IN 指定傳輸型態為 Control-IN transfer。
關於 setup data 的資料結構,可參考 USB Specification 這張表格:
沒有留言:
張貼留言
注意:只有此網誌的成員可以留言。