ESP32 (经典蓝牙 SPP)-蓝牙学习(9)
提示:本博客作为学习笔记,有错误的地方希望指正 绪论:这里主要讲解一些关于ESP32的经典蓝牙,蓝牙是一个比较庞大的体系,需要又一些基础知识才可以更好的学习,这里有一些写的比较好的关于蓝牙的文章。吐血推荐历史最全的蓝牙协议栈介绍Bluetooth GAP介绍蓝牙设备配对的四种方式ESP32 蓝牙开发:开发指南ESP32学习笔记十七之蓝牙通信-Bluetooth文章目录一、ESP32蓝牙介绍二、硬
提示:本博客作为学习笔记,有错误的地方希望指正
绪论:这里主要讲解一些关于ESP32的经典蓝牙,蓝牙是一个比较庞大的体系,需要又一些基础知识才可以更好的学习,这里有一些写的比较好的关于蓝牙的文章。
一、ESP32蓝牙介绍
芯片集成了蓝牙链路控制器和蓝牙基带,支持基带协议和其他底层链路协议,例如调制/解调、包处理、比特流处理和跳频等。
蓝牙接口:
- 提供 UART HCI 接口,速度高达 4 Mbps
- 提供 SDIO/SPI HCI 接口
- 提供 PCM/I2S 音频接口
蓝牙协议
芯片的蓝牙协议栈支持蓝牙 v4.2 BR/EDR 和 Bluetooth LE 标准。
蓝牙基本框架:蓝牙的基本框架挺复杂的,更多的可以看推荐的第一篇文章的那个博主,他对蓝牙比较专业的,这里用他的一张图来简单叙述蓝牙的基本框架。下面这张图其实在HOST运用层还差一个GAP协议没有加进去,GAP(Generic Access Profile)通用访问协议,其中BLE对于ESP32的BLEGAP和经典蓝牙的BLE的API有些不一样。按照下图蓝牙协议主要分为层,上层是APP运用层,HOST是蓝牙协议栈,Transport主要是HOST与HW层的一些通信接口,下面以一层HW是一些物理协议层之类的东西。
对于ESP32的蓝牙框架有Bluedroid和Bluetooth Controller,Bluedroid相当于主机,通过VHCI(Host Controller Interface)与 Bluetooth Controller通讯。
由于这样的设计ESP32有以下的几种通讯场景。
场景一(ESP-IDF默认):在 ESP32 的系统上,选择 BLUEDROID 为蓝⽛牙主机,并通过 VHCI(软件实现的虚拟 HCI 接⼝口)接⼝口,访问控制器器(Bluetooth Controller)。
场景⼆:在 ESP32 上运⾏控制器器(此时设备将单纯作为蓝⽛控制器使⽤),外接⼀个运⾏蓝⽛主机的设备(如运⾏ BlueZ 的 Linux PC、运⾏BLUEDROID 的 Android等)。
场景三:此场景与场景二类似,特别之处在于,在 BQB(或其它认证)的控制器测试下,可以将 ESP32 作为 DUT,用 UART 作为 IO 接口,接上认证测试的 PC 机,即可完成认证。
二、硬件
这里的硬件使用的是ESP32 ROOM支持经典蓝牙以及BLE,ESP32S3,以及ESP32C3只支持BLE,不支持经典蓝牙。
三、实现代码
需要值得注意的是使用经典蓝牙的时候需要配置一下ESP-IDF项目配置菜单中的一些蓝牙配置。需要使能蓝牙以及打开配追经典蓝牙,然后使能SPP并且配置简单安全认证。不配置编译会报错,找不到对应的.h头文件。SPP模式只有安卓手机支持,苹果手机不支持SPP模式。
在这里我主要加了一些的发送功能,连接上手机之后就会每隔一段时间发送信息给手机。这个发送函数是官方历程中没有的,我自己研究了好久才找到怎么给给手机发送信息的。
蓝牙初始化流程:
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include "nvs.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_bt.h"
//要在ESP-IDF项目配置菜单中使能蓝牙
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "time.h"
#include "sys/time.h"
#include "esp_task_wdt.h"
#define SPP_SERVER_NAME "SPP_SERVER" //服务名
#define EXAMPLE_DEVICE_NAME "ESP_SPP_ACCEPTOR" //蓝牙名
#define SPP_SHOW_DATA 1 //数据模式
#define SPP_SHOW_SPEED 1 //测度模式
#define SPP_SHOW_MODE SPP_SHOW_DATA //选择对应的模式
static const char * SPP_TAG = "SPP_ACCEPTOR_DEMO";
static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB; //SPP模式选择 当数据到来时,回调将伴随着数据到来
static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE; //需要认证
static const esp_spp_role_t role_slave = ESP_SPP_ROLE_SLAVE; //从模式角色
uint16_t bt_handle;
static struct timeval time_new,time_old; //结构体由gettimeofday(2)系统调用返回,并在其他调用中使用。
static long data_num = 0; //数据数量
static void print_speed(void)
{
float time_old_s = time_old.tv_sec + time_old.tv_usec / 1000000.0;
float time_new_s = time_new.tv_sec + time_new.tv_usec / 1000000.0;
float time_interval = time_new_s - time_old_s;
float speed = data_num * 8 / time_interval / 1000.0;
ESP_LOGI(SPP_TAG,"speed(%fs ~ %fs): %f kbit/s",time_old_s,time_new_s,speed);
data_num = 0;
time_old.tv_sec = time_new.tv_sec;
time_old.tv_usec= time_new.tv_usec;
}
// ESP_SPP_INIT_EVT = 0, /*!当SPP被启动时,事件来*/
// ESP_SPP_UNINIT_EVT = 1, /*!<当SPP是未启动的,事件来*/
// ESP_SPP_DISCOVERY_COMP_EVT = 8, /*!<当SDP发现完成时,事件发生*/
// ESP_SPP_OPEN_EVT = 26, /*!<当SPP Client连接打开时,事件发生*/
// ESP_SPP_CLOSE_EVT = 27, /*!<当SPP连接关闭时,事件发生*/
// ESP_SPP_START_EVT = 28, /*!<当SPP服务器启动时,事件发生*/
// ESP_SPP_CL_INIT_EVT = 29, /*!当SPP客户端发起一个连接时,事件发生*/
// ESP_SPP_DATA_IND_EVT = 30, /*!<当SPP连接收到数据时,事件发生,只有ESP_SPP_MODE_CB */
// ESP_SPP_CONG_EVT = 31, /*!<当SPP连接拥塞状态改变时,该事件发生,仅针对ESP_SPP_MODE_CB */
// ESP_SPP_WRITE_EVT = 33, /*!<SPP写操作完成时,事件出现,仅针对ESP_SPP_MODE_CB */
// ESP_SPP_SRV_OPEN_EVT = 34, /*!<当SPP服务器连接打开时,事件发生*/
// ESP_SPP_SRV_STOP_EVT = 35, /*!<当SPP服务器停止时,事件发生*/
static void esp_spp_cb(esp_spp_cb_event_t event,esp_spp_cb_param_t *param)
{
switch(event){
case ESP_SPP_INIT_EVT: //当SPP被启动时,事件来
ESP_LOGI(SPP_TAG,"ESP_SPP_INIT_EVT"); //打印初始化事件
//这个函数创建一个SPP服务器,并开始监听来自远程蓝牙设备的SPP连接请求。当服务器成功启动时,
//使用ESP_SPP_START_EVT调用回调。连接建立后,使用ESP_SPP_SRV_OPEN_EVT调用回调。
//这个函数必须在esp_spp_init()成功之后,在esp_spp_deinit()之前调用。
esp_spp_start_srv(sec_mask,role_slave,0,SPP_SERVER_NAME); //开启spp服务
break;
case ESP_SPP_DISCOVERY_COMP_EVT: //当SDP发现完成时,事件发生
ESP_LOGI(SPP_TAG,"ESP_SPP_DISCOVERY_COMP_EVT");
break;
case ESP_SPP_OPEN_EVT: //当SPP客户端连接打开时,事件发生
ESP_LOGI(SPP_TAG,"ESP_SPP_OPEN_EVT");
break;
case ESP_SPP_CLOSE_EVT: //当SPP连接关闭时,事件发生
ESP_LOGI(SPP_TAG,"ESP_SPP_CLOSE_EVT");
bt_handle = 0;
break;
case ESP_SPP_START_EVT: //当SPP服务器启动时,事件发生
ESP_LOGI(SPP_TAG,"ESP_SPP_START_EVT");
esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME); //设置蓝牙名称
esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE,ESP_BT_GENERAL_DISCOVERABLE);//设置gap的扫描模式 可以连接 一般可发现
break;
case ESP_SPP_CL_INIT_EVT: //当SPP客户端发起一个连接时,事件发生
ESP_LOGI(SPP_TAG,"ESP_SPP_CL_INIT_EVT");
break;
case ESP_SPP_DATA_IND_EVT: //当SPP连接收到数据时,事件发生,只有ESP_SPP_MODE_CB
#if(SPP_SHOW_MODE == SPP_SHOW_DATA) //SPP模式
ESP_LOGI(SPP_TAG,"ESP_SPP_DATA_IND_EVT len=%d data:%s handle=%d",param->data_ind.len,param->data_ind.data,param->data_ind.handle);
esp_log_buffer_hex("",param->data_ind.data,param->data_ind.len); //16进制显示数据 数据长度
#else
gettimeofday(&time_new,NULL); //获取时间
data_num += param->data_ind.len; //数据长度累加
if(time_new.tv_sec - time_old.tv_sec >= 3){
print_speed(); //测量速度
}
#endif
// ESP_LOGI(SPP_TAG,"handle:%d",param->cong.handle);
// if (param->cong.cong == 0) {
// }
break;
case ESP_SPP_CONG_EVT: //当SPP连接拥塞状态改变时,该事件发生,仅针对ESP_SPP_MODE_CB
ESP_LOGI(SPP_TAG,"ESP_SPP_CONG_EVT");
break;
case ESP_SPP_WRITE_EVT: //SPP写操作完成时,事件出现,仅针对ESP_SPP_MODE_CB
ESP_LOGI(SPP_TAG,"ESP_SPP_WRITE_EVT");
break;
case ESP_SPP_SRV_OPEN_EVT: //当SPP服务器连接打开时,事件发生
ESP_LOGI(SPP_TAG,"ESP_SPP_SRV_OPEN_EVT");
bt_handle = param->cong.handle;
ESP_LOGI(SPP_TAG,":handle:%d :%d",bt_handle,param->cong.handle);
gettimeofday(&time_old,NULL); //获取时间
break;
case ESP_SPP_SRV_STOP_EVT: //当SPP服务器停止时,事件发生
ESP_LOGI(SPP_TAG,"ESP_SPP_SRV_STOP_EVT");
break;
case ESP_SPP_UNINIT_EVT: //当SPP是未启动的,事件来
ESP_LOGI(SPP_TAG,"ESP_SPP_UNINIT_EVT");
break;
default:
break;
}
}
// ESP_BT_GAP_DISC_RES_EVT = 0, /*!<设备发现结果事件*/
// ESP_BT_GAP_DISC_STATE_CHANGED_EVT = 1, /*!<发现状态改变事件*/
// ESP_BT_GAP_RMT_SRVCS_EVT = 2, /*!<获取远程服务事件*/
// ESP_BT_GAP_RMT_SRVC_REC_EVT = 3, /*!<获取远程服务记录事件*/
// ESP_BT_GAP_AUTH_CMPL_EVT = 4, /*!<认证完成事件*/
// ESP_BT_GAP_PIN_REQ_EVT = 5, /*!<遗留配对Pin码请求*/
// ESP_BT_GAP_CFM_REQ_EVT = 6, /*!<安全简单配对用户确认请求。*/
// ESP_BT_GAP_KEY_NOTIF_EVT = 7, /*!<安全简单配对密钥通知*/
// ESP_BT_GAP_KEY_REQ_EVT = 8, /*!<安全简单配对密码请求*/
// ESP_BT_GAP_READ_RSSI_DELTA_EVT = 9, /*!<读取rssi事件*/
// ESP_BT_GAP_CONFIG_EIR_DATA_EVT = 10, /*!配置EIR数据事件*/
// ESP_BT_GAP_SET_AFH_CHANNELS_EVT = 11, /*!<设置AFH通道事件*/
// ESP_BT_GAP_READ_REMOTE_NAME_EVT = 12, /*!<读取远程名称事件*/
// ESP_BT_GAP_MODE_CHG_EVT = 13, /*!<模式改变事件*/
// ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT = 14, /*!<移除绑定设备完成事件*/
// ESP_BT_GAP_QOS_CMPL_EVT = 15, /*!< QOS完成事件*/
// ESP_BT_GAP_EVT_MAX = 16,
static void esp_bt_gap_cb(esp_bt_gap_cb_event_t event,esp_bt_gap_cb_param_t *param)
{
switch (event){
case ESP_BT_GAP_AUTH_CMPL_EVT: //认证完成事件
if(param->auth_cmpl.stat == ESP_BT_STATUS_SUCCESS){ //校验成功
ESP_LOGI(SPP_TAG,"authentication success: %s",param->auth_cmpl.device_name); //打印设备名
esp_log_buffer_hex(SPP_TAG,param->auth_cmpl.bda,ESP_BD_ADDR_LEN); //远程蓝牙设备地址
}else {
ESP_LOGI(SPP_TAG,"authentication failed, status:%d",param->auth_cmpl.stat); //认证完成状态
}
break;
case ESP_BT_GAP_PIN_REQ_EVT: //遗留配对Pin码请求
ESP_LOGI(SPP_TAG,"ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d",param->pin_req.min_16_digit); //如果返回的引脚必须至少为16位,则为TRUE
if(param->pin_req.min_16_digit){ //引脚请求参数结构 如果返回的引脚必须至少为16位,则为TRUE
ESP_LOGI(SPP_TAG,"Input pin code: 0000 0000 0000 0000");
esp_bt_pin_code_t pin_code = {0}; //Pin Code(最大128位)MSB为0
esp_bt_gap_pin_reply(param->pin_req.bda,true,16,pin_code); //当ESP_BT_GAP_PIN_REQ_EVT到来时,回复对端设备的pin_code进行遗留配对。
}else{
ESP_LOGI(SPP_TAG,"Input pin code: 1234"); //打印pincode
esp_bt_pin_code_t pin_code; //Pin Code(最大128位)MSB为0
pin_code[0] = '1';
pin_code[1] = '2';
pin_code[2] = '3';
pin_code[3] = '4';
esp_bt_gap_pin_reply(param->pin_req.bda,true,4,pin_code); //当ESP_BT_GAP_PIN_REQ_EVT到来时,回复对端设备的pin_code进行遗留配对。
}
break;
#if (CONFIG_BT_SSP_ENABLED == true)
case ESP_BT_GAP_CFM_REQ_EVT: //安全简单配对用户确认请求configure require event
ESP_LOGI(SPP_TAG,"ESP_BT_GAP_CFM_REQ_EVT please compare the numeric value: %d",param->cfm_req.num_val);//确认请求参数结构
esp_bt_gap_ssp_confirm_reply(param->cfm_req.bda,true); //远程蓝牙设备地址
break;
case ESP_BT_GAP_KEY_NOTIF_EVT: //安全简单配对密钥通知
ESP_LOGI(SPP_TAG,"ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d",param->key_notif.passkey); //密钥条目的数值
break;
case ESP_BT_GAP_KEY_REQ_EVT: //安全简单配对密码请求
ESP_LOGI(SPP_TAG,"ESP_BT_GAP_KEY_REQ_EVT please enter passkey!");
break;
#endif
case ESP_BT_GAP_MODE_CHG_EVT: //模式改变事件
ESP_LOGI(SPP_TAG,"ESP_BT_GAP_MODE_CHG_EVT mode:%d",param->mode_chg.mode); //模式更改事件参数struct
break;
default:
ESP_LOGI(SPP_TAG,"event: %d",event);
break;
}
return;
}
void app_main(void)
{
esp_err_t ret = nvs_flash_init(); //初始化nvs flash
//NVS分区包含新格式的数据,不能被这个版本的代码识别
//NVS分区不包含任何空页。如果NVS分区被截断,可能会发生这种情况。擦除整个分区,重新调用nvs_flash_init。
if(ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND){
ESP_ERROR_CHECK(nvs_flash_erase()); //擦除默认NVS分区
ret = nvs_flash_init(); //初始化nvs flash
}
ESP_ERROR_CHECK(ret);
ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_BLE)); //根据不同模式释放控制器内存
esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();//获取蓝牙默认配置信息 ,通过宏定义的方式赋值给变量
if((ret = esp_bt_controller_init(&bt_cfg)) != ESP_OK){ //初始化蓝牙控制器
ESP_LOGE(SPP_TAG,"%s initialize controller failed: %s\n",__func__,esp_err_to_name(ret));
return;
}
if((ret = esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT)) != ESP_OK){ //使能经典蓝牙控制器
ESP_LOGE(SPP_TAG,"%s enable controller failed: %s\n",__func__,esp_err_to_name(ret));
return;
}
if((ret = esp_bluedroid_init()) != ESP_OK){ //初始化bluedriod
ESP_LOGE(SPP_TAG,"%s initialize bluedriod failed: %s\n",__func__,esp_err_to_name(ret));
return;
}
if((ret = esp_bluedroid_enable() != ESP_OK)){ //使能bluedriod
ESP_LOGE(SPP_TAG,"%s enable bluedriod failed: %s\n",__func__,esp_err_to_name(ret));
return;
}
if((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK){ //注册蓝牙bt回调
ESP_LOGE(SPP_TAG,"%s gap register failed: %s\n",__func__,esp_err_to_name(ret));
return;
}
if((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK){ //注册spp回调函数
ESP_LOGE(SPP_TAG,"%s spp register failed: %s\n",__func__,esp_err_to_name(ret));
return;
}
if((ret = esp_spp_init(esp_spp_mode)) != ESP_OK){
ESP_LOGE(SPP_TAG,"%s spp init failed: %s\n",__func__,esp_err_to_name(ret));
return;
}
if(CONFIG_BT_SSP_ENABLED == true){ //是否使能蓝牙控制器
esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE; //设置IO模式
esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IO; //显示YES/ON
esp_bt_gap_set_security_param(param_type,&iocap,sizeof(uint8_t)); //配置GAP安全参数值。覆盖默认值。
}
esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE; //设置pin类型不可变
esp_bt_pin_code_t pin_code; //设置pin code
esp_bt_gap_set_pin(pin_type,0,pin_code); //设置蓝牙gap pin
uint8_t data[] = "1688\n\r";
while (1){
vTaskDelay(30/portTICK_PERIOD_MS);
if(bt_handle != 0)
esp_spp_write(bt_handle,sizeof(data),&data);
}
}
四、串口实验演示结果
手机端调试APP界面,我这里使用的蓝牙调试器这个软件做为调试工具。
ESP32接收数据
五、ESP32 蓝牙API
5.1、esp_spp_api.h文件中的内容的API
typedef enum {
ESP_SPP_SUCCESS = 0, /*!< 成功操作。*/
ESP_SPP_FAILURE , /*!< 通用的失败。*/
ESP_SPP_BUSY , /*!< 暂时无法处理此请求。*/
ESP_SPP_NO_DATA , /*!< 没有数据*/
ESP_SPP_NO_RESOURCE , /*!< 没有更多的资源*/
ESP_SPP_NEED_INIT , /*!< SPP模块应该先init */
ESP_SPP_NEED_DEINIT , /*!< SPP模块应首先deinit */
ESP_SPP_NO_CONNECTION , /*!< 连接可能已关闭*/
ESP_SPP_NO_SERVER , /*!< 无SPP服务器*/
} esp_spp_status_t;
/*安全设置掩码
使用以下三种蒙版模式:
1. ESP_SPP_SEC_NONE
2. ESP_SPP_SEC_AUTHENTICATE
3.(ESP_SPP_SEC_ENCRYPT | ESP_SPP_SEC_AUTHENTICATE)
*/
#define ESP_SPP_SEC_NONE 0x0000 /*!< 不安全。在bta/bta_api.h 中关联到BTA_SEC_NONE*/
#define ESP_SPP_SEC_AUTHORIZE 0x0001 /*!< 需要的授权(只在出连接时需要)与bta/bta_api.h中的BTA_SEC_AUTHORIZE相关*/
#define ESP_SPP_SEC_AUTHENTICATE 0x0012 /*!< 需要身份验证。与bta/bta_api.h中的BTA_SEC_AUTHENTICATE相关*/
#define ESP_SPP_SEC_ENCRYPT 0x0024 /*!< 需要加密。与bta/bta_api.h中BTA_SEC_ENCRYPT相关*/
#define ESP_SPP_SEC_MODE4_LEVEL4 0x0040 /*!< Mode 4 level 4业务,即入/出MITM和P-256加密涉及bta/bta_api.h中的BTA_SEC_MODE4_LEVEL4*/
#define ESP_SPP_SEC_MITM 0x3000 /*!< Man-In-The_Middle保护与bta/bta_api.h中的BTA_SEC_MITM相关*/
#define ESP_SPP_SEC_IN_16_DIGITS 0x4000 /*!< pin码的最小16位与bta/bta_api.h中的BTA_SEC_IN_16_DIGITS有关*/
typedef uint16_t esp_spp_sec_t;
typedef enum {
ESP_SPP_ROLE_MASTER = 0, /*!< 角色:主 */
ESP_SPP_ROLE_SLAVE = 1, /*!< 角色:从 */
} esp_spp_role_t;
typedef enum {
ESP_SPP_MODE_CB = 0, /*!<当数据到来时,回调函数会带data */
ESP_SPP_MODE_VFS = 1, /*!<使用VFS写/读数据*/
} esp_spp_mode_t;
#define ESP_SPP_MAX_MTU (3*330) /*!< SPP最大MTU */
#define ESP_SPP_MAX_SCN 31 /*!< SPP最大SCN */
/**
* @brief SPP回调函数事件
*/
typedef enum {
ESP_SPP_INIT_EVT = 0, /*!当SPP被启动时,事件来*/
ESP_SPP_UNINIT_EVT = 1, /*!<当SPP是未启动的,事件来*/
ESP_SPP_DISCOVERY_COMP_EVT = 8, /*!<当SDP发现完成时,事件发生*/
ESP_SPP_OPEN_EVT = 26, /*!<当SPP Client连接打开时,事件发生*/
ESP_SPP_CLOSE_EVT = 27, /*!<当SPP连接关闭时,事件发生*/
ESP_SPP_START_EVT = 28, /*!<当SPP服务器启动时,事件发生*/
ESP_SPP_CL_INIT_EVT = 29, /*!当SPP客户端发起一个连接时,事件发生*/
ESP_SPP_DATA_IND_EVT = 30, /*!<当SPP连接收到数据时,事件发生,只有ESP_SPP_MODE_CB */
ESP_SPP_CONG_EVT = 31, /*!<当SPP连接拥塞状态改变时,该事件发生,仅针对ESP_SPP_MODE_CB */
ESP_SPP_WRITE_EVT = 33, /*!<SPP写操作完成时,事件出现,仅针对ESP_SPP_MODE_CB */
ESP_SPP_SRV_OPEN_EVT = 34, /*!<当SPP服务器连接打开时,事件发生*/
ESP_SPP_SRV_STOP_EVT = 35, /*!<当SPP服务器停止时,事件发生*/
} esp_spp_cb_event_t;
/**
* @brief SPP回调参数联合
*/
typedef union {
//SPP_INIT_EVT
struct spp_init_evt_param {
esp_spp_status_t status; /* !<状态*/
} init; /* !<SPP_INIT_EVT的SPP回调参数*/
//SPP_UNINIT_EVT
struct spp_uninit_evt_param {
esp_spp_status_t status; /* !<状态*/
} uninit; /* !<SPP_UNINIT_EVT的SPP回调参数*/
//PP_DISCOVERY_COMP_EVT
struct spp_discovery_comp_evt_param {
esp_spp_status_t status; /* !<状态*/
uint8_t scn_num; /* !<scn_num 的数量*/
uint8_t scn_num(ESP_SPP_MAX_SCN); /* !<通道 # */
const char * service_name [ESP_SPP_MAX_SCN];/* !< 服务器名字 */
} disc_comp; /* !< SPP_DISCOVERY_COMP_EVT的SPP回调参数*/
//ESP_SPP_OPEN_EVT
struct spp_open_evt_param {
esp_spp_status_t status; /* !<状态*/
uint32_t handle; /* !<连接句柄*/
int fd; /* !<仅适用于ESP_SPP_MODE_VFS 的文件描述符*/
esp_bd_addr_t rem_bda; /* !<对端地址*/
} open; /* !<ESP_SPP_OPEN_EVT的SPP回调参数*/
//ESP_SPP_SRV_OPEN_EVT
struct spp_srv_open_evt_param {
esp_spp_status_t status; /* !<状态*/
uint32_t handle; /* !<连接句柄*/
uint32_t new_listen_handle;/*!<新的监听句柄*/
int fd; /* !<仅适用于ESP_SPP_MODE_VFS 的文件描述符*/
esp_bd_addr_t rem_bda; /* !<对端地址*/
} srv_open; /* !<ESP_SPP_SRV_OPEN_EVT 的SPP回调参数*/
//ESP_SPP_CLOSE_EVT
struct spp_close_evt_param {
esp_spp_status_t status; /* !<状态*/
uint32_t port_status; /* !<端口状态*/
uint32_t handle; /* !<连接句柄*/
bool async; /* !<FALSE,如果本地启动断开连接*/
} close; /* !<ESP_SPP_CLOSE_EVT的SPP回调参数*/
//ESP_SPP_START_EVT
struct spp_start_evt_param {
esp_spp_status_t status; /* !<状态*/
uint32_t handle; /* !<连接句柄*/
uint8_t sec_id; /* !<此服务器使用的安全ID */
uint8_t scn; /* !<服务器通道号*/
bool use_co; /* !<TRUE使用co_rfc_data */
} open; /* !<ESP_SPP_START_EVT的SPP回调参数*/
//ESP_SPP_SRV_STOP_EVT
struct spp_srv_stop_evt_param {
esp_spp_status_t status; /* !<状态*/
uint8_t scn; /* !<服务器通道号*/
} srv_stop; /* !<ESP_SPP_SRV_STOP_EVT的SPP回调参数*/
//ESP_SPP_CL_INIT_EVT
struct spp_cl_init_evt_param {
esp_spp_status_t status; /* !<状态*/
uint32_t handle; /* !<连接句柄*/
uint8_t sec_id; /* !<此服务器使用的安全ID */
bool use_co; /* !<TRUE使用co_rfc_data */
} cl_init; /* !<ESP_SPP_CL_INIT_EVT的SPP回调参数*/
//ESP_SPP_WRITE_EVT
struct spp_write_evt_param {
esp_spp_status_t status; /* !<状态*/
uint32_t handle; /* !<连接句柄*/
int sec_id; /* !<写入数据的长度。*/
bool use_co; /* !<拥塞状态*/
} write; /* !<ESP_SPP_WRITE_EVT的SPP回调参数*/
//ESP_SPP_DATA_IND_EVT
struct spp_data_ind_evt_param {
esp_spp_status_t statue; /* !<状态*/
uint32_t handle; /* !<连接句柄*/
uint16_t len; /* !<数据的长度*/
uint8_t * data; /* !<接收的数据*/
} data_ind; /* !<ESP_SPP_DATA_IND_EVT的SPP回调参数*/
//ESP_SPP_CONG_EVT
struct spp_cong_evt_param {
esp_spp_status_t status; /* !<状态*/
uint32_t handle; /* !<连接句柄*/
bool cong; /* !<真的,拥挤。假,拥堵*/
} cong; /* !<ESP_SPP_CONG_EVT的SPP回调参数*/
} esp_spp_cb_param_t; /* !<SPP回调参数联合类型*/
/**
* @brief SPP回调函数类型。
* 当句柄ESP_SPP_DATA_IND_EVT时,强烈建议缓存传入的数据,并处理它们
* 其他低优先级的应用程序任务,而不是直接在这个回调中。
* @param事件:事件类型
* @param param:指向回调参数,目前是联合类型
*/
typedef void (esp_spp_cb_t)(esp_spp_cb_event_t event,esp_spp_cb_param_t *param);
/**
* 这个函数被调用来初始化SPP模块的回调。
* @param[in] callback: init回调函数的指针。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_register_callback (esp_spp_cb_t callback);
/**
* 这个函数被调用来初始化SPP模块。
* 当操作完成时,回调函数将被调用ESP_SPP_INIT_EVT。
* 这个函数应该在esp_bluedroid_enable()成功完成后调用。
* @param[in] mode:选择SPP、ESP_SPP_MODE_CB或ESP_SPP_MODE_VFS模式。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_init (esp_spp_mode_t mode);
/**
* 这个函数被调用来uninit SPP模块。
* 该操作将首先关闭所有活动的SPP连接,然后调用回调函数
* ESP_SPP_CLOSE_EVT, ESP_SPP_CLOSE_EVT的个数等于连接数。
* 当操作完成时,回调函数将被调用ESP_SPP_UNINIT_EVT。
* 这个函数应该在esp_spp_init()成功完成后调用。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_deinit(void);
/**
* @brief该函数用于发现对等设备提供的服务。
* 当操作完成时,将调用ESP_SPP_DISCOVERY_COMP_EVT回调函数。
* 该函数必须在esp_spp_init()成功之后,在esp_spp_deinit()之前调用。
* @param[in] bd_addr:远端设备蓝牙设备地址。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_start_discovery (esp_bd_addr_t bd_addr);
/**
* 这个函数建立一个到远程BD地址的SPP连接。
* 当连接启动或失败时,使用ESP_SPP_CL_INIT_EVT调用回调函数。
* 当连接建立或失败时,使用ESP_SPP_OPEN_EVT调用回调函数。
* 该函数必须在esp_spp_init()成功之后,在esp_spp_deinit()之前调用。
* @param[in] sec_mask:安全设置掩码。建议只使用“ESP_SPP_SEC_NONE”、“ESP_SPP_SEC_AUTHORIZE”或“ESP_SPP_SEC_AUTHENTICATE”。
* @param[in]角色:主或从。
* @param[in] remote_scn:远端设备蓝牙设备SCN。
* @param[in] peer_bd_addr:远端设备蓝牙设备地址。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_connect(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t remote_scn, esp_bd_addr_t peer_bd_addr);
/**
* 这个函数关闭一个SPP连接。
* 当操作完成时,将使用ESP_SPP_CLOSE_EVT调用回调函数。
* 该函数必须在esp_spp_init()成功之后,在esp_spp_deinit()之前调用。
* @param[in] handle:连接句柄。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_disconnect(uint32_t handle);
/**
* 这个函数创建一个SPP服务器,并开始监听一个
* 来自远程蓝牙设备的SPP连接请求。
* 当服务器启动成功时,调用ESP_SPP_START_EVT回调函数。
* 当连接建立后,使用ESP_SPP_SRV_OPEN_EVT调用回调。
* 该函数必须在esp_spp_init()成功之后,在esp_spp_deinit()之前调用。
* @param[in] sec_mask:安全设置掩码。建议只使用“ESP_SPP_SEC_NONE”、“ESP_SPP_SEC_AUTHORIZE”或“ESP_SPP_SEC_AUTHENTICATE”。
* @param[in]角色:主或从。
* @param[in] local_scn:你想要获得的特定通道。
* 如果通道是0,意味着获得任何通道。
* @param[in] name:服务器名。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_start_srv(esp_spp_sec_t sec_mask, esp_spp_role_t role, uint8_t local_scn, const char *name);
/**
* @brief停止所有SPP服务器。
* 该操作将首先关闭所有活动的SPP连接,然后调用回调函数
* ESP_SPP_CLOSE_EVT, ESP_SPP_CLOSE_EVT的个数等于连接数。
* 当操作完成时,使用ESP_SPP_SRV_STOP_EVT调用回调函数。
* 该函数必须在esp_spp_init()成功之后,在esp_spp_deinit()之前调用。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_stop_srv(void);
/**
* @brief停止一个特定的SPP服务器。
* 该操作将首先关闭特定SPP服务器上所有活动的SPP连接,然后调用回调函数
* ESP_SPP_CLOSE_EVT, ESP_SPP_CLOSE_EVT的个数等于连接数。
* 当操作完成时,使用ESP_SPP_SRV_STOP_EVT调用回调函数。
* 该函数必须在esp_spp_init()成功之后,在esp_spp_deinit()之前调用。
* @param[in] scn:服务器通道号。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_stop_srv_scn (uint8_t scn);
/**
* @brief写数据,仅针对ESP_SPP_MODE_CB。
* 当需要重复调用此函数时,强烈建议在之后再次调用此函数
* 接收到前一个事件ESP_SPP_WRITE_EVT,参数cong等于false。如果前一个事件
* 参数'cong'的ESP_SPP_WRITE_EVT等于true,该函数只能在事件发生时被再次调用
* 参数cong等于false的ESP_SPP_CONG_EVT被接收。
* 这个函数必须在启动器和接受器之间建立连接后调用。
* @param[in] handle:连接句柄。
* @param[in] len:写入数据的长度。
* @param[in] p_data:写入的数据。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t (uint32_t handle, int len, uint8_t *p_data);
/**
* @brief用于注册VFS。
* 目前SPP只支持写、读和关闭。
* @return
* —ESP_OK: success
* - other:失败
*/
esp_err_t esp_spp_vfs_register(void);
5.2、esp_gap_bt_api.h文件中的内容的API
/// RSSI阈值
#define ESP_BT_GAP_RSSI_HIGH_THRLD -20 /*!< 高 RSSI 阈值 */
#define ESP_BT_GAP_RSSI_LOW_THRLD -45 /*!< 低 RSSI 阈值 */
/// 设备类
typedef struct {
uint32_t reserved_2: 2; /*!< 未定义 */
uint32_t minor: 6; /*!< 次要类 */
uint32_t major: 5; /*!< 主要类*/
uint32_t service: 11; /*!< 服务类 */
uint32_t reserved_8: 8; /*!< 未定义 */
} esp_bt_cod_t;
/// 设备设置类
typedef enum {
ESP_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_cod_mode_t;
#define ESP_BT_GAP_AFH_CHANNELS_LEN 10
typedef uint8_t esp_bt_gap_afh_channels[ESP_BT_GAP_AFH_CHANNELS_LEN];
/// 可发现性和可连接性模式
typedef enum {
ESP_BT_NON_CONNECTABLE, /*!< 不可连接 */
ESP_BT_CONNECTABLE, /*!< 可连接 */
} esp_bt_connection_mode_t;
typedef enum {
ESP_BT_NON_DISCOVERABLE, /*!< 不可发现 */
ESP_BT_LIMITED_DISCOVERABLE, /*!< 有限可发现 */
ESP_BT_GENERAL_DISCOVERABLE, /*!< 一般可发现 */
} esp_bt_discovery_mode_t;
/// 蓝牙设备属性类型
typedef enum {
ESP_BT_GAP_DEV_PROP_BDNAME = 1, /*!<蓝牙设备名称,值类型为int8_t [] */
ESP_BT_GAP_DEV_PROP_COD, /*!< 设备类别,值类型为 uint32_t */
ESP_BT_GAP_DEV_PROP_RSSI, /*!< 接收到的信号强度指示,值类型为int8_t,范围从-128到127 */
ESP_BT_GAP_DEV_PROP_EIR, /*!< 扩展查询响应,值类型为 uint8_t [] */
} esp_bt_gap_dev_prop_type_t;
/// 蓝牙设备名称的最大字节数
#define ESP_BT_GAP_MAX_BDNAME_LEN (248)
/// EIR 有效部分的最大大小
#define ESP_BT_GAP_EIR_DATA_LEN (240)
/// 蓝牙设备属性描述符
typedef struct {
esp_bt_gap_dev_prop_type_t type; /*!< 设备属性类型 */
int len; /*!< 设备属性值长度 */
void *val; /*!< 设备属性值 */
} esp_bt_gap_dev_prop_t;
/// 扩展查询响应数据类型
#define ESP_BT_EIR_TYPE_FLAGS 0x01 /*!< 带有 BR/EDR 和 LE 支持等信息的标志 */
#define ESP_BT_EIR_TYPE_INCMPL_16BITS_UUID 0x02 /*!< 16 位服务 UUID 的不完整列表 */
#define ESP_BT_EIR_TYPE_CMPL_16BITS_UUID 0x03 /*!< 16 位服务 UUID 的完整列表 */
#define ESP_BT_EIR_TYPE_INCMPL_32BITS_UUID 0x04 /*!< 32 位服务 UUID 的不完整列表 */
#define ESP_BT_EIR_TYPE_CMPL_32BITS_UUID 0x05 /*!< 32 位服务 UUID 的完整列表 */
#define ESP_BT_EIR_TYPE_INCMPL_128BITS_UUID 0x06 /*!< 128 位服务 UUID 不完整列表 */
#define ESP_BT_EIR_TYPE_CMPL_128BITS_UUID 0x07 /*!< 128 位服务 UUID 的完整列表 */
#define ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME 0x08 /*!< 缩短的本地名称 */
#define ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME 0x09 /*!< 完整的本地名称 */
#define ESP_BT_EIR_TYPE_TX_POWER_LEVEL 0x0a /*!< Tx 功率电平,值是 1 个八位字节,范围从 -127 到 127,单位是 dBm*/
#define ESP_BT_EIR_TYPE_URL 0x24 /*!< 统一资源标识符 */
#define ESP_BT_EIR_TYPE_MANU_SPECIFIC 0xff /*!< 制造商特定数据 */
#define ESP_BT_EIR_TYPE_MAX_NUM 12 /*!< EIR 类型的最大数量 */
typedef uint8_t esp_bt_eir_type_t;
/* ESP_BT_EIR_FLAG 位定义 */
#define ESP_BT_EIR_FLAG_LIMIT_DISC (0x01 << 0)
#define ESP_BT_EIR_FLAG_GEN_DISC (0x01 << 1)
#define ESP_BT_EIR_FLAG_BREDR_NOT_SPT (0x01 << 2)
#define ESP_BT_EIR_FLAG_DMT_CONTROLLER_SPT (0x01 << 3)
#define ESP_BT_EIR_FLAG_DMT_HOST_SPT (0x01 << 4)
#define ESP_BT_EIR_MAX_LEN 240
/// EIR数据内容,根据“蓝牙核心规范补充”
typedef struct {
bool fec_required; /* !< FEC是否必需,默认为true */
bool include_txpower; /* !< EIR数据包含TX功率,默认为false */
bool include_uuid; /* !< EIR数据包含UUID,默认为false */
uint8_t flag; /* !< EIR flags,参见ESP_BT_EIR_FLAG详细信息,EIR将不包括flag,如果它是0,0默认*/
uint16_t manufacturer_len; /* !< 制造商数据长度,默认为0 */
uint8_t * p_manufacturer_data; /* !< 制造商数据点*/
uint16_t url_len; /* !< URL长度,默认为0 */
uint8_t * p_url; /* !< URL点*/
} esp_bt_eir_data_t;
///设备类别的主要服务类别字段,可设置多位
typedef enum {
ESP_BT_COD_SRVC_NONE = 0, /* !< None表示无效值*/
ESP_BT_COD_SRVC_LMTD_DISCOVER = 0x1, /* !<有限的可发现模式*/
ESP_BT_COD_SRVC_POSITIONING = 0x8, /* !<定位(位置标识)*/
ESP_BT_COD_SRVC_NETWORKING = 0x10, /* !<网络,例如LAN, Ad hoc */
ESP_BT_COD_SRVC_RENDERING = 0x20, /* !<渲染,例如打印,扬声器*/
ESP_BT_COD_SRVC_CAPTURING = 0x40, /* !<捕获,例如扫描仪,麦克风*/
ESP_BT_COD_SRVC_OBJ_TRANSFER = 0x80, /* !<对象传输,例如v-Inbox, v-Folder */
ESP_BT_COD_SRVC_AUDIO = 0x100, /* !<音频,如扬声器、麦克风、耳机服务*/
ESP_BT_COD_SRVC_TELEPHONY = 0x200, /* !<电话服务,例如无绳电话、调制解调器、耳机服务*/
ESP_BT_COD_SRVC_INFORMATION = 0x400, /* !<信息,例如:WEB-server, WAP-server */
} esp_bt_cod_srvc_t;
typedef enum {
ESP_BT_PIN_TYPE_VARIABLE = 0, /* !<参考BTM_PIN_TYPE_VARIABLE */
ESP_BT_PIN_TYPE_FIXED = 1, /* !<参考BTM_PIN_TYPE_FIXED */
} esp_bt_pin_type_t;
#define ESP_BT_PIN_CODE_LEN 16 /* !<最大pin码长度*/
typedef uint8_t esp_bt_pin_code_t [ESP_BT_PIN_CODE_LEN];/* !< Pin Code(最多128 bits) MSB是0 */
typedef enum {
ESP_BT_SP_IOCAP_MODE = 0, /*!<设置IO模式*/
// ESP_BT_SP_OOB_DATA, // TODO /*!<设置OOB数据*/
} esp_bt_sp_param_t;
/*关联到堆栈/BTM_IO_CAP_xxxin stack/btm_api.h */
#define ESP_BT_IO_CAP_OUT 0 /*!< 仅显示 */ /*与堆栈中的BTM_IO_CAP_OUT相关/btm_api.h */
#define ESP_BT_IO_CAP_IO 1 /*!< 是否显示 */ /*关联到堆栈中的BTM_IO_CAP_IO /btm_api.h */
#define ESP_BT_IO_CAP_IN 2 /*!< 仅键盘 */ /*关联到堆栈中的BTM_IO_CAP_IN /btm_api.h */
#define ESP_BT_IO_CAP_NONE 3 /*!< 无输入无输出 */ /*关联到堆栈BTM_IO_CAP_NONE中的/btm_api.h*/
typedef uint8_t esp_bt_io_cap_t; /*!< IO能力的组合*/
/* BTM电源管理器模式*/
#define ESP_BT_PM_MD_ACTIVE 0x00 /*!<激活模式*/
#define ESP_BT_PM_MD_HOLD 0x01 /*!<保持模式*/
#define ESP_BT_PM_MD_SNIFF 0x02 /*!<嗅探模式*/
#define ESP_BT_PM_MD_PARK 0x03 /*!<公园状态*/
typedef uint8_t esp_bt_pm_mode_t;
///主要服务类别字段的位
#define ESP_BT_COD_SRVC_BIT_MASK (0xffe000) /*!<主要业务位掩码*/
#define ESP_BT_COD_SRVC_BIT_OFFSET (13) /*!<主要服务位偏移*/
/// class of device的主要设备类字段
typedef enum {
ESP_BT_COD_MAJOR_DEV_MISC = 0, /*!<杂*/
ESP_BT_COD_MAJOR_DEV_COMPUTER = 1, /*!<计算机*/
ESP_BT_COD_MAJOR_DEV_PHONE = 2, /*!<电话(蜂窝电话,无绳电话,公用电话,调制解调器*/
ESP_BT_COD_MAJOR_DEV_LAN_NAP = 3, /*!<局域网,网络接入点*/
ESP_BT_COD_MAJOR_DEV_AV = 4, /*!<音频/视频(耳机、扬声器、立体声、视频显示器、VCR */
ESP_BT_COD_MAJOR_DEV_PERIPHERAL = 5, /*!<外设(鼠标,操纵杆,键盘)*/
ESP_BT_COD_MAJOR_DEV_IMAGING = 6, /*!<成像(打印机,扫描仪,相机,显示器*/
ESP_BT_COD_MAJOR_DEV_WEARABLE = 7, /*!<可穿戴*/
ESP_BT_COD_MAJOR_DEV_TOY = 8, /*!<玩具*/
ESP_BT_COD_MAJOR_DEV_HEALTH = 9, /*!<健康*/
ESP_BT_COD_MAJOR_DEV_UNCATEGORIZED = 31, /*!<未分类:设备未指定*/
} esp_bt_cod_major_dev_t;
///主要设备类字段的位
#define ESP_BT_COD_MAJOR_DEV_BIT_MASK (0x1f00) /*!<主要设备位掩码*/
#define ESP_BT_COD_MAJOR_DEV_BIT_OFFSET (8) /*!<主要设备位偏移*/
///次要设备类字段的位
#define ESP_BT_COD_MINOR_DEV_BIT_MASK (0xfc) /*!<一般设备位掩码*/
#define ESP_BT_COD_MINOR_DEV_BIT_OFFSET (2) /*!<次要设备位偏移*/
///格式类型的位
#define ESP_BT_COD_FORMAT_TYPE_BIT_MASK (0x03) /*!<格式类型位掩码*/
#define ESP_BT_COD_FORMAT_TYPE_BIT_OFFSET (0) /*!<格式类型位偏移*/
///设备格式类型1
#define ESP_BT_COD_FORMAT_TYPE_1 (0x00)
/**蓝牙设备发现状态*/
typedef enum {
ESP_BT_GAP_DISCOVERY_STOPPED, /*!<设备发现已停止*/
ESP_BT_GAP_DISCOVERY_STARTED, /*!<设备发现已启动*/
} esp_bt_gap_discovery_state_t;
/// BT GAP回调事件
typedef enum {
ESP_BT_GAP_DISC_RES_EVT = 0, /*!<设备发现结果事件*/
ESP_BT_GAP_DISC_STATE_CHANGED_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, /*!<遗留配对Pin码请求*/
ESP_BT_GAP_CFM_REQ_EVT, /*!<安全简单配对用户确认请求。*/
ESP_BT_GAP_KEY_NOTIF_EVT, /*!<安全简单配对密钥通知*/
ESP_BT_GAP_KEY_REQ_EVT, /*!<安全简单配对密码请求*/
ESP_BT_GAP_READ_RSSI_DELTA_EVT, /*!<读取rssi事件*/
ESP_BT_GAP_CONFIG_EIR_DATA_EVT, /*!<配置EIR数据事件*/
ESP_BT_GAP_SET_AFH_CHANNELS_EVT, /*!<设置AFH通道事件*/
ESP_BT_GAP_READ_REMOTE_NAME_EVT, /*!<读取远程名称事件*/
ESP_BT_GAP_MODE_CHG_EVT,
ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT, /*!<移除绑定设备完成事件*/
ESP_BT_GAP_QOS_CMPL_EVT, /*!<QOS完成事件*/
ESP_BT_GAP_EVT_MAX,
} esp_bt_gap_cb_event_t;
/**查询模式*/
typedef enum {
ESP_BT_INQ_MODE_GENERAL_INQUIRY, /*!<一般查询模式*/
ESP_BT_INQ_MODE_LIMITED_INQUIRY, /*!<有限查询模式*/
} esp_bt_inq_mode_t;
/**最小和最大查询长度*/
#define ESP_BT_GAP_MIN_INQ_LEN (0x01) /*!<最小查询时长,单位为1.28s */
#define ESP_BT_GAP_MAX_INQ_LEN (0x30) /*!<最大查询时长,单位为1.28s */
/// A2DP状态回调参数
typedef union {
//ESP_BT_GAP_DISC_RES_EVT
struct disc_res_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
int num_prop; /* !<获取属性的数量*/
esp_bt_gap_dev_prop_t *prop; /* !<从新设备发现的属性*/
} disc_res; /* !<发现结果参数struct */
//ESP_BT_GAP_DISC_STATE_CHANGED_EVT
struct disc_state_changed_param {
esp_bt_gap_discovery_state_t状态;/* !<发现状态*/
} disc_st_chg; /* !<发现状态改变参数struct */
//ESP_BT_GAP_RMT_SRVCS_EVT
struct rmt_srvcs_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
esp_bt_status_t stat; /* !<服务搜索状态*/
int num_uuids; /* !< uuid_list中UUID的个数*/
esp_bt_uuid_t * uuid_list; /* !<远端设备uuid列表*/
} rmt_srvcs; /* !<服务的远端设备参数struct */
//ESP_BT_GAP_RMT_SRVC_REC_EVT
struct rmt_srvc_rec_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
esp_bt_status_t stat; /* !<服务搜索状态*/
} rmt_srvc_rec; /* !<来自远端设备的特定服务记录参数struct */
//ESP_BT_GAP_READ_RSSI_DELTA_EVT
struct read_rssi_delta_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
esp_bt_status_t stat; /* !<读取rssi状态*/
int8_t rssi_delta; /* !< rssi delta值范围-128 ~127,取值为0表示rssi在黄金接收功率范围内,黄金接收功率范围从ESP_BT_GAP_RSSI_LOW_THRLD到ESP_BT_GAP_RSSI_HIGH_THRLD */
} read_rssi_delta; /* !<读取rssi参数struct */
// ESP_BT_GAP_CONFIG_EIR_DATA_EVT
struct config_eir_data_param {
esp_bt_status_t stat; /* !配置EIR状态:
ESP_BT_STATUS_SUCCESS:配置成功
ESP_BT_STATUS_EIR_TOO_LARGE: EIR数据大于240B。EIR可能不包含整个数据。
其他:失败*/
uint8_t eir_type_num; /* !< EIR类型中EIR类型的数量*/
esp_bt_eir_type_t eir_type [ESP_BT_EIR_TYPE_MAX_NUM];/* !< EIR类型中的EIR类型*/
} config_eir_data; /* !<配置EIR数据*/
// ESP_BT_GAP_AUTH_CMPL_EVT
struct auth_cmpl_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
esp_bt_status_t stat; /* !<认证完成状态*/
uint8_t device_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];/* !<设备名*/
} auth_cmpl; /* !<认证完成参数struct */
//ESP_BT_GAP_PIN_REQ_EVT
struct pin_req_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
bool min_16_digit; /* !< TRUE如果返回的引脚必须至少为16位*/
} pin_req; /* !< pin请求参数struct */
//ESP_BT_GAP_CFM_REQ_EVT
struct cfm_req_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
uint32_t num_val; /* !<用于比较的数值。*/
} cfm_req; /* !<确认请求参数struct */
//ESP_BT_GAP_KEY_NOTIF_EVT
struct key_notif_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
uint32_t passkey; /* !<密钥条目的数值。*/
} key_notif; /* !< passkey notif参数struct */
//ESP_BT_GAP_KEY_REQ_EVT
struct key_req_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
} key_req; /* !< passkey请求参数struct */
//ESP_BT_GAP_SET_AFH_CHANNELS_EVT
struct set_afh_channels_param {
esp_bt_status_t stat; /* !<设置AFH通道状态*/
} set_afh_channels; /* !<设置AFH通道参数struct */
//ESP_BT_GAP_READ_REMOTE_NAME_EVT
struct read_rmt_name_param {
esp_bt_status_t stat; /* !<读取远端名称状态*/
uint8_t rmt_name[ESP_BT_GAP_MAX_BDNAME_LEN + 1];/* !<远端设备名称*/
} read_rmt_name; /* !<读取远程名称参数struct */
//ESP_BT_GAP_MODE_CHG_EVT
struct mode_chg_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
esp_bt_pm_mode_t mode; /* !< PM模式*/
} mode_chg; /* !<模式更改事件参数struct */
//ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT
struct bt_remove_bond_dev_cmpl_evt_param {
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
esp_bt_status_t status; /* !<移除绑定设备操作成功状态*/
} remove_bond_dev_cmpl; /* !< ESP_BT_GAP_REMOVE_BOND_DEV_COMPLETE_EVT事件参数*/
//ESP_BT_GAP_QOS_CMPL_EVT
struct qos_cmpl_param {
esp_bt_status_t stat; /* !< QoS状态*/
esp_bd_addr_t bda; /* !<远程蓝牙设备地址*/
uint32_t t_poll; /* !<轮询间隔,传输之间的最大时间
哪个从主到ACL上的特定从
逻辑运输。单位是0.625毫秒。*/
} qos_cmpl; /* !< QoS complete parameter struct */
} esp_bt_gap_cb_param_t;
/**
* @brief蓝牙GAP回调功能类型
* @param事件:事件类型
* @param param:回调参数指针
*/
typedef void (* esp_bt_gap_cb_t)(esp_bt_gap_cb_event_t事件,esp_bt_gap_cb_param_t *param);
/**
*简要获取COD的主要服务领域
* @param[in] cod:设备的类别
* @返回主要服务位
*/
static inline uint32_t esp_bt_gap_get_cod_srvc(uint32_t cod)
{
return (cod & ESP_BT_COD_SRVC_BIT_MASK);
}
/**
简要获取COD的主要设备领域
* @param[in] cod:设备的类别
* @返回主要设备位
*/
static inline uint32_t esp_bt_gap_get_cod_major_dev(uint32_t cod)
{
return (cod & ESP_BT_COD_MAJOR_DEV_BIT_MASK) >;
}
/**
*简要得到COD的次要服务领域
* @param[in] cod:设备的类别
* @返回次要服务位
*/
static inline uint32_t esp_bt_gap_get_cod_minor_dev(uint32_t cod)
{
return (cod & ESP_BT_COD_MINOR_DEV_BIT_MASK) >;
}
/**
* @brief获取COD格式类型
* @param[in] cod:设备的类别
* @返回格式类型
*/
static inline uint32_t esp_bt_gap_get_cod_format_type(uint32_t cod)
{
return (cod & ESP_BT_COD_FORMAT_TYPE_BIT_MASK);
}
/**
* @brief决定COD的完整性
* @param[in] cod:设备的类别
* @return
* -当cod有效时为真
* - false otherise
*/
static inline bool esp_bt_gap_is_valid_cod(uint32_t cod)
{
if (esp_bt_gap_get_cod_format_type(cod) == ESP_BT_COD_FORMAT_TYPE_1 && esp_bt_gap_get_cod_srvc(cod) != ESP_BT_COD_SRVC_NONE) {
return true;
}
return fals
}
/**
* @brief寄存器回调函数。这个函数应该在esp_bluedroid_enable()成功完成后调用
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_register_callback (esp_bt_gap_cb_t callback);
/**
* @brief设置遗留蓝牙的可发现和可连接模式。这个函数应该
*在esp_bluedroid_enable()成功完成后被调用
* @param[in] c_mode: esp_bt_connection_mode_t的枚举之一
* @param[in] d_mode: esp_bt_discovery_mode_t的枚举之一
* @return
*—ESP_OK: Succeed .输出说明
* - ESP_ERR_INVALID_ARG:如果参数无效
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_set_scan_mode(esp_bt_connection_mode_t c_mode, esp_bt_discovery_mode_t d_mode);
/**
这个函数开始查询和名称发现。这个函数应该在esp_bluedroid_enable()成功完成后调用。
*当查询停止,缓存的结果不包含设备名称,那么名称发现将连接到对等目标以获取设备名称。
当查询开始或名称发现完成时,esp_bt_gap_cb_t将被ESP_BT_GAP_DISC_STATE_CHANGED_EVT调用。
* esp_bt_gap_cb_t与ESP_BT_GAP_DISC_RES_EVT一起调用,每次得到两种类型的发现结果。
* @param[in] mode -查询模
* @param[in] inq_len -以1.28秒为单位的查询时间,范围从0x01到0x30。此参数仅指定查询进程的总持续时间,
* -当这个时间到期时,查询将停止。
* @param[in] num_rsps -查询停止前可以接收到的响应数,值0表示无限的响应数。
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
*—ESP_ERR_INVALID_ARG:如果提供了无效参数
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_start_discovery(esp_bt_inq_mode_t mode, uint8_t inq_len, uint8_t num_rsps);
/**
* @brief取消查询和名称发现。这个函数应该在esp_bluedroid_enable()成功完成后调用。
如果查询或名称发现被取消,esp_bt_gap_cb_t将被ESP_BT_GAP_DISC_STATE_CHANGED_EVT调用
*调用此函数。
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_cancel_discovery(void);
/**
启动SDP获取远程服务。这个函数应该在esp_bluedroid_enable()成功完成后调用。
在服务发现结束后,esp_bt_gap_cb_t将被ESP_BT_GAP_RMT_SRVCS_EVT调用。
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_get_remote_services (esp_bd_addr_t remote_bda);
/**
* @brief启动SDP,查找远端设备的服务匹配uuid。之后应该调用此函数
esp_bluedroid_enable()成功完成。
在服务发现结束后,esp_bt_gap_cb_t将被ESP_BT_GAP_RMT_SRVC_REC_EVT调用
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_get_remote_service_record(esp_bd_addr_t remote_bda, esp_bt_uuid_t *uuid);
/**
这个函数被调用来获取特定类型的EIR数据。
@param[in] eir -要解析的原始eir数据的指针
@param[in] type -特定的EIR数据类型
* @param[out] length -返回EIR数据的长度,不包括长度和数据类型字段
* @返回eir数据的起始位置的指针,如果没有找到eir数据类型,则为NULL
*/
Uint8_t *esp_bt_gap_resolve_eir_data(Uint8_t *eir, esp_bt_eir_type_t type,Uint8_t *length);
/**
这个函数被调用来配置EIR数据。
esp_bt_gap_cb_t将在配置EIR结束后调用ESP_BT_GAP_CONFIG_EIR_DATA_EVT。
@param[in] eir_data——EIR数据内容的指针
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
*—ESP_ERR_INVALID_ARG:参数无效
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_config_eir_data (esp_bt_eir_data_t * eir_data);
/**
这个函数被调用来设置设备的类。
结构体esp_bt_gap_cb_t将在设置的COD结束后被ESP_BT_GAP_SET_COD_EVT调用。
*一些配置文件对设备类别有特殊的限制,更改可能导致这些配置文件不工作。
* @param[in] cod -设备的等级
* @param[in] mode -设置模式
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
*—ESP_ERR_INVALID_ARG:参数无效
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_set_cod(esp_bt_cod_t cod, esp_bt_cod_mode_t mode);
/**
这个函数被调用来获取device的类。
* @param[out] cod -设备的等级
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_get_cod (esp_bt_cod_t *cod);
/**
这个函数在连接后按地址读取RSSI增量。ESP_BT_GAP_READ_RSSI_DELTA_EVT返回的RSSI值。
* @param[in] remote_addr -远端设备地址,对应于某个连接句柄
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_read_rssi_delta (esp_bd_addr_t remote_addr);
/**
从安全数据库列表中删除一个设备对等设备。
* @param[in] bd_addr:对端设备BD地址
* @return - ESP_OK:成功
*—ESP_FAIL:失败
*/
esp_err_t esp_bt_gap_remove_bond_device (esp_bd_addr_t bd_addr);
/**
* @brief从对端设备的安全数据库列表中获取设备号。
*立即返回设备保税编号。
* @return - >= 0:绑定设备号
*—ESP_FAIL:失败
*/
int esp_bt_gap_get_bond_device_num(void);
/**
从对端设备的安全数据库列表中获取该设备。
*立即返回设备绑定信息。
* @param[inout] dev_num:指定作为输入的dev_list数组(缓冲区)大小。
*如果dev_num足够大,则表示实际输出的数字。
*建议dev_num的值为esp_ble_get_bond_device_num()。
* @param[out] dev_list:一个“esp_bd_addr_t”类型的数组(缓冲区)。用于存放绑定设备的地址。
* dev_list应该由调用API的人分配。
* @return
*—ESP_OK: Succeed .输出说明
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
*—ESP_FAIL: others
*/
esp_err_t esp_bt_gap_get_bond_device_list(int *dev_num, esp_bd_addr_t *dev_list);
/**
* @brief为遗留配对设置引脚类型和默认引脚代码。
* @param[in] pin_type:使用变量或固定引脚。
*如果pin_type为ESP_BT_PIN_TYPE_VARIABLE,则pin_code和pin_code_len
*将被忽略,ESP_BT_GAP_PIN_REQ_EVT将在控制时出现
*要求pin码。
*否则,将使用固定的pin码和不回调用户。
* @param[in] pin_code_len: pin_code长度
* @param[in] pin_code: pin_code
* @return - ESP_OK:成功
* —ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
* - other:失败
*/
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);
/**
回复对端设备的pin_code进行遗留配对
* ESP_BT_GAP_PIN_REQ_EVT何时到来。
* @param[in] bd_addr:对端BD地址
@param[in] accept: Pin_code回复成功或被拒绝。
* @param[in] pin_code_len: pin_code长度
* @param[in] pin_code: pin_code
* @return - ESP_OK:成功
* —ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
* - other:失败
*/
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);
#if (BT_SSP_INCLUDED == TRUE)
/**
* @brief配置GAP安全参数值。覆盖默认值。
* @param[in] param_type:要设置的参数类型
* @param[in] value:参数值
* @param[in] len:参数值的长度
* @return - ESP_OK:成功
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
* - other:失败
*/
esp_err_t esp_bt_gap_set_security_param (esp_bt_sp_param_t param_type,void *value,uint8_t len);
/**
* @brief回复遗留连接阶段的键值给对端设备。
* @param[in] bd_addr:对端BD地址
* @param[in] accept:密码输入成功或被拒绝。
* @param[in] passkey:密钥值,必须是6位数字,可以由0开头。
* @return - ESP_OK:成功
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
* - other:失败
*/
esp_err_t esp_bt_gap_ssp_passkey_reply(esp_bd_addr_t bd_addr, bool accept, uint32_t passkey);
/**
* @brief在遗留连接阶段向对端设备回复确认值。
* @param[in] bd_addr:对端设备BD地址
* @param[in] accept:要比较的数字是相同的还是不同的
* @return - ESP_OK:成功
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
* - other:失败
*/
esp_err_t esp_bt_gap_ssp_confirm_reply(esp_bd_addr_t bd_addr, bool accept);
#endif /*(BT_SSP_INCLUDED == TRUE)*/
/**
设置AFH频道
* @param[in] channels:第n个这样的字段(范围0到78)包含通道n的值:
* 0表示通道n是坏的。
* 1表示通道n是未知的。
*最高位保留,设置为0。
*至少20个通道应标记为未知。
* @return - ESP_OK:成功
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
* - other:失败
*/
esp_err_t esp_bt_gap_set_afh_channels (esp_bt_gap_afh_channels channels);
/**
* @brief读取远端设备名称
* @param[in] remote_bda:远端设备地址
* @return - ESP_OK:成功
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
* - other:失败
*/
esp_err_t esp_bt_gap_read_remote_name (esp_bd_addr_t remote_bda);
/**
* @brief配置服务质量
* @param[in] remote_bda:远端设备地址
* @param[in] t_poll:轮询间隔,传输之间的最大时间间隔
哪个从主到ACL上的特定从
逻辑运输。单位是0.625毫秒
* @return - ESP_OK:成功
*—ESP_ERR_INVALID_STATE:如果蓝牙栈尚未启用
* - other:失败
*/
esp_err_t esp_bt_gap_set_qos(esp_bd_addr_t remote_bda, uint32_t t_poll);
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)