読者です 読者をやめる 読者になる 読者になる

カタカタブログ

SIerで働くITエンジニアがカタカタした記録を残す技術ブログ。Java, Oracle Database, Linuxが中心です。たまにRuby on Railsなども。

Raspberry Pi 2にBluetoothシリアル通信でデータ送受信してみた

Raspberry Pi Linux ネットワーク

以前Raspberry Pi 2にUSBのBluetoothアダプタを接続し、WindowsおよびMacのPCとペアリングするところまでみた。

totech.hateblo.jp

今回は、Bluetoothによるシリアル通信を行い、Raspberry PiとWindows-PC間でデータ送受信をやってみる。
シリアル通信は本来、Bluetoothとは関係のない、シリアルケーブルを使ったPCの標準的なデバイス通信用プロトコルだが、BluetoothのSPP(Serial Port Profile)というプロファイルを使うことで、仮想的なシリアルポートを用いてデバイス接続ができるようになる。
SPPはRFCOMM(Radio Frequency Communication) というシリアルポートをエミュレートして無線通信するためのプロトコルと、SDP(Service Discovery Protocol)というBluetoothで利用できるサービスを通知するためのプロトコルの二つを利用する。

事前準備

Raspberry PiとWindows-PCを前回の記事の通りにペアリングした状態にしておく。

pi@raspberrypi:~ $ bluetoothctl
[NEW] Controller 00:1B:DC:XX:XX:XX raspberrypi [default]
[NEW] Device 28:C2:DD:XX:XX:XX MY-WINDOWS-PC

SDPサーバ準備

Raspberry PiでSDPサーバが使えるか確認する。
前回のセットアップでBluetooth関連のツールはインストール済みの状態のはずのため、
以下のようにsdptoolコマンドでローカルのサービスを確認すればよい。

pi@raspberrypi:~ $ sdptool browse local
Failed to connect to SDP server on FF:FF:FF:00:00:00: No such file or directory

実行するとエラーになった。
/etc/systemd/system/dbus-org.bluez.serviceを編集してbluetoothdの設定変更が必要らしいので、以下のように修正する。
・変更前

ExecStart=/usr/lib/bluetooth/bluetoothd

・変更後

ExecStart=/usr/lib/bluetooth/bluetoothd --compat

変更後、bluetoothdを再起動する。

pi@raspberrypi:~ $ sudo systemctl daemon-reload
pi@raspberrypi:~ $ sudo systemctl restart bluetooth

再実行すると、今度は別のエラーになった。

pi@raspberrypi:~ $ sdptool browse local
Failed to connect to SDP server on FF:FF:FF:00:00:00: Permission denied

今度はパーミッションエラーなので/var/run/sdpのアクセスレベルを変更する。

pi@raspberrypi:~ $ sudo chmod 777 /var/run/sdp

再実行すると、SDPサービスが確認できた。

pi@raspberrypi:~ $ sdptool browse local
Browsing FF:FF:FF:00:00:00 ...
Service RecHandle: 0x10000
Service Class ID List:
 "PnP Information" (0x1200)
Profile Descriptor List:
 "PnP Information" (0x1200)
  Version: 0x0103

Browsing FF:FF:FF:00:00:00 ...
Service Search failed: Invalid argument
Service Name: Generic Access Profile
Service Provider: BlueZ
Service RecHandle: 0x10001
Service Class ID List:
 "Generic Access" (0x1800)
Protocol Descriptor List:
 "L2CAP" (0x0100)
  PSM: 31
 "ATT" (0x0007)
  uint16: 0x0001
  uint16: 0x0008

Service Name: Generic Attribute Profile
Service Provider: BlueZ
Service RecHandle: 0x10002
Service Class ID List:
 "Generic Attribute" (0x1801)
Protocol Descriptor List:
 "L2CAP" (0x0100)
  PSM: 31
 "ATT" (0x0007)
  uint16: 0x0010
  uint16: 0x0010

Service Name: AVRCP CT
Service RecHandle: 0x10003
Service Class ID List:
 "AV Remote" (0x110e)
 "AV Remote Controller" (0x110f)
Protocol Descriptor List:
 "L2CAP" (0x0100)
  PSM: 23
 "AVCTP" (0x0017)
  uint16: 0x0103
Profile Descriptor List:
 "AV Remote" (0x110e)
  Version: 0x0105

