2015年11月24日火曜日

nrf51822 でデバイスをスキャンして Macアドレスと RSSI を取得する方法

概要

nrf51822 に Central の機能を実装して BLE デバイスをスキャンしてみました
スキャンした際に対象デバイスの Mac アドレスと RSSI (受信信号強度) を取得してデバッグ出力してみます

環境

  • Windows7 64bit
  • nRF51822
  • nRF51 DK
  • nRF51 SDK 9.0.0
  • SoftDevice S130

実装方法

今回は Peripheral ではなく Central の機能を実装するので SoftDevice のバージョンは s120 or s130 が必要になります
なので、あらかじめ上記の SoftDevice を書き込んでおいてください
実装方法は SDK に含まれる Central のサンプルコードベースで説明します

スキャンできるように初期化する

まずスキャンの方法を設定します
サンプルコードでは基本的に main メソッド内で初期化用のメソッドをコールすることで初期化を行っています

スキャンの初期化の流れは ble_stack_init -> softdevice_ble_evt_handler_set -> ble_evt_dispatch -> on_ble_central_evt になります
簡単に説明するとスキャンを実行した際に発生するイベントを on_ble_central_evt メソッドでハンドリングする設定を行っています

このコールの流れは基本サンプルのままで OK です
これが設定されていればスキャンの基本の設定は完了です
次にハンドリングしたイベント内で実際に Macアドレスと RSSI を取得してみます

Macアドレスと RSSI を取得するロジックを追加

修正は on_ble_central_evt メソッドだけになります
このメソッドは発生したイベント ID を取得して switch 文でイベントを分岐しています

static void on_ble_central_evt(ble_evt_t * p_ble_evt) {
    uint32_t                err_code;
    const ble_gap_evt_t   * p_gap_evt = &p_ble_evt->evt.gap_evt;

    switch (p_ble_evt->header.evt_id) {
    case BLE_GAP_EVT_ADV_REPORT: {
            // ...
            break;
        }
    case BLE_GAP_EVT_TIMEOUT:
        // ...
        break;

    case BLE_GAP_EVT_CONN_PARAM_UPDATE_REQUEST:
        // ...
        break;

    case BLE_GAP_EVT_DISCONNECTED:
        // ...
        break;

    default:
        break;
    }
}

今回はこの中の BLE_GAP_EVT_ADV_REPORT の switch 文を修正します
Mac アドレスと RSSI は引数として渡ってきた ble_evt_t のポインタから取得します

取得方法は以下の通りです

ble_gap_addr_t pa = p_gap_evt->params.adv_report.peer_addr;
int8_t rssi = p_gap_evt->params.adv_report.rssi;
printf("Mac Address: %02x:%02x:%02x:%02x:%02x:%02x \r\n", pa.addr[5], pa.addr[4], pa.addr[3], pa.addr[2], pa.addr[1], pa.addr[0]);
printf("RSSI %d \r\n", rssi);

これをそのまま BLE_GAP_EVT_ADV_REPORT の switch 文中に記載すれば OK です
Mac アドレスは LSB (下位ビットから格納する方式) になっているので、添字の大きい方から参照します

ドットや矢印でいろいろと参照していますが流れとしては

  1. ble_evt_t から evt.gap_evt で GAP (General Access Profile) のイベントを取得
  2. イベントの params フィールドからパラメータを参照
  3. パラメータの adv_report フィールドからアドバタイジング情報を参照
  4. アドバタイジング情報の peer_addr フィールドから Mac アドレス情報を参照
  5. アドレス情報の addr[6] フィールドが Macアドレスが格納されている配列になっている

という感じです
RSSI は adv_report から直接数値が参照できます
この辺りはリファレンスを参照すると、この構造体のこのフィールドを参照しているという流れがわかると思います

スキャンを開始する

これもサンプルをそのまま使っているのであれば特に変更する箇所はありません
main メソッド内 scan_start というメソッドをコールしていれば Central のスキャンを開始することができます

int main(void) {
    uint32_t err_code;
    bool erase_bonds;

    // Some Initialize ...
    ble_stack_init();
    // Some Initialize ...

    // Some Initialize ...
    scan_start();
    // Some Initialize ...

    for (;; ) {
        power_manage();
    }
}

scan_start を辿ってみるとわかると思いますが結構いろいろな設定をしています
スキャンの間隔やホワイトリストを使って、信頼するデバイスだけスキャンするようにするとか、タイムアウトをどうするかなど設定できます
興味があれば、scan_start メソッドのサンプルとリファレンスを見ながらいろいろとパラメータチューニングしてみてください

コードが記載できたら Keil でビルドして nRFgo Studio でアプリケーションを焼きこんでみましょう
焼きこみが完了すれば自動的に nRF51 DK が BLE デバイスとなりスキャンを開始します

試す

アドバタイズしている BLE デバイスは結構街中に飛んでいるのでスキャンを開始すればデバイスが見つかるかもしれません
ない場合はスマホアプリで Peripheral になれるアプリがあるので、それを使ってみてください
自分は SensorTag CC2650 を使いました

デバッグは nRF51 DK を PC に USB で接続して TeraTerm でシリアルモニタをすればいいと思います
ボーレートは 38400 を設定してください

今回のサンプルは printf しているだけなので、デバイスが見つかればそのまま出力されると思います

最後に

コンシューマ向けの BLE デバイスは基本は Peripheral のみが実装されており、iPhone とか Android などのスマホが Central になっています
nrf51822 は Central にもなることでできるのでちょっとおもしろい実装ができます

nrf51822 には pstorage という仕組みもあってデバイス上にデータも保存できるので、スキャンした情報を保存しておくこともできます

pstorage の話もどっかでできればなぁと思っています
あと、サラッと書いたデバッグの方法とかも書いたほうがいいかなと思っています

0 件のコメント:

コメントを投稿