nRF Connect SDK:拡張アドバタイズ


Bluetoothのアドバタイズ

従来のアドバタイズ(以下、レガシーアドバタイズ)はパケット長が31Bytesまででした。128Bit UUIDをパケットに入れようものなら半分以上持っていき、AD NAMEは仕様上31Bytesまでですが、それ以外の情報も必要なので31BytesのAD NAMEは絶対に入らないというトンデモと言えなくもない仕様でした(笑)
そのレガシーアドバタイズの仕様がBluetooth 5で見直され、拡張アドバタイズという仕様で出てきました。

とは言ったものの

登場して間もないころは受信側となるスマートフォンやパソコン側が全然Bluetooth 5ではないので拡張アドバタイズを受信することができず、全く見向きされることはありませんでした。少なくとも日本企業はそんな限定的な対応しかできない仕様を使うことは絶対にしません。ちなみに初めてBluetooth 5を採用して拡張アドバタイズを受信できるようになったのがたしかiPhone 7だったと思います。
その後、すぐにPixel 3も拡張アドバタイズを受信できるデバイスとして登場したような記憶がなんとなくありますが、めんどくさいので時系列は調べません。

ちなみに最近は

最近はパソコンに搭載されるBluetoothもほとんどが5以上になってきており、ようやく拡張アドバタイズを使っても問題が起きなさそうな環境になってきています。が、まだまだ既存デバイスもいっぱい残っているため、拡張アドバタイズが本格的に使われるのはもっとずっと後の話になるのだろうと思われます。
ちなみに弊社は自社で送信側も受信側も作っているので、そのデバイス間で拡張アドバタイズを使っております。おそらく日本初の拡張アドバタイズを使った製品(2019年当時)だと思っていますが調べたわけではないので分かりません。

せっかくnRF52(nRF53)系を使っているので

でもせっかくBluetooth 5の拡張アドバタイズに対応したチップを使っているのだから使ってみようと思いませんか?え、思わない?まあまあそう言わずに・・・。

拙作のアドバタイズを改変

以前に公開したアドバタイズプロジェクトをベースに手を加えていきます。拡張アドバタイズは基本的にAPIの名称にextが付加されていますが、単純に名称が変わっているだけではなく、与える引数が変わっているものもあります。

main.c
/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr.h>
#include <sys/printk.h>
#include <settings/settings.h>

#include <bluetooth/bluetooth.h>
#include <bluetooth/gatt.h>

#define DEVICE_NAME CONFIG_BT_DEVICE_NAME
#define DEVICE_NAME_LEN (sizeof(DEVICE_NAME) - 1)

static const struct bt_data ad[] = {
    BT_DATA_BYTES(BT_DATA_FLAGS, (BT_LE_AD_GENERAL | BT_LE_AD_NO_BREDR)),
    BT_DATA(BT_DATA_NAME_COMPLETE, DEVICE_NAME, DEVICE_NAME_LEN),
};

static void connected(struct bt_conn *conn, uint8_t err)
{
    printk("Connected\n");
}

static void disconnected(struct bt_conn *conn, uint8_t reason)
{
    printk("Disconnected\n");
}

static struct bt_conn_cb conn_callbacks = {
    .connected    = connected,
    .disconnected = disconnected,
};

void main(void)
{
    struct bt_le_ext_adv *ext_adv;
    struct bt_le_adv_param *adv_param = BT_LE_ADV_PARAM(
        BT_LE_ADV_OPT_CONNECTABLE | BT_LE_ADV_OPT_EXT_ADV,
        BT_GAP_ADV_FAST_INT_MIN_2,
        BT_GAP_ADV_FAST_INT_MAX_2,
        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_ext_adv_create(adv_param, NULL, &ext_adv);
    if (err)
    {
        printk("Failed to create advertiser set (%d)\n", err);
        return;
    }

    err = bt_le_ext_adv_set_data(ext_adv, ad, ARRAY_SIZE(ad), NULL, 0);
    if (err)
    {
        printk("Failed to set advertising data (%d)\n", err);
        return;
    }

    err = bt_le_ext_adv_start(ext_adv, NULL);
    if (err)
    {
        printk("Failed to start advertising set (%d)\n", err);
        return;
    }

    printk("Start advertising with extension.");
}

また、proj.confのほうで拡張アドバタイズを使用する設定をする必要があります。う~ん、めんどくさいな・・・。

proj.conf
# BLUETOOTH
CONFIG_BT=y
CONFIG_BT_PERIPHERAL=y
CONFIG_BT_DEVICE_NAME="nRF connect SDK"
CONFIG_BT_EXT_ADV=y

確認方法

拡張アドバタイズかどうかを確認するにはスニファーでももちろんできますが、もっと簡単にnRF Connect for mobileで見ることができます。受信したアドバタイズをタップすると詳細情報が出るので、そこに拡張アドバタイズという記載があれば拡張アドバタイズになっています。