BLE Legacy 广播【广播使能】

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取值如下ValueParameter Description0x00Advertising is disabled禁用广播默认值0x01Advertising is enabled使能广播All other valuesReserved for future use保留供将来使用也就是说Advertising_Enable 0x00表示关闭广播。Advertising_Enable 0x01表示开启广播。其他值不能使用。四、Return Parameters 翻译该命令返回一个参数Status大小1 octet取值如下ValueParameter Description0x00HCI_LE_Set_Advertising_Enable command 执行成功0x01 to 0xFFHCI_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竞态条件官方文档最后有一个 NoteThere 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 Controllers 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 Controllers 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 是停止当前广播行为 不是清空所有广播配置。如果后续再次 EnableController 可能继续使用已有配置重新开始广播。当然具体细节也可能受 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 3Advertising_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 8Disable 和连接建立可能发生竞态如果 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真正开始或停止广播