第三方蓝牙协议
本页介绍 AW33N BLE SDK 中第三方蓝牙协议(Profile)的实现机制:从杰理 GATT Profile 生成工具产出 profile_data[] 静态属性表,到 lib_profile_config.c 中的协议开关配置,以及 HID/HOGP、透传数据、AT 指令透传、Find My、Google FHN、多连接、快速开关机等典型第三方 Profile 的工程组织方式。
Purpose and Scope
本页覆盖 SDK 中与第三方/私有 BLE Profile 相关的内容:
- Profile 的生成机制与数据结构(
gatt_inc_generator.exe工具、gatt_profile.cfg描述文件、static const uint8_t xxx_profile_data[]属性数组); - 各示例工程中内置的第三方 Profile(HID、透传、Find My、Google FHN、多连接等);
- Profile 使能开关配置(
apps/*/config/lib_profile_config.c)及其对协议栈行为的影响。
不在本页范围的内容:BLE 基础协议栈/GATT 规范本身的实现、经典蓝牙(BR/EDR)协议、芯片底层射频与控制器配置,请参见目录中对应的 BLE 基础与经典蓝牙协议页面。本页以 apps/demo/hid 与 apps/demo/transfer 两个示例工程为事实依据。
Overview
BLE(Bluetooth Low Energy)应用层协议以 Profile 为组织单位:一个 Profile 由一组 GATT 服务(Service)、特征(Characteristic)与描述符(Descriptor)组成,决定设备对外暴露的数据交互语义。除 SIG 标准 Profile(如 HID over GATT、HOGP)外,实际产品常常需要第三方/私有 Profile——例如耳机厂商的透传通道、Apple Find My 网络、Google Fast Pair 等——这些协议未被 SIG 标准化,或带有厂商私有扩展,因此需要由 SDK 以定制 GATT 属性表的方式实现。
在 AW33N BLE SDK 中,第三方 Profile 的工程形态非常统一:
- 开发期:使用杰理提供的
gatt_inc_generator.exe(BLE Profile 工具)将gatt_profile.cfg描述文件(如工具包中的trans_data_cfg目录)编译为 C 头文件; - 产物:每个 Profile 对应一个
static const uint8_t xxx_profile_data[]静态数组,内容即 GATT 属性表(Service/Characteristic/Descriptor 的二进制描述); - 运行期:应用层把该数组注册到 GATT Server,BLE 协议栈据此构建数据库并向远端设备提供服务;
- 裁剪:
lib_profile_config.c中以const u8 xxx_support = 0/1形式集中声明各 Profile/扩展命令的编译期开关,用于裁剪代码体积与行为。
这种"工具生成属性表 + 配置开关裁剪"的设计,使得新增一个第三方协议只需修改 cfg 描述文件并重新生成头文件,无需改动协议栈核心,是 SDK 支持多样化产品形态的关键扩展机制。
Architecture
下图展示第三方 Profile 从"开发期生成"到"运行期服务"的完整架构与数据流:
flowchart TD
subgraph sg_Tools["开发期工具链"]
GEN["杰理 GATT Profile 生成工具<br/>gatt_inc_generator.exe"]
CFG["profile cfg 描述文件<br/>如 trans_data_cfg"]
end
subgraph sg_Headers["生成的协议头文件"]
AT["ble_at_char_profile.h"]
FBOOT["ble_fast_boot_soff_profile.h"]
FMY["ble_fmy_profile.h"]
GFHN["ble_google_fhn_profile.h"]
MCONN["ble_multi_profile.h"]
TRNS["ble_trans_profile.h"]
HOGP["ble_hogp_profile.h"]
end
subgraph sg_App["应用层示例工程"]
HIDAPP["hid 工程<br/>modules/bt"]
TRNSAPP["transfer 工程<br/>examples/*"]
end
subgraph sg_Cfg["Profile 开关配置"]
PCFG["lib_profile_config.c<br/>const u8 xxx_support"]
end
subgraph sg_Runtime["运行期协议栈"]
GATT["GATT Server 属性表"]
STACK["BLE 协议栈"]
end
CFG --> GEN
GEN --> AT
GEN --> FBOOT
GEN --> FMY
GEN --> GFHN
GEN --> MCONN
GEN --> TRNS
GEN --> HOGP
AT --> TRNSAPP
FBOOT --> TRNSAPP
FMY --> TRNSAPP
GFHN --> TRNSAPP
MCONN --> TRNSAPP
TRNS --> TRNSAPP
HOGP --> HIDAPP
TRNSAPP --> GATT
HIDAPP --> GATT
PCFG --> STACK
GATT --> STACK
STACK -->|"广播 / 连接 / GATT 交互"| DEV["远端设备"]
架构要点:
- 生成工具是唯一入口:所有
*_profile.h头部注释均标明generated by jieli gatt_inc_generator.exe,属性表内容由工具根据 cfg 文件生成,人工手写极易出错; - Profile 与工程解耦:
transfer工程的examples/目录按协议各建子目录(at_char_com、findmy、google_fhn、multi_conn、trans_data、fast_boot_soff),每个子目录一个独立 Profile 头文件,按需纳入编译; - 配置集中化:
lib_profile_config.c是 Profile 相关行为的"开关面板",hid工程额外包含 HID 专属配置(如hid_conn_depend_on_dev_company); - 协议栈统一承载:无论何种第三方协议,最终都以 GATT 属性表形式注册进 BLE 协议栈,由协议栈统一处理广播、连接与 ATT 交互。
Profile 生成机制与数据结构
工具链:gatt_inc_generator.exe
仓库内所有第三方 Profile 头文件都带有同一段生成说明,以 at_char_com 的 AT 指令透传 Profile 为例:
// gatt profile include file, generated by jieli gatt_inc_generator.exe
// ...
/*
生成profile工具的链接下载
https://gitee.com/Jieli-Tech/fw-AC63_BT_SDK/tree/master/sdk_tools/BLE%20Profile%E5%B7%A5%E5%85%B7
profile cfg 文件参考工具包里面目录trans_data_cfg
*/
static const uint8_t at_char_profile_data[] = {
Source: ble_at_char_profile.h
这段注释揭示了完整的工作流:
- 在 PC 端运行
gatt_inc_generator.exe(工具随 AC63 SDK 工具包发布,链接见注释); - 输入一个 profile cfg 描述文件——工具包内以
trans_data_cfg目录作为参考样例; - 工具输出一个 C 头文件,内含以
static const uint8_t ..._profile_data[]定义的 GATT 属性表数组。
设计意图:GATT 属性表(UUID、句柄、权限、值)本质上是一份结构化的二进制数据,直接手写极易在 UUID 顺序、句柄偏移或权限位上出错。由工具从可读的 cfg 文本生成,既保证一致性,也便于在不同 SDK 工程间复用同一份协议描述。
属性表数组:static const uint8_t[]
每个 Profile 的产物都是一个 static const 数组,例如:
at_char_profile_data[]—— AT 指令透传(ble_at_char_profile.h)fast_boot_soff_profile_data[]—— 快速开机/软关机(ble_fast_boot_soff_profile.h)- Find My Profile(
ble_fmy_profile.h,其头部以gatt_profile.cfg注释标明来源)
/******************************************************************************
//gatt_profile.cfg
Source: ble_fmy_profile.h
数组内容按 GATT 规范编码:Primary Service 声明、包含的 Characteristic(属性、UUID、值句柄)、以及可选的 Descriptor(如 CCCD)。数组被声明为 static const,意味着:
- 存放在只读存储区(flash),不占用 RAM,符合嵌入式资源约束;
- 编译期即确定内容,运行期不可变,协议栈可直接引用其地址构建 GATT 数据库;
- 同一协议在不同产品间复用仅需重新生成头文件,与业务代码完全解耦。
内置第三方 Profile 一览
SDK 示例工程中随附的第三方/私有 Profile 及其组织方式如下表:
| Profile 头文件 | 所属示例 | 协议用途 |
|---|---|---|
ble_hogp_profile.h | apps/demo/hid/modules/bt/ | HID over GATT(HOGP):鼠标/遥控器/键盘等输入设备上报 |
ble_trans_profile.h | apps/demo/transfer/examples/trans_data/ | 通用数据透传通道(透明传输) |
ble_at_char_profile.h | apps/demo/transfer/examples/at_char_com/ | AT 指令透传,兼容 AT 指令集的串口桥接 |
ble_fmy_profile.h | apps/demo/transfer/examples/findmy/ | Apple Find My 网络寻物协议 |
ble_google_fhn_profile.h | apps/demo/transfer/examples/google_fhn/ | Google Fast Pair / FHN 快速配对辅助 |
ble_multi_profile.h | apps/demo/transfer/examples/multi_conn/ | 多连接场景下的 Profile 组织 |
ble_fast_boot_soff_profile.h | apps/demo/transfer/examples/fast_boot_soff/ | 快速开机/软关机状态通知 |
HID / HOGP(hid 工程)
HID 工程把 BLE 侧 HOGP Profile 头文件放在 apps/demo/hid/modules/bt/ble_hogp_profile.h,与经典蓝牙 HID 实现(btcontroller_config.h 等)并列。HOGP 使设备以标准 HID 服务(服务 UUID 0x1812)向主机上报鼠标/键盘/遥控器事件,从而无需厂商私有驱动即可被 PC、手机等主机识别。
工程支持多种板级形态(board_aw33n_mouse*.c、board_aw33n_rc.c 等),对应鼠标单连接/多连接/遥控器等不同 HID 产品,HOGP 属性表在各类形态间复用。
透传与 AT 指令(transfer 工程)
trans_data 是最基础的私有透传 Profile(工具包 cfg 参考即 trans_data_cfg),提供双向无格式数据通道,常用于 App 与设备之间的自定义命令交互;at_char_com 在其上叠加 AT 指令语义,使设备可被标准 AT 指令集控制,便于与既有串口生态对接。
Find My 与 Google FHN(生态对接)
findmy 与 google_fhn 两个 Profile 面向消费电子生态:Find My 使设备接入 Apple 的全球查找网络(利用附近 iPhone 匿名上报位置),Google FHN(Fast Pair)则在 Android 侧实现快速配对与功能发现。这两类协议涉及与云端/生态侧的私有交互,其 GATT 服务定义完全由生态方规范决定,因此必须通过自定义 Profile 实现——这正是第三方 Profile 机制的核心价值场景。
核心运行流程
第三方 Profile 从系统启动到与远端设备完成一次数据交互的完整时序如下:
sequenceDiagram
participant APP as 应用模块<br/>(hid / transfer)
participant CFG as lib_profile_config.c
participant GATT as GATT Server
participant STACK as BLE 协议栈
participant DEV as 远端设备<br/>(手机/PC/主机)
APP->>CFG: 读取 profile 开关(const u8 xxx_support)
CFG-->>APP: 决定哪些 Profile/命令被编译与使能
APP->>GATT: 注册 xxx_profile_data[] 属性表
GATT->>STACK: 构建 GATT 数据库(服务/特征/描述符)
STACK->>DEV: 广播(可发现/可连接)
DEV->>STACK: 发起连接
STACK->>GATT: 建立 ATT 承载
DEV->>GATT: 发现服务/特征(Discovery)
GATT-->>DEV: 返回 Profile 中声明的 UUID 与属性
DEV->>GATT: 读写请求 / 订阅 CCCD 通知
GATT->>APP: 回调应用层处理
APP-->>GATT: 应答数据 / 使能通知
GATT-->>DEV: ATT 响应 / Notification
流程要点:
- 配置先行:
lib_profile_config.c中的const u8变量在编译期/初始化期决定协议行为,例如hid工程的hid_conn_depend_on_dev_company直接决定 HID 连接的生命周期策略; - 属性表即协议:注册进 GATT Server 的
profile_data[]数组就是设备对外承诺的全部协议能力,远端设备通过标准 GATT Discovery 即可获知; - 业务回调解耦:协议栈只负责 ATT 传输,具体读写语义(透传封包、AT 解析、Find My 上报等)全部由应用层回调实现,第三方 Profile 因此可以做到"换协议不换栈"。
Profile 开关配置(lib_profile_config.c)
每个应用工程在 config/lib_profile_config.c 中集中声明协议相关开关。这些变量以 const u8 导出,值为 1 时使能对应能力,为 0 时裁剪。transfer 工程的配置如下:
const u8 hci_inquiry_support = 0;
const u8 btstack_emitter_support = 0;
const u8 a2dp_mutual_support = 0;
const u8 more_addr_reconnect_support = 0;
const u8 more_hfp_cmd_support = 0;
const u8 more_avctp_cmd_support = 0;
const u8 adt_profile_support = 0;
const u8 pbg_support_enable = 0;
Source: lib_profile_config.c
hid 工程除上述通用开关外,还定义了 HID 专属策略:
/*注意hid_conn_depend_on_dev_company置2之后,默认不断开HID连接 */
const u8 hid_conn_depend_on_dev_company = 2;
const u8 sdp_get_remote_pnp_info = 0;
Source: lib_profile_config.c
配置项含义
| 配置项 | 默认值 | 作用 |
|---|---|---|
hid_conn_depend_on_dev_company | 2 | HID 连接生命周期策略;置 2 后默认不断开 HID 连接,避免误断连导致鼠标/键盘失联 |
sdp_get_remote_pnp_info | 0 | 是否通过 SDP 获取远端 PnP 信息(经典蓝牙 HID 设备识别用) |
hci_inquiry_support | 0 | 是否支持 HCI 层 Inquiry(经典蓝牙扫描) |
btstack_emitter_support | 0 | 蓝牙音频发射(Emitter)支持;注释说明用于优化代码编译,裁剪未使用功能 |
a2dp_mutual_support | 0 | A2DP 双向(同时作为源与接收端)支持 |
more_addr_reconnect_support | 0 | 多地址重连支持 |
more_hfp_cmd_support | 0 | 扩展 HFP AT 指令支持 |
more_avctp_cmd_support | 0 | 扩展 AVCTP 指令支持 |
adt_profile_support | 0 | ADT Profile 支持 |
pbg_support_enable | 0 | PBG(电话本)支持 |
设计意图:BLE/蓝牙协议栈功能庞杂,而每个产品只用到其中一小部分。把开关集中为 const u8 常量,既便于链接器裁剪未引用代码(如 btstack_emitter_support 的注释明确说明"定义用于优化代码编译"),也让工程师在单一文件即可审计"这个固件到底开启了哪些协议能力",降低配置漂移风险。
使用示例
示例一:裁剪/调整 Profile 能力
以纯 BLE 透传类产品为例,在 apps/demo/transfer/config/lib_profile_config.c 中关闭与第三方 Profile 无关的经典蓝牙扩展命令,仅保留透传所需能力:
const u8 hci_inquiry_support = 0; // 不需要经典蓝牙 Inquiry
const u8 btstack_emitter_support = 0; // 不需要音频发射,裁剪相关代码
const u8 a2dp_mutual_support = 0; // 不需要 A2DP 双向
const u8 more_hfp_cmd_support = 0; // 不需要扩展 HFP 指令
const u8 more_avctp_cmd_support = 0; // 不需要扩展 AVCTP 指令
const u8 adt_profile_support = 0; // 不需要 ADT Profile
const u8 pbg_support_enable = 0; // 不需要电话本
Source: lib_profile_config.c
将不需要的项置 0 后,链接器可移除对应实现,减小固件体积(btstack_emitter_support 注释即表明此类开关专为代码裁剪而设)。
示例二:调整 HID 连接保持策略
HID 产品(鼠标/键盘/遥控器)若出现"主机短暂断开后设备主动断开 HID 链路"的体验问题,可在 apps/demo/hid/config/lib_profile_config.c 中确认 hid_conn_depend_on_dev_company 的取值:
/*注意hid_conn_depend_on_dev_company置2之后,默认不断开HID连接 */
const u8 hid_conn_depend_on_dev_company = 2;
Source: lib_profile_config.c
该值置 2 后协议栈默认保持 HID 连接不主动断开——对依赖 HID 链路稳定性的输入设备而言,这是防止"静置断连、使用时需重新配对"等用户投诉的关键开关。
示例三:新增一个第三方 Profile 的标准步骤
基于仓库证据,接入新第三方协议(如新的生态私有服务)的推荐路径为:
- 编写 cfg 描述:参照工具包
trans_data_cfg目录的格式,用文本描述新协议的 Service/Characteristic/Descriptor(UUID、属性、权限); - 生成头文件:运行
gatt_inc_generator.exe(下载链接见 ble_at_char_profile.h 注释),产出xxx_profile_data[]静态数组; - 纳入工程:仿照
apps/demo/transfer/examples/下各子目录(findmy、google_fhn等)组织方式,将头文件放入对应模块目录; - 注册到 GATT:在应用初始化中把数组注册进 GATT Server,实现业务回调处理读写/通知;
- 配置裁剪:若新协议有行为开关,在
lib_profile_config.c中按const u8 xxx_support模式声明。
故障模式、边界情况与并发注意
基于源码证据,以下场景需要特别关注:
HID 连接误断开
hid 工程的配置注释直接警示了此问题:"置 2 之后,默认不断开 HID 连接"。若 hid_conn_depend_on_dev_company 取值不当,设备可能在主机(PC/手机)临时释放链路后主动断开 HID 连接,造成输入设备失联、需重新配对。配置该值时需与产品功耗策略权衡:保持连接会略微增加功耗,但换来即点即用的输入体验。
经典蓝牙与 BLE 能力耦合
lib_profile_config.c 中同时管理 HCI Inquiry、A2DP、HFP、AVCTP 等经典蓝牙扩展开关。BLE-only 的第三方 Profile 产品(如 Find My 防丢器)若误开这些开关,不仅增加固件体积,还可能引入非预期的经典蓝牙行为(如被旧式主机以 BR/EDR 方式连接)。建议按"最小能力集"原则逐项置 0。
属性表只读约束
profile_data[] 声明为 static const,运行期不可修改。若需要动态变更服务内容(如按连接对象切换 Profile),不能直接改写数组,而应在应用层通过 GATT 服务端回调动态应答,或在协议栈层重建数据库——直接在原数组上做写操作将导致未定义行为(写入只读区)。
多连接场景的并发
multi_conn Profile 表明 SDK 支持多连接。当多个远端设备同时访问同一 Profile 的同一特征时,属性表本身是只读共享的(无并发写问题),但应用层的回调处理与通知发送需要自行保证串行化——透传类业务(如 trans_data)尤其要注意多个连接的数据包交织,避免协议封包错位。
扩展点
第三方 Profile 机制本身就是 SDK 面向新协议的主要扩展点:
- 新增私有服务:通过
gatt_inc_generator.exe+ cfg 描述生成新xxx_profile_data[],无需修改协议栈;examples/目录结构(at_char_com、findmy、google_fhn、multi_conn、trans_data、fast_boot_soff)即官方推荐的"一个协议一个子目录"组织范式; - 行为开关扩展:仿照
lib_profile_config.c中const u8 xxx_support模式,为新增协议声明独立开关,保持"单文件审计协议能力"的惯例; - HID 形态扩展:
hid工程通过板级文件(board_aw33n_mouse*.c、board_aw33n_rc.c)复用同一 HOGP Profile 支持鼠标/遥控器等不同产品,说明"属性表复用 + 板级差异隔离"是既定的产品化路径; - 工具链复用:生成工具与 cfg 参考(
trans_data_cfg)随 SDK 工具包发布,跨 SDK(如 AC63)可复用同一协议描述,降低多平台维护成本。
性能与运维注意
- 固件体积:Profile 属性表是只读常量,占用 flash 而非 RAM;但每多使能一个经典蓝牙扩展(A2DP/HFP/AVCTP/PBG 等),代码段与数据段都会增加,
btstack_emitter_support的注释明确其为"优化代码编译"而设——量产前应按产品能力集逐项检查lib_profile_config.c的 0/1 配置; - 属性表大小:一次 GATT 发现交互携带的属性条目有限,服务/特征过多的 Profile 会拉长首次连接发现时间;透传类 Profile 建议保持特征数量精简,将业务指令编码进少量特征;
- 连接保持与功耗:
hid_conn_depend_on_dev_company = 2会保持 HID 连接不主动断开,低功耗产品需在"连接保持"与"休眠省电"之间做显式权衡; - 日志观察:
lib_profile_config.c通过LOG_TAG "[BT-CFG]"与LOG_ERROR_ENABLE/LOG_INFO_ENABLE控制配置模块日志,排查协议使能问题时可按该 TAG 过滤日志确认实际生效的配置。
Related Links
- lib_profile_config.c(transfer 工程) — 透传工程 Profile 开关配置
- lib_profile_config.c(hid 工程) — HID 工程 Profile 开关与 HID 连接策略
- ble_hogp_profile.h — HID over GATT(HOGP)Profile 头文件
- ble_at_char_profile.h — AT 指令透传 Profile(含工具下载与 cfg 参考说明)
- ble_fmy_profile.h — Find My Profile(gatt_profile.cfg 来源标注)
- ble_fast_boot_soff_profile.h — 快速开机/软关机 Profile
- 目录内相关页面:BLE 基础协议与 GATT 规范、经典蓝牙协议(HFP/A2DP/AVCTP)相关目录页