BLE 总结

来源:互联网 发布:易建联的雄鹿赛季知乎 编辑:程序博客网 时间:2024/05/24 03:54
一:BLE相关概念概述
1:相关概念
Generic Attribute Profile (GATT)
通过BLE连接,读写属性类小数据的Profile通用规范。现在所有的BLE应用Profile都是基于GATT的。

Attribute Protocol (ATT)
GATT是基于ATT Protocol的。ATT针对BLE设备做了专门的优化,具体就是在传输过程中使用尽量少的数据。每个属性都有一个唯一的UUID,属性将以characteristics and services的形式传输。

Characteristic
Characteristic可以理解为一个数据类型,它包括一个value和0至多个对次value的描述(Descriptor)。

Descriptor
对Characteristic的描述,例如范围、计量单位等。

Service
Characteristic的集合。例如一个service叫做“Heart Rate Monitor”,它可能包含多个Characteristics,其中可能包含一个叫做“heart rate measurement"的Characteristic。

2:相关原理图
周围设备模型:

关于 BLE (Bluetooth Low Energy) 之Central 与 peripheral都用支持BLE的手机如何实现 - 龚东东 - gdd330282的博客


二:应用层框架层重要内容介绍
周围设备中的介绍:
1相关的类
BluetoothManager.java
BluetoothAdapter.java
BluetoothGattServer.java
BluetoothGatt.java
BluetoothGattService.java
BluetoothGattCharacteristic.java
BluetoothGattDescriptor.java
上述类位于frameworks/base/core/java/src/android/bluetooth/

BluetoothLeAdvertiser.java

AdvertiseSettings.java
上面的类设置Advertise时候的参数,构造方法私有,需要通过公开的Builder类来构造这个类的实例

AdvertiseData.java
上面的类设置Advertise时候的相关数据,构造方法私有,需要通过公开的Builder类来构造这个类的实例

上述类位于frameworks/base/core/java/src/android/bluetooth/le

2重要的方法
public BluetoothGattServer openGattServer(
Context context,BluetoothGattServerCallback callback)
获取GattServer实例

BluetoothGattService的构造方法
public BluetoothGattService(UUID uuid, int serviceType)
serviceType服务类型可以有BluetoothGattService.SERVICE_TYPE_PRIMARY和
BluetoothGattService.SERVICE_TYPE_SECONDARY

BluetoothGattCharacteristic的构造方法参数介绍
public BluetoothGattCharacteristic(UUID uuid, int properties, int permissions)
uuid Characteristic的唯一标识符
properties Characteristic的属性详细数据见BluetoothGattCharacteristic类开头
permissions Characteristic所支持的权限比如可读可写0x11同样在类开头有英文介绍

BluetoothGattDescriptor的构造方法参数介绍
public BluetoothGattDescriptor(UUID uuid, int permissions)
同Characteristic在类的开头也有英文介绍。

public void startAdvertising(AdvertiseSettings settings,
AdvertiseData advertiseData, final AdvertiseCallback callback)
发送让中心设备获取自己信息的方法

BluetoothGattServerCallback中的相关方法的介绍:
方法都是异步的方法,因此在回调中不要写大量的工作
public void onConnectionStateChange(BluetoothDevice device, int status,
int newState)
当连接状态发生变化的时候的回调,比如连接和断开的时候都会回调
参数说明
device 产生回调的远端设备引用
status 回调的时候的状态信息
newState 进入的新的状态的信息

public void onServiceAdded(int status, BluetoothGattService service) {
}
当服务添加到Server中时的回调
status 添加服务的状态信息,成功还是失败
service 添加的服务的引用

public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,int offset, BluetoothGattCharacteristic characteristic)
当有服务请求读 characteristic的时候
device发请求的远端设备引用
requestId 请求Id
offset 偏移量
characteristic被请求的 characteristic

public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded,int offset, byte[] value)
characteristic 需要写的 characteristic
preparedWrite 是不是需要保存到队列之后执行写入操作的
responseNeeded 需不需要返回数据的
value 需要写的数据

public void onDescriptorReadRequest(BluetoothDevice device,int requestId, int offset, BluetoothGattDescriptor descriptor)
类似characteristic的读

public void onDescriptorWriteRequest(BluetoothDevice device,int requestId, BluetoothGattDescriptor descriptor,boolean preparedWrite, boolean responseNeeded, int offset,byte[] value)
类似characteristic的写
public void onExecuteWrite(BluetoothDevice device, int requestId,boolean execute)
执行将保存到队列中的数据写入到characteristic的回调

public void onNotificationSent(BluetoothDevice device, int status)
会回调当有服务端的数据传送到客户端的时候

BluetoothGattServer中一些方法的说明
public boolean connect(BluetoothDevice device, boolean autoConnect)
连接远端蓝牙设备

public void cancelConnection(BluetoothDevice device)
断开和远端设备的连接

public boolean sendResponse(BluetoothDevice device, int requestId,int status, int offset, byte[] value)
当远端设备需要读或者写的时候,本读需要发送一个回应

