BLE 广播数据解析
从上一篇 GATT Profile 简介中提到过,BLE 设备工作的第一步就是向外广播数据。广播数据中带有设备相关的信息。本文主要说一下 BLE 的广播中的数据的规范以及广播包的解析。
广播模式
BLE 中有两种角色 Central 和 Peripheral,也就是中心设备和外围设备。中心设备可以主动连接外围设备,外围设备发送广播或者被中心设备连接。外围通过广播被中心设备发现,广播中带有外围设备自身的相关信息。
广播包有两种:广播包(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 自己,剩下的就用 0 补全。这部分的数据是无效的,解释的时候,忽略即可。
广播数据格式
所有的 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,剩下的是厂商自己按照需求添加,里面的数据内容自己定义。
还有一些其他的数据,我这里就不一一列举了,有需要的可以从这个文档查阅 Core Specification Supplement。
广播数据解析
在 Android 可以使用 BluetoothAdapter
来发起扫描。基本用法如下:
BluetoothAdapter.LeScanCallback mLeScanCallback = new BluetoothAdapter.LeScanCallback() {@Overridepublic void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {// 解析广播数据
parseAdvData(scanRecord);}};mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
// 开始扫描设备
mBluetoothAdapter.startLeScan(mLeScanCallback);
...
// 停止扫描设备
mBluetoothAdapter.stopLeScan(mLeScanCallback);
当扫描到设备以后,就会回调 onLeScan(...)
,这里的参数 scanRecord
就是广播数据,这里同时包含广播数据和扫描相应数据(如果有的话),所以长度一般就是 62 字节。
根据上一节的广播数据格式的说明,可以实现解析广播数据函数 parseAdvData(scanRecord);
,下面的代码实现了解析几个我关心的数据:
public static ParsedAd parseData(byte[] adv_data) { ParsedAd parsedAd = new ParsedAd();ByteBuffer buffer = ByteBuffer.wrap(adv_data).order(ByteOrder.LITTLE_ENDIAN);while (buffer.remaining() > 2) {byte length = buffer.get();if (length == 0)break;byte type = buffer.get();length -= 1;switch (type) {case 0x01: // Flags
parsedAd.flags = buffer.get();length--;break;case 0x02: // Partial list of 16-bit UUIDs
case 0x03: // Complete list of 16-bit UUIDs
case 0x14: // List of 16-bit Service Solicitation UUIDs
while (length >= 2) {parsedAd.uuids.add(UUID.fromString(String.format("%08x-0000-1000-8000-00805f9b34fb", buffer.getShort())));length -= 2;}break;case 0x04: // Partial list of 32 bit service UUIDs
case 0x05: // Complete list of 32 bit service UUIDs
while (length >= 4) {parsedAd.uuids.add(UUID.fromString(String.format("%08x-0000-1000-8000-00805f9b34fb", buffer.getInt())));length -= 4;}break;case 0x06: // Partial list of 128-bit UUIDs
case 0x07: // Complete list of 128-bit UUIDs
case 0x15: // List of 128-bit Service Solicitation UUIDs
while (length >= 16) {long lsb = buffer.getLong();long msb = buffer.getLong();parsedAd.uuids.add(new UUID(msb, lsb));length -= 16;}break;case 0x08: // Short local device name
case 0x09: // Complete local device name
byte sb[] = new byte[length];buffer.get(sb, 0, length);length = 0;parsedAd.localName = new String(sb).trim();break; case (byte) 0xFF: // Manufacturer Specific Data
parsedAd.manufacturer = buffer.getShort();length -= 2;break;default: // skip
break;}if (length > 0) {buffer.position(buffer.position() + length);}}return parsedAd;
}
其中 ParsedAd
是自定义的简单 Java 对象,用来保存解析后的数据。这里只是解析了我关心的数据,你也可以根据前面的说明,解析更多的内容。
参考资料:
- 蓝牙官方文档
- GAP Advertising and Scan Response Data format
- Parsing BLE Advertisement packets
https://race604.com/ble-advertising/
BLE 广播数据解析相关推荐
- Android的BLE广播数据包介绍和解析---BLE--Android系列, 蓝牙技术BLE
目录 一.引言 二.广播的类型 三.广播数据格式 四.广播数据解析 五.总结 一.引言 理解和分析这个数据包结构(这里面也涉及广播间隔时间的设置,设备广播数据间隔设置长了,会影响设备被发现的效率:设置 ...
- 蓝牙广播数据包_一分钟读懂低功耗蓝牙(BLE)广播数据包
一分钟读懂低功耗蓝牙(BLE)广播数据包 低功耗蓝牙 => BLE (Bluetooth Low Energy) 1. 怎样抓取BLE广播数据包 * 硬件:一个BLE设备(具有广播功能): 一台 ...
- 蓝牙4.0 BLE 广播包解析
本文转自:蓝牙4.0BLE抓包(二) – 广播包解析 - 强光手电 - 博客园 感谢原创作者! SleepingBug评论:这篇文档写的相当好,受教了,多谢了! 所有图片水印均是CSDN自动标上的,并 ...
- 51822模拟ble广播-理论
http://blog.chinaunix.net/uid/28852942/cid-219646-list-1.html 这讲教程介绍如何使用51822的radio部分来模拟实现ble广播功能,并使 ...
- 蓝牙广播数据包_蓝牙BLE数据包格式汇总
以蓝牙4.0为例说明: BLE包格式有:广播包.扫描包.初始化连接包.链路层控制包(LL层数据包).逻辑链路控制和自适应协议数据包(即L2CAP数据包)等: 其中广播包又分为:定向广播包和非定向广播包 ...
- CC2541解析广播数据及扫描响应
广播数据(advertData)和扫描响应(scanRspData) 在典型的蓝牙BLE(Bluetooth Low Energy )系统中,从机设备广播数据让所有主机设备知道它是一个可连接的设备.接 ...
- 【IoT】BLE 广播的基础数据定义:广播名字类型和设备类型标志
BLE 实际广播 AD 数据区满足 LTV 格式,下面介绍的类型就是指数据 LTV 中的 T 字段. 1.广播名字类型 广播中的 name_type 字段: typedef enum {BLE_ADV ...
- 【BLE】广播数据包结构讲解,五颗蓝牙芯片对比
[广播数据包结构讲解] 广播数据包的讲解网上可参考的也挺多,讲解了整个数据包的每个字节每个位的功能描述,非常详细. 今天我们换个方式,按照代码编写的方式,只要是被SDK封装的部分都不做考虑,例如报头. ...
- 蓝牙4.0BLE抓包(二) – 广播包解析
转自: http://www.cnblogs.com/aikm/p/5022502.html 版权声明:本文为博主原创文章,转载请注明作者和出处. 作者:强光手电[艾克姆科技-无线事业部] 在使 ...
最新文章
- Android 内容观察者 ContentObserver 类
- zabbix server、zabbix agent、zabbix proxy 配置文件详解
- 傅里叶卷积实现「万物隐身」,这个神器可试玩
- 宇宙和你,本质上其实只是个八维数字?
- 技术分享:浅谈Service Mesh在瓜子的实践
- Windows下Caffe-SSD编译
- Windows Server 2016 Hyper-v 嵌套虚拟化技术
- linux cmake 安装mysql5.5.11_以及更高版本_linux cmake 安装mysql5.5.11,以及更高版本
- 【转】由投影重建图像:滤波反投影、FDK、TFDK三维重建算法理论基础
- php jquery mysql,使用PHP / MySQL搜索并使用jQuery动态更新
- 基于CUDA的GPU优化建议
- [.NET领域驱动设计实战系列]专题十:DDD扩展内容:全面剖析CQRS模式实现
- matlab中3乘4魔方阵,小代码3 魔方矩阵
- 记一次闲置电视盒子乐视C1S折腾entware
- QT控件 之(TreeView)实现右键菜单栏功能,双击事件能实现区分不同的节点的点击效果
- word文档动态插入水印,45度角,位于文档中央,可插入中文(附jar包和licence文件))
- 阿尔伯塔计算机硕士要求,阿尔伯塔大学计算机硕士专业介绍
- 如何彻底关闭Win10自动更新,Win10永久关闭自动更新的方法
- EDM营销解读[转载]
- 感谢各位博友的关注和支持!
热门文章
- oracle常用函数之STDDEV、STDDEV_POP、STDDEV_SAMP区别
- STM32驱动Marvell 88W8686 WiFi模块代码说明(20180129版)
- 线性代数之 矩阵求导(3)标量、向量求导的快速记忆
- 关于计算机故障排除的文章 三(转)
- 【升华网络】为你介绍淘宝
- 大话设计模式12.25-2.19(过年十五天没有更~偷个懒)
- APISIX 助力中东社交软件,实现本地化部署
- 喝“饮料”后财物被偷 菲2华人起诉“迷魂党”成员
- 国外html5转app store,H5唤醒移动端APP,或跳转到App Store和应用宝
- Philips飞利浦 Sonicare E系列电动牙刷替换刷头