ESP32 开发笔记——SPP蓝牙

一.释放低功耗蓝牙控制器内存

esp_bt_controller_mem_release(ESP_BT_MODE_BLE)
//传参 esp_bt_mode_t mode
//typedef enum {
//    ESP_BT_MODE_IDLE       = 0x00,   /*!< Bluetooth is not running */
//    ESP_BT_MODE_BLE        = 0x01,   /*!< Run BLE mode *///低功耗蓝牙
//    ESP_BT_MODE_CLASSIC_BT = 0x02,   /*!< Run Classic BT mode *///经典蓝牙
//    ESP_BT_MODE_BTDM       = 0x03,   /*!< Run dual mode *///双模
//} esp_bt_mode_t;

二.初始化蓝牙控制器

esp_bt_controller_init(&bt_cfg);


 三.开启经典蓝牙控制器

esp_bt_controller_enable(ESP_BT_MODE_CLASSIC_BT);
//传参 esp_bt_mode_t mode
//typedef enum {
//    ESP_BT_MODE_IDLE       = 0x00,   /*!< Bluetooth is not running */
//    ESP_BT_MODE_BLE        = 0x01,   /*!< Run BLE mode *///低功耗蓝牙
//    ESP_BT_MODE_CLASSIC_BT = 0x02,   /*!< Run Classic BT mode *///经典蓝牙
//    ESP_BT_MODE_BTDM       = 0x03,   /*!< Run dual mode *///双模
//} esp_bt_mode_t;


四.初始化蓝牙协议栈

esp_bluedroid_init();


五.开启蓝牙协议栈

esp_bluedroid_enable();


六.SPP蓝牙初始化

