ESP-IDF 蓝牙经典 GAP 开发指南:设备发现、配对与安全管理 API 全解析

ESP-IDF 蓝牙经典 GAP 开发指南:设备发现、配对与安全管理 API 全解析 ESP-IDF 蓝牙经典 GAP 开发指南设备发现、配对与安全管理 API 全解析【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf导读本文面向基于 ESP-IDFEspressif IoT Development Framework进行蓝牙经典Bluetooth ClassicBR/EDR开发的工程师系统讲解蓝牙经典 GAPGeneric Access Profile通用访问规范API 的完整能力从设备发现Inquiry、服务发现SDP、可见性与连接模式控制到传统配对Legacy Pairing与安全简单配对SSP的完整安全体系。通过阅读本文你将掌握esp_gap_bt_api.h中核心接口的调用方式、事件回调的解析方法并能够基于仓库自带的bt_discovery示例独立实现搜索指定类型设备并查询其服务的完整实战方案。一、Bluetooth Classic GAP 在 ESP-IDF 中的角色在 ESP-IDF 的 Bluedroid 协议栈中GAP 处于应用层与链路层之间的枢纽位置。官方 API 参考文档 esp_gap_bt.rst 明确概括了它的职责为设备发现、配对与安全管理提供接口允许应用控制设备可见性、发起连接并为蓝牙经典链路配置认证与加密。与 BLE 的 GAPesp_gap_ble_api.h不同蓝牙经典 GAP 需要处理的是 BR/EDR 链路特有的概念Inquiry查询、Class of Device设备类别码CoD、Extended Inquiry Response扩展查询响应EIR、SDP 服务发现、Link Key链路密钥与 ACL 链路管理等。从源码结构看整个模块的代码组织如下对外 API 声明esp_gap_bt_api.h位于host/bluedroid/api/include/api/对外 API 实现esp_gap_bt_api.c底层蓝牙栈桥接层BTC实现btc_gap_bt.c理解这一分层对排查问题很有帮助应用层调用esp_*系列函数后参数会通过btc_transfer_context()封装成btc_msg_t消息投递给 BTCBluetooth Controller/Bluetooth Transfer Context任务最终由底层 BTABluetooth Application层执行实际操作结果再以回调事件的形式回到应用层。在 esp_gap_bt_api.c 中可以看到esp_bt_gap_set_scan_mode()的典型实现模式先做参数合法性检查再构造消息并投递。二、初始化流程先跑通 Bluedroid 再谈 GAP所有 GAP API 都有一个共同的硬性前提必须在esp_bluedroid_enable()成功之后调用否则会返回ESP_ERR_INVALID_STATE。这一点在头文件中几乎每个函数注释都有标注也是初学者最常踩的坑。完整的最小初始化序列取自示例 bt_discovery/main/main.c// 1. 初始化 NVS用于存储 PHY 校准数据与键值对 esp_err_t ret nvs_flash_init(); if (ret ESP_ERR_NVS_NO_FREE_PAGES || ret ESP_ERR_NVS_NEW_VERSION_FOUND) { ESP_ERROR_CHECK(nvs_flash_erase()); ret nvs_flash_init(); } ESP_ERROR_CHECK(ret); // 2.纯经典 BT 应用释放 BLE 控制器内存 ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE)); // 3. 初始化并启用蓝牙控制器 esp_bt_controller_config_t bt_cfg BT_CONTROLLER_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_bt_controller_init(bt_cfg)); ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)); // 4. 初始化并启用 Bluedroid 主机协议栈 esp_bluedroid_config_t bluedroid_cfg BT_BLUEDROID_INIT_CONFIG_DEFAULT(); ESP_ERROR_CHECK(esp_bluedroid_init_with_cfg(bluedroid_cfg)); ESP_ERROR_CHECK(esp_bluedroid_enable());要点说明示例配套的 sdkconfig.defaults 展示了经典蓝牙的典型裁剪配置CONFIG_BT_ENABLEDy、CONFIG_BTDM_CTRL_MODE_BR_EDR_ONLYy、CONFIG_BT_CLASSIC_ENABLEDy且CONFIG_BT_BLE_ENABLEDn。esp_bt_controller_mem_release(ESP_BT_MODE_BLE)释放 BLE 模式内存以腾出 RAM 给 BR/EDR该操作不可逆若需双模BLE Classic工作应使用ESP_BT_MODE_BTDM且不要释放 BLE 内存。控制器模式共有四种ESP_BT_MODE_IDLE、ESP_BT_MODE_BLE、ESP_BT_MODE_CLASSIC_BT、ESP_BT_MODE_BTDM。初始化完成后即可注册 GAP 回调并启动应用esp_bt_gap_register_callback(bt_app_gap_cb); // 注册事件回调 esp_bt_gap_set_device_name(ESP_GAP_INQUIRY); // 设置本机名称 esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE); // 可被发现、可被连接 esp_bt_gap_start_discovery(ESP_BT_INQ_MODE_GENERAL_INQUIRY, 10, 0); // 启动查询三、设备发现Inquiry与结果解析3.1 启动与停止查询查询Inquiry是经典蓝牙发现邻近设备的核心机制相关 API 定义在 esp_gap_bt_api.hesp_err_t esp_bt_gap_start_discovery(esp_bt_inq_mode_t mode, uint8_t inq_len, uint8_t num_rsps); esp_err_t esp_bt_gap_cancel_discovery(void);参数语义modeESP_BT_INQ_MODE_GENERAL_INQUIRY一般查询或ESP_BT_INQ_MODE_LIMITED_INQUIRY受限查询。inq_len查询持续时间单位为 1.28 秒合法范围ESP_BT_GAP_MIN_INQ_LEN(0x01) 到ESP_BT_GAP_MAX_INQ_LEN(0x30)即最长约 61 秒。示例中传入10表示约 12.8 秒。num_rsps停止查询前可接收的响应数量0 表示不限数量。从实现esp_gap_bt_api.c可以看到参数越界会直接返回ESP_ERR_INVALID_ARG。查询机制还内置了 Name Discovery当查询结束而缓存结果中缺少设备名称时协议栈会自动连接对端获取名称。查询流程通过两个事件反馈给应用ESP_BT_GAP_DISC_STATE_CHANGED_EVT查询启动ESP_BT_GAP_DISCOVERY_STARTED或停止ESP_BT_GAP_DISCOVERY_STOPPED时触发。ESP_BT_GAP_DISC_RES_EVT每发现一台设备时触发携带该设备的属性集合。3.2 设备属性Device Property解析ESP_BT_GAP_DISC_RES_EVT的参数中包含num_prop和prop数组属性类型由枚举esp_bt_gap_dev_prop_type_t定义见 esp_gap_bt_api.h属性类型含义值类型ESP_BT_GAP_DEV_PROP_BDNAME蓝牙设备名称int8_t[]最长ESP_BT_GAP_MAX_BDNAME_LEN 248 字节ESP_BT_GAP_DEV_PROP_COD设备类别码uint32_tESP_BT_GAP_DEV_PROP_RSSI接收信号强度int8_t范围 -128 ~ 127ESP_BT_GAP_DEV_PROP_EIR扩展查询响应uint8_t[]有效数据最长ESP_BT_GAP_EIR_DATA_LEN 240 字节示例 main.c 中update_device_info()展示了标准解析模板遍历prop数组、按p-type分支取出各字段。注意 RSSI 与 COD 分别需要以int8_t*和uint32_t*解引用取值。3.3 EIR 数据解析设备名的兜底来源部分设备不单独上报 BDNAME 属性而是把名称放入 EIR 数据中。此时用esp_bt_gap_resolve_eir_data()从原始 EIR 缓冲中提取uint8_t *esp_bt_gap_resolve_eir_data(uint8_t *eir, esp_bt_eir_type_t type, uint8_t *length);EIR 数据类型由ESP_BT_EIR_TYPE_*宏定义见 esp_gap_bt_api.h常用值包括ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME(0x09) 完整本地名称、ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME(0x08) 缩短名称、ESP_BT_EIR_TYPE_TX_POWER_LEVEL(0x0a)、ESP_BT_EIR_TYPE_URL(0x24)、ESP_BT_EIR_TYPE_MANU_SPECIFIC(0xff) 厂商自定义数据以及完整的 16/32/128 位服务 UUID 列表。实现上该函数直接透传给底层BTM_CheckEirData()完成类型过滤见 esp_gap_bt_api.c。示例中的get_name_from_eir()展示了推荐顺序先尝试完整名称失败再尝试缩短名称见 main.c。3.4 CoD 设备类别码筛选目标设备的利器设备类别码是发现结果筛选的核心字段示例正是靠它找到Phone或Audio/Video类设备。头文件提供了位域结构体与一整套内联解析工具见 esp_gap_bt_api.h 与 esp_gap_bt_api.huint32_t esp_bt_gap_get_cod_srvc(uint32_t cod); // 主服务类 uint32_t esp_bt_gap_get_cod_major_dev(uint32_t cod); // 主设备类 uint32_t esp_bt_gap_get_cod_minor_dev(uint32_t cod); // 次设备类 uint32_t esp_bt_gap_get_cod_format_type(uint32_t cod); // 格式类型 bool esp_bt_gap_is_valid_cod(uint32_t cod); // CoD 完整性校验主设备类枚举esp_bt_cod_major_dev_t的关键取值ESP_BT_COD_MAJOR_DEV_PHONE(2) 手机、ESP_BT_COD_MAJOR_DEV_AV(4) 音视频、ESP_BT_COD_MAJOR_DEV_COMPUTER(1) 计算机、ESP_BT_COD_MAJOR_DEV_PERIPHERAL(5) 外设、ESP_BT_COD_MAJOR_DEV_WEARABLE(7) 可穿戴。主服务类枚举esp_bt_cod_srvc_t则包含ESP_BT_COD_SRVC_AUDIO、ESP_BT_COD_SRVC_TELEPHONY、ESP_BT_COD_SRVC_RENDERING等多位可同时置位。示例中的目标筛选逻辑if (!esp_bt_gap_is_valid_cod(cod) || (!(esp_bt_gap_get_cod_major_dev(cod) ESP_BT_COD_MAJOR_DEV_PHONE) !(esp_bt_gap_get_cod_major_dev(cod) ESP_BT_COD_MAJOR_DEV_AV))) { return; // 不是目标设备忽略 }注意esp_bt_gap_is_valid_cod()要求格式类型为 Type 1 且主服务类字段非零这是对合法 CoD的严格校验。四、服务发现SDP查询对端能做什么找到目标设备后下一步通常是通过 SDPService Discovery Protocol查询其支持的服务// 获取对端全部服务结果通过 ESP_BT_GAP_RMT_SRVCS_EVT 回调返回 esp_err_t esp_bt_gap_get_remote_services(esp_bd_addr_t remote_bda); // 只查找匹配指定 UUID 的服务记录结果通过 ESP_BT_GAP_RMT_SRVC_REC_EVT 返回 esp_err_t esp_bt_gap_get_remote_service_record(esp_bd_addr_t remote_bda, esp_bt_uuid_t *uuid);ESP_BT_GAP_RMT_SRVCS_EVT参数包含num_uuids与uuid_list其中esp_bt_uuid_t通过len字段2/4/16 对应 16/32/128 位 UUID区分 UUID 类型。示例的uuid2str()见 main.c演示了三种长度 UUID 的格式化输出方法。在实现层面esp_gap_bt_api.cesp_bt_gap_get_remote_service_record()会校验uuid-len必须是 16/32/128 位之一否则返回ESP_ERR_INVALID_ARG。示例的完整工作流见 main.c通过状态机app_gap_state_t串联DEVICE_DISCOVERING→ 发现目标后cancel_discovery()→ 收到ESP_BT_GAP_DISCOVERY_STOPPED后进入SERVICE_DISCOVERING并调用esp_bt_gap_get_remote_services()→ 收到ESP_BT_GAP_RMT_SRVCS_EVT后打印服务 UUID 列表。这套状态机 回调驱动的模式值得直接复用。五、配对与安全管理5.1 传统配对Legacy PairingPIN 码机制经典蓝牙的传统配对需要用户输入 PIN 码流程如下// 设置 PIN 类型与默认 PIN esp_err_t esp_bt_gap_set_pin(esp_bt_pin_type_t pin_type, uint8_t pin_code_len, esp_bt_pin_code_t pin_code); // 收到 ESP_BT_GAP_PIN_REQ_EVT 后回复 PIN esp_err_t esp_bt_gap_pin_reply(esp_bd_addr_t bd_addr, bool accept, uint8_t pin_code_len, esp_bt_pin_code_t pin_code);esp_bt_pin_type_tESP_BT_PIN_TYPE_VARIABLE可变 PIN此时固定 PIN 参数被忽略配对时通过ESP_BT_GAP_PIN_REQ_EVT向应用索要或ESP_BT_PIN_TYPE_FIXED固定 PIN栈自动应答、不回回调。esp_bt_pin_code_t最长ESP_BT_PIN_CODE_LEN(16) 字节即 128 位MSB 必须为 0。ESP_BT_GAP_PIN_REQ_EVT的参数min_16_digit指示对端是否要求 PIN 至少 16 位。5.2 安全简单配对SSPSSP 是蓝牙 2.1 引入的免 PIN 配对机制根据 IO 能力自动选择关联模型。相关 API// 设置安全参数当前支持 ESP_BT_SP_IOCAP_MODE 设置 IO 能力 esp_err_t esp_bt_gap_set_security_param(esp_bt_sp_param_t param_type, void *value, uint8_t len); // 回复 PasskeyKeyReq 时使用必须是 6 位数字、允许前导 0 esp_err_t esp_bt_gap_ssp_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t passkey); // 回复确认数字比较模型数值一致则 accepttrue esp_err_t esp_bt_gap_ssp_confirm_reply(esp_bd_addr_t bd_addr, bool accept);IO 能力定义在 esp_gap_bt_api.hESP_BT_IO_CAP_OUT(0) 仅显示、ESP_BT_IO_CAP_IO(1) 显示确认、ESP_BT_IO_CAP_IN(2) 仅键盘、ESP_BT_IO_CAP_NONE(3) 无输入无输出。SSP 相关回调事件见 esp_gap_bt_api.h事件触发时机关键参数ESP_BT_GAP_CFM_REQ_EVT数字比较确认请求Just Works / Numeric Comparisonnum_val待比较的 6 位数值ESP_BT_GAP_KEY_NOTIF_EVTPasskey 通知Keyboard Only 模型passkey显示给用户ESP_BT_GAP_KEY_REQ_EVTPasskey 输入请求需调用ssp_passkey_reply()回复ESP_BT_GAP_AUTH_CMPL_EVT认证完成stat状态、lk_type链路密钥类型、device_name5.3 加密与链路密钥管理加密模式枚举esp_bt_enc_mode_tESP_BT_ENC_MODE_OFF(0x00)、ESP_BT_ENC_MODE_E0(0x01)、ESP_BT_ENC_MODE_AES(0x02)链路加密状态变化时触发ESP_BT_GAP_ENC_CHG_EVT。链路密钥类型esp_bt_link_key_type_t涵盖ESP_BT_LINK_KEY_COMB(0x00) 组合密钥到ESP_BT_LINK_KEY_AUTHED_COMB_P256(0x08) 基于 P-256 的已认证组合密钥等 8 种。最小加密密钥长度ESP_BT_ENC_KEY_SIZE_CTRL_MIN(7) ~ESP_BT_ENC_KEY_SIZE_CTRL_MAX(16)通过esp_bt_gap_set_min_enc_key_size()设置完成后触发ESP_BT_GAP_SET_MIN_ENC_KEY_SIZE_EVT。5.4 绑定Bonding管理已配对设备会进入安全数据库管理接口如下esp_err_t esp_bt_gap_remove_bond_device(esp_bd_addr_t bd_addr); // 解除绑定 int esp_bt_gap_get_bond_device_num(void); // 已绑定设备数量 esp_err_t esp_bt_gap_get_bond_device_list(int *dev_num, esp_bd_addr_t *dev_list); // 获取绑定列表esp_bt_gap_get_bond_device_list()的dev_num是输入输出参数调用前传入dev_list缓冲区容量返回后为实际设备数官方建议容量取esp_bt_gap_get_bond_device_num()的返回值。解除绑定完成后会触发ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT。六、可见性、连接与链路控制6.1 扫描模式可见性与可连接性esp_err_t esp_bt_gap_set_scan_mode(esp_bt_connection_mode_t c_mode, esp_bt_discovery_mode_t d_mode);连接模式esp_bt_connection_mode_tESP_BT_NON_CONNECTABLE/ESP_BT_CONNECTABLE。发现模式esp_bt_discovery_mode_tESP_BT_NON_DISCOVERABLE/ESP_BT_LIMITED_DISCOVERABLE/ESP_BT_GENERAL_DISCOVERABLE。实现esp_gap_bt_api.c会对两个参数逐一校验非法组合返回ESP_ERR_INVALID_ARG。6.2 设备名称与设备类别码esp_err_t esp_bt_gap_set_device_name(const char *name); // 设置本机名称最长 248 字节 esp_err_t esp_bt_gap_get_device_name(void); // 异步获取完成触发 ESP_BT_GAP_GET_DEV_NAME_CMPL_EVT esp_err_t esp_bt_gap_set_cod(esp_bt_cod_t cod, esp_bt_cod_mode_t mode); // 设置 CoD esp_err_t esp_bt_gap_get_cod(esp_bt_cod_t *cod); // 读取本机 CoDesp_bt_gap_set_cod()的六种设置模式esp_bt_cod_mode_t见 esp_gap_bt_api.hESP_BT_SET_COD_MAJOR_MINOR(0x01) 覆盖主/次设备类、ESP_BT_SET_COD_SERVICE_CLASS(0x02) 置位服务类比特、ESP_BT_CLR_COD_SERVICE_CLASS(0x04) 清除服务类比特、ESP_BT_SET_COD_ALL(0x08) 覆盖主次类并置位服务类、ESP_BT_INIT_COD(0x0a) 完全重写、ESP_BT_SET_COD_RESERVED_2(0x10) 覆盖保留低 2 位。注意部分 profile 对 CoD 有特殊限制随意修改可能导致这些 profile 无法工作且应在本机 profile 初始化完成后再调用否则配置可能被覆盖。6.3 EIR 数据配置在查询响应中广播自定义 EIR 数据名称、UUID、发射功率、URL、厂商数据等esp_err_t esp_bt_gap_config_eir_data(esp_bt_eir_data_t *eir_data);esp_bt_eir_data_t结构见 esp_gap_bt_api.h字段包括include_txpower、include_uuid、include_name默认 true、flagEIR 标志位ESP_BT_EIR_FLAG_*可组合为 0 则不包含、manufacturer_len/p_manufacturer_data厂商数据、url_len/p_urlURL。实现esp_gap_bt_api.c会校验长度不超过ESP_BT_EIR_MAX_LEN(240) 且指针非空。配置结果通过ESP_BT_GAP_CONFIG_EIR_DATA_EVT返回若 EIR 数据超过 240 字节状态为ESP_BT_STATUS_EIR_TOO_LARGE。6.4 链路级参数Page Timeout、QoS 与 ACL 包类型Page Timeout页超时主设备发起连接时等待对端基带响应的最长时间合法范围 0x0016 ~ 0xffff默认 0x2000单位 0.625 msesp_err_t esp_bt_gap_set_page_timeout(uint16_t page_to); // 完成触发 ESP_BT_GAP_SET_PAGE_TO_EVT esp_err_t esp_bt_gap_get_page_timeout(void); // 完成触发 ESP_BT_GAP_GET_PAGE_TO_EVT建议在发起连接之前设置因为新值要到下一次 Page 流程才生效。QoS 配置esp_bt_gap_set_qos(remote_bda, t_poll)设置主设备向从设备发送的轮询间隔t_poll单位 0.625 ms完成触发ESP_BT_GAP_QOS_CMPL_EVT。ACL 包类型esp_bt_gap_set_acl_pkt_types(remote_bda, pkt_types)可限制链路上使用的包类型DM1/DH1/DM3/DH3/DM5/DH5 以及 2/3-DH 组合见ESP_BT_ACL_*_ONLY系列宏注意 DM1 不可禁用结果通过ESP_BT_GAP_ACL_PKT_TYPE_CHANGED_EVT返回。链路状态事件ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT与ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT上报 ACL 链路建立/断开结果含链路句柄 handleESP_BT_GAP_MODE_CHG_EVT上报功率管理模式变化Active/Hold/Sniff/Park对应ESP_BT_PM_MD_*。6.5 其他实用接口esp_bt_gap_read_remote_name(remote_bda)异步读取对端名称结果通过ESP_BT_GAP_READ_REMOTE_NAME_EVT返回。esp_bt_gap_read_rssi_delta(remote_addr)/esp_bt_gap_read_acl_real_rssi(remote_addr)链路建立后读取 RSSI分别触发ESP_BT_GAP_READ_RSSI_DELTA_EVT/ESP_BT_GAP_READ_ACL_REAL_RSSI_EVT后者依赖厂商专用 HCI 与BT_CLASSIC_ENABLE_POWER_CTRL_VSC配置。esp_bt_gap_set_afh_channels(channels)设置自适应跳频信道地图79 个信道至少 20 个标记为 unknown地图长度ESP_BT_GAP_AFH_CHANNELS_LEN10 字节。esp_bt_gap_get_profile_status(profile_status)查询当前 GAP 状态发现状态、连接/发现模式、BR/EDR ACL 链路数esp_bt_gap_profile_status_t定义见 esp_gap_bt_api.h。七、回调事件全景参考所有异步结果统一通过注册的回调函数esp_bt_gap_cb_t派发原型见 esp_gap_bt_api.h事件枚举esp_bt_gap_cb_event_t共 28 个事件按功能归类如下功能域事件设备发现ESP_BT_GAP_DISC_RES_EVT、ESP_BT_GAP_DISC_STATE_CHANGED_EVT、ESP_BT_GAP_READ_REMOTE_NAME_EVT服务发现ESP_BT_GAP_RMT_SRVCS_EVT、ESP_BT_GAP_RMT_SRVC_REC_EVT配对安全ESP_BT_GAP_AUTH_CMPL_EVT、ESP_BT_GAP_PIN_REQ_EVT、ESP_BT_GAP_CFM_REQ_EVT、ESP_BT_GAP_KEY_NOTIF_EVT、ESP_BT_GAP_KEY_REQ_EVT、ESP_BT_GAP_ENC_CHG_EVT、ESP_BT_GAP_SET_MIN_ENC_KEY_SIZE_EVT、ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT链路控制ESP_BT_GAP_ACL_CONN_CMPL_STAT_EVT、ESP_BT_GAP_ACL_DISCONN_CMPL_STAT_EVT、ESP_BT_GAP_MODE_CHG_EVT、ESP_BT_GAP_SET_PAGE_TO_EVT、ESP_BT_GAP_GET_PAGE_TO_EVT、ESP_BT_GAP_ACL_PKT_TYPE_CHANGED_EVT、ESP_BT_GAP_QOS_CMPL_EVT射频与 EIRESP_BT_GAP_CONFIG_EIR_DATA_EVT、ESP_BT_GAP_SET_AFH_CHANNELS_EVT、ESP_BT_GAP_READ_RSSI_DELTA_EVT、ESP_BT_GAP_READ_ACL_REAL_RSSI_EVT、ESP_BT_GAP_READ_NEW_CONN_TX_PWR_RNG_EVT、ESP_BT_GAP_WRITE_NEW_CONN_TX_PWR_RNG_EVT、ESP_BT_GAP_READ_TX_PWR_LVL_EVT、ESP_BT_GAP_WRITE_TX_PWR_LVL_EVT设备信息ESP_BT_GAP_GET_DEV_NAME_CMPL_EVT所有事件的参数都定义在联合体esp_bt_gap_cb_param_t中见 esp_gap_bt_api.h回调中应根据event访问对应的结构体成员未处理的事件应落入default分支做日志记录示例中的做法值得借鉴。八、构建、烧录与验证以官方示例 bt_discovery 为例完整流程如下配置idf.py menuconfig确认蓝牙经典模式已启用参考该示例的 sdkconfig.defaultsCONFIG_BT_CLASSIC_ENABLEDy、CONFIG_BT_BLE_ENABLEDn。构建烧录idf.py -p PORT build flash monitor退出串口监视器按Ctrl-]。预期行为启动后本机进入可发现、可连接状态日志打印本机地址随后启动查询日志逐条打印Device found: xx:xx:xx:xx:xx:xx及每台设备的 CoD、RSSI、名称命中Phone或Audio/Video类目标后自动停止查询并转入 SDP 服务发现最终打印Services for device ... found及服务 UUID 列表。该示例配套了自动化测试 pytest_classic_bt_discovery_test.py 与两套默认配置ESP32 与 ESP32-S31 各一份可作为回归验证的参考。支持的芯片目标见示例 README 顶部的支持矩阵当前为 ESP32、ESP32-S31。结语本文以官方 API 文档 esp_gap_bt.rst 为主线结合 esp_gap_bt_api.h 的完整接口定义与 bt_discovery 示例完整覆盖了蓝牙经典 GAP 的设备发现、服务发现、配对安全与链路管理四大能力域。上手建议先跑通bt_discovery示例建立回调驱动的心智模型再按需组合本文中的安全与链路控制接口。若需深入了解底层消息机制可继续阅读 esp_gap_bt_api.c 与 btc_gap_bt.c 的对应实现。【免费下载链接】esp-idfEspressif IoT Development Framework. Official development framework for Espressif SoCs.项目地址: https://gitcode.com/GitHub_Trending/es/esp-idf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考