news 2026/4/29 4:17:36

Zephyr RTOS 中 BT_CONN_CB_DEFINE 详解

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Zephyr RTOS 中 BT_CONN_CB_DEFINE 详解

目录

概述

1 BT_CONN_CB_DEFINE 和原理介绍

1.1 基本定义

1.2 核心功能和工作原理

1.3 与传统注册方式的对比

1.4 BT_CONN_CB_DEFINE 的核心优势

2 基本用法

2.1 最简单的使用示例

2.2 完整回调结构体定义

3 高级用法和完整示例

3.1 完整的连接管理示例

3.2 多模块回调示例

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

5 实际应用场景

5.1 中央设备(Central)应用

5.2 外围设备(Peripheral)应用

5.3 多角色设备(Central+Peripheral)


概述

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

1BT_CONN_CB_DEFINE和原理介绍

1.1 基本定义

// 在 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 最简单的使用示例

#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 完整回调结构体定义

/* 连接回调结构体 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 完整的连接管理示例

#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 多模块回调示例

/* 模块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)回调执行顺序

/* 当有多个 BT_CONN_CB_DEFINE 实例时 */ BT_CONN_CB_DEFINE(callbacks1) = { /* ... */ }; BT_CONN_CB_DEFINE(callbacks2) = { /* ... */ }; BT_CONN_CB_DEFINE(callbacks3) = { /* ... */ }; /* 所有回调都会被执行,但顺序不确定 */ /* 不要依赖回调的执行顺序! */

2)回调函数的性能考虑

/* 错误的做法:在回调中执行耗时操作 */ 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)连接对象生命周期管理

/* 正确管理连接引用 */ 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)错误处理和恢复

/* 健壮的回调实现 */ 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)应用

/* 中央设备连接管理器 */ 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)应用

/* 外围设备连接处理器 */ 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)

/* 同时作为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); } }
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/29 4:17:33

Phi-3-mini-4k-instruct-gguf实战案例:用5条提示词完成会议纪要自动整理

Phi-3-mini-4k-instruct-gguf实战案例&#xff1a;用5条提示词完成会议纪要自动整理 1. 会议纪要自动整理的痛点 作为一名经常需要参加各种会议的职场人士&#xff0c;我深知手动整理会议纪要的痛苦。每次会议结束后&#xff0c;面对录音或潦草的笔记&#xff0c;需要花费大量…

作者头像 李华
网站建设 2026/4/29 4:17:04

企业内部通讯软件是什么?

一、企业内部通讯软件的定义 企业内部通讯软件&#xff0c;又称企业即时通讯&#xff08;Enterprise Instant Messaging&#xff0c;简称企业IM&#xff09;&#xff0c;是一种专门面向企业内部员工使用的即时交流与沟通工具。从广义上说&#xff0c;企业IM是一种面向企业使用的…

作者头像 李华
网站建设 2026/4/29 4:16:59

Phi-3.5-Mini-Instruct本地化部署教程:Windows/macOS/Linux三端适配

Phi-3.5-Mini-Instruct本地化部署教程&#xff1a;Windows/macOS/Linux三端适配 1. 项目概述 Phi-3.5-Mini-Instruct是微软推出的轻量级大语言模型&#xff0c;专为本地化部署优化设计。本教程将带您完成在Windows、macOS和Linux三大操作系统上的完整部署流程&#xff0c;无需…

作者头像 李华
网站建设 2026/4/29 4:16:37

XXMI Launcher终极指南:一站式游戏模组管理平台快速上手

XXMI Launcher终极指南&#xff1a;一站式游戏模组管理平台快速上手 【免费下载链接】XXMI-Launcher Modding platform for GI, HSR, WW and ZZZ 项目地址: https://gitcode.com/gh_mirrors/xx/XXMI-Launcher XXMI Launcher是一款专为米哈游游戏玩家设计的游戏模组管理器…

作者头像 李华