2015年10月28日 星期三

在 ubuntu / Raspberry pi 上的藍牙基本操作,與建立序列埠 (serial port) 連線

最近買了一些藍牙的小 device,想要在 RPi 上開發一些藍牙的小工具。但是一方面對於藍牙的 software stack 不太熟,另一方面也想知道這些 device 操作藍牙的方式,所以乾脆先用手邊的 Ubuntu 和 RPi 來嘗試建立藍牙連線。

就先從最基本的序列埠連線開始吧。

1. 安裝環境


Raspbian版本: 2015-05-05-raspbian-wheezy


2. 安裝套件

sudo apt-get install bluetooth bluez bluez-hcidump
其中 bluetooth 套件包含了底層的 hci (host controller interface) 和 sdp (service discovery protocol) 工具。而 bluez 則是官方藍牙軟體協定 (Official Linux Bluetooth protocol stack),屬於較上層。bluez 的網頁如下: http://www.bluez.org/

3. 查詢本機藍牙位址

用下面這個指令可以看到本機藍牙發射器的位址。
sudo hcitool dev
Devices:
        hci0    00:1A:7D:DA:71:13

4. 掃描附近藍牙裝置

從這裡開始會分成兩部分來說明,一部份是 master 端,就是執行掃描的機器(例如 ubuntu);另一部分則是被掃描的 slave (RPi),會回應 master 的掃描訊號。
slave 端的指令:
sudo hciconfig hci0 piscan
master 端則是執行
sudo hcitool scan
若是找到 slave,在 master 端會顯示 slave 的位址 (所謂的 bdaddr) 和名稱。

5. 建立與尋找序列埠(SP)服務

我們可以用此指令,在 slave 端建立一個序列埠的服務。
sudo sdptool add --channel=3 --handle=1 SP
--channel 與 --handle 的參數可任選。在此我們選用3號頻道,並且給此服務一個編號1。
然後 master 就可用此指令查訊到附近有 SP 服務的機器:
sudo sdptool search SP
此外,sdptool 還可以讓我們瀏覽 (browse)本地或某一台機器上的所有服務,只要你給它位址 (bdaddr)。
sudo sdptool browse local
sudo sdptool browse <bdaddr>

6. 建立序列埠連線

SP 服務似乎已經準備好了,該如何建立真正的連線呢? 我們需要 rfcomm 這個工具。
首先,在 slave 端必須先建立一個監聽埠:
sudo rfcomm -i hci0 watch /dev/rfcomm0 3 <command>
此處的 3 是指SP服務中的 3號頻道,而 /dev/rfcomm0 此一節點會由 rfcomm 自動建立,我們無需使用 mknod -m 666 /dev/rfcomm0 c 216 0 此類指令來建立。
至於 command,是指建立連線時所要執行的命令,我們可以使用 minicom 或是再建立一個TTY 給遠端的藍牙,如下:
sudo rfcomm -i hci0 watch /dev/rfcomm0 3 minicom -D /dev/rfcomm0
sudo rfcomm -i hci0 watch /dev/rfcomm0 3 /sbin/agetty rfcomm0
接下來,在 master 端就可以用 rfcomm 來建立通訊的序列埠:
sudo rfcomm connect /dev/rfcomm0 <slave_bdaddr> 3 &
把這行放在背景執行,是因為我們一直需要這個埠 (/dev/rfcomm0) 。這埠的節點也是由 rfcomm 自動產生,不需使用 mknod。而這行指令返回時 (按下 Ctrl + C),埠也會消失 (這裡有一個 BUG,詳情請看下面)。此外,3是指頻道,是由我們剛剛建立的服務而來。
最後,在埠建立完成後,master 就可以用 minicom 來和 slave 通訊了。
sudo minicom -D /dev/rfcomm0

7. 障礙排除:

A.  Permission denied 與 Invalid exchange

有時 master 在執行 rfcomm connect 時無法成功,並會得到下列2種錯誤訊息:
  • Can't connect RFCOMM socket: Permission denied 
  • Can't connect RFCOMM socket: Invalid exchange
這是一個 rfcomm 的小 bug,解法是清除 master 中,/var/lib/bluetooth/ 目錄下的所有檔案,就可以讓 rfcomm commect 順利成功。
sudo rm /var/lib/bluetooth/* -rf

B. Address already in use

master 在執行 rfcomm connect 時,有時會得到下列的錯誤訊息:
  • Can't create RFCOMM TTY: Address already in use
這也是一個已知的 bug (連結),原因是上一次 rfcomm 在 release com port (例如 /dev/rfcomm0) 的時候失敗,所以之前那個 com port 依舊存在。我們可以用選項 -a 來看看目前有多少埠存在。
sudo rfcomm -a
這些埠似乎已經變成了殭屍,用 rfcomm release 也清不掉。所以我們只能重啟系統,或是另外開一個埠,例如 /dev/rfcomm3 之類的。

C. 監看 hci 

bluez 提供了一個監看 hci 動作的工具,用以下指令就可以使用:
sudo hcidump -X
不過因為它會不斷的丟出訊息,建議另開一個 TTY 來執行它並進行監看。當不知道障礙的成因,透過它或許能得到一些線索。

D. 確認 slave 的 pairing mode

從藍牙 v2.1 版之後引進了 Secure Simple Pairing mode (SSP) 來做裝置配對的工作。預設是打開,但是如果我們懷疑問題出在裝置配對,也懷疑 SSP 是否打開的話,可以執行以下直令來強制 slave 開啟 SSP mode。
sudo hciconfig hci0 sspmode 1
把1拿掉就可以查詢 SSP 的狀況。
sudo hciconfig hci0 sspmode
順道一提,倘若不使用SSP,master 可以用下面指令將 PIN 送給 slave:
sudo bluetooth-agent PIN <slave_bdaddr>

沒有留言:

張貼留言