2018年4月22日 星期日

運用 Raspberry Pi 學習 USB (1)

多年前曾經對 USB 很有興趣,帶著滿腔熱血遠赴新竹想跟 ChamberPlus 老前輩偷學一招半式。不過這麼多年來連邊都沒摸到,也漸漸對 USB 失去興趣。

人生就是這麼奇妙,最近老闆指派一項任務要我用公司 IC(USB device) 把資料透過 USB 傳到 Linux(USB Host) 上。

首先當然是先 k 點資料,建立一些觀念。當年台灣最有名的 USB 技術作家就屬許永和老師(現在好像還是?走進天瓏還是看到一整排許老師的著作),不過筆者想說經過這麼多年,對岸應該也玩出一些心得了,或許他們的書 + 實驗板 CP 值更高?於是筆者上了豆瓣看了一下書評,發現下面這本評價不錯,而且實驗板不但便宜在淘寶也很容易購得。


這些年台灣搞技術出版可以說確定輸給對岸了,我在對岸買個 Wi-Fi 實驗板,淘寶賣家(就是作者)給我 1.5GB 的參考資料,週末深夜還很有耐心的慢慢回答我問題,還有社群跟專有QQ頻道,我在公司搞同樣的東西合作廠商愛理不理的,還得找高層施壓。所以我蠻認同 ChamberPlus 老大講的:「...所以當我決定去弄一套類似的EV 平台時,我根本不會想到台灣這些廠商,更何況現在在台灣沒有認清這一點,反而還自以為是讓別人難以忍受那種工程師的"傲"...」

不要說工程師,常去x華某幾間電子材料行的人都領教過他們的服務態度,跟 10 年前一樣完全沒變,東西跟網拍一比也沒有比較便宜,那您說除了沒信用卡的學生跟需要急用的人之外,誰還想繼續光顧呢?

當然還要搭配一本 USB bible 交叉驗證吸收才會更好,找來找去還是 USB Complete 這本最為經典,現在沒想到出到第五版了(擺本原文書的照片才不會被人說你看不懂英文吼?~)。


當年學 USB 最苦惱的是:實驗板還算小事,要怎麼才能把封包錄下來慢慢研究呢?

常看 ChamberPlus 老前輩用 CATC 示範,聽說當年一台 CATC 可以買一台小車,這絕非一般人有能力消費的產品,而且 ChamberPlus 老前輩也表示 CATC 早已停產,公司被 Teledyne LeCroy 收購,隨便查了一台他們生產的  USB-T0S3-A01-X 要價 13 萬台幣,可以買2,3台機車了。

於是筆者上淘寶搜尋看看有沒有便宜貨,發現即使是對岸生產的 USB 封包分析儀,換算回台幣也要好幾萬,筆者當然不可能自己花錢買這種東西,要買當然也是叫公司出錢。

不花錢的方式就是用軟體,書上推薦 Bus Hound,不過這是商業軟體,免費版本沒三小路用,筆者也不想冒風險裝破解版。

筆者想到,既然最終我是要在 Linux 上讀寫 USB,那拿 Raspberry Pi 學 USB 不是更接地氣嗎?

本篇就是要跟大家分享,筆者如何使用 rpi 入門 USB 的心得。

搭建實驗環境

實驗器材與相關軟體
  • Raspberry Pi B+
  • SanDisk SDHC 16G MicroSD
  • 2017-07-05-raspbian-jessie-lite.img (for rpi)
  • VirtualBox 5.0.20
  • Ubuntu 14 64bit (for VirtualBox)
  • Wireshark 2.4.6

實驗流程:
  1. rpi 錄下 USB  封包(.cap)
  2. 透過 sshfs 丟回 VirtualBox 與 Windows 共享的目錄
  3. 用 Wireshark 打開 .cap 觀察學習
應該有人會問這樣好厚工喔,直接用 VirtualBox + Ubuntu 不行嗎?當然可以,不過筆者認為學習或實驗時應該盡量把環境單純化,PC 是個複雜的環境,筆者不想花時間瞎猜到底是 Windows 還是 VirtualBox 從中搞鬼。

