叶鋼は午前1時に計算をする

電子工作と計算の記録

【BLEを使う】nRF51822 のAdvertisingパケットとScanパケットの作成(Peripheral側)

神は細部に宿る

いままでの記事はこちらをご覧ください。

  

BLE接続が確立していない段階では、BLEのスレーブがアドバタイジングパケットを発信し、接続できるセントラルに自分の存在を報せます。

NordicのサンプルプログラムではソフトウェアS110で用意された諸々の関数や定義を用いてアドバタイジングパケットやスキャンパケットを作成しています。

今回はその作成方法について説明します。  

設定しないといけない主な項目は以下になります。

 

①Adv PDU

アドバタイジングパケットのヘッダーの上位4bitです。 以下の種類があります。

値[3:0]Type接続性スキャン指向性
0000ADV_IND有り有り無し
0001ADV_DIRECT_IND有り無し有り
0010ADV_NONCONN_IND無し無し無し
0110ADV_SCAN_IND無し有り無し

 

②AD Type

AD Dataの先頭に配置される1byteのデータです。

多くの種類がありますが、今回説明するのは以下になります。

DataType
0x0Flags
0x03Complete List of 16-bit Service Class UUIDs
0x07Complete List of 128-bit Service Class UUIDs
0x08Shortened Local Name
0x09Complete Local Name
0x0ATx Power Level
0x19Appearance

 

では、実際にこれらの設定をプログラムに反映させてみます。

 

Adv PDU

アドバタイジングPDUは、構造体ble_gap_adv_params_tのtypeで設定します。

ble_gap_adv_params_tの構造は以下を参照してください。

nRF5 SDK guides - Nordic DevZone

 

サンプルプログラムの多くでは、advertising_start関数やadvertising_init関数などでプログラム冒頭に設定されています。

例えば、以下のサンプルプログラムにおけるmain.cの関数advertising_startのadv_params.typeがそれになります。

nrf51-ble-app-lbs/main.c at master · NordicPlayground/nrf51-ble-app-lbs · GitHub

    adv_params.type        = BLE_GAP_ADV_TYPE_ADV_IND;

設定する項目は以下の定数のどれかを選択してください。

Type定義
ADV_INDBLE_GAP_ADV_TYPE_ADV_IND0x00
ADV_DIRECT_INDBLE_GAP_ADV_TYPE_ADV_DIRECT_IND0x01
ADV_NONCONN_INDBLE_GAP_ADV_TYPE_ADV_NONCONN_IND0x03
ADV_SCAN_INDBLE_GAP_ADV_TYPE_ADV_SCAN_IND0x02

アドバタイジングPDUは4種類ありますがADV_DIRECT_IND は使うべきではありません。

 

Flags

Flagsは必須設定項目です。

構造体ble_advdata_tのflags.sizeとflags.p_dataを設定してください。

ble_advdata_tの構造は以下を参照してください。

https://devzone.nordicsemi.com/documentation/nrf51/4.3.0/html/structble__advdata__t.html

例えば、以下のサンプルプログラムにおけるmain.cの関数advertising_initをご覧ください。

nrf51-ble-app-lbs/main.c at master · NordicPlayground/nrf51-ble-app-lbs · GitHub

advertising_initの変数flagsで設定しているのが分かります。

    uint8_t       flags = BLE_GAP_ADV_FLAGS_LE_ONLY_LIMITED_DISC_MODE;      

すると以下のようにflagsのサイズと設定値が自動的に更新されます。

    advdata.flags.size              = sizeof(flags);               
    advdata.flags.p_data            = &flags;               

flagsには、以下のいずれかの定数を設定してください。

定義
BLE_GAP_ADV_FLAG_LE_LIMITED_DISC_MODE0x01
BLE_GAP_ADV_FLAG_LE_GENERAL_DISC_MODE0x02
BLE_GAP_ADV_FLAG_BR_EDR_NOT_SUPPORTED0x04
BLE_GAP_ADV_FLAG_LE_BR_EDR_CONTROLLER0x08
BLE_GAP_ADV_FLAG_LE_BR_EDR_HOST0x10
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)

 

DEVICE_NAME

ユーザーが任意につけられる装置の名前です。

