一个 BLE 设备,可以使用两种类型的地址(一个 BLE 设备可同时具备两种地址):
在通信系统中,设备地址是用来唯一识别一个物理设备的,如TCP/IP网络中的MAC地址、传统蓝牙中蓝牙地址等。对设备地址而言,一个重要的特性,就是唯一性。
对于经典蓝牙(BR/EDR)来说,其设备地址是一个 48bits 的数字,称作“48-bit universal LAN MAC address”。正常情况下,该地址需要向 IEEE 申请,具有唯一性。
这种地址分配方式在 BLE 中也保留了下来,就是公共设备地址(Public Device Address)。由 24-bit 的 company_id 和 24-bit 的 company_assigned 组成。
高 24 位是公司标识,低 24 位公司内部自己赋值。
但是,在 BLE 时代,只有公共设备地址明显不够用了,有如下原因:
为了解决上述问题,BLE 协议新增了一种地址:随机设备地址,即设备地址不是固定分配的,而是在设备启动后随机生成的。根据不同的目的,随机设备地址分为静态设备地址和私密设备地址。
静态设备地址是设备在上电时随机生成的地址,NRF52832 官方工程默认都是使用静态地址
,其格式如下:
静态设备地址的特征可总结为:
静态设备地址的使用场景可总结为:
静态设备地址通过地址随机生成的方式,解决了部分问题。私密设备地址则更进一步,通过定时更新和地址加密两种方式,提高蓝牙地址的可靠性和安全性。根据设备地址是否加密,又分为两类:
① 不可解析私密地址 Non-resolvable Private Address
不可解析私密地址和静态设备地址类似,不同之处在于不可解析私密地址会定时更新。更新的周期是由 GAP 规定的,称作 T_GAP(private_addr_int),建议值是 15 分钟。其格式如下:
不可解析私密地址的特征可总结为:
② 可解析私密地址 Resolvable Private Address
可解析私密地址比较有用,它通过一个随机数和一个称作 identity resolving key(IRK) 的密码生成,因此只能被拥有相同 IRK 的设备扫描到,可以防止被未知设备扫描和追踪。其格式如下:
可解析私密地址的特征可总结为:
使用抓包工具抓取类似如下数据包:
其中数据包第 6 部分:
其中 TxAdd 表示发送方的地址类型(0 为 public,1为 random)。
RxAdd 表示接收方的地址类型。
对于普通广播来说,只有 TxAdd 的指示是有效的,表示广播发送者的第一类型。而对于定向广播来说,TxAdd 和 RxAdd 都是有效的。
其中数据包第 7 部分:
如果是随机设备地址,则查看地址的最高两位。
#include "ble_gap.h"
ble_gap_addr_t bleAddr;
BLE 的地址由 ble_gap_addr_t
进行管理:
/**@brief Bluetooth Low Energy address. */
typedef struct
{
uint8_t addr_id_peer : 1; /**< Only valid for peer addresses.
This bit is set by the SoftDevice to indicate whether the address has been resolved from
a Resolvable Private Address (when the peer is using privacy).
If set to 1, @ref addr and @ref addr_type refer to the identity address of the resolved address.
This bit is ignored when a variable of type @ref ble_gap_addr_t is used as input to API functions. */
uint8_t addr_type : 7; /**< See @ref BLE_GAP_ADDR_TYPES. */
uint8_t addr[BLE_GAP_ADDR_LEN]; /**< 48-bit address, LSB format.
@ref addr is not used if @ref addr_type is @ref BLE_GAP_ADDR_TYPE_ANONYMOUS. */
} ble_gap_addr_t;
uint32_t sd_ble_gap_addr_get(ble_gap_addr_t *p_addr)
sd_ble_gap_addr_get(&bleAddr);
#include "nrf_log.h"
uint8 address[6];
uint8 i;
for(i = 0; i < 6; i++)
{
address[i] = bleAddr.addr[5 - i]; // 逆序
}
NRF_LOG_INFO("address:%02x", address[0]);
NRF_LOG_INFO("address:%02x", address[1]);
NRF_LOG_INFO("address:%02x", address[2]);
NRF_LOG_INFO("address:%02x", address[3]);
NRF_LOG_INFO("address:%02x", address[4]);
NRF_LOG_INFO("address:%02x", address[5]);
首先采用 sd_ble_gap_addr_get
读取官方默认的 MAC 地址,然后再默认地址+1,再用 sd_ble_gap_addr_set
写入到设备中。
void mac_set(void)
{
ble_gap_addr_t addr;
uint32_t err_code = sd_ble_gap_addr_get(&addr);
APP_ERROR_CHECK(err_code);
// Increase the BLE address by one when advertising openly.
addr.addr[0] += 1;
err_code = sd_ble_gap_addr_set(&addr);
APP_ERROR_CHECK(err_code);
}
主函数中进行调用,注意,一定要在广播开始前设置,下次广播后新的 MAC 地址就设置成功。
/**@brief Application main function.
*/
int main(void)
{
bool erase_bonds;
// Initialize.
uart_init();
log_init();
timers_init();
buttons_leds_init(&erase_bonds);
power_management_init();
ble_stack_init();
gap_params_init();
mac_set();
gatt_init();
services_init();
advertising_init();
conn_params_init();
// Start execution.
advertising_start();
// Enter main loop.
for (;;)
{
idle_state_handle();
}
}
• 由 Leung 写于 2020 年 2 月 19 日
• 参考:青风电子社区