esp32 ble gatt server创建多个Characteristic

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_system.h"
#include "esp_log.h"
#include "nvs_flash.h"
#include "esp_bt.h"

#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bt_defs.h"
#include "esp_bt_main.h"
#include "esp_gatt_common_api.h"

#include "sdkconfig.h"
#define  GATTS_TAG "qqqq"

#define GATTS_TABLE_TAG "GATTS_TABLE_DEMO"
#define PROFILE_NUM                 1
#define PROFILE_APP_IDX             0
#define ESP_APP_ID                  0x56
#define SAMPLE_DEVICE_NAME          "ESP_GATTS_DEMO"
#define SVC_INST_ID                 0

static uint8_t adv_config_done       = 0;

#define GATTS_DEMO_CHAR_VAL_LEN_MAX 500
#define PREPARE_BUF_MAX_SIZE        1024
#define CHAR_DECLARATION_SIZE       (sizeof(uint8_t))
#define ADV_CONFIG_FLAG             (1 << 0)
#define SCAN_RSP_CONFIG_FLAG        (1 << 1)

static uint8_t service_uuid[16] = {
    /* LSB <--------------------------------------------------------------------------------> MSB */
    //first uuid, 16bit, [12],[13] is the value
    0xfa, 0x39, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0xdd, 0xaa,
};


static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t p_gatts_if, esp_ble_gatts_cb_param_t *param);

/* Attributes State Machine */
enum
{
    IDX_SVC,
    IDX_CHAR_A,
    IDX_CHAR_VAL_A,
    IDX_CHAR_CFG_A,

    IDX_CHAR_B,
    IDX_CHAR_VAL_B,

    IDX_CHAR_C,
    IDX_CHAR_VAL_C,

	IDX_CHAR_D,
	IDX_CHAR_VAL_D,

    HRS_IDX_NB,
};


uint16_t heart_rate_handle_table[HRS_IDX_NB];


static esp_ble_adv_params_t adv_params = {
    .adv_int_min         = 0x20,
    .adv_int_max         = 0x40,
    .adv_type            = ADV_TYPE_IND,
    .own_addr_type       = BLE_ADDR_TYPE_PUBLIC,
    .channel_map         = ADV_CHNL_ALL,
    .adv_filter_policy   = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};


struct gatts_profile_inst {
    esp_gatts_cb_t gatts_cb;
    uint16_t gatts_if;
    uint16_t app_id;
    uint16_t conn_id;
    uint16_t service_handle;
    esp_gatt_srvc_id_t service_id;
    uint16_t char_handle;
    esp_bt_uuid_t char_uuid;
    esp_gatt_perm_t perm;
    esp_gatt_char_prop_t property;
    uint16_t descr_handle;
    esp_bt_uuid_t descr_uuid;
};

/* The length of adv data must be less than 31 bytes */
static esp_ble_adv_data_t adv_data = {
    .set_scan_rsp        = false,
    .include_name        = true,
    .include_txpower     = true,
    .min_interval        = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
    .max_interval        = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
    .appearance          = 0x00,
    .manufacturer_len    = 0,    //TEST_MANUFACTURER_DATA_LEN,
    .p_manufacturer_data = NULL, //test_manufacturer,
    .service_data_len    = 0,
    .p_service_data      = NULL,
    .service_uuid_len    = sizeof(service_uuid),
    .p_service_uuid      = service_uuid,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};


// scan response data
static esp_ble_adv_data_t scan_rsp_data = {
    .set_scan_rsp        = true,
    .include_name        = true,
    .include_txpower     = true,
    .min_interval        = 0x0006,
    .max_interval        = 0x0010,
    .appearance          = 0x00,
    .manufacturer_len    = 0, //TEST_MANUFACTURER_DATA_LEN,
    .p_manufacturer_data = NULL, //&test_manufacturer[0],
    .service_data_len    = 0,
    .p_service_data      = NULL,
    .service_uuid_len    = sizeof(service_uuid),
    .p_service_uuid      = service_uuid,
    .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
};

