USB HID學習 一點開發記錄

2021-10-02 19:31:27 字數 3557 閱讀 7535

某天,曾經的前同事找我,說有個usb專案。因為知道我當時離職在找工作,於是轉給我,然後介紹客戶給我。

前期做介面,完成2種版本發給客戶,客戶選中其中一款。同時寄硬體裝置過來。

在板子未到之前,完成主體介面視窗以及主要布局。研究mfc程式開機自動啟動,系統托盤等功能。

板子到之後,就開始研究hid通訊。客戶發來乙個工具讀取引數的,可與裝置正常通訊。不過自編寫的**讀取不到引數。重新研究hid協議,安裝bus hound抓usb包,對照協議分析報文,對hid有一點認識。深入跟蹤hidapi庫原始碼,發現開啟usb裝置時出錯,具體來說,列舉階段,以讀的方式開啟,其後使用讀寫方式,但失敗,返回error_access_denied(錯誤碼為5l),於是再使用讀方式開啟,成功。於是懷疑是因為讀寫方式開啟失敗的原因。網上說windows10系統不讓以讀寫方式開啟hid,切換win7虛擬機器,測試,效果一樣。在linux系統用root許可權跑同樣**,卻正常。一度陷入困境。

研究了幾天,實在無法,跟客戶反映困難,客戶找了份c#的**,看了裡面標記的時間,雖然有些年頭了,但也嘗試跑,發現可以。即:同樣使用windows10系統,是能正常與hid裝置通訊的(其實先前工具能讀取引數亦證明了)。於是分析c#**,發現在收發feature report的地方有問題。原來feature report對大小有規定,目前知道是32個字元(使用hidapi等**,必須多加乙個id的位元組,共33位元組),如果不符合長度要求,會返回錯誤,錯誤碼為87l(即error_invalid_parameter)。修改了,一切正常,難題解決。

接著研究通過usb寫資料到板子上的flash上,亦遇到問題。通過bus hound分析,發現寫的資料有部分與燒寫檔案二進位制對應不上。找了很久,發現**的偏移量範圍有問題。由於feature report只有32位元組,一次要寫512位元組,所以要迴圈多次,偏移量變數使用uint8,範圍只有255,所以512位元組都是前面128位元組的內容,內容出錯了,當然失敗。修正後,一切正常。

到此,第一階段結束,介面布局、語言切換、操作flash,全部完成,從第一天接觸至完成,耗時三周。為了給客戶乙個良好印象,趕了進度,晚上基本搞到1~2點,週末大部分時間也在搞。雖然賦閒在家,但因為要照料小孩,也要煮飯買菜,日常瑣事也占用很多時間。還好,客戶如期打款,暫時緩解了燃眉之急。

後續階段基本沒有真正的難度,要說耗時的,主要是需求的不確定性,由於對背景及行業知識了解不多,很多時候,客戶所述的需求都很多簡單,但對我而言並不簡單,所以來回多次溝通。

客戶提到要支援 windows xp 和 windows 7 系統,由於前期沒有確認這點,所以選擇 vs 2015 開發,經測試,還是不能在 xp 上執行,於是跟客戶反饋,最終確認無須支援 xp 系統。

由於要顯示校準的過程,所以需要畫游標,並進行閃爍,最大支援9點,約十年前知道了 tslib 庫,當在 github 上看到 tslib 的十字形圖示時,倍感親切。於是在 mfc 中實現了一模一樣的圖案。不知這叫抄襲還是叫致敬。

另一塊畫圖相關的是座標及柱狀圖顯示,但無論怎樣,也找不到根據滑鼠縮放的方案,也是由於這個原因,開始學習 qt,想看看另一套圖形開發框架的效果。當然,這是另一話題了。

由於個人崇尚簡潔,因此原則上最終的程式只有乙個exe,不依賴其它檔案(當然,有些系統級別的dll,不在此列)。所以將 hidapi 原始碼檔案直接新增到工程專案中,再將其封裝為類。接著是中英文的切換,開始考慮使用po來實現語言的翻譯,但實施起來過於複雜。既要編寫語言檔案,又要編譯,所以捨棄。最終使用笨方式,在介面設計之時使用中文,然後再在**中切換。語言切換和開機啟動等標誌寫到登錄檔中。

此專案中,使用到如下技術:hid 資料讀寫、usb 裝置拔插檢測、父子視窗通訊、開機啟動、系統托盤、登錄檔讀寫、控制項畫圖。

1、開啟hid裝置返回 error_access_denied(錯誤碼為5l) 問題。

失敗的原因是,windows認為滑鼠、鍵盤,不應該用讀寫(實際影響的應該是「寫」)方式開啟。為安全起見,因此不提供寫機制。hidapi 作者在 github 的 issue 中亦提到這點。

