Bluetooth Serial Port Setting on Mac OS X 10.10 (Yosemite) and some others

    有一天我哥和我談到他在玩Arduino可以透過藍牙來搖控模型車,只是都要用Android手機,無法用iPhone來搖控。這有點奇怪,我想要弄清楚為什麼是這樣,真的是這樣麼?首先我找到Hock Chen寫的一篇文章[1],談論的內容跟這個問題很相關。Hock Chen主要在教我們如何用MIT AI2這個工具寫一支可以在Android手機上跑的App,這支App主要是可以透過藍牙送出字串到Arduino+HC 06的版子上面。然後也教我們如何在Arduino上面寫程式,可以將收到的字串顯示在LCD顯示器上。

     MIT AI2是個很有趣的工具,只要拖拉元件,再玩拼圖就可以寫成App了。我依照Hock Chen的文章把這支App做出來,發現主要只是利用一個藍牙client元件來送出字串而已。可是這樣就可以運作,實在也太神奇了。因為藍牙是個多才多藝的玩意,有藍牙滑鼠,有藍牙鍵盤,有藍牙音樂,有藍牙耳機。那這個元件到底做了什麼呢?
    因為我手上也沒有Arduino的硬體,所以我想用一台電腦來接收看看,是不是可以收到這支App送出來的字串。我在一台沒有藍牙硬體的Vista電腦上安裝了一支藍牙donger, 如下圖示。它使用broadcom晶片,和widcomm的軟體。

    在安裝好驅動程式後, 先把手機和電腦做個配對。之後打開藍牙的設定, 如下圖:

在Windows8.1, 我裝了一支CSR晶片的BT 4.0 donger, Win8.1會自己認到, 之後要設定藍時, 只要到裝置和印表機, 找到該donger按右鍵選Bluetooth設定即可。
我在COM連接埠的設定頁中, 新增了一個連入的COM9埠。然後, 打開putty, 連到這個COM9埠去。如下圖示:

然後, 等putty的畫面出現後, 就可以使用andriod手機, 打開那支App來連到電腦, 再輸入幾個字串來送出去。

此時可以看到成功的把字串由手機送出到電腦了。
所以這支用MIT AI2拉出來的App,到底是做什麼呢?我知道是透過藍牙送字串啦。但由以上送字串到電腦的設定過程中,可以了解我在電腦上設了一個連入的COM埠,而且在這個COM埠上用putty來接收字串。其實這個過程就是所謂的藍牙序列埠,也就是把以前的RS232的實體線,用無線的藍牙來取代的方式。有一種產品就叫做序列藍牙轉接器(Serial Bluetooth Adaptor), 專門用來做這個工作。剛好看到一個網站[6]在賣,其說明文件寫得很好,怕以後不賣時會把文件拿掉,複製其說明圖片於下。基本上這是實作了藍牙規格Serial Port Profile, 大家可以去藍牙組織的網站[2]找一下這個規格文件。

    其實,我們也不用自己去寫這支App的,因為在Play商店已經有許多別人寫好的此類用途App,大部份就叫做Bluetooth Terminal之類的名字。所以我就去找了一支免費的App,如下圖示。(有廣告!沒辦法,免費的就是這樣。)同樣是先連到電腦(請先把原來的藍牙連線中斷掉。)再輸入要傳送的字串,按Send就可以了。

有趣的是,如果此時,你在電腦上的Putty輸入一些字。你會發現在手機上也會看到你輸入的這些字串。也就是說這條連線是可以雙向傳送資料的。

    那如果我不想用Windows電腦,想用Mac來玩呢?
    當然也是可以的。
    而這其實是本文想記錄的一個重點。
Matthew Ford有一篇文章[3]在說明這個設定,可是Mac這幾年實在改的很快,以幾乎每年一個小改版的步調在變化,藍牙的部份改掉不少。所以這篇文章中的Mac關於藍牙設定部份已有所不同。特別是針對藍牙序列埠設定部份,原本Mac OS X 10.4 - 10.6左右版本有的可以設定序列埠的UI,在10.9 - 10.10(Yosemite)已經找不到(我找了很久,都找不到,如果有人找到,還請告知,感謝!)。後來看到Mike's PBX Cookbook[4], 發現可以這樣來做設定:

$ ls /dev/cu.*
/dev/cu.Bluetooth-Incoming-Port /dev/cu.Bluetooth-Modem