static void gatts_profile_event_handler(esp_gatts_cb_event_t event,
					esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);


/* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
static struct gatts_profile_inst heart_rate_profile_tab[PROFILE_NUM] = {
    [PROFILE_APP_IDX] = {
        .gatts_cb = gatts_profile_event_handler,
        .gatts_if = ESP_GATT_IF_NONE,       /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
    },
};



/* Service */
static const uint16_t GATTS_SERVICE_UUID_TEST      = 0x00FF;
static const uint16_t GATTS_CHAR_UUID_TEST_A       = 0xFF01;
static const uint16_t GATTS_CHAR_UUID_TEST_B       = 0xFF02;
static const uint16_t GATTS_CHAR_UUID_TEST_C       = 0xFF03;
static const uint16_t GATTS_CHAR_UUID_TEST_D       = 0xFF09;

static const uint16_t primary_service_uuid         = ESP_GATT_UUID_PRI_SERVICE;
static const uint16_t character_declaration_uuid   = ESP_GATT_UUID_CHAR_DECLARE;
static const uint16_t character_client_config_uuid = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
static const uint8_t char_prop_read                =  ESP_GATT_CHAR_PROP_BIT_READ;
static const uint8_t char_prop_write               = ESP_GATT_CHAR_PROP_BIT_WRITE;
static const uint8_t char_prop_read_write_notify   = ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
static const uint8_t heart_measurement_ccc[2]      = {0x00, 0x00};

static const uint8_t char_value[4]                 = {0x11, 0x22, 0x33, 0x44};
static const uint8_t char_value_d[5]                 = {0xa0, 0x22, 0x33, 0x78,0x71};


/* Full Database Description - Used to add attributes into the database */
static const esp_gatts_attr_db_t gatt_db[HRS_IDX_NB] =
{
    // Service Declaration
    [IDX_SVC]        =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&primary_service_uuid, ESP_GATT_PERM_READ,
      sizeof(uint16_t), sizeof(GATTS_SERVICE_UUID_TEST), (uint8_t *)&GATTS_SERVICE_UUID_TEST}},

    /* Characteristic Declaration */
    [IDX_CHAR_A]     =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write_notify}},

    /* Characteristic Value */
    [IDX_CHAR_VAL_A] =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_A, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},

    /* Client Characteristic Configuration Descriptor */
    [IDX_CHAR_CFG_A]  =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_client_config_uuid, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      sizeof(uint16_t), sizeof(heart_measurement_ccc), (uint8_t *)heart_measurement_ccc}},

    /* Characteristic Declaration */
    [IDX_CHAR_B]      =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read}},

    /* Characteristic Value */
    [IDX_CHAR_VAL_B]  =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_B, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},

    /* Characteristic Declaration */
    [IDX_CHAR_C]      =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
      CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_write}},

    /* Characteristic Value */
    [IDX_CHAR_VAL_C]  =
    {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_C, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
      GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value), (uint8_t *)char_value}},

	  /* Characteristic Declaration */
	     [IDX_CHAR_D]      =
	     {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&character_declaration_uuid, ESP_GATT_PERM_READ,
	       CHAR_DECLARATION_SIZE, CHAR_DECLARATION_SIZE, (uint8_t *)&char_prop_read_write_notify}},

	     /* Characteristic Value */
	     [IDX_CHAR_VAL_D]  =
	     {{ESP_GATT_AUTO_RSP}, {ESP_UUID_LEN_16, (uint8_t *)&GATTS_CHAR_UUID_TEST_D, ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
	       GATTS_DEMO_CHAR_VAL_LEN_MAX, sizeof(char_value_d), (uint8_t *)char_value_d}},

};

