NimBLE-蓝牙设备地址设置


本文主要介绍 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() 获取地址类型。


文章作者: Jackistang
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Jackistang !
  目录