例えば、iphone(central)にadvertisingパケットが検知されたときに、iphoneのアプリ画面上にこの装置名が表示されます。  

DEVICE_NAMEはプログラム中の以下の定数に入力してください。 例えば、以下のサンプルプログラムにおけるmain.cの43行目がそれです。

nrf51-ble-app-lbs/main.c at master · NordicPlayground/nrf51-ble-app-lbs · GitHub

#define DEVICE_NAME                     "LedButtonDemo"          

定義したDEVICE_NAMEはmain.cの関数gap_params_initにおいてアドバタイジングパケットに組み込まれているのが分かります。

    err_code = sd_ble_gap_device_name_set(&sec_mode,          
                                          (const uint8_t *)DEVICE_NAME,           
                                          strlen(DEVICE_NAME));          

また、DEVICE_NAMEについては、DEVICE_NAMEの全文字を使うComplete local name(AD typeは0x09)か先頭の数byteのみを短縮名として使うShortened Local Name(AD typeは0x08)を指示します。

短縮名を使用する場合、完全なDEVICE_NAMEはGATTのdevice name characteristicを使って読み出せます。

どちらを使用するかは、構造体ble_advdata_tのname_typeで設定してください。

例えば、サンプルプログラムのmain.cの関数advertising_initのadvdata. name_typeがそれです。

    advdata.name_type               = BLE_ADVDATA_FULL_NAME; 

advdata.name_typeには、以下のいずれかの定数を設定します。

定義意味
BLE_ADVDATA_NO_NAME装置名なし
BLE_ADVDATA_SHORT_NAME装置名短縮
BLE_ADVDATA_FULL_NAME 装置名Full

 

外部装置

APPEARANCE(外部装置)は、main.cの関数gap_params_initの sd_ble_gap_appearance_setで設定することでアドバタイジングパケットに組み込まれます。

nrf51-ble-app-lbs/main.c at master · NordicPlayground/nrf51-ble-app-lbs · GitHub

    err_code = sd_ble_gap_appearance_set(BLE_APPEARANCE_HEART_RATE_SENSOR_HEART_RATE_BELT);
    APP_ERROR_CHECK(err_code);

APPEARANCE(外部装置)は以下の定義から適切なものを選択します。

nRF5 SDK guides - Nordic DevZone

また、APPEARANCEを使用する場合、構造体ble_advdata_tのinclude_appearanceを設定してください。

例えば、以下のサンプルプログラムにおけるmain.cの関数advertising_initをご覧ください。

nrf51-ble-app-lbs/main.c at master · NordicPlayground/nrf51-ble-app-lbs · GitHub

    advdata.include_appearance      = true;

 

TX power

送信出力はプログラム中でBLE_GAP_AD_TYPE_TX_POWER_LEVELで設定します。

#define BLE_GAP_AD_TYPE_TX_POWER_LEVEL                      0x0A /**< Transmit power level. */    

 

スキャン応答によるデータ送信

アドバタイジングパケットは31bytesしか使用できないので、必要な情報を伝えきれないことがあります。

その場合は、centralからのスキャン要求に対するスキャン応答においてデータを追加で送信できます。

ちなみにcentralからのスキャン要求が送信されるタイミングは、centralがperipheralからのアドバタイジングパケットを検知した直後になります。  

またスキャンパケットに乗せるデータは構造体ble_advdata_tを持つ変数を追加でもう1個作成してください。

例えば、以下のサンプルプログラムにおけるmain.cの関数advertising_initをご覧ください。

nrf51-ble-app-lbs/main.c at master · NordicPlayground/nrf51-ble-app-lbs · GitHub

サンプルプログラムでは以下の2つを作成しています。

    ble_advdata_t advdata;
    ble_advdata_t scanrsp;

スキャン応答でデータを送信する場合は、関数ble_advdata_setの2番目の引数に上で作成したスキャンパケットデータの先頭アドレス&scanrspを設定します。

スキャンパケットに何もデータを乗せない場合は2番目の引数をNULLにしておきます。

    //スキャンパケットに何もデータを乗せない場合           
    //err_code = ble_advdata_set(&advdata, NULL);              
    //スキャンパケットでデータを送信する場合            
    err_code = ble_advdata_set(&advdata, &scanrsp);          

 