static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
{
	switch (event) {
	 case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
	            adv_config_done &= (~ADV_CONFIG_FLAG);
	            if (adv_config_done == 0){
	                esp_ble_gap_start_advertising(&adv_params);
	            }
	            break;
	        case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
	            adv_config_done &= (~SCAN_RSP_CONFIG_FLAG);
	            if (adv_config_done == 0){
	                esp_ble_gap_start_advertising(&adv_params);
	            }
	            break;
default:
break;

	}
}

static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
    /* If event is register event, store the gatts_if for each profile */
    if (event == ESP_GATTS_REG_EVT) {
        if (param->reg.status == ESP_GATT_OK) {
            heart_rate_profile_tab[PROFILE_APP_IDX].gatts_if = gatts_if;
        } else {
            ESP_LOGE(GATTS_TABLE_TAG, "reg app failed, app_id %04x, status %d",
                    param->reg.app_id,
                    param->reg.status);
            return;
        }
    }
    do {
        int idx;
        for (idx = 0; idx < PROFILE_NUM; idx++) {
            /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
            if (gatts_if == ESP_GATT_IF_NONE || gatts_if == heart_rate_profile_tab[idx].gatts_if) {
                if (heart_rate_profile_tab[idx].gatts_cb) {
                    heart_rate_profile_tab[idx].gatts_cb(event, gatts_if, param);
                }
            }
        }
    } while (0);
}

static void gatts_profile_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
{
	switch (event) {
	        case ESP_GATTS_REG_EVT:{
	            esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(SAMPLE_DEVICE_NAME);
	            if (set_dev_name_ret){
	                ESP_LOGE(GATTS_TABLE_TAG, "set device name failed, error code = %x", set_dev_name_ret);
	            }
	            //config adv data
	            esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
	            if (ret){
	                ESP_LOGE(GATTS_TABLE_TAG, "config adv data failed, error code = %x", ret);
	            }
	            adv_config_done |= ADV_CONFIG_FLAG;
	            //config scan response data
	            ret = esp_ble_gap_config_adv_data(&scan_rsp_data);
	            if (ret){
	                ESP_LOGE(GATTS_TABLE_TAG, "config scan response data failed, error code = %x", ret);
	            }
	            adv_config_done |= SCAN_RSP_CONFIG_FLAG;

	            esp_err_t create_attr_ret = esp_ble_gatts_create_attr_tab(gatt_db, gatts_if, HRS_IDX_NB, SVC_INST_ID);
	            if (create_attr_ret){
	                ESP_LOGE(GATTS_TABLE_TAG, "create attr table failed, error code = %x", create_attr_ret);
	            }
	        }
	       	    break;
	        case ESP_GATTS_CREAT_ATTR_TAB_EVT:{
	                   if (param->add_attr_tab.status != ESP_GATT_OK){
	                       ESP_LOGE(GATTS_TABLE_TAG, "create attribute table failed, error code=0x%x", param->add_attr_tab.status);
	                   }
	                   else if (param->add_attr_tab.num_handle != HRS_IDX_NB){
	                       ESP_LOGE(GATTS_TABLE_TAG, "create attribute table abnormally, num_handle (%d) \
	                               doesn't equal to HRS_IDX_NB(%d)", param->add_attr_tab.num_handle, HRS_IDX_NB);
	                   }
	                   else {
	                	   printf("create attribute table successfully, start_service\n");
	                       ESP_LOGI(GATTS_TABLE_TAG, "create attribute table successfully, the number handle = %d\n",param->add_attr_tab.num_handle);
	                       memcpy(heart_rate_handle_table, param->add_attr_tab.handles, sizeof(heart_rate_handle_table));
	                       esp_ble_gatts_start_service(heart_rate_handle_table[IDX_SVC]);
	                   }
	                   break;
	               }

	        case ESP_GATTS_START_EVT:
	        	printf("SERVICE_START_EVT, status %d, service_handle %d", param->start.status, param->start.service_handle);
	                  break;

	        case ESP_GATTS_DISCONNECT_EVT:
	                  ESP_LOGI(GATTS_TABLE_TAG, "ESP_GATTS_DISCONNECT_EVT, reason = 0x%x", param->disconnect.reason);
	                  esp_ble_gap_start_advertising(&adv_params);
	                  break;
	        default:
	        break;
	}
}