public boolean notifyCharacteristicChanged(BluetoothDevice device,BluetoothGattCharacteristic characteristic, boolean confirm)
设置提醒Characteristic改变的提醒,同时可以设置Characteristic,会产生远端设备的某个回调

客户端中某些方法介绍
BluetoothAdapter中的方法
由于扫描设备是能源集中型的方法需要谨慎使用适时的停止。
public boolean startLeScan(LeScanCallback callback)
开始扫描设备
public void stopLeScan(LeScanCallback callback)
停止扫描设备

BluetoothDevice中的方法
public BluetoothGatt connectGatt(Context context, boolean autoConnect,BluetoothGattCallback callback)
连接周围设备,返回BluetoothGatt对象

BluetoothGatt中的方法
public void disconnect()
用完了之后需要断开连接

public boolean discoverServices()
发现服务的请求

public List<BluetoothGattService> getServices()
获取当前连接的周围设备上的服务的请求

public boolean readCharacteristic(BluetoothGattCharacteristic characteristic)
发起对某个 characteristic的读请求

public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic)
发起对某个characteristic的写请求

public boolean readDescriptor(BluetoothGattDescriptor descriptor)
类似characteristic

public boolean writeDescriptor(BluetoothGattDescriptor descriptor)
类似characteristic

public boolean beginReliableWrite()
开始可靠的characteristic写的请求,所有characteristic的写请求都会保存在gattServer中的队列中,直到有executeReliableWrite()执行,中途可以检验某个之是不是已经正确写入,同时可以调用public void abortReliableWrite()来终止这次可靠写characteristic请求,所有从开始的数据都不会写入到characteristic中

public boolean executeReliableWrite()
执行可靠写数据的请求

public void abortReliableWrite()
放弃可靠写请求

public boolean readRemoteRssi()
读取当前的Rssi的值

public boolean setCharacteristicNotification(BluetoothGattCharacteristic characteristic,boolean enable)
发起对某个characteristic改变的提醒, 通过enable参数来设置开启和关闭

BluetoothGattCallback中的某些方法的介绍与ServerCallback类似是异步的所以需要注意
public void onConnectionStateChange(BluetoothGatt gatt, int status,int newState)
请求连接之后的回调, status返回的状态成功与否, newState提示新的状态

public void onServicesDiscovered(BluetoothGatt gatt, int status)
服务发现之后的回调

public void onCharacteristicRead(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status)
请求 characteristic读之后的回调

public void onCharacteristicWrite(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic, int status)
请求characteristic写之后的回调

public void onCharacteristicChanged(BluetoothGatt gatt,BluetoothGattCharacteristic characteristic)
characteristic属性改变之后的回调

public void onDescriptorRead(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status)
类似characteristic

public void onDescriptorWrite(BluetoothGatt gatt,BluetoothGattDescriptor descriptor, int status)
类似characteristic

public void onReliableWriteCompleted(BluetoothGatt gatt, int status)
可靠写完成之后的回调

public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status)
读远端Rssi请求之后的回调

public void onMtuChanged(BluetoothGatt gatt, int mtu, int status)
请求MTU改变之后的回调

3重要的接口

BluetoothAdapter.LeScanCallback
当有搜索结果的时候回调

4重要的抽象类
BluetoothGattServerCallback.java
上面的回调类服务的回调都写在这个抽象类中,需要扩展下,实现更加具体的逻辑。

BluetoothGattCallback.java
上面的回调类的回调是中心设备的具体回调,需要扩展下,实现更加具体的逻辑。

位于frameworks/base/core/java/src/android/bluetooth/

AdvertiseCallback
上面的回调类发送自身信息完成后的回调,会返回发送的结果和实际发送的信息

位于frameworks/base/core/java/src/android/bluetooth/le

