配广播是 BLE 里最基础的一环也是最容易配错的一环。实际工作中最常见的三类问题想配置广播集controller 直接回一个Command Disallow广播看着开起来了扫描端却什么都收不到想用定向广播 RPA 保护隐私结果怎么都解析不出来对端。这三个问题的根因全部藏在下面这 8 条指令的参数里。而且 Legacy 和 Extended 两套指令长得像行为却完全不同。一、先做选择Legacy 还是 ExtendedBLE 的广播有两套 HCI 指令。它们解决的是同一个问题但能力边界差很多Legacy AdvertisingExtended Advertising参数指令LE Set Advertising Parameters0x2006LE Set Extended Advertising Parameters0x2036广播数据LE Set Advertising Data0x2008LE Set Extended Advertising Data0x2037扫描响应LE Set Scan Response Data0x2009LE Set Extended Scan Response Data0x2038开关指令LE Set Advertising Enable0x200ALE Set Extended Advertising Enable0x2039广播集标识无 handle只能有一份广播Advertising_Handle0–0xEF可多份广播数据长度0–0x1F31 字节通过 Operation / Fragment 机制支持分片隐私地址控制Own_Address_Type同左且 Peer 侧需为 Identity Address发射功率不在此指令中配置Advertising_TX_Power 可设时长与次数控制无Duration / Max Extended Advertising EventPHY 选择无Primary / Secondary PHY 可分别指定兼容传统广播就是传统广播通过 Event_Properties 的 bit4 可开传统广播一句话结论只要一份广播、数据不超 31 字节、不需要指定 PHY用 Legacy 就够了指令简单、兼容性最好。需要多广播集、更长的数据、独立控制时长/次数/功率用 Extended。注意Extended 不是只能开新式广播——Advertising_Event_Properties的 bit4 可以让它开传统广播这是很多人不知道的。二、Legacy Advertising四条指令2.1 LE Set Advertising Parameters Commandopcode0x2006① Advertising_Interval_Min / Advertising_Interval_Max各占 2 字节。Interval_Min必须小于等于Interval_Max。最佳实践给一个范围而不是固定值。由 controller 根据当前实际情况是否存在 BLE 连接、是否在 scan、是否处于 BT sniff mode、是否同时有 advertising 等在范围内取最合适的值。取值范围0x20–0x4000单位 625 μs即20 ms – 10.24 s。controller 内的默认值是0x08001.28 s。避坑如果设置的是High Duty Cycle Advertising这两个参数会被直接忽略设了也没意义。② Advertising_Type占 1 字节。决定advertising enable时使用什么样的 packet。③ Own_Address_Type / Peer_Address_Type各占 1 字节。这里有个容易踩的点——当Own_Address_Type设为0x02或0x03时controller 会根据Peer_Address从 resolving list 中找到对应的IRK用它生成Resolvable Private Address同时Advertising_Type必须设置为0x01或0x04也就是定向广播否则这套机制不生效。host 想开定向广播且Own_Address_Type设的是 RPA那么 controller 会从 resolving list 里找到Peer_Address对应的 IRK用这个 IRK 生成 RPA。从空口上看自己的广播地址就变成了 RPA。④ Advertising_Channel_Map占 1 字节。指定使用哪些 primary channel。三个信道不是每个都必须用但至少得选一个。⑤ Advertising_Filter_Policy避坑如果用的是定向广播这个参数会被直接忽略。过滤策略的含义是在处理连接请求和扫描请求时检查对端设备地址是否在Filter Accept List中不在就忽略。host 通过下面两条指令维护这张表LE Add Device To Filter Accept List commandopcode0x2011LE Remove Device From Filter Accept List command避坑很常见广播一旦打开就不能再对 Filter Accept List 做添加或移除操作了。要改先关广播。2.2 LE Set Advertising Data Commandopcode0x2008Advertising_Data_Length1 字节范围0 – 0x1F即 0–31 字节。特点这条指令可以在 advertising 已经打开的情况下使用不需要先关广播。2.3 LE Set Scan Response Data Commandopcode0x2009Scan_Response_Data_Length1 字节范围0 – 0x1F。同样可以在 advertising 已打开的情况下使用。2.4 LE Set Advertising Enable Commandopcode0x200A两个必须知道的行为打开可连接广播后只要有别的设备来连接广播会自动停止。关闭广播存在竞态。当 host 下发指令关闭广播时如果之前设置的是可连接类型有可能 controller 还没完成关闭动作就有设备来建立连接了。这会导致controller 可能同时返回HCI_Command_Complete和LE_Connection_Completeevent。避坑处理 event 的时候要把这种情况考虑进去别假设关了广播就一定不会再有连接事件。三、Extended Advertising四条指令3.1 LE Set Extended Advertising Parameters Commandopcode0x2036先说一条最容易踩的红线避坑这条指令可以指定某一个广播集但如果该广播集当前处于 enable 状态是不允许重新配置的——controller 会返回Command Disallow。相关参数① Advertising_Handle1 字节范围0 – 0xEF。指定哪一个广播集会被配置。② Advertising_Event_Properties2 字节。这个参数用来设置广播类型。注意 bit4 代表是否使用 legacy 广播——也就是说可以用这条指令去开启传统广播。③ Primary_Advertising_Interval_Min / Primary_Advertising_Interval_MaxMin必须小于等于Max。避坑如果设置了High Duty Cycle Connectable Directed Advertising这两个参数会被 controller 忽略。④ Primary_Advertising_Channel_Map选择哪个或哪些信道进行广播。⑤ Own_Address_Type / Peer_Address_Type避坑如果Own_Address_Type设为2或3那么Peer_Address的类型应该是 Identity Address——要么是 public address要么是 static identity address。其中 Own Address 是利用对端设备的 IRK生成的。【配图 10】Own_Address_Type / Peer_Address_Type 取值说明用一个例子把隐私地址解析说清楚设备 A 和 B 已经配对过并交换了 IRK。A 的解析列表中存有一条记录B 的 Identity Address和B 的 IRK。现在 A 想要主动找到并连接 B。而 B 为了隐私使用 RPA 进行广播它的 RPA 可能每分钟都在变。A 并不知道 B 当前的 RPA 是什么。A 下发连接指令其中Own_Address_Type使用0x02用 RPA 保护自己的隐私要找的设备是Peer_Address其身份地址是 B_Identity类型为Peer_Address_Type比如0x01静态随机地址。controller 收到指令后看到Own_Address_Type是0x02就知道要进入隐私模式。它用Peer_Address在解析列表中查找对应的IRK_B然后通过IRK_B为 A 生成一个RPA_A。A 开始扫描会收到很多广播包。当收到一个广播包时A 会用自己解析列表里所有的 IRK 去尝试解析广播包中的发送者地址。如果解析成功A 就知道这个广播来自 B于是向 B 发送连接请求。B 收到连接请求后看到发送者是RPA_A它同样用自己的解析列表去尝试解析解析成功后B 就知道这个连接请求来自 A。⑥ Advertising_TX_Power广播的最大功率。⑦ Advertising_Filter_Policy同 Legacy 的过滤策略。⑧ Primary_Advertising_PHY / Secondary_Advertising_PHY分别指定 primary 和 secondary 广播所用的 PHY。【配图 11】Primary / Secondary Advertising PHY 取值⑨ Secondary_Advertising_Max_Skip在必须发一个新的AUX_ADV_IND来更新 Secondary Advertising 的时间之前设备最多可以连续跳过多少个计划中的 Secondary Advertising Event。⑩ Advertising_SID设置的是 Extended Header 中的SID 字段。避坑如果广播中没有使用 ADI 字段这个参数会被忽略。⑪ Scan_Request_Notification_Enable决定当有扫描设备对广播发出扫描请求SCAN_REQ时controller 是否要向 host 发出一个通知来报告这个事件。这个参数是针对每个广播集单独设置的。是否触发通知取决于是否符合广播过滤策略——这是最重要的过滤条件允许任何扫描者所有SCAN_REQ都会触发通知。仅允许白名单中的扫描者只有当SCAN_REQ来自白名单中的设备时才会触发通知来自非白名单设备的请求会被忽略不会通知给 host。3.2 LE Set Extended Advertising Data Commandopcode0x2037这条指令用来设置指定广播集的广播数据。可以在广播集建立后的任何时间发送不管广播是否打开。① Advertising_Handle指定广播集。② Operation避坑语义容易搞错如果Operation是新数据的开始0x01或0x03那么当前存在的完整的、或者一部分的 advertising data将会被丢弃。如果广播数据被丢弃或者这条命令结束后广播数据的长度为 0那么这个广播集就是没有广播数据的广播。如果Operation是0x04说明广播数据没有变化唯一不同的是DID 字段。 DID 字段用于向 scanner 表明scanner 是否可以认为当前广播数据的内容与之前数据包中发送的 AdvData 相同。③ Fragment_Preference告诉 controller是否需要分割host 下发过来的 advertising data。3.3 LE Set Extended Scan Response Data Commandopcode0x2038用来设置指定广播集的 scan response 数据。同样可以在广播集建立后的任何时间发送不管广播是否打开。① Advertising_Handle指定广播集。② Operation / Fragment_Preference含义与LE Set Extended Advertising Data Command0x2037中的同名参数相同。③ Scan_Response_Data_Length④ Scan_Response_Data3.4 LE Set Extended Advertising Enable Commandopcode0x2039这条指令用来请求 controller打开或关闭一个或多个广播集。controller 依据LE Set Extended Advertising Parameters0x2036中的参数来管理这些广播的时序。如果Enable字段和Num_Set字段都设置为 0那么所有广播集都会被关闭。① Enable② Num_Set③ Advertising_Handle④ Duration设置广播多长时间后停止。如果为0则需要由 host 下发指令来停止。避坑如果是High Duty Cycle Connectable Directed Advertising这个值需要小于等于 1.28 秒而且不能设置为 0。⑤ Max_Extended_Advertising_Event当 controller 发送的 extended advertising event 数量超过这个值时就会停止广播。避坑如果这条指令在已经打开广播的情况下再次下发Duration和Max_Extended_Advertising_Event会被重置。四、广播会在什么时候停止完整汇总把散在各处的停止条件集中起来一共四种#停止原因出现的位置1被其他设备连接上了Legacy可连接广播被连接后自动停止Extended 同样2广播时间超过设置的 DurationExtended0x20393controller 发送的extended advertising event 数量超过 Max_Extended_Advertising_EventExtended0x20394host 下发指令停止广播两者的 Enable 指令均可五、避坑清单#坑正确做法1以为 High Duty Advertising 也能设广播间隔High Duty 时Interval_Min/Max 被忽略2Own_Address_Type设 0x02/0x03 却不生效此时Advertising_Type 必须是 0x01 或 0x04定向广播3Channel_Map一个信道都不选至少选一个primary channel4定向广播里还在调 Filter Policy定向广播时Filter Policy 被忽略5广播开着就去增删 Filter Accept List必须先关广播才能改6广播集 enable 状态下用 0x2036 重配会返回Command Disallow先关闭广播集7Extended 里 High Duty 还设 Primary Interval会被忽略80x2039 的 Duration 在 High Duty 下设为 0 或超 1.28sHigh Duty 下必须 ≤1.28s 且不能为 090x2037 用 0x01/0x03 却以为数据会追加该取值会丢弃已有广播数据10设了Advertising_SID却没生效广播未使用 ADI 字段时该参数被忽略11关广播后没处理连接事件可连接广播关闭存在竞态可能同时返回Command_Complete和Connection_Complete写在最后广播这块的坑基本都集中在两类地方状态相关的限制——广播开着的时候很多参数不能改Filter Accept List、0x2036 重配参数之间的依赖——Own_Address_Type和Advertising_Type必须配对Advertising_SID依赖 ADI 字段。
阅读完成 · 觉得有帮助?