#概要
1.0.0 では大丈夫だったコードでなぜか 1.0.1 だとうまく動かないコードがあって、調べてみたところ
既に伝わってる問題のようであるのだけど、まぁ解決してない(当初執筆時現在)
https://github.com/nkolban/esp32-snippets/issues/744
https://github.com/nkolban/esp32-snippets/issues/767
以下は夢は人に託すなと歌の歌詞にあったので自分の足で歩こうとするおっさんの話。
#なお
2019/2/3 現在、767 のほうに wakwak-koba さんや chegewara さんのコメントにあるとおり「connect 呼ぶときはアドレスとタイプを指定する関数ならタイプまでちゃんと指定する」「もしくは BLEAdvertisedDevice* を渡すほうの関数を使う」で解決するっぽいです。以下は経緯とかなんとかのために残しておきますが、これを知ってれば読まなくて大丈夫!
#問題点
元々 BLEClient::connect
関数の中で m_semaphoreOpenEvt.wait("connect");
している奴に give するパートが、
void BLEClient::gattClientEventHandler
関数の swicth
での case ESP_GATTC_OPEN_EVT:
のところなのだが、
たまに ESP_GATTC_OPEN_EVT
が来てないのに切断されて ESP_GATTC_DISCONNECT_EVT:
が来てしまい、
結果前述のm_semaphoreOpenEvt.wait("connect");
が永遠に待機状態になる、
というもの。
#弄ってみよう
ESP_GATTC_OPEN_EVT:
が来た時は m_isConnected = true;
に設定してから、give
するので、
要するに m_isConnected == false
な時に ESP_GATTC_DISCONNECT_EVT:
が来たら wait
を解消する give
を投げりゃええんじゃないの?わからんけど!
というわけで、まず ESP_GATTC_DISCONNECT_EVT:
側を弄る。give しろ give 。
case ESP_GATTC_DISCONNECT_EVT: {
// If we receive a disconnect event, set the class flag that indicates that we are
// no longer connected.
if ( !m_isConnected) m_semaphoreOpenEvt.give(evtParam->open.status);
でもって受け側は以下のように m_isConnected == false
なら繋がってねーじゃんチキショーという判定を入れる
uint32_t rc = m_semaphoreOpenEvt.wait("connect"); // Wait for the connection to complete.
if ( !m_isConnected ) {
ESP_LOGE(LOG_TAG, "m_semaphoreOpenEvt.wait terminated by disconnection" );
ESP_LOGD(LOG_TAG, "<< connect(), rc=%d", rc==ESP_GATT_OK);
return false;
}
これで無限待機はしない。
我が家の場合、1度目が 100% 失敗するが、再度 BLEScan からやりなおすと、2回目の試行ではちゃんと接続できる。なんなんだ。
ペリフェラルが2つあるのだが、2つとも1回目失敗して2回目成功する。なんなんだ。
引き続き、一発目から成功するコードの書き方を探るか、Arduino-ESP32 を諦めて SDK 的に記述するか考えたい。
#ちなみに
動いていた(今も動いてる)コードってのは
https://qiita.com/ajtajta_j/items/fd17980e71ddecb74da3
で書いたものなんだけど、(動いているとは言え)見返すといろいろ恥ずかしいコードなのであんまり見ないでくださいw
#続報
1回目(100%失敗)と2回目(100%成功)のログを見比べるて、ひょっとして BLEClient の準備が間に合ってなくて失敗してるのか?と疑ってみて、advertise callback で device found の時点で BLEClient を作ってしまうようにしたら上手くうごいたぞ。わからんけど!
#さらに続報 2019/2/1
Arduino-ESP32 1.0.1 でやる場合は
https://github.com/nkolban/esp32-snippets/issues/767 にて
wakwak-koba さんが指摘されているとおり BLEClient::connect( BLEAddress address, esp_ble_addr_type_t type )
の type
を適切に設定する、
または
chegewara さんが挙げているとおり BLEClient::connect( BLEAdvertisedDevice* device )
のほうで呼ぶ
ことで回避できる、気がします(私の最新のコードは( BLEAdvertisedDevice* device ) のほうで呼んでいるから動いてる説)
自分で検証はまだできてませんが、取り急ぎ。(整理出来たら元の記事に集約してこちらは消すかも)
#最終の続報 2019/2/3
検証しましたが、たしかに
BLEClient::connect( BLEAddress address, esp_ble_addr_type_t type )
の type
を適切に設定する、
(AE-TYBLE16 や micro:bit の場合は BLE_ADDR_TYPE_RANDOM)
または
BLEClient::connect( BLEAdvertisedDevice* device )
のほうで呼ぶ
で解決します。
自分のコードが動いてたのは前述の「advertise callback で device found の時点で BLEClient を作ってしまうようにしたら」の時に「advertise callback は BLEAdvertisedDevice* が解ってるから、こっちの関数で呼ぶかー」ってやってたからで、タイミングの問題じゃなくて呼ぶ関数の問題でした。うーん、気付かない私アホですみません。
まぁこれで解決したってことで!(1.0.2が来たらまた調べる必要あるやつかなーこれ)