杰理 SDK 文档中心
首页
首页
  • SDK 概述与入门

    • SDK 总览
    • 支持芯片与蓝牙认证
    • 工程结构导航
  • 开发环境与构建

    • 环境搭建与工具链安装
    • 编译指南与工程选择
    • 烧录与生产工具
  • BLE 透传/数传应用

    • 透传应用框架与处理模块
    • 透传与数传示例
    • 多连接与自定义服务示例
    • FindMy 与查找网络示例
  • HID 人机交互应用

    • 键盘与按键设备示例
    • 鼠标设备示例
    • 遥控器示例
    • HID 蓝牙应用模块
  • 公共 BSP 模块

    • 按键、编码器与红外输入
    • 传感器驱动
    • LED 与显示控制
    • 串口与 USB 通信
    • 存储、参数与时钟
    • 电源与温度管理
    • 消息、内存与系统配置
    • OTA 升级框架
  • 蓝牙协议栈与库

    • BLE 控制器与协议栈适配
    • 经典蓝牙 BR/EDR 支持
    • 第三方蓝牙协议
    • 设备管理框架
    • DUT 测试与射频认证
  • 构建系统与开发工具

    • Makefile 构建系统
    • 固件后处理与配置工具
    • 辅助脚本与库合并
  • 文档与硬件资料

    • AT 命令参考
    • 硬件参考资料
    • SDK 文档与在线资源

多连接与自定义服务示例

本页介绍 AW33N BLE SDK 中 apps/demo/transfer/examples/multi_conn 多连接示例(CONFIG_APP_MULTI),包括其角色架构、初始化流程、GATT 控制块、安全管理配置、低功耗处理方式以及基于自定义 GATT Profile 的多链路服务实现方式。

Purpose and Scope

本页覆盖以下内容:

  • multi_conn 示例的模块划分(peripheral / central / adv / scan / profile)与文件职责;
  • 多连接应用从注册、启动到 BLE 协议栈初始化的完整控制流;
  • GATT 控制块(gatt_ctrl_t)中 multi_dev_flag 多设备标志与多链路 ATT 相关 API(multi_att_*);
  • 多角色(server + client + 非连接 adv/scan)同时运行的控制器层配置(lib_btctrler_config.c);
  • 低功耗(软关机)流程中多链路断开的处理。

以下内容属于其他页面,不在本页展开:通用 BLE 通信框架 ble_comm 的完整实现、单独的单连接 GATT Server/Client 示例(如 simple_ble)、dongle/OTA 示例以及 RCSP 协议。相关页面见文末 Related Links。

Overview

在典型的单连接 BLE 应用中,设备要么作为 GATT Server 被手机连接,要么作为 GATT Client 去连接外设,链路数量固定为一。multi_conn 示例演示的是 SDK 的多链路能力:同一台设备可以同时运行多个 GATT Server 实例(被多台主机连接)、多个 GATT Client 实例(同时连接多台从机),并且可以叠加非连接的广播(ADV)与扫描(SCAN)通道。这种能力适用于 TWS/音箱双连接、一拖多遥控器、数据采集网关等场景。

该示例由以下几个子模块构成,每个子模块都可以通过编译宏独立开关:

  • ble_multi_peripheral.c / ble_multi_central.c:多 GATT Server / 多 GATT Client 的实现,二者内部的 Profile 定义集中在 ble_multi_profile.h,即"自定义服务"的载体;
  • ble_multi_adv.c / ble_multi_scan.c:非连接广播与扫描通道,可叠加在连接通道之上;
  • ble_multi.c:多连接模块的核心胶水层,负责 GATT 控制块、安全配置与初始化编排;
  • app_multi_conn.c:应用层入口,定义 ble_init_cfg_t 配置并驱动整个 app 的消息循环。

设计上,SDK 通过 gatt_ctrl_t.multi_dev_flag = 1 显式打开多设备模式,控制器层通过 config_btctler_le_master_multilink 等配置使能底层多链路调度,从而把"多连接"从应用层一路贯通到射频链路层。

Architecture

