BLE广播报文和扫描报文解析

本文详细解析了蓝牙低功耗(BLE)广播报文的结构,包括前导、接入地址、报头、长度、数据部分和校验,以及实例中通过BLEAnalyzer捕获的peripheral广播包分析。讲解了如何构造广播和扫描响应数据,以及UUID的使用和压缩策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

关于广播和扫描报文的解析如果想从协议本身就了解可以从头看起,如果想直接看看芯片的开发怎么使用,可以直接从第2节,报文解析开始。

图1  BLE报文结构

1.1 前导

前导是一个8比特的交替序列。根据接入地址的第一个比特为0或者1,分01010101和10101010两种。接收机可以根据前导的无线信号强度来配置自动增益控制。

1.2 接入地址

  接入地址有两种类型:广播接入地址和数据接入地址。

  • 广播接入地址:固定为0x8E89BED6,在广播、扫描、发起连接时使用。
  • 数据接入地址:随机值,不同的连接有不同的值。在连接建立之后的两个设备间使用。

1.3 报头

1.3.1 广播报文报头

 图2  广播报文报头                      图3  Advertising channel PDU Headercore_v4.2 page 2583

1)广播报文类型

图3  广播报文类型  

  2) 发送地址类型和接收地址类型

  发送地址类型和接收地址类型指示了设备使用公共地址(Public Address)还是随机地址(Random Address)。公共地址和随机地址的长度一样,都包含6个字节共48位。BLE设备至少要拥有这两种地址类型中的一种,当然也可以同时拥有这两种地址类型。

  • 公共地址(Public Address)

  公共地址由两部分组成,如下图。公共地址由制造商从IEEE申请,由IEEE注册机构为该制造商分配的机构唯一标识符OUI(Organizationally Unique Identifier)。这个地址是独一无二,不能修改的。Core_v4.2 P2576的1.3.1节描述了公共地址。

图4  公共地址结构

  • 随机地址

随机地址有包含两种:静态地址(Static Device Address)和私有地址(PrivateDevice Address)。Core_v4.2 P2577的1.3.2.1节描述了静态地址。

随机地址有包含两种:静态地址(Static Device Address)和私有地址(PrivateDevice Address)。Core_v4.2 P2577的1.3.2.1节描述了静态地址。

静态地址有如下要求:

a)       静态地址的最高2位有效位必须是1。

b)       静态地址最高2位有效位之外的其余部分不能全为0和1。

在私有地址的定义当中,又包含了两个子类:不可解析私有地址(Non-resolvable Private Address)和可解析私有地址(Resolvable Private Address,RPA)。CH57x使用的是静态地址,芯片在出厂时自带全球唯一的48位MAC地址。在提供的driver代码中,有获取MAC的接口,可以直接调用。

图5  CH57x 获取芯片MAC接口函数

1.4 长度

广播报文:长度域包含6个比特,有效值的范围是6~37。

数据报文:长度域包含5个比特,有效值的范围是0~31。

广播报文和和数据报文的长度域有所不同,主要原因是:广播报文除了最多31个字节的数据之外,还必须要包含6个字节的广播设备地址。6+31=37,所以需要6比特的长度域。

再次强调:广播时必须要包含6个字节的广播设备地址。

1.5 数据(AdvData)

广播和扫面响应的数据格式如下图所示,由有效数据部分和无效数据部分组成。 

图6广播和扫描响应的数据格式

1)  有效数据部分:包含N个AD Structure,每个AD Structure由Length,AD Type和AD Data组成。其中:

Length:AD Type和AD Data的长度。

AD Type:指示AD Data数据的含义。

AD Type的意义可以通过下面2种方式查看AD Type和他们表示的意义。

从官网查询,但是需要是会员才可以查询。

  https://www.bluetooth.org/Technical/AssignedNumbers/generic_access_profile.htm

查看WCH的SDK中的定义,AD type的定义在程序的“CH57xBLE_LIB.h”头文件中。定义如下:

// GAP_ADTYPE_DEFINES GAP Advertisement Data Types

#define GAP_ADTYPE_FLAGS                         0x01 //!< Discovery Mode: @ref GAP_ADTYPE_FLAGS_MODES

#define GAP_ADTYPE_16BIT_MORE                   0x02 //!< Service: More 16-bit UUIDs available

#define GAP_ADTYPE_16BIT_COMPLETE               0x03 //!< Service: Complete list of 16-bit UUIDs

#define GAP_ADTYPE_32BIT_MORE                    0x04 //!< Service: More 32-bit UUIDs available

#define GAP_ADTYPE_32BIT_COMPLETE               0x05 //!< Service: Complete list of 32-bit UUIDs

#define GAP_ADTYPE_128BIT_MORE                   0x06 //!< Service: More 128-bit UUIDs available

#define GAP_ADTYPE_128BIT_COMPLETE              0x07 //!< Service: Complete list of 128-bit UUIDs

#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)

#define GAP_ADTYPE_OOB_SIMPLE_PAIRING_HASHC     0x0E //!< Simple Pairing OOB Tag: Simple Pairing Hash C (16 octets)

