LoginSignup
24
28

More than 5 years have passed since last update.

Android で GATT 通信アプリを作ってみる

Posted at

準備

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 の指定を変更します。

変更前

main.cpp
uint16_t customServiceUUID  = 0xA000;
uint16_t readCharUUID       = 0xA001;
uint16_t writeCharUUID      = 0xA002;

変更後

main.cpp
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 に公開してくださっているコードをベースに改造していきます。改造ポイントはこちらになります。

  1. UUID の追加
  2. データ通信ボタンを追加
  3. 独自サービス発見時の処理の追加
  4. GATT 通信切断時の処理の追加
  5. LED ON/OFF ボタンの制御の追加
  6. 受信ボタンの制御の追加

UUID の追加

BleUuid.java で UUID の定義をしているので、BLE Nano と Android 間の通信間に生成した UUID を追加していきます。

BleUuid.java
    // 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 に追加します。

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 で定義しています。

strings.xml
    <string name="ble_nano_read">BLE Nano Read</string>

さらに、追加したボタンのためのコードを DeviceActivity.java に追加しておきます。

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() に、独自サービスを発見したときの処理を追加します。

DeviceActivity.java
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 しているので、追加したボタンの分も追加します。

DeviceActivity.java
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 に送信します。

DeviceActivity.java
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 から返ってきた値を取得して表示します。

DeviceActivity.java
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 が表示されています。

BNENanoLED_ON.PNG

LED ON/OFF ボタンを OFF にして、受信ボタンをクリックしたところ。LEDが消灯し、受信ボタンに 1 が表示されています。

BNENanoLED_OFF.PNG

24
28
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
28