//注册	SPP	的	callback
    esp_err_t ret = esp_spp_register_callback(esp_spp_cb);
    if(ret){
        ESP_LOGE(BT_SPP_TAG,"%s	spp	register failed\n",	__func__);
        return;
    }
    // ret	= esp_spp_init(esp_spp_mode);
    // if(ret){
    //     ESP_LOGE(BT_SPP_TAG,"%s	spp	init failed\n",	__func__);
    //     return;
    // }

    esp_spp_cfg_t bt_spp_cfg = {
        .mode = esp_spp_mode,
        .enable_l2cap_ertm = true,
        .tx_buffer_size = 0, // Only used for ESP_SPP_MODE_VFS mode 
    };
    ret = esp_spp_enhanced_init(&bt_spp_cfg);
    if (ret) {
        ESP_LOGE(SPP_TAG, "%s spp init failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

spp回调函数

static void	esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t	*param)
{
    // 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服务器停止时,事件发生*/
    switch(event){
    case ESP_SPP_INIT_EVT:
    //SPP callback 注册成功后,将返回ESP_SPP_INIT_EVT事件,在此事件中设置蓝牙名称,设置经典蓝牙	Scan模式
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_INIT_EVT\n");
        esp_bt_dev_set_device_name(bt_ble_device_name);
        // esp_bt_gap_set_scan_mode(ESP_BT_SCAN_MODE_CONNECTABLE_DISCOVERABLE);
        esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
        esp_spp_start_srv(sec_mask,role_slave,	0,	SPP_SERVER_NAME);//开启spp服务
        break;
    case ESP_SPP_DISCOVERY_COMP_EVT:
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_DISCOVERY_COMP_EVT\n");
        break;
    //SPP	连接成功后,将返回	ESP_SPP_OPEN_EVT	事件
    case ESP_SPP_OPEN_EVT:
        // ble_bt_date_flag = 2;
        bt_handle = param->data_ind.handle;
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_OPEN_EVT\n");
        break;
    //SPP	断开后,将返回	ESP_SPP_CLOSE_EVT	事件
    case ESP_SPP_CLOSE_EVT:
        // ble_conect_flag = 0;//
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_CLOSE_EVT\n");
        break;
    case ESP_SPP_START_EVT:
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_START_EVT\n");
        break;
    case ESP_SPP_CL_INIT_EVT:
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_CL_INIT_EVT\n");
        break;  
    case ESP_SPP_DATA_IND_EVT:
        #if	(SPP_SHOW_MODE	==	SPP_SHOW_DATA)
            bt_handle = param->data_ind.handle;
            bt_cmd_date(param);
        #else
            gettimeofday(&time_new,	NULL);
            data_num +=	param->data_ind.len;
            if(time_new.tv_sec-time_old.tv_sec>=3){
                print_speed();
            }
        #endif
    break;
    case ESP_SPP_CONG_EVT:
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_CONG_EVT\n");
        break;
    case ESP_SPP_WRITE_EVT:
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_WRITE_EVT\n");
        break;
    case ESP_SPP_SRV_OPEN_EVT:
        ESP_LOGI(BT_SPP_TAG,"ESP_SPP_SRV_OPEN_EVT\n");
        // gettimeofday(&time_old,	NULL);
        break;
    default:
        break;
    }
}

spp发送函数

esp_err_t esp_spp_write(
    uint32_t handle,
    int len, //数据长度
    uint8_t *p_data//数据内容
)

esp_spp_write(bt_handle,strlen("SPP_SERVE"),(uint8_t *)"SPP_SERVE");

七.源码

/*
 * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
 *
 * SPDX-License-Identifier: Unlicense OR CC0-1.0
 */

#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <stdio.h>
#include "nvs.h"
#include "nvs_flash.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_log.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_bt_api.h"
#include "esp_bt_device.h"
#include "esp_spp_api.h"
#include "console_uart.h"

#include "time.h"
#include "sys/time.h"

#define SPP_TAG "SPP_INITIATOR_DEMO"
#define EXAMPLE_DEVICE_NAME "ESP_SPP_INITIATOR"

#define SPP_SHOW_DATA 0
#define SPP_SHOW_SPEED 1
#define SPP_SHOW_MODE SPP_SHOW_SPEED    /*Choose show mode: show data or speed*/

static const esp_spp_mode_t esp_spp_mode = ESP_SPP_MODE_CB;
static const bool esp_spp_enable_l2cap_ertm = true;

static struct timeval time_new, time_old;
static long data_num = 0;

static const esp_spp_sec_t sec_mask = ESP_SPP_SEC_AUTHENTICATE;
static const esp_spp_role_t role_master = ESP_SPP_ROLE_MASTER;

esp_bd_addr_t peer_bd_addr = {0};
static uint8_t peer_bdname_len;
static char peer_bdname[ESP_BT_GAP_MAX_BDNAME_LEN + 1];
static const char remote_device_name[] = "ESP_SPP_ACCEPTOR";
static const esp_bt_inq_mode_t inq_mode = ESP_BT_INQ_MODE_GENERAL_INQUIRY;
static const uint8_t inq_len = 30;
static const uint8_t inq_num_rsps = 0;

#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
#define SPP_DATA_LEN 20
#else
#define SPP_DATA_LEN ESP_SPP_MAX_MTU
#endif
static uint8_t spp_data[SPP_DATA_LEN];
static uint8_t *s_p_data = NULL; /* data pointer of spp_data */

static char *bda2str(uint8_t * bda, char *str, size_t size)
{
    if (bda == NULL || str == NULL || size < 18) {
        return NULL;
    }

    uint8_t *p = bda;
    sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
            p[0], p[1], p[2], p[3], p[4], p[5]);
    return str;
}

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;
}

static bool get_name_from_eir(uint8_t *eir, char *bdname, uint8_t *bdname_len)
{
    uint8_t *rmt_bdname = NULL;
    uint8_t rmt_bdname_len = 0;

    if (!eir) {
        return false;
    }

    rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_CMPL_LOCAL_NAME, &rmt_bdname_len);
    if (!rmt_bdname) {
        rmt_bdname = esp_bt_gap_resolve_eir_data(eir, ESP_BT_EIR_TYPE_SHORT_LOCAL_NAME, &rmt_bdname_len);
    }

    if (rmt_bdname) {
        if (rmt_bdname_len > ESP_BT_GAP_MAX_BDNAME_LEN) {
            rmt_bdname_len = ESP_BT_GAP_MAX_BDNAME_LEN;
        }

        if (bdname) {
            memcpy(bdname, rmt_bdname, rmt_bdname_len);
            bdname[rmt_bdname_len] = '\0';
        }
        if (bdname_len) {
            *bdname_len = rmt_bdname_len;
        }
        return true;
    }

    return false;
}

