
前面理解 BLE Legacy 广播时我们主要是在看这些 HCI CommandLE Set Advertising Parameters command LE Set Advertising Data command LE Set Scan Response Data command LE Set Advertising Enable command LE Set Scan Parameters command LE Set Scan Enable command这些命令更多是在讲怎么配置广播 怎么开启广播 怎么配置扫描 怎么开启扫描但是对于扫描端来说还有一个非常重要的问题扫描到广播包后Controller 怎么把结果告诉 Host这个就要看LE Advertising Report event对应事件名称HCI_LE_Advertising_Report它就是 BLE Legacy Scanning 中非常核心的“广播包回调结果”。一、LE Advertising Report event 是什么LE Advertising Report event是 Controller 上报给 Host 的事件。当 Controller 扫描到 BLE Legacy 广播包或者主动扫描时收到 Scan ResponseController 就可以通过这个事件把结果上报给 Host。可以简单理解为Controller 扫描到了广播包 然后通过 HCI_LE_Advertising_Report event 把扫描结果回调给 Host这个事件里面会包含设备地址 地址类型 广播事件类型 广播数据 广播数据长度 RSSI也就是说App 或 Host 层最终看到的很多扫描结果本质上都可以追溯到这个事件中的字段。二、官方描述翻译事件名称HCI_LE_Advertising_ReportEvent Code0x3E事件参数Subevent_Code Num_Reports Event_Type[i] Address_Type[i] Address[i] Data_Length[i] Data[i] RSSI[i]Description 翻译这个事件表示一个或多个 Bluetooth 设备响应了主动扫描或者表示在被动扫描期间接收到了一个或多个 Bluetooth 设备广播的 advertisement。Controller 可以把这些 advertising reports 排队并在一个HCI_LE_Advertising_Report event中发送来自多个设备的信息。这个事件只有在通过HCI_LE_Set_Scan_Enable命令启用了扫描之后才会生成。它只报告使用 Legacy Advertising PDU 的 advertising events。这段描述的重点这段描述里有几个关键点第一这个 event 是扫描开启后才会产生的。也就是说你必须先通过LE Set Scan Parameters LE Set Scan Enable配置并开启扫描然后 Controller 才可能上报LE Advertising Report event。第二它既可能上报普通广播包也可能上报 Scan Response。如果是被动扫描Controller 只能接收普通广播包。如果是主动扫描Controller 可能先收到广播包然后发送 Scan Request再收到对端返回的 Scan Response。第三一个LE Advertising Report event里面可能包含多个 report。所以不要简单理解为一个 event 一定只对应一个设备规范允许 Controller 把多个扫描结果一起上报。第四它只报告 Legacy Advertising PDU。如果是 Extended Advertising通常要看另外的扩展广播报告事件而不是这个 Legacy Advertising Report event。三、Event parameters 翻译下面逐个翻译事件参数。1. Subevent_Code大小1 octet取值0x02含义Subevent code for the HCI_LE_Advertising_Report event翻译HCI_LE_Advertising_Report event 对应的子事件码这里要注意HCI_LE_Advertising_Report的 Event Code 是0x3E而Subevent_Code是0x02原因是 LE 相关事件很多都通过LE Meta Event来承载。也就是说外层 Event Code 是0x3E表示这是一个 LE Meta Event。里面再通过Subevent_Code区分具体是哪一种 LE 事件。所以这里的关系是Event Code 0x3E 表示 LE Meta Event Subevent Code 0x02 表示 LE Advertising Report event2. Num_Reports大小1 octet取值0x01 to 0x19含义Number of responses in event.翻译该 event 中包含的 report 数量。其他值Reserved for future use翻译保留供未来使用。这个字段非常重要。因为后面的字段都是数组Event_Type[i] Address_Type[i] Address[i] Data_Length[i] Data[i] RSSI[i]其中i的范围就是0 到 Num_Reports - 1也就是说Num_Reports 1 表示这次 event 里只有 1 条广播报告 Num_Reports 3 表示这次 event 里有 3 条广播报告解析时不能只固定按一条 report 解析。3. Event_Type[i]大小Num_Reports × 1 octet它表示第 i 条 report 的广播事件类型。取值如下0x00Connectable and scannable undirected advertising (ADV_IND) 0x01Connectable directed advertising (ADV_DIRECT_IND) 0x02Scannable undirected advertising (ADV_SCAN_IND) 0x03Non connectable undirected advertising (ADV_NONCONN_IND) 0x04Scan Response (SCAN_RSP) 其他值Reserved for future use翻译如下0x00可连接、可扫描的非定向广播也就是 ADV_IND 0x01可连接的定向广播也就是 ADV_DIRECT_IND 0x02可扫描的非定向广播也就是 ADV_SCAN_IND 0x03不可连接的非定向广播也就是 ADV_NONCONN_IND 0x04扫描响应也就是 SCAN_RSP 其他值保留供未来使用Event_Type 的重点理解Event_Type不是告诉你“这是哪个设备”而是告诉你这条 report 对应的空口广播 PDU 类型是什么例如Event_Type 0x00 表示扫描到的是 ADV_INDADV_IND 的特点是可连接 可扫描 非定向所以 Central 可以对它发起连接也可以在主动扫描时向它发送 Scan Request获取 Scan Response。再比如Event_Type 0x04表示这条 report 不是普通广播包而是SCAN_RSP 扫描响应包所以如果你看到同一个设备先上报了一条ADV_IND后面又上报一条SCAN_RSP这是正常现象。因为主动扫描时流程大致是Peripheral 发出 ADV_IND 或 ADV_SCAN_IND Central 扫描到后发送 SCAN_REQ Peripheral 回复 SCAN_RSP Controller 上报 Advertising Report4. Address_Type[i]大小Num_Reports × 1 octet它表示第 i 条 report 中广播设备地址的地址类型。取值如下0x00Public Device Address 0x01Random Device Address 0x02Public Identity Address对应已解析的 RPA 0x03Random static Identity Address对应已解析的 RPA 其他值Reserved for future use翻译如下0x00公共设备地址 0x01随机设备地址 0x02公共身份地址对应已解析的 RPA 0x03随机静态身份地址对应已解析的 RPA 其他值保留供未来使用这里的重点是Address_Type 和 Address 要一起看不要只看 Address 字符串。因为同一个 48-bit 地址值在不同 Address_Type 下含义可能不同。Address_Type 中的 Identity Address 怎么理解这里比较容易困惑的是0x02Public Identity Address 0x03Random static Identity Address这两个值和 RPA 有关。RPA 是Resolvable Private Address也就是可解析私有地址。如果对端使用 RPA空口中看到的地址会变化。但是如果 Controller 通过 Resolving List 和 IRK 成功解析了这个 RPA那么它可以在上报给 Host 时把地址类型上报为 Identity Address。所以Address_Type 0x02 表示这个地址是 Public Identity Address并且对应一个已经解析的 RPA Address_Type 0x03 表示这个地址是 Random static Identity Address并且对应一个已经解析的 RPA简单说0x00 / 0x01更像是直接看到的设备地址类型 0x02 / 0x03更像是 Controller 解析 RPA 后上报的身份地址类型这也是为什么 BLE 地址不能只说“MAC 地址”还要看Address Value Address Type5. Address[i]大小Num_Reports × 6 octets含义Public Device Address, Random Device Address, Public Identity Address or Random static Identity Address of the advertising device.翻译广播设备的 Public Device Address、Random Device Address、Public Identity Address 或 Random static Identity Address。也就是说这个字段是第 i 条 report 对应设备的地址值。它是6 octets也就是48-bit 地址例如AA:BB:CC:DD:EE:FF但是再次强调Address 不能脱离 Address_Type 单独理解完整描述一个 BLE 广播设备地址应该是Address_Type Address6. Data_Length[i]大小Num_Reports × 1 octet取值0x00 to 0x1F含义Length of the Data[i] field for the device which responded.翻译该响应设备的 Data[i] 字段长度。其他值Reserved for future use翻译保留供未来使用。这里的0x1F就是十进制 31。也就是说在 Legacy Advertising Report 中单条 report 的数据长度最大是31 bytes这和 Legacy Advertising Data / Scan Response Data 最大 31 字节是对应的。所以Data_Length 0x1F 表示 Data 字段长度为 31 字节如果Data_Length 0x00表示这条 report 没有携带广告数据或扫描响应数据。7. Data[i]大小SUM(Data_Length[i]) octets含义Data_Length[i] octets of advertising or scan response data formatted as defined in [Vol 3] Part C, Section 11.翻译长度为 Data_Length[i] 字节的 advertising data 或 scan response data其格式按照规范 [Vol 3] Part C, Section 11 定义。注意该数组中的每个元素长度是可变的。这句话非常关键。因为每条 report 的Data_Length[i]可能不一样所以Data[i]不是固定长度数组。解析时要根据每条 report 自己的Data_Length[i]来截取对应的数据。Data[i] 怎么解析Data[i]就是我们经常说的广播数据 扫描响应数据它内部通常由多个 AD Structure 组成。每个 AD Structure 的格式一般是Length AD Type AD Data例如02 01 06可以解析为02长度表示后面还有 2 个字节 01AD TypeFlags 06AD Data再例如09 09 46 53 43 2D 42 54 39 37可以解析为09长度表示后面还有 9 个字节 09AD TypeComplete Local Name 46 53 43 2D 42 54 39 37名称数据也就是 FSC-BT97所以 HCI_LE_Advertising_Report 中的Data[i]不是直接一个“字符串”而是一段需要继续按照 AD Structure 格式解析的原始数据。8. RSSI[i]大小Num_Reports × 1 octet取值范围-127 to 20单位dBm特殊值0x7FRSSI is not available翻译0x7FRSSI 不可用RSSI 表示 Controller 接收到该广播包或扫描响应包时的接收信号强度。但是要特别注意RSSI 不能直接等同于距离RSSI 会受到很多因素影响例如发射功率 天线方向 人体遮挡 墙体遮挡 环境反射 手机型号 模块天线设计 当前信道所以看到 RSSI 更强只能粗略说明“接收信号更强”不能严格说明“距离一定更近”。如果要用来粗略估计远近至少应该结合广播中的 TX Power Level 或设备已知发射功率一起看。四、这个 event 和 LE Set Scan Enable 的关系规范中特别说This event shall only be generated if scanning was enabled using the HCI_LE_Set_Scan_Enable command.翻译过来就是只有通过 HCI_LE_Set_Scan_Enable 开启扫描后才会生成这个事件。所以 Legacy Scanning 的基本链路可以这样理解1. Host 发送 HCI_LE_Set_Scan_Parameters 配置扫描类型、扫描间隔、扫描窗口、地址类型、过滤策略等 2. Host 发送 HCI_LE_Set_Scan_Enable 开启扫描 3. Controller 在空口上接收 Legacy Advertising PDU 4. Controller 通过 HCI_LE_Advertising_Report event 把扫描结果上报给 Host也就是说LE Set Scan Enable 负责开启扫描 LE Advertising Report event 负责返回扫描结果一个是 Command一个是 Event。五、主动扫描和被动扫描下的回调区别BLE Legacy Scanning 里有两种扫描方式Passive Scanning Active Scanning也就是被动扫描 主动扫描1. Passive Scanning被动扫描只听广播不主动发送 Scan Request。所以它通常只能收到ADV_IND ADV_DIRECT_IND ADV_SCAN_IND ADV_NONCONN_IND也就是广播包本身。它不会因为自己主动请求而收到SCAN_RSP所以在被动扫描中通常不会看到Event_Type 0x04的 Scan Response。2. Active Scanning主动扫描不仅听广播还可以在扫描到可扫描广播后发送SCAN_REQ对端 Peripheral 收到后如果允许响应就会回复SCAN_RSP这时 Controller 就可能上报Event_Type 0x04也就是 Scan Response。所以主动扫描下同一个设备可能会出现两条 report第一条ADV_IND 或 ADV_SCAN_IND 第二条SCAN_RSP这就是为什么有时候 App 层看到同一个设备的广播数据和扫描响应数据是分开来的。很多 BLE App 会把同一个 Address 的广播包和扫描响应包合并显示例如广播包里放 Flags、Service UUID、Manufacturer Data 扫描响应包里放 Complete Local Name六、Event_Type 和 Legacy Advertising PDU 的对应关系Event_Type可以帮助我们判断扫描到的是哪种 Legacy 广播 PDU。对应关系如下Event_Type 0x00 ADV_IND 可连接、可扫描、非定向广播 Event_Type 0x01 ADV_DIRECT_IND 可连接、定向广播 Event_Type 0x02 ADV_SCAN_IND 可扫描、非定向广播 Event_Type 0x03 ADV_NONCONN_IND 不可连接、非定向广播 Event_Type 0x04 SCAN_RSP 扫描响应进一步理解ADV_IND 既可以被连接也可以被主动扫描获取扫描响应 ADV_DIRECT_IND 定向给某个目标设备主要用于快速建立连接 ADV_SCAN_IND 不能连接但可以扫描请求扫描响应 ADV_NONCONN_IND 不能连接也不能扫描只是单向广播数据 SCAN_RSP 不是普通广播事件而是对 Scan Request 的响应所以当你拿到Event_Type时就能初步判断这个设备是否可连接 这个设备是否可扫描 这条数据是不是扫描响应七、Data_Length 为什么最大是 0x1FData_Length[i]的取值是0x00 to 0x1F0x1F十进制就是 31。这和 BLE Legacy 广播数据最大 31 字节是对应的。Legacy Advertising 中Advertising Data 最大 31 bytes Scan Response Data 最大 31 bytes所以在LE Advertising Report event中单条 report 上报的数据长度最大也是 31 字节。需要注意Advertising Data 最大 31 字节 Scan Response Data 最大 31 字节这两个是分开的。所以一个设备在主动扫描场景下可能通过ADV_IND / ADV_SCAN_IND 上报最多 31 字节 Advertising Data SCAN_RSP 上报最多 31 字节 Scan Response Data合起来 App 层可能看到更多信息但在 HCI Report 中通常是分两条 report 上报的。八、Num_Reports 多条报告时怎么解析因为 Controller 可以把多个 advertising reports 排队然后在一个 event 中一起上报所以解析时一定要注意Num_Reports。事件参数不是简单的Event_Type Address_Type Address Data_Length Data RSSI而是数组形式Event_Type[i] Address_Type[i] Address[i] Data_Length[i] Data[i] RSSI[i]其中i 0, 1, 2, ... Num_Reports - 1而且Data[i]是变长字段。所以实际解析时要按照顺序逐条解析。可以理解为先读 Subevent_Code 再读 Num_Reports 然后读取 Num_Reports 个 Event_Type 然后读取 Num_Reports 个 Address_Type 然后读取 Num_Reports 个 Address 然后读取 Num_Reports 个 Data_Length 然后根据每个 Data_Length 读取对应长度的 Data 最后读取 Num_Reports 个 RSSI注意这里不是每条 report 完全连续地按Event_Type Address_Type Address Data_Length Data RSSI这种结构简单重复。规范表格里是数组字段顺序解析 HCI event payload 时应按照规范字段顺序处理。这是写底层解析时很容易踩坑的地方。九、RSSI 要怎么看RSSI 是扫描结果里最常被使用、也最容易被误用的字段。它的单位是dBm范围是-127 到 20例如RSSI -40 dBm通常说明信号比较强。RSSI -85 dBm通常说明信号比较弱。但是不能直接说RSSI -40所以距离一定是 1 米 RSSI -80所以距离一定是 10 米这是不严谨的。因为 RSSI 不是距离它只是接收信号强度。同一个距离下不同模块、不同手机、不同方向、不同遮挡、不同广播信道RSSI 都可能明显不同。比较合理的说法是RSSI 可以用于粗略判断信号强弱 RSSI 可以在同一环境、同一设备、同一条件下做相对比较 RSSI 不应该单独作为准确测距依据如果广播数据里带有 TX Power Level可以结合 TX Power 和 RSSI 做更合理的粗略判断。十、Address_Type Address 才是完整地址信息在 Advertising Report 中有两个字段Address_Type[i] Address[i]这两个字段要一起看。例如Address_Type 0x00 Address AA:BB:CC:DD:EE:FF表示Public Device Address而Address_Type 0x01 Address AA:BB:CC:DD:EE:FF表示Random Device Address虽然地址值看起来一样但是地址类型不同语义就不同。所以更规范的表达不是只说蓝牙 MAC 地址是 AA:BB:CC:DD:EE:FF而应该说Address_Type Public Device Address Address AA:BB:CC:DD:EE:FF或者Address_Type Random Device Address Address AA:BB:CC:DD:EE:FF这也是 BLE 地址体系容易让人混乱的地方。十一、Data[i] 不是“设备名”而是广播数据原始内容很多 App 层会直接显示name manufacturer data service uuid service data但在 HCILE Advertising Report event中真正上报的是Data[i]这是一段 AD Structure 原始数据。里面可能包含Flags Incomplete List of Service UUIDs Complete List of Service UUIDs Shortened Local Name Complete Local Name TX Power Level Manufacturer Specific Data Service Data Appearance等等。所以设备名不是单独一个固定字段它通常是从Data[i]里的 AD Structure 解析出来的。例如 AD Type0x08Shortened Local Name 0x09Complete Local Name如果广播包里没有名称但扫描响应包里有名称那么 App 可能要等收到SCAN_RSP后才能显示名称。这也是为什么有些 BLE 设备一开始扫描出来没有名字过一会儿才出现名字。十二、Advertising Report 只报告 Legacy Advertising PDU规范中特别说It only reports advertising events that used legacy advertising PDUs.翻译它只报告使用 Legacy Advertising PDU 的 advertising events。所以这个事件对应的是 Legacy Advertising。如果设备使用的是 Extended Advertising那么扫描结果通常不通过这个事件上报而要看扩展扫描相关事件例如LE Extended Advertising Report event所以文章标题叫BLE Legacy 广播【广播包回调】这个范围要明确这里讲的是 Legacy Advertising Report 不是 Extended Advertising Report十三、一个典型扫描结果怎么理解假设 Controller 上报了一条 reportSubevent_Code 0x02 Num_Reports 0x01 Event_Type[0] 0x00 Address_Type[0] 0x01 Address[0] C1:22:33:44:55:66 Data_Length[0] 0x0A Data[0] 02 01 06 06 09 48 65 6C 6C 6F RSSI[0] -55 dBm可以理解为这是一个 LE Advertising Report event 本次 event 中有 1 条 report 这条 report 是 ADV_IND 也就是可连接、可扫描、非定向广播 广播设备地址类型是 Random Device Address 地址是 C1:22:33:44:55:66 广播数据长度是 10 字节 广播数据内容是 02 01 06 06 09 48 65 6C 6C 6F RSSI 是 -55 dBm进一步解析 Data02 01 06表示Flags 0x0606 09 48 65 6C 6C 6F表示Complete Local Name Hello所以这条扫描结果最终可以理解为扫描到一个使用随机地址的 BLE 设备 地址为 C1:22:33:44:55:66 广播类型为 ADV_IND 设备名为 Hello RSSI 为 -55 dBm十四、主动扫描下 ADV_IND 和 SCAN_RSP 的合并问题假设同一个设备广播数据和扫描响应数据是分开放的Advertising Data02 01 06 03 02 F0 FFScan Response Data09 09 46 53 43 2D 42 54 39 37那么主动扫描时Controller 可能会上报两条 report第一条Event_Type 0x00 Data 02 01 06 03 02 F0 FF第二条Event_Type 0x04 Data 09 09 46 53 43 2D 42 54 39 37其中Event_Type 0x04表示第二条是SCAN_RSPApp 层如果想完整展示设备信息就需要根据设备地址把这两条数据合并起来理解。所以不要误以为扫描回调只有一条数据 所有广播内容都在同一个 Data 里在 Legacy 广播中广播数据和扫描响应数据本来就是两个不同的数据来源。十五、和 Android / iOS 扫描结果的关系在 Android 或 iOS App 层我们通常不会直接看到 HCI Event 的原始结构。系统蓝牙协议栈会帮我们做一层封装。例如 App 层可能看到device address device name RSSI advertisementData manufacturerData serviceUUIDs serviceData这些字段很多都是从 HCI 的 Advertising Report 进一步解析、加工、合并而来的。可以粗略理解为HCI_LE_Advertising_Report event ↓ 系统蓝牙协议栈解析 ↓ App 层扫描回调所以当我们在 App 层看到RSSI 广播数据 设备名 Manufacturer Data Service UUID背后都可以回到 HCI Advertising Report 的这些字段去理解Address_Type Address Data_Length Data RSSI Event_Type十六、必要 Tip 总结Tip 1这个事件是扫描结果不是广播配置命令LE Advertising Report event是 Event不是 Command。它不是 Host 发给 Controller 的命令而是 Controller 扫描到广播后上报给 Host 的结果。CommandHost - Controller EventController - HostTip 2必须开启扫描后才会产生只有通过HCI_LE_Set_Scan_Enable开启扫描后Controller 才会生成这个事件。Tip 3它只对应 Legacy Advertising这个事件只报告 Legacy Advertising PDU。Extended Advertising 要看 Extended Advertising Report 相关事件。Tip 4一个 Event 里可能包含多个 Report不要默认一个 event 只有一个设备。要看Num_Reports然后按数组字段解析Event_Type[i] Address_Type[i] Address[i] Data_Length[i] Data[i] RSSI[i]Tip 5Event_Type 可以判断广播包类型例如0x00ADV_IND 0x02ADV_SCAN_IND 0x03ADV_NONCONN_IND 0x04SCAN_RSP通过它可以知道这条 report 是普通广播包还是扫描响应包。Tip 6Address_Type 和 Address 必须一起看BLE 地址不是只看 48-bit 地址值。完整理解应该是Address_Type Address尤其在 Public Address、Random Address、Identity Address、RPA 解析场景下这一点非常重要。Tip 7Data 是 AD Structure 原始数据Data[i]不是简单字符串而是广播数据或扫描响应数据。它要继续按Length AD Type AD Data格式解析。设备名、Manufacturer Data、Service UUID 等都是从这里进一步解析出来的。Tip 8RSSI 不是距离RSSI 单位是 dBm表示接收信号强度。它可以粗略反映信号强弱但不能单独准确表示距离。如果要粗略估计远近最好结合 TX Power、设备环境、信道、历史数据一起看。十七、总结LE Advertising Report event是 BLE Legacy Scanning 中非常核心的扫描结果回调事件。它的作用是Controller 在扫描到 Legacy Advertising PDU 后 通过 HCI_LE_Advertising_Report event 把广播报告上报给 Host。它包含的信息主要有Subevent_Code Num_Reports Event_Type[i] Address_Type[i] Address[i] Data_Length[i] Data[i] RSSI[i]其中最常用、最关键的是Event_Type 判断广播事件类型比如 ADV_IND、ADV_SCAN_IND、SCAN_RSP Address_Type Address 表示广播设备地址信息 Data_Length Data 表示广播数据或扫描响应数据 RSSI 表示接收信号强度一句话总结LE Advertising Report event 就是 BLE Legacy 扫描时 Controller 把“扫描到了谁、是什么广播类型、广播数据是什么、信号强度是多少” 上报给 Host 的事件。对于 App 开发来说系统扫描回调里看到的设备地址、设备名、RSSI、Manufacturer Data、Service UUID 等信息底层都可以从这个事件的字段继续理解。