本文主要介绍 NimBLE Host 端的蓝牙地址如何配置,Controller 端请参考:NimBLE - Configure device address 。
NimBLE 里与蓝牙地址设置相关的文件有:
- nimble/
- host/
- include/
- host/
- ble_hs_id.h # 对应用开放的接口
- src/
- ble_hs_id_priv.h # 内部使用接口,对应用不可见
- ble_hs_id.c # 功能实现
下面将公共地址(Public Address)和随机地址(Random Address)分开介绍。
Public Address
ble_hs_id.c 文件里用一个静态数组 ble_hs_id_pub 存储公共地址,并提供了 ble_hs_id_set_pub() 函数接口来设置该地址。
static uint8_t ble_hs_id_pub[6];
void ble_hs_id_set_pub(const uint8_t *pub_addr)
{
memcpy(ble_hs_id_pub, pub_addr, 6);
}
不幸的是,该接口位于 ble_hs_id_priv.h 内部接口文件里,应用层不能使用该接口。进一步在协议栈中搜索该接口的调用位置,发现是在协议栈初始化的时候调用的:
nimble/host/src/ble_hs_startup.c
- ble_hs_startup_go()
- ble_hs_startup_read_bd_addr()
- ble_hs_id_set_pub()
继续查看 ble_hs_startup_read_bd_addr() 函数:
static int ble_hs_startup_read_bd_addr(void)
{
struct ble_hci_ip_rd_bd_addr_rp rsp;
int rc;
rc = ble_hs_hci_cmd_tx(BLE_HCI_OP(BLE_HCI_OGF_INFO_PARAMS,
BLE_HCI_OCF_IP_RD_BD_ADDR),
NULL, 0, &rsp, sizeof(rsp));
if (rc != 0) {
return rc;
}
ble_hs_id_set_pub(rsp.addr);
return 0;
}
可以发现 Host 先发送了 HCI_Read_BD_ADDR 命令从 LE Controller 获取公共地址,并利用返回结果设置公共地址。
命令解释:Host 发送该命令给 LE Controller 读取公共设备地址(Public Device Address),若控制器没有公共设备地址,返回 0x000000000000 ,代表无效地址。
Random Address
ble_hs_id.c 文件里用一个静态数组 ble_hs_id_rnd 存储随机地址,并提供了接口 ble_hs_id_set_rnd() 设置它,同时还提供了一个接口来生成随机地址:
int ble_hs_id_gen_rnd(int nrpa, ble_addr_t *out_addr)
{
int rc;
out_addr->type = BLE_ADDR_RANDOM;
rc = ble_hs_hci_util_rand(out_addr->val, 6);
if (rc != 0) {
return rc;
}
if (nrpa) {
out_addr->val[5] &= ~0xc0;
} else {
out_addr->val[5] |= 0xc0;
}
return 0;
}
不过该接口是通过发送 HCI_LE_Rand 命令从 Controller 端获取随机数,而该命令一般只有控制器支持 LE Encryption Feature 时才支持,因此 ble_hs_id_gen_rnd() 接口很有可能会失败,需仔细检查返回值。
命令解释:Host 发送该命令给 LE Controller,当控制器支持 LE Feature (LE Encryption) 时,返回 8 字节的随机数。
配置使用
ble_hs_id.h 接口文件里 ble_hs_id_infer_auto() 接口能够自动识别协议栈内部已拥有的地址,并可获取地址类型,若协议栈内没有地址,返回错误码 BLE_HS_ENOADDR 。
因此 NimBLE 对于蓝牙设备地址的配置共有三种模式:
- 若 Controller 拥有公共地址,在应用程序里直接调用
ble_hs_id_infer_auto()接口获取地址类型即可,公共地址读取的工作在协议栈初始化的时候就完成了。 - 若 Controller 没有公共地址,但支持 HCI_LE_Rand 命令,先通过
ble_hs_id_gen_rnd()生成随机设备地址,再通过ble_hs_id_set_rnd()函数设置随机地址,地址类型为 Random 。 - 其他情况,固定一个随机设备地址,或利用 Host 硬件自身的功能生成随机地址,然后通过
ble_hs_id_set_rnd()函数设置随即地址,地址类型为 Random 。
为了方便配置,nimble/host/util/include/host/util/util.h 文件里的接口
ble_hs_util_ensure_addr();
能够配置蓝牙设备至少包含一个地址(公共或随机),可先用 ble_hs_util_ensure_addr() 函数生成地址,然后在用接口 ble_hs_id_infer_auto() 获取地址类型。