Procedure

Genuino 101とAndroidをBLE接続する

Procedure
この記事は約22分で読めます。
スポンサーリンク

インテル様のCPUが搭載しているGenuino 101を遊びで使っています

このマイコンはオンボードでBLEや6軸センサーが内蔵しています

昨年ぐらいにこのマイコンを使ってBLE通信を試みたのですが、知識不足だったこともあり通信ができませんでした・・・

 

しかし、もう一度挑戦してみた所無事にBLE通信ができたので書き留めておきます

 

 

スポンサーリンク

Genuino 101側

はじめにGenuino 101のプログラムを色々といじります

基本はサンプルプログラムであるCurlBLE->LEDを参考にしています

いじった内容は受け取る文字で、Genuino 101はバイト型でデータを受け取るらしいです

Android側でバイト型に変換して送信しようとしてもうまく行かなかったので、Genuino 101のほうで無理やり合わせることにしました

下記のプログラムをGenuino 101へ書き込んでください

/*
 * Copyright (c) 2016 Intel Corporation.  All rights reserved.
 * See the bottom of this file for the license terms.
 */

#include <CurieBLE.h>

BLEPeripheral blePeripheral;  // BLE Peripheral Device (the board you're programming)
BLEService ledService("19B10000-E8F2-537E-4F6C-D104768A1214"); // BLE LED Service

// BLE LED Switch Characteristic - custom 128-bit UUID, read and writable by central
BLEUnsignedCharCharacteristic switchCharacteristic("19B10001-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite);

const int ledPin = 13; // pin to use for the LED

void setup() {
  Serial.begin(9600);

  // set LED pin to output mode
  pinMode(ledPin, OUTPUT);

  // set advertised local name and service UUID:
  blePeripheral.setLocalName("LED");
  blePeripheral.setAdvertisedServiceUuid(ledService.uuid());

  // add service and characteristic:
  blePeripheral.addAttribute(ledService);
  blePeripheral.addAttribute(switchCharacteristic);

  // set the initial value for the characeristic:
  switchCharacteristic.setValue(0);

  // begin advertising BLE service:
  blePeripheral.begin();

  Serial.println("BLE LED Peripheral");
}

void loop() {
  // listen for BLE peripherals to connect:
  BLECentral central = blePeripheral.central();

  // if a central is connected to peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's MAC address:
    Serial.println(central.address());

    // while the central is still connected to peripheral:
    while (central.connected()) {
      // if the remote device wrote to the characteristic,
      // use the value to control the LED:
      if (switchCharacteristic.written()) {
        //ココらへんを編集
        Serial.println(switchCharacteristic.value()); //debug用
        if (switchCharacteristic.value() == 48) { //android側は"0"を送信している
          Serial.println("LED on");
          digitalWrite(ledPin, HIGH);         // will turn the LED on
        } 
        else if(switchCharacteristic.value() == 49) {//android側は"1"を送信している
          Serial.println(F("LED off"));
          digitalWrite(ledPin, LOW);          // will turn the LED off
        }
      }
    }

    // when the central disconnects, print it out:
    Serial.print(F("Disconnected from central: "));
    Serial.println(central.address());
  }
}

 

Android側

Android側のプログラムは結構な量なのでポイントだけ記述します(全てのプログラムはGitHubに上げます)

 

はじめにAndroidManifest.xmlの編集です

bleのスキャニングには位置情報も必要です

<!-- permission -->
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
<uses-feature android:name="android.hardware.bluetooth_le" android:required="true"/>

<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<!-- android 5.0以上の場合は必要 -->
<uses-feature android:name="android.hardware.location.gps" />

 

MainActivity.javaの編集

パーミッションの設定やマテリアルデザインのSnackBar等を入れています

SnackBarについてはここを参照してください

 

