2023年6月18日 星期日

For Xamarin.android 如何用Android.Hardware.usbconnect來做HID 的write report類似的動作

 最近拿到一個設備做整合的案子,是USB-HID介面
跟廠商要到的sample code是用HidSharp的寫.
-------------------------------
                    var device = HidDevices.Enumerate(vendorId, productId).First();
                    dev.OpenDevice();
                    const UInt32 ZEROS=0x00;
                    const UInt32  Heading04=.....;
                    var bytes=new List<Byte>();
                    bytes.AddRange(BitConverter.GetBytes(Heading04).Reverse().ToArray());
                    bytes.AddRange(BitConverter.GetBytes(ZEROS).Reverse().ToArray());
                    //to write data to HID,use "report" as pocket
                    var outputReport = dev.CreateReport();
                    outputReport.ReportId = 0;
                    outputReport.Data=bytes.ToArray();
                    dev.WriteReport(outputReport);
-------------------------------
今欲轉移到安卓設備上,一直找不到HID 類似的實作.
「既然沒有,就自己包了」,不過HID真的是很不單純的規格(光是USB就有一堆書跟規格要看了),談個容易
「不然就觀察看看上述的code,在USB介面是如何動作的?」
 這時就要借助好用的工具「DeviceMonitor Studio」(試用期14天,動作快!!)
因為我們知道是用USB的HID規格,所以監視方式請用HID等選項


不過,真正比較有用的是在packet view的狀態.....

嗯,看那裡面的參數Request、Value、index、data.... ,真的是「火燒豬頭-- 面熟面熟咧」 
「阿這不就是UsbConnection的ControlTransfer嘛」
「好啊,那你試看看用controlTransfer會不會傳回-1?如果不是-1表示成功了」
先讀看看Descrption看看,如果可能,就可以把其他動作給它(controlTransfer)來做了
xamarin.android ControlTransfer的API在此
「我試了UsbAddressing.In的方式一直讀取不了資料,心很累....」
別一開始就埋頭苦幹用戇力(gōng-lak)--先找成功案例的code來改來測才好比對驗證
先以這篇討論的例子來改
---
UsbDeviceConnection.controlTranfer(0x81, 0x06, 0x2200, 0x00, byte[] buffer, 104, 2000)
----
「第一個參數不是UsbAddressing型態嗎?怎麼會是一個叫0x81的整數?」
「儘信API不如無API,更何況那是從java包裝來的,直接把0x81 cast成UsbAddress就是了」
所以用以下的code來測,結果傳回值不再是-1,而是37(是的buffer 裡也有值了,我出運啊,我出運啊啦...)
-------------------------
var returvalue = conn.ControlTransfer((UsbAddressing)0x81, 0x06, 0x2200, 0,buffer,200,int.MaxValue);
//returnvalue為37
--------------------------
「嗯....又是另一個問題了,,為什麼是0x81,而不是UsbAddress.In? 為什麼用UsbAddress.In & UsbAddress.Out傳回都是-1 ...為什麼」
「請把剛才那篇討論文看完,答案就在大師回覆的連結裡」
參考這段文章吧,為什麼address選0x81? 因為bit7 & bit0是1,表示為Device to host(Interface)
這個bmRequestType表很重要,他是問題核心.


為什麼request用0x06? 因為要讀Description


綜上所知,如果要把我們在DeviceMonitor studio的packet所看到的動作,用controlTransfer來包裝的話
那address要選什麼?.....答案就在畫面裡....


試試看把Request & Value都改成我們要傳送的資料,而UsbAddress改成0b00100001看看
(即表"bmRequestType"裡的"interface" & "class"兩個bit都要on起來)
--------------------------
List<Byte> bytes = new List<Byte>(0);
              ......
                bytes.AddRange(BitConverter.GetBytes(Heading04).Reverse().ToArray());
                bytes.AddRange(BitConverter.GetBytes(ZEROS).ToArray());
                returvalue = await conn.ControlTransferAsync((UsbAddressing)0b00100001, 0x09, 0x0200, 0, bytes.ToArray(), bytes.Count, int.MaxValue);
                System.Console.WriteLine($" return: {returvalue}");
                await Task.Delay(10);
---------------------------
returnvalue不再是-1,也很正確地輸出訊號到HID上了
這次真的很難得的經驗啊
一起加油吧