BLE General Discoverable ModeとLimited Discoverable Modeの比較

# 記事の概要
Nordic社製BLE nRF54280を用いて、BLEのGeneral Discoverable ModeとLimited Discoverable Modeの比較をします。

# BLE接続の仕組み
BLEはスレーブ側が発信するアドバタイジングパケットを、マスター側が検出することで接続を確立し、通信を行います。

このアドバタイジングパケットの発信には２つのモード、General Discoverable ModeとLimited Discoverable Modeがあります。

# General Discoverable Modeとは何か？
常にアドバタイジングパケットを発信するモードです。
マスター側BLE機器は、いつでもアドバタイジングパケットを検知できます。

# Limited Discoverable Modeとは何か？
何らかのイベント発生時に一定時間のみアドバタイジングパケットを発信するモードです。
マスター側BLE機器は、その期間中のみアドバタイジングパケットを検知できます。

アドバタイジングパケットの発信は電力を消費するので、発信期間を限定することで消費電力を抑えることができます。

# nRF52480を用いた比較
今回はnRF5 SDK v16.0.0を使用して、nRF52480の設定を行います。
他のバージョンのSDKや別のnRFシリーズにおいても、設定方法は同様になります。

## General Discoverable Mode試験
まずはGeneral Discoverable Modeを試してみます。
以下のサンプルプロジェクトを使用します。

~\nRF5SDK160098a08e2\examples\ble_peripheral\ble_app_blinky\pca10056\s140\arm5_no_packs\ble_app_blinky_pca10056_s140.uvprojx

サンプルプロジェクトのビルド方法は以下を参照してください。
[Nordic社製BLEの開発環境構築と動作確認](https://qiita.com/Kosuke_Matsui/items/5d61ce77e928b9f117cc#%E3%82%B5%E3%83%B3%E3%83%97%E3%83%AB%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%A0%E3%81%AE%E3%83%93%E3%83%AB%E3%83%89%E3%81%A8%E6%9B%B8%E8%BE%BC%E3%81%BF)

main.cの関数advertising_initにおいて、インスタンスadvdataを生成した上で、GAP Advertisement Flagsを『BLEのみに対応しているGeneral Discoverable Mode』に設定しています。

```c:main.c
ble_advdata_t advdata;

advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
```

flagsに設定可能な定義は以下になります。

| 定義名       |  値 |    意味    |
|:-----------------|:------------------:|:------------------|
| BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE |   (0x01)| Limited Discoverable Mode |
| BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE |   (0x02)| General Discoverable Mode |
| BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED |   (0x04)| BLE(Bluetooth Low Energy)のみに対応し、Bluetooth 3.0には対応していない |
| BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER |   (0x08)| BLE(Bluetooth Low Energy)とBluetooth 3.0 コントロール側に対応している |
| BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST |   (0x10)| BLE(Bluetooth Low Energy)とBluetooth 3.0 ホスト側に対応している |
| BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE |  |BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODEかつBLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED  |
| BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE || BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODEかつBLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED | 

これをビルドして書き込み、スニッファーでアドバタイジングパケットをスキャンすると、以下が検知できます。

![GENERAL_DISC_MODEのアドバタイジングパケット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/f89ce72f-44db-e468-5ea4-32e8b44893be.png)

Flagsが"LeGeneralDiscMode"になっていることが分かります。
このアドバタイジングパケットは、どれだけ時間が経過しても常に発信され続けます。

## Limited Discoverable Mode試験
次にLimited Discoverable Modeを試してみます。
アドバタイジングパケット設定がより複雑になるので、以下のサンプルプロジェクトを使用します。

~\nRF5SDK160098a08e2\examples\ble_peripheral\ble_app_uart\pca10056\s140\arm5_no_packs\ble_app_uart_pca10056_s140.uvprojx

main.cの関数advertising_initにおいて、インスタンスinitを生成した上で、GAP Advertisement Flagsを『BLEのみに対応しているLimited Discoverable Mode』に設定しています。

```c:main.c
ble_advertising_init_t init;

init.advdata.flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;
```

Limited Discoverable Modeは一定時間だけアドバタイジングパケットを発信するモードです。
具体的な発信時間は以下で設定しています。

```c:main.c
advdata.flags = init.config.ble_adv_fast_interval = APP_ADV_INTERVAL;
```

APP_ADV_INTERVALは、サンプルにおいては定数18000に設定されています。単位当たり10msecなので、このアドバタイジングパケットは3分後に発信を停止します。

これをビルドして書き込み、スニッファーでアドバタイジングパケットをスキャンすると、以下が検知できます。

![LIMITED_DISC_MODEのアドバタイジングパケット.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/8a2cfaa7-41d1-7125-efd0-6e1ca95857de.png)


Flagsが"LeLimitedDiscMode"になっていることが分かります。
このアドバタイジングパケットは、先述したように3分が経過すると発信されなくなります。

ちなみにプログラムにおいては、アドバタイジングパケット停止時に関数on_adv_evt()を呼び出し、イベントble_adv_evtのBLE_ADV_EVT_IDLEに分岐しています。

サンプルでは分岐先でシステムOFFモードに遷移させています。

```c:main.c
        case BLE_ADV_EVT_IDLE:
            sleep_mode_enter();
            break;
```

また、システムOFFモードに入る前に、WakeUp条件にスイッチ押下を設定しています。
今回のテーマから逸脱するので関数の詳細を説明しませんが、興味のある方はサンプルのプログラムを直接ご覧ください。

```c:main.c
    // Prepare wakeup buttons.
    err_code = bsp_btn_ble_sleep_mode_prepare();
    APP_ERROR_CHECK(err_code);
```

実際にスイッチ押下すると、システムOFFが解除されて、リセットが入り、以下のUART通信後にアドバタイジングパケットが発信を再開します。

![WakeUpボタン.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150620/e789faf8-f453-75e2-70c3-7c6f9473ea70.png)


Limited Discoverable Modeにおける発信再開するには、関数advertising_start()を実行します。

サンプルではシステムOFF解除によるリセットをかけることでadvertising_start()を再実行していましたが、スイッチ、加速度計の検知出力、通信を起因とする割り込み処理によりadvertising_start()を実行することでも再開できます。

# まとめ
General Discoverable ModeとLimited Discoverable Modeを比較し、アドバタイジングパケットの発信時間が異なることが確認できました。

Limited Discoverable Modeを使用する時は、セントラル側もこのモードのアドバタイジングパケットしか検知できないようにすることで、特定のBLE機器とのみ接続できるようにします。

ですが実際にはLimited Discoverable Modeが使用されることは少なく、General Discoverable Modeのアドバタイジングパケットをセントラル側が取捨選択して、目当てのBLE機器とのみ接続できるようにすることが多いと思われます。