另外 sshfs 也可以在 Windows 下使用,因為筆者已經有 VirtualBox + Ubuntu 環境,就沒想要去安裝了。

軟硬體安裝流程如下:

安裝 2017-07-05-raspbian-jessie-lite.img

沒太多可以說的,就是用 Win32DiskImager 把 .img 燒到 MicroSD 裡。

安裝 sshfs


開啟 ssh:
~# raspi-config > 5. Interfacing Options > P2 SSH > Would you like the SSH server to be enabled? <Yes>ㄈ
如果您想用 root login:
~# nano /etc/ssh/sshd_config
Ctrl+W 搜尋 PermitRootLogin ,把下列字串:
PermitRootLogin without-password
替換成:
PermitRootLogin yes

最後記得重新啟動 ssh daemon
~# /etc/init.d/ssh restart

apt-get install tcpdump


USB enumeration

眾所皆知 USB device 插入 USB host 後系統的第一個動作就是裝置列舉,
這是筆者的初步學習目標。在把列舉時的封包錄下來研究之前,還需要做幾個預備動作。

掛載 usbmon module:
~# modprobe usbmon
確認 debugfs 是否已經掛載,不過在筆者的實驗環境中無此必要:
~# mount -t debugfs none_debugs /sys/kernel/debug
mount: none_debugs is already mounted or /sys/kernel/debug busy
使用 tcpdump -D 找出 interface:

在 Ubuntu 環境下掛載 rpi 目錄:
sshfs RPI_ID@RPI_IP_ADDRESS:/tmp ~/folder_in_ubuntu
至此差不多可以開始了,先用 lsusb 觀察系統上有什麼:


可以看到東西很少,這也是用 rpi 的優點之一,不然 PC 上隨便一列就一狗票,初學者恐怕得猜老半天,這邊可以看出 rpi b+ 的乙太網是用 USB to Ethernet。

開始錄封包:
~# tcpdump -i usbmon1 -w usblog.cap &
插入隨身碟,把列舉的動作錄下來: 終止 tcpdump:
~# killall tcpdump
然後用 Wireshark 把 usblog.cap 打開:


從圖中可以看出沒有辦法像 CATC 那樣解析到 toke-data-handshake packet 的層次,甚至是連 CRC 都保留下來。如果真的做到這種程度,恐怕不只是害人家年終減半,而是要被裁員了。不過,這些資訊對於筆者這種剛入門 的 USB 菜鳥也夠了。

首先無論是 Source/Destination 欄位都可以看到用逗點隔開的三個數字:


X.Y.Z 這三個數字分別代表的意義是:
  • X: bus id,也就是輸入 lsusb 顯示的第一個欄位(如前面看過的 Bus 001),代表 USB host controller 編號。
  • Y: device address
  • Z: endpoint

讀了 USB Complete 之後,了解到 USB enumeration 的幾個要點:
  • 以 control transfer 通訊
  • 初始時以 device address 0 通訊
  • 用 endpoint 0 通訊
P.91 給出了詳細的步驟(如下圖所示),作者也強調不一定每個 OS 都會按照相同的步驟,即使是 Windows 版本不同步驟也可能不同,但是無論是 Windows or Linux 應該有些關鍵步驟都是一樣的。

Reset, Suspended, Reset, High speed detection Handshake 這四個步驟比較難在 usblog.cap 裡找到對照組,但 GetDescriptor(Device) 這個肯定找得著,在 display filter 輸入 usb.device_address==0:



看圖說故事有了初步的成功,USB host 的確是以  device address 0, endpoint 0 與剛插入 hub 的 USB device 通訊:


觀察 USB device Vendor ID & Product ID,的確是筆者剛剛插入的隨身碟:


雖說沒有像 CATC 那麼詳細,但 Control Transfer > Setup Stage > Data Packet 中的 bmRequestType, bRequest, wValue... 都看得到:


由上圖可知 Wireshark 會依據 bmRequestType, bRequest 翻譯 wValue, wIndex。

下一個 Control Transfer 是 Set Address,下圖參考 USB Complete 5th P.91:


