1. 前言
最近领导安排一个项目,直接丢了一个机器给我,和两份通讯协议给我,让我完成Android 端和微信小程序平台的蓝牙BLE项目开发。我一看,我问领导这个项目还有没有其他相关资料,领导回复两个字:“没有”,我顿时蒙了,又是这样子,每次由他安排的项目总是坑,还问我什么大概什么时候可以做好,什么时候可以提交一份Demo. 此时,想哭的心都有。领导没有相关项目资料,只能自己想办法了,后来看协议,发现这种蓝牙设备是微信蓝牙设备。就是蓝牙模块是符合微信蓝牙规范的设备,单片机通过是一个支持蓝牙Airsync协议 的模块,使用其中的通道指令进行通讯。
2. 基本知识
2.1 微信蓝牙外设是符合微信官方规定的蓝牙设备规范的蓝牙设备,其包括经典蓝牙和 4.0 BLE 蓝牙,目前支持 ios 和 andriod 两个系统。
2.2 微信硬件平台使用蓝牙作为近场控制的连接件,并拟定了《微信蓝牙外设协议》,这份协议像一个标准,用于规范微信和蓝牙外设之间的数据交互场景和接口。。
2.3 微信蓝牙物联是一种近场控制场景
微信硬件平台支持蓝牙和Wifi/3G/GPRS接入。蓝牙接入则是一种近场控制手段,用户只能利用微信通过手机的蓝牙来控制20米左右的蓝牙设备。也即是,当蓝牙设备离开手机蓝牙的连接范围,那么用户是控制不了该设备的。
对于蓝牙外设来说,手机就像一个蓝牙网关一样,手机通过蓝牙来跟蓝牙外设进行通信,将得到的数据通过手机的wifi或者3G/4G信号与云后端(微信公众平台、第三方云服务端)交互。前者是基于微信Airsync协议,后者则是微信制定的基于TCP/IP协议的《设备接入接口协议》。
3. 微信蓝牙硬件设备
3.1 服务UUID 和 读写特征和指示特征的UUID
名称 值
ServiceUUID 0xFEE7(该 uuid 经蓝牙官方授权)
Write Characteristics UUID 0xFEC7
Indicate Characteristics UUID 0xFEC8
Read Characteristics UUID 0xFEC9Andriod RFCOMM UUID e5b152ed-6b46-09e9-4678-665e9a972cbc
3.2 蓝牙广播
3.2.1 广播模式
BLE 中有两种角色 Central 和 Peripheral,也就是中心设备和外围设备。中心设备可以主动连接外围设备,外围设备发送广播或者被中心设备连接。外围通过广播被中心设备发现,广播中带有外围设备自身的相关信息。
对于蓝牙设备来说,主要的状态是,包括未连接和已连接两种。
在未连接时,它需要进行广播。其广播的目的是为了让手机能够扫描蓝牙知到这个蓝牙设备是支持Airsync协议的设备。
那么,广播数据需要包含什么格式的数据才能被手机微信所识别到呢?这就是蓝牙Airsync协议规定的内容。
根据微信规范定义,
蓝牙普通广播包格式::manufature specific data 需以 MAC 地址(6 字节)结尾。
并且 manufature specific data 长度需大于等于 8 字节(最前两个字节为 company id,没有的话随便填)。
确认广播包:manufature specific data 需以下面格式结尾,
0xfe 0x01 0x01 + MAC 地址(6 字节)。并且 manufature specific data 长度需大于等于
8 字节(最前两个字节为 company id,没有的话随便填)。
3.2.2 BLE 蓝牙广播包
3.2.2.1 BLE广播概述
BLE 连接过程中有三个重要的数据包:SCAN_REQ, SCAN_RSP 和 CONNECT_REQ。
SCAN_REQ: 扫描请求,由主设备(MASTER DEVICE)向从设备(SLAVE DEVICE)发出,目的是为了获得从设备的响应以得到更多的从设备广播数据信息(包括设备名字,或者服务UUID,及其它如厂家特定格式的信息(如硬件版本,软件版本号,设备系列号等等)
SCAN_RSP: 从设备对就主设备发起的SCAN_REQ的响应,作为广播包的补充,从设备可以给主设备更多的广播数据,比如说,有些设备在广播包里面没有设备名字,这个时候就可以把设备名字放在这个包里面发给主设备
CONNECT_REQ:主设备向从设备发出连接请求。至此连接建立完成(从设备不会响应这个请求),如果从设备没有连接上面的问题的话,以后主从双方会开始相互交换有效数据(基于GAP,GATT及SMP协议)或者交换空包。
3.2.2.2 BLE 广播包报文结构 (摘:《ble 广播数据格式细致分析》)
BLE报文结构如下,他由下图所示的各个域组成。因为有的域的长度超过了一个字节,所以在传输的过程中就涉及到多字节域中哪个字节先传输的问题,BLE报文传输时的字节序和比特序如下:
- 字节序:大多数多字节域是从低字节开始传输的。注意,并不是所有的多字节域都是从低字节开始传输的。
- 比特序:各个字节传输时,每个字节都是从低位开始。
具体每个部分的详细解析可以查看《ble 广播数据格式细致分析》 这篇文章。
其中,本文关注PDU 中的数据段(AdvData)
- 广播报文:长度域包含6个比特,有效值的范围是6~37。
- 数据报文:长度域包含5个比特,有效值的范围是0~31。
广播报文和和数据报文的长度域有所不同,主要原因是:广播报文除了最多31个字节的数据之外,还必须要包含6个字节的广播设备地址。6+31=37,所以需要6比特的长度域。
再次强调:广播时必须要包含6个字节的广播设备地址。
3..2.2.3 数据(AdvData)
广播和扫面响应的数据格式如下图所示,由有效数据部分和无效数据部分组成。
图8:广播和扫描响应的数据格式
1) 有效数据部分:包含N个AD Structure,每个AD Structure由Length,AD Type和AD Data组成。其中:
- Length:AD Type和AD Data的长度。
- AD Type:指示AD Data数据的含义。
3.2.3.4 广播包可以在 Android 代码中可以使用 BluetoothAdapter 来发起扫描得到,基本用法如下:
BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback()
{
@Override
public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
//其中,scanRecord 就是广播包的二进制数据
//这个广播包,其位置是在, BLE 广播报文格式中的PDU(协议数据单元)中的AdvData 段,
//而且,AdvData 段由有效数据部分和无效数据部分组成,
//有效数据部分:包含N个AD Structure,每个AD Structure由Length,AD Type和AD Data组成。其中:
//Length:AD Type和AD Data的长度。
//AD Type:指示AD Data数据的含义。
}
};
安卓蓝牙在扫描设备后,回调方法 onLeScan(...)中的参数 scanRecord 就是广播数据,这里同时包含广播数据和扫描应答数据(均为31字节),所以长度一般就是 62 字节,BLE4.0规定,如果广播包和扫描应答包不足字节,则以0补齐.
3.2.2.5 广播数据格式
所有的 AD type 的定义在文档 Core Specification Supplement 中。 AD Type 包括如下类型:
-
Flags: TYPE = 0x01。这个数据用来标识设备 LE 物理连接的功能。DATA 是 0 到多个字节的 Flag 值,每个 bit 上用 0 或者 1 来表示是否为 True。如果有任何一个 bit 不为 0,并且广播包是可连接的,就必须包含此数据。各 bit 的定义如下:
- 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: 预留
-
Service UUID: 广播数据中一般都会把设备支持的 GATT Service 广播出来,用来告诉外面本设备所支持的 Service。有三种类型的 UUID:16 bit, 32bit, 128 bit。广播中,每种类型类型有有两个类别:完整和非完整的。这样就共有 6 种 AD Type。
- 非完整的 16 bit UUID 列表: TYPE = 0x02;
- 完整的 16 bit UUID 列表: TYPE = 0x03;
- 非完整的 32 bit UUID 列表: TYPE = 0x04;
- 完整的 32 bit UUID 列表: TYPE = 0x05;
- 非完整的 128 bit UUID 列表: TYPE = 0x06;
- 完整的 128 bit UUID 列表: TYPE = 0x07;
-
Local Name: 设备名字,DATA 是名字的字符串。Local Name 可以是设备的全名,也可以是设备名字的缩写,其中缩写必须是全名的前面的若干字符。
- 设备全名: TYPE = 0x08
- 设备简称: TYPE = 0x09
-
TX Power Level: TYPE = 0x0A,表示设备发送广播包的信号强度。DATA 部分是一个字节,表示 -127 到 + 127 dBm。
-
带外安全管理(Security Manager Out of Band):TYPE = 0x11。DATA 也是 Flag,每个 bit 表示一个功能:
- bit 0: OOB Flag,0 表示没有 OOB 数据,1 表示有
- bit 1: 支持 LE
- bit 2: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
- bit 3: 地址类型,0 表示公开地址,1 表示随机地址
-
外设(Slave)连接间隔范围:TYPE = 0x12。数据中定义了 Slave 最大和最小连接间隔,数据包含 4 个字节:
- 前 2 字节:定义最小连接间隔,取值范围:0x0006 ~ 0x0C80,而 0xFFFF 表示未定义;
- 后 2 字节:定义最大连接间隔,同上,不过需要保证最大连接间隔大于或者等于最小连接间隔。
-
服务搜寻:外围设备可以要请中心设备提供相应的 Service。其数据定义和前面的 Service UUID 类似:
- 16 bit UUID 列表: TYPE = 0x14
- 32 bit UUID 列表: TYPE = 0x??
- 128 bit UUID 列表: TYPE = 0x15
-
Service Data: Service 对应的数据。
- 16 bit UUID Service: TYPE = 0x16, 前 2 字节是 UUID,后面是 Service 的数据;
- 32 bit UUID Service: TYPE = 0x??, 前 4 字节是 UUID,后面是 Service 的数据;
- 128 bit UUID Service: TYPE = 0x??, 前 16 字节是 UUID,后面是 Service 的数据;
-
公开目标地址:TYPE = 0x17,表示希望这个广播包被指定的目标设备处理,此设备绑定了公开地址,DATA 是目标地址列表,每个地址 6 字节。
-
随机目标地址:TYPE = 0x18,定义和前一个类似,表示希望这个广播包被指定的目标设备处理,此设备绑定了随机地址,DATA 是目标地址列表,每个地址 6 字节。
-
Appearance:TYPE = 0x19,DATA 是表示了设备的外观。
-
厂商自定义数据: TYPE = 0xFF,厂商自定义的数据中,前两个字节表示厂商 ID,剩下的是厂商自己按照需求添加,里面的数据内容自己定义。
3.2.2.6 微信蓝牙设备广播包数据:
02 01 06 05 02 E7 FE E0 FF 09 FF FF FF F3 3F 31 F3 FF 3F 0D 09 41 46 47 46 34 20 20 20 20 20 20 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
上面蓝牙广播包中,包含广播包和应答包,各个AD Structure 解析如下:
第1个AD Structure: 02 01 06
Length |
AD Type |
AD Data |
02 |
01 |
06 |
2字节 |
AD type为“Flag” |
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: 预留。 |
第2个AD Structure: 05 02 E7 FE E0 FF
Length |
AD Type |
AD Data |
05 |
02 |
E7 FE E0 FF |
5字节 |
AD type为“SERVICE_UUID_MORE_AVAILABLE” 非完整的 16 bit UUID 列表 |
E7 FE 为 微信蓝牙硬件指定的服务UUID ,根据微信蓝牙外设协议介绍 (该 uuid 经蓝牙官方授权) FF E0 为 另外一个服务 UUID |
第3个AD Structure: 09 FF FF FF F3 3F 31 F3 FF 3F
Length |
AD Type |
AD Data |
09 |
FF |
FF FF F3 3F 31 F3 FF 3F |
9字节 |
AD type为“Manufacturer Specific Data”
厂商自定义数据: TYPE = 0xFF,厂商自定义的数据中,前两个字节表示厂商 ID,剩下的是厂商自己按照需求添加,里面的数据内容自己定义 |
根据微信蓝牙外设规定, 普通广播包:manufature specific data 需以 MAC 地址(6 字节)结尾。 并且 manufature specific data 长度需大于等于 8 字节(最前两个字节为 company id,没有的话随便填)。 确认广播包:manufature specific data 需以下面格式结尾, 0xfe 0x01 0x01 + MAC 地址(6 字节)。 并且 manufature specific data 长度需大于等于 8 字节(最前两个字节为 company id,没有的话随便填)。
因此: FF FF F3 3F 31 F3 FF 3F , FF FF 为厂商ID, F3 3F 31 F3 FF 3F , 为蓝牙设备的MAC 地址 |
第4个AD Structure: 0D 09 41 46 47 46 34 20 20 20 20 20 20 20
Length |
AD Type |
AD Data |
0D |
09 |
41 46 47 46 34 20 20 20 20 20 20 20 |
13字节 |
AD type为“完整的本地名称” |
41 46 47 46 34 20 20 20 20 20 20 20 蓝牙名称的ASCII 码的16进制 |
以上就是微信蓝牙广播包解析。
参考文章