SensorTag をラズパイから操作する

Texus Instruments の SensorTag (CC2541) を触る機会があったので、またもラズパイから操作してみました。

技術情報がオープンになっているので非常にわかりやすいです。

  • SensorTag User's Guide

http://processors.wiki.ti.com/index.php/SensorTag_User_Guide

  • SensorTag attribute table

(ググるとPDFの表が出てきます)

外形はこんな感じ。赤い筐体がかっこいいです。

それでは SensorTag のプライマリサービスを見てみましょう。

$ sudo ./gatttool -i hci0 -b 78:A5:04:19:6D:DB -I
[78:A5:04:19:6D:DB][LE]> connect
Attempting to connect to 78:A5:04:19:6D:DB
Connection successful
[78:A5:04:19:6D:DB][LE]> primary
attr handle: 0x0001, end grp handle: 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x000f uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0010, end grp handle: 0x0022 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle: 0x0023, end grp handle: 0x002a uuid: f000aa00-0451-4000-b000-000000000000
attr handle: 0x002b, end grp handle: 0x0035 uuid: f000aa10-0451-4000-b000-000000000000
attr handle: 0x0036, end grp handle: 0x003d uuid: f000aa20-0451-4000-b000-000000000000
attr handle: 0x003e, end grp handle: 0x0048 uuid: f000aa30-0451-4000-b000-000000000000
attr handle: 0x0049, end grp handle: 0x0054 uuid: f000aa40-0451-4000-b000-000000000000
attr handle: 0x0055, end grp handle: 0x005c uuid: f000aa50-0451-4000-b000-000000000000
attr handle: 0x005d, end grp handle: 0x0061 uuid: 0000ffe0-0000-1000-8000-00805f9b34fb
attr handle: 0x0062, end grp handle: 0x0068 uuid: f000aa60-0451-4000-b000-000000000000
attr handle: 0x0069, end grp handle: 0x0073 uuid: f000ccc0-0451-4000-b000-000000000000
attr handle: 0x0074, end grp handle: 0xffff uuid: f000ffc0-0451-4000-b000-000000000000

この中で加速度データに関するサービスの uuid は f000aa10-0451-4000-b000-000000000000 で、 関連する characteristic のハンドル番号は 0x2b 〜 0x35 が割り当てられていることがわかります。

それぞれの characteristic のタイプをみてみましょう。

[78:A5:04:19:6D:DB][LE]> char-desc 0x002b 0x0035
handle: 0x002b, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x002c, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x002d, uuid: f000aa11-0451-4000-b000-000000000000
handle: 0x002e, uuid: 00002902-0000-1000-8000-00805f9b34fb
handle: 0x002f, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0030, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0031, uuid: f000aa12-0451-4000-b000-000000000000
handle: 0x0032, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x0033, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x0034, uuid: f000aa13-0451-4000-b000-000000000000
handle: 0x0035, uuid: 00002901-0000-1000-8000-00805f9b34fb

"SensorTag attribute table" と見比べていくと、SensorTag で加速度サービスを 使うのに必要そうなハンドル番号は以下のようです。

  • ハンドル番号=0x2d 加速度の読み出し
  • ハンドル番号=0x2e 通知モードの設定
  • ハンドル番号=0x31 レンジの設定
  • ハンドル番号=0x34 計測間隔時間の設定

それでは、gatttool のインタラクティブモードを使って SensorTag を操作するコマンドを以下に記述していきます。

(1) SensorTagとの接続開始

コマンド:connect

(2) 計測値のレンジの設定(ハンドル番号=0x31)

使用するレンジに応じて設定値が異なる。 またデフォルトでは加速度の計測が無効になっていることに注意。 無効 → 0x00(デフォルト) ±2G→ 0x00 ±4G→ 0x02 ±8G→ 0x03

コマンド:char-write-cmd 0x31 01

(3) 計測間隔時間の設定(ハンドル番号=0x34)

計測間隔は最小100ms/最大1000ms(デフォルト)で、設定値は10分の1の値を指定する。 最小とする場合:100ms → 100x0.1=10 → 0x0A

コマンド:char-write-cmd 0x34 0a

(4) 通知モードの設定(ハンドル番号=0x2e)

SensorTag から加速度データの通知の有無を設定する。 通知なし→ 0x0000 (デフォルト) 通知あり→ 0x0100

コマンド:char-write-cmd 0x2e 0100 (通知ありに変更)

コマンド:char-write-cmd 0x2e 0000 (通知なしに変更)

(5) SensorTag との接続終了

コマンド:disconnect

実行例は以下のようになりました。

