Zephyr RTOS 中 BT_CONN_CB_DEFINE 详解

目录

概述

[1 BT_CONN_CB_DEFINE 和原理介绍](#1 BT_CONN_CB_DEFINE 和原理介绍)

[1.1 基本定义](#1.1 基本定义)

[1.2 核心功能和工作原理](#1.2 核心功能和工作原理)

[1.3 与传统注册方式的对比](#1.3 与传统注册方式的对比)

[1.4 BT_CONN_CB_DEFINE 的核心优势](#1.4 BT_CONN_CB_DEFINE 的核心优势)

[2 基本用法](#2 基本用法)

[2.1 最简单的使用示例](#2.1 最简单的使用示例)

[2.2 完整回调结构体定义](#2.2 完整回调结构体定义)

[3 高级用法和完整示例](#3 高级用法和完整示例)

[3.1 完整的连接管理示例](#3.1 完整的连接管理示例)

[3.2 多模块回调示例](#3.2 多模块回调示例)

[4 注意事项和操作方法总结](#4 注意事项和操作方法总结)

[5 实际应用场景](#5 实际应用场景)

[5.1 中央设备(Central)应用](#5.1 中央设备(Central)应用)

[5.2 外围设备(Peripheral)应用](#5.2 外围设备(Peripheral)应用)

[5.3 多角色设备(Central+Peripheral)](#5.3 多角色设备(Central+Peripheral))


概述

BT_CONN_CB_DEFINE 是 Zephyr Bluetooth API 中的一个关键宏,用于静态定义和自动注册蓝牙连接回调函数。它简化了连接事件处理的配置,避免了手动注册回调的繁琐过程。

1 BT_CONN_CB_DEFINE 和原理介绍

1.1 基本定义

cpp 复制代码
// 在 include/bluetooth/conn.h 中
#define BT_CONN_CB_DEFINE(_name) \
    static const STRUCT_SECTION_ITERABLE(bt_conn_cb, _name)

1.2 核心功能和工作原理

1) 功能特性

  • 自动注册:定义的连接回调会自动被蓝牙栈发现和注册

  • 零配置 :无需手动调用 bt_conn_cb_register()

  • 多实例支持:可以定义多个回调实例,都会被执行

  • 编译时初始化:在编译时确定,不占用运行时初始化时间

2) 工作原理

编译时:

宏展开 → 结构体定义 → 放入特定段(section)


系统启动时:

蓝牙栈初始化 → 扫描特定段 → 自动注册所有回调


运行时:

连接事件发生 → 调用所有注册的回调函数

1.3 与传统注册方式的对比

优势对比:

特性 传统方式 BT_CONN_CB_DEFINE
注册时机 运行时手动注册 编译时自动注册
代码复杂度 需要显式调用注册函数 零配置,自动完成
多实例支持 需要管理多个注册 自然支持多实例
初始化顺序 必须确保在蓝牙初始化前注册 无顺序要求
模块化 需要集中管理注册 每个模块可以独立定义

1.4 BT_CONN_CB_DEFINE 的核心优势

  1. 简化代码:无需手动注册回调

  2. 提高可靠性:避免因忘记注册回调导致的bug

  3. 支持模块化:各模块可以独立定义自己的回调

  4. 编译时优化:编译器可以进行更好的优化

2 基本用法

2.1 最简单的使用示例

cpp 复制代码
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>

/* 定义连接回调结构体 */
BT_CONN_CB_DEFINE(conn_callbacks) = {
    .connected = connected_callback,
    .disconnected = disconnected_callback,
};

/* 连接建立回调 */
static void connected_callback(struct bt_conn *conn, uint8_t err)
{
    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    if (err) {
        printk("连接失败: %s (错误: 0x%02x)\n", addr, err);
        return;
    }
    
    printk("已连接到: %s\n", addr);
}

/* 连接断开回调 */
static void disconnected_callback(struct bt_conn *conn, uint8_t reason)
{
    char addr[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr, sizeof(addr));
    
    printk("连接断开: %s (原因: 0x%02x)\n", addr, reason);
}

2.2 完整回调结构体定义

cpp 复制代码
/* 连接回调结构体 bt_conn_cb 的完整定义 */
struct bt_conn_cb {
    /* 连接建立时调用 */
    void (*connected)(struct bt_conn *conn, uint8_t err);
    
    /* 连接断开时调用 */
    void (*disconnected)(struct bt_conn *conn, uint8_t reason);
    
    /* LE连接参数更新时调用 */
    void (*le_param_updated)(struct bt_conn *conn, uint16_t interval,
                             uint16_t latency, uint16_t timeout);
    
    /* 远程设备信息可用时调用(如远程版本信息) */
    void (*remote_info_available)(struct bt_conn *conn);
    
    /* 身份验证取消时调用 */
    void (*auth_cancel)(struct bt_conn *conn);
    
    /* 安全级别变化时调用 */
    void (*security_changed)(struct bt_conn *conn, bt_security_t level);
    
    /* 身份验证成功时调用 */
    void (*identity_resolved)(struct bt_conn *conn,
                              const bt_addr_le_t *rpa,
                              const bt_addr_le_t *identity);
    
    /* 系统使用的链表节点 */
    sys_snode_t node;
};

3 高级用法和完整示例

3.1 完整的连接管理示例

cpp 复制代码
#include <zephyr/kernel.h>
#include <zephyr/bluetooth/bluetooth.h>
#include <zephyr/bluetooth/conn.h>

#define MAX_CONNECTIONS 3

struct connection_info {
    struct bt_conn *conn;
    bool active;
    uint8_t id;
    char addr_str[BT_ADDR_LE_STR_LEN];
};

static struct connection_info connections[MAX_CONNECTIONS];
static uint8_t next_conn_id = 0;

/* 连接建立回调 */
static void connected_cb(struct bt_conn *conn, uint8_t err)
{
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_t *addr = bt_conn_get_dst(conn);
    
    bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    
    if (err) {
        printk("连接失败: %s (错误: 0x%02x)\n", addr_str, err);
        return;
    }
    
    /* 查找空闲连接槽 */
    int free_slot = -1;
    for (int i = 0; i < MAX_CONNECTIONS; i++) {
        if (!connections[i].active) {
            free_slot = i;
            break;
        }
    }
    
    if (free_slot >= 0) {
        connections[free_slot].conn = conn;
        connections[free_slot].active = true;
        connections[free_slot].id = next_conn_id++;
        strncpy(connections[free_slot].addr_str, addr_str,
                sizeof(connections[free_slot].addr_str) - 1);
        
        /* 增加引用计数 */
        bt_conn_ref(conn);
        
        printk("连接 #%d 建立: %s\n", 
               connections[free_slot].id, addr_str);
    } else {
        printk("已达到最大连接数,拒绝新连接: %s\n", addr_str);
        bt_conn_disconnect(conn, BT_HCI_ERR_REMOTE_LOW_RESOURCES);
    }
}

/* 连接断开回调 */
static void disconnected_cb(struct bt_conn *conn, uint8_t reason)
{
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_t *addr = bt_conn_get_dst(conn);
    
    bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    
    /* 查找并清除连接信息 */
    for (int i = 0; i < MAX_CONNECTIONS; i++) {
        if (connections[i].active && connections[i].conn == conn) {
            printk("连接 #%d 断开: %s (原因: 0x%02x)\n",
                   connections[i].id, addr_str, reason);
            
            /* 释放引用计数 */
            bt_conn_unref(conn);
            
            connections[i].active = false;
            connections[i].conn = NULL;
            break;
        }
    }
}

/* LE连接参数更新回调 */
static void le_param_updated_cb(struct bt_conn *conn, uint16_t interval,
                               uint16_t latency, uint16_t timeout)
{
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_t *addr = bt_conn_get_dst(conn);
    
    bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    
    printk("连接参数更新: %s\n", addr_str);
    printk("  间隔: %.2fms (实际: %d * 1.25ms)\n", 
           interval * 1.25f, interval);
    printk("  延迟: %d (允许跳过的连接事件数)\n", latency);
    printk("  超时: %dms (实际: %d * 10ms)\n", 
           timeout * 10, timeout);
    
    /* 根据参数调整应用行为 */
    if (interval > 80) {  // 100ms以上
        printk("  进入低功耗模式\n");
    } else if (interval < 12) {  // 15ms以下
        printk("  进入高速模式\n");
    }
}

/* 安全级别变化回调 */
static void security_changed_cb(struct bt_conn *conn, bt_security_t level)
{
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_t *addr = bt_conn_get_dst(conn);
    
    bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    
    const char *level_str;
    switch (level) {
        case BT_SECURITY_L0:
            level_str = "无安全";
            break;
        case BT_SECURITY_L1:
            level_str = "无加密";
            break;
        case BT_SECURITY_L2:
            level_str = "未认证加密";
            break;
        case BT_SECURITY_L3:
            level_str = "已认证加密";
            break;
        case BT_SECURITY_L4:
            level_str = "安全连接加密";
            break;
        default:
            level_str = "未知";
            break;
    }
    
    printk("安全级别变化: %s -> %s (%d)\n", 
           addr_str, level_str, level);
}

/* 远程信息可用回调 */
static void remote_info_available_cb(struct bt_conn *conn)
{
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_t *addr = bt_conn_get_dst(conn);
    
    bt_addr_le_to_str(addr, addr_str, sizeof(addr_str));
    
    /* 获取远程版本信息 */
    struct bt_conn_info info;
    int err = bt_conn_get_info(conn, &info);
    
    if (err == 0) {
        printk("远程设备信息: %s\n", addr_str);
        printk("  版本: %d.%d\n", 
               info.le.remote_version,
               info.le.remote_subversion);
        printk("  制造商: 0x%04x\n", 
               info.le.remote_features);
    }
}

/* 身份解析回调(隐私特性) */
static void identity_resolved_cb(struct bt_conn *conn,
                                const bt_addr_le_t *rpa,
                                const bt_addr_le_t *identity)
{
    char rpa_str[BT_ADDR_LE_STR_LEN];
    char identity_str[BT_ADDR_LE_STR_LEN];
    
    bt_addr_le_to_str(rpa, rpa_str, sizeof(rpa_str));
    bt_addr_le_to_str(identity, identity_str, sizeof(identity_str));
    
    printk("身份解析完成:\n");
    printk("  RPA地址: %s\n", rpa_str);
    printk("  真实身份地址: %s\n", identity_str);
}

/* 使用 BT_CONN_CB_DEFINE 定义并自动注册回调 */
BT_CONN_CB_DEFINE(conn_callbacks) = {
    .connected = connected_cb,
    .disconnected = disconnected_cb,
    .le_param_updated = le_param_updated_cb,
    .security_changed = security_changed_cb,
    .remote_info_available = remote_info_available_cb,
    .identity_resolved = identity_resolved_cb,
};

/* 初始化函数 */
void connection_manager_init(void)
{
    memset(connections, 0, sizeof(connections));
    printk("连接管理器已初始化\n");
    printk("支持最大连接数: %d\n", MAX_CONNECTIONS);
}

3.2 多模块回调示例

cpp 复制代码
/* 模块1:连接监控 */
BT_CONN_CB_DEFINE(conn_monitor_callbacks) = {
    .connected = monitor_connected,
    .disconnected = monitor_disconnected,
};

static void monitor_connected(struct bt_conn *conn, uint8_t err)
{
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
    
    if (err == 0) {
        log_connection_event("CONNECTED", addr_str);
    }
}

static void monitor_disconnected(struct bt_conn *conn, uint8_t reason)
{
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
    
    log_connection_event("DISCONNECTED", addr_str, reason);
}

/* 模块2:功耗管理 */
BT_CONN_CB_DEFINE(power_manager_callbacks) = {
    .connected = power_connected,
    .disconnected = power_disconnected,
    .le_param_updated = power_param_updated,
};

static void power_connected(struct bt_conn *conn, uint8_t err)
{
    if (err == 0) {
        /* 连接建立,调整功耗策略 */
        adjust_power_policy(POWER_MODE_CONNECTED);
    }
}

static void power_disconnected(struct bt_conn *conn, uint8_t reason)
{
    /* 连接断开,进入低功耗模式 */
    adjust_power_policy(POWER_MODE_IDLE);
}

static void power_param_updated(struct bt_conn *conn, uint16_t interval,
                               uint16_t latency, uint16_t timeout)
{
    /* 根据连接参数调整功耗 */
    if (interval > 80) {
        adjust_power_policy(POWER_MODE_LOW_POWER);
    } else {
        adjust_power_policy(POWER_MODE_NORMAL);
    }
}

4 注意事项和操作方法总结

1) 回调执行顺序

cpp 复制代码
/* 当有多个 BT_CONN_CB_DEFINE 实例时 */
BT_CONN_CB_DEFINE(callbacks1) = { /* ... */ };
BT_CONN_CB_DEFINE(callbacks2) = { /* ... */ };
BT_CONN_CB_DEFINE(callbacks3) = { /* ... */ };

/* 所有回调都会被执行,但顺序不确定 */
/* 不要依赖回调的执行顺序! */

2) 回调函数的性能考虑

cpp 复制代码
/* 错误的做法:在回调中执行耗时操作 */
static void bad_connected_cb(struct bt_conn *conn, uint8_t err)
{
    /* 错误:可能阻塞蓝牙栈 */
    k_sleep(K_SECONDS(1));
    
    /* 错误:复杂计算 */
    perform_heavy_calculation();
    
    /* 错误:I/O操作 */
    write_to_storage();
}

/* 正确的做法:快速处理,推迟复杂操作 */
static void good_connected_cb(struct bt_conn *conn, uint8_t err)
{
    /* 快速处理:记录基本信息 */
    char addr_str[BT_ADDR_LE_STR_LEN];
    bt_addr_le_to_str(bt_conn_get_dst(conn), addr_str, sizeof(addr_str));
    
    /* 提交工作到工作队列进行后续处理 */
    struct k_work *work = k_work_alloc();
    if (work) {
        setup_connection_work(work, conn, err);
        k_work_submit(work);
    }
}

3) 连接对象生命周期管理

cpp 复制代码
/* 正确管理连接引用 */
static void safe_connected_cb(struct bt_conn *conn, uint8_t err)
{
    if (err == 0) {
        /* 如果需要保存连接句柄,必须增加引用计数 */
        struct connection_context *ctx = k_malloc(sizeof(*ctx));
        if (ctx) {
            ctx->conn = conn;
            bt_conn_ref(conn);  // 增加引用计数
            /* ... 存储 ctx ... */
        }
    }
}

static void safe_disconnected_cb(struct bt_conn *conn, uint8_t reason)
{
    /* 在断开回调中释放引用 */
    struct connection_context *ctx = find_context(conn);
    if (ctx) {
        bt_conn_unref(ctx->conn);  // 减少引用计数
        k_free(ctx);
    }
}

4) 错误处理和恢复

cpp 复制代码
/* 健壮的回调实现 */
static void robust_connected_cb(struct bt_conn *conn, uint8_t err)
{
    /* 处理各种错误情况 */
    switch (err) {
        case 0:
            /* 连接成功 */
            handle_connection_success(conn);
            break;
            
        case BT_HCI_ERR_UNKNOWN_CONN_ID:
            printk("错误:未知连接标识\n");
            break;
            
        case BT_HCI_ERR_AUTH_FAIL:
            printk("错误:认证失败\n");
            /* 可以尝试重新连接 */
            schedule_reconnection(conn);
            break;
            
        case BT_HCI_ERR_CONN_TIMEOUT:
            printk("错误:连接超时\n");
            break;
            
        default:
            printk("连接错误: 0x%02x\n", err);
            break;
    }
}

5 实际应用场景

5.1 中央设备(Central)应用

cpp 复制代码
/* 中央设备连接管理器 */
struct central_manager {
    struct bt_conn *active_conn;
    struct k_work connect_work;
    struct k_work disconnect_work;
};

BT_CONN_CB_DEFINE(central_callbacks) = {
    .connected = central_connected,
    .disconnected = central_disconnected,
    .le_param_updated = central_param_updated,
};

static void central_connected(struct bt_conn *conn, uint8_t err)
{
    if (err == 0) {
        /* 启动服务发现 */
        start_service_discovery(conn);
        
        /* 设置连接参数为最优值 */
        request_optimal_connection_params(conn);
    }
}

static void central_disconnected(struct bt_conn *conn, uint8_t reason)
{
    /* 清理资源 */
    cleanup_connection_resources(conn);
    
    /* 根据原因决定是否重连 */
    if (reason == BT_HCI_ERR_CONN_TIMEOUT) {
        schedule_reconnection(conn);
    }
}

5.2 外围设备(Peripheral)应用

cpp 复制代码
/* 外围设备连接处理器 */
BT_CONN_CB_DEFINE(peripheral_callbacks) = {
    .connected = peripheral_connected,
    .disconnected = peripheral_disconnected,
    .security_changed = peripheral_security_changed,
};

static void peripheral_connected(struct bt_conn *conn, uint8_t err)
{
    if (err == 0) {
        /* 更新连接状态LED */
        set_led_state(LED_CONNECTED);
        
        /* 通知应用层 */
        notify_application_connected(conn);
    }
}

static void peripheral_security_changed(struct bt_conn *conn, 
                                       bt_security_t level)
{
    /* 根据安全级别启用/禁用特定服务 */
    if (level >= BT_SECURITY_L2) {
        enable_secure_services(conn);
    } else {
        disable_secure_services(conn);
    }
}

5.3 多角色设备(Central+Peripheral)

cpp 复制代码
/* 同时作为Central和Peripheral的设备 */
BT_CONN_CB_DEFINE(dual_role_callbacks) = {
    .connected = dual_role_connected,
    .disconnected = dual_role_disconnected,
    .identity_resolved = dual_role_identity_resolved,
};

static void dual_role_connected(struct bt_conn *conn, uint8_t err)
{
    bt_conn_info info;
    bt_conn_get_info(conn, &info);
    
    if (info.role == BT_CONN_ROLE_CENTRAL) {
        printk("作为Central连接到外围设备\n");
        handle_central_connection(conn, err);
    } else {
        printk("作为Peripheral被中心设备连接\n");
        handle_peripheral_connection(conn, err);
    }
}
相关推荐
ScilogyHunter14 天前
Zephyr串口驱动开发及构建完全指南
驱动开发·uart·zephyr
ScilogyHunter14 天前
Zephyr Hello World应用开发构建完全指南
zephyr·hello world
ScilogyHunter14 天前
Zephyr Twister测试框架完全指南
zephyr·twister
ScilogyHunter15 天前
west init 命令详解
init·zephyr·west
ScilogyHunter15 天前
使用Kconfig配置Zephyr工程完全指南
kconfig·zephyr
ScilogyHunter15 天前
Zephyr设备树完全指南
zephyr
ScilogyHunter16 天前
Zephyr项目按需配置完全指南
zephyr
ScilogyHunter16 天前
Zephyr最简工程配置指南
zephyr
ScilogyHunter16 天前
Zephyr主仓库目录结构完全指南
zephyr
ScilogyHunter16 天前
Zephyr工程配置完全指南
zephyr