サービスUUID(BLE SIGで定義済みのUUIDを使用する場合)

ここではBLE SIGであらかじめ定義されているサービスUUIDを、アドバタイジングパケットで送信する場合を考えます。

サービスUUIDの設定は、構造体ble_advdata_tのuuids_complete.uuid_cntとuuids_complete.p_uuidsを設定してください。

例えば、以下のサンプルプログラムにおけるmain.cの関数advertising_initをご覧ください。

nrf51-ble-app-lbs/main.c at master · NordicPlayground/nrf51-ble-app-lbs · GitHub  

main.cにおいて ble_uuid_t adv_uuidsで設定します。サンプルプログラムと異なり、以下は既存のサービスを使う場合の設定です。

    ble_uuid_t adv_uuids[] = {{BLE_UUID_BATTERY_SERVICE, BLE_UUID_TYPE_BLE}};

ble_uuid_t adv_uuidsの1番目の引数がUUIDのデータを示し、2番目の引数がUUIDのtypeを示しています。

BLE SIGで定義されたサービスUUIDを使用する場合は、BLE_UUID_TYPE_BLEを指定します。

1番目の引数には、あらかじめ定義されたサービスUUIDが使用できます。(プログラムではble_srv_common.hで定義されています。)

すると以下のように設定値が自動的に更新されます。

    advdata.uuids_complete.uuid_cnt = sizeof(adv_uuids) / sizeof(adv_uuids[0]); 
    advdata.uuids_complete.p_uuids  = adv_uuids;    

 

また、サービスUUIDが複数の場合は、以下のようにして指定します。

    ble_uuid_t adv_uuids[] =
    {
        {BLE_UUID_HEART_RATE_SERVICE,         BLE_UUID_TYPE_BLE},
        {BLE_UUID_BATTERY_SERVICE,            BLE_UUID_TYPE_BLE},
        {BLE_UUID_DEVICE_INFORMATION_SERVICE, BLE_UUID_TYPE_BLE}
    };

 

サービスUUID(カスタムUUIDを使用する場合)

ここではサービスUUIDを自分で作成し、スキャンパケットで送信する場合を考えます。

既存のサービスのときと同様にble_uuid_t adv_uuidsを設定します。

    ble_uuid_t adv_uuids[] = {{LBS_UUID_SERVICE, m_lbs.uuid_type}};

ble_uuid_t adv_uuidsの1番目の引数は自分で作成したUUIDを指定します。

UUIDにはnRFgo StudioのUUID生成ツールで作成したBase UUIDを使用しました。

nRF8001 Configurationを選択します。

f:id:yegang:20141025152945j:plain

nRF80001 SetupからEdit 128-bit UUIDsを選択します。

f:id:yegang:20141025153001j:plain

Add newで新しいUUIDを作成します。

f:id:yegang:20141025153013j:plain

プログラムにおいては、xxxxを0000で埋めて、下位byteから2byteずつ配置してください。

例)UUID = 1234xxxx-5678-9ABC-DEFA-132547698BACの場合、プログラムのどこかに以下のUUIDを定義します。

以下の例では、作成したUUIDのxxxxの部分に任意の4桁の数字を代入して、Service UUIDと複数のCharacteristic UUIDを作成しています。

#define LBS_UUID_BASE {0xAC, 0x8B, 0x69, 0x47, 0x25, 0x13, 0xFA, 0xDE, 0xBC, 0x9A, 0x78, 0x56, 0x00, 0x00, 0x34, 0x12}            
#define LBS_UUID_SERVICE 0x1523         
#define LBS_UUID_LED_CHAR 0x1525        
#define LBS_UUID_BUTTON_CHAR 0x1524

uuid_type は関数sd_ble_uuid_vs_addを使うことで各SeviceやCharacteristicに組み込まれます。

詳細はサービス初期化関数で説明します。

サンプルプログラムでは、サービスUUIDはスキャンパケットで送信するので、advdataパラメータではなく、scanrspパラメータに格納されています。

また、ble_advdata_setの2番目の引数には&scanrspを指定しています。