nRF5 SDK v11.0.0のble_app_hrs_cサンプルを見ていくシリーズ。
たぶん最終回だ。
前回、HRSPeripheralとのBLE接続を行うようにしたので、ble_evt_dispatch()でイベント処理を有効にした。
これでmain.cは、ログの追加以外はオリジナルと同じになった。
HRSとBASのイベントハンドラを有効にしたのだが、これはどちらもSDKが提供しているので、独自で実装している箇所はない。
だから、おそらくコールバックする設定をinitでやってるんじゃないか。
あった。
- HRS : hrs_c_evt_handler()
- BAS : bas_c_evt_handler()
SDKが提供しているハンドラの中では、BLE_GATTC_EVT_HVXやBLE_GATTC_EVT_WRITE_RSPなどのイベントをさばいている。
WRITE_RESなんかは、コールバックされないようだけど、中でsd_ble_gattc_write()を呼ぶようだ。
でも、これってWriteするAPIじゃないのか?
HRSでWriteがMandatoryなのは、Control Pointだ。
現在はリセットだけなのかな。
ble_hrs.cを見ると、WriteではCCCDの処理しかしていないし、Characteristic自体がConditionalだから、ble_hrs_cもWriteはCCCDしか意識していないのでコールバックしない、ということか。
Write without Responseの場合はBLE_EVT_TX_COMPLETEが発生し、そうでなければBLE_GATTC_EVT_WRITE_RSPが発生するらしい。
CCCD書込みでNotificationを有効にする場合、この順で呼ばれる。
ble_hrs_c_hrm_notif_enable()
↓
cccd_configure()
↓
tx_buffer_process(WRITE_REQ)
↓
sd_ble_gattc_write()
これはわかる。
しかし、BLE_GATTC_EVT_WRITE_RSPの場合はこうなると思うのだ。
ble_hrs_c_on_ble_evt()
↓
on_write_rsp()
↓
tx_buffer_process(WRITE_REQ ??)
↓
sd_ble_gattc_write()
WRITE_REQかどうかははっきりしないが、誰も変数に書込む人がいないので、維持されるはず。。。
あー、tx_buffer_process()の頭にあるindexの比較ではじかれるのかな?
バッファは8つ分あって、送信するときはcccd_configure()でm_tx_insert_indexが指すバッファに代入してインクリメントし、送信が成功したらm_tx_indexもインクリメントする。
WRITE_RSPイベントのときはインデックスは操作せずにtx_buffer_process()を呼ぶから、同じ値なので処理はしない。
もしcccd_configure()のルートで送信したときに失敗していたらm_tx_indexはインクリメントされないので、WRITE_RSPイベントの時にはインデックスが不一致なので再送される、と。
難しいよ!
HRSでReadのイベントがないのは、ReadするCharacteristicのBody Sensor LocationがOptionalだからだろう。
つまり、積極的にアプリが処理しないといけないのはNotification受信時だけとなる。
そういう目線でHRSのハンドラを見てみよう。
処理しているイベントは2つ。
BLE_HRS_C_EVT_DISCOVERY_COMPLETEとBLE_HRS_C_EVT_HRM_NOTIFICATION。
BLE_HRS_C_EVT_DISCOVERY_COMPLETEはイベントなのだが、サービスが見つかった、というイベントだ。
これは、db_disc_handler()から呼ばれる。
このハンドラはble_db_discovery_init()で登録している。
そして、db自体のハンドラはble_evt_dispatch()で他のイベントと一緒に並んでいる。
なのでまあ、BLE接続後のイベントは一緒くたということだな。
サービスが見つかったら、まずはNotificationを有効にせねば、ということでble_hrs_c_hrm_notif_enable()を呼んでいる。
BLE_HRS_C_EVT_HRM_NOTIFICATIONは、受信した値をログ出力するだけだ。
まあ、他にやれることがないしね。
Notificationされるのは、Heart Rate MeasurementというCharacteristic。
最初のバイトが、どのデータを含んでいるかのビットを立てるようになっていて、あとはそれに従ってデータが詰まっているだけのようだ。
Heart Rateだけは有無ビットがないので、必須なのだろう。
まあ、Heart RateサービスなのにHeart Rateが入ってなかったら、困るわね。
徐脈というか、脈が欠ける人はR-R間隔もほしいかも。
HRだけじゃわからないのよねぇ。
BLE接続後のことだけ書いたが、接続されたときのイベント処理も忘れてはいかんだろう。
BLE_GAP_EVT_CONNECTEDだ。
ここで、ハンドル値をHRSとBASに教えて、紐付けしているのだろう。
じゃあ切断の時はBLE_GAP_EVT_DISCONNECTEDかと思うと、そうではなくDM_EVT_DISCONNECTIONだ。
PeripheralだとGAPの方は切断された一番最後辺りに呼ばれて、DMの方が先に呼ばれていたと思う。
切断されてしまってからじゃ遅いよ、ということか。。。
でも、対称性がないからちょっとイヤなので、「今から切れます」イベントもGAPに来てくれるとうれしい。そんなのないけど。
CONNECTEDで紐付けしたハンドル値は、ble_hrs_cやble_bas_cの中で勝手に忘れるようになっている。
自分でサービスを作るときには忘れないようにせねば。
DMのDISCONNECTIONが何をしているかというと、スキャンの再開のようだ。
このサンプルでは1台しかPeripheralを接続しないので、切断したらスキャンが始まる。
スキャンの開始なんかGAPのDISCONNECTEDで始める方が良いような気がするのだけど、ここでよいってことなんだ。
まあ、Centralは相手が複数いるから、接続可能台数に達していない場合は常にスキャンしていることになるのか。
その上のDM_EVT_CONNECTIONでも台数未満だったらscan_start()してるし。
駆け足で見ていったCentralだったけど、よくわかってないことも多い。
こういうのは、実際に作りながらやってみるとよいのだろう。
BDSがCentral側のサービスもテンプレートを作ってくれるとよいのだけどなぁ。。。
0 件のコメント:
コメントを投稿
コメントありがとうございます。
スパムかもしれない、と私が思ったら、
申し訳ないですが勝手に削除することもあります。
注: コメントを投稿できるのは、このブログのメンバーだけです。