参考
https://www.jianshu.com/p/3a372af38103
蓝牙版本的介绍
深入了解Android蓝牙Bluetooth——《基础篇》 (qq.com)
蓝牙发展至今经历了8个版本的更新。1.1、1.2、2.0、2.1、3.0、4.0、4.1、4.2、5.0。
那么在1.x~3.0之间的我们称之为传统蓝牙,
4.x开始的蓝牙我们称之为低功耗蓝牙也就是蓝牙ble,当然4.x版本的蓝牙也是向下兼容的。
android手机必须系统版本4.3及以上才支持BLE API。
蓝牙各版本间区别
- 蓝牙1.0:传输速率约1M/s。
- 蓝牙2.0+EDR:传输速率约2-3M/s,其中2.1+EDR是最经典的蓝牙,最大的特点是安全简易配对。
- 蓝牙3.0+HS(高传输蓝牙):高传输24M/s,只有标注了"+HS"商标的设备才是真正支持802.11高速数据传输。
- 蓝牙4.0(低功耗蓝牙):它包括经典蓝牙、高速蓝牙和蓝牙低功耗协议,在3.0基础上功耗更低,主要面向对功耗需求极低、用纽扣电池供电的应用。
- 蓝牙5.0:4 倍通讯距离,2 倍传输速度,8 倍广播资料传输量
现在主流 4.0BLE蓝牙
蓝牙4.0有几种模式,如果是蓝牙4.0低功耗模式单模的设备(常称为BLE模式),是不向下兼容的。
- 低功耗蓝牙比传统蓝牙,传输速度更快,覆盖范围更广,安全性更高,延迟更短,耗电极低等等优点
- 传统的一般通过socket方式,而低功耗蓝牙是通过Gatt协议来实现。
若是之前没做过传统蓝牙开发,也是可以直接上手低功耗蓝牙开发的。因为它们在通信协议上都有所改变,关联不大。
那么我们现在所处的4.x的设备大多是属于主从模式的。
什么是主从模式
一个主设备比如手机,一个从设备(这里也成为子设备或从机)
主设备搜索从机,可以发送,也可以接收,
从机也可以发送和接收,但只能被搜索
蓝牙协议规范
https://www.bluetooth.com/specifications/archived-specifications/
蓝牙GATT协议介绍
http://murata.eetrend.com/article/2017-11/1000980.html
https://blog.csdn.net/u013378580/article/details/52891462
一、 引言
现在低功耗蓝牙(BLE buletouch low energy)连接都是建立在 GATT (Generic Attribute Profile) 协议之上。GATT 是一个在蓝牙连接之上的发送和接收很短的数据段的通用规范,这些很短的数据段被称为属性(Attribute)。
二、 GAP
详细介绍 GATT 之前,需要了解 GAP(Generic Access Profile),它在用来控制设备连接和广播。
GAP 使你的设备被其他设备可见,并决定了你的设备是否可以 或者 怎样与合同设备进行交互。例如 Beacon 设备就只是向外广播,不支持连接,小米手环就等设备就可以与中心设备连接。
1. 设备角色
GAP 给设备定义了若干角色,其中主要的两个是:外围设备(Peripheral)和中心设备(Central)。
- 外围设备:这一般就是非常小 或者 简单的低功耗设备,用来提供数据,并连接到一个更加相对强大的中心设备。例如小米手环。
- 中心设备:中心设备相对比较强大,用来连接其他外围设备。例如手机等。
2. 广播数据
在 GAP 中外围设备通过两种方式向外广播数据: Advertising Data Payload(广播数据)和 Scan Response Data Payload(扫描回复),每种数据最长可以包含 31 byte。
- 这里广播数据是必需的,因为外设必需不停的向外广播,让中心设备知道它的存在。
- 扫描回复是可选的,中心设备可以向外设请求扫描回复,这里包含一些设备额外的信息,例如设备的名字。(广播的数据格式我将另外专门写一个篇博客来讲。)
3. 广播流程
GAP 的广播工作流程如下图所示。
外围设备会设定一个广播间隔,每个广播间隔中,它会重新发送自己的广播数据。广播间隔越长,越省电,同时也不太容易扫描到。
4. 广播的网络拓扑结构
大部分情况下,外设通过广播自己来让中心设备发现自己,并建立 GATT 连接,从而进行更多的数据交换。
也有些情况是不需要连接的,只要外设广播自己的数据即可。用这种方式主要目的是让外围设备,把自己的信息发送给多个中心设备。因为基于 GATT 连接的方式的,只能是一个外设连接一个中心设备。使用广播这种方式最典型的应用就是苹果的 iBeacon。广播工作模式下的网络拓扑图如下:
三、GATT
GATT 的全名是 Generic Attribute Profile(姑且翻译成:普通属性协议),它定义两个 BLE 设备通过叫做 Service 和 Characteristic 的东西进行通信。
ATT(Attribute Protocol)属性协议 (ATT) 是 GATT 的构建基础,二者的关系也被称为 GATT/ATT。ATT 经过优化,可在 BLE 设备上运行。为此,该协议尽可能少地使用字节。
ATT 协议把 Service, Characteristic以及对应的数据保存在一个查找表中,此查找表使用 16 bit ID 作为每一项的索引。
一旦两个设备建立起了连接,GATT 就开始起作用了,这也意味着,你必需完成前面的 GAP 协议。这里需要说明的是,GATT 连接,必需先经过 GAP 协议。实际上,我们在 Android 开发中,可以直接使用设备的 MAC 地址,发起连接,可以不经过扫描的步骤。这并不意味不需要经过 GAP,实际上在芯片级别已经给你做好了,蓝牙芯片发起连接,总是先扫描设备,扫描到了才会发起连接。
GATT 连接需要特别注意的是:GATT 连接是独占的。也就是一个 BLE 外设同时只能被一个中心设备连接。一旦外设被连接,它就会马上停止广播,这样它就对其他设备不可见了。当设备断开,它又开始广播。
中心设备和外设需要双向通信的话,唯一的方式就是建立 GATT 连接。
1. GATT 连接的网络拓扑
下图展示了 GTT 连接网络拓扑结构。这里很清楚的显示,一个外设只能连接一个中心设备,而一个中心设备可以连接多个外设。
一旦建立起了连接,通信就是双向的了,对比前面的 GAP 广播的网络拓扑,GAP 通信是单向的。如果你要让两个设备外设能通信,就只能通过中心设备中转。
2. GATT 通信事务
GATT 通信的双方是 C/S 关系。外设作为 GATT 服务端(Server),它维持了 ATT 的查找表以及 service 和 characteristic 的定义。中心设备是 GATT 客户端(Client),它向 Server 发起请求。需要注意的是,所有的通信事件,都是由客户端(也叫主设备,Master)发起,并且接收服务端(也叫从设备,Slave)的响应。
一旦连接建立,外设将会给中心设备建议一个连接间隔(Connection Interval),这样,中心设备就会在每个连接间隔尝试去重新连接,检查是否有新的数据。但是,这个连接间隔只是一个建议,你的中心设备可能并不会严格按照这个间隔来执行,例如你的中心设备正在忙于连接其他的外设,或者中心设备资源太忙。
下图展示一个外设(GATT 服务端)和中心设备(GATT 客户端)之间的数据交换流程,可以看到的是,每次都是主设备发起请求:
3. GATT 结构
GATT 事务是建立在嵌套的Profiles, Services 和 Characteristics之上的的,如下图所示:
- Profile
并不是实际存在于 BLE 外设上的,它只是一个被 Bluetooth SIG 或者外设设计者预先定义的 Service 的集合。
例如心率Profile(Heart Rate Profile)就是结合了 Heart Rate Service 和 Device Information Service。
一个设备可以实现多个配置文件。例如,一个设备可能包括心率监测仪和电量检测。
- Service
每个profile中会包含多个service,每个service代表从机的一种能力。
是把数据分成一个个的独立逻辑项,它包含一个或者多个 Characteristic。每个 Service 有一个 UUID 唯一标识。 UUID 有 16 bit 的,或者 128 bit 的。16 bit 的 UUID 是官方通过认证的,需要花钱购买,128 bit 是自定义的,这个就可以自己随便设置。
官方通过了一些标准 Service,以 Heart Rate Service为例,可以看到它的官方通过 16 bit UUID 是 0x180D,包含 3 个 Characteristic:Heart Rate Measurement, Body Sensor Location 和 Heart Rate ControPoint,并且定义了只有第一个是必须的,它是可选实现的。
service可以理解为一个服务,在ble从机中,通过有多个服务,例如电量信息服务、系统信息服务等,每个service中又包含多个characteristic特征值。每个具体的characteristic特征值才是ble通信的主题。比如当前的电量是80%,所以会通过电量信息服务的characteristic特征值存在从机的profile里,这样主机就可以通过这个characteristic来读取80%这个数据。
你可以在bluetooth.org 找到一个目前支持的基于GATT的配置文件和服务列表。
- Characteristic
在 Service 下面,又包括了许多的独立数据项,我们把这些独立的数据项称作 Characteristic,
一个characteristic包括一个单一变量和0-n个用来描述characteristic变量的descriptor。
与 Service 类似,每个 Characteristic 用 16 bit 或者 128 bit 的 UUID 唯一标识。你可以免费使用 Bluetooth SIG 官方定义的标准 Characteristic,使用官方定义的,可以确保 BLE 的软件和硬件能相互理解。当然,你可以自定义 Characteristic,这样的话,就只有你自己的软件和外设能够相互理解。
举个例子, Heart Rate Measurement Characteristic,这是上面提到的 Heart Rate Service 必需实现的 Characteristic,它的 UUID 是 0x2A37。它的数据结构是,开始 8 bit 定义心率数据格式(是UINT8 还是 UINT16?),接下来就是对应格式的实际心率数据。
实际上,和 BLE 外设打交道,主要是通过 Characteristic。你可以从 Characteristic 读取数据,也可以往 Characteristic 写数据。这样就实现了双向的通信。所以你可以自己实现一个类似串口(UART)的 Sevice,这个 Service 中包含两个 Characteristic,一个被配置只读的通道(RX),另一个配置为只写的通道(TX)。
在 Android 开发中,建立蓝牙连接后,我们说的通过蓝牙发送数据给外围设备就是往这些 Characteristic 中的 Value 字段写入数据;外围设备发送数据给手机就是监听这些 Charateristic 中的 Value 字段有没有变化,如果发生了变化,手机的 BLE API 就会收到一个监听的回调。
- Descriptor
Descriptor用来描述characteristic变量的属性。
每个characteristic可以对应一个或多个Description用于描述characteristic的信息或属性
例如,一个descriptor可以规定一个人类可读的可读的描述,或者一个characteristic变量可接受的范围,或者一个characteristic变量特定的测量单位。
蓝牙广播数据解析
https://www.cnblogs.com/Free-Thinker/archive/2014/03/07/5872239.html
蓝牙协议规范中的vo3 Part C
BLE 中有两种角色 Centra和 Periphera,也就是中心设备和外围设备。中心设备可以主动连接外围设备,外围设备发送广播或者被中心设备连接。外围通过广播被中心设备发现,广播中带有外围设备自身的相关信息。
广播包有两种: 广播包 (Advertising Data)和 响应包 (Scan Response),其中广播包是每个设备必须广播的,而响应包是可选的。
数据包的格式如下图所示(图片来自官方 Spec):
每个包都是 31 字节,数据包中分为有效数据(significant)和无效数据(non-significant)两部分。
- 有效数据部分 :包含若干个广播数据单元,每个数据单元称为 AD Structure 。
如图中所示,AD Structure 的组成是:
-
- 第一个字节是长度值 Len ,表示接下来的 Len 个字节是数据部分。
- 数据部分的第一个字节表示数据的类型 AD Type ,剩下的 Len - 1 个字节是真正的数据 AD data 。
- 其中 AD type 非常关键,决定了 AD Data 的数据代表的是什么和怎么解析,这个在后面会详细讲;
- 无效数据部分 :
因为广播包的长度必须是 31 个 byte,如果有效数据部分不到 31 byte,剩下的就用 0 补全。这部分的数据是无效的,解释的时候,忽略即可。
The non-significant part extends the data when necessary and shalcontain all-zero octets
AD Type 包括如下类型
https://blog.csdn.net/slimmm/article/details/100583655
https://www.bluetooth.com/specifications/assigned-numbers/generic-access-profile/
定义 |
说明 |
备注 |
#define GAP_ADTYPE_FLAGS 0x01 |
Discovery Mode: @ref GAP_ADTYPE_FLAGS_MODES |
flag说明了物理连接功能,比如有限发现模式,不支持经典蓝牙等。 bit 0: LE 有限发现模式。 bit 1: LE 普通发现模式。 bit 2: 不支持 BR/EDR。 bit 3: 对 Same Device Capable(Controller) 同时支持 BLE 和 BR/EDR。 bit 4: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR。 bit 5..7: 预留。 |
#define GAP_ADTYPE_16BIT_MORE 0x02 |
Service: More 16-bit UUIDs available |
Service UUID: 广播数据中一般都会把设备支持的 GATT Service 广播出来,用来告诉外面本设备所支持的 Service。有三种类型的 UUID:16 bit, 32bit, 128 bit。广播中,每种类型类型有有两个类别:完整和非完整的。这样就共有 6 种 AD Type。 |
#define GAP_ADTYPE_16BIT_COMPLETE 0x03 |
Service: Complete list of 16-bit UUIDs |
服务的 UUID,通知中央设备什么服务包括在此外围设备 |
#define GAP_ADTYPE_32BIT_MORE 0x04 |
Service: More 32-bit UUIDs available |
服务的 UUID,通知中央设备什么服务包括在此外围设备 |
#define GAP_ADTYPE_32BIT_COMPLETE 0x05 |
Service: Complete list of 32-bit UUIDs |
服务的 UUID,通知中央设备什么服务包括在此外围设备 |
#define GAP_ADTYPE_128BIT_MORE 0x06 |
Service: More 128-bit UUIDs available |
服务的 UUID,通知中央设备什么服务包括在此外围设备 |
#define GAP_ADTYPE_128BIT_COMPLETE 0x07 |
Service: Complete list of 128-bit UUIDs |
服务的 UUID,通知中央设备什么服务包括在此外围设备 |
#define GAP_ADTYPE_LOCAL_NAME_SHORT 0x08 |
Shortened locaname |
简称 |
#define GAP_ADTYPE_LOCAL_NAME_COMPLETE 0x09 |
Complete locaname |
完整名称 |
#define GAP_ADTYPE_POWER_LEVE0x0A |
TX Power Level: 0xXX: -127 to +127 dBm |
发送功率 |
#define GAP_ADTYPE_OOB_CLASS_OF_DEVICE 0x0D |
Simple Pairing OOB Tag: Class of device (3 octets) |
out-of-band,OOB- 带外数据 |
#define GAP_ADTYPE_OOB_SIMPLE_PAIRING_HASHC 0x0E |
Simple Pairing OOB Tag: Simple Pairing Hash C (16 octets) |
简单配对OOB标签:简单配对散列C |
#define GAP_ADTYPE_OOB_SIMPLE_PAIRING_RANDR 0x0F |
Simple Pairing OOB Tag: Simple Pairing Randomizer R (16 octets) |
简单配对OOB标签:简单配对随机器R |
#define GAP_ADTYPE_SM_TK 0x10 |
Security Manager TK Value |
安全管理器TK值 |
#define GAP_ADTYPE_SM_OOB_FLAG 0x11 |
Security Manager OOB Flags |
安全管理器OOB标志 |
#define GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE 0x12 |
Min and Max values of tde connection interva(2 octets Min, 2 octets Max) (0xFFFF indicates no conn intervamin or max) |
从机连接间隔的最小值和最大值 |
#define GAP_ADTYPE_SIGNED_DATA 0x13 |
Signed Data field |
签名数据字段 |
#define GAP_ADTYPE_SERVICES_LIST_16BIT 0x14 |
Service Solicitation: list of 16-bit Service UUIDs |
服务搜寻:外围设备可以要请中心设备提供相应的 Service |
#define GAP_ADTYPE_SERVICES_LIST_128BIT 0x15 |
Service Solicitation: list of 128-bit Service UUIDs |
服务征集:128位服务uuid列表 |
#define GAP_ADTYPE_SERVICE_DATA 0x16 |
Service Data - 16-bit UUID |
服务数据- 16位UUID |
#define GAP_ADTYPE_PUBLIC_TARGET_ADDR 0x17 |
Public Target Address |
公共目标地址 |
#define GAP_ADTYPE_RANDOM_TARGET_ADDR 0x18 |
Random Target Address |
随机目标地址 |
#define GAP_ADTYPE_APPEARANCE 0x19 |
Appearance |
外观特性 |
#define GAP_ADTYPE_ADV_INTERVA0x1A |
Advertising Interval |
广播时间间隔 |
#define GAP_ADTYPE_LE_BD_ADDR 0x1B |
LE Bluetootd Device Address |
LE 蓝牙设备地址 |
#define GAP_ADTYPE_LE_ROLE 0x1C |
LE Role |
LE 角色 |
#define GAP_ADTYPE_SIMPLE_PAIRING_HASHC_256 0x1D |
Simple Pairing Hash C-256 |
简单配对哈希C-256 |
#define GAP_ADTYPE_SIMPLE_PAIRING_RANDR_256 0x1E |
Simple Pairing Randomizer R-256 |
简单配对随机发生器R-256 |
#define GAP_ADTYPE_SERVICE_DATA_32BIT 0x20 |
Service Data - 32-bit UUID |
服务数据- 32位UUID |
#define GAP_ADTYPE_SERVICE_DATA_128BIT 0x21 |
Service Data - 128-bit UUID |
服务数据- 128位UUID |
#define GAP_ADTYPE_3D_INFO_DATA 0x3D |
3D Information Data |
三维信息数据 |
#define GAP_ADTYPE_MANUFACTURER_SPECIFIC 0xFF |
Manufacturer Specific Data: first 2 octets contain tde Company Identifier Code followed by tde additionamanufacturer specific data |
特定于制造商的数据: 前两个字节包含设备公司标识码, 然后是设备附加的特定于制造商的数据 |
16bit 转为128 bit uuid
https://www.cnblogs.com/Free-Thinker/p/11375265.html
熟悉BLE技术同学应该对UUID不陌生,服务、特征值、描述都是有UUID格式定义。
蓝牙广播中对服务UUID格式定义都有三种16 bit UUID、32 bit UUID、128 bit UUID。
但是熟悉安卓开发的小伙伴都知道接口都UUID格式,fromString时候16bit的UUID该咋办呢?
16bit和32bit的UUID与128bit的值之间转换关系:
128_bit_UUID = 16_bit_UUID * 2^96 + Bluetooth_Base_UUID
128_bit_UUID = 32_bit_UUID * 2^96 + Bluetooth_Base_UUID
其中 Bluetooth_Base_UUID定义为 00000000-0000-1000-8000-00805F9B34FB
如果你想说这是啥呀,那我这样说你应该可以明白点:
若16 bit UUID为xxxx,那么128 bit UUID为0000xxxx-0000-1000-8000-00805F9B34FB
若32 bit UUID为xxxxxxxx,那么128 bit UUID为xxxxxxxx-0000-1000-8000-00805F9B34FB