其實原本Mac就有藍牙硬體,預設在/dev目錄下就有幾個檔案是藍牙序列埠的對應。因為Mac也是BSD-like的OS,所以和UNIX的作法相同,所有硬體都有一個檔案來對應。這裡我們看到/dev/cu.Bluetooth-Incoming-Port這個檔案就是用來對應到連入的COM埠。因此,我做了一個試驗:
1. 先把手機和Mac配對
2. 在Mac的Terminal下指令:

$ screen /dev/cu.Bluetooth-Incoming-Port 9600

3. 由手機使用之前的Bluetooth Terminal或者用MIT AI2寫的App來連接到Mac
4. 填入字串,送出
5. 在Mac上就可以看到有接收到字串了。

6. 記得Mac要離開screen, 要按Ctrl-a, Ctrl-\

接下來要談一下藍牙Serial Port Profile中有接到的DevA, DevB的定義,DevA是所謂的Initiator,也就是發動連線要求的設備。而DevB就是等待連入的設備了。
到目前為止,我們都是用手機來發起連線,也就是把手機當做DevA。Windows電腦或者Mac都是當做DevB。
那麼要如何反過來使用呢?也就是由Mac或Windows發動連線,連到另一台裝置。先來看一下Mac的部份好了。我手上有兩台Mac電腦,他們是可以用藍牙序列埠互連送資料的。步驟如下:
1. 兩台先配對
2. 在A這台下指令:

$ ls /dev/cu.*
/dev/cu.Bluetooth-Incoming-Port /dev/cu.Bluetooth-Modem /dev/cu.opsMacmini-Bluetooth-In

3. 可以看到多了一個/dev/cu.xxxxx的裝置檔案
4. 到B那台Mac上下指令:

$ screen /dev/cu.Bluetooth-Incoming-Port 9600

5. 這樣表示B這台已經在等待連入,我們就可在A這台下指令:

$ screen /dev/cu.opsMacmini-Bluetooth-In 9600

6. 此時在A打字,就會出現在B那台Mac的螢幕上了。同時在B打字,也會出現在A的螢幕上。

這裡有一個重點是,Mac會在配對之後,自己出現這個連出的藍牙序列埠裝置檔。同樣的過程也出現在Windows電腦上面,回到上文談論Windows藍牙設定連入的圖示,也可以看到有一個連出的COM埠。這個COM埠也是在配對之後自己產生的。就和這裡Mac當發動連線者的作法一樣,Windows電腦也是利用那個連出COM埠來連到另一個裝置。
所以要被連的裝置,也就是DevB,必須要在配對的過程中,告訴對方我有提供Serial Port Profile的功能,請DevA設定好你的COM埠或者裝置檔案。由規格書中可以看到,就是要提供SDP的查詢回覆。而我手上的裝置中有做這件事的只有Mac:
而我在Windows電腦上使用的藍牙donger並沒有提供這個SDP查詢回覆, 由下圖右下角的SPP是打X的就知道。
這樣,也造成Mac無法以發動連線的角色來連入Windows電腦。(不過,也許換個藍牙donger就可以解決也不一定!)反過來,Mac當DevB,Windows電腦以發動連線的角色來連線是可以運作的。
可是明明手機就可以以發動連線的角色來連入Windows電腦,Mac這樣做不是自我設限嗎?說得也是沒錯,我想之前版本的Mac在其藍牙設定可以自己增設序列埠相關設定的作法,可能是比較彈性的。(以下純屬億測)Android手機根本不管有沒有SDP回覆,反正是先連了再說,大不了就連不上吧!Mac 10.9 10.10都是有收到SDP回覆說對方提供SPP才會自動建立裝置檔案來提供連出的功能。可能是因為SPP 1.2規格書的要求,才改成這樣的。其實我現在使用的Windows藍牙donger在設定連出COM埠的時候也是如此的,它也是在你新增連出COM埠時,去查詢SDP,有找到SPP才會讓你新增。
    以下是SPP 1.2規格書中所提到建立模擬序列埠連線的程序:
  1. Submit a query using SDP to find out the RFCOMM Server channel number of the desired application in the remote device. This might include a browsing capability to let the user select among available ports (or services) in the peer device. Alternatively, if it is known exactly which service to contact, it is sufficient look up the necessary parameters using the Service Class ID associated with the desired service.
  2. Optionally, require authentication of the remote device to be performed. Also optionally, require encryption to be turned on.
  3. Request a new L2CAP channel to the remote RFCOMM entity.
  4. Initiatean RFCOMM session on the L2CAP channel.
  5. Start a new data link connection on the RFCOMM session, using the aforementioned server channel number. 