おおまか流れとして、

  1. レイアウトやボタンの等のIDのくくりつけ
  2. 端末でBLEが使えるか確認
  3. BluetoothがONになっているか確認
  4. 位置情報のパーミッションはOKになっているか
  5. 接続ボタン(connect_button)を押すとGenuino 101へ接続
  6. 操作のボタン(left_button, right_button)で0と1を送信している
  7. 切断ボタン(disconnect_button)を押すとGenuino 101を切断

という流れになっています

 

GATTがなんなのかがわかればなんとかなる?と思います

また、昨年の私もドツボにはまったのですが、Bluetoothのペアリングからの通信とBLEのペアリングからの通信は全く違うので注意が必要です

public class MainActivity extends AppCompatActivity implements View.OnClickListener{
    private static final int REQUEST_ENABLE_BT = 1;
    private static final int REQUEST_CODE_LOCATE_PERMISSION = 5;
    //UUID系
    private static String GENUINOMACADDRESS = "11:11:11:11:11:11"; //Genuino 101のBLEアドレス
    private static String LEDSERVICEUUID = "19B10000-E8F2-537E-4F6C-D104768A1214"; //custom service
    private static String CHARACTERISTICUUID = "19B10001-E8F2-537E-4F6C-D104768A1214"; //charactersticuuid

    //devicelevel
    private final static int SDKVER_LOLLIPOP = 21;

    //BLE
    private BluetoothAdapter mBluetoothAdapter;
    private BluetoothGatt mBleGatt;
    private BluetoothLeScanner mBluetoothLeScanner;
    private BluetoothGattCharacteristic mBluetoothGattCharacteristic;
    private boolean mIsBluetoothEnable = false; //接続判定

    //いろいろ
    private Button connect_button, disconnect_button, right_button, left_buton;
    private RelativeLayout layout;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        /**
         * 初期化
         */
        //button
        connect_button = (Button)findViewById(R.id.connect_button);
        connect_button.setOnClickListener(this);

        disconnect_button = (Button)findViewById(R.id.disconnect_button);
        disconnect_button.setOnClickListener(this);

        right_button = (Button)findViewById(R.id.right_button);
        right_button.setOnClickListener(this);

        left_buton = (Button)findViewById(R.id.left_button);
        left_buton.setOnClickListener(this);

        //relytive
        layout = (RelativeLayout) findViewById(R.id.relativeLayout);

