
このマイコンはオンボードで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;
}
}
}
実際に動作しているところ
[tweet http://twitter.com/momijinn\_aka/status/854368958106845184 lang=“ja”]
AndroidでBLEペアリングができるようになったので、Genuino 101以外のマイコンでも接続できると思うので夢が広がります ( ˘ω˘)