開啟裝置函式為 open_device,如下:

static handle open_device(const char *path, bool open_rw)

實際使用createfilea函式,傳入引數有二:路徑以及許可權(是否讀寫)。列舉時,不使用讀寫。即createfilea第二個引數dwdesiredaccess為0。在正式開啟時,先嘗試讀寫(一般會失敗),失敗後再用0,此時成功。誤入死胡同,以為傳送資料一定要讀寫方式開啟,關鍵語句:

desired_access = (open_rw)? (generic_write | generic_read): 0;
研究很久,也設定過standard_rights_read、standard_rights_write,但失敗。

後找到一篇類似問題的帖子。 裡面提到的問題雖然類似,但本質不同。帖子作者是同一usb裝置被識別出2個裝置,因此可以通過path判斷出hid class那乙個。但是作者並不成功,鑑於問題表現不同,沒細看帖子(英文資料都是跳著看的)。

2、feature report 傳送問題。

傳送report,出錯,在hid_send_feature_report函式,即hidd_setfeature函式用getlasterror獲取錯誤碼,返回87l(即error_invalid_parameter)。改report報文大小為0x20+1,成功,bus hound可捕獲到。(觀察bus hound以及網上一些報文分析(長度為0x20),結合error_invalid_parameter,猜測可能是長度問題,改之,亦成功。)

開始之時,先完成主體框架,再慢慢細化,先有大綱,再有細節,做到胸有成竹,不怕花時間修改,否則要等某個前置資源,如果資源不到位,只能等,一切都是空想。另外,整體架構好之後,不一定按需求前後實現,可以切換,即把多個需求錯峰實現,這樣,利用大腦的潛時間、暗時間幫我們思考問題。通俗地說,當遇到乙個坎時,可以先跳過,過幾天可能想到解決之法。做其它事也類似,比如寫書。

對於結構體、移位或crc計算等,需要限制變數的位數。但是對於長度、返回值、偏移量等,直接用int即可,在pc領域開發,不考慮位元組的節省。這個在開發時沒有引起足夠重視,導致花費一定時間。

關於需求,其實誰也不能保證一開始就十分準確和完整,都是慢慢補充的。有時候,客戶也不知道要實現什麼樣的功能,做成什麼樣的東西,此時,我們可以引導客戶,甚至先按自己想法完成一版,讓客戶評估。如果我們等客戶,客戶等我們,這樣徒耗時間,於專案無補。如果誰也不提方案,則自行提出,如果誰也不提意見,則按自己的意見。這是我比較喜歡的做事方式。

做這個專案時,汲取了之前的經驗,一切從實際問題出發,追求速度,不擴充套件研究技術。先完成,再慢慢回顧和總結。其實,程式設計這麼多年,在開發時會有自己的一套準則,以目前來看,開發必須要有git版本管理,編碼格式和注釋,簡短的開發手記,如果不做這些,會覺得不安心。

說實話,現在回顧,當初的評估是有點冒險的。我只是使用 hidapi 獲取了滑鼠的資訊,但寫資料未測試(注:嘗試寫資料給滑鼠,失敗)。因此,首次除錯硬體時就遇到大問題,一度以為案子會失敗。幸好客戶給了 c# **,幸好有一點點 c# 基礎,跟蹤除錯後最終解決問題。解決過程中到網絡卡查閱大量資料,還研究了 hidapi 原始碼。

無論怎樣,從開發中的緊張擔心到現在的釋然,成就感還是有一點的,因為積累了乙個方面的開發經驗,除了熬夜的不良後果外,其它都是好的。

一點點開發經驗(二)

1.當你使用某些標籤的時候,可能你沒有寫閉合標籤,但是後來瀏覽器渲染的時候給你補上了,例如123,但是後來瀏覽器渲染的時候 是 123 雖然說這樣可以節省網路流量,但是可能會出現相容性的問題,不是所有的瀏覽器都會給你補上的。2.陣列的建立方式有兩種 var arr1 字面量的方式定義 var arr...

學習docker的一點記錄

0x00 docker簡介 docker 是乙個開源的應用容器引擎,讓開發者可以打包他們的應用以及依賴包到乙個可移植的映象中,然後發布到任何流行的 linux或windows 機器上,也可以實現虛擬化。容器是完全使用沙箱機制,相互之間不會有任何介面。0x01 在ubuntu上安裝docker 第一步...

docker學習的一點記錄(一)

環境 阿里雲 docker 傻瓜一鍵映象 有公網ip,ssh 自己本地 windows7 ssh終端 xshell xftp docker 是這個傻瓜映象 自己帶的 下面是一張 簡單的介紹了一下,dockerfile當中的一些語法及對應功能 最後的 entrypoint 是 docker 啟動這個映...