三:实现例子
周围端的实现的例子:
步骤一:获取BluetoothGattServer的实例
例子如下:
mBluetoothManager=(BluetoothManager)getSystemService(Context.BLUETOOTH_SERVICE);
gattServer = mBluetoothManager.openGattServer(this, mCallback);
步骤二:添加gattServer中的service,characteristic和descriptor
例子如下:
gattService = new BluetoothGattService(SERVICE_UUID,BluetoothGattService.SERVICE_TYPE_PRIMARY);
BluetoothGattCharacteristic characteristic = new BluetoothGattCharacteristic(CHARACTERISTIC_UUID, 0x0A, 0x11);
BluetoothGattDescriptor descriptor = new BluetoothGattDescriptor(DESCRIPTOR_UUID, 0x11);
descriptor.setValue("gdd test".getBytes());
characteristic.addDescriptor(descriptor);
characteristic.setValue("the characteristic".getBytes());
BluetoothGattCharacteristic characteristicUpdating = new BluetoothGattCharacteristic(CHARACTERISTIC_UUID_UPDATING, 0x0A, 0x11);
gattService.addCharacteristic(characteristic);
gattService.addCharacteristic(characteristicUpdating);
gattServer.addService(gattService);
步骤三:实现mCallback的功能
需要具体化的方法罗列如下:
public void onConnectionStateChange(BluetoothDevice device, int status,
int newState) {
}
public void onServiceAdded(int status, BluetoothGattService service) {
}
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId,
int offset, BluetoothGattCharacteristic characteristic) {
}
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId,
BluetoothGattCharacteristic characteristic,
boolean preparedWrite, boolean responseNeeded,
int offset, byte[] value) {
}
public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
BluetoothGattDescriptor descriptor,
boolean preparedWrite, boolean responseNeeded,
int offset,  byte[] value) {
}
public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) {
}
public void onNotificationSent(BluetoothDevice device, int status) {
}
步骤四:让中心设备可以发现我们的设备
例子如下:
adapter = mBluetoothManager.getAdapter();
leAdvertiser = adapter.getBluetoothLeAdvertiser();
leAdvertiser.startAdvertising(
new AdvertiseSettings.Builder().build(),
new AdvertiseData.Builder()
.addServiceUuid(new ParcelUuid(SERVICE_UUID))
.addManufacturerData(1, "1".getBytes())
.setIncludeDeviceName(true)
.addServiceData(new ParcelUuid(SERVICE_UUID),
"1".getBytes()).build(),
new AdvertiseCallback() {
@Override
public void onStartSuccess(
AdvertiseSettings settingsInEffect) {
Log.d(TAG,
"AdvertiseCallbackImpl->onStartSuccess is being invoked!!!");
Log.d(TAG, "SETTING MODE:" + settingsInEffect.getMode());
Log.d(TAG,
"SETTING TIMEOUT:"
+ settingsInEffect.getTimeout());
Log.d(TAG,
"SETTING TxPowerLevel:"
+ settingsInEffect.getTxPowerLevel());
}

@Override
public void onStartFailure(int errorCode) {
Log.d(TAG,
"AdvertiseCallbackImpl->onStartFailure is being invoked!!!");
Log.d(TAG, "errorCode is :" + errorCode);
}
});
到此gattServer的设置完成,开始等待中心设备连接

中心设备的实例的例子:
步骤一:搜索到周围设备
例子如下:
开始搜索的代码入下:
private void startScanning() {
Log.d(TAG, "startScanning");
mLeDeviceListAdapter.clear();
mLeDeviceListAdapter.notifyDataSetChanged();
// Stops scanning after a pre-defined scan period.
mHandler.postDelayed(new Runnable() {
@Override
public void run() {
isScanning = false;
mBluetoothAdapter.stopLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
}, SCAN_PERIOD);

isScanning = true;
mBluetoothAdapter.startLeScan(mLeScanCallback);
invalidateOptionsMenu();
}
mLeScanCallback 的代码如下:
// Device scan callback.
private BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {

@Override
public void onLeScan(final BluetoothDevice device, int rssi,
byte[] scanRecord) {
Log.d("gdd debug", device.getAddress() + "  rssi:" + rssi
+ "scanRecord:" + scanRecord.toString());
runOnUiThread(new Runnable() {
@Override
public void run() {
mLeDeviceListAdapter.addDevice(device);
mLeDeviceListAdapter.notifyDataSetChanged();
}
});
}
};
步骤二:通过回调来的设备信息,进行连接周围设备
例子如下:
private boolean connect(final String address) {
if (mBluetoothAdapter == null || address == null) {
Log.w(TAG, "BluetoothAdapter not initialized or unspecified address.");
return false;
}

final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
if (device == null) {
Log.w(TAG, "Device not found.  Unable to connect.");
return false;
}
// We want to directly connect to the device, so we are setting the autoConnect
// parameter to false.
mBluetoothGatt = device.connectGatt(this, false, mGattCallback);
showLOG("Connecting to " + address);
Log.d(TAG, "Trying to create a new connection.");
return true;
}
步骤三:通过的mBluetoothGatt 请求方法异步调用mGattCallback中的回调
通过以上代码大致可以写出周围设备和中心设备实现gatt通讯的例子
四 : 总结和展望
总结本次BLE设备通讯的学习:
在这次学习中深入了关于TL给出的要求,然后对蓝牙GATT PROFILE 的认识更加深入,但是仅仅还只是在java代码的层面上对这些内容进行了总结,并没有对GattServic中相关内容做分析,需要继续学习,可能还需要对JNI部分的代码进行一定的分析,所以还需要深入对GATT 通讯过程中的流程做更进一步的分析。

继续总结
关于对网上一些说法的看法,首先是关于对蓝牙通讯的安全性问题的分析,由于蓝牙服务和数据获取UUID的方便性,就目前代码貌似是无法完成安全要求的。因此,我觉得这一问题,可能会成为一个比较重要的问题。
然后是关于和其他的平台的对比的问题
Zigbee的自组网技术也可以实现和蓝牙类似的功能,并且是一个强有力的竞争对手。但是鉴于蓝牙的低功耗,还是有一定的优势的。
wifi mesh也可以实现室内定位等功能。

基于这次学习做展望:
对于蓝牙,前段时间有智能穿戴设备搞的风风火火,现在蓝牙用到智能家庭中的想法也是可以预想的。

0 0