準備
Android の BLE GATT 通信サンプル・コードの入手
Android で GATT 通信アプリをスクラッチから作るのは大変そうなので、参考になりそうなのを探しました。
まずは、Android SDK 本家のサンプルを見てみたんですが、複雑で characteristics の write がないため断念。
こちらのサイトがわかりやすかったので、こちらを参考にさせていただきました。
AndroidのBLEでCharacteristicsのRead/Writeサンプルを作ってみた
UUIDの生成
BLE の GATT 通信をするためには、サービスやキャラクタリスティックというものが必要となります。
このあたりの詳しいことは、こちらのサイトにまとまっていますので、こちらをご覧ください。
BLE のサービスやキャラクタリスティックには、その種類を識別するための UUID が定義されています。
よく見かける 16bit の UUID は Bluetooth の SIG で規定されているものであり、独自のサービスを作る場合は 128bit の UUID を使うことになるようです。
作りたい BLE Nano と Android 間の通信は、独自のデータのやり取りなので、独自のサービスとして定義していきたいと思います。
そこで、Online UUID Generatorのサイトを利用して 128bit の UUID をランダム生成しました。
種類 | UUID |
---|---|
Custom Service | ff1ecf59-513e-4aa6-9db0-490a63ebb1ac |
read characteristics | e3274236-89fa-4ac6-bd1c-4fe77ecdd331 |
write characteristics | d0dbb034-75a1-4cc4-8b59-1bce1ba6adc5 |
BLE Nano 側の service / characteristics 設定
以前の記事で作成したコードの UUID の指定を変更します。
変更前
uint16_t customServiceUUID = 0xA000;
uint16_t readCharUUID = 0xA001;
uint16_t writeCharUUID = 0xA002;
変更後
static uint8_t customServiceUUID[16] = {0xff, 0x1e, 0xcf, 0x59, 0x51, 0x3e, 0x4a, 0xa6, 0x9d, 0xb0, 0x49, 0x0a, 0x63, 0xeb, 0xb1, 0xac};
static uint8_t readCharUUID[16] = {0xe3, 0x27, 0x42, 0x36, 0x89, 0xfa, 0x4a, 0xc6, 0xbd, 0x1c, 0x4f, 0xe7, 0x7e, 0xcd, 0xd3, 0x31};
static uint8_t writeCharUUID[16] = {0xd0, 0xdb, 0xb0, 0x34, 0x75, 0xa1, 0x4c, 0xc4, 0x8b, 0x59, 0x1b, 0xce, 0x1b, 0xa6, 0xad, 0xc5};
コンパイルしてバイナリを BLE Nano に書き込んだら BLE Nano 側は完了です。
Android GATT 通信サンプル・コードの改造
AndroidのBLEでCharacteristicsのRead/Writeサンプルを作ってみた で、github に公開してくださっているコードをベースに改造していきます。改造ポイントはこちらになります。
- UUID の追加
- データ通信ボタンを追加
- 独自サービス発見時の処理の追加
- GATT 通信切断時の処理の追加
- LED ON/OFF ボタンの制御の追加
- 受信ボタンの制御の追加
UUID の追加
BleUuid.java で UUID の定義をしているので、BLE Nano と Android 間の通信間に生成した UUID を追加していきます。
// BLE Nano Custom Service
public static final String SERVICE_BLENANO_CUSTOM = "ff1ecf59-513e-4aa6-9db0-490a63ebb1ac";
public static final String CHAR_CUSTOM_SERVICE_READ = "e3274236-89fa-4ac6-bd1c-4fe77ecdd331";
public static final String CHAR_CUSTOM_SERVICE_WRITE = "d0dbb034-75a1-4cc4-8b59-1bce1ba6adc5";
データ通信ボタンの追加
BLE Nano との通信を行なうためのボタンを、app/res/layout/activity_device.xml に追加します。
<ToggleButton
android:id="@+id/blenano_led_onoff_button"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<Button
android:id="@+id/blenano_read"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/ble_nano_read" />
LED の ON/OFF を制御する ToggleButton と、BLE Nano から返ってくる characteristics を受信する Button をそれぞれ追加しています。
表示する文字列は res/values/strings.xml で定義しています。
<string name="ble_nano_read">BLE Nano Read</string>
さらに、追加したボタンのためのコードを DeviceActivity.java に追加しておきます。
public class DeviceActivity extends Activity implements View.OnClickListener {
private ToggleButton mWriteBleNanoLedOnOffButton;
private Button mReadBleNanoButton;
:
protected void onCreate(Bundle savedInstanceState) {
:
mWriteBleNanoLedOnOffButton = (ToggleButton) findViewById(R.id.blenano_led_onoff_button);
mWriteBleNanoLedOnOffButton.setOnClickListener(this);
mReadBleNanoButton = (Button) findViewById(R.id.blenano_read);
mReadBleNanoButton.setOnClickListener(this);
}
private void init() {
:
mWriteBleNanoLedOnOffButton.setEnabled(false);
mReadBleNanoButton.setEnabled(false);
:
}
追加したボタンを制御するための変数の定義と初期化コードになります。
独自サービス発見時の処理の追加
DeviceActivity.java の onServicesDiscovered() に、独自サービスを発見したときの処理を追加します。
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
:
if (BleUuid.SERVICE_BLENANO_CUSTOM.equalsIgnoreCase(service.getUuid().toString())) {
runOnUiThread(new Runnable() {
public void run() {
mWriteBleNanoLedOnOffButton.setEnabled(true);
mReadBleNanoButton.setEnabled(true);
};
});
mWriteBleNanoLedOnOffButton.setTag(service.getCharacteristic(UUID.fromString(BleUuid.CHAR_CUSTOM_SERVICE_WRITE)));
mReadBleNanoButton.setTag(service.getCharacteristic(UUID.fromString(BleUuid.CHAR_CUSTOM_SERVICE_READ)));
}
:
}
setEnabled(true) で追加したボタンを Enable にし、setTag を使って独自サービスの Characteristic をボタンに対応付けています。
GATT 通信切断時の処理を追加
GATT 通信の状態が変化したときに実行する onConnectionStateChange というコールバックがサンプルの中で定義されています。
ここで、GATT 通信が切断されたときに各ボタンを Disable しているので、追加したボタンの分も追加します。
private final BluetoothGattCallback mGattcallback = new BluetoothGattCallback() {
:
mWriteBleNanoLedOnOffButton.setEnabled(false);
mReadBleNanoButton.setEnabled(false);
:
}
LED ON/OFF ボタンの制御の追加
ボタンが押されたときに呼ばれる onClick 関数に、LED ON/OFF の Toggle Button の処理を追加します。
Toggle Button が checked の状態の場合はLEDを点灯させるための値 0x00
を、そうでない場合は消灯させるための値 0x01
を data に格納します。
そして、タグ付けしておいた Characteristic を使って、data を BNE Nano に送信します。
public void onClick(View v) {
:
} else if (v.getId() == R.id.blenano_led_onoff_button) {
byte[] data = (mWriteBleNanoLedOnOffButton.isChecked())? new byte[] {(byte) 0x00} : new byte[] {(byte) 0x01};
if ((v.getTag() != null) && (v.getTag() instanceof BluetoothGattCharacteristic)) {
BluetoothGattCharacteristic ch = (BluetoothGattCharacteristic) v.getTag();
ch.setValue(data);
if (mConnGatt.writeCharacteristic(ch)) {
setProgressBarIndeterminateVisibility(true);
}
}
}
}
受信ボタンの制御の追加
BLE Nano に信号を送信すると、BLE Nano は送信した値をそのまま返してきます。
blenano_read ボタンで、BLE Nano から返ってきた値を取得して表示します。
public void onClick(View v) {
:
} else if (v.getId() == R.id.blenano_read) {
if ((v.getTag() != null) && (v.getTag() instanceof BluetoothGattCharacteristic)) {
BluetoothGattCharacteristic ch = (BluetoothGattCharacteristic) v.getTag();
if (mConnGatt.readCharacteristic(ch)) {
setProgressBarIndeterminateVisibility(true);
}
}
}
}
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
if (status == BluetoothGatt.GATT_SUCCESS) {
if (BleUuid.CHAR_MANUFACTURER_NAME_STRING.equalsIgnoreCase(characteristic.getUuid().toString())) {
:
} else if (BleUuid.CHAR_CUSTOM_SERVICE_READ.equalsIgnoreCase(characteristic.getUuid().toString())) {
final byte[] val = characteristic.getValue();
runOnUiThread(new Runnable() {
public void run() {
ReadBleNanoButton.setText(getString(R.string.ble_nano_read)+":"+val[0]);
setProgressBarIndeterminateVisibility(false);
};
});
}
}
受信ボタンのクリックを検知すると、タグ付けしておいた Characteristic を使って BLE Nano からデータを読み出します。
そして、読み出しが完了すると実行される onCharacteristicRead 関数で、読み出したデータ val を受信ボタンに表示していきます。
動作例
LED ON/OFF ボタンを ON にして、受信ボタンをクリックしたところ。LEDが点灯し、受信ボタンに 0 が表示されています。
LED ON/OFF ボタンを OFF にして、受信ボタンをクリックしたところ。LEDが消灯し、受信ボタンに 1 が表示されています。