static void esp_spp_cb(esp_spp_cb_event_t event, esp_spp_cb_param_t *param)
{
    uint8_t i = 0;
    char bda_str[18] = {0};

    switch (event) {
    case ESP_SPP_INIT_EVT:
        if (param->init.status == ESP_SPP_SUCCESS) {
            ESP_LOGI(SPP_TAG, "ESP_SPP_INIT_EVT");
            esp_bt_dev_set_device_name(EXAMPLE_DEVICE_NAME);
            esp_bt_gap_set_scan_mode(ESP_BT_CONNECTABLE, ESP_BT_GENERAL_DISCOVERABLE);
            esp_bt_gap_start_discovery(inq_mode, inq_len, inq_num_rsps);
        } else {
            ESP_LOGE(SPP_TAG, "ESP_SPP_INIT_EVT status:%d", param->init.status);
        }
        break;
    case ESP_SPP_DISCOVERY_COMP_EVT:
        if (param->disc_comp.status == ESP_SPP_SUCCESS) {
            ESP_LOGI(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT scn_num:%d", param->disc_comp.scn_num);
            for (i = 0; i < param->disc_comp.scn_num; i++) {
                ESP_LOGI(SPP_TAG, "-- [%d] scn:%d service_name:%s", i, param->disc_comp.scn[i],
                         param->disc_comp.service_name[i]);
            }
            /* We only connect to the first found server on the remote SPP acceptor here */
            esp_spp_connect(sec_mask, role_master, param->disc_comp.scn[0], peer_bd_addr);
        } else {
            ESP_LOGE(SPP_TAG, "ESP_SPP_DISCOVERY_COMP_EVT status=%d", param->disc_comp.status);
        }
        break;
    case ESP_SPP_OPEN_EVT:
        if (param->open.status == ESP_SPP_SUCCESS) {
            ESP_LOGI(SPP_TAG, "ESP_SPP_OPEN_EVT handle:%d rem_bda:[%s]", param->open.handle,
                     bda2str(param->open.rem_bda, bda_str, sizeof(bda_str)));
            /* Start to write the first data packet */
            esp_spp_write(param->open.handle, SPP_DATA_LEN, spp_data);
            s_p_data = spp_data;
            gettimeofday(&time_old, NULL);
        } else {
            ESP_LOGE(SPP_TAG, "ESP_SPP_OPEN_EVT status:%d", param->open.status);
        }
        break;
    case ESP_SPP_CLOSE_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_CLOSE_EVT status:%d handle:%d close_by_remote:%d", param->close.status,
                 param->close.handle, param->close.async);
        break;
    case ESP_SPP_START_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_START_EVT");
        break;
    case ESP_SPP_CL_INIT_EVT:
        if (param->cl_init.status == ESP_SPP_SUCCESS) {
            ESP_LOGI(SPP_TAG, "ESP_SPP_CL_INIT_EVT handle:%d sec_id:%d", param->cl_init.handle, param->cl_init.sec_id);
        } else {
            ESP_LOGE(SPP_TAG, "ESP_SPP_CL_INIT_EVT status:%d", param->cl_init.status);
        }
        break;
    case ESP_SPP_DATA_IND_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_DATA_IND_EVT");
        break;
    case ESP_SPP_WRITE_EVT:
        if (param->write.status == ESP_SPP_SUCCESS) {
            if (s_p_data + param->write.len == spp_data + SPP_DATA_LEN) {
                /* Means the previous data packet be sent completely, send a new data packet */
                s_p_data = spp_data;
            } else {
                /*
                 * Means the previous data packet only be sent partially due to the lower layer congestion, resend the
                 * remainning data.
                 */
                s_p_data += param->write.len;
            }
#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
            /*
             * We only show the data in which the data length is less than 128 here. If you want to print the data and
             * the data rate is high, it is strongly recommended to process them in other lower priority application task
             * rather than in this callback directly. Since the printing takes too much time, it may stuck the Bluetooth
             * stack and also have a effect on the throughput!
             */
            ESP_LOGI(SPP_TAG, "ESP_SPP_WRITE_EVT len:%d handle:%d cong:%d", param->write.len, param->write.handle,
                     param->write.cong);
            if (param->write.len < 128) {
                esp_log_buffer_hex("", spp_data, param->write.len);
                /* Delay a little to avoid the task watch dog */
                vTaskDelay(pdMS_TO_TICKS(10));
            }
#else
            gettimeofday(&time_new, NULL);
            data_num += param->write.len;
            if (time_new.tv_sec - time_old.tv_sec >= 3) {
                print_speed();
            }
#endif
        } else {
            /* Means the prevous data packet is not sent at all, need to send the whole data packet again. */
            ESP_LOGE(SPP_TAG, "ESP_SPP_WRITE_EVT status:%d", param->write.status);
        }

        if (!param->write.cong) {
            /* The lower layer is not congested, you can send the next data packet now. */
            esp_spp_write(param->write.handle, spp_data + SPP_DATA_LEN - s_p_data, s_p_data);
        } else {
            /*
             * The lower layer is congested now, don't send the next data packet until receiving the
             * ESP_SPP_CONG_EVT with param->cong.cong == 0.
             */
            ;
        }

        /*
         * If you don't want to manage this complicated process, we also provide the SPP VFS mode that hides the
         * implementation details. However, it is less efficient and will block the caller until all data has been sent.
         */
        break;
    case ESP_SPP_CONG_EVT:
#if (SPP_SHOW_MODE == SPP_SHOW_DATA)
        ESP_LOGI(SPP_TAG, "ESP_SPP_CONG_EVT cong:%d", param->cong.cong);
#endif
        if (param->cong.cong == 0) {
            /* Send the privous (partial) data packet or the next data packet. */
            esp_spp_write(param->write.handle, spp_data + SPP_DATA_LEN - s_p_data, s_p_data);
        }
        break;
    case ESP_SPP_SRV_OPEN_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_SRV_OPEN_EVT");
        break;
    case ESP_SPP_UNINIT_EVT:
        ESP_LOGI(SPP_TAG, "ESP_SPP_UNINIT_EVT");
        break;
    default:
        break;
    }
}

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_DISC_RES_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_RES_EVT");
        esp_log_buffer_hex(SPP_TAG, param->disc_res.bda, ESP_BD_ADDR_LEN);
        /* Find the target peer device name in the EIR data */
        for (int i = 0; i < param->disc_res.num_prop; i++){
            if (param->disc_res.prop[i].type == ESP_BT_GAP_DEV_PROP_EIR
                && get_name_from_eir(param->disc_res.prop[i].val, peer_bdname, &peer_bdname_len)){
                esp_log_buffer_char(SPP_TAG, peer_bdname, peer_bdname_len);
                if (strlen(remote_device_name) == peer_bdname_len
                    && strncmp(peer_bdname, remote_device_name, peer_bdname_len) == 0) {
                    memcpy(peer_bd_addr, param->disc_res.bda, ESP_BD_ADDR_LEN);
                    /* Have found the target peer device, cancel the previous GAP discover procedure. And go on
                     * dsicovering the SPP service on the peer device */
                    esp_bt_gap_cancel_discovery();
                    esp_spp_start_discovery(peer_bd_addr);
                }
            }
        }
        break;
    case ESP_BT_GAP_DISC_STATE_CHANGED_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_DISC_STATE_CHANGED_EVT");
        break;
    case ESP_BT_GAP_RMT_SRVCS_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_RMT_SRVCS_EVT");
        break;
    case ESP_BT_GAP_RMT_SRVC_REC_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_RMT_SRVC_REC_EVT");
        break;
    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_LOGE(SPP_TAG, "authentication failed, status:%d", param->auth_cmpl.stat);
        }
        break;
    }
    case ESP_BT_GAP_PIN_REQ_EVT:{
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_PIN_REQ_EVT min_16_digit:%d", param->pin_req.min_16_digit);
        if (param->pin_req.min_16_digit) {
            ESP_LOGI(SPP_TAG, "Input pin code: 0000 0000 0000 0000");
            esp_bt_pin_code_t pin_code = {0};
            esp_bt_gap_pin_reply(param->pin_req.bda, true, 16, pin_code);
        } else {
            ESP_LOGI(SPP_TAG, "Input pin code: 1234");
            esp_bt_pin_code_t pin_code;
            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);
        }
        break;
    }