flowchart TD
    subgraph sg_App["应用层 (apps/demo/transfer)"]
        AppMain["app_main.c<br/>CONFIG_APP_MULTI → ACTION_MULTI_MAIN"]
        AppMultiConn["app_multi_conn.c<br/>multi_data_config (ble_init_cfg_t)"]
    end

    subgraph sg_Multi["multi_conn 示例模块"]
        MultiCore["ble_multi.c<br/>gatt 控制块 + sm 配置"]
        Server["ble_multi_peripheral.c<br/>多 GATT Server"]
        Client["ble_multi_central.c<br/>多 GATT Client"]
        Profile["ble_multi_profile.h<br/>自定义服务 Profile"]
        Adv["ble_multi_adv.c<br/>非连接广播"]
        Scan["ble_multi_scan.c<br/>非连接扫描"]
    end

    subgraph sg_Stack["协议栈层 (apps/include_lib/bt_include)"]
        BleComm["ble_comm (le_gatt_common.h)"]
        Att["att.h<br/>multi_att_set/get/clear_ccc_config"]
        GattCtrl["gatt_ctrl_t<br/>multi_dev_flag"]
    end

    subgraph sg_Ctrl["控制器配置层 (config)"]
        BtCtrlCfg["lib_btctrler_config.c<br/>multi-link 角色配置"]
    end

    AppMain -->|"ACTION_MULTI_MAIN"| AppMultiConn
    AppMultiConn -->|"bt_ble_init / bt_ble_before_start_init / bt_ble_exit"| MultiCore
    MultiCore -->|"multi_server_init"| Server
    MultiCore -->|"multi_client_init"| Client
    Server --> Profile
    Client --> Profile
    MultiCore -->|"multi_adv_init/enable"| Adv
    MultiCore -->|"multi_scan_init/enable"| Scan
    MultiCore -->|"ble_comm_init(&ctrl_block)"| BleComm
    BleComm --> GattCtrl
    BleComm --> Att
    GattCtrl -->|"server/client 数量宏"| BtCtrlCfg

如上图所示,多连接能力是一条从应用入口到控制器层的完整链路:app_main.c 根据 CONFIG_APP_MULTI 把应用名注册为 multi_conn 并派发到 ACTION_MULTI_MAIN;app_multi_conn.c 通过 ble_init_cfg_t 把 multi_bt_ble_init、multi_bt_ble_before_start_init、multi_bt_ble_exit 等回调挂到协议栈;ble_multi.c 则统一装配 GATT 控制块、安全配置并逐个初始化 server/client/adv/scan 子模块。底层 ble_comm 依赖 att.h 提供的 multi_att_* 系列 API 维护每连接独立的 CCC(Client Characteristic Configuration)状态,这是多链路 GATT 通信正确性的关键。

实现详解

1. 应用注册与入口分发

multi_conn 是 transfer demo 下的一个可选应用,通过编译宏 CONFIG_APP_MULTI 启用。在 app_main.c 中,应用名被注册为 "multi_conn",动作类型为 ACTION_MULTI_MAIN:

#elif CONFIG_APP_MULTI
    it->name = "multi_conn";
    it->action = ACTION_MULTI_MAIN;

Source: app_main.c

随后 app_multi_conn.c 定义 multi_data_config(类型 ble_init_cfg_t),把多连接模块的生命周期回调全部挂载到协议栈。这里 same_address = 0 表示多链路各实例使用独立的地址(避免多个角色共用地址导致链路冲突),appearance = 0 表示不广播外观字段:

static const ble_init_cfg_t multi_data_config = {
    .same_address = 0,
    .appearance = 0,
    .ble_profile_init = comm_ble_profile_init,
    .bt_ble_init  = multi_bt_ble_init,
    .bt_ble_before_start_init = multi_bt_ble_before_start_init,
    .bt_ble_exit = multi_bt_ble_exit,
    .ble_module_enable = multi_ble_module_enable,
};

Source: app_multi_conn.c

multi_app_start() 是应用主入口:先初始化时钟,再调用 multi_bt_start() 完成 PLL 配置与协议栈启动,最后进入消息循环,所有事件(按键、BLE 事件、电源事件等)统一交给 app_comm_process_handler 处理:

static void multi_app_start()
{
    log_info("-----------multi_conn demo-------------");
    clock_bt_init();
    clk_set("sys", TCFG_CLOCK_SYS_HZ);
    clk_set("lsb", TCFG_CLOCK_LSB_HZ);
    clk_set("sfc", TCFG_CLOCK_SFC_HZ);
    multi_bt_start();
    int msg[4] = {0};
    while (1) {
        get_msg(sizeof(msg) / sizeof(int), msg);
        app_comm_process_handler(msg);
    }
}

