nRF Connect SDK:アドバタイズをもう少し詳しく見てみよう


(3/28追記)

まずはnRF SDK

nRF Connect SDK(以下NCS)のアドバタイズを解析するにあたって、その前に比較対象としてnRF SDKのアドバタイズを見てみようと思います。
BLEには明確な仕様が定められているので、その仕様をちゃんと理解していればいきなりNCSのアドバタイズを見るだけでも検証はできるわけですが、比較対象があると理解し易いのではないでしょうか。

nRF SDKのble_app_templateプロジェクト

何はともあれ、このプロジェクトが一番基本になると思うので何も手を加えずにコンパイルして動かしてみようと思います。それをBluetoothスニファーで掴まえてみたのがこちらです。

Nordic_Templateの欄に印が付いているのがBLEのパケットを拾っている部分です。パケットの間隔を見てみると196.4msecと出ていますが、

main.c
#define APP_ADV_INTERVAL                300                                     /**< The advertising interval (in units of 0.625 ms. This value corresponds to 187.5 ms). */

main.cのdefineにある187.5msecとおおむね一致しているということでよいと思います。
さらにもう少し詳しくパケットを見てみると・・・お、パケットが3つある?

なんと1回のアドバタイズで全アドバタイズチャネル(37~39)に投げているんですね。BLE触り始めてもう何年も経っていますが初めて知りました(笑)。
(って考えるとこういうことを書くのも勉強になりますね)

続いてNCSのアドバタイズを見てみる

NCSにはアドバタイズのテンプレートはありませんので、稚拙ですが自分で公開している記事から引用したいと思います。

さっそく動かしてみます。なお、proj.confには必要最小限の記述しかしていないため、nRF SDKのdefineにあるようなインターバル設定はしていないはずで、おそらくデフォルトの値が使用されているはずです。

スニファーで確認してみたところデフォルトのインターバルは100msecのようです。ほう、NCSのデフォルトはnRF SDK時代よりも早くなっているんですね。そんなに電池消費に影響するわけではないですが、個人的には200msecくらいのインターバルでいいんじゃないかと思っています。あと、こちらも全チャンネル一斉にアドバタイズパケットが飛んでいます。

ところでどこで設定するの?

NCSのアドバタイズインターバルが100msecなのは分かったのですが・・・これってどこで設定するのでしょうか?今までの流れからは、普通に考えるとprj.confの設定だと思われるのですがそれらしい設定は見つかりません。ついでに言うとスキャンレスポンスも設定しているつもりはないのですが、どこで設定するのかこれも分かりません。
CAF(Common Application Frame)の中にはそれっぽい設定があるのが見つかりましたが、現時点(V1.9.0)でNCSはCAFをサポートしていないようです。
(Show Allしないと出てこないし、表示してみたところでグレーアウトして設定できない)

Bluetooth関連はZephyrが握っていた

コメントで教えていただいたので調べてみたところ、Bluetoothの設定に関する部分は全部Zephyrが握っているということが判明しました。ZephyrはあくまでRTOSの部分だけを担っていると思っていたので、まさかBluetooth関連の設定がこちらにあるとは考えすらしませんでした。

もう少し追っていくと、実は自分で設定していた

一つ一つ検索でdefineを追っていくと実は自分で設定していたという事実を発見しました(笑)

main.c
    err = bt_le_adv_start(BT_LE_ADV_CONN, ad, ARRAY_SIZE(ad), NULL, 0);
    if (err) {
        printk("Advertising failed to start (err %d)\n", err);
    }

にあるBT_LE_ADV_CONNがそうです。この中身はBluetooth.hの中に定義されており、見てみると

#define BT_LE_ADV_CONN BT_LE_ADV_PARAM(BT_LE_ADV_OPT_CONNECTABLE, \
				       BT_GAP_ADV_FAST_INT_MIN_2, \
				       BT_GAP_ADV_FAST_INT_MAX_2, NULL)

のようになっていて、ここでアドバタイズ間隔の最小値と最大値を決めています。(お、NCSでは最大値も決められるんだ・・・どんな意味があるのか知らんけど)

つまり、知らないうちにサンプルに書かれていたZephyr推奨(?)の設定値を使っていたということなんですね。いや、やっぱり何も考えずにコピペするとこうなりますよね(笑)

自分で定義する

というところまで分かったので、自分で定義することでおそらくアドバタイズのインターバルを変更することはきっとできるはず!
ということで、試しに200msecインターバルにしてみようと思います。

main.c
void main(void)
{
    struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(
        BT_LE_ADV_OPT_CONNECTABLE,
        0x0140,   // 0x140(320) * 0.625 = 200(msec)
        0x0140,   // 0x140(320) * 0.625 = 200(msec)
        NULL
    );
    int err = 0;

    err = bt_enable(NULL);
    if (err) {
        printk("Blutooth failed to start (err %d)\n", err);
    }

    if (IS_ENABLED(CONFIG_SETTINGS)) {
        settings_load();
    }

    bt_conn_cb_register(&conn_callbacks);

    err = bt_le_adv_start(adv_param, ad, ARRAY_SIZE(ad), NULL, 0);
    if (err)
    {
        printk("Advertising failed to start (err %d)\n", err);
    }
}

スニファーで確認するとちゃんと200msecになっています。うん、すばらしい!(笑)

結論

Bluetooth関連の設定は全部Zephyrが握っているのだということを改めて発見(認識)しました。次はこのあたりを深堀していこうと思います。