usblog.cap 這邊看到的是:


由下圖可以看到 host 指定 device address 4 給隨身碟:


Set Address 完成後的通訊都會改用 device address 4:


用 device address 4 取回各式各樣的 descriptor,這與 P.93 10. The host learns about the device’s abilities. 的說法相符(細節就不列了,除非您失眠):


P.13 12. The host’s device driver selects a configuration. 也找到了:


SET CONFIGUREATION > bConfigurationValue: 1

在 P.104
bConfigurationValue identifies the configuration for Get Configuration and
Set Configuration requests and must be 01h or higher. A Set Configuration
request with a value of zero causes the device to enter the Not Configured state.

意思是這個值要與 Get Configuration 的值匹配:


至此 P.91 1. The system has a new device. ~ P.94 12. The host’s device driver selects a configuration. 已經大致完成。至於其他的細節以後再補充。

以上就是筆者的 USB 幼幼班初體驗。當然您可以跟某些人一樣堅持從k  spec 開始學起不碰任何 code 跟設備,不過像這樣的人才不去搞理論物理研究宇宙起源當霍金接班人真是太可惜了,因為這票人認為紙筆研究才是真研究。筆者太弱離不開實作,本篇就留給跟筆者一樣平庸的朋友們參考~

7 則留言:

  1. 謝謝 還在學 前輩老師的寶貴經驗分享以提攜晚輩後學們
    Thank you very much!!!

    苦工人主小P ~

    回覆刪除
    回覆
    1. 感謝回應

      不敢為人師~純粹交流分享

      刪除
  2. 你老闆也只不過要你從USB Device 跟Linux 傳個資料,需要搞得這麼"厚工"嗎?

    從你上面某一張圖看到一堆 Set Feature/clear feature 的,不就是 HID 的而已嗎?有必要嗎?

    現在有很多事真的也不用光靠自己一個人搞啦,尤其自己還不熟的東西。更何況還是這一種真的還牽涉到許多兼容性的東西。寫完是一回事,後續 Debug 又是另一回事。

    "不要讓猴子跳到自己身上",除非你真的很閒,或是能叫得動其他可以幫助你的人,否則,最後可能還是會把自己搞得一身腥啊。

    我現在連要幫人家解USB 的問題(大部分都是有兼容性或不明原因Fail),也都會很留意對方到底可以忍受這些問題的程度。

    搞不太清楚的,那就謝謝再連絡。

    如果你還是年輕,還是菜鳥工程師,我是不反對你自己跳下來學這個。

    但以你現在這個年紀,這個程度,不要因為搞不一定新的、別人就可以很容易搞定的東西,而讓別人忽略到你原本專業的領域與技能。破壞了你原本的價值與名聲啊。

    純屬個人意見。僅供參考。

    回覆刪除
    回覆
    1. 如果要把USB修煉到完備,小弟也沒那個體力與時間了,雖然人家有給我整包開發環境+範例程式,但完全沒概念要吃下來大概也不容易,還是得有點概念,不然拿問題問同事他會覺得我沒做功課就來問是在浪費他時間,您說是吧?

      我的系統是封閉性的,沒有要拿著到處插來插去,只要某Linux可以通就好了..其實還好拉

      刪除
    2. 我也沒有修練到完備,我也只有幾個像HID 或基本的觀念有,

      以前有做過U盤,但沒有搞到量產,所以也算經驗一半。

      如果只是拿來領薪水的,全部都會應該也不會加薪吧。

      反正夠用就好,我現在也看得很開了。不要把自己搞得累的死了。

      刪除
  3. 謝謝你所提供的資訊,我都已經分別下載了

    "圈圈教你玩USB"/"圈圈教你玩USB(第二版)"

    書籍的電子檔了,不過我稍微看一下內容,我對於光碟片內容就沒興趣了。

    你說得沒錯,市場不同,做法就不同,所以我在台灣大概也只能寫部落格,

    沒辦法出書了。

    回覆刪除
    回覆
    1. 這對您老來說太淺了拉,這是給小弟這種幼幼班用的XD

      刪除