インテル様の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についてはここを参照してください
おおまか流れとして、
- レイアウトやボタンの等のIDのくくりつけ
- 端末でBLEが使えるか確認
- BluetoothがONになっているか確認
- 位置情報のパーミッションはOKになっているか
- 接続ボタン(connect_button)を押すとGenuino 101へ接続
- 操作のボタン(left_button, right_button)で0と1を送信している
- 切断ボタン(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とgenuinoをble接続するプログラムを作ることに成功して嬉しみ
— みやかわ (@momijinn_aka) 2017年4月18日
動画はLちかさせてます pic.twitter.com/t8RB1ZYZpS
AndroidでBLEペアリングができるようになったので、Genuino 101以外のマイコンでも接続できると思うので夢が広がります ( ˘ω˘)
コメント