本記事について
この記事は CoreBluetoothForUnity Advent Calendar 2023 の3日目の記事です。
02_ButtonInformation サンプルの解説をします。
前提
- 前回の記事
- 02_ButtonInformation サンプルを動かすことができること。
環境
- CoreBluetoothForUnity 0.4.3
02_ButtonInformation の概要
02_ButtonInformation は、Peripheral に配置されたボタンの状態を Central に送信するサンプルです。
SampleButtonInformation_PeripheralScene
ボタンが6つ配置されており、それぞれのボタンが以下のように登録されています。
それぞれのボタンのインデックス + 1 が id となるような仕様にしています。
例: A のインデックスは4なため、id は5。
SampleButtonInformation_CentralScene
送られてきたデータによって画面中央の Cube..(1)と右下のテキスト..(2)を更新しています。
上下左右 -> Cube が上下移動
AB -> Cube の拡大・縮小
01_LightControl との違い
サンプル | データの読み書きの方向 | 名称 |
---|---|---|
01_LightControl | Central -> Peripheral | Write |
02_ButtonInformation | Peripheral -> Central | Notify |
Write と Notify は書き方が全然違います。
本記事では Notify の書き方を解説します。
Service, Characteristic の作成 (Peripheral)
var service = new CBMutableService(SampleButtonInformation_Data.ServiceUUID, true);
_buttonInformationCharacteristic = new CBMutableCharacteristic(
SampleButtonInformation_Data.ButtonInformationCharacteristicUUID,
CBCharacteristicProperties.Read | CBCharacteristicProperties.Notify,
null,
CBAttributePermissions.Readable
);
Service の作成は特に変わりません。
Peripheral -> Central とデータを送信するために、今回は Characteristic の権限に Notify を追加しています。
(Read については権限追加していますが、本記事では使いません。)
Notify できるように設定
SetNotifyValue (Central)
void ICBPeripheralDelegate.DidDiscoverCharacteristics(CBPeripheral peripheral, CBService service, CBError error)
{
...
foreach (var characteristic in service.Characteristics)
{
if (characteristic.UUID.Equals(SampleButtonInformation_Data.ButtonInformationCharacteristicUUID))
{
if (characteristic.Properties.HasFlag(CBCharacteristicProperties.Notify))
{
peripheral.SetNotifyValue(true, characteristic);
}
}
}
}
Characteristic に Notify 権限がある場合、SetNotifyValue の引数 enabled に true を渡すことで Notify が有効になります。
この処理を 「Characteristic のデータを購読する」(Subscribe)と言います。
Characteristic のデータが購読されたことを検知 (Peripheral)
Central がデータを購読すると Peripheral 側では以下の処理が呼ばれます。
void ICBPeripheralManagerDelegate.DidSubscribeToCharacteristic(CBPeripheralManager peripheral, CBCentral central, CBCharacteristic characteristic)
{
if (_peripheralManager.IsAdvertising)
{
peripheral.StopAdvertising();
}
_stateLabel.text = "Connected";
_central = central;
}
これによってどの Central が Peripheral を購読しているかを検知することができます。
Peripheral では Central から接続されることで呼び出されるイベントはないため、DidSubscribeToCharacteristic は接続されたことを把握する方法でもあります。
サンプルでは電池の消費を抑えるために、Peripheral が Central に接続されたらアドバタイズを停止しています。
Peripheral から Central へデータを送信 (Peripheral)
void OnButtonDown(int buttonID)
{
if (_central == null)
{
return;
}
var data = SampleButtonInformation_Data.GetButtonInformation(buttonID, true);
_peripheralManager.UpdateValue(data, _buttonInformationCharacteristic, new CBCentral[] { _central });
}
/// <summary>
/// Convert button information to byte array.
/// This data format is same as toio button information.
/// https://toio.github.io/toio-spec/en/docs/ble_button#read-operations
/// </summary>
/// <param name="isPressed"></param>
/// <returns></returns>
public static byte[] GetButtonInformation(int buttonId, bool isPressed)
{
byte[] buff = new byte[2];
buff[0] = BitConverter.GetBytes(Mathf.Clamp(buttonId, 0, 255))[0];
buff[1] = (byte)(isPressed ? 0x80 : 0x00);
return buff;
}
Peripheral から Central へデータを送信するには、UpdateValue を使います。
送信対象を指定するために、第3引数に CBCentral[] を渡します。
Central でデータを受信
DidUpdateValueForCharacteristic でデータを受信します。
void ICBPeripheralDelegate.DidUpdateValueForCharacteristic(CBPeripheral peripheral, CBCharacteristic characteristic, CBError error)
{
if (error != null)
{
Debug.LogError($"[DidUpdateValue] error: {error}");
return;
}
if (SampleButtonInformation_Data.ParseButtonInformation(characteristic.Value, out int buttonId, out bool isPressed))
{
_log.AppendLog(buttonId, isPressed);
_cube.Action(buttonId, isPressed);
}
}
Notify は Peripheral -> Central の一方通行なため、返答する必要はありません。
おわりに
本記事では、02_ButtonInformation サンプルを通して Notify の使い方を解説しました。
Write よりも Notify のほうが使う機会多いと思いますので、ぜひ参考にしてください!