BLE Legacy 广播【广播使能】
在 BLE Legacy 广播流程中,前面几个 HCI Command 主要负责“配置”:
HCI_LE_Set_Advertising_Parameters HCI_LE_Set_Advertising_Data HCI_LE_Set_Scan_Response_Data但是这些命令只是把广播参数、广播数据、扫描响应数据配置到 Controller 中,并不会真正让 Controller 开始发送广播包。
真正用于“开始广播”或“停止广播”的命令是:
HCI_LE_Set_Advertising_Enable也就是本文要讲的:
7.8.9 LE Set Advertising Enable command这个命令可以理解为 BLE Legacy 广播流程中的“启动 / 停止开关”。
一、命令概览
官方文档中该命令的信息如下:
Command: HCI_LE_Set_Advertising_Enable OCF: 0x000A Command Parameters: Advertising_Enable Return Parameters: Status需要注意,文档中还有一句说明:
This command was formerly called “LE Set Advertise Enable”.翻译:
该命令以前被称为 “LE Set Advertise Enable”。也就是说,在一些旧资料、旧代码或厂商文档中,你可能会看到:
LE Set Advertise Enable它和现在的:
LE Set Advertising Enable指的是同一个命令。
二、Description 翻译
官方描述第一段:
This command is used to request the Controller to start or stop advertising. The Controller manages the timing of advertisements as per the advertising parameters given in the HCI_LE_Set_Advertising_Parameters command.翻译:
该命令用于请求 Controller 开始或停止广播。Controller 会根据 HCI_LE_Set_Advertising_Parameters command 中给定的广播参数来管理广播的时序。这句话非常关键。
它说明:
HCI_LE_Set_Advertising_Enable 只负责请求 Controller 开始或停止广播。而广播怎么发,比如:
广播间隔是多少 广播类型是什么 使用什么地址类型 在哪些广播信道上发 广播过滤策略是什么这些不是由本命令决定的,而是由前面的:
HCI_LE_Set_Advertising_Parameters决定。
所以可以这样理解:
HCI_LE_Set_Advertising_Parameters 负责告诉 Controller:广播应该怎么发。 HCI_LE_Set_Advertising_Enable 负责告诉 Controller:现在开始发,或者停止发。官方描述第二段:
The Controller shall continue advertising until the Host issues an HCI_LE_Set_Advertising_Enable command with Advertising_Enable set to 0x00 (Advertising is disabled), a connection is created using the advertising, or the Advertising is timed out due to high duty cycle Directed Advertising. In these cases, advertising is then disabled.翻译:
Controller 会持续进行广播,直到 Host 发送 HCI_LE_Set_Advertising_Enable command 并将 Advertising_Enable 设置为 0x00,也就是禁用广播;或者通过该广播建立了连接;或者由于高占空比定向广播超时。在这些情况下,广播随后会被禁用。这段说明了广播会在几种情况下停止:
1. Host 主动关闭广播 2. 通过该广播建立了连接 3. 高占空比定向广播超时对于普通 Legacy 广播来说,我们最常见的是第一种:
Host 发送 Advertising_Enable = 0x00主动关闭广播。
如果广播类型是可连接广播,比如:
ADV_IND ADV_DIRECT_IND当连接建立成功后,Controller 也会停止广播。
官方描述第三段:
Enabling advertising when it is already enabled can cause the random address to change. Disabling advertising when it is already disabled has no effect.翻译:
当广播已经使能时再次使能广播,可能会导致随机地址发生变化。当广播已经禁用时再次禁用广播,不会产生影响。这里有两个点。
第一:
广播已经开启时,再次执行 Enable,可能导致随机地址变化。这个和地址类型有关,尤其是使用随机地址、可解析私有地址等场景时需要注意。
第二:
广播已经关闭时,再次执行 Disable,没有效果。也就是说,重复关闭广播通常是安全的,不会产生额外行为。
三、Command Parameters 翻译
该命令只有一个参数:
Advertising_Enable大小:
1 octet取值如下:
| Value | Parameter Description |
|---|---|
| 0x00 | Advertising is disabled,禁用广播,默认值 |
| 0x01 | Advertising is enabled,使能广播 |
| All other values | Reserved for future use,保留,供将来使用 |
也就是说:
Advertising_Enable = 0x00表示关闭广播。
Advertising_Enable = 0x01表示开启广播。
其他值不能使用。
四、Return Parameters 翻译
该命令返回一个参数:
Status大小:
1 octet取值如下:
| Value | Parameter Description |
|---|---|
| 0x00 | HCI_LE_Set_Advertising_Enable command 执行成功 |
| 0x01 to 0xFF | HCI_LE_Set_Advertising_Enable command 执行失败,具体错误码见 Controller Error Codes |
也就是说:
Status = 0x00表示命令执行成功。
如果返回:
Status = 0x01 ~ 0xFF表示命令失败,需要结合具体错误码分析。
五、Event(s) generated 翻译
官方文档中提到:
When the HCI_LE_Set_Advertising_Enable command has completed, an HCI_Command_Complete event shall be generated.翻译:
当 HCI_LE_Set_Advertising_Enable command 完成后,应当生成一个 HCI_Command_Complete event。也就是说,这个命令执行完成后,Controller 会通过:
HCI_Command_Complete event告诉 Host 命令完成,并返回 Status。
注意,它不是通过 LE Advertising Report event 返回结果。
LE Advertising Report event 是扫描端收到广播后上报扫描结果用的,不是广播端配置命令的返回事件。
六、特殊情况:高占空比定向广播超时
官方文档还提到:
If the Advertising_Type parameter is 0x01 (ADV_DIRECT_IND, high duty cycle) and the directed advertising fails to create a connection, an HCI_LE_Connection_Complete or HCI_LE_Enhanced_Connection_Complete event shall be generated with the Status code set to Advertising Timeout (0x3C).翻译:
如果 Advertising_Type 参数是 0x01,也就是高占空比定向广播 ADV_DIRECT_IND,并且该定向广播未能建立连接,则会生成 HCI_LE_Connection_Complete 或 HCI_LE_Enhanced_Connection_Complete event,并且 Status code 设置为 Advertising Timeout,错误码为 0x3C。这里要理解的是:
高占空比定向广播不是一直无限广播。它是为了快速连接某个指定设备而设计的广播类型。
如果在规定时间内没有建立连接,就会超时,然后广播停止,并产生连接完成相关事件,只是这个事件的状态是:
Advertising Timeout 0x3C七、连接建立后广播会停止
官方文档还提到:
If the Advertising_Type parameter is 0x00 (ADV_IND), 0x01 (ADV_DIRECT_IND, high duty cycle), or 0x04 (ADV_DIRECT_IND, low duty cycle) and a connection is created, an HCI_LE_Connection_Complete or HCI_LE_Enhanced_Connection_Complete event shall be generated.翻译:
如果 Advertising_Type 参数是 0x00,也就是 ADV_IND;或者 0x01,也就是高占空比定向广播 ADV_DIRECT_IND;或者 0x04,也就是低占空比定向广播 ADV_DIRECT_IND,并且连接被建立,则会生成 HCI_LE_Connection_Complete 或 HCI_LE_Enhanced_Connection_Complete event。这说明:
对于可连接广播,如果连接建立成功,Controller 会产生连接完成事件。常见可连接广播包括:
ADV_IND ADV_DIRECT_IND连接建立后,广播会停止。
这也很好理解:设备已经进入连接状态,就不再继续以同一个广播实例对外广播。
八、Race Condition:竞态条件
官方文档最后有一个 Note:
There is a possible race condition if the Advertising_Enable parameter is set to 0x00 (Disable) and the Advertising_Type parameter is 0x00, 0x01, or 0x04. The advertisements might not be stopped before a connection is created, and therefore both the HCI_Command_Complete event and either an HCI_LE_Connection_Complete event or an HCI_LE_Enhanced_Connection_Complete event could be generated.翻译:
如果 Advertising_Enable 参数设置为 0x00,也就是禁用广播,并且 Advertising_Type 参数是 0x00、0x01 或 0x04,则可能存在竞态条件。广播可能还没来得及停止,连接就已经建立了。因此,可能同时产生 HCI_Command_Complete event,以及 HCI_LE_Connection_Complete event 或 HCI_LE_Enhanced_Connection_Complete event。这个点非常重要。
意思是:
Host 正准备关闭广播。 但是关闭广播命令还没完全生效时,某个中心设备已经发起连接并成功建立了连接。于是 Controller 可能既上报:
HCI_Command_Complete又上报:
HCI_LE_Connection_Complete或者:
HCI_LE_Enhanced_Connection_Complete这就是竞态条件。
在 App 或 Host 协议栈中,如果看到“关闭广播”和“连接建立”几乎同时发生,不要误以为一定是异常,也可能是规范允许的竞态行为。
九、Error 情况翻译与解释
官方文档列出了一些可能返回:
Invalid HCI Command Parameters 0x12的情况。
这些错误主要和:
Own_Address_Type Random Address Resolving List Public Address有关。
也就是说,广播使能失败,很多时候不是 Advertising_Enable 这个参数本身的问题,而是前面配置的地址类型不满足条件。
1. Own_Address_Type = 0x00,但设备没有 Public Address
错误条件:
Advertising_Enable is set to 0x01, the advertising parameters' Own_Address_Type parameter is set to 0x00, and the device does not have a public address.翻译:
Advertising_Enable 设置为 0x01,也就是使能广播; 广播参数中的 Own_Address_Type 设置为 0x00; 但是设备没有 Public Address。错误码:
Invalid HCI Command Parameters 0x12解释:
Own_Address_Type = 0x00表示使用 Public Device Address。
但是如果设备本身没有公共地址,那么 Controller 就无法用 Public Address 去发广播。
所以开启广播会失败。
2. Own_Address_Type = 0x01,但 Random Address 没有初始化
错误条件:
Advertising_Enable is set to 0x01, the advertising parameters' Own_Address_Type parameter is set to 0x01, and the random address for the device has not been initialized using the HCI_LE_Set_Random_Address command.翻译:
Advertising_Enable 设置为 0x01; 广播参数中的 Own_Address_Type 设置为 0x01; 但是设备的随机地址还没有通过 HCI_LE_Set_Random_Address command 初始化。错误码:
Invalid HCI Command Parameters 0x12解释:
Own_Address_Type = 0x01表示使用 Random Device Address。
但是在使用随机地址之前,需要先通过:
HCI_LE_Set_Random_Address设置随机地址。
如果没有设置,就直接开启广播,Controller 不知道该用哪个随机地址发广播,因此会返回参数错误。
3. Own_Address_Type = 0x02,但解析列表没有匹配项,且设备没有 Public Address
错误条件:
Advertising_Enable is set to 0x01, the advertising parameters' Own_Address_Type parameter is set to 0x02, the Controller's resolving list does not contain a matching entry, and the device does not have a public address.翻译:
Advertising_Enable 设置为 0x01; 广播参数中的 Own_Address_Type 设置为 0x02; Controller 的 resolving list 中没有匹配项; 并且设备没有 Public Address。错误码:
Invalid HCI Command Parameters 0x12解释:
Own_Address_Type = 0x02一般和可解析私有地址,也就是 Resolvable Private Address,相关。
如果解析列表里没有匹配项,并且设备又没有 Public Address 可以作为备用,那么 Controller 就无法确定应该使用什么地址进行广播。
因此开启广播失败。
4. Own_Address_Type = 0x03,但解析列表没有匹配项,且 Random Address 没有初始化
错误条件:
Advertising_Enable is set to 0x01, the advertising parameters' Own_Address_Type parameter is set to 0x03, the Controller's resolving list does not contain a matching entry, and the random address for the device has not been initialized using the HCI_LE_Set_Random_Address command.翻译:
Advertising_Enable 设置为 0x01; 广播参数中的 Own_Address_Type 设置为 0x03; Controller 的 resolving list 中没有匹配项; 并且设备的随机地址还没有通过 HCI_LE_Set_Random_Address command 初始化。错误码:
Invalid HCI Command Parameters 0x12解释:
这也是地址配置相关的问题。
如果使用的地址类型依赖 resolving list,但 resolving list 中没有匹配项,同时随机地址又没有初始化,那么 Controller 无法确定广播时使用的地址,所以开启广播失败。
十、R 和 MC 是什么意思?
错误表中 Type 一栏出现了:
R MC可以这样理解:
R = Remote MC = Module / Controller,也可以理解为本地 Controller 侧条件在这里,我们不需要过度纠结这个 Type 字段,重点是看 Condition。
这些错误的核心原因都是:
开启广播时,Own_Address_Type 对应的地址条件没有满足。所以如果执行:
HCI_LE_Set_Advertising_Enable返回:
Invalid HCI Command Parameters 0x12就应该优先检查:
Own_Address_Type 配置是否正确 是否有 Public Address 是否已经设置 Random Address Resolving List 是否有匹配项十一、广播使能命令在 Legacy 广播流程中的位置
完整的 BLE Legacy 广播配置流程通常是:
1. HCI_LE_Set_Advertising_Parameters 配置广播参数 2. HCI_LE_Set_Advertising_Data 配置广播数据 3. HCI_LE_Set_Scan_Response_Data 配置扫描响应数据 4. HCI_LE_Set_Advertising_Enable 开启广播如果使用 Random Address,可能还需要在前面加上:
HCI_LE_Set_Random_Address也就是:
1. HCI_LE_Set_Random_Address 设置随机地址 2. HCI_LE_Set_Advertising_Parameters 配置广播参数 3. HCI_LE_Set_Advertising_Data 配置广播数据 4. HCI_LE_Set_Scan_Response_Data 配置扫描响应数据 5. HCI_LE_Set_Advertising_Enable 开启广播所以HCI_LE_Set_Advertising_Enable是广播配置链路中的最后一步。
前面命令只是配置,只有这个命令执行成功后,Controller 才真正开始在空口上发送 Legacy 广播包。
十二、开启广播后,Controller 做了什么?
当 Host 发送:
HCI_LE_Set_Advertising_Enable Advertising_Enable = 0x01并且命令执行成功后,Controller 会根据之前配置的参数开始广播。
这些参数主要来自:
HCI_LE_Set_Advertising_Parameters包括:
Advertising_Interval_Min Advertising_Interval_Max Advertising_Type Own_Address_Type Peer_Address_Type Peer_Address Advertising_Channel_Map Advertising_Filter_Policy然后 Controller 会按照广播事件时序,在指定的 advertising channels 上发送广播 PDU。
例如:
Channel 37 Channel 38 Channel 39如果广播类型是:
ADV_IND那么 Controller 会发送可连接、可扫描的非定向广播。
如果扫描方是主动扫描,并且过滤策略允许,扫描方可以发送:
SCAN_REQ广播方收到后可以回复:
SCAN_RSP如果中心设备发起连接,并且广播类型允许连接,则可能进入连接建立流程。
十三、关闭广播后,Controller 做了什么?
当 Host 发送:
HCI_LE_Set_Advertising_Enable Advertising_Enable = 0x00并且命令执行成功后,Controller 会停止广播。
这意味着 Controller 不再继续发送 Legacy advertising PDU。
但要注意,关闭广播不等于清空广播参数。
也就是说,之前通过下面这些命令设置的参数和数据:
HCI_LE_Set_Advertising_Parameters HCI_LE_Set_Advertising_Data HCI_LE_Set_Scan_Response_Data不一定会因为关闭广播而全部消失。
通常可以理解为:
Disable advertising 是停止当前广播行为; 不是清空所有广播配置。如果后续再次 Enable,Controller 可能继续使用已有配置重新开始广播。
当然,具体细节也可能受 Controller 实现或厂商模块封装影响。
十四、为什么修改广播参数前通常要先关闭广播?
实际开发中,如果要修改广播参数、广播数据或扫描响应数据,通常建议先关闭广播,再修改配置,然后重新开启广播。
也就是:
1. Disable Advertising 2. Set Advertising Parameters 3. Set Advertising Data 4. Set Scan Response Data 5. Enable Advertising这样做比较稳妥。
因为很多参数在广播已经开启时可能不允许修改,或者修改行为存在限制。
例如你想修改:
Advertising_Type Own_Address_Type Advertising_Channel_Map Advertising_Data Scan_Response_Data最好先停止广播。
否则可能会遇到:
Command Disallowed Invalid HCI Command Parameters或者某些厂商 Controller 行为不一致的问题。
所以从实践角度看:
配置前先关闭,配置后再开启是更稳妥的流程。
十五、它和 App 端“开始广播”的关系
如果你在 Android 或 iOS 上调用系统 API 开启 BLE 广播,App 层通常不会直接接触 HCI Command。
例如 Android 里可能调用:
BluetoothLeAdvertiser.startAdvertising()或者:
BluetoothLeAdvertiser.startAdvertisingSet()iOS 里可能调用:
CBPeripheralManager.startAdvertising()但在系统蓝牙协议栈内部,最终会转换为 Controller 能理解的 HCI 命令。
对于 Legacy 广播场景,核心思想仍然类似:
配置广播参数 配置广播数据 开启广播其中开启广播这个动作,在 HCI 层就对应:
HCI_LE_Set_Advertising_Enable当然,实际手机系统可能做了很多封装、权限检查、参数适配和兼容处理,App 开发者通常看不到这些 HCI 命令。
十六、必要 Tip 总结
Tip 1:它是 Legacy 广播的启动 / 停止开关
HCI_LE_Set_Advertising_Enable最核心作用就是:
开始广播 停止广播它不负责配置广播内容,也不负责配置广播类型。
Tip 2:广播怎么发,由 Set Advertising Parameters 决定
广播使能命令只是开关。
广播的具体行为由:
HCI_LE_Set_Advertising_Parameters决定。
例如:
广播间隔 广播类型 地址类型 信道 Map 过滤策略都不是本命令配置的。
Tip 3:Advertising_Enable 只有两个有效值
0x00 = Disable advertising 0x01 = Enable advertising其他值都是保留值,不应该使用。
Tip 4:开启广播前要确保地址条件满足
如果使用 Public Address,设备必须有 Public Address。
如果使用 Random Address,必须先执行:
HCI_LE_Set_Random_Address如果使用和隐私相关的地址类型,还要考虑 resolving list 是否存在匹配项。
否则开启广播时可能返回:
Invalid HCI Command Parameters 0x12Tip 5:广播已经开启时再次开启,可能导致随机地址变化
规范中明确说:
Enabling advertising when it is already enabled can cause the random address to change.所以不要随便重复 Enable。
如果确实要重新配置广播,建议流程是:
Disable Configure EnableTip 6:广播已经关闭时再次关闭,没有影响
规范中也说明:
Disabling advertising when it is already disabled has no effect.所以重复 Disable 一般不会产生额外影响。
Tip 7:连接建立后,广播会停止
对于可连接广播,如果通过该广播建立了连接,Controller 会停止广播,并上报连接完成事件:
HCI_LE_Connection_Complete或者:
HCI_LE_Enhanced_Connection_CompleteTip 8:Disable 和连接建立可能发生竞态
如果 Host 正在关闭广播,但连接刚好在关闭前建立成功,那么可能同时看到:
HCI_Command_Complete和:
HCI_LE_Connection_Complete这不一定是异常,而是规范允许的竞态情况。
十七、一句话总结
HCI_LE_Set_Advertising_Enable 是 BLE Legacy 广播中的启动 / 停止开关。它通过:
Advertising_Enable = 0x01请求 Controller 开始广播。
通过:
Advertising_Enable = 0x00请求 Controller 停止广播。
但是广播的具体参数和数据不是由它决定的,而是由前面的:
HCI_LE_Set_Advertising_Parameters HCI_LE_Set_Advertising_Data HCI_LE_Set_Scan_Response_Data决定。
所以在 BLE Legacy 广播流程中,可以这样理解:
Set Advertising Parameters:配置广播怎么发 Set Advertising Data:配置广播包里放什么 Set Scan Response Data:配置扫描响应包里放什么 Set Advertising Enable:真正开始或停止广播