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 包括如下类型:
定义 | 说明 | 备注 |
#define GAP_ADTYPE_FLAGS 0x01 | Discovery Mode: @ref GAP_ADTYPE_FLAGS_MODES | flag说明了物理连接功能,比如有限发现模式,不支持经典蓝牙等。 l bit 0: LE 有限发现模式。 l bit 1: LE 普通发现模式。 l bit 2: 不支持 BR/EDR。 l bit 3: 对 Same Device Capable(Controller) 同时支持 BLE 和 BR/EDR。 l 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。 服务的 UUID,通知中央设备什么服务包括在此外围设备 更多的16位可用UUID,但不是全部 |
#define GAP_ADTYPE_16BIT_COMPLETE 0x03 | Service: Complete list of 16-bit UUIDs | 服务的 UUID,通知中央设备什么服务包括在此外围设备 可用16位uuid的完整列表 |
#define GAP_ADTYPE_32BIT_MORE 0x04 | Service: More 32-bit UUIDs available | 服务的 UUID,通知中央设备什么服务包括在此外围设备 更多的32位可用UUID,但不是全部 |
#define GAP_ADTYPE_32BIT_COMPLETE 0x05 | Service: Complete list of 32-bit UUIDs | 服务的 UUID,通知中央设备什么服务包括在此外围设备 可用32位uuid的完整列表 |
#define GAP_ADTYPE_128BIT_MORE 0x06 | Service: More 128-bit UUIDs available | 服务的 UUID,通知中央设备什么服务包括在此外围设备 更多的128位可用UUID,但不是全部 |
#define GAP_ADTYPE_128BIT_COMPLETE 0x07 | Service: Complete list of 128-bit UUIDs | 服务的 UUID,通知中央设备什么服务包括在此外围设备 可用128位uuid的完整列表 |
#define GAP_ADTYPE_LOCAL_NAME_SHORT 0x08 | Shortened local name | 简称 |
#define GAP_ADTYPE_LOCAL_NAME_COMPLETE 0x09 | Complete local name | 完整名称 |
#define GAP_ADTYPE_POWER_LEVEL 0x0A | 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- 带外数据 简单配对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 interval (2 octets Min, 2 octets Max) (0xFFFF indicates no conn interval min 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 服务征集:16位服务uuid列表 |
#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 | 公共目标地址 表示希望这个广播包被指定的目标设备处理,此设备绑定了公开地址,DATA 是目标地址列表,每个地址 6 字节。 |
#define GAP_ADTYPE_RANDOM_TARGET_ADDR 0x18 | Random Target Address | 随机目标地址 表示希望这个广播包被指定的目标设备处理,此设备绑定了随机地址,DATA 是目标地址列表,每个地址 6 字节。 |
#define GAP_ADTYPE_APPEARANCE 0x19 | Appearance | 外观特性 |
#define GAP_ADTYPE_ADV_INTERVAL 0x1A | 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 additional manufacturer specific data | 特定于制造商的数据:前两个八位包含设备公司标识码,然后是设备附加的特定于制造商的数据 |
#define GAP_ADTYPE_FLAGS 0x01
- 对于BR/EDR 蓝牙设备类型,Controller通常包含无线电处理、基带、链路管理、和可选择的HCI接口层;
- 对应LE Controller主要包含LE PHY、链路层、和可选择的HCI;
- 通常来说我们还可以合并BR/EDR Controller 和LE Controller到一个Controller,也就是我们常说的双模蓝牙。
低功耗蓝牙的发现模式主要分为有限可发现模式和普通(无限)可发现模式。
注意发现模式的定义必须在广播数据的开头处,不能在扫描回应数据中定义。
设备就处于有限可发现模式,当设备处于有限可发现模式时,很多人以及网上的一些资料提到广播会在使能打开之后的 30.72s 之后停止广播。但是实际测试并不是这样,而是180s
在有限可发现模式下,默认是180s之后停止广播,如果想设置这个值,可以用下面的方式:GAP_SetParamValue(TGAP_LIM_ADV_TIMEOUT, ADV_TIMEOUT);
为了实现在设置的时间或者是默认的时间之后,广播停止,过了一段时间(默认应该是 30s 之后),广播又重新开启了。出现这种情况的时候应关注“GAPROLE_ADVERT_OFF_TIME”的设置,如果不设置该值,就会出现停止广播 30s(默认值)之后重新广播的情况。
最常用的场景,一直持续广播
#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_GENERAL
// Duration of slow advertising duration in ms (set to 0 for continuous advertising)
#define DEFAULT_SLOW_ADV_DURATION 0
GAP_SetParamValue( TGAP_GEN_DISC_ADV_MIN, DEFAULT_SLOW_ADV_DURATION );
广播使能开启之后,限制广播在 30s 之后停止,并且在应用部分没有使能打开的情况下不再广播
#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_LIMITED
uint16 gapRole_AdvertOffTime = 0;
GAPRole_SetParameter( GAPROLE_ADVERT_OFF_TIME, sizeof( uint16 ), &gapRole_AdvertOffTime );//GAPROLE_ADVERT_OFF_TIME设置的时间单位是ms,默认是30s
uint16 ADV_TIMEOUT = 30;
GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, ADV_TIMEOUT );//设置的单位是s,不设置的话,默认是180s
广播使能开启之后,限制广播在 20s 之后停止,然后过 15s 之后自动重新广播,如此反复
#define DEFAULT_DISCOVERABLE_MODE GAP_ADTYPE_FLAGS_LIMITED
uint16 gapRole_AdvertOffTime = 15000;
GAPRole_SetParameter( GAPROLE_ADVERT_OFF_TIME, sizeof( uint16 ), &gapRole_AdvertOffTime );//GAPROLE_ADVERT_OFF_TIME设置的时间单位是ms,默认是30s
uint16 ADV_TIMEOUT = 20;
GAP_SetParamValue( TGAP_LIM_ADV_TIMEOUT, ADV_TIMEOUT );//设置的单位是s,不设置的话,默认是180s