首页 > 代码库 > Bluetooth LE(低功耗蓝牙) - 第五部分
Bluetooth LE(低功耗蓝牙) - 第五部分
回顾:
在本系列前面的文章中我们完成了发现BLE传感器并与之建立连接。现在只剩下从其中获取数据了,但是这并没有看起来那么简单。在这篇文章中我们将讨论GATT的特点以及如何促进主机与传感器之间的数据交换。
GATT服务器的结构:
在前面的文章看我们了解了传感器包含GATT服务器,我们也已经与GATT建立连接。GATT服务器包含一个或多个GATT服务,不同的GATT服务代表了可以进行交换的不同类型的数据。例如,在SensorTag中有不同的GATT服务分别代表着SensorTag中不同的传感器组件(湿度传感器,气压传感器,等)。
每个GATT服务包含一个或多个GATT特性。一个GATT特性是一个可以通过BLE进行传递的原子数据。一个GATT特性可以包含任意的数据,用一个类型标识符表示任意数据的类型。它也可以包含零个或多个GATT描述符。
GATT描述符包含了关于该GATT特性的原子数据,例如GATT特性值的单位,或者当GATT特征值变化时是否需要通知我们。
总之,GATT服务器可以包含一个或多个GATT服务;每个GATT服务可以包含一个或多个GATT特性;每个GATT特性可包含零个或更多个GATT描述符。
GATT服务、特征以及描述符的一个共同点是他们都是使用一个通用唯一标识符(UUID)标识。正如UUID名称所表现的那样,UUID是一个简单且唯的标识符,用来找到GATT服务、特征以及描述符。
SensorTag的UUIDs可在 GATT服务器参考文档 中找到的。这可能有点令人困惑,但它其实是很简单的。所有的SensorTag UUID 都是基于这种形式:F0000000-0451-4000-B000- 00000000。四个黑体字的数字是不同的GATT服务、特征、描述唯一不一样的地方。如果我们看看下面的湿度传感器,我们可以看到其UUID是为AA20(类型为GATT_PRIMARY_SERVICE_UUID)。此服务的完整的UUID是F000AA20-0451-4000-B000-00000000.
服务有两个特征:
第一个代表着实际的传感器数据,UUID为AA21,转换后完整的UUID为 F000AA21-0451-4000-B000- 00000000。这些数据为4个字节,表示的温度和湿度值:TempLSB:TempMSB:HumidityLSB:HumidityMSB 之后我们将看看该如何解码。该特征有一个描述符(GATT_CLIENT_CHAR_CFG_UUID 条目),在文档中不会有该特征的UUID定义。这是因为这是一个标准的UUID,因为它提供一个公共的功能而被共同使用,就是当该值改变时我们需要被通知到。我们将在后面深入讨论这一点。
第二个特征是一个需要我们设置其为打开状态的标志,UUID为AA22,完整的UUID为 F000AA22-0451-4000-B000- 00000000。还是那句话,我们将在适当的时候看到其使用方法。
我们有必要去解释一些关于UUID以及UUID怎么工作的事情,在某些情况下,他们可能不像在SensorTag上那样作为设备的显著的特征。在许多传感器上可能很多服务都拥有一个共同的UUID和结构,不同的厂商都坚持将执行相同的功能的传感器使用一个标准的GATT服务标准(例如有一个专门的心率仪GATT服务标准等)。Also, it is possible to include GATT service UUIDS in the device discovery phase to only match devices which offer specific services. 。不幸的是,SensorTag不支持这个,所以在这篇教程不涉及这一块。如果你有兴趣的话,可以通过调用 BluetoothAdapter#onStartLeScan() 方法的不同形式来实现。
那么,现在我们知道了服务是如何组织的,我们可以开始读取数据了,是吗?不幸的是,它不是那么简单的。记住,与GATT服务器的连接由两部分组成:传感器上的GATT服务器,和一个本地代理。虽然我们可能知道GATT服务,本地代理不知道,所以我们要让本地代理从传感器中获取其服务列表。这个通过使用 discoverservices() 方法实现:
private BluetoothGattCallback mGattCallback = new BluetoothGattCallback() { @Override public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { super.onConnectionStateChange(gatt, status, newState); Log.v(TAG, "Connection State Changed: " + (newState == BluetoothProfile.STATE_CONNECTED ? "Connected" : "Disconnected")); if (newState == BluetoothProfile.STATE_CONNECTED) { setState(State.CONNECTED); gatt.discoverServices(); } else { setState(State.IDLE); } } @Override public void onServicesDiscovered(BluetoothGatt gatt, int status) { if(status == BluetoothGatt.GATT_SUCCESS) { Log.v(TAG, "onServicesDiscovered: " + status); } }}
再次说明,这是一个异步方法,所以我们可以毫无顾虑地在UI线程调用,同时我们需要定义一个合适的回调方法,当服务列表被完整后被调用。比较重要的一点事是要在回调方法中检查状态值,因为有时在搜索服务的过程中会调用相应的回调,但事实上搜索服务已经完成了。所以检查是否为GATT_SUCCESS 状态将确保一旦服务发现完成我们的回调方法只执行一次。
下期预告:
一旦支持的服务被装载到当地的代理,我们就可以访问服务所包含的特征,我们将在本系列文章的总结中讨论这一点。
本文的源代码在这里 可以找到。
-----------------------------------------------------不怎么华丽的分割线----------------------------------------------------------------------
原文链接:http://blog.stylingandroid.com/archives/2526
© 2014, Mark Allison. All rights reserved. This article originally appeared on Styling Android.
Portions of this page are modifications based on work created and shared by Google and used according to terms described in the Creative Commons 3.0 Attribution License
Bluetooth LE(低功耗蓝牙) - 第五部分