提示:本博客作为学习笔记,有错误的地方希望指正

  绪论:这里主要讲解一些关于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);
Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