Android BLE Bluetooth通信学習
30240 ワード
Android BLE Bluetooth通信学習
紹介するの利点:消費電力がより低く、接続速度がより速い 欠点:送信ごとのデータが比較的小さい AndroidとBLE
いくつかの概念
ATT
GATT
services
サービスは、
characteristics
フィーチャー.各サービスには複数のフィーチャーが含まれ、フィーチャーには有用な値と権限が格納されます.ここで、Bluetoothモジュールと
descriptor
フィーチャーの記述は、記述子とも呼ばれ、1つのフィーチャーに複数の記述子があります.
Notification
通知、
BLE透伝
透過モードでは、すべてのシリアルポートデータがユーザーデータと見なされ、モジュールはこれらのデータをBluetoothモジュールと携帯電話または他の制御装置との間の通信(実際には別のコマンドモードがあるが、透過モードはより迅速で簡単である)にホストに送信します.透過モードは、
役割と役割
センタ装置(
Android使用
権限の準備
BLEの準備取得 判断 スキャンデバイスの開始:
デバイスの接続
前にリンクしたので、最初にトリガーされたコールバックは
上記のコードでは、接続に成功した後に
前述の説明から分かるように、
上のコードの山は、取得したサービスと特徴を1つのリストで示すことが重要ではありません.前の
通知が設定された後、
前述の説明からBluetoothの透過は
リード操作は、コールバック関数onCharacteristicRead()をトリガーします.
同様に、読み取りがある以上、書き込み操作も可能であり、書き込み操作は以下のようにして、コールバック関数
書き込みに成功し、透過モジュールに応答がある場合、一般的な応答方式は通知によって行われる.だから普通はプロジェクトの中でリンクが成功した后に通知の権限を开いて、省の后ろに书く时忘れます.これで,携帯電話と
もちろん、これは簡単に通信が完了しただけで、本当に使うときはパケットサイズの制限でパケット転送、受信など、完璧な点がたくさんあります.
app
アプリケーションの開発過程では、一般的にBluetoothと接触することは多くありませんが、スマートウェアラブルデバイスの発展に伴い、ウェアラブルデバイスと携帯電話に関連するapp
がますます多くなり、これまであまり接触したことがなく、ちょうど最近Bluetoothに関連するapp
を作る必要があるので、研究学習の下で、アプリケーションのものをまとめてみましょう.プロジェクトのソースコードはgithubにアップロードされました.紹介する
BLE
は、Bluetooth Low Energy
の略であり、Bluetooth 3.0と従来の技術とは異なるBluetooth 4.0とも呼ばれる.BLE
の前身はNOKIA
が開発したWibree
技術で、主にモバイルスマート端末と周辺部品との間の持続的な接続を実現するために用いられ、消費電力が極めて低い短距離無線通信技術であり、有効伝送距離は100メートル以上に引き上げられ、同時に1本のボタン電池だけで数年働くことができる.BLE
は、Bluetooth技術に基づいて発展し、Bluetoothと同様であり、従来のBluetoothとは異なる.BLE
設備は単型と二型の2種類に分けられ、二型はBR
、商標はBluetooth Smart Ready
、単型はBLEまたはLE、商標はBluetooth Smart
である.Android
は4.3後にBLE
をサポートしたが、これはすべてのBluetooth携帯電話がBLE
をサポートしているわけではなく、BLE
をサポートしているBluetooth携帯電話が一般的にデュアルモードであることを説明することができる.BLE
と通常のBluetoothには違いがあります.いくつかの概念
ATT
ATT
(Attribute Protocol)プロトコルはベースプロトコルであり、ATT
はBLE
デバイスに対して特に最適化され、そのベースは属性であり、UUID
を使用して属性のタイプを定義する.GATT
GATT
(Generic Attribute Profile)は、BLE
のすべての最上位プロトコルの基礎であり、ATT
の属性をどのようにグループ化して有意義なサービスにするかを定義しています.services
サービスは、
UUID
の値が0 x 2800のプロパティに基づいています.このプロパティの後に続くすべてのプロパティは、別の0 x 2800プロパティが現れるまで、このプロパティ定義のサービスに属します.1つのBLE
デバイスは、複数のサービスを提供することができる.characteristics
フィーチャー.各サービスには複数のフィーチャーが含まれ、フィーチャーには有用な値と権限が格納されます.ここで、Bluetoothモジュールと
app
との通信は、主にそれによって行われる.descriptor
フィーチャーの記述は、記述子とも呼ばれ、1つのフィーチャーに複数の記述子があります.
GATT
プロトコルは、ほとんどの標準記述子を定義しており、特に重要な記述子の1つは、client characteristic configuration
であり、そのUUID
は0 x 2902であり、16 bitの読み書き可能な値を有する.通知と暗示を定義するために使用され、設定によってデバイスに通知を送信させ、ホスト側に受信させることができる.Notification
通知、
BLE
モジュールは、ホスト側のBluetoothモジュールによって受信できるメッセージを空中に送信する.characteristics
に含まれていますが、権限を開く必要があります.BLE透伝
透過モードでは、すべてのシリアルポートデータがユーザーデータと見なされ、モジュールはこれらのデータをBluetoothモジュールと携帯電話または他の制御装置との間の通信(実際には別のコマンドモードがあるが、透過モードはより迅速で簡単である)にホストに送信します.透過モードは、
services
およびcharacteristics
によって行われる.一般的なメーカーまたはエンジニアは、次の図のような説明をします.役割と役割
Android
デバイスとBLE
デバイスのインタラクションには、2つのロールがあります.センタ装置(
Central
)および周辺装置(Periphery
).周辺機器はデータプロバイダであり,中央はデータ使用/処理者である.1つの中央装置は複数の周辺装置を同時に接続することができるが、1つの周辺装置は同時に1つの中央装置しか接続できない.Android使用
権限の準備
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
BLEの準備
BluetoothAdapter
: BluetoothManager bluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
bluetoothAdapter = bluetoothManager.getAdapter();
//
if (!bluetoothAdapter.isEnabled()) {
bluetoothAdapter.enable();
}
//
Intent enabler = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enabler, REQUEST_ENABLE);
BLE
: private boolean checkBluetooth() {
if (!getPackageManager().hasSystemFeature(
PackageManager.FEATURE_BLUETOOTH_LE)) {
return false;
}
return true;
}
bluetoothAdapter.startLeScan(mLeScanCallback);
BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
runOnUiThread(new Runnable() {
@Override
public void run() {
/*
, BLEDeviceTestActivity
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_NAME, device.getName());
intent.putExtra(DeviceControlActivity.EXTRAS_DEVICE_ADDRESS, device.getAddress());
*/
adapter.add("name : " + device.getName() + "
address : " + device.getAddress());
bluetoothDevices.add(device);
}
});
}
};
デバイスの接続
BLEDeviceTestActivity
でデバイスを取得し、デバイスを接続します.//
BluetoothDevice device = bluetoothAdapter.getRemoteDevice(addressStr);
// BluetoothGattCallback
BluetoothGatt bluetoothGatt = device.connectGatt(this, false, bluetoothGattCallback);
device.connectGatt(this, false, bluetoothGattCallback);
方法については、デバイスによってGATT
リンクが確立されていることがわかり、GATT
リンクに関する操作はコールバックをトリガーします.BluetoothGattCallback
は、これらのコールバック結果を非同期で処理します. /**
* Connect to GATT Server hosted by this device. Caller acts as GATT client.
* The callback is used to deliver results to Caller, such as connection status as well
* as any further GATT client operations.
* The method returns a BluetoothGatt instance. You can use BluetoothGatt to conduct
* GATT client operations.
* @param callback GATT callback handler that will receive asynchronous callbacks.
* @param autoConnect Whether to directly connect to the remote device (false)
* or to automatically connect as soon as the remote
* device becomes available (true).
* @throws IllegalArgumentException if callback is null
*/
public BluetoothGatt connectGatt(Context context, boolean autoConnect,
BluetoothGattCallback callback) {
return (connectGatt(context, autoConnect,callback, TRANSPORT_AUTO));
}
bluetoothGattCallback
を実現しました BluetoothGattCallback bluetoothGattCallback = new BluetoothGattCallback() {
/**
*
* @param gatt
* @param status {@link BluetoothGatt#GATT_SUCCESS}
* @param newState {@link BluetoothProfile#STATE_DISCONNECTED} or
* {@link BluetoothProfile#STATE_CONNECTED}
*/
@Override
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
}
/**
* GATT
* @param gatt
* @param status {@link BluetoothGatt#GATT_SUCCESS}
*/
@Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
}
/**
*
* @param gatt
* @param characteristic
* @param status
*/
@Override
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
}
/**
*
* @param gatt
* @param characteristic
* @param status
*/
@Override
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
}
/**
*
* @param gatt
* @param characteristic
*/
@Override
public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
}
/**
*
* @param gatt
* @param descriptor
* @param status
*/
@Override
public void onDescriptorRead(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorRead(gatt, descriptor, status);
}
/**
*
* @param gatt
* @param descriptor
* @param status
*/
@Override
public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
super.onDescriptorWrite(gatt, descriptor, status);
}
/**
*
* @param gatt
* @param status
*/
@Override
public void onReliableWriteCompleted(BluetoothGatt gatt, int status) {
super.onReliableWriteCompleted(gatt, status);
}
@Override
public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) {
super.onReadRemoteRssi(gatt, rssi, status);
}
@Override
public void onMtuChanged(BluetoothGatt gatt, int mtu, int status) {
super.onMtuChanged(gatt, mtu, status);
}
};
BluetoothGattCallback
には多くの方法が見られ、名前によってその意味が分かりにくくなく、Bluetoothの使用過程に基づいて一つ一つ分析すればその機能が明らかになります.前にリンクしたので、最初にトリガーされたコールバックは
onConnectionStateChange()
メソッドです.
/**
*
* @param gatt
* @param status {@link BluetoothGatt#GATT_SUCCESS}
* @param newState {@link BluetoothProfile#STATE_DISCONNECTED} or
* {@link BluetoothProfile#STATE_CONNECTED}
newState
*/
public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
super.onConnectionStateChange(gatt, status, newState);
if (newState == BluetoothProfile.STATE_CONNECTED) {
// UI , hanlder Eventbus
runOnUiThread(new Runnable() {
@Override
public void run() {
connectTv.setText(" ");
}
});
//
gatt.discoverServices();
} else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
//
runOnUiThread(new Runnable() {
@Override
public void run() {
connectTv.setText(" ");
}
});
}
}
上記のコードでは、接続に成功した後に
gatt.discoverServices();
メソッドが呼び出され、このメソッドは、リモートデバイスが提供するサービス、およびそれらに含まれる特徴的特性および記述子などを発見するために使用されることが分かった.前述の説明から分かるように、
app
とBluetoothモジュールを通信するには、これらのサービスや特徴などが必要です.この方法はコールバックonServicesDiscovered()
をトリガーします. @Override
public void onServicesDiscovered(BluetoothGatt gatt, int status) {
super.onServicesDiscovered(gatt, status);
if (BluetoothGatt.GATT_SUCCESS == status) {
gatt.getServices();
/*
GATT BluetoothGattService , UUID BluetoothGatt ;
GATT BluetoothGattCharacteristic , UUID BluetoothGattService ;
, value 0~n value (BluetoothGattDescriptor)
GATT BluetoothGattDescriptor , UUID BluetoothGattCharacteristic :
, Characteristic , 、
*/
gattCharacteristicList.clear();
String uuid = null;
ArrayList> gattServiceData = new ArrayList>();
ArrayList>> gattCharacteristicData = new ArrayList>>();
//
for (BluetoothGattService gattService : gatt.getServices()) {
HashMap currentServiceData = new HashMap();
uuid = gattService.getUuid().toString();
currentServiceData.put("name",
SampleGattAttributes.lookup(uuid, " "));
currentServiceData.put("uuid", uuid);
gattServiceData.add(currentServiceData);
ArrayList> gattCharacteristicGroupData = new ArrayList>();
List gattCharacteristics = gattService
.getCharacteristics();
ArrayList charas = new ArrayList();
//
for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
charas.add(gattCharacteristic);
HashMap currentCharaData = new HashMap();
uuid = gattCharacteristic.getUuid().toString();
currentCharaData.put("name",
SampleGattAttributes.lookup(uuid, " "));
currentCharaData.put("uuid", uuid);
// UUID 0000ff02-0000-1000-8000-00805f9b34fb BLE
if (uuid.equals("0000ff02-0000-1000-8000-00805f9b34fb")) {
setCharacteristicNotification(gattCharacteristic, true);
}
gattCharacteristicGroupData.add(currentCharaData);
}
gattCharacteristicList.add(charas);
gattCharacteristicData.add(gattCharacteristicGroupData);
}
//
final SimpleExpandableListAdapter gattServiceAdapter = new SimpleExpandableListAdapter(
BLEDeviceTestActivity.this, gattServiceData,
android.R.layout.simple_expandable_list_item_2, new String[]{
"name", "uuid"}, new int[]{android.R.id.text1,
android.R.id.text2}, gattCharacteristicData,
android.R.layout.simple_expandable_list_item_2, new String[]{
"name", "uuid"}, new int[]{android.R.id.text1,
android.R.id.text2});
runOnUiThread(new Runnable() {
@Override
public void run() {
listView.setAdapter(gattServiceAdapter);
}
});
}
}
上のコードの山は、取得したサービスと特徴を1つのリストで示すことが重要ではありません.前の
characteristic
の説明によると、0 xff 02の先頭の特徴値が通知可能であるため、次のコードがあります. if (uuid.equals("0000ff02-0000-1000-8000-00805f9b34fb")) {
setCharacteristicNotification(gattCharacteristic, true);
}
setCharacteristicNotification()
メソッドは、指定されたフィーチャーの通知権限を有効にすることです.ここは小さな穴に穴をあけられて、bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
だと思っていた.true
を設定すれば十分ですが、デバッグ時に通知を受信できないことに気づき、資料を調べてみたら、ディスクリプタに通知権限を設定して有効にする必要があることがわかりましたが、具体的にどのディスクリプタが分からないので、最後にBluetoothモジュールメーカーから送られてきたdemoに基づいて逆コンパイルし、そのソースコードを見てから対応するUUID
を知りました.さらに、この記述子が発見されたUUID
は0 x 2902で始まることから、この記述子はGATT
プロトコルで書かれた死んだ記述子であるべきであると推測される.
public static String CLIENT_CHARACTERISTIC_CONFIG = "00002902-0000-1000-8000-00805f9b34fb";
public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {
//
bluetoothGatt.setCharacteristicNotification(characteristic, enabled);
//
BluetoothGattDescriptor descriptor = characteristic.getDescriptor(UUID
.fromString(CLIENT_CHARACTERISTIC_CONFIG));
if (descriptor != null) {
System.out.println("write descriptor");
descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
bluetoothGatt.writeDescriptor(descriptor);
}
}
通知が設定された後、
BLE
デバイスが通知によってデータを送信すると、app
エンドが通知を受信するとonCharacteristicChanged()
メソッドがトリガーされ、このメソッドは、BLE
モジュールがブロードキャスト形式で返されることを受信するために使用することができる. public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicChanged(gatt, characteristic);
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(BLEDeviceTestActivity.this, " ", Toast.LENGTH_SHORT).show();
}
});
//
final byte[] data = characteristic.getValue();
if (data != null && data.length > 0) {
final StringBuilder stringBuilder = new StringBuilder(
data.length);
StringBuffer test = new StringBuffer();
for (byte byteChar : data) {
test.append(byteChar);
stringBuilder.append(String.format("%02X ", byteChar));// 16 0
}
runOnUiThread(new Runnable() {
@Override
public void run() {
//
dataTv.setText(new String(data) + "
"
+ stringBuilder.toString());
}
});
}
}
前述の説明からBluetoothの透過は
characteristics
で行われていることが分かるので、もちろん読み書きの操作もありますが、操作を行う前にサービスのUUIDを判断する必要があります.characteristic.getUuid()
に従ってUUID
を得るか、またはUUID
を知っている場合に、対応する特徴をアクティブに取得して操作することができる.リード操作は、コールバック関数onCharacteristicRead()をトリガーします.
//
bluetoothGatt.readCharacteristic(characteristic);
//
public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicRead(gatt, characteristic, status);
// characteristic , characteristic.getValue(); 。 。
if (BluetoothGatt.GATT_SUCCESS == status) {
final byte[] data = characteristic.getValue();
...
//
}
}
同様に、読み取りがある以上、書き込み操作も可能であり、書き込み操作は以下のようにして、コールバック関数
onCharacteristicWrite()
をトリガーする. //
characteristic.setValue(byte[] value);
bluetoothGatt.writeCharacteristic(characteristic);
// ,
public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
super.onCharacteristicWrite(gatt, characteristic, status);
if (BluetoothGatt.GATT_SUCCESS == status) {
Log.d("BLEDeviceTestActivity", " ");
runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(BLEDeviceTestActivity.this, " ", Toast.LENGTH_SHORT).show();
}
});
}
書き込みに成功し、透過モジュールに応答がある場合、一般的な応答方式は通知によって行われる.だから普通はプロジェクトの中でリンクが成功した后に通知の権限を开いて、省の后ろに书く时忘れます.これで,携帯電話と
BLE
モジュール間の通信はほぼ完了し,他の書き込み記述子のこれらのコールバック過程は大きく異なる.もちろん、これは簡単に通信が完了しただけで、本当に使うときはパケットサイズの制限でパケット転送、受信など、完璧な点がたくさんあります.