Source: app_multi_conn.c

multi_bt_start() 在启动协议栈前先配置蓝牙 PLL 参数,然后调用 btstack_ble_start_before_init(&multi_data_config, 0) 注册配置,最后 btstack_init() 拉起协议栈任务:

static void multi_bt_start(void)
{
    uint32_t sys_clk =  clk_get("sys");
    bt_pll_para(TCFG_CLOCK_OSC_HZ, sys_clk, 0, 0);
    btstack_ble_start_before_init(&multi_data_config, 0);
    btstack_init();
}

Source: app_multi_conn.c

2. GATT 控制块:多设备模式的开关

多连接的核心在于 ble_multi.c 中定义的 multi_gatt_control_block。gatt_ctrl_t 的 multi_dev_flag = 1 显式告知 GATT 层按照多设备模式运行——ATT 缓存、CCC 配置、发送队列都必须按连接句柄(conn_handle)区分:

//gatt 控制块初始化
static gatt_ctrl_t multi_gatt_control_block = {
    //public
    .mtu_size = ATT_LOCAL_MTU_SIZE,
    .cbuffer_size = ATT_SEND_CBUF_SIZE,
    .multi_dev_flag	= 1,

    //config
#if CONFIG_BT_GATT_SERVER_NUM
    .server_config = &multi_server_init_cfg,
#else
    .server_config = NULL,
#endif

#if CONFIG_BT_GATT_CLIENT_NUM
    .client_config = &multi_client_init_cfg,
#else
    .client_config = NULL,
#endif

#if CONFIG_BT_SM_SUPPORT_ENABLE
    .sm_config = &multi_sm_init_config,
#else
    .sm_config = NULL,
#endif
    //cbk,event handle
    .hci_cb_packet_handler = NULL,
};

Source: ble_multi.c

要点解读:

  • server_config / client_config 分别指向多 Server 与多 Client 的初始化配置(multi_server_init_cfg / multi_client_init_cfg),它们由 ble_multi_peripheral.c / ble_multi_central.c 提供,并在文件中以 extern 声明引用(见 ble_multi.c L71-L72);
  • mtu_size 取 ATT_LOCAL_MTU_SIZE,cbuffer_size 由 ble_multi.h 中的宏计算得出——ATT_PACKET_NUMS_MAX (2) 表示 ATT 发送缓存支持 2 个待发数据包,每个包的大小为 ATT_PACKET_HEAD_SIZE + ATT_LOCAL_MTU_SIZE:
//ATT缓存的buffer支持缓存数据包个数
#define ATT_PACKET_NUMS_MAX       (2)

//ATT缓存的buffer大小,  note: need >= 23,可修改
#define ATT_SEND_CBUF_SIZE        (ATT_PACKET_NUMS_MAX * (ATT_PACKET_HEAD_SIZE + ATT_LOCAL_MTU_SIZE))

Source: ble_multi.h

multi_dev_flag = 1 在多连接场景下至关重要:单连接模式下 CCC 配置通常是全局一份,多连接模式下每个对端设备各自使能/关闭通知,因此必须按 conn_handle 隔离。协议栈为此提供了 multi_att_set_ccc_config / multi_att_get_ccc_config / multi_att_clear_ccc_config 三个按连接句柄操作的 API(att.h L114-L118),链路断开时用 multi_att_clear_ccc_config(conn_handle) 清理该链路的 CCC 状态。

3. 安全管理配置

multi_sm_init_config 定义了多连接模式下的配对/加密策略:主机侧(Client)主动发起安全请求并等待安全完成;从机侧(Server)不主动请求安全,但等待安全流程完成。默认 io_capabilities = IO_CAPABILITY_NO_INPUT_NO_OUTPUT(无输入输出,即 Just Works 配对),如需 PIN 码配对可打开 PASSKEY_ENABLE 宏切换为 IO_CAPABILITY_DISPLAY_ONLY:

//输入passkey 加密
#define PASSKEY_ENABLE                     0

static const sm_cfg_t multi_sm_init_config = {
    .master_security_auto_req = 1,
    .master_set_wait_security = 1,
    .slave_security_auto_req = 0,
    .slave_set_wait_security = 1,

#if PASSKEY_ENABLE
    .io_capabilities = IO_CAPABILITY_DISPLAY_ONLY,
#else
    .io_capabilities = IO_CAPABILITY_NO_INPUT_NO_OUTPUT,
#endif

    .authentication_req_flags = SM_AUTHREQ_BONDING | SM_AUTHREQ_MITM_PROTECTION,
    .min_key_size = 7,
    .max_key_size = 16,
    .sm_cb_packet_handler = NULL,
};