#if (CONFIG_BT_SSP_ENABLED == true)
    case ESP_BT_GAP_CFM_REQ_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_CFM_REQ_EVT Please compare the numeric value: %d", param->cfm_req.num_val);
        ESP_LOGW(SPP_TAG, "To confirm the value, type `spp ok;`");
        break;
    case ESP_BT_GAP_KEY_NOTIF_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_NOTIF_EVT passkey:%d", param->key_notif.passkey);
        ESP_LOGW(SPP_TAG, "Waiting responce...");
        break;
    case ESP_BT_GAP_KEY_REQ_EVT:
        ESP_LOGI(SPP_TAG, "ESP_BT_GAP_KEY_REQ_EVT Please enter passkey!");
        ESP_LOGW(SPP_TAG, "To input the key, type `spp key xxxxxx;`");
        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);
        break;

    default:
        break;
    }
}

void app_main(void)
{
    esp_err_t ret = ESP_OK;
    char bda_str[18] = {0};

    for (int i = 0; i < SPP_DATA_LEN; ++i) {
        spp_data[i] = i;
    }

    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 );

    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) {
        ESP_LOGE(SPP_TAG, "%s initialize bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    if ((ret = esp_bluedroid_enable()) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s enable bluedroid failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    if ((ret = esp_bt_gap_register_callback(esp_bt_gap_cb)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s gap register failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

#if (CONFIG_BT_SSP_ENABLED == true)
    /* Set default parameters for Secure Simple Pairing */
    esp_bt_sp_param_t param_type = ESP_BT_SP_IOCAP_MODE;
    esp_bt_io_cap_t iocap = ESP_BT_IO_CAP_IN;
    esp_bt_gap_set_security_param(param_type, &iocap, sizeof(uint8_t));
    if (iocap == ESP_BT_IO_CAP_IN || iocap == ESP_BT_IO_CAP_IO) {
        console_uart_init();
        vTaskDelay(pdMS_TO_TICKS(500));
    }
#endif

    if ((ret = esp_spp_register_callback(esp_spp_cb)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s spp register failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    esp_spp_cfg_t bt_spp_cfg = {
        .mode = esp_spp_mode,
        .enable_l2cap_ertm = esp_spp_enable_l2cap_ertm,
        .tx_buffer_size = 0, /* Only used for ESP_SPP_MODE_VFS mode */
    };
    if ((ret = esp_spp_enhanced_init(&bt_spp_cfg)) != ESP_OK) {
        ESP_LOGE(SPP_TAG, "%s spp init failed: %s\n", __func__, esp_err_to_name(ret));
        return;
    }

    /*
     * Set default parameters for Legacy Pairing
     * Use variable pin, input pin code when pairing
     */
    esp_bt_pin_type_t pin_type = ESP_BT_PIN_TYPE_VARIABLE;
    esp_bt_pin_code_t pin_code;
    esp_bt_gap_set_pin(pin_type, 0, pin_code);

    ESP_LOGI(SPP_TAG, "Own address:[%s]", bda2str((uint8_t *)esp_bt_dev_get_address(), bda_str, sizeof(bda_str)));
}

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SPP(Serial Port Profile)是蓝牙技术中的一个基本功能,它允许通过蓝牙无线连接实现串口通信。在嵌入式开发中,SPP蓝牙模块常用于实现低功耗、短距离的数据传输。 SPP蓝牙嵌入式开发需要以下几个步骤: 1. 硬件选型:选择适合项目需求的嵌入式蓝牙模块,一般具有UART接口,并支持SPP蓝牙协议。 2. 开发环境搭建:安装并配置嵌入式开发环境,如Keil、IAR等。同时,需要了解蓝牙相关的协议和规范。 3. 硬件连接:将蓝牙模块与目标设备进行连接,通常是通过UART接口进行连接。 4. 软件开发:根据项目需求编写相关的嵌入式软件程序。这些程序包括与蓝牙模块的通信协议、数据处理、错误处理等。 5. 蓝牙配置:配置蓝牙模块的参数,包括设备名称、使能SPP功能、通信波特率等。 6. 测试与调试:在开发过程中,需要进行一系列测试与调试工作,以确保蓝牙通信的正常运行。可以使用蓝牙终端或手机等设备进行测试。 7. 产品部署:完成开发和测试后,将嵌入式设备搭配蓝牙模块进行部署。 总之,SPP蓝牙嵌入式开发是一项基于蓝牙技术的项目开发工作,它能够实现无线数据传输,方便实现嵌入式设备与蓝牙终端的通信。在开发过程中,我们需要选择合适的硬件、搭建开发环境、编写嵌入式软件程序以及进行各种测试与调试工作,最后完成产品的部署。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值