Nordic の SDK に、BLE で UART のサンプルプログラムがあります。
「UART/Serial Port Emulation over BLE」
https://www.nordicsemi.com/en/DocLib/Content/SDK_Doc/nRF5_SDK/v15-2-0/ble_sdk_app_nus_eval
それにつなげるアプリとして、Android 上のアプリ「 nRF UART 2.0 」 があります。
https://play.google.com/store/apps/details?id=com.nordicsemi.nrfUARTv2&hl=ja
これを使って接続の確認ができました。
「nRF52チップでシリアル通信の実験」
https://qiita.com/nanbuwks/items/1d5a65739ecd3f1be34e
ここではそこから一歩進んで、BlueZを使って接続してみます。
環境
- Ubuntu 16.04(AMD64) ですが、RaspberryPi(Raspbian Stretch)でも同様でした。
- MDBT50Q-DB
- ファーム Nordic SDK サンプルプログラム ble_app_uart
接続は、以下と同様です。
「nRF52チップでシリアル通信の実験」
https://qiita.com/nanbuwks/items/1d5a65739ecd3f1be34e
bluez
まず、bluezのインストール。
今回の環境では、既にインストールしていましたが確認もかねて apt-get install を実行します。
$ sudo apt-get install bluez
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています
状態情報を読み取っています... 完了
bluez はすでに最新バージョン (5.43-0ubuntu1~lorenzen1) です。
アップグレード: 0 個、新規インストール: 0 個、削除: 0 個、保留: 13 個。
入っているみたいです。
デバイスの検出
hcitool を使って、BLEデバイスを検出します。
$ sudo hcitool lescan
LE Scan ...
C0:42:BE:97:27:DF Nordic_UART
C0:42:BE:97:27:DF (unknown)
「Nordic_UART」というのが現れます。
このままだとずっとスキャンしているので、Ctrl+Cで中断します。
Nordicのサンプルプログラムでは、
#define DEVICE_NAME "Nordic_UART" /**< Name of device. Will be included in the advertising data. */
となっていて、それがここに現れます。
なお、
#define APP_ADV_DURATION 18000 /**< The advertising duration (180 seconds) in units of 10 milliseconds. */
ということで、アドバタイズの時間は起動してから180秒なので、それまでに lescan や下記のconnectをする必要があります。
時間切れになったらデバイスを再起動して「Nordic_UART」を検出してください。
gattool
検出したBDアドレスを使って、gattoolで接続します。
$ gatttool -b C0:42:BE:97:27:DF -t random -I
[C0:42:BE:97:27:DF][LE]> connect
Attempting to connect to C0:42:BE:97:27:DF
Connection successful
primaryコマンドでサービスのUUIDを表示します。
[C0:42:BE:97:27:DF][LE]> primary
attr handle: 0x0001, end grp handle: 0x0009 uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x000a, end grp handle: 0x000a uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x000b, end grp handle: 0xffff uuid: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
[C0:42:BE:97:27:DF][LE]>
UUID の定義
Service Name | UUID |
---|---|
Generic Access | 00001800-0000-1000-8000-00805f9b34fb |
Generic Attribute | 00001801-0000-1000-8000-00805f9b34fb |
NUS(Nordic UART Service) | 6E400001-B5A3-F393-E0A9-E50E24DCCA9E |
NUS の定義は SDK の ble_nus.cで定義されています。
#define NUS_BASE_UUID {{0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x00, 0x00, 0x40, 0x6E}} /**< Used vendor specific UUID. */
この中のキャラクタリスティックは以下のようになっています。
Characteristic Name | UUID |
---|---|
Central Address Resolution | 00002aa6-0000-1000-8000-00805f9b34fb |
Device Name | 00002a00-0000-1000-8000-00805f9b34fb |
Appearance | 00002a01-0000-1000-8000-00805f9b34fb |
Peripheral Preferred Connection Parameters | 00002a04-0000-1000-8000-00805f9b34fb |
RX | 6E400002-B5A3-F393-E0A9-E50E24DCCA9E |
TX | 6E400003-B5A3-F393-E0A9-E50E24DCCA9E |
RXとTXがオリジナルの定義となり、SDK の ble_nus.cで定義されています。
#define BLE_UUID_NUS_TX_CHARACTERISTIC 0x0003 /**< The UUID of the TX Characteristic. */
#define BLE_UUID_NUS_RX_CHARACTERISTIC 0x0002 /**< The UUID of the RX Characteristic. */
ディスクリプタ(Descriptor)
Descriptor Name | UUID |
---|---|
Client Characteristic Configuration | 00002902-0000-1000-8000-00805f9b34fb |
Declarations
Declarations Name | UUID |
---|---|
Primary Service | 00002800-0000-1000-8000-00805f9b34fb |
Characteristic Declaration | 00002803-0000-1000-8000-00805f9b34fb |
ということから、
まずは
NUS に着目します。対応する handle は 0x000b ということなので、char-desc コマンドで 0x000b を調べてみます。
[C0:42:BE:97:27:DF][LE]> char-desc 0x000b
handle: 0x000b, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000c, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000d, uuid: 6e400002-b5a3-f393-e0a9-e50e24dcca9e
handle: 0x000e, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000f, uuid: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
handle: 0x0010, uuid: 00002902-0000-1000-8000-00805f9b34fb
なお、char-descだけだと以下のように全部のcharactoristicのリストが取得できました。
[C0:42:BE:97:27:DF][LE]> char-desc
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0003, uuid: 00002a00-0000-1000-8000-00805f9b34fb
handle: 0x0004, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0005, uuid: 00002a01-0000-1000-8000-00805f9b34fb
handle: 0x0006, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0007, uuid: 00002a04-0000-1000-8000-00805f9b34fb
handle: 0x0008, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0009, uuid: 00002aa6-0000-1000-8000-00805f9b34fb
handle: 0x000a, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000b, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x000c, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000d, uuid: 6e400002-b5a3-f393-e0a9-e50e24dcca9e
handle: 0x000e, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x000f, uuid: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
handle: 0x0010, uuid: 00002902-0000-1000-8000-00805f9b34fb
ここで、
- RX 6E400002-B5A3-F393-E0A9-E50E24DCCA9E
- TX 6E400003-B5A3-F393-E0A9-E50E24DCCA9E
ということでしたから、RX のハンドルは 0x000d TX のハンドルが 0x000f ということになります。
データ受信
さて、 汎用のディスクリプタが見えています。
https://www.bluetooth.com/specifications/gatt/descriptors
によると
00002902-0000-1000-8000-00805f9b34fb
がClient Characteristic Configurationなるものらしい。
[C0:42:BE:97:27:DF][LE]> char-read-uuid 00002902-0000-1000-8000-00805f9b34fb
handle: 0x0010 value: 00 00
現在は 0b0000000000000000 です。
これの最下位ビットを1にするとNotifications enabledとなるらしいです。
リトリエンディアンなので 16進表記で 0x0100 を書いてみたらデバイスから送られたデータを取得できました。
[C0:42:BE:97:27:DF][LE]> char-write-req 0x0010 0100
Characteristic value was written successfully
otification handle = 0x000f value: 31 32 33 31 32 33 0d
Notification handle = 0x000f value: e3 81 8a e3 81 af e3 82 88 e3 81 86 e3 81 94 e3 81 96 e3 81
Notification handle = 0x000f value: 84 e3 81 be e3 81 99 0d
このvalueは、シリアルデータとしてデバイスから送られてきているものです。
シリアルデータは「123123(エンター)」「おはようございます(エンター)」と流しました。
0000 を入力したら止まりました。
[C0:42:BE:97:27:DF][LE]> char-write-req 0x0010 0000
Characteristic value was written successfully
[C0:42:BE:97:27:DF][LE]>
データ送信
先ほどの受信データはTXのハンドルに流れてきていますね。PC側のTXではなくデバイス側のTXらしいです。
ということは、RXに書き込んだらデバイスに送信できそうですね。
[C0:42:BE:97:27:DF][LE]> char-write-cmd 0x000d 3334353637380d0a
としたら、
説明を補足しておくと、現在 nRF52840 デバイスにプログラムされている ble_app_uart は、nRF52840 内で BLE で受信したシリアルデータを物理 UART に転送されるようになっています。今回の実験では、その UART にUSBシリアルアダプタ経由でPCに、PCでは ArduinoIDE のシリアルモニターでデータを見えるようにしています。
具体的な配線はこちら
「nRF52チップでシリアル通信の実験」
https://qiita.com/nanbuwks/items/1d5a65739ecd3f1be34e
次に、
[C0:42:BE:97:27:DF][LE]> char-write-cmd 0x000d 3132333435363738313233343536373831323334353637380d0a
一回に20bytesの制限があるみたいです。
Pythonを使ってデータをゲットする
以下はRaspberryPiでテストしました。
Python3で試しました
pi@raspberrypi:~ $ sudo apt-get install python3-pip
pi@raspberrypi:~ $ sudo pip3 install bluepy
以下のようなtestb.pyというプログラムを作りました。
# -*- coding: utf-8 -*-
from bluepy.btle import Peripheral
import bluepy.btle as btle
import binascii
import struct
MyNUSUUID = "C0:42:BE:97:27:DF"
class MyDelegate(btle.DefaultDelegate):
def __init__(self, params):
btle.DefaultDelegate.__init__(self)
def handleNotification(self, cHandle, data):
c_data = binascii.b2a_hex(data)
print( c_data)
class SensorNUS(Peripheral):
def __init__(self, addr):
Peripheral.__init__(self, addr, addrType="random")
self.result = 1
def main():
nus = SensorNUS(MyNUSUUID)
nus.setDelegate(MyDelegate(btle.DefaultDelegate))
nus.writeCharacteristic(0x0010, struct.pack('<bb', 0x01, 0x00), True)
while True:
if nus.waitForNotifications(1.0):
continue
print( "wait...")
if __name__ == "__main__":
main()
pi@raspberrypi:~ $ python3 testb.py
とすると
b'e695b0e580a4efbc9a3133360a0000'
b'e695b0e580a4efbc9a3133370a0000'
wait...
b'e695b0e580a4efbc9a3133380a0000'
wait...
b'e695b0e580a4efbc9a3133390a0000'
wait...
b'e695b0e580a4efbc9a3134300a0000'
wait...
b'e695b0e580a4efbc9a3134310a0000'
というように出力されます。