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);
    }
}
相关推荐
mftang20 天前
Nordic nRF52805 Zephyr OS下低功耗模式应用详细介绍-D
watchdog·低功耗·zephyr
硬汉嵌入式23 天前
Zephyr 十周年报告:开源嵌入式创新的十年历程
zephyr
fitpolo24 天前
串行通讯(I2C)
zephyr
mftang2 个月前
Zephyr RTOS中的k_stack相关函数
zephyr·k_stack
fitpolo2 个月前
向控制台打印消息并进行日志记录
zephyr
智驾3 个月前
【瑞萨RA8D1 LVGL/LWIP评测】二、CPKCOR-RA8D1B Zephyr工程适配
瑞萨·zephyr·ra8d1 lvgl/lwip
智驾3 个月前
【瑞萨RA x Zephyr评测】四、在线调试功能
vscode·debug·瑞萨·zephyr·renesas·ra6e2·fpb-ra6e2
智驾4 个月前
【瑞萨RA x Zephyr评测】三、CAN模块测试
嵌入式·瑞萨·canfd·zephyr·renesas·ra6e2
星源~4 个月前
Zephyr - MCU 开发快速入门指南
单片机·嵌入式硬件·物联网·嵌入式开发·zephyr