目录
[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 的核心优势
简化代码:无需手动注册回调
提高可靠性:避免因忘记注册回调导致的bug
支持模块化:各模块可以独立定义自己的回调
编译时优化:编译器可以进行更好的优化
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);
}
}