gatttool を使って NUS( Nordic UART Service ) とつなぐ実験

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

```
としたら、

345678
が デバイスのUARTに出力されました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/139524/812eb70c-35fc-9d39-d21c-8aa2ec25dcb9.png)

説明を補足しておくと、現在 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
```
とすると、
以下のようになりました。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/139524/b96b1fad-a55f-d8e9-d7e5-6eb2a4246976.png)

一回に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'

```
というように出力されます。