Source: ble_multi.c

设计意图:master_security_auto_req = 1 保证 Client 在连接建立后自动触发加密协商,无需应用层额外调用;slave_set_wait_security = 1 则让 Server 端在收到安全请求前保持等待状态,二者配合确保主从双方都能感知链路安全状态。authentication_req_flags 同时设置 Bonding 与 MITM 保护,密钥长度范围 7~16 字节,符合 BLE 安全规范中对加密密钥长度的要求。

4. BLE 初始化编排(核心控制流)

ble_multi.c 的三个回调 multi_bt_ble_before_start_init → multi_bt_ble_init → multi_bt_ble_exit 对应协议栈生命周期的三个阶段。

启动前初始化在协议栈任务运行之前执行,将 GATT 控制块交给 ble_comm 框架:

void multi_bt_ble_before_start_init(void)
{
    log_info("%s", __FUNCTION__);
    ble_comm_init(&multi_gatt_control_block);
}

Source: ble_multi.c

正式初始化按依赖顺序执行:先设置本地名称,再分别初始化 GATT Server 与 GATT Client(各自内部完成自定义 Profile 注册),随后使能 BLE 模块,最后叠加非连接广播与扫描通道:

void multi_bt_ble_init(void)
{
    log_info("%s\n", __FUNCTION__);
    ble_comm_set_config_name(bt_get_local_name(), 1);

#if CONFIG_BT_GATT_SERVER_NUM
    multi_server_init();
#if CFG_USE_24G_CODE_ID_ADV
    rf_set_adv_24g_hackable_coded(CFG_RF_24G_CODE_ID_ADV);//设置为2.4g模式
#endif
#endif

#if CONFIG_BT_GATT_CLIENT_NUM
    multi_client_init();
#if CFG_USE_24G_CODE_ID_SCAN
    rf_set_scan_24g_hackable_coded(CFG_RF_24G_CODE_ID_SCAN);//设置为2.4g模式
#endif
#endif

    ble_module_enable(1);

#if CONFIG_BT_NOCONN_ADV_NUM
    multi_adv_init();
    multi_adv_enable(1);
#endif

#if CONFIG_BT_NOCONN_SCAN_NUM
    multi_scan_init();
    ble_comm_dev_scan_report_handler_register(multi_scan_report_handle);
    multi_scan_enable(1);
#endif
}

Source: ble_multi.c

注意 multi_scan_init() 之后通过 ble_comm_dev_scan_report_handler_register(multi_scan_report_handle) 把扫描上报回调注册到 ble_comm,说明非连接扫描与连接管理共用同一套设备发现框架。

退出流程与初始化严格对称,先关 BLE 模块,再退出 ble_comm,最后退出各子模块:

void multi_bt_ble_exit(void)
{
    log_info("%s\n", __FUNCTION__);
    ble_module_enable(0);
    ble_comm_exit();

#if CONFIG_BT_GATT_SERVER_NUM
    multi_server_exit();
#endif

#if CONFIG_BT_GATT_CLIENT_NUM
    multi_client_exit();
#endif
}

Source: ble_multi.c

按键测试入口 ble_multi_key_test() 则按编译宏把按键事件分发给 Client 与 Server 两侧,便于在没有手机 App 时用按键验证多链路收发(ble_multi.c L103-L112)。

5. 控制器层多链路配置

多连接不是纯应用层特性,底层控制器(BT Controller)必须同时调度多条链路。config/lib_btctrler_config.c 中按 CONFIG_APP_MULTI 调整角色配置宏:当存在非连接广播时从机角色仅保留 LE_ADV,当存在非连接扫描时主机角色仅保留 LE_SCAN,并且只要四个通道数量之和大于 1 就打开主链路多连接开关:

#elif CONFIG_APP_MULTI && CONFIG_BT_NOCONN_ADV_NUM
#define SET_SLAVE_ROLS_CFG   (LE_ADV)
...
#elif CONFIG_APP_MULTI && CONFIG_BT_NOCONN_SCAN_NUM
#define SET_MASTER_ROLS_CFG   (LE_SCAN)
...
#if CONFIG_APP_MULTI
const int config_btctler_le_master_multilink = ((CONFIG_BT_GATT_CLIENT_NUM + CONFIG_BT_GATT_SERVER_NUM + CONFIG_BT_NOCONN_SCAN_NUM + CONFIG_BT_NOCONN_ADV_NUM) > 1) ? 1 : 0;
#else

Source: lib_btctrler_config.c

这里 config_btctler_le_master_multilink 是控制器多链路调度的总开关,取值取决于 GATT Client 数、GATT Server 数、扫描数与广播数之和。这意味着"多连接"的最终形态(纯双从机、纯多主机、主机+从机+广播+扫描混跑)完全由这四组宏决定,应用代码无需改动。

Core Flow

下面是多连接示例从上电到建立两条链路的完整时序:

sequenceDiagram
    participant App as app_main / app_multi_conn
    participant MC as ble_multi.c
    participant BC as ble_comm
    participant Stack as BTStack
    participant Ctrl as BT Controller
    participant Peer as 对端设备(手机/从机)

    App->>MC: btstack_ble_start_before_init(&multi_data_config)
    App->>MC: btstack_init() 启动协议栈
    MC->>BC: multi_bt_ble_before_start_init → ble_comm_init(&multi_gatt_control_block)
    Note over BC: multi_dev_flag=1 打开多设备模式
    MC->>MC: multi_bt_ble_init
    MC->>MC: multi_server_init() 注册自定义服务
    MC->>MC: multi_client_init() 注册客户端
    MC->>MC: ble_module_enable(1)
    MC->>MC: multi_adv_init/enable、multi_scan_init/enable
    Stack->>Ctrl: 使能 ADV / SCAN
    Peer->>Stack: 连接请求 (作为 Server 被连接)
    Stack-->>MC: 连接事件 (conn_handle A)
    MC->>BC: 按 conn_handle A 管理 GATT/CCC
    MC->>Stack: 主动连接对端 (作为 Client)
    Stack-->>MC: 连接完成 (conn_handle B)
    MC->>BC: 按 conn_handle B 管理 GATT/CCC
    Note over MC,BC: multi_att_set_ccc_config(conn_handle, ...) 每链路独立

时序要点:

  1. 协议栈启动前,ble_comm_init 收到带 multi_dev_flag=1 的控制块,此后所有 GATT 状态均按连接句柄隔离;
  2. Server/Client 各自初始化后,设备同时处于"可被连接"与"可主动连接"状态,并叠加广播/扫描通道;
  3. 每条链路建立后,CCC 配置、通知使能、发送队列都绑定各自的 conn_handle,互不干扰;
  4. 低功耗/软关机时,multi_set_soft_poweroff 先主动断开所有链路再进入低功耗,避免链路超时导致关机失败(见下一节)。

6. 低功耗与软关机处理

多链路场景下进入低功耗比单连接更复杂:任何一条链路不断开,射频都必须保持活跃。app_multi_conn.c 的 multi_set_soft_poweroff() 展示了标准处理流程——先主动关闭协议栈链路,再根据剩余连接情况决定是立即软关机还是等待断开:

static void multi_set_soft_poweroff(void)
{
    log_info("set_soft_poweroff\n");

#if (TCFG_LOWPOWER_PATTERN == SOFT_MODE)
    multi_is_active = 1;
#elif (TCFG_LOWPOWER_PATTERN == SOFT_BY_POWER_MODE)
    multi_is_active = 0;//allow enter lowpower
#endif
    //必须先主动断开蓝牙链路,否则要等链路超时断开
    btstack_ble_exit(0);
    //延时,确保BT退出链路断开

    if (ble_comm_dev_is_connected(GATT_ROLE_SERVER) || ble_comm_dev_is_connected(GATT_ROLE_CLIENT)) {
#if (TCFG_LOWPOWER_PATTERN == SOFT_MODE)
        //soft 方式非必须等链路断开
        sys_timeout_add((void *)POWER_EVENT_POWER_SOFTOFF, (void *)app_power_event_to_user, WAIT_DISCONN_TIME_MS);
#elif (TCFG_LOWPOWER_PATTERN == SOFT_BY_POWER_MODE)
        //must wait disconn
        app_power_soft.wait_disconn = 1;
#endif
    } else {
        app_power_set_soft_poweroff(NULL);
    }
}