如此,DevB確實是在SPP 1.2規格書中,被要求要提供SDP查詢回覆的能力。SPP 1.2規格書中p.16還有以下一段話:
Serial Port Profile versions earlier than v1.2 did not mandate the BluetoothProfileDescriptorList attribute. New DevA devices shall assume that a remote DevB without this attribute does not support Serial Port Profile version 1.2 or greater. 
    所以這樣很明白的告訴我們,DevB是必須回覆SDP查詢,至於回覆的內容為何呢?規格書中是以一個圖來表示:
我用Mac的工具,可以查到SDP回覆的封包,以Mac mini的回覆封包來看如下:
                {
0x0000 = uint32(65540),
0x0009 = { { uuid16(11 01), uint16(256) } },
0x0005 = { uuid16(10 02) },
0x0001 = { uuid16(11 01) },
0x0100 = string(Bluetooth-Incoming-Port),
0x0006 = { uint16(25966), uint16(106), uint16(256) },
0x0004 = { { uuid16(01 00) }, { uuid16(00 03), uint8(3) } }
},
說真的,不太好看,圖形表示中以名稱來定義欄位,其實在封包中都是以數字來代表,所以有一個文件在說明這個名稱和數字的對應關係。這個文件好像要加入藍牙組織的會員才能拿到啊!那就將就一下,用猜的好了。不過,以這個例子來說,我發現反過來用資料型態來看,好像就很容易看出來了。例如,資料型態為字串的只有一個欄位ServiceName, 規格書中說其值可能是"COM5"之類的。而我們在查到的封包中也只有一行0x0100=string(Bluetooth-Incoming-Port)資料型態是字串, 所以這兩個就連起來了。這也符合前文中提到,在Mac中預設有一個連入的序列串,其裝置檔案的名稱就叫做/dev/cu.Bluetooth-Incoming-Port的說明。
我特別以紅線將SDP格式圖形框起來的欄位ProtocolDescriptorList,其擁有三個值,資料型態分別為uuid, uuid, uint8,在查到封包中也只有0x0004={{uuid16(01 00)}, {uuid16(00 03), unit8(3)}}這行符合。所以這兩個又連起來了。這表示使用RFCOMM Server Channel 為3。
我們可以驗證是不是如此:透過工具來看,在我們建立兩台Mac之間的藍牙序列埠連線時,可以看到真的有一個RFCOMM的連線己經建立,而且其方向是連出的(藍色的), 也沒錯,因為我是在DevA的這台上跑這個工具看的。而且,最重要的其Channel為3。
當然,如果我中斷藍牙序列埠連線時,這個工具所顯示的藍牙連線就是空的了。
在Mac上這些觀看藍狀態的工具可以由Apple的網站取得,不過可能要先加入其開發者成員,這是免費加入的。網址可以由XCode-> Open Developer Tool -> More Developer Tool取得。

    所以回到透過藍牙來搖控Arduino模型車的問題上,可以做個小結論:如果使用HC-06(or HC-05)來當藍牙模組,除了可以使用Android手機來搖控外。其實用PC(Windows / Mac)也都可以,只要HC-06會回覆SDP查詢並指出其提供SPP服務。而我看有人[5]提到HC-06和Windows配對後,會指出其提供SPP服務。
    這兩天在ic shopping網站逛時,發現他們就有在賣HC-06(大概吧,沒看到詳細的標註)[7],而且產品的說明文件寫得還很仔細,雖然是大陸用語,但是由本文以上的說明後,再去看,應該就能明白他在說些什麼。沒錯,這個藍牙模組,基本上就是只提供SPP。也就是BT 2.0 (Legacy BT)。不是BT 4.0 (BLE, Bluetooth Smart)。


參考網址:
[1] Hock Chen, Android與Arduino的藍芽通訊
[2] Bluetooth Spec, 藍牙規格
[3] Matthew Ford, serial Bluetooth Connections MacOSX
[4] Mike, Mac TTY
[5] using-the-hc-06-bluetooth-module
[6] serial-rs232-bluetooth-adapter
[7] 藍芽無線串口模塊

留言

這個網誌中的熱門文章

D-BUS學習筆記

Cisco Switch學習筆記: EtherChannel

Cisco Switch學習筆記: interface的封包錯誤統計