如何配置蓝牙广播地址类型
概述
1 BLE_ADDR_TYPE_PUBLIC
这个是蓝牙的公共地址,它可以使用 esp32-s3 自带的,也可以使用自己设置,这个地址设置好了之后就是一直不变的。
1.1 自己设置 mac 地址
/*
设置 MAC 地址:
注意:要在初始化蓝牙控制器接口 esp_bt_controller_init() 之前设置 MAC 地址。esp_base_mac_addr_set() 会在地址最后一位或上 0x01 也有可能是加2
*/
uint8_t mac[6] = 0xbc, 0xdd, 0xc2, 0xd1, 0xc5 ,0x6F;
esp_base_mac_addr_set(mac);
//基本MAC必须是单播MAC(第一个字节的最低有效位必须为零)。
//E (403) system_api: Base MAC must be a unicast MAC
1.2 使用默认的 mac 地址
2 BLE_ADDR_TYPE_RANDOM
BLE_ADDR_TYPE_RANDOM 表示随机静态地址(Random Static Address),是一种固定的、不变的地址类型。虽然它也是随机生成的,但在设备生命周期内不会更改。
每次电源重启后设备可选择将其静态设备地址初始化并赋予新的静态地址值。设备完成初始化后在下一次电源重启前不得再修改其静态地址值。
备注: 设备的静态地址修改后存储其原来地址的对等设备将无法与其自动重连。
2.1 配置代码
static esp_ble_adv_params_t hidd_adv_params =
.adv_int_min = 0x20,
.adv_int_max = 0x30,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_RANDOM,
//.peer_addr =
//.peer_addr_type =
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
;
//设置地址的位置最好在广播数据配置之前 esp_ble_gap_set_rand_addr
case ESP_HIDD_EVENT_REG_FINISH:
if (param->init_finish.state == ESP_HIDD_INIT_OK)
esp_ble_gap_set_device_name(HIDD_DEVICE_NAME);
// esp_ble_gap_config_local_privacy(true); 这句是不需要的,是私有可解析的地址才会用到
uint8_t test_mac[6];
esp_fill_random(test_mac,6);
test_mac[0] = test_mac[0] | ((0x01 << 7) | (0x01 << 6));
esp_ble_gap_set_rand_addr(test_mac);
esp_ble_gap_config_adv_data(&hidd_adv_data);
break;
3 BLE_ADDR_TYPE_RPA_PUBLIC
3.1 ble_addr_type_rpa_public 的使用示例
- 将 BLE 设备的地址类型设置为 "ble_addr_type_rpa_public"。
- 在设备启动时,生成一个随机数作为低 24 位,并将上 24 位设置为公共设备 ID。
- 将生成的地址广播出去,以供其他设备扫描和连接。
这样,其他设备就可以使用公共设备 ID 来识别设备,并且每次设备启动时都会生成一个新的随机数,从而提高了设备的安全性和隐私性。同时,由于地址仍然是可解析的,因此其他设备可以继续与该设备通信。
这种类型的地址需要进行购买吗?
4 BLE_ADDR_TYPE_RPA_RANDOM
4.1 不可解析私有地址配置
不可解析私有地址随机部分和随机静态地址的随机部分是一样的,个人理解这两个地址的不同就在于,随机静态地址在电源重启之前都不能改变其地址。而不可解析私有地址可以在每次广播之前都可以改变自己的地址。
static esp_ble_adv_params_t hidd_adv_params =
.adv_int_min = 0x20,
.adv_int_max = 0x30,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_RPA_RANDOM,
//.peer_addr =
//.peer_addr_type =
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
;
//在蓝牙设备配置广播数据之前,设定一次蓝牙的 MAC 地址
case ESP_HIDD_EVENT_REG_FINISH:
if (param->init_finish.state == ESP_HIDD_INIT_OK)
//esp_bd_addr_t rand_addr = 0x04,0x11,0x11,0x11,0x11,0x05;
esp_ble_gap_set_device_name(HIDD_DEVICE_NAME);
// esp_ble_gap_config_local_privacy(true); // 这句是不需要的,是私有可解析的地址才会用到
uint8_t test_mac[6];
esp_fill_random(test_mac,6);
test_mac[0] = test_mac[0] & (~((0x01 << 7) | (0x01 << 6)));
esp_ble_gap_set_rand_addr(test_mac);
esp_ble_gap_config_adv_data(&hidd_adv_data);
break;
//每次断开连接之后,重新进行广播时,都重新设立一个 MAC 地址
case ESP_HIDD_EVENT_BLE_DISCONNECT:
sec_conn = false;
ESP_LOGI(HID_DEMO_TAG, "ESP_HIDD_EVENT_BLE_DISCONNECT");
uint8_t test_mac[6];
esp_fill_random(test_mac,6);
test_mac[0] = test_mac[0] & (~((0x01 << 7) | (0x01 << 6)));
esp_ble_gap_set_rand_addr(test_mac);
esp_ble_gap_start_advertising(&hidd_adv_params);
break;
4.2 可解析私有地址配置
只要设备里面保存的那几个密钥不改变,设备断电、重启等,都不会影响已配对设备的连接。但是删除配对之后就需要重新交换密钥才能连接了。
可解析地址对于未配对的设备来说是地址随机的,但是已配对的设备来说,这个地址却是已知的。
static esp_ble_adv_params_t hidd_adv_params =
.adv_int_min = 0x20,
.adv_int_max = 0x30,
.adv_type = ADV_TYPE_IND,
.own_addr_type = BLE_ADDR_TYPE_RPA_RANDOM,
//.peer_addr =
//.peer_addr_type =
.channel_map = ADV_CHNL_ALL,
.adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
;
// 可解析私有地址,只需要这一句(esp_ble_gap_config_local_privacy)即可,它的地址会由系统自动生成。
//这一句的最佳位置就是在配置广播数据之前。
esp_ble_gap_config_local_privacy(true); // 这句是不需要的,是私有可解析的地址才会用到
// uint8_t test_mac[6];
// esp_fill_random(test_mac,6);
// test_mac[0] = test_mac[0] & (~((0x01 << 7) | (0x01 << 6)));
// esp_ble_gap_set_rand_addr(test_mac);
esp_ble_gap_config_adv_data(&hidd_adv_data);
5 ble_addr_type_rpa_random 与 ble_addr_type_random 的区别
"ble_addr_type_rpa_random" 和 "ble_addr_type_random" 都是蓝牙设备地址类型的枚举值。
区别:
- "ble_addr_type_rpa_random" 表示随机私有地址(Random Private Address),也就是临时生成的、用于保护用户隐私的地址。每次设备启动时,都会生成一个新的随机私有地址。
- "ble_addr_type_random" 表示随机静态地址(Random Static Address),是一种固定的、不变的地址类型。虽然它也是随机生成的,但在设备生命周期内不会更改。
示例:
例如,如果一个蓝牙设备需要隐藏自己的身份并保护用户隐私,它可以使用随机私有地址作为蓝牙设备地址(即使用 "ble_addr_type_rpa_random")。而如果一个蓝牙设备只是需要一个随机的地址,并且不需要频繁更改,那么它可以使用随机静态地址作为蓝牙设备地址(即使用 "ble_addr_type_random")。
注
- 配对成功之后,改变广播地址类型,手机扫描到的广播地址仍然不会改变。此时只有先忘记配对,然后才能看到广播地址的改变。
- 可解析私有地址是可以实现自动重连的,不可解析私有地址不能实现自动重连。
- esp_ble_gap_set_rand_addr 此函数设置应用程序的静态随机地址和不可解析专用地址。
参考文档
- RPA和Static Random Address_ble_rpa
- 低功耗蓝牙(BLE)中的设备地址
BLE 中有两种角色 Central 和 Peripheral ,也就是中心设备和外围设备。中心设备可以主动连接外围设备,外围设备发送广播或者被中心设备连接。外围通过广播被中心设备发现,广播中带有外围设备自身的相关信息。
广播包 (Advertising Data)和 响应包 (Scan Response),其中广播包是每个设备必须广播的,而响应包是可选的。 数据包的格式如下图所示(图片来自官方 Spec):每个包都是 31 字节,数据包中分为有效数据(significant)和无效数据(non-significant)两部分。
Len
个字节是数据部分。数据部分的第一个字节表示数据的类型
AD
Type
AD type 非常关键,决定了 AD
Data 的数据代表的是什么和怎么解析,这个在后面会详细讲;
- 无效数据部分 :因为广播包的长度必须是 31 个 byte,如果有效数据部分不到 31 自己,剩下的就用 0 补全。这部分的数据是无效的,解释的时候,忽略即可。
所有的 AD type 的定义 如下类型:
Flags: TYPE = 0x01。这个数据用来标识设备 LE 物理连接的功能。DATA 是 0 到多个字节的 Flag 值,每个 bit 上用 0 或者 1 来表示是否为 True。如果有任何一个 bit 不为 0,并且广播包是可连接的,就必须包含此数据。各 bit 的定义如下:
- bit 0: LE 有限发现模式
- bit 1: LE 普通发现模式
- bit 2: 不支持 BR/EDR
- bit 3: 对 Same Device Capable(Controller) 同时支持 BLE 和 BR/EDR
- bit 4: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
- bit 5..7: 预留
- 特别注意的是 :
这里我们发现我们的广播数据为0x06,其实就是我们程序设计广播模式flag:
- flags = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
-
Service
UUID: 广播数据中一般都会把设备支持的 GATT Service 广播出来,用来告诉外面本设备所支持的 Service。有三种类型的
UUID:16 bit, 32bit, 128 bit。广播中,每种类型类型有有两个类别:完整和非完整的。这样就共有 6 种 AD Type。
- 非完整的 16 bit UUID 列表: TYPE = 0x02;
- 完整的 16 bit UUID 列表: TYPE = 0x03;
- 非完整的 32 bit UUID 列表: TYPE = 0x04;
- 完整的 32 bit UUID 列表: TYPE = 0x05;
- 非完整的 128 bit UUID 列表: TYPE = 0x06;
- 完整的 128 bit UUID 列表: TYPE = 0x07;
-
Local Name: 设备名字,DATA 是名字的字符串。 Local Name 可以是设备的全名,也可以是设备名字的缩写,其中缩写必须是全名的前面的若干字符。
- 设备全名: TYPE = 0x08
- 设备简称: TYPE = 0x09
-
TX Power Level: TYPE = 0x0A,表示设备发送广播包的信号强度。DATA 部分是一个字节,表示 -127 到 + 127 dBm。
-
带外安全管理(Security Manager Out of Band):TYPE = 0x11。DATA 也是 Flag,每个 bit 表示一个功能:
- bit 0: OOB Flag,0 表示没有 OOB 数据,1 表示有
- bit 1: 支持 LE
- bit 2: 对 Same Device Capable(Host) 同时支持 BLE 和 BR/EDR
- bit 3: 地址类型,0 表示公开地址,1 表示随机地址
-
外设(Slave)连接间隔范围:TYPE = 0x12。数据中定义了 Slave 最大和最小连接间隔,数据包含 4 个字节:
- 前 2 字节:定义最小连接间隔,取值范围:0x0006 ~ 0x0C80,而 0xFFFF 表示未定义;
- 后 2 字节:定义最大连接间隔,同上,不过需要保证最大连接间隔大于或者等于最小连接间隔。
-
服务搜寻:外围设备可以要请中心设备提供相应的 Service。其数据定义和前面的 Service UUID 类似:
- 16 bit UUID 列表: TYPE = 0x14
- 32 bit UUID 列表: TYPE = 0x??
- 128 bit UUID 列表: TYPE = 0x15
-
Service Data: Service 对应的数据。
- 16 bit UUID Service: TYPE = 0x16, 前 2 字节是 UUID,后面是 Service 的数据;
- 32 bit UUID Service: TYPE = 0x??, 前 4 字节是 UUID,后面是 Service 的数据;
- 128 bit UUID Service: TYPE = 0x??, 前 16 字节是 UUID,后面是 Service 的数据;
-
公开目标地址:TYPE = 0x17,表示希望这个广播包被指定的目标设备处理,此设备绑定了公开地址,DATA 是目标地址列表,每个地址 6 字节。
-
随机目标地址:TYPE = 0x18,定义和前一个类似,表示希望这个广播包被指定的目标设备处理,此设备绑定了随机地址,DATA 是目标地址列表,每个地址 6 字节。
-
Appearance:TYPE = 0x19,DATA 是表示了设备的外观。
-
厂商自定义数据: TYPE = 0xFF,厂商自定义的数据中,前两个字节表示厂商 ID,剩下的是厂商自己按照需求添加,里面的数据内容自己定义,我们的程序在这块添加了mac地址。
-
还有一些其他的数据,用的不多大家需要可以查阅核心手册。