Source: app_multi_conn.c

其中 ble_comm_dev_is_connected(GATT_ROLE_SERVER) / ble_comm_dev_is_connected(GATT_ROLE_CLIENT) 分别查询从机侧与主机侧是否仍存在活动链路——这是多连接特有的检查,单连接实现通常只查一个角色。multi_is_active 标志(app_multi_conn.c L49)配合 multi_state_idle_set_active() 控制空闲状态是否允许进入低功耗;app_to_recover() 则预留了恢复流程的钩子(默认注释掉 scan 低功耗开关)。

Configuration Options

多连接示例的行为完全由编译宏驱动,无运行时配置。关键选项如下:

配置项类型默认/取值说明
CONFIG_APP_MULTIbool0/1是否编译 multi_conn 应用(应用注册名 "multi_conn")
CONFIG_BT_GATT_SERVER_NUMint0~NGATT Server 实例数量,即"可同时被多少台主机连接"
CONFIG_BT_GATT_CLIENT_NUMint0~NGATT Client 实例数量,即"可同时主动连接多少台从机"
CONFIG_BT_NOCONN_ADV_NUMint0~N非连接广播通道数量(叠加在连接之上)
CONFIG_BT_NOCONN_SCAN_NUMint0~N非连接扫描通道数量
CONFIG_BT_SM_SUPPORT_ENABLEbool0/1是否使能安全管理器;为 0 时 sm_config 置 NULL
PASSKEY_ENABLEbool0置 1 时 io_capabilities 切换为 IO_CAPABILITY_DISPLAY_ONLY(PIN 码配对)
ATT_PACKET_NUMS_MAXint2ATT 发送缓存支持的数据包个数(可修改)
ATT_SEND_CBUF_SIZEint派生ATT 发送缓存总大小,需 ≥ 23 字节
CFG_USE_24G_CODE_ID_ADV/SCANbool0/1是否将广播/扫描切换为 2.4G 私有模式(rf_set_*_24g_hackable_coded)
TCFG_LOWPOWER_PATTERNenumSOFT_MODE 等低功耗模式,决定软关机是否等待链路断开
WAIT_DISCONN_TIME_MSint自定义软关机等待链路断开的超时时间

其中 Server/Client/Adv/Scan 四个数量宏不仅决定应用层初始化哪些子模块,还通过 config_btctler_le_master_multilink 决定控制器是否进入多链路调度模式(见 lib_btctrler_config.c L176)。

API Reference

ble_multi.h 声明了多连接模块对外暴露的全部接口(ble_multi.h L17-L37):

生命周期接口

函数说明
void multi_bt_ble_before_start_init(void)协议栈启动前调用,执行 ble_comm_init(&multi_gatt_control_block) 注册 GATT 控制块
void multi_bt_ble_init(void)协议栈启动后初始化 Server/Client/Adv/Scan 全部子模块并 ble_module_enable(1)
void multi_bt_ble_exit(void)关闭 BLE 模块并依次退出 ble_comm、Server、Client
void multi_ble_module_enable(uint8_t en)使能/关闭 BLE 模块(透传 ble_comm_module_enable)
void multi_state_idle_set_active(uint8_t active)设置空闲状态是否允许进入低功耗

子模块接口

函数说明
void multi_server_init(void) / multi_server_exit(void)多 GATT Server 初始化/退出(自定义服务注册)
void multi_client_init(void) / multi_client_exit(void)多 GATT Client 初始化/退出
int multi_server_clear_pair(void) / int multi_client_clear_pair(void)清除 Server/Client 侧配对信息
void multi_server_key_test(uint8_t key_type, uint8_t key_value) / multi_client_key_test(...)按键测试分发,验证收发
void ble_multi_key_test(uint8_t key_type, uint8_t key_value)按键测试总入口,按宏分发给 Client/Server
void multi_adv_init(void) / multi_adv_enable(u8 enable)非连接广播初始化/使能
void multi_scan_init(void) / multi_scan_enable(u8 enable)非连接扫描初始化/使能
void multi_scan_report_handle(adv_report_t *report_pt, uint16_t len)扫描上报回调,注册给 ble_comm 使用

多链路 ATT 辅助 API(协议栈提供)

