【BlueZ 】蓝牙地址与 UUID:BlueZ 源码中核心标识的定义与使用

蓝牙技术中,蓝牙地址(BD_ADDR)UUID Universally Unique Identifier **)**是两个最核心的标识符。地址用于唯一标识蓝牙设备,UUID用于标识蓝牙服务和特征。理解这两类标识符的定义、生成、绑定和使用,是深入掌握 BlueZ 协议栈的关键。


目录

一、蓝牙地址体系:从物理标识到逻辑抽象

[二、BLE 随机地址深度解析](#二、BLE 随机地址深度解析)

[三、蓝牙地址在 BlueZ 中的绑定与使用](#三、蓝牙地址在 BlueZ 中的绑定与使用)

[四、UUID 体系:从基础定义到协议规范](#四、UUID 体系:从基础定义到协议规范)

[五、UUID 核心操作函数源码解析](#五、UUID 核心操作函数源码解析)

[六、UUID 在服务发现与匹配中的应用](#六、UUID 在服务发现与匹配中的应用)

[七、地址与 UUID 在连接流程中的协同作用](#七、地址与 UUID 在连接流程中的协同作用)

八、开发实战与踩坑经验

九、核心函数索引

十、总结


本文基于 BlueZ 5.x 完整源码,深度剖析蓝牙地址与 UUID 的核心机制,涵盖:

  • 蓝牙公有/私有地址、随机地址类型原理

  • BlueZ 地址结构体、地址校验、地址生成、地址绑定实现

  • 基础 UUID、自定义 UUID、服务特征 UUID 规范定义

  • UUID 解析、匹配、注册、设备服务标识绑定核心函数

  • 设备扫描、连接配对、服务发现场景下的地址与 UUID 应用


一、蓝牙地址体系:从物理标识到逻辑抽象

1.1 地址类型分类

蓝牙规范定义了三种地址类型,在 BlueZ 中通过宏定义明确区分:

cpp 复制代码
// lib/bluetooth.h - 地址类型定义
#define BDADDR_BREDR           0x00    /* 经典蓝牙地址 */
#define BDADDR_LE_PUBLIC       0x01    /* BLE 公共地址 */
#define BDADDR_LE_RANDOM       0x02    /* BLE 随机地址 */

|--------------------|---------|--------------------------------|
| 类型 | 定义值 | 描述 |
| BDADDR_BREDR | 0x00 | BR/EDR 设备地址,基于 IEEE 802-24 MAC |
| BDADDR_LE_PUBLIC | 0x01 | BLE 公共地址,与 BR/EDR 地址相同 |
| BDADDR_LE_RANDOM | 0x02 | BLE 随机地址,可动态变化 |

1.2 地址结构体定义

cpp 复制代码
// lib/bluetooth.h - BD Address 结构体
typedef struct {
    uint8_t b[6];
} __attribute__((packed)) bdaddr_t;

关键特性

  • 6 字节(48 位)固定长度

  • 紧凑存储(__attribute__((packed))

  • 可直接用于网络传输

1.3 特殊地址常量

cpp 复制代码
// lib/bluetooth.h - 预定义地址
#define BDADDR_ANY   (&(bdaddr_t) {{0, 0, 0, 0, 0, 0}})     /* 任意地址 */
#define BDADDR_ALL   (&(bdaddr_t) {{0xff, 0xff, 0xff, 0xff, 0xff, 0xff}}) /* 广播地址 */
#define BDADDR_LOCAL (&(bdaddr_t) {{0, 0, 0, 0xff, 0xff, 0xff}})  /* 本地地址 */

1.4 地址操作 内联函数

cpp 复制代码
// lib/bluetooth.h - 地址比较与拷贝
static inline int bacmp(const bdaddr_t *ba1, const bdaddr_t *ba2)
{
    return memcmp(ba1, ba2, sizeof(bdaddr_t));
}

static inline void bacpy(bdaddr_t *dst, const bdaddr_t *src)
{
    memcpy(dst, src, sizeof(bdaddr_t));
}

二、 BLE 随机地址深度解析

2.1 随机地址类型

BLE 随机地址分为四类,通过地址最高 2 位区分:

|----------|------------|------------------|-----------|
| 类型 | 最高 2 位 | 特性 | 生命周期 |
| 静态随机地址 | 0xC0 | 上电随机生成,断电不变 | 设备生命周期内不变 |
| 私有可解析地址 | 0x40 | 基于 IRK 生成,可被对端解析 | 周期性更新 |
| 私有不可解析地址 | 0x00 | 完全随机,不可解析 | 每次连接更新 |
| 固定地址 | 0x80 | 保留 | - |

2.2 BlueZ 地址生成 逻辑

cpp 复制代码
// src/adapter.c - 静态随机地址生成
static bool generate_static_address(struct btd_adapter *adapter)
{
    // ...
    bdaddr_t addr;
    
    // 从存储中获取可用地址列表
    addrs = g_key_file_get_string_list(file, "Static", mfg, &len, NULL);
    if (addrs) {
        for (i = 0; i < len; i++) {
            str2ba(addrs[i], &addr);
            if (adapter_find(&addr))
                continue;
            
            /* 找到可用地址 */
            bacpy(&adapter->bdaddr, &addr);
            adapter->bdaddr_type = BDADDR_LE_RANDOM;  /* 标记为随机地址 */
            ret = true;
            goto done;
        }
    }
    
    // 生成新地址
    crypto = bt_crypto_new();
    bt_crypto_random_bytes(crypto, &adapter->bdaddr, sizeof(adapter->bdaddr));
    
    // 设置静态地址标志(最高 2 位置 1)
    adapter->bdaddr.b[5] |= 0xc0;  /* 设置 0xC0 标识 */
    adapter->bdaddr_type = BDADDR_LE_RANDOM;
    // ...
}

源码 解读

  1. 首先从持久化存储中查找可用地址

  2. 如果没有可用地址,使用随机数生成器生成新地址

  3. 将地址最高 2 位置为 0xC0,标识为静态随机地址

  4. 最终将地址类型设为 BDADDR_LE_RANDOM

2.3 隐私地址( RPA )与 IRK

BLE 隐私功能使用**身份解析密钥(IRK)**生成可解析的私有地址:

cpp 复制代码
// src/adapter.c - 设置隐私功能
static int set_privacy(struct btd_adapter *adapter, uint8_t privacy)
{
    struct mgmt_cp_set_privacy cp;
    
    memset(&cp, 0, sizeof(cp));
    
    if (privacy) {
        uint8_t irk[16];
        
        // 加载 IRK
        if (load_irk(adapter, irk) == 0) {
            cp.privacy = privacy;
            memcpy(cp.irk, irk, 16);  /* 传递 IRK 给内核 */
        }
    }
    // ...
}

关键机制

  • IRK(Identity Resolving Key):用于生成和解析私有地址

  • 设备周期性使用 IRK 生成新的私有地址

  • 对端设备使用相同的 IRK 可以解析这些地址

2.4 地址类型配置

cpp 复制代码
// src/adapter.c - 读取地址类型配置
static uint8_t get_default_address_type(void)
{
    // 从配置文件读取 AddressType
    type = g_key_file_get_string(keyfile, "General", "AddressType", NULL);
    if (!type)
        return BDADDR_LE_PUBLIC;  /* 默认为公共地址 */
    
    if (g_str_equal(type, "public"))
        addr_type = BDADDR_LE_PUBLIC;
    else if (g_str_equal(type, "static"))
        addr_type = BDADDR_LE_RANDOM;
    
    return addr_type;
}

配置示例(/etc/bluetooth/main.conf):

cpp 复制代码
[General]
AddressType = public    # 使用公共地址
# 或
AddressType = static    # 使用静态随机地址

三、蓝牙地址在 BlueZ 中的绑定与使用

3.1 设备创建时的地址绑定

cpp 复制代码
// src/device.c - 设备创建
struct btd_device *device_create(struct btd_adapter *adapter,
                                const bdaddr_t *address, uint8_t bdaddr_type)
{
    struct btd_device *device;
    
    device = g_new0(struct btd_device, 1);
    device->adapter = adapter;
    
    // 绑定地址信息
    bacpy(&device->bdaddr, address);
    device->bdaddr_type = bdaddr_type;  /* 记录地址类型 */
    
    // 根据地址类型设置支持的协议
    if (bdaddr_type == BDADDR_BREDR)
        device->bredr = TRUE;    /* 标记支持 BR/EDR */
    else
        device->le = TRUE;       /* 标记支持 LE */
    
    return device;
}

3.2 地址类型在连接流程中的判断

cpp 复制代码
// src/adapter.c - 连接建立时的地址类型处理
if (dst_type == BDADDR_BREDR) {
    // BR/EDR 连接:使用经典蓝牙地址
    bt_io_connect(io, connect_cb, data, NULL,
            BT_IO_OPT_SOURCE_TYPE, BDADDR_BREDR,
            BT_IO_OPT_DEST_TYPE, BDADDR_BREDR,
            BT_IO_OPT_DEST_BDADDR, &dst,
            BT_IO_OPT_INVALID);
} else {
    // BLE 连接:根据地址类型设置
    uint8_t addr_type = BDADDR_BREDR;
    
    // 根据实际地址类型选择参数
    if (data->dst_type == BDADDR_LE_PUBLIC)
        addr_type = BDADDR_LE_PUBLIC;
    else if (data->dst_type == BDADDR_LE_RANDOM)
        addr_type = BDADDR_LE_RANDOM;
    
    bt_io_connect(io, connect_cb, data, NULL,
            BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
            BT_IO_OPT_DEST_TYPE, addr_type,
            BT_IO_OPT_DEST_BDADDR, &dst,
            BT_IO_OPT_INVALID);
}

3.3 双模式设备的地址管理

cpp 复制代码
// src/device.h - 设备状态结构
struct btd_device {
    // ...
    bdaddr_t bdaddr;
    uint8_t bdaddr_type;
    
    // 双模式标记
    bool bredr;           /* 支持 BR/EDR */
    bool le;              /* 支持 LE */
    
    // 独立状态管理
    struct bearer_state bredr_state;  /* BR/EDR 连接状态 */
    struct bearer_state le_state;     /* LE 连接状态 */
    // ...
};

// src/device.c - 获取指定类型的状态
static struct bearer_state *get_state(struct btd_device *dev, uint8_t bdaddr_type)
{
    if (bdaddr_type == BDADDR_BREDR)
        return &dev->bredr_state;
    else
        return &dev->le_state;
}

四、UUID 体系:从基础定义到协议规范

4.1 UUID 类型定义

BlueZ 支持三种 UUID 长度,通过 bt_uuid_t 结构体统一抽象:

cpp 复制代码
// lib/uuid.h - UUID 类型定义
typedef struct {
    enum {
        BT_UUID_UNSPEC = 0,  /* 未指定 */
        BT_UUID16 = 16,      /* 16-bit UUID */
        BT_UUID32 = 32,      /* 32-bit UUID */
        BT_UUID128 = 128,    /* 128-bit UUID */
    } type;
    union {
        uint16_t  u16;      /* 16-bit 值 */
        uint32_t  u32;      /* 32-bit 值 */
        uint128_t u128;     /* 128-bit 值 */
    } value;
} bt_uuid_t;

UUID 类型对比

|--------------|---------|-------------|----------------------------------------|
| 类型 | 长度 | 用途 | 示例 |
| BT_UUID16 | 16-bit | GATT 服务/特征值 | 0x2800 (Primary Service) |
| BT_UUID32 | 32-bit | 扩展 UUID | 较少使用 |
| BT_UUID128 | 128-bit | SDP 服务 UUID | 0000110d-0000-1000-8000-00805f9b34fb |

4.2 蓝牙基础 UUID

所有蓝牙 UUID 都基于一个基础 UUID

cpp 复制代码
// lib/uuid.c - 蓝牙基础 UUID
static uint128_t bluetooth_base_uuid = {
    .data = {   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
                0x80, 0x00, 0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB }
};

基础 UUID 格式:`00000000-0000-1000-8000-00805F9B34FB`

所有 16-bit 和 32-bit UUID 都嵌入到这个基础 UUID 中形成 128-bit 格式。

4.3 常用 UUID 常量定义

cpp 复制代码
// lib/uuid.h - 经典蓝牙服务 UUID
#define HSP_HS_UUID         "00001108-0000-1000-8000-00805f9b34fb"  /* 耳机服务 */
#define HFP_HS_UUID         "0000111e-0000-1000-8000-00805f9b34fb"  /* 免提服务 */
#define ADVANCED_AUDIO_UUID "0000110d-0000-1000-8000-00805f9b34fb"  /* 高级音频服务 */
#define HID_UUID            "00001124-0000-1000-8000-00805f9b34fb"  /* 人机接口设备 */

// BLE GATT 服务 UUID
#define GATT_UUID           "00001801-0000-1000-8000-00805f9b34fb"  /* GATT 服务 */
#define BATTERY_UUID        "0000180f-0000-1000-8000-00805f9b34fb"  /* 电池服务 */
#define HEART_RATE_UUID     "0000180d-0000-1000-8000-00805f9b34fb"  /* 心率服务 */

// GATT 16-bit 特征值 UUID
#define GATT_CHARAC_DEVICE_NAME             0x2A00  /* 设备名称 */
#define GATT_CHARAC_APPEARANCE              0x2A01  /* 外观 */
#define GATT_CHARAC_BATTERY_LEVEL           0x2A19  /* 电池电量 */
#define GATT_CHARAC_FIRMWARE_REVISION_STRING 0x2A26  /* 固件版本 */
#define GATT_CHARAC_SOFTWARE_REVISION_STRING 0x2A28  /* 软件版本 */

五、UUID 核心操作函数源码解析

5.1 UUID 创建函数

cpp 复制代码
// lib/uuid.c - 创建不同类型的 UUID
int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value)
{
    memset(btuuid, 0, sizeof(bt_uuid_t));
    btuuid->type = BT_UUID16;
    btuuid->value.u16 = value;
    return 0;
}

int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value)
{
    memset(btuuid, 0, sizeof(bt_uuid_t));
    btuuid->type = BT_UUID32;
    btuuid->value.u32 = value;
    return 0;
}

int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value)
{
    memset(btuuid, 0, sizeof(bt_uuid_t));
    btuuid->type = BT_UUID128;
    btuuid->value.u128 = value;
    return 0;
}

5.2 UUID 转换为 128-bit

为了统一比较,所有 UUID 都需要转换为 128-bit 格式:

cpp 复制代码
// lib/uuid.c - UUID 转 128-bit
#define BASE_UUID16_OFFSET  2  /* 16-bit UUID 在 128-bit 中的偏移 */
#define BASE_UUID32_OFFSET  0  /* 32-bit UUID 在 128-bit 中的偏移 */

static void bt_uuid16_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
{
    uint16_t be16;
    
    // 填充基础 UUID
    dst->value.u128 = bluetooth_base_uuid;
    dst->type = BT_UUID128;
    
    // 将 16-bit UUID 转换为大端序并插入正确位置
    be16 = htons(src->value.u16);
    memcpy(&dst->value.u128.data[BASE_UUID16_OFFSET], &be16, sizeof(be16));
}

static void bt_uuid32_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
{
    uint32_t be32;
    
    dst->value.u128 = bluetooth_base_uuid;
    dst->type = BT_UUID128;
    
    be32 = htonl(src->value.u32);
    memcpy(&dst->value.u128.data[BASE_UUID32_OFFSET], &be32, sizeof(be32));
}

// 统一入口
void bt_uuid_to_uuid128(const bt_uuid_t *src, bt_uuid_t *dst)
{
    switch (src->type) {
    case BT_UUID128:
        *dst = *src;
        break;
    case BT_UUID32:
        bt_uuid32_to_uuid128(src, dst);
        break;
    case BT_UUID16:
        bt_uuid16_to_uuid128(src, dst);
        break;
    }
}

转换示意图

cpp 复制代码
16-bit UUID:        0x2A19 (电池电量)
    ↓ 转换为
128-bit UUID:       00002A19-0000-1000-8000-00805F9B34FB
                    ^^^^^^
                    嵌入位置(偏移 2 字节)

5.3 UUID 比较函数

cpp 复制代码
// lib/uuid.c - UUID 比较
int bt_uuid_cmp(const bt_uuid_t *uuid1, const bt_uuid_t *uuid2)
{
    bt_uuid_t u1, u2;
    
    // 先都转换为 128-bit 再比较
    bt_uuid_to_uuid128(uuid1, &u1);
    bt_uuid_to_uuid128(uuid2, &u2);
    
    return bt_uuid128_cmp(&u1, &u2);  /* memcmp 比较 */
}

static int bt_uuid128_cmp(const bt_uuid_t *u1, const bt_uuid_t *u2)
{
    return memcmp(&u1->value.u128, &u2->value.u128, sizeof(uint128_t));
}

设计亮点:统一转换为 128-bit 后再比较,支持不同类型 UUID 之间的相等判断。

5.4 字符串与 UUID 互转

cpp 复制代码
// lib/uuid.c - 字符串转 UUID
int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
{
    if (!string)
        return -EINVAL;
    
    // 智能识别 UUID 格式
    if (is_base_uuid128(string))
        return bt_string_to_uuid16(uuid, string + 4);  // 基础UUID格式,提取16-bit部分
    else if (is_uuid128(string))
        return bt_string_to_uuid128(uuid, string);     // 完整 128-bit
    else if (is_uuid32(string))
        return bt_string_to_uuid32(uuid, string);      // 32-bit
    else if (is_uuid16(string))
        return bt_string_to_uuid16(uuid, string);     // 16-bit
    
    return -EINVAL;
}

// lib/uuid.c - UUID 转字符串
int bt_uuid_to_string(const bt_uuid_t *uuid, char *str, size_t n)
{
    bt_uuid_t tmp;
    
    // 先转 128-bit
    bt_uuid_to_uuid128(uuid, &tmp);
    
    // 按标准格式输出
    snprintf(str, n, "%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
                data0, data1, data2, data3, data4, data5);
    return 0;
}

六、UUID 在服务发现与匹配中的应用

6.1 SDP 服务搜索中的 UUID 匹配

cpp 复制代码
// src/sdpd-request.c - SDP UUID 匹配
static int sdp_match_uuid(sdp_list_t *search, sdp_list_t *pattern)
{
    int patlen = sdp_list_len(pattern);
    
    if (patlen < sdp_list_len(search))
        return -1;
    
    // 遍历搜索 UUID,检查是否都存在于模式列表中
    for (; search; search = search->next) {
        uuid_t *uuid128;
        void *data = search->data;
        
        // 转换为 128-bit
        uuid128 = sdp_uuid_to_uuid128((uuid_t *)data);
        // 在模式列表中查找
        list = sdp_list_find(pattern, uuid128, sdp_uuid128_cmp);
        bt_free(uuid128);
        
        if (!list)
            return 0;  // 未找到匹配
    }
    
    return 1;  // 所有 UUID 都匹配
}

6.2 设备 UUID 列表管理

cpp 复制代码
// src/device.c - 添加 UUID 到设备
void btd_device_add_uuid(struct btd_device *device, const char *uuid)
{
    GSList *uuid_list;
    char *new_uuid;
    
    // 检查 UUID 是否已存在(使用字符串比较)
    if (g_slist_find_custom(device->uuids, uuid, bt_uuid_strcmp))
        return;  // 已存在,直接返回
    
    new_uuid = g_strdup(uuid);
    uuid_list = g_slist_append(NULL, new_uuid);
    
    // 触发 Profile 探测
    device_probe_profiles(device, uuid_list);
    
    g_free(new_uuid);
    g_slist_free(uuid_list);
    
    // 保存到持久化存储
    store_device_info(device);
    
    // 通知 DBus 属性变更
    g_dbus_emit_property_changed(dbus_conn, device->path,
                    DEVICE_INTERFACE, "UUIDs");
}

6.3 Profile 匹配核心逻辑

cpp 复制代码
// src/device.c - Profile 匹配
static bool device_match_profile(struct btd_device *device,
                                struct btd_profile *profile,
                                GSList *uuids)
{
    if (profile->remote_uuid == NULL)
        return false;
    
    // 使用 UUID 字符串比较进行匹配
    if (g_slist_find_custom(uuids, profile->remote_uuid,
                            bt_uuid_strcmp) == NULL)
        return false;
    
    return true;  // 匹配成功
}

// 探测服务
static struct btd_service *probe_service(struct btd_device *device,
                                        struct btd_profile *profile,
                                        GSList *uuids)
{
    struct btd_service *service;
    
    if (profile->device_probe == NULL)
        return NULL;
    
    // 首先检查 UUID 是否匹配
    if (!device_match_profile(device, profile, uuids))
        return NULL;
    
    // 创建服务实例
    service = service_create(device, profile);
    
    // 执行服务探测
    if (service_probe(service)) {
        btd_service_unref(service);
        return NULL;
    }
    
    return service;
}

6.4 GATT 服务 UUID 处理

cpp 复制代码
// src/device.c - GATT 服务 UUID 提取
static void add_gatt_service(struct gatt_db_attribute *attr, void *user_data)
{
    struct btd_device *device = user_data;
    bt_uuid_t uuid;
    char uuid_str[MAX_LEN_UUID_STR];
    
    // 获取服务 UUID
    gatt_db_attribute_get_service_uuid(attr, &uuid);
    bt_uuid_to_string(&uuid, uuid_str, sizeof(uuid_str));
    
    // 检查是否已处理
    if (find_service_with_uuid(device->services, uuid_str))
        return;
    
    // 添加 UUID 并触发服务探测
    btd_device_add_uuid(device, uuid_str);
}

七、地址与 UUID 在连接流程中的协同作用

7.1 设备扫描阶段

cpp 复制代码
// src/adapter.c - 扫描发现设备时
static void device_found(struct btd_adapter *adapter,
                        const bdaddr_t *bdaddr, uint8_t bdaddr_type)
{
    struct btd_device *device;
    
    // 1. 通过地址查找或创建设备
    device = btd_adapter_find_device(adapter, bdaddr, bdaddr_type);
    if (!device) {
        device = device_create(adapter, bdaddr, bdaddr_type);
        btd_adapter_add_device(adapter, device);
    }
    
    // 2. 根据地址类型标记支持的协议
    if (bdaddr_type == BDADDR_BREDR)
        device_set_bredr_support(device);
    else
        device_set_le_support(device, bdaddr_type);
    
    // 3. 发送 DBus 信号通知新设备
    g_dbus_emit_signal(dbus_conn, adapter->path,
                    ADAPTER_INTERFACE, "DeviceFound",
                    DBUS_TYPE_OBJECT_PATH, &device->path,
                    DBUS_TYPE_INVALID);
}

7.2 服务发现阶段

cpp 复制代码
// src/device.c - 连接后服务发现
static void resolve_services(struct btd_device *dev, DBusMessage *msg)
{
    uint8_t bdaddr_type = btd_device_get_bdaddr_type(dev);
    int err;
    
    // 根据地址类型选择不同的服务发现方式
    if (bdaddr_type == BDADDR_BREDR)
        err = device_browse_sdp(dev, msg);   /* BR/EDR: SDP */
    else
        err = device_browse_gatt(dev, msg); /* LE: GATT */
    
    if (err < 0) {
        return btd_error_failed(msg, bdaddr_type == BDADDR_BREDR ?
            ERR_BREDR_CONN_SDP_SEARCH : ERR_LE_CONN_GATT_BROWSE);
    }
}

7.3 Profile 自动匹配

cpp 复制代码
// src/adapter.c - 设备探测 Profile
static void probe_devices(void *user_data)
{
    struct btd_device *device = user_data;
    
    // 使用设备的 UUID 列表进行 Profile 匹配
    device_probe_profiles(device, btd_device_get_uuids(device));
    device_resolved_drivers(device_get_adapter(device), device);
}

流程总结

八、开发实战与踩坑经验

8.1 地址相关问题

|-------------|----------|----------------------------------------------|
| 问题 | 原因 | 解决方案 |
| 无法识别 BLE 设备 | 地址类型错误 | 确保使用 BDADDR_LE_PUBLICBDADDR_LE_RANDOM |
| 随机地址连接失败 | 地址已过期 | 使用 IRK 解析真实身份 |
| 双模式设备无法连接 | 地址类型判断错误 | 检查 bdaddr_type 参数 |

8.2 UUID 相关问题

|----------------------|------------|------------------------------|
| 问题 | 原因 | 解决方案 |
| 服务无法识别 | UUID 格式不一致 | 使用 bt_uuid_cmp() 统一比较 |
| Profile 不匹配 | UUID 列表为空 | 确保服务发现完成后再匹配 |
| 16-bit 与 128-bit 不匹配 | 类型转换问题 | 使用 bt_uuid_to_uuid128() 转换 |

8.3 调试技巧

cpp 复制代码
# 查看设备详细信息(包括地址和 UUID)
bluetoothctl info AA:BB:CC:DD:EE:FF

# 查看设备支持的 UUID 列表
bluetoothctl uuids AA:BB:CC:DD:EE:FF

# 使用 btmgmt 查看地址设置
btmgmt info

# 启用 BlueZ 调试日志
bluetoothd -d

8.4 代码示例

cpp 复制代码
// 创建设备连接代码示例
int connect_to_device(const char *address, uint8_t addr_type)
{
    bdaddr_t bdaddr;
    struct btd_device *device;
    
    // 1. 解析地址字符串
    if (str2ba(address, &bdaddr) < 0) {
        fprintf(stderr, "Invalid address format\n");
        return -1;
    }
    
    // 2. 创建设备对象
    device = device_create(adapter, &bdaddr, addr_type);
    if (!device) {
        fprintf(stderr, "Failed to create device\n");
        return -1;
    }
    
    // 3. 添加到适配器
    btd_adapter_add_device(adapter, device);
    
    // 4. 执行连接
    return device_connect(device);
}

// UUID 比较代码示例
bool check_service_match(const char *uuid_str, bt_uuid_t *service_uuid)
{
    bt_uuid_t target_uuid;
    
    // 字符串转 UUID
    if (bt_string_to_uuid(&target_uuid, uuid_str) < 0) {
        return false;
    }
    
    // 比较 UUID
    return bt_uuid_cmp(&target_uuid, service_uuid) == 0;
}

九、核心函数索引

9.1 地址相关函数

|-----------------------------|-----------------|----------|
| 函数 | 文件 | 功能 |
| bacmp() | lib/bluetooth.h | 比较两个蓝牙地址 |
| bacpy() | lib/bluetooth.h | 拷贝蓝牙地址 |
| str2ba() | lib/bluetooth.h | 字符串转地址 |
| ba2str() | lib/bluetooth.h | 地址转字符串 |
| generate_static_address() | src/adapter.c | 生成静态随机地址 |
| set_privacy() | src/adapter.c | 设置隐私功能 |

9.2 UUID 相关函数

|--------------------------|--------------|-----------------|
| 函数 | 文件 | 功能 |
| bt_uuid16_create() | lib/uuid.c | 创建 16-bit UUID |
| bt_uuid32_create() | lib/uuid.c | 创建 32-bit UUID |
| bt_uuid128_create() | lib/uuid.c | 创建 128-bit UUID |
| bt_uuid_to_uuid128() | lib/uuid.c | UUID 转 128-bit |
| bt_uuid_cmp() | lib/uuid.c | UUID 比较 |
| bt_uuid_to_string() | lib/uuid.c | UUID 转字符串 |
| bt_string_to_uuid() | lib/uuid.c | 字符串转 UUID |
| btd_device_add_uuid() | src/device.c | 设备添加 UUID |
| device_match_profile() | src/device.c | Profile UUID 匹配 |

十、总结

蓝牙地址和 UUID 是 BlueZ 协议栈中最基础的两个核心标识体系:

  1. 地址体系
  • 三种类型:BDADDR_BREDRBDADDR_LE_PUBLICBDADDR_LE_RANDOM

  • 支持静态随机地址和隐私地址(RPA)

  • 通过 bdaddr_t 结构体统一抽象

  1. UUID 体系
  • 三种长度:16-bit、32-bit、128-bit

  • 基于统一基础 UUID 进行转换

  • 通过 bt_uuid_t 结构体统一抽象

  1. 协同工作
  • 地址用于设备识别和连接

  • UUID 用于服务识别和功能匹配

  • 两者配合实现完整的蓝牙设备管理

深入理解这两个标识体系,不仅有助于掌握 BlueZ 源码架构,更能有效解决实际开发中的设备识别、服务发现和功能适配问题。


相关推荐
Baron X1 小时前
Linux PAM登录告警
linux·运维·告警
团子股股东峥哥1 小时前
day27-RHEL-访问Linux文件系统
linux·运维·服务器
佳児素花痴╮1 小时前
Linux IO模型详解:从阻塞到多路复用
linux·运维·服务器
朝发如雪2 小时前
快速掌握Linux(4)(进程)
java·linux·服务器
啦啦啦啦啦zzzz2 小时前
共享内存的网络聊天室
linux·服务器·网络·c++·网络编程
Tanner_SL2 小时前
Linux笔记之vim操作
linux·vim
用户041328465132 小时前
Linux 查看端口占用的 6 种方法:ss、netstat、lsof 实战
linux
二宝哥2 小时前
Rocky Linux 10.2 安装 PostgreSQL 15 完整教程
linux·运维·postgresql
不会就选b3 小时前
Linux之线程池(二)
linux·运维·服务器