Android中的蓝牙
说到Android中的蓝牙,大家听到的可能有蓝牙1.0、蓝牙2.0、蓝牙3.0、蓝牙4.0之类的以数字结尾的蓝牙版本号,而实际上,在最新的标准中,已经不再使用数字版本号作为蓝牙版本的区分了,取而代之的是经典蓝牙与低功耗蓝牙(BLE)这两种区别。
这里提到的低功耗蓝牙也会有很多人会误解为就是蓝牙4.0,但是完整的蓝牙4.0规范中实际上包括有经典蓝牙和低功耗蓝牙这两个部分,大家看看如下这张分类表就能够明白这其中的关系了。
如表中所述,现在的蓝牙实际上分为了三类:单模、双模和经典。那么,最官方的蓝牙版本称呼就是,单模蓝牙、双模蓝牙和经典蓝牙。
在这其中,最前沿的当属单模蓝牙了,也就是低功耗蓝牙。这个蓝牙标准和经典蓝牙区别极大,在最初甚至考虑过加入WIFI阵营,但是因为蓝牙阵营这边条件较为优厚(比如授权费用极低)才并入了蓝牙标准。
那么,低功耗蓝牙和经典蓝牙的区别究竟在哪里呢?
要是仅仅从两者的通信方式上来说,可以说除了名字叫蓝牙外,完全可以当做两个东西。不过,两者在总体上的流程却也是相似的,那就是:
发现设备->配对/绑定设备->建立连接->数据通信
经典蓝牙和低功耗蓝牙除了配对/绑定这个环节是一样的之外,其它三个环节都是不同的。
1. 发现设备
经典蓝牙:经典蓝牙设备发现其它经典蓝牙设备的方式是调用BluetoothAdapter的startDiscovery()方法。
api上说的比较模糊,大致是说只能够发现经典蓝牙设备。
请点击输入图片描述
然而实验发现 BluetoothAdapter.startDiscovery是可以同时发现经典蓝牙和ble的
低功耗蓝牙:低功耗蓝牙中则有一个主设备(Central)和从设备(Peripheral,也叫外围设备)的概念。主设备作为发现方,调用发现设备的方法,通过BluetoothAdapter的startLeScan()方法实现。从设备则作为被发现方,发出广播,以供发现。同样,这个startLeScan()方法也仅能够发现低功耗蓝牙从设备。
总结:BluetoothAdapter.startDiscovery在大多数手机上是可以同时发现经典蓝牙和Ble的,但是startDiscovery的回调无法返回Ble的广播,所以无法通过广播识别设备,且startDiscovery扫描Ble的效率比StartLeScan低很多。所以在实际应用中,还是StartDiscovery和StartLeScan分开扫,前者扫传统蓝牙,后者扫低功耗蓝牙。
注意:当两种蓝牙设备被某设备(包括当前的设备)配对/绑定后,可能不会再被扫描到。
2. 配对/绑定
有很多小伙伴都不太理解配对和绑定究竟有什么区别,或者它们根本就是同一个东西。好吧,严格说配对和绑定是有区别的,也就是不是指的同一件事情。但是这两者的区别比较模糊,也不好解释。目前JACK的机器人的理解是,配对是建立两者的对应关系,而绑定则把这层关系保存固定下来并进行了强化,暂时这么理解着吧。
不管是经典蓝牙还是低功耗蓝牙,绑定方法都是通用的,可以调用相同的绑定方法。
3. 建立连接
在建立连接的方式上,两者就千差万别了。
——蓝牙小知识——
在蓝牙设备中,存在着物理地址,我们也叫作蓝牙的MAC地址,这个地址是唯一的,就像咱们网络上的IP地址。同时还存在着一个叫做UUID的东西,可以把它理解为是IP地址中的端口号。正如知道了IP地址和端口号,就知道了怎么链接到目标网络服务器位置,知道了蓝牙设备的MAC地址和UUID也就能够确定到具体是哪一台蓝牙设备了,这两者合起来就是蓝牙的唯一身份标识。
经典蓝牙:经典蓝牙建立连接的方式实际上就是Socket的连接的建立。只不过这里不是直接用Socket,而是BluetoothSocket。获取BluetoothSocket的方式也很简单,利用搜索找到的BluetoothDevice,调用其方法createRfcommSocketToServiceRecord(UUID)。最后,使用获取到的BluetoothDevice调用其方法connect()就建立了经典蓝牙设备之间的连接通道。
低功耗蓝牙:低功耗蓝牙则用了一种看起来比较怪异的方式建立连接。
——关于BLE的一些基本概念——
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。
这里举个例子,例如现在需要使用一个智能手机作为主设备去连接一个作为从设备的智能手环,那么,此时这个作为主设备的智能手机连接过程中实际是一个客户端(Client),而作为从设备的智能手环在此过程中则是服务端(Server)。这里的主设备和从设备,客户端和服务端一定要区分清楚。
想要和一台BLE从设备建立连接,一般是某个智能设备,例如智能手环、智能灯泡之类的。如果使用智能手机作为测试平台,其硬件条件是,蓝牙得至少是低功耗蓝牙版本,然后安卓系统的话,至少得是Android 4.3以上系统才行,因为Google在Android 4.3以上才做了BLE主设备的支持,如果想将智能手机作为BLE从设备,则必须在Android 5.0以上才行。
具体建立GATT连接的顺序则是,首先通过BluetoothAdapter的getRemoteDevice(address)方法获取大相应BLE从设备的BluetoothDevice,其中的address为目标蓝牙设备MAC地址。然后通过此BluetoothDevice的connectGatt(this, false, mGattCallback)方法获取设备连接。
此时的连接,只能够进行监听,也就是获取到当前BLE从设备广播出来的数据。
4. 数据通信
经典蓝牙:当建立连接后,就可以直接使用BluetoothSocket的getOutputStream()方法获取输出流写入需要发送的数据。读取发送回来的数据,则是调用BluetoothSocket的getInputStream()方法获取输入流读取。这点和Java中的Socket通信几乎是一模一样。
低功耗蓝牙:想要实现主设备对从设备的数据发送,则需要直接读取获取到的从设备的Characteristic,而Characteristic又是Service下面的一层,所以 *** 作顺序是:
(1)通过BLE从设备相应的Service_UUID获取对应的BluetoothGattService,获取方法是:使用BluetoothDevice的connectGatt(this, false, mGattCallback)方法返回的BluetoothGatt对象,调用BluetoothGatt的方法getService(Service_UUID)获取相应的BluetoothGattService;
(2)调用BluetoothGattService和对应的Characteristic的写入UUID获取相应的BluetoothGattCharacteristic,获取方法是:调用BluetoothGattService的getCharacteristic(Characteristic_UUID)方法获得;
(3)设置需要发送的命令值,调用BluetoothGattCharacteristic的方法setValue(value)进行设置,其中value一般为byte[];
(4)最后,使用BluetoothGatt的写入方法writeCharacteristic(TxChar)完成命令发送。
可以看到,想要实现BLE的数据通信,步骤相当繁琐,这里只是做一个简单的概念理解,如果想要获取到BLE从设备的返回值,还需要设置Notification,然后调用BluetoothGatt的readCharacteristic(characteristic)方法进行数据的读取,这里不做详细说明了,放在以后详细说明BLE通信的时候再做解释。
蓝牙的选用
既然有经典蓝牙和低功耗蓝牙之分,我们在设计物联网产品和智能硬件产品的时候,如何选择呢?
经典蓝牙:蓝牙最初的设计意图,是打电话放音乐。3.0版本以下的蓝牙,都称为“经典蓝牙”。功耗高、传输数据量大、传输距离只有10米。
低功耗蓝牙:就是BLE,通常说的蓝牙4.0(及以上版本)。低功耗,数据量小,距离50米左右。
传声音的,用经典蓝牙:
如蓝牙耳机、蓝牙音箱。蓝牙设计的时候就是为了传声音的,所以是近距离的音频传输的不二选择。
电池供电、连手机APP的,用BLE:
如共享单车锁、蓝牙智能锁、蓝牙防丢器、蓝牙室内定位,是目前手机和智能硬件通信的性价比最高的手段。直线距离约50米,一节5号电池能用一年,传输模组成本10块钱,远比WIFI、4G等大数据量的通信协议更实用。
又要声音又要数据的,用双模蓝牙: 双模蓝牙,就是同时支持经典蓝牙音频和低功耗蓝牙。
如智能电视遥控器、降噪耳机等。很多智能电视配的遥控器带有语音识别,需要用经典蓝牙才能传输声音
传大数据量的,用经典蓝牙: 如某些工控场景,使用Android或Linux主控,外挂蓝牙遥控设备的,可以使用经典蓝牙里的SPP协议,当作一个无线串口使用。速度比BLE传输快多了。
远距离的,不用蓝牙。 固定供电的、不考虑功耗的、要传超过几十米距离的、要传高速数据的,这些都不适合蓝牙。远距离的可以用2G、4G、NB-IOT,大数据量的可以用WIFI。
Bluetooth Low Energy (BLE),也经常被称为 Bluetooth Smart ,它是传统蓝牙的子集,在Bluetooth 4.0 core specification中被引入。虽然BLE和传统蓝牙有很多重叠的地方,但是它是有自己独特的历史血统的,BLE被Bluetooth SIG即蓝牙标准纳入之前,一直是诺基亚发展的一个叫做Wibree的室内项目。
对工程师们来说虽然有很多种的无线协议可供选择,但是BLE是实现和现代移动平台通信的最简单的方式,尤其是对于苹果设备而言,BLE可以说是唯一的可以避免为了成功的提交苹果商店的硬件设计选择。
以下的简介将使你有一个快速对BLE的总体的了解,尤其是数据如何组织,以及设备如何通过广播来告之其存在,让你可以连接他们并进行数据的传输。
以下列出的设备和平台均支持蓝牙 4.0和BLE:
GAP是 Generic Access Profile 的缩写,它控制着蓝牙的连接和广播过程。GAP协议使得设备可以被其他设备识别,并决定两个设备如何交互。
GAP为设备定义了各种各样的角色,但两个最关键的概念是中心设备( Central devices)和周边设备( Peripheral * devices)。
周边设备是指那些体积较小,功耗较小,资源有限的设备,它可以连接更加强大的中心设备,例如各种手环,手表,心跳检测器等;中心设备通常指的是手机或者平板等拥有更强大的计算和存储的设备。
下图可以详细的说明了整个广播的过程,以及广播负载和扫描回复负载是如何工作的。
周边设备会设置一个特定的广播的时间间隔(Advertising Interval),每个时间段的开始,它会发送其广播数据包,时间间隔越长节省电量,但是不能及时被扫描到。这是很明显的道理。
周边设备的广播包括两种,一种是Advertising data,一种是scan response data,广播数据就是上面所说的,是必选,每一广播间隔开始都会不间断发送,通过它来告诉中心设备自己的存在;扫描回复则是可选的,它包含了设备的基本信息,比如设备的名字和地址等,只有当中心设备对他感兴趣,发送扫描回复请求时,周边设备才会发送扫描回复数据包作为反馈。
尽管大多数情况下,周边设备广播自己都是为了建立连接后使用GATT services、characteristics完成更多的双向的数据交换,但也有些情况是不需要连接的,只需要周边设备将数据广播出去即可。
这种情况主要存在于需要周边设备 同时 给多个中心设备发送数据,而一旦建立连接,数据的收发就只对在建立连接的两台设备间可见。
周边设备可以发送一段包含少量自定义数据的 31字节 的广播或者扫描回复包给在监听范围的所有设备,这就是典型的BLE广播的过程。
通俗点的讲就是BLE的广播有两种作用,一种是告诉中心设备自己的存在然后等待连接;另一种就是单纯的对外广播信息,苹果的iBeacon就是后者的定性应用,它在广播包Manufacturer Specific Data中插入了一段自定义的数据,用来完成特定的功能。
周边设备和中心设备一旦建立连接,周边设备的广播过程就停止了,也不能再发送广播包了,接下来就要通过GATT services和characteristic进行通信。
GATT全称 Generic Attribute Profile ,中文名叫通用属性协议,它定义了 services 和 characteristic 两种东西来完成低功耗蓝牙设备之间的数据传输。它是建立在通用数据协议 Attribute Protocol (ATT) ,之上的,ATT把services和characteristic以及相关的数据保存在一张简单的查找表中,该表使用16-bit的id作为索引。
一旦两个设备建立了连接,GATT就开始发挥作用,同时意味着GAP协议管理的广播过程结束了。但是必须要知道的是,建立GATT连接必要经过GAP协议。
最重要的事情,GATT连接是 独占的 ,也就意味着一个BLE周边设备同时只能与一个中心设备连接。一旦周边设备与中心设备连接成功,直至连接断开,它不再对外广播自己的存在,其他的设备就无法发现该周边设备的存在了。
周边设备和中心设备要完成双方的通信只能通过建立GATT连接的方式。
下图展示了BLE设备如何工作的。一个周边设备只能同时连接一台中心设备,但是中心设备可以连接多台周边设备。
如果两个周边设备需要进行数据的交换的话,就必须经由中心设备的中转。
一旦周边设备和中心设备建立了连接,通信就是双向的了,对比前面的GAP广播的网络拓扑,通信是单向的,只能由周边设备往中心设备广播数据。
GATT是基于典型的C/S模式,其中周边设备通常扮演 GATT Server ,它保有services、characteristic以及查找表,也就是数据的存储是在 GATT Server 中;而例如手机平板等中心设备通常是 GATT Client ,他们向 GATT Server 发送请求。一切都是主设备GATT Client发起,然后接受来自从设备GATT Server的相应。
当连接建立之后,周边设备会给中心设备建议一个连接间隔(Connection Interval),然后中心设备每个时间间隔都会重连查看是否有新数据可以获取。但是这个连接间隔只是一个建议,因为中心设备可能忙于与其它周边设备通信或者系统资源不可得而并不能完全遵循。
下图展示了周边设备和中心设备的数据交换的流程,可以看出每一次事务都是由中心设备发起的,而周边设备只负责应答。
BLE GATT通信是基于嵌套的 Profiles , Services and Characteristics 结构之上的,下图是其框架:
Profile并不是真实存在的一种结构,而是多个完成某一特定功能services的集合,或者说是对这个特定结合的功能的描述,或者名称。以 Heart Rate Profile 为例,它包括Heart Rate Service 和 Device Information Service,他们都是为了完成测量心率这个功能而存在的service。
更详细的可以查看 Profiles Overview 。
每个service拥有一个唯一标识UUID,可以是官方认证的16bit的id,也可以是128位的自定义id。service是GATT数据的逻辑分类,它包含一个或者多个characteristic。
官方通过了一些标准 Service,完整列表在 这里 。以 Heart Rate Service 为例,可以看到它的官方通过 16 bit UUID 是 0x180D
,包含 3 个 Characteristic: Heart Rate Measurement , Body Sensor Location 和 Heart Rate Control Point ,实现该service第一个 Heart Rate Measurement 是必选的,其他两个是可选的。
Characteristic也拥有一个16-bit 或者128-bit的UUID,它是GATT通信中的最小的逻辑数据单元,它封装了一个单一的数据点,当然这个数据点可能包含一组相关的数据,比如加速度传感器的x/y/z三个坐标轴的数据。
实际上,和 BLE 外设打交道,主要是通过 Characteristic。你可以从 Characteristic 读取数据,也可以往 Characteristic 写数据。这样就实现了双向的通信。你可以使用Characteristic实现一个类似串口(UART)的 Sevice,这个 Service 中包含两个 Characteristic,一个被配置只读的通道(RX),另一个配置为只写的通道(TX)。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)