函数说明
void multi_att_set_ccc_config(uint16_t conn_handle, uint16_t att_handle, uint16_t cfg)按连接句柄设置某属性的 CCC 值
uint16_t multi_att_get_ccc_config(uint16_t conn_handle, uint16_t att_handle)按连接句柄读取某属性的 CCC 值
int multi_att_clear_ccc_config(uint16_t conn_handle)断开时清除指定链路的所有 CCC 状态

Source: att.h

自定义服务(Profile)扩展方式

"自定义服务"在多连接示例中的载体是 ble_multi_profile.h 与 ble_multi_peripheral.c / ble_multi_central.c。扩展一个新服务时,遵循以下模式:

  1. 在 ble_multi_profile.h 中定义服务 UUID、特征 UUID 与句柄索引(该文件位于 examples/multi_conn/ 目录下,与 ble_multi.c 同目录,被 Server/Client 两端共同引用);
  2. 在 ble_multi_peripheral.c 的 multi_server_init_cfg(gatt_server_cfg_t)中把新服务加入服务表;
  3. 若该服务需要向对端发送通知,使用 multi_att_set_ccc_config(conn_handle, handle, ...) 按链路维护 CCC;
  4. Server/Client 数量宏(CONFIG_BT_GATT_SERVER_NUM / CONFIG_BT_GATT_CLIENT_NUM)决定协议栈为该服务分配多少实例。

由于本示例的四个数量宏全部独立可配,同一份 Profile 代码即可编译成"纯双从机"、"一主多从"或"主从+广播扫描混跑"等不同形态。

失败模式、边界情况与并发

  • 链路断开清理:多链路下断开事件按 conn_handle 区分,必须调用 multi_att_clear_ccc_config(conn_handle) 清理该链路的 CCC,否则新连接可能读到残留的使能状态(协议栈 API 见 att.h L114-L118)。
  • 软关机等待链路断开:SOFT_BY_POWER_MODE 下必须等所有链路断开(app_power_soft.wait_disconn = 1)才能关机,否则射频仍占用功耗;SOFT_MODE 下则通过 sys_timeout_add(..., WAIT_DISCONN_TIME_MS) 延迟关机,超时后强制执行。
  • 地址冲突:multi_data_config.same_address = 0 明确要求多实例使用不同地址。若改为 1(共享地址),多角色同时广播/扫描可能造成地址解析冲突,应避免在混跑模式下使用。
  • ATT 发送缓存瓶颈:ATT_SEND_CBUF_SIZE 仅支持 ATT_PACKET_NUMS_MAX = 2 个待发包。多链路并发下发通知时,发送缓冲是共享的,若多条链路同时产生大量数据,可能出现队列拥塞,需要按业务调节包数或错峰发送。
  • 安全流程并发:master_security_auto_req = 1 使每条 Client 链路在连接后自动发起加密。多条链路同时建连时,安全协商按链路串行完成,master_set_wait_security / slave_set_wait_security 保证双方都等待安全状态稳定后再进行数据收发。

性能与运维

  • 资源占用与宏强相关:每个 Server/Client 实例都会占用 ATT 缓存、链路资源与 RAM,实例数量由 CONFIG_BT_GATT_SERVER_NUM 等宏决定,按需裁剪可显著降低内存占用。
  • 日志开关:MULTI_CONN 日志标签在 log_config.c L176-L180 中统一控制(log_tag_const_v/i/d/w/e_MULTI_CONN),排查多链路问题时建议打开 d 级日志观察每链路事件。
  • 24G 私有模式:CFG_USE_24G_CODE_ID_ADV/SCAN 可把广播/扫描切换到 2.4G 私有编码模式,用于私有协议互联;开启后蓝牙标准连接行为不受影响,但需确认对端同样支持该模式。

Related Links

  • ble_multi.c(核心胶水层)
  • app_multi_conn.c(应用入口与低功耗)
  • ble_multi.h(接口与缓存宏定义)
  • lib_btctrler_config.c(控制器多链路配置)
  • att.h(多链路 ATT/CCC API)
  • 示例目录其他子模块:ble_multi_peripheral.c、ble_multi_central.c、ble_multi_profile.h、ble_multi_adv.c、ble_multi_scan.c(位于 apps/demo/transfer/examples/multi_conn/)
  • 相关页面:BLE 通信公共框架(ble_comm)、单连接 GATT Server/Client 示例、dongle/OTA 示例
Prev
透传与数传示例
Next
FindMy 与查找网络示例