#define GAP_ADTYPE_OOB_SIMPLE_PAIRING_RANDR     0x0F //!< Simple Pairing OOB Tag: Simple Pairing Randomizer R (16 octets)

#define GAP_ADTYPE_SM_TK                         0x10 //!< Security Manager TK Value

#define GAP_ADTYPE_SM_OOB_FLAG                  0x11 //!< Security Manager OOB Flags

#define GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE    0x12 //!< Min and Max values of the 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

#define GAP_ADTYPE_SERVICES_LIST_128BIT        0x15 //!< Service Solicitation: list of 128-bit Service UUIDs

#define GAP_ADTYPE_SERVICE_DATA                  0x16 //!< Service Data - 16-bit UUID

#define GAP_ADTYPE_PUBLIC_TARGET_ADDR           0x17 //!< Public Target Address

#define GAP_ADTYPE_RANDOM_TARGET_ADDR           0x18 //!< Random Target Address

#define GAP_ADTYPE_APPEARANCE                     0x19 //!< Appearance

#define GAP_ADTYPE_ADV_INTERVAL                   0x1A //!< Advertising Interval

#define GAP_ADTYPE_LE_BD_ADDR                     0x1B //!< LE Bluetooth Device Address

#define GAP_ADTYPE_LE_ROLE                         0x1C //!< LE Role

#define GAP_ADTYPE_SIMPLE_PAIRING_HASHC_256     0x1D //!< Simple Pairing Hash C-256

#define GAP_ADTYPE_SIMPLE_PAIRING_RANDR_256     0x1E //!< Simple Pairing Randomizer R-256

#define GAP_ADTYPE_SERVICE_DATA_32BIT           0x20 //!< Service Data - 32-bit UUID

#define GAP_ADTYPE_SERVICE_DATA_128BIT          0x21 //!< Service Data - 128-bit UUID

#define GAP_ADTYPE_3D_INFO_DATA                  0x3D //!< 3D Information Data

#define GAP_ADTYPE_MANUFACTURER_SPECIFIC       0xFF //!< Manufacturer Specific Data: first 2 octets contain the Company Identifier Code followed by the additional manufacturer specific data

// GAP_ADTYPE_FLAGS_MODES GAP ADTYPE Flags Discovery Modes

#define GAP_ADTYPE_FLAGS_LIMITED                0x01 //!< Discovery Mode: LE Limited Discoverable Mode

#define GAP_ADTYPE_FLAGS_GENERAL                0x02 //!< Discovery Mode: LE General Discoverable Mode

#define GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED  0x04 //!< Discovery Mode: BR/EDR Not Supported

图7 广播类型定义

 1.6 校验 

BLE采用的是24位CRC校验。CRC对报头、长度和数据进行计算。24位CRC的生成多项式如下:

2.  广播包解析

通过上文的描述,我们对BLE广播包有了大致的了解,接下来我们用沁恒的BLE Analyzer捕获一个peripheral的广播包,通过对实际广播包的分析来理解BLE报文结构和广播。广播包捕获实验的硬件连接如下。

WCH_BLEAnalyzer.zip - 南京沁恒微电子股份有限公司(包含安装软件和使用说明)

        

3. 实例解析

以EXAM\BLE\Peripheral为例,进行广播和扫描报文的解释

 3.1 代码部分

// GAP - SCAN RSP data (max size = 31 bytes)

static uint8 scanRspData[ ] =

{

  // complete name

  0x12,   // length of this data                                                        AD Structure

  GAP_ADTYPE_LOCAL_NAME_COMPLETE,                                                      len + GAP_ADTYPE + data

  'S', 'i', 'm', 'p', 'l','e',' ','P','e','r','i','p','h','e','r','a','l',  

  // connection interval range

  0x05,   // length of this data

  GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,

  LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),   // 100ms                      AD Structure

  HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),                                   len + GAP_ADTYPE + data

  LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),   // 1s

  HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),

  // Tx power level

  0x02,   // length of this data                                                        AD Structure              GAP_ADTYPE_POWER_LEVEL,                                                                len + GAP_ADTYPE + data

  0       // 0dBm

};

// GAP - Advertisement data (max size = 31 bytes, though this is best kept short to conserve power while advertising)

static uint8 advertData[] =

{

  // Flags; this sets the device to use limited discoverable mode (advertises for 30 seconds at a time) instead of general discoverable mode (advertises indefinitely)

  0x02,   // length of this data                                                        AD Structure

  GAP_ADTYPE_FLAGS,                                                                          

  DEFAULT_DISCOVERABLE_MODE | GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED,

  // service UUID, to notify central devices what services are included in this peripheral

  0x03,   // length of this data

  GAP_ADTYPE_16BIT_MORE,      // some of the UUID's, but not all

  LO_UINT16( SIMPLEPROFILE_SERV_UUID ),                                               AD Structure

  HI_UINT16( SIMPLEPROFILE_SERV_UUID )

};

准备好广播和扫描报文数据,使用时需要将这些信息通过RF发出去,具体在代码中实现方式如下,使用到的函数如下:

蓝牙初始化函数如下:

BLE分析仪抓包

从上图可以看到:

第一行广播包,间隔时间约(Time:+54394us)50ms

广播包数据

看看PDU(Packet data)报头*1B+长度*1B+MAC*6B+数据

数据部分与advertData定义相同,如果需要添加数据部分,需要按照AD Structure的构造去添加。

后面2行是主机向地址0x84C2E4030252发起扫描请求(SCAN_REQ),然后设备对于扫描请求的响应(SCAN_RSP).

响应数据如下:

看看PDU(Packet data)报头*1B+长度*1B +MAC*6B+数据。

数据部分与scanRspData相同,如果修改需要按照AD Structure的构造去改造,并且保证长度不超过31B。

其他的AD Structure不过多的讲,着重说一下UUID:
UUID定义:

 “GATT层”中定义的所有属性都有一个UUID值,UUID是全球唯一的128位的号码,它用来识别不同的特性。

128位的UUID相当长,设备间为了识别数据的类型需要发送长达16字节的数据。为了提高传输效率,蓝牙技术联盟(SIG)定义了一个称为“UUID基数”的128位通用唯一识别码,结合一个较短的16位数使用。二者仍然遵循通用唯一识别码的分配规则,只不过在设备间传输常用的UUID时,只发送较短的16位版本,接收方收到后补上蓝牙UUID基数即可。

蓝牙UUID基数如下:

00000000 – 0000 – 1000 – 8000 – 008059B34FB

如要发送的16位UUID为0x2A01,完整的128的UUID便是:

00002A01 – 0000 – 1000 – 8000 – 008059B34FB

低功耗蓝牙使用的那部分UUID被分为下列几组:

l          0x1800 ~ 0x26FF:用作服务类通用唯一识别码。

l          0x2700 ~ 0x27FF:用于标识计量单位。

l          0x2800 ~ 0x28FF:用于区分属性类型。

l          0x2900 ~ 0x29FF:用作特性描述。

l          0x2A00 ~ 0x7FFF:用于区分特性类型。

### BLE广播类型及其数据包结构 #### 数据包结构概述 BLE(Bluetooth Low Energy)广播数据包是一种用于设备间无连接通信的方式。它允许外围设备周期性地发送短小的数据包至周围的空间,这些数据包可以携带多种信息,如设备名称、UUID服务数据等[^1]。 #### 广播类型的分类 BLE广播主要分为四种标准类型,每种类型适用于不同的应用场景: 1. **ADV_IND**: 可连接的不可定向广告。这种广播类型表示接收方可以通过发起连接请求来与广播设备建立连接。 2. **ADV_DIRECT_IND**: 定向广告。该广播仅针对特定的目标地址发出,通常用于快速建立一对一连接的情况。 3. **ADV_NONCONN_IND**: 不可连接的非定向广告。这类广播不接受来自任何设备的连接请求,主要用于单向数据传输场景。 4. **SCAN_REQ SCAN_RSP**: 扫描请求响应机制。当中心设备希望获取更多关于广播设备的信息时,它可以发送 `SCAN_REQ` 请求,随后广播设备会返回额外的数据作为 `SCAN_RSP` 响应[^2]。 #### 数据字段及格式说明 BLE广播数据包的最大有效载荷为31字节,在某些情况下可能通过扩展协议增加到更大的尺寸[^3]。以下是典型的广播数据包组成: - **Preamble (前导码)**: 占用1个字节,用于同步目的。 - **Access Address (访问地址)**: 长度固定为4字节,标识一个合法的BLE链路。 - **Payload (负载)**: 这是实际承载应用层数据的部分,具体包括以下几个子域: - **AD Structure Header (广告数据头)**: 表明后续跟随的是何种类型的服务或参数配置。 - AD Type 字段指示当前记录的具体含义,比如完整的本地名字 (`Complete Local Name`) 或者服务 UUID 列表(`Service UUIDs`) 等。 - AD Length 字段则指定了紧随其后的数据长度。 - **Advertising Data / Scan Response Data**: 实际的应用级数据区域,依据前面提到的不同广播模式填充相应的具体内容。 - **CRC Checksum (循环冗余校验位)**: 为了检测传输过程中可能出现错误的最后一部分附加信息,大小也是固定的三个八比特组[^5]。 对于需要更大容量的有效载荷情况,则可通过协商启用所谓的“Data Length Extension”功能,从而突破原有较小帧体带来的局限性[^4]。 ```python # 示例代码展示如何解析简单的BLE广播报文中的AD Structures部分 def parse_ad_structures(data_bytes): parsed_data = [] index = 0 while index < len(data_bytes): length = data_bytes[index] if not length or index + length >= len(data_bytes): break ad_type = data_bytes[index+1] value = data_bytes[(index+2):(index+length+1)] parsed_data.append({ 'Length': length, 'Type': ad_type, 'Value': bytes(value).hex() }) index += length + 1 return parsed_data example_payload = bytearray([7, 9, 82, 65, 83, 80, 73, 82, 90]) print(parse_ad_structures(example_payload)) ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值