void app_main(void) {
	 esp_err_t ret;
	 nvs_flash_erase();
	    /* Initialize NVS. */
	    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_CLASSIC_BT));

	    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
	    ret = esp_bt_controller_init(&bt_cfg);
	    if (ret) {
	        ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
	        return;
	    }

	    ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
	    if (ret) {
	        ESP_LOGE(GATTS_TABLE_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
	        return;
	    }

	    ret = esp_bluedroid_init();
	    if (ret) {
	        ESP_LOGE(GATTS_TABLE_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
	        return;
	    }

	    ret = esp_bluedroid_enable();
	    if (ret) {
	        ESP_LOGE(GATTS_TABLE_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
	        return;
	    }

	    ret = esp_ble_gatts_register_callback(gatts_event_handler);
	    if (ret){
	        ESP_LOGE(GATTS_TABLE_TAG, "gatts register error, error code = %x", ret);
	        return;
	    }

	    ret = esp_ble_gap_register_callback(gap_event_handler);
	    if (ret){
	        ESP_LOGE(GATTS_TABLE_TAG, "gap register error, error code = %x", ret);
	        return;
	    }

	    ret = esp_ble_gatts_app_register(ESP_APP_ID);
	    if (ret){
	        ESP_LOGE(GATTS_TABLE_TAG, "gatts app register error, error code = %x", ret);
	        return;
	    }

}

ESP32-S3 BLE(蓝牙低功耗)模块是一种基于Wi-Fi和蓝牙双模的物联网开发板,常用于构建嵌入式设备。在ESP32-S3上通过BLE(Bluetooth Low Energy)功能发送数据通常涉及以下步骤: 1. **初始化模块**:首先,需要在程序中初始化ESP32-S3的蓝牙功能,包括配对模式的选择、适配器启动等。 ```cpp esp_err_t ble_err = esp_bluedroid_init(); if (ble_err != ESP_OK) { // 处理错误 } ``` 2. **创建服务和Characteristic**:为了传输数据,你需要在蓝牙中定义一个或多个服务,并在这些服务下创建Characteristics。比如,你可以创建一个包含数据的Characteristics,设置为通知模式以便接收者可以获取实时更新。 ```cpp esp_gatts_service_create_data_t service_data = {0}; esp_gatts_char_create_data_t char_data = {0}; esp_err_t result = esp_ble_gatts_new_service(&service_data); // ... 创建和服务描述符相关的操作 result = esp_ble_gatts_new_char(service_handle, &char_data); ``` 3. **设置通知**:将Characteristic设置为通知模式,当其值改变时,会主动推送给连接的设备。 ```cpp esp_gatt_notify_params_t notify_params; notify_params.notify_type = ESP_GATT_NOTIFY_TYPE_NO_RSP; result = esp_ble_gatts_set_notif_params(service_handle, char_handle, &notify_params); ``` 4. **发送数据**:当你准备好要发送的数据时,可以将其写入到Characteristic实例的值中。 ```cpp uint8_t data[] = {"Hello World"}; result = esp_ble_gatts_write_char_value(char_handle, strlen((const char*)data), data); ``` 5. **等待连接并发送**:设备需要先建立连接,然后才能接收数据。在`esp_event_loop_create_default()`的事件循环中,监听连接事件并发送数据。 ```cpp esp_err_t status = esp_bluedroid_start_advertising(&adv_config); // 广播配置 while (!conn成立) { esp_event_loop_run(); } // 连接成功后,发送数据 esp_gatt_send_notification(conn, char_handle, data, sizeof(data)); ```
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值