Brilloのbluetoothtbdとbluetooth-cliを読む

Brilloのbluetoothtbd とbluetooth-cli についてちょっと調べてみました。

BrilloではAndroid由来のBluetoothプロトコルスタック Fluoride (system/bt)を採用しています。

ただし、AndroidとはAPIが異なります。
AndroidではAndroid Bluetooth HAL(libhardware)をwrapper経由 (core/java/android/bluetooth/)で使っていますが、
Brilloではcppで実装したBinder APIを用います。

# ソース
* https://android.googlesource.com/platform/system/bt/+/master/service/main.cc
* https://android.googlesource.com/platform/system/bt/+/master/service/common/android/bluetooth
* https://android.googlesource.com/platform/system/bt/+/master/service/client/main.cc


# bluetoothtbd
* Brilloではbluetoothtbdというデーモンがbluetoothプロトコルスタックの本体です。
* bluetoothtbdのメインのソースは service/main.cc にあります。 このソースでプロトコルスタックのメインループを起動しています。

```cpp:main.cc
  if (!bluetooth::Daemon::Initialize()) {
    LOG(ERROR) << "Failed to initialize Daemon";
    return EXIT_FAILURE;
  }
  // Start the main event loop.
  bluetooth::Daemon::Get()->StartMainLoop();
```

# Brilloのbluetooth API
* APIは、service/common/android/bluetooth のAIDLからヘッダファイルを生成して使います。
* Bluetoothの起動・停止などを行うIBluetooth.aidl

```c:IBluetooth.aidl
package android.bluetooth;
import android.bluetooth.IBluetoothCallback;
import android.bluetooth.IBluetoothLowEnergy;
import android.bluetooth.IBluetoothGattClient;
import android.bluetooth.IBluetoothGattServer;
import android.bluetooth.UUID;
interface IBluetooth {
  boolean IsEnabled();
  int GetState();
  boolean Enable(boolean startRestricted);
  boolean EnableNoAutoConnect();
  boolean Disable();
  String GetAddress();
  UUID[] GetUUIDs();
  boolean SetName(String name);
  String GetName();
  void RegisterCallback(IBluetoothCallback callback);
  void UnregisterCallback(IBluetoothCallback callback);
  boolean IsMultiAdvertisementSupported();
  IBluetoothLowEnergy GetLowEnergyInterface();
  IBluetoothGattClient GetGattClientInterface();
  IBluetoothGattServer GetGattServerInterface();
}
```
* binder APIの実装は https://android.googlesource.com/platform/system/bt/+log/master/service/ipc/binder にあります。

# bluetooth-cli
* APIのサンプルとして、bluetooh-cli というツールが提供されています。
* bluetooth-cli のソースは service/client/main.cc にあります。
* 現時点ではBLEのアドバタイズ、BLEの接続などをコマンドで行うことができます。

```
# bluetooth-cli                                                                                                                                                                                                   
Fluoride Command-Line Interface

Type "help" to see possible commands.

[FCLI] help

	help			Display this message
	disable			Disable Bluetooth
	enable			Enable Bluetooth
	get-state		Get the current adapter state
	is-enabled		Return if Bluetooth is enabled
	get-local-address	Get the local adapter address
	set-local-name		Set the local adapter name
	get-local-name		Get the local adapter name
	adapter-info		Print adapter properties
	supports-multi-adv	Whether multi-advertisement is currently supported
	register-ble		Register with the Bluetooth Low Energy interface
	unregister-ble		Unregister from the Bluetooth Low Energy interface
	unregister-all-ble	Unregister all clients from the Bluetooth Low Energy interface
	register-gatt		Register with the Bluetooth GATT Client interface
	unregister-gatt		Unregister from the Bluetooth GATT Client interface
	connect-le		Connect to LE device (-h for options)
	disconnect-le		Disconnect LE device (-h for options)
	set-mtu		Set MTU (-h for options)
	start-adv		Start advertising (-h for options)
	stop-adv		Stop advertising
	start-le-scan		Start LE device scan (-h for options)
	stop-le-scan		Stop LE device scan
```

* ソースコードを少し見てみました。
* bt_ifaceの取得

```cpp
  sp<IBluetooth> bt_iface;
  status_t status = getService(String16(kServiceName.c_str()), &bt_iface);
```

* コールバックの登録

```cpp
  // Register Adapter state-change callback
  sp<CLIBluetoothCallback> callback = new CLIBluetoothCallback();
  bt_iface->RegisterCallback(callback);
```

* Bluetooth起動

```
  bool status;
  bt_iface->Enable(is_restricted_mode, &status);
```

* BDアドレスの取得

```cpp
  String16 address;
  bt_iface->GetAddress(&address);
  PrintFieldAndValue("\tAddress", std::string(String8(address).string()));
```

* アドバタイズの開始

```cpp
  base::TimeDelta timeout;
  bluetooth::AdvertiseSettings settings(
      bluetooth::AdvertiseSettings::MODE_LOW_POWER, timeout,
      bluetooth::AdvertiseSettings::TX_POWER_LEVEL_MEDIUM, connectable);
  bluetooth::AdvertiseData adv_data(data);
  adv_data.set_include_device_name(include_name);
  adv_data.set_include_tx_power_level(include_tx_power);
  bluetooth::AdvertiseData scan_rsp;
  bool status;
  ble_iface->StartMultiAdvertising(ble_client_id.load(), adv_data, scan_rsp,
                                   settings, &status);
```

* Android Bluetooth HALに比べて、callbackがclass化されているので見通しが良くなっている気がします。
* Brilloが正式にリリースされる際には、BluetoothのBinder APIがドキュメント化されるのを期待します。