$ sudo gatttool -i hci0 -b 78:A5:04:19:6D:DB -I
[78:A5:04:19:6D:DB][LE]> connect                     (1)
Attempting to connect to 78:A5:04:19:6D:DB
Connection successful
[78:A5:04:19:6D:DB][LE]> char-write-cmd 0x31 01      (2)
[78:A5:04:19:6D:DB][LE]> char-write-cmd 0x34 0a      (3)
[78:A5:04:19:6D:DB][LE]> char-write-cmd 0x2e 0100    (4)
Notification handle = 0x002d value: 3e 07 f3 
Notification handle = 0x002d value: 3e 07 f3 
Notification handle = 0x002d value: 3d 06 f3 
Notification handle = 0x002d value: 3e 06 f3 
Notification handle = 0x002d value: 3c 06 f3 
Notification handle = 0x002d value: 3d 06 f2 
Notification handle = 0x002d value: 3d 06 f2 
Notification handle = 0x002d value: 3c 05 f4
...(snipped)...
[78:A5:04:19:6D:DB][LE]> char-write-cmd 0x2e 0000
[78:A5:04:19:6D:DB][LE]> disconnect                  (5)
[78:A5:04:19:6D:DB][LE]> exit
$ 

(4)のコマンドを入力すると、加速度データが SensorTag から順次通知されてきます。

gatttool では通知がきた時刻がわからないため、(3)のコマンドで設定した計測間隔100ms なのか確認できません。

そこで、gatttool のソースを修正してリコンパイルしてみました。

$ tar xfJ bluez-5.23.tar.xz
$ cd bluez-5.23
$ cp attrib/interactive.c{,.ORG}
$ vi attrib/interactive.c
$ make

bluez-5.23.tar.xz を bluez.org からダウンロードし、 展開してできる attrib/interactive.c を次のように修正。

修正前

static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
        uint8_t *opdu;
        uint16_t handle, i, olen;
        size_t plen;
        GString *s;

        handle = get_le16(&pdu[1]);

        switch (pdu[0]) {
        case ATT_OP_HANDLE_NOTIFY:
                s = g_string_new(NULL);
                g_string_printf(s, "Notification handle = 0x%04x value: ",
                                                                        handle);
                break;

修正後

static void my_g_string_printf_with_time(GString *s, uint16_t handle) {
        struct timeval myTime;
        struct tm *time_st;
        gettimeofday(&myTime, NULL);
        time_st = localtime(&myTime.tv_sec);

        g_string_printf(s,
                "%d/%02d/%02d %02d:%02d:%02d.%06d Notification handle = 0x%04x value: ",
                time_st->tm_year+1900,
                time_st->tm_mon+1,
                time_st->tm_mday,
                time_st->tm_hour,
                time_st->tm_min,
                time_st->tm_sec,
                myTime.tv_usec,
                handle);
}

static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
{
        uint8_t *opdu;
        uint16_t handle, i, olen;
        size_t plen;
        GString *s;

        handle = get_le16(&pdu[1]);

        switch (pdu[0]) {
        case ATT_OP_HANDLE_NOTIFY:
                s = g_string_new(NULL);
                /*
                g_string_printf(s, "Notification handle = 0x%04x value: ",
                                                                        handle);
                */
                my_g_string_printf_with_time(s, handle);
                break;

この改造版 attrib/gatttool で実行するとマイクロ秒単位での時刻付きで表示されます。

$ sudo attrib/gatttool -i hci0 -b 78:A5:04:19:6D:DB -I
[78:A5:04:19:6D:DB][LE]> connect
Attempting to connect to 78:A5:04:19:6D:DB
Connection successful
[78:A5:04:19:6D:DB][LE]> char-write-cmd 0x31 01
[78:A5:04:19:6D:DB][LE]> char-write-cmd 0x34 0a
[78:A5:04:19:6D:DB][LE]> char-write-cmd 0x2e 0100
2016/11/12 19:23:26.818633 Notification handle = 0x002d value: fb 02 42 
2016/11/12 19:23:26.886093 Notification handle = 0x002d value: ff 04 42 
2016/11/12 19:23:27.021098 Notification handle = 0x002d value: 00 06 41 
2016/11/12 19:23:27.088594 Notification handle = 0x002d value: 00 06 41 
2016/11/12 19:23:27.223609 Notification handle = 0x002d value: fe 04 41 
2016/11/12 19:23:27.291091 Notification handle = 0x002d value: ff 06 41 
2016/11/12 19:23:27.358580 Notification handle = 0x002d value: ff 03 42 
2016/11/12 19:23:27.493601 Notification handle = 0x002d value: fe 06 40 
2016/11/12 19:23:27.561082 Notification handle = 0x002d value: fe 04 3f 
2016/11/12 19:23:27.696095 Notification handle = 0x002d value: 00 06 41 
...(snipped)...
[78:A5:04:19:6D:DB][LE]> char-write-cmd 0x2e 0000
[78:A5:04:19:6D:DB][LE]> disconnect
[78:A5:04:19:6D:DB][LE]> exit
$ 

目測ではありますが、設定通りに 0.1 秒くらいの間隔で計測データが通知されていることを確認できました。