2016-04-21

Android BLEのReliableWriteはあまりReliableじゃなかった話

Bluetooth Low Energyの話


Android BLE
みんな大好きBLE。
人は誰しもBLEで長いデータを
送りたくなることがあると思います。

通常のWrite

ある書き込み可能なCharacteristicに対して、
(そこまで長くない)任意のバイト列を
送りつける際は、
BluetoothGatt gatt;
BluetoothGattCharacteristic characteristics;
byte[] data;

characteristic.setValue(data);
gatt.writeCharacteristic(characteristic);
みたいにやってあげれば、その後に
BluetoothGattCallback
onCharacteristicWrite()が呼ばれて、
メデタシメデタシとなる。

20バイト以上のデータ送る

MTUの関係である一定以上の長さのデータを
送る際はすこし厄介な話になる。
もちろんそのままでは送ることはできないので、
以下の2つの方法を検討する必要がある。
  • MTUの値を引き上げる
  • PrepareWrite/ExecuteWriteを使う

MTUを変更する


これは特に問題なく動いている感じ。
BluetoothGatt#requestMtu()をつかって
MTUサイズを変更してあげるやり方。
Android BLE
Peripheralとの通信の部分は詳しくないので、
よく分からずひどいシーケンス図ですが、
MTUサイズ変更後は、それを超えない
データ列であれば、そのままCharacteristicに
setしてWriteできます。

Prepare/Execute Writeをする


今回のメインの愚痴はこれ。
MTUサイズを変更せずに、データ列を分割して
ペリフェラルにWriteを行う方法。
LongWriteとも呼ばれる。
Android的にはbeginReliableWrite()
executeReliableWrite()を使うそうです。
Android BLE
これがまぁ、まともに動かない。
onCharacteristicWrite()が来なかったり、
データ列のオフセット情報がPeripheralに
伝わらなかったりひどい状態でした。
Issue 158619: BLE write long data
IssueTrackerにも挙がっているので、
みんな苦しんでいる様子・・・。
というわけで、MTUを変更して送るほうが吉のようです。

悪夢はここから


ひょんなことから、MTUの変更もせずに、
ReliableWriteも使わずに長いデータ列を
送りつけるとどうなるかやってみたが、
これが酷かった。
Android BLE
こんな感じで、何事もなかったかのように
onCharacteristicWrite()がAPPに飛んでくる。
その裏ではAndroidがせっせと
Prepare/ExecuteWriteを繰り返している…。
ただし、onReliableWriteCompleted()
飛んでこない。
もうね、何なんだろう。
何のためにReliableWriteがAndroidに
存在しているのか本当にわからない。
百歩譲って、ちゃんとWriteできてるんだから、
writeCharacteristic()はtrueを返してほしい。

2 件のコメント:

  1. 勘違いだと思われ。

    beginReliableWrite()、executeReliableWrite() メソッドは複数の characteristic をまとめて write するためのものでは?

    BT 仕様だと
    Core Vol.3, Part G GATT, 4.9.4 Write Long Characteristic ではなく
    4.9.5 Reliable Writes

    返信削除
  2. コメントありがとうございます。
    つまり、LongWriteとは別物なんですね・・・勉強になりました。
    とはいえ、APIをコールしても、リファレンス通りの挙動になっていないのでちょっと気持ち悪いのも事実です。

    返信削除