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 状态将确保一旦服务发现完成我们的回调方法只执行一次。
下期预告:
一旦支持的服务被装载到当地的代理,我们就可以访问服务所包含的特征,我们将在本系列文章的总结中讨论这一点。
本文的源代码在这里 可以找到。
Bluetooth LE(低功耗蓝牙) - 第五部分的更多相关文章
- Bluetooth LE(低功耗蓝牙) - 第一部分
前言 在写这篇文章的时候,谷歌刚刚发布了Android Wear ,摩托罗拉也发布了 Moto 360 智能手表.Android Wear的API还是相当基本的,是很好的文档材料,而且还会不断的更新, ...
- Bluetooth LE(低功耗蓝牙) - 第三部分
回顾 在本系列的前两篇文章中,我们已经了解了一些关于Bluetooth LE的背景并建立一个简单的Activity / Service框架. 在这篇文章中,我们将探讨Bluetooth LE的细节 ...
- Bluetooth LE(低功耗蓝牙) - 第二部分
回顾 在前面的文章中我们介绍了Bluetooth LE的背景也说明了我们在本系列文章中将要开发什么,但是还没有实际的代码.我们将在这篇文章中纠正这一点,我们将通过定义 Service/Activity ...
- Bluetooth LE(低功耗蓝牙) - 第四部分
回顾 在本系列前几篇文章中我们完成了BLE设备的发现 , 为我们的app通过BLE显示从TI SensorTag设备中获取到环境温度和湿度的工作打下了基础.在这篇文章中我们将着眼于连接到我们所发现的S ...
- Bluetooth LE(低功耗蓝牙) - 第六部分(完)
在本系列前面的文章中我们已经了解了,在我们从一个TI SensorTag中获取温度和湿度数据之前,我们需要经历的各种步骤.在本系列中的最后一篇文章,我们将完成注册并接收SensorTag的通知,并接收 ...
- Android BLE与终端通信(五)——Google API BLE4.0低功耗蓝牙文档解读之案例初探
Android BLE与终端通信(五)--Google API BLE4.0低功耗蓝牙文档解读之案例初探 算下来很久没有写BLE的博文了,上家的技术都快忘记了,所以赶紧读了一遍Google的API顺便 ...
- Bluetooth Low Energy——蓝牙低功耗
Android4.3(API级别18)引入内置平台支持BLE的central角色,同时提供API和app应用程序用来发现设备,查询服务,和读/写characteristics.与传统蓝牙(Classi ...
- Android使用BLE(低功耗蓝牙,Bluetooth Low Energy)
背景 在学习BLE的过程中,积累了一些心得的DEMO,放到Github,形成本文.感兴趣的同学可以下载到源代码. github: https://github.com/vir56k/bluetooth ...
- 低功耗之战!ANT VS Bluetooth LE
利用近距离无线通信技术将手机及可穿戴式传感器终端等与智能电话连接起来,实现新的功能.最近,以此为目标的行动正在展开.其中备受关注的近距离无线方式是“ANT”和“Bluetooth LE”.为了在各种便 ...
随机推荐
- Linux bash常用测试判断选项
bash编程中if [ ]后面的测试选项: 1.整数测试: -le less equal -lt less than -ge greater equal -gt greater than -eq ...
- jquery刷新iframe页面的方法
1,reload 方法,该方法强迫浏览器刷新当前页面. 语法:location.reload([bForceGet]) 参数: bForceGet, 可选参数, 默认为 false,从客户端缓存里取当 ...
- 【锋利的jQuery】学习笔记01
第一章 认识jQuery 一.常见的JS库 Prototype 最早的js库之一.把好用JS方法组合,缺点结构松散. Dojo 离线存储API.生成图标组件.矢量图形库.Comet支持.企业级JS库, ...
- Bootstarp--全局CSS样式之表格
表格在实际开发中可以说是非常常见的,但是有很多人不喜欢使用表格,但个人觉得在简单的界面布局中使用表格还是很简单的.毕竟人家给了表格这元素,而你却不去使用,貌似有点不解风情. 下面简单介绍Bootstr ...
- NHibernate动态加载资源文件
最近做项目,又用到了以前做过的ORM框架--NHibernate. 此次想要实现的目标: 1.简单SQL用NHibernate的Session的CRUD方法实现 2.复杂SQL用Native SQL实 ...
- Windows Socket五种I/O模型
转载:http://www.cnblogs.com/tianzhiliang/archive/2010/08/31/1813637.html 如果你想在Windows平台上构建服务器应用,那么I/O模 ...
- Error parsing XML: not well-formed (invalid token)
从网络上或别的文件复制粘贴进来的代码有隐含格式,可将内容先粘贴进记事本清除格式,再复制粘贴进工程文件,即可解决此问题 注:1. 要使工程文件全选清空, 2. 若粘贴后刷新仍无效果,可手动输入
- linux ssh rsa免输入密码
A为本地主机(即用于控制其他主机的机器) ; B为远程主机(即被控制的机器Server), 假如ip为172.24.253.2 ; 在A上的命令: ssh-keygen -t rsa (连续三 ...
- MSSQL存储过程(好久的笔记,翻出来怀念下)
语法结构: create proc 名称 参数列表 as 代码段 调用: exec 存储过程名称 参数列表 要点: .可以使用output修饰参数 .可以使用默认值,注意需要将最后的参数设置成默认值 ...
- Oracle 的merge into 用法
1.merge into的用途 Merge是一个非常有用的功能,与DB2中的merge into功能几乎一样,与Mysql里的insert into on duplicate key也很类似.MERG ...