        //BLEがサポートしているかの確認
        if(!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)){
            Snackbar.make(layout,  R.string.ble_not_supported, Snackbar.LENGTH_LONG).show();
            finish();
        }

        //bluetoothがONになっているか確認
        final BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

        if(mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()){
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        }

        //permisstion
        if(PermissionChecker.checkSelfPermission(MainActivity.this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED){
            requestLocatePermission();
            return;
        }

    }

    /**
     * 位置情報のpermisstion
     */
    private void requestLocatePermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this, Manifest.permission.ACCESS_FINE_LOCATION)) {
            new AlertDialog.Builder(this)
                    .setTitle("パーミッションの追加説明")
                    .setMessage("このアプリを使うには位置情報の許可が必要です")
                    .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            ActivityCompat.requestPermissions(MainActivity.this,
                                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                                    REQUEST_CODE_LOCATE_PERMISSION);
                        }
                    })
                    .create()
                    .show();
            return;
        }
        ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, REQUEST_CODE_LOCATE_PERMISSION);
        return;
    }


    /**
     * デバイスの検索(LOLIPOP以上の時)
     */
    private void scanLeDevice(){
        if(Build.VERSION.SDK_INT >= SDKVER_LOLLIPOP){
            //LOLIOPOP以上の処理
            this.scanLeDeviceLolipop();
        }else{
            mBluetoothAdapter.startLeScan(mScanCallback);
        }

    }
    @TargetApi(SDKVER_LOLLIPOP)
    private void scanLeDeviceLolipop() {
        mBluetoothLeScanner = mBluetoothAdapter.getBluetoothLeScanner();

        //デバイスの検出
        mBluetoothLeScanner.startScan(new ScanCallback() {
            @Override
            public void onScanResult(int callbackType, ScanResult result) {
                super.onScanResult(callbackType, result);

                //genoinoに接続 MACアドレスの比較
                if(result.getDevice().toString().equals(GENUINOMACADDRESS)){
                    result.getDevice().connectGatt(getApplicationContext(), false, mGattCallback);
                }
            }

            @Override
            public void onScanFailed(int errorCode) {
                super.onScanFailed(errorCode);
            }
        });
    }


    /**
     * デバイスの検索(LOLIPOP以下の処理)
     */
    private final BluetoothAdapter.LeScanCallback mScanCallback = new BluetoothAdapter.LeScanCallback(){
        @Override
        public void onLeScan(BluetoothDevice device, int rssi, byte[] scanRecord) {
            mBleGatt = device.connectGatt(getApplicationContext(), false, mGattCallback);

        }
    };

    /**
     * GATTへ接続
     */
    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback(){
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState){
            if (newState == BluetoothProfile.STATE_CONNECTED) {
                // 接続できたらサービスの検索
                gatt.discoverServices();
            }else if(newState == BluetoothProfile.STATE_DISCONNECTED){
                //接続が切れたらGATTを空にする
                if(mBleGatt != null){
                    mBleGatt.close();
                    mBleGatt = null;
                }
                mIsBluetoothEnable = false;
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status){
            //Serviceがあれば実行
            if (status == BluetoothGatt.GATT_SUCCESS) {
                //UUIDの突き合わせ
                BluetoothGattService service = gatt.getService(UUID.fromString(LEDSERVICEUUID));

                if(service != null){
                    //charastaticseの突き合わせ
                    mBluetoothGattCharacteristic = service.getCharacteristic(UUID.fromString(CHARACTERISTICUUID));

                    if(mBluetoothGattCharacteristic != null){
                        //LEDとCHARAが一緒ならgattの更新
                        mBleGatt = gatt;

                        Snackbar.make(layout, "接続しました", Snackbar.LENGTH_LONG).show();
                        //ペアリング完了のフラッグ
                        mIsBluetoothEnable = true;
                    }
                }
            }

        }
    };

    /**
     * Buttonの処理
     * @param v
     */
    @Override
    public void onClick(View v) {
        switch (v.getId()){
            case R.id.connect_button:
                if(mIsBluetoothEnable == false) scanLeDevice();
                else Snackbar.make(layout, "接続済みです", Snackbar.LENGTH_SHORT).show();
                break;

            case R.id.disconnect_button:
                if(mIsBluetoothEnable == true){
                    mBleGatt.close();
                    mBleGatt = null;
                    mIsBluetoothEnable = false;
                    Snackbar.make(layout, "切断しました", Snackbar.LENGTH_SHORT).show();
                } else Snackbar.make(layout, "切断しています", Snackbar.LENGTH_SHORT).show();
                break;


            case R.id.right_button:
                if(mIsBluetoothEnable == true){
                    mBluetoothGattCharacteristic.setValue("1"); //"1"という文字列を送信
                    mBleGatt.writeCharacteristic(mBluetoothGattCharacteristic);
                }else{
                    Snackbar.make(layout, "接続してください", Snackbar.LENGTH_SHORT).show();
                }
                break;

            case R.id.left_button:
                if(mIsBluetoothEnable == true){
                    mBluetoothGattCharacteristic.setValue("0"); //"0"という文字列を送信
                    mBleGatt.writeCharacteristic(mBluetoothGattCharacteristic);
                }else{
                    Snackbar.make(layout, "接続してください", Snackbar.LENGTH_SHORT).show();
                }
                break;
        }
    }
}

 

実際に動作しているところ

 

AndroidでBLEペアリングができるようになったので、Genuino 101以外のマイコンでも接続できると思うので夢が広がります ( ˘ω˘)

 

参考文献

コメント

タイトルとURLをコピーしました