Help us understand the problem. What is going on with this article?

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

説明を補足しておくと、現在 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

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

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

Why do not you register as a user and use Qiita more conveniently?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away