广播报文结构
BLE广播报文格式如下:
前导
接收机可根据前导码执行频率同步、符号时序预估和自动增益控制(AGC)训练。
LE 1M物理层上发送的数据包前导码为8比特;
LE 2M物理层上发送的数据包前导码为16比特。
LE Coded物理层数据包的前导码由10组二进制序列’00111100’构成,合计为80比特。
这里我们只讨论LE 1M物理层上的数据包,即前导是一个8比特的交替序列。
接入地址
接入地址为一个随机的4byte地址。对于广播来说,其值固定为0X8E89BED6。
接收机可以通过接入地址的值确定为广播包,以及防止数据信号干扰。
报头
广播报文的报头和数据报文的报头是不一样的。
对于广播报文来说,报头格式为 4bit广播报文类型 + 2bit预留值 + 1bit发送地址类型 + 1bit接收地址类型
广播报文类型
蓝牙内核协议中一共有7种广播报文类型,接收机根据4bit的类型值确定属于哪种广播类型。
发送地址类型和接收地址类型
共有两种地址类型,分别为公共地址(public address)和随机地址(random address)。
长度
这里指数据域的长度。
由于广播数据域为0~37byte,故用6bit表示。剩余的2bit预留。
数据
广播数据最大长度为37byte,为6byte MAC地址 + 31byte 实际数据组成。
对于广播包来说,6byte MAC地址是必须包含的,故剩余给用户的实际数据最大为31byte。
注: 对于数据包而言,不包含6byte MAC地址。故数据包长度为0~31byte,用5bit长度表示即可。
数据定义规则
广播包中的数据域使用LTV的格式进行定义,即 length + type + value
length表示(type + value)的总长度;
type为1byte数据类型,蓝牙协议规范定义类型如下:
/// The type of advertising data(not adv_type)
typedef enum {
ESP_BLE_AD_TYPE_FLAG = 0x01, /* relate to BTM_BLE_AD_TYPE_FLAG in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_16SRV_PART = 0x02, /* relate to BTM_BLE_AD_TYPE_16SRV_PART in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_16SRV_CMPL = 0x03, /* relate to BTM_BLE_AD_TYPE_16SRV_CMPL in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_32SRV_PART = 0x04, /* relate to BTM_BLE_AD_TYPE_32SRV_PART in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_32SRV_CMPL = 0x05, /* relate to BTM_BLE_AD_TYPE_32SRV_CMPL in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_128SRV_PART = 0x06, /* relate to BTM_BLE_AD_TYPE_128SRV_PART in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_128SRV_CMPL = 0x07, /* relate to BTM_BLE_AD_TYPE_128SRV_CMPL in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_NAME_SHORT = 0x08, /* relate to BTM_BLE_AD_TYPE_NAME_SHORT in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_NAME_CMPL = 0x09, /* relate to BTM_BLE_AD_TYPE_NAME_CMPL in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_TX_PWR = 0x0A, /* relate to BTM_BLE_AD_TYPE_TX_PWR in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_DEV_CLASS = 0x0D, /* relate to BTM_BLE_AD_TYPE_DEV_CLASS in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_SM_TK = 0x10, /* relate to BTM_BLE_AD_TYPE_SM_TK in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_SM_OOB_FLAG = 0x11, /* relate to BTM_BLE_AD_TYPE_SM_OOB_FLAG in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_INT_RANGE = 0x12, /* relate to BTM_BLE_AD_TYPE_INT_RANGE in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_SOL_SRV_UUID = 0x14, /* relate to BTM_BLE_AD_TYPE_SOL_SRV_UUID in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_128SOL_SRV_UUID = 0x15, /* relate to BTM_BLE_AD_TYPE_128SOL_SRV_UUID in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_SERVICE_DATA = 0x16, /* relate to BTM_BLE_AD_TYPE_SERVICE_DATA in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_PUBLIC_TARGET = 0x17, /* relate to BTM_BLE_AD_TYPE_PUBLIC_TARGET in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_RANDOM_TARGET = 0x18, /* relate to BTM_BLE_AD_TYPE_RANDOM_TARGET in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_APPEARANCE = 0x19, /* relate to BTM_BLE_AD_TYPE_APPEARANCE in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_ADV_INT = 0x1A, /* relate to BTM_BLE_AD_TYPE_ADV_INT in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_LE_DEV_ADDR = 0x1b, /* relate to BTM_BLE_AD_TYPE_LE_DEV_ADDR in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_LE_ROLE = 0x1c, /* relate to BTM_BLE_AD_TYPE_LE_ROLE in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_SPAIR_C256 = 0x1d, /* relate to BTM_BLE_AD_TYPE_SPAIR_C256 in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_SPAIR_R256 = 0x1e, /* relate to BTM_BLE_AD_TYPE_SPAIR_R256 in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_32SOL_SRV_UUID = 0x1f, /* relate to BTM_BLE_AD_TYPE_32SOL_SRV_UUID in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_32SERVICE_DATA = 0x20, /* relate to BTM_BLE_AD_TYPE_32SERVICE_DATA in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_128SERVICE_DATA = 0x21, /* relate to BTM_BLE_AD_TYPE_128SERVICE_DATA in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_LE_SECURE_CONFIRM = 0x22, /* relate to BTM_BLE_AD_TYPE_LE_SECURE_CONFIRM in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_LE_SECURE_RANDOM = 0x23, /* relate to BTM_BLE_AD_TYPE_LE_SECURE_RANDOM in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_URI = 0x24, /* relate to BTM_BLE_AD_TYPE_URI in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_INDOOR_POSITION = 0x25, /* relate to BTM_BLE_AD_TYPE_INDOOR_POSITION in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_TRANS_DISC_DATA = 0x26, /* relate to BTM_BLE_AD_TYPE_TRANS_DISC_DATA in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_LE_SUPPORT_FEATURE= 0x27, /* relate to BTM_BLE_AD_TYPE_LE_SUPPORT_FEATURE in stack/btm_ble_api.h */
ESP_BLE_AD_TYPE_CHAN_MAP_UPDATE = 0x28, /* relate to BTM_BLE_AD_TYPE_CHAN_MAP_UPDATE in stack/btm_ble_api.h */
ESP_BLE_AD_MANUFACTURER_SPECIFIC_TYPE = 0xFF, /* relate to BTM_BLE_AD_MANUFACTURER_SPECIFIC_TYPE in stack/btm_ble_api.h */
} esp_ble_adv_data_type;
部分常见类型定义解析如下:
value为具体数据类型定义的值。
校验
校验为24bit的CRC校验,对报头,长度和数据进行计算。
广播抓包分析
我们使用wireshark对广播包进行抓包分析,如下为所抓实际数据:
注意:
- 广播数据为小段模式,即低字节在前,如接入地址4byte为0X8E89BED6,在广播数据中的存在格式为 “d6 be 89 8e” 。
- 广播1byte前导是在接收时被底层处理掉,不会存在抓包后的广播数据中显示的。
- wireshark抓到的广播数据除了蓝牙本身数据外,还会增加软件自己的头信息。另我们去掉wireshark软件自带的头信息。
我们去掉wireshark自带的数据信息,实际广播数据是从4byte接入地址开始的,即 “d6 be 89 8e”。
根据广播包格式,在4byte接入地址后,为1byte的报头 + 1byte 的数据长度,这2byte组成了抓包数据中的Packet Header,如下:
Packet Header的数据解析格式如下:
根据解析格式,我们可以0x2520值解析如下: - RxAddr和TxAddr位均为0,表示使用的是Public address地址
- PDU Type为0000,表示使用的广播模式为通用广播
- Length为37,表示广播数据域长度为37byte
然后我们来看看37byte数据域的内容:
前面我们说过,广播包必须带6byte的MAC地址,这里的Advertising Address为 34:85:18:b8:35:82,即为广播设备的MAC地址。
还剩31byte的实际数据如下:
第1个LTV数据组合为L = 2,T = 0x01,V = ‘0000 0110’
L = 2, 表示T+V的数据长度为2bytre
T = 0x01, 表示数据类型为ESP_BLE_AD_TYPE_FLAG ,表示设置广播标志
在ESP32中是这么定义广播标志的:
/**
* @brief BLE_ADV_DATA_FLAG data flag bit definition used for advertising data flag
*/
#define ESP_BLE_ADV_FLAG_LIMIT_DISC (0x01 << 0)
#define ESP_BLE_ADV_FLAG_GEN_DISC (0x01 << 1)
#define ESP_BLE_ADV_FLAG_BREDR_NOT_SPT (0x01 << 2)
#define ESP_BLE_ADV_FLAG_DMT_CONTROLLER_SPT (0x01 << 3)
#define ESP_BLE_ADV_FLAG_DMT_HOST_SPT (0x01 << 4)
#define ESP_BLE_ADV_FLAG_NON_LIMIT_DISC (0x00 )
V = ‘0000 0110’,表示使用ESP_BLE_ADV_FLAG_GEN_DISC 和 ESP_BLE_ADV_FLAG_BREDR_NOT_SPT ,即使用通用广播发现模式,不支持BR/EDR。
依次类推:
第2个TLV数据组合为L = 3,T = 0x19, V = 0x0040 ,设置蓝牙外观显示。可以设置为手表、手机等等外观形式,这里设置成手机外观。
第3个TLV数据组合为L = 13,T = 0x09, V = CcBle-123456,为蓝牙名称
第4个TLV数据组合为L = 3, T = 0x03, V = 0x00ee, 为2byte广播UUID
第5个LTV数据组合为L = 5, T = 0x12,V = 6和16, 表示表示从机连接最小间隔和最大间隔时间。实际时间为 值*1.25毫秒
到此,一共5个LTV数据组合全部解析完成。
一共为5byte + L总长度(2+3+13+3+5) = 31byte,刚好与我们前面解析出来的31byte实际数据长度对应。
最后是3byte的CRC值。