Service Name: AVRCP TG
Service RecHandle: 0x10004
Service Class ID List:
 "AV Remote Target" (0x110c)
Protocol Descriptor List:
 "L2CAP" (0x0100)
  PSM: 23
 "AVCTP" (0x0017)
  uint16: 0x0103
Profile Descriptor List:
 "AV Remote" (0x110e)
  Version: 0x0104

ただし、Service Name: Serial Portというサービスがない状態であることが分かる。
そのため、SPPを追加する。

pi@raspberrypi:~ $ sudo sdptool add --channel=22 SP
Serial Port service registered

もう一度実行すると、Service Name: Serial Portが追加されていることが分かる。

pi@raspberrypi:~ $ sdptool browse local
(・・・上と同じなので省略)
Service Name: Serial Port
Service Description: COM Port
Service Provider: BlueZ
Service RecHandle: 0x10005
Service Class ID List:
 "Serial Port" (0x1101)
Protocol Descriptor List:
 "L2CAP" (0x0100)
 "RFCOMM" (0x0003)
  Channel: 22
Language Base Attr List:
 code_ISO639: 0x656e
 encoding:  0x6a
 base_offset: 0x100
Profile Descriptor List:
 "Serial Port" (0x1101)
  Version: 0x0100

Serial Portが追加されたことが確認できる。

RFCOMMセットアップ

以下のコマンドでrfcommをリッスン状態にする。

pi@raspberrypi:~ $ sudo rfcomm listen /dev/rfcomm0 22
Waiting for connection on channel 22

これでシリアル通信のリッスン待ちの状態になる。シリアル通信が確立すると、/dev/rfcomm0デバイスでデータ送受信ができるようになる。

シリアル通信でデータ送受信

ペアリングしたWindows 7のPCとシリアル通信してみる。
Windows側の準備として、ペアリングした状態で以下を開く。
コントロール パネル > ハードウェアとサウンド >デバイスとプリンター
デバイスからペアリングしたRaspberry Piデバイスのプロパティを開く。

「サービス」タブの「シリアルポート (SPP) 'Serial Port'」のチェックを入れると、仮想ポートが割り当てられる。
今回は「COM5」という名前のポートが使えるようになった。
f:id:osn_th:20170315092602p:plain
Tera Termを開き、「シリアル」接続する。ポートは上記の「COM5」が選択できるので、それを指定する。
f:id:osn_th:20170315092601p:plain
この時点でRasbperry Piのリッスン状態だったrfcommにConnectionと表示され、正常に接続できたことが確認できる。

pi@raspberrypi:~ $ sudo rfcomm listen /dev/rfcomm0 22
Waiting for connection on channel 22
Connection from28:C2:DD:XX:XX:XX to /dev/rfcomm0
Press CTRL-C for hangup

Windows PCからRaspberry Piへデータ送信

Tera Termで適当に文字列を入力してみる。
シリアル通信は一文字ずつの送信なので特にEnterとかせずともメッセージは送信される。
f:id:osn_th:20170315092604p:plain
Raspberry Pi側でメッセージを確認するために、/dev/rfcomm0をcatする。

pi@raspberrypi:~ $ sudo cat /dev/rfcomm0
1234

Tera Termで入力した文字が出力される。

Raspberry PiからWindows PCへデータ送信

今度はRaspberry Pi上で/dev/rfcomm0デバイスにメッセージをechoしてみる。

pi@raspberrypi:~ $ sudo echo abcd > /dev/rfcomm0

するとTera Termの画面にechoされた文字列が表示される。
f:id:osn_th:20170315092559p:plain

双方向でメッセージ通信ができていることが確認できた。

最後にRFCOMMはCtrl-Cで停止する。

pi@raspberrypi:~ $ sudo rfcomm listen /dev/rfcomm0 22
Waiting for connection on channel 22
Connection from28:C2:DD:XX:XX:XXto /dev/rfcomm0
Press CTRL-C for hangup
Disconnected

まとめ

以上、Raspberry PiとBluetoothでペアリングした端末とシリアル通信によるデータ送受信ができることを確認した。
これでBluetoothのペアリングからデータ通信までできるようになったので、Wi-Fiがない状況下でも代替手段として使うこともできそう。
今回はシリアル通信という手段でデータ通信してみたが、PANとか他の方法も調査してみたい。

以上!

関連記事

totech.hateblo.jp