espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.53k stars 7.26k forks source link

[TW#12271] BLE indicate/notification issue #568

Closed Nicholas3388 closed 7 years ago

Nicholas3388 commented 7 years ago

Hi, is there a sample to show how to send and receive indicate/noitification between two ESP32 devices? I can send notification between ESP32 (sender) and iPhone (receiver). But I cannot receive notification between two ESP32.

xiewenxiang commented 7 years ago

@Nicholas3388 If you want receive notify or indicate from server:

  1. register for notification.
  2. write char description.

In step 1, call esp_ble_gattc_register_for_notify(gattc_if, server_bda, srvc_id, char_id)

/**
 * @brief           This function is called to register for notification of a service.
 *
 * @param[in]       gattc_if: Gatt client access interface.
 * @param[in]       server_bda : target GATT server.
 * @param[in]       srvc_id : pointer to GATT service ID.
 * @param[in]       char_id : pointer to GATT characteristic ID.
 *
 * @return
 *                  - ESP_OK: registration succeeds
 *                  - other: failed
 *
 */
esp_gatt_status_t esp_ble_gattc_register_for_notify (esp_gatt_if_t gattc_if,
                                                    esp_bd_addr_t server_bda,
                                                    esp_gatt_srvc_id_t *srvc_id,
                                                    esp_gatt_id_t *char_id);

after invoke this API, the event ESP_GATTC_REG_FOR_NOTIFY_EVT will come.

In step 2, write char descr, if the char prem is notify, write value 0x1, if the char prem is indicate, write value 0x2.

    case ESP_GATTC_REG_FOR_NOTIFY_EVT:
        esp_ble_gattc_write_char_descr(......)
        break;

/**
 * @brief           This function is called to write characteristic descriptor value.
 *
 * @param[in]       gattc_if: Gatt client access interface.
 * @param[in]       conn_id : connection ID
 * @param[in]       srvc_id : service ID.
 * @param[in]       char_id : characteristic ID.
 * @param[in]       descr_id : characteristic descriptor ID to write.
 * @param[in]       value_len: length of the value to be written.
 * @param[in]       value : the value to be written.
 * @param[in]       write_type : the type of attribute write operation.
 * @param[in]       auth_req : authentication request.
 *
 * @return
 *                  - ESP_OK: success
 *                  - other: failed
 *
 */
esp_err_t esp_ble_gattc_write_char_descr (esp_gatt_if_t gattc_if, 
                                        uint16_t conn_id,
                                        esp_gatt_srvc_id_t *srvc_id,
                                        esp_gatt_id_t *char_id,
                                        esp_gatt_id_t *descr_id,
                                        uint16_t value_len,
                                        uint8_t *value,
                                    esp_gatt_write_type_t write_type,
                                        esp_gatt_auth_req_t auth_req);

OK, you can receive notify or indicate now!

Nicholas3388 commented 7 years ago

@xiewenxiang Hi, thanks for you code. I follow your steps, on the client I register notify for char, say 0xFF01, and then write char descriptor (0x2902). For server, I use the esp-idf gatts_demo.

The server calls esp_ble_gatts_add_char to add char 0xFF01 (read|write|notify), and then calls esp_ble_gatts_add_char_descr to add the descriptor 0x2902. When char and desc is added, I create a task to send notification as following:

static void led_task(void *arg) { while (1) { vTaskDelay(3000 / portTICK_RATE_MS); esp_ble_gatts_send_indicate(client_if, client_conn, char_handle, notif_len, value, false); } }

The char_handle is the handle for char 0xFF01. Is there anything wrong with my steps? The ESP32 client cannot receive notification from the ESP32 server.

xiewenxiang commented 7 years ago

@Nicholas3388 Hi, Nicholas, I'd like to confirm the procedure for your operation:

  1. server: create service 、start service and start adv
  2. client connected to server
  3. client discover service esp_ble_gattc_search_service(gattc_if, conn_id, NULL) , in this step, If there is only one service on the server, Event case ESP_GATTC_SEARCH_RES_EVT: will come three times, the last one is the real service.
  4. client discover char esp_ble_gattc_get_characteristic(gatt_if, conn_id, &srvc_id, NULL) , in this step, event case ESP_GATTC_GET_CHAR_EVT: will come, you can find the descripton of this char, and find next char

    case ESP_GATTC_GET_CHAR_EVT:
        if (p_data->get_char.status != ESP_GATT_OK) {
            break;
        }
        char_id.inst_id = p_data->get_char.char_id.inst_id;
        char_id.uuid.len = p_data->get_char.char_id.uuid.len;
        if (char_id.uuid.len == ESP_UUID_LEN_16) {
            char_id.uuid.uuid.uuid16 = p_data->get_char.char_id.uuid.uuid.uuid16;
        } else if (char_id.uuid.len == ESP_UUID_LEN_32) {
            char_id.uuid.uuid.uuid32 = p_data->get_char.char_id.uuid.uuid.uuid32;
        } else if (char_id.uuid.len == ESP_UUID_LEN_128) {
            for (int i = 0; i < 16; i++) {
                char_id.uuid.uuid.uuid128[i] = p_data->get_char.char_id.uuid.uuid.uuid128[i];
            }
        }
        //TODO:
        esp_ble_gattc_get_descriptor(gatt_if, conn_id, &srvc_id, &char_id, NULL);
        break;
    case ESP_GATTC_GET_DESCR_EVT:
        if (p_data->get_descr.status != ESP_GATT_OK) {
            esp_ble_gattc_get_characteristic(gatt_if, conn_id, &srvc_id, &char_id);
            break;
        }
        descr_id.inst_id = p_data->get_descr.descr_id.inst_id;
        descr_id.uuid.len = p_data->get_descr.descr_id.uuid.len;
    
        if (descr_id.uuid.len == ESP_UUID_LEN_16) {
            descr_id.uuid.uuid.uuid16 = p_data->get_descr.descr_id.uuid.uuid.uuid16;
        } else if (descr_id.uuid.len == ESP_UUID_LEN_32) {
            descr_id.uuid.uuid.uuid32 = p_data->get_descr.descr_id.uuid.uuid.uuid32;
        } else if (descr_id.uuid.len == ESP_UUID_LEN_128) {
            for (int i = 0; i < 16; i++) {
                descr_id.uuid.uuid.uuid128[i] = p_data->get_descr.descr_id.uuid.uuid.uuid128[i];
            }
        }
        //TODO:
        esp_ble_gattc_get_descriptor(gatt_if, conn_id, &srvc_id, &char_id, &descr_id);
        break;
  5. Make sure that the parameters are correct esp_ble_gattc_register_for_notify(gattc_if, server_bda, srvc_id, char_id) esp_ble_gattc_write_char_descr(...)

If possible, please provide your code. Thanks

Nicholas3388 commented 7 years ago

@xiewenxiang Hi, the following code is client:

`#include

include

include

include

include "controller.h"

include "bt.h"

include "bt_trace.h"

include "bt_types.h"

include "btm_api.h"

include "bta_api.h"

include "bta_gatt_api.h"

include "esp_gap_ble_api.h"

include "esp_gattc_api.h"

include "esp_gatt_defs.h"

include "esp_bt_main.h"

include "driver/gpio.h"

include "freertos/FreeRTOS.h"

include "freertos/task.h"

define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"

define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]

define TEST_SRV_UUID 0x00FF

define TEST_CHAR_UUID 0xFF01

define LED_GPIO 2

static esp_gatt_if_t client_if; static uint16_t client_conn = 0; esp_gatt_status_t status = ESP_GATT_ERROR; bool connet = false; uint16_t simpleClient_id = 0xEE;

const char device_name[] = "ESP32"; static char tar_dev_mac[6] = {0xff, 0xb5, 0x30, 0x4e, 0x0a, 0xcb};

static esp_bd_addr_t server_dba; static bool is_led_on = false;

static esp_ble_scan_params_t ble_scan_params = { .scan_type = BLE_SCAN_TYPE_ACTIVE, .own_addr_type = ESP_PUBLIC_ADDR, .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, .scan_interval = 0x50, .scan_window = 0x30 };

static esp_gatt_srvc_id_t test_service_id = { .id = { .uuid = { .len = ESP_UUID_LEN_16, .uuid = {.uuid16 = TEST_SRV_UUID,}, }, .inst_id = 0, }, .is_primary = true, };

static esp_gatt_id_t test_char_id = { .uuid = { .len = ESP_UUID_LEN_16, .uuid = {.uuid16 = TEST_CHAR_UUID,}, }, .inst_id = 0, };

static esp_gatt_id_t notify_descr_id = { .uuid = { .len = ESP_UUID_LEN_16, .uuid = {.uuid16 = GATT_UUID_CHAR_CLIENT_CONFIG,}, }, .inst_id = 0, };

static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t param); static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t param);

static void get_characteristic_property(uint32_t flag) { int i; ESP_LOGI(TAG, "======================================="); for (i = 0; i < 8; i ++) { switch (flag & (2 << i)) { case ESP_GATT_CHAR_PROP_BIT_BROADCAST: ESP_LOGI(TAG, "==> CHAR PROP ESP_GATT_CHAR_PROP_BIT_BROADCAST"); break; case ESP_GATT_CHAR_PROP_BIT_READ: ESP_LOGI(TAG, "==> CHAR PROP ESP_GATT_CHAR_PROP_BIT_READ"); break; case ESP_GATT_CHAR_PROP_BIT_WRITE_NR: ESP_LOGI(TAG, "==> CHAR PROP ESP_GATT_CHAR_PROP_BIT_WRITE_NR"); break; case ESP_GATT_CHAR_PROP_BIT_WRITE: ESP_LOGI(TAG, "==> CHAR PROP ESP_GATT_CHAR_PROP_BIT_WRITE"); break; case ESP_GATT_CHAR_PROP_BIT_NOTIFY: ESP_LOGI(TAG, "==> CHAR PROP ESP_GATT_CHAR_PROP_BIT_NOTIFY"); break; case ESP_GATT_CHAR_PROP_BIT_INDICATE: ESP_LOGI(TAG, "==> CHAR PROP ESP_GATT_CHAR_PROP_BIT_INDICATE"); break; case ESP_GATT_CHAR_PROP_BIT_AUTH: ESP_LOGI(TAG, "==> CHAR PROP ESP_GATT_CHAR_PROP_BIT_AUTH"); break; case ESP_GATT_CHAR_PROP_BIT_EXT_PROP: ESP_LOGI(TAG, "==> CHAR PROP ESP_GATT_CHAR_PROP_BIT_EXT_PROP"); break; default: break; } } ESP_LOGI(TAG, "======================================="); }

static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t param) { uint8_t adv_name = NULL; uint8_t adv_name_len = 0; switch (event) { case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { //the unit of the duration is second uint32_t duration = 10; esp_ble_gap_start_scanning(duration); break; } case ESP_GAP_BLE_SCAN_RESULT_EVT: { esp_ble_gap_cb_param_t scan_result = (esp_ble_gap_cb_param_t )param; switch (scan_result->scan_rst.search_evt) { case ESP_GAP_SEARCH_INQ_RES_EVT: switch (scan_result->scan_rst.dev_type) { case ESP_BT_DEVICE_TYPE_BREDR: ESP_LOGI(TAG, "==> Connected Device type BREDR"); break; case ESP_BT_DEVICE_TYPE_BLE: ESP_LOGI(TAG, "==> Connected Device type BLE"); break; case ESP_BT_DEVICE_TYPE_DUMO: ESP_LOGI(TAG, "==> Connected Device type DUMO"); break; default: break; } LOG_INFO("BDA %x,%x,%x,%x,%x,%x:",scan_result->scan_rst.bda[0], scan_result->scan_rst.bda[1],scan_result->scan_rst.bda[2], scan_result->scan_rst.bda[3],scan_result->scan_rst.bda[4], scan_result->scan_rst.bda[5]); for (int i = 0; i < 6; i++) { server_dba[i]=scan_result->scan_rst.bda[i]; } adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); LOG_INFO("adv_name_len=%x\n", adv_name_len);`

        `if (strncmp((char *)adv_name, device_name,adv_name_len) == 0 && connet == false) {
            connet = true;
            ESP_LOGI(TAG, "==> address type: %d, dev name: %s", scan_result->scan_rst.ble_addr_type, adv_name);
            LOG_INFO("Connect to the remote device.");
            esp_ble_gap_stop_scanning();
            esp_ble_gattc_open(client_if, scan_result->scan_rst.bda, true);
            memcpy(tar_dev_mac, scan_result->scan_rst.bda, 6);
        }
        break;
    case ESP_GAP_SEARCH_INQ_CMPL_EVT:
        //esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
        switch (scan_result->scan_rst.ble_evt_type) {
             case ESP_BLE_EVT_CONN_ADV:
                 ESP_LOGI(TAG, "==> CONN_ADV");
                 ESP_LOGI(TAG, "BDA %x,%x,%x,%x,%x,%x:",scan_result->scan_rst.bda[0],
                             scan_result->scan_rst.bda[1],scan_result->scan_rst.bda[2],
                                             scan_result->scan_rst.bda[3],scan_result->scan_rst.bda[4],
                                             scan_result->scan_rst.bda[5]);
                 ESP_LOGI(TAG, "==> RSSI: %d", scan_result->scan_rst.rssi);
                 ESP_LOGI(TAG, "==> address type: %d", scan_result->scan_rst.ble_addr_type);
                 break;
             case ESP_BLE_EVT_CONN_DIR_ADV:
                 ESP_LOGI(TAG, "==> CONN_DIR_ADV");
                 break;
             case ESP_BLE_EVT_DISC_ADV:
                 ESP_LOGI(TAG, "==> DISC_ADV");
                 break;
             case ESP_BLE_EVT_NON_CONN_ADV:
                 ESP_LOGI(TAG, "==> NON_CONN_ADV");
                 break;
             case ESP_BLE_EVT_SCAN_RSP:
                 ESP_LOGI(TAG, "==> receive scan response");
                 LOG_INFO("BDA %x,%x,%x,%x,%x,%x:",scan_result->scan_rst.bda[0],
                             scan_result->scan_rst.bda[1],scan_result->scan_rst.bda[2],
                                             scan_result->scan_rst.bda[3],scan_result->scan_rst.bda[4],
                                             scan_result->scan_rst.bda[5]);
                 break;
        }
        break;
    default:
        break;
    }
    break;
}
default:
    break;
}

}

static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t param) { uint16_t conn_id = 0; esp_ble_gattc_cb_param_t p_data = (esp_ble_gattc_cb_param_t *)param;

LOG_INFO("esp_gattc_cb, event = %x", event);
switch (event) {
case ESP_GATTC_REG_EVT:
    status = p_data->reg.status;
    LOG_INFO("ESP_GATTC_REG_EVT status = %x, client_if = %x", status, gattc_if);
if (status == ESP_GATT_OK) {
    client_if = gattc_if;
} else {
    LOG_INFO("ESP_GATTC_REG failed!");
}
    break;
case ESP_GATTC_OPEN_EVT:
    conn_id = p_data->open.conn_id;
    LOG_INFO("ESP_GATTC_OPEN_EVT conn_id %d, if %d, status %d", conn_id, gattc_if, p_data->open.status);
    if (p_data->open.status != 0) {
        LOG_INFO("==> open GATTC error, closed");
        esp_ble_gattc_close(gattc_if, conn_id);
        esp_ble_gattc_open(gattc_if, (uint8_t *)tar_dev_mac, true);
        break;
    }
    esp_ble_gattc_search_service(gattc_if, conn_id, NULL);
    client_conn = conn_id;
    break;
case ESP_GATTC_CLOSE_EVT:
    LOG_INFO("==> GATTC closed");
    esp_ble_gattc_open(client_if, (uint8_t *)tar_dev_mac, true);
    client_conn = 0;
break;
case ESP_GATTC_READ_CHAR_EVT: {
    // esp_gatt_srvc_id_t *srvc_id = &p_data->read.srvc_id;
    esp_gatt_id_t *char_id = &p_data->read.char_id;
    conn_id = p_data->open.conn_id;
    LOG_INFO("READ CHAR: open.conn_id = %x search_res.conn_id = %x  read.conn_id = %x", conn_id,p_data->search_res.conn_id,p_data->read.conn_id);
    LOG_INFO("READ CHAR: read.status = %x inst_id = %x", p_data->read.status, char_id->inst_id);
    if (p_data->read.status==0) {
        if (char_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("Char UUID16: %x", char_id->uuid.uuid.uuid16);
        } else if (char_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("Char UUID32: %x", char_id->uuid.uuid.uuid32);
        } else if (char_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("Char UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_id->uuid.uuid.uuid128[0],
                     char_id->uuid.uuid.uuid128[1], char_id->uuid.uuid.uuid128[2], char_id->uuid.uuid.uuid128[3],
                     char_id->uuid.uuid.uuid128[4], char_id->uuid.uuid.uuid128[5], char_id->uuid.uuid.uuid128[6],
                     char_id->uuid.uuid.uuid128[7], char_id->uuid.uuid.uuid128[8], char_id->uuid.uuid.uuid128[9],
                     char_id->uuid.uuid.uuid128[10], char_id->uuid.uuid.uuid128[11], char_id->uuid.uuid.uuid128[12],
                     char_id->uuid.uuid.uuid128[13], char_id->uuid.uuid.uuid128[14], char_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("Char UNKNOWN LEN %d\n", char_id->uuid.len);
        }
        for (int i = 0; i < p_data->read.value_len; i++) {
            LOG_INFO("%x:", p_data->read.value[i]);
        }
    }
    break;
}
case ESP_GATTC_WRITE_CHAR_EVT: {
    // esp_gatt_srvc_id_t *srvc_id = &p_data->write.srvc_id;
    esp_gatt_id_t *char_id = &p_data->write.char_id;
    esp_gatt_id_t *descr_id = &p_data->write.descr_id;
    conn_id = p_data->open.conn_id;
    LOG_INFO("WRITE CHAR: open.conn_id = %x search_res.conn_id = %x  write.conn_id = %x", conn_id,p_data->search_res.conn_id,p_data->write.conn_id);
    LOG_INFO("WRITE CHAR: write.status = %x inst_id = %x", p_data->write.status, char_id->inst_id);
    if (p_data->write.status==0) {
        if (char_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("Char UUID16: %x", char_id->uuid.uuid.uuid16);
        } else if (char_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("Char UUID32: %x", char_id->uuid.uuid.uuid32);
        } else if (char_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("Char UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_id->uuid.uuid.uuid128[0],
                     char_id->uuid.uuid.uuid128[1], char_id->uuid.uuid.uuid128[2], char_id->uuid.uuid.uuid128[3],
                     char_id->uuid.uuid.uuid128[4], char_id->uuid.uuid.uuid128[5], char_id->uuid.uuid.uuid128[6],
                     char_id->uuid.uuid.uuid128[7], char_id->uuid.uuid.uuid128[8], char_id->uuid.uuid.uuid128[9],
                     char_id->uuid.uuid.uuid128[10], char_id->uuid.uuid.uuid128[11], char_id->uuid.uuid.uuid128[12],
                     char_id->uuid.uuid.uuid128[13], char_id->uuid.uuid.uuid128[14], char_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("Char UNKNOWN LEN %d", char_id->uuid.len);
        }
        if (descr_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("Decr UUID16: %x", descr_id->uuid.uuid.uuid16);
        } else if (descr_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("Decr UUID32: %x", descr_id->uuid.uuid.uuid32);
        } else if (descr_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("Decr UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", descr_id->uuid.uuid.uuid128[0],
                     descr_id->uuid.uuid.uuid128[1], descr_id->uuid.uuid.uuid128[2], descr_id->uuid.uuid.uuid128[3],
                     descr_id->uuid.uuid.uuid128[4], descr_id->uuid.uuid.uuid128[5], descr_id->uuid.uuid.uuid128[6],
                     descr_id->uuid.uuid.uuid128[7], descr_id->uuid.uuid.uuid128[8], descr_id->uuid.uuid.uuid128[9],
                     descr_id->uuid.uuid.uuid128[10], descr_id->uuid.uuid.uuid128[11], descr_id->uuid.uuid.uuid128[12],
                     descr_id->uuid.uuid.uuid128[13], descr_id->uuid.uuid.uuid128[14], descr_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("Decr UNKNOWN LEN %d", descr_id->uuid.len);
        }
    }
    break;
}
case ESP_GATTC_SEARCH_RES_EVT: {
    esp_gatt_srvc_id_t *srvc_id = &p_data->search_res.srvc_id;
    conn_id = p_data->open.conn_id;
    LOG_INFO("SEARCH RES: open.conn_id = %x search_res.conn_id = %x", conn_id,p_data->search_res.conn_id);
    if (srvc_id->id.uuid.len == ESP_UUID_LEN_16) {
        LOG_INFO("UUID16: %x", srvc_id->id.uuid.uuid.uuid16);
    } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_32) {
        LOG_INFO("UUID32: %x", srvc_id->id.uuid.uuid.uuid32);
    } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_128) {
        LOG_INFO("UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", srvc_id->id.uuid.uuid.uuid128[0],
                 srvc_id->id.uuid.uuid.uuid128[1], srvc_id->id.uuid.uuid.uuid128[2], srvc_id->id.uuid.uuid.uuid128[3],
                 srvc_id->id.uuid.uuid.uuid128[4], srvc_id->id.uuid.uuid.uuid128[5], srvc_id->id.uuid.uuid.uuid128[6],
                 srvc_id->id.uuid.uuid.uuid128[7], srvc_id->id.uuid.uuid.uuid128[8], srvc_id->id.uuid.uuid.uuid128[9],
                 srvc_id->id.uuid.uuid.uuid128[10], srvc_id->id.uuid.uuid.uuid128[11], srvc_id->id.uuid.uuid.uuid128[12],
                 srvc_id->id.uuid.uuid.uuid128[13], srvc_id->id.uuid.uuid.uuid128[14], srvc_id->id.uuid.uuid.uuid128[15]);
    } else {
        LOG_ERROR("UNKNOWN LEN %d", srvc_id->id.uuid.len);
    }
    esp_ble_gattc_get_characteristic(gattc_if, p_data->search_res.conn_id, srvc_id, NULL);
    break;
}
case ESP_GATTC_WRITE_DESCR_EVT: {
    esp_gatt_srvc_id_t *srvc_id = &p_data->write.srvc_id;
    esp_gatt_id_t *char_id = &p_data->write.char_id;
    esp_gatt_id_t *descr_id = &p_data->write.descr_id;
    conn_id = p_data->open.conn_id;
    LOG_INFO("WRITE DESCR: open.conn_id = %x search_res.conn_id = %x  write.conn_id = %x", conn_id,p_data->search_res.conn_id,p_data->write.conn_id);
    LOG_INFO("WRITE DESCR: write.status = %x inst_id = %x open.gatt_if = %x", p_data->write.status, char_id->inst_id,gattc_if);
    if (p_data->write.status==0) {
        if (char_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("Char UUID16: %x", char_id->uuid.uuid.uuid16);
        } else if (char_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("Char UUID32: %x", char_id->uuid.uuid.uuid32);
        } else if (char_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("Char UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_id->uuid.uuid.uuid128[0],
                     char_id->uuid.uuid.uuid128[1], char_id->uuid.uuid.uuid128[2], char_id->uuid.uuid.uuid128[3],
                     char_id->uuid.uuid.uuid128[4], char_id->uuid.uuid.uuid128[5], char_id->uuid.uuid.uuid128[6],
                     char_id->uuid.uuid.uuid128[7], char_id->uuid.uuid.uuid128[8], char_id->uuid.uuid.uuid128[9],
                     char_id->uuid.uuid.uuid128[10], char_id->uuid.uuid.uuid128[11], char_id->uuid.uuid.uuid128[12],
                     char_id->uuid.uuid.uuid128[13], char_id->uuid.uuid.uuid128[14], char_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("Char UNKNOWN LEN %d", char_id->uuid.len);
        }
        if (descr_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("Decr UUID16: %x", descr_id->uuid.uuid.uuid16);
        } else if (descr_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("Decr UUID32: %x", descr_id->uuid.uuid.uuid32);
        } else if (descr_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("Decr UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", descr_id->uuid.uuid.uuid128[0],
                     descr_id->uuid.uuid.uuid128[1], descr_id->uuid.uuid.uuid128[2], descr_id->uuid.uuid.uuid128[3],
                     descr_id->uuid.uuid.uuid128[4], descr_id->uuid.uuid.uuid128[5], descr_id->uuid.uuid.uuid128[6],
                     descr_id->uuid.uuid.uuid128[7], descr_id->uuid.uuid.uuid128[8], descr_id->uuid.uuid.uuid128[9],
                     descr_id->uuid.uuid.uuid128[10], descr_id->uuid.uuid.uuid128[11], descr_id->uuid.uuid.uuid128[12],
                     descr_id->uuid.uuid.uuid128[13], descr_id->uuid.uuid.uuid128[14], descr_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("Decr UNKNOWN LEN %d", descr_id->uuid.len);
        }
        if (srvc_id->id.uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("SRVC UUID16: %x", srvc_id->id.uuid.uuid.uuid16);
        } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("SRVC UUID32: %x", srvc_id->id.uuid.uuid.uuid32);
        } else if (srvc_id->id.uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("SRVC UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", srvc_id->id.uuid.uuid.uuid128[0],
                     srvc_id->id.uuid.uuid.uuid128[1], srvc_id->id.uuid.uuid.uuid128[2], srvc_id->id.uuid.uuid.uuid128[3],
                     srvc_id->id.uuid.uuid.uuid128[4], srvc_id->id.uuid.uuid.uuid128[5], srvc_id->id.uuid.uuid.uuid128[6],
                     srvc_id->id.uuid.uuid.uuid128[7], srvc_id->id.uuid.uuid.uuid128[8], srvc_id->id.uuid.uuid.uuid128[9],
                     srvc_id->id.uuid.uuid.uuid128[10], srvc_id->id.uuid.uuid.uuid128[11], srvc_id->id.uuid.uuid.uuid128[12],
                     srvc_id->id.uuid.uuid.uuid128[13], srvc_id->id.uuid.uuid.uuid128[14], srvc_id->id.uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("SRVC UNKNOWN LEN %d", srvc_id->id.uuid.len);
        }
        LOG_INFO("WRITE DESCR: gattc_if = %x",gattc_if);
        LOG_INFO("remote_bda %x,%x,%x,%x,%x,%x:",p_data->open.remote_bda[0],
                p_data->open.remote_bda[1],p_data->open.remote_bda[2],
                p_data->open.remote_bda[3],p_data->open.remote_bda[4],
                p_data->open.remote_bda[5]);
        LOG_INFO("server_dba %x,%x,%x,%x,%x,%x:",server_dba[0],
                server_dba[1],server_dba[2],
                server_dba[3],server_dba[4],
                server_dba[5]);
    }
    break;
}
case ESP_GATTC_NOTIFY_EVT: {
    // esp_gatt_srvc_id_t *srvc_id = &p_data->read.srvc_id;
    esp_gatt_id_t *char_id = &p_data->notify.char_id;
    conn_id = p_data->open.conn_id;
    LOG_INFO("NOTIFY: open.conn_id = %x search_res.conn_id = %x  notify.conn_id = %x", conn_id,p_data->search_res.conn_id,p_data->notify.conn_id);
    LOG_INFO("NOTIFY: notify.is_notify = %x inst_id = %x", p_data->notify.is_notify, char_id->inst_id);
    if (p_data->notify.is_notify==1) {
        if (char_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("Char UUID16: %x", char_id->uuid.uuid.uuid16);
        } else if (char_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("Char UUID32: %x", char_id->uuid.uuid.uuid32);
        } else if (char_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("Char UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_id->uuid.uuid.uuid128[0],
                     char_id->uuid.uuid.uuid128[1], char_id->uuid.uuid.uuid128[2], char_id->uuid.uuid.uuid128[3],
                     char_id->uuid.uuid.uuid128[4], char_id->uuid.uuid.uuid128[5], char_id->uuid.uuid.uuid128[6],
                     char_id->uuid.uuid.uuid128[7], char_id->uuid.uuid.uuid128[8], char_id->uuid.uuid.uuid128[9],
                     char_id->uuid.uuid.uuid128[10], char_id->uuid.uuid.uuid128[11], char_id->uuid.uuid.uuid128[12],
                     char_id->uuid.uuid.uuid128[13], char_id->uuid.uuid.uuid128[14], char_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("Char UNKNOWN LEN %d\n", char_id->uuid.len);
        }
        for (int i = 0; i < p_data->notify.value_len; i++) {
            LOG_INFO("NOTIFY: V%d %x:", i, p_data->notify.value[i]);
        }

        if (is_led_on) {
            gpio_set_level(LED_GPIO, 1);
        } else {
            gpio_set_level(LED_GPIO, 0);
        }
    }
    break;
}
case ESP_GATTC_GET_CHAR_EVT: {
    esp_gatt_srvc_id_t *srvc_id = &p_data->get_char.srvc_id;
    esp_gatt_id_t *char_id = &p_data->get_char.char_id;
    conn_id = p_data->open.conn_id;
    LOG_INFO("GET CHAR: open.conn_id = %x search_res.conn_id = %x  get_char.conn_id = %x", conn_id,p_data->search_res.conn_id,p_data->get_char.conn_id);
    LOG_INFO("GET CHAR: get_char.char_prop = %x get_char.status = %x inst_id = %x open.gatt_if = %x", p_data->get_char.char_prop, p_data->get_char.status, char_id->inst_id,gattc_if);
    LOG_INFO("remote_bda %x,%x,%x,%x,%x,%x:",p_data->open.remote_bda[0],
            p_data->open.remote_bda[1],p_data->open.remote_bda[2],
            p_data->open.remote_bda[3],p_data->open.remote_bda[4],
            p_data->open.remote_bda[5]);
    if (p_data->get_char.status==0) {
        // print characteristic property
        get_characteristic_property(p_data->get_char.char_prop);

        if (char_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("UUID16: %x", char_id->uuid.uuid.uuid16);
            if (char_id->uuid.uuid.uuid16 == TEST_CHAR_UUID) {
                ESP_LOGI(TAG, "register notify\n");
                esp_ble_gattc_register_for_notify(gattc_if, p_data->open.remote_bda, &test_service_id, &test_char_id);
            }
        } else if (char_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("UUID32: %x", char_id->uuid.uuid.uuid32);
        } else if (char_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_id->uuid.uuid.uuid128[0],
                     char_id->uuid.uuid.uuid128[1], char_id->uuid.uuid.uuid128[2], char_id->uuid.uuid.uuid128[3],
                     char_id->uuid.uuid.uuid128[4], char_id->uuid.uuid.uuid128[5], char_id->uuid.uuid.uuid128[6],
                     char_id->uuid.uuid.uuid128[7], char_id->uuid.uuid.uuid128[8], char_id->uuid.uuid.uuid128[9],
                     char_id->uuid.uuid.uuid128[10], char_id->uuid.uuid.uuid128[11], char_id->uuid.uuid.uuid128[12],
                     char_id->uuid.uuid.uuid128[13], char_id->uuid.uuid.uuid128[14], char_id->uuid.uuid.uuid128[15]);

            esp_ble_gattc_get_descriptor(gattc_if, conn_id, srvc_id, char_id, NULL);
            esp_ble_gattc_get_characteristic(gattc_if, conn_id, srvc_id, char_id);
        } else {
            LOG_ERROR("UNKNOWN LEN %d", char_id->uuid.len);
        }
    } else {
        ESP_LOGE(TAG, "get characteristic failed");
    }
    break;
}
case ESP_GATTC_GET_DESCR_EVT: {
    //esp_gatt_srvc_id_t *srvc_id = &p_data->get_descr.srvc_id;
    esp_gatt_id_t *char_id = &p_data->get_descr.char_id;
    esp_gatt_id_t *descr_id = &p_data->get_descr.descr_id;
    conn_id = p_data->open.conn_id;
    LOG_INFO("GET DESCR: open.conn_id = %x search_res.conn_id = %x  get_descr.conn_id = %x", conn_id,p_data->search_res.conn_id,p_data->get_descr.conn_id);
    LOG_INFO("GET DESCR: get_descr.status = %x inst_id = %x open.gatt_if = %x", p_data->get_descr.status, char_id->inst_id,gattc_if);
    //uint8_t value[2];
    //value[0]=0x01;
    //value[1]=0x00;
    if (p_data->get_descr.status==0) {
        if (char_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("Char UUID16: %x", char_id->uuid.uuid.uuid16);
        } else if (char_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("Char UUID32: %x", char_id->uuid.uuid.uuid32);
        } else if (char_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("Char UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_id->uuid.uuid.uuid128[0],
                     char_id->uuid.uuid.uuid128[1], char_id->uuid.uuid.uuid128[2], char_id->uuid.uuid.uuid128[3],
                     char_id->uuid.uuid.uuid128[4], char_id->uuid.uuid.uuid128[5], char_id->uuid.uuid.uuid128[6],
                     char_id->uuid.uuid.uuid128[7], char_id->uuid.uuid.uuid128[8], char_id->uuid.uuid.uuid128[9],
                     char_id->uuid.uuid.uuid128[10], char_id->uuid.uuid.uuid128[11], char_id->uuid.uuid.uuid128[12],
                     char_id->uuid.uuid.uuid128[13], char_id->uuid.uuid.uuid128[14], char_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("Char UNKNOWN LEN %d", char_id->uuid.len);
        }
        if (descr_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("Decr UUID16: %x", descr_id->uuid.uuid.uuid16);
        } else if (descr_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("Decr UUID32: %x", descr_id->uuid.uuid.uuid32);
        } else if (descr_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("Decr UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", descr_id->uuid.uuid.uuid128[0],
                     descr_id->uuid.uuid.uuid128[1], descr_id->uuid.uuid.uuid128[2], descr_id->uuid.uuid.uuid128[3],
                     descr_id->uuid.uuid.uuid128[4], descr_id->uuid.uuid.uuid128[5], descr_id->uuid.uuid.uuid128[6],
                     descr_id->uuid.uuid.uuid128[7], descr_id->uuid.uuid.uuid128[8], descr_id->uuid.uuid.uuid128[9],
                     descr_id->uuid.uuid.uuid128[10], descr_id->uuid.uuid.uuid128[11], descr_id->uuid.uuid.uuid128[12],
                     descr_id->uuid.uuid.uuid128[13], descr_id->uuid.uuid.uuid128[14], descr_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("Decr UNKNOWN LEN %d", descr_id->uuid.len);
        }
        /*esp_ble_gattc_write_char_descr (
            gattc_if,
            conn_id,
            srvc_id,
            char_id,
            descr_id,
            2,
            &value[0],
            ESP_GATT_WRITE_TYPE_NO_RSP,
            ESP_GATT_AUTH_REQ_NONE);*/
    }
    break;
}
case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
    LOG_INFO("NOTIFY_EVT: open.conn_id = %x ", p_data->open.conn_id);
    LOG_INFO("NOTIFY_EVT: reg_for_notify.status = %x ", p_data->reg_for_notify.status);
    esp_gatt_id_t *char_id = &p_data->reg_for_notify.char_id;
    if (p_data->reg_for_notify.status==0) {
        if (char_id->uuid.len == ESP_UUID_LEN_16) {
            LOG_INFO("UUID16: %x", char_id->uuid.uuid.uuid16);
        } else if (char_id->uuid.len == ESP_UUID_LEN_32) {
            LOG_INFO("UUID32: %x", char_id->uuid.uuid.uuid32);
        } else if (char_id->uuid.len == ESP_UUID_LEN_128) {
            LOG_INFO("UUID128: %x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x,%x", char_id->uuid.uuid.uuid128[0],
                     char_id->uuid.uuid.uuid128[1], char_id->uuid.uuid.uuid128[2], char_id->uuid.uuid.uuid128[3],
                     char_id->uuid.uuid.uuid128[4], char_id->uuid.uuid.uuid128[5], char_id->uuid.uuid.uuid128[6],
                     char_id->uuid.uuid.uuid128[7], char_id->uuid.uuid.uuid128[8], char_id->uuid.uuid.uuid128[9],
                     char_id->uuid.uuid.uuid128[10], char_id->uuid.uuid.uuid128[11], char_id->uuid.uuid.uuid128[12],
                     char_id->uuid.uuid.uuid128[13], char_id->uuid.uuid.uuid128[14], char_id->uuid.uuid.uuid128[15]);
        } else {
            LOG_ERROR("UNKNOWN LEN %d", char_id->uuid.len);
        }

        // enable gatt server notification
        uint8_t notify_en = 1;
        esp_err_t err = esp_ble_gattc_write_char_descr(
            gattc_if,
            conn_id,
            &test_service_id,
            &test_char_id,
            &notify_descr_id,
            1,
            &notify_en,
            ESP_GATT_WRITE_TYPE_RSP,
            ESP_GATT_AUTH_REQ_NONE);
        if (err != 0) {
            ESP_LOGE(TAG, "write char desc failed");
        } else {
            ESP_LOGI(TAG, "==> write char desc OK");
        }
    } else {
        ESP_LOGE(TAG, "notify register failed");
    }
    break;
}
case ESP_GATTC_SEARCH_CMPL_EVT:
    conn_id = p_data->search_cmpl.conn_id;
    LOG_INFO("SEARCH_CMPL: conn_id = %x, status %d", conn_id, p_data->search_cmpl.status);
    esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
    switch (scan_result->scan_rst.ble_evt_type) {
        case ESP_BLE_EVT_CONN_ADV:
            ESP_LOGI(TAG, "==> CONN_ADV");
            ESP_LOGI(TAG, "BDA %x,%x,%x,%x,%x,%x:",scan_result->scan_rst.bda[0],
                             scan_result->scan_rst.bda[1],scan_result->scan_rst.bda[2],
                                             scan_result->scan_rst.bda[3],scan_result->scan_rst.bda[4],
                                             scan_result->scan_rst.bda[5]);
            ESP_LOGI(TAG, "==> RSSI: %d", scan_result->scan_rst.rssi);
            ESP_LOGI(TAG, "==> address type: %d", scan_result->scan_rst.ble_addr_type);
            /*esp_ble_gap_stop_scanning();
            esp_err_t err = esp_ble_gattc_open(client_if, scan_result->scan_rst.bda, true);
            ESP_LOGI(TAG, "==> esp_ble_gattc_open %d", err);*/
            break;
        case ESP_BLE_EVT_CONN_DIR_ADV:
            ESP_LOGI(TAG, "==> CONN_DIR_ADV");
            break;
        case ESP_BLE_EVT_DISC_ADV:
            ESP_LOGI(TAG, "==> DISC_ADV");
            break;
        case ESP_BLE_EVT_NON_CONN_ADV:
            ESP_LOGI(TAG, "==> NON_CONN_ADV");
            break;
        case ESP_BLE_EVT_SCAN_RSP:
            ESP_LOGI(TAG, "==> receive scan response");
            LOG_INFO("BDA %x,%x,%x,%x,%x,%x:",scan_result->scan_rst.bda[0],
                             scan_result->scan_rst.bda[1],scan_result->scan_rst.bda[2],
                                             scan_result->scan_rst.bda[3],scan_result->scan_rst.bda[4],
                                             scan_result->scan_rst.bda[5]);
            break;
    }
    //esp_ble_gattc_get_characteristic(gattc_if, conn_id, &p_data->search_res.srvc_id, NULL);
    break;
default:
    break;
}

}

void ble_client_appRegister(void) { LOG_INFO("register callback");

//register the scan callback function to the Generic Access Profile (GAP) module
if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {
    LOG_ERROR("gap register error, error code = %x", status);
    return;
}

//register the callback function to the Generic Attribute Profile (GATT) Client (GATTC) module
if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) {
    LOG_ERROR("gattc register error, error code = %x", status);
    return;
}
esp_ble_gattc_app_register(simpleClient_id);
esp_ble_gap_set_scan_params(&ble_scan_params);

}

void gattc_client_test(void) { esp_bluedroid_init(); esp_bluedroid_enable(); ble_client_appRegister(); }

void app_main() { gpio_pad_select_gpio(LED_GPIO); / Set the GPIO as a push/pull output / gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT); gpio_set_level(LED_GPIO, 0);

esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
esp_err_t ret = esp_bt_controller_init(&bt_cfg);

if (ret) {
    ESP_LOGE(TAG, "%s initialize controller failed\n", __func__);
    return;
}

esp_bt_controller_enable(ESP_BT_MODE_BTDM);
gattc_client_test();

}`

Nicholas3388 commented 7 years ago

The following is the server code:

`#include

include

include

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 "bt.h"

include "bta_api.h"

include "esp_gap_ble_api.h"

include "esp_gatts_api.h"

include "esp_bt_defs.h"

include "esp_bt_main.h"

include "esp_bt_main.h"

include "driver/gpio.h"

include "sdkconfig.h"

include "freertos/FreeRTOS.h"

include "freertos/task.h"

define GATTS_TAG "GATTS_DEMO"

///Declare the static function static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t param); static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t param);

static bool task_run = false; static esp_gatt_if_t client_if; static uint16_t client_conn = 0; static uint16_t ccc_handle = 0; static uint16_t notif_test_v = 1;

define GATTS_SERVICE_UUID_TEST_A 0x00FF

define GATTS_CHAR_UUID_TEST_A 0xFF01

define GATTS_DESCR_UUID_TEST_A 0x3333

define GATTS_NUM_HANDLE_TEST_A 4

define GATTS_SERVICE_UUID_TEST_B 0x00EE

define GATTS_CHAR_UUID_TEST_B 0xEE01

define GATTS_DESCR_UUID_TEST_B 0x2222

define GATTS_NUM_HANDLE_TEST_B 4

define TEST_DEVICE_NAME "ESP32"

define TEST_MANUFACTURER_DATA_LEN 17

define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40

define LED_GPIO 2

uint8_t char1_str[] = {0x11,0x22,0x33}; esp_attr_value_t gatts_demo_char1_val = { .attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX, .attr_len = sizeof(char1_str), .attr_value = char1_str, };

static uint8_t test_service_uuid128[32] = { / LSB <--------------------------------------------------------------------------------> MSB / //first uuid, 16bit, [12],[13] is the value 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0x00, 0x00, //second uuid, 32bit, [12], [13], [14], [15] is the value 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xAB, 0xCD, 0xAB, 0xCD, };

//static uint8_t test_manufacturer[TEST_MANUFACTURER_DATA_LEN] = {0x12, 0x23, 0x45, 0x56}; static esp_ble_adv_data_t test_adv_data = { .set_scan_rsp = false, .include_name = true, .include_txpower = true, .min_interval = 0x20, .max_interval = 0x40, .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 = 32, .p_service_uuid = test_service_uuid128, .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT), };

static esp_ble_adv_params_t test_adv_params = { .adv_int_min = 0x20, .adv_int_max = 0x40, .adv_type = ADV_TYPE_SCAN_IND, .own_addr_type = BLE_ADDR_TYPE_PUBLIC, //.peer_addr = //.peer_addr_type = .channel_map = ADV_CHNL_ALL, .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY, };

define PROFILE_NUM 2

define PROFILE_A_APP_ID 0

define PROFILE_B_APP_ID 1

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

/ 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 gl_profile_tab[PROFILE_NUM] = { [PROFILE_A_APP_ID] = { .gatts_cb = gatts_profile_a_event_handler, .gatts_if = ESP_GATT_IF_NONE, / Not get the gatt_if, so initial is ESP_GATT_IF_NONE / }, [PROFILE_B_APP_ID] = { .gatts_cb = gatts_profile_b_event_handler, / This demo does not implement, similar as profile A / .gatts_if = ESP_GATT_IF_NONE, / Not get the gatt_if, so initial is ESP_GATT_IF_NONE / }, };

static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t param) { esp_ble_gap_cb_param_t scan_result = (esp_ble_gap_cb_param_t *)param; switch (scan_result->scan_rst.ble_evt_type) { case ESP_BLE_EVT_CONN_ADV: ESP_LOGI(TAG, "==> CONN_ADV"); LOG_INFO("BDA %x,%x,%x,%x,%x,%x:",scan_result->scan_rst.bda[0], scan_result->scan_rst.bda[1],scan_result->scan_rst.bda[2], scan_result->scan_rst.bda[3],scan_result->scan_rst.bda[4], scan_result->scan_rst.bda[5]); break; case ESP_BLE_EVT_CONN_DIR_ADV: ESP_LOGI(TAG, "==> CONN_DIR_ADV"); break; case ESP_BLE_EVT_DISC_ADV: ESP_LOGI(TAG, "==> DISC_ADV"); break; case ESP_BLE_EVT_NON_CONN_ADV: ESP_LOGI(TAG, "==> NON_CONN_ADV"); break; case ESP_BLE_EVT_SCAN_RSP: ESP_LOGI(TAG, "==> receive scan response"); LOG_INFO("BDA %x,%x,%x,%x,%x,%x:",scan_result->scan_rst.bda[0], scan_result->scan_rst.bda[1],scan_result->scan_rst.bda[2], scan_result->scan_rst.bda[3],scan_result->scan_rst.bda[4], scan_result->scan_rst.bda[5]); break; } switch (event) { case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&test_adv_params); break; case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&test_adv_params); break; case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT: esp_ble_gap_start_advertising(&test_adv_params); break; case ESP_GAP_BLE_ADV_START_COMPLETE_EVT: //advertising start complete event to indicate advertising start successfully or failed if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) { ESP_LOGE(GATTS_TAG, "Advertising start failed\n"); } break; default: break; } }

static void gatts_profile_a_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_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); gl_profile_tab[PROFILE_A_APP_ID].service_id.is_primary = true; gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00; gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A; esp_ble_gap_set_device_name(TEST_DEVICE_NAME);

ifdef CONFIG_SET_RAW_ADV_DATA

    esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data));
    esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data));

else

    esp_ble_gap_config_adv_data(&test_adv_data);

endif

    esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A);
    break;
case ESP_GATTS_READ_EVT: {
    ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle);
    esp_gatt_rsp_t rsp;
    memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
    rsp.attr_value.handle = param->read.handle;
    rsp.attr_value.len = 4;
    rsp.attr_value.value[0] = 0xde;
    rsp.attr_value.value[1] = 0xed;
    rsp.attr_value.value[2] = 0xbe;
    rsp.attr_value.value[3] = 0xef;
    esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
    break;
}
case ESP_GATTS_WRITE_EVT: {
    ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle);
    ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value %08x\n", param->write.len, *(uint32_t *)param->write.value);
    esp_gatt_rsp_t rsp;
    memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
    rsp.attr_value.handle = param->read.handle;
    rsp.attr_value.len = 4;
    rsp.attr_value.value[0] = 0xde;
    rsp.attr_value.value[1] = 0xed;
    rsp.attr_value.value[2] = 0xbe;
    rsp.attr_value.value[3] = 0xef;
    esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, &rsp);
    uint32_t val = *(uint32_t *)param->write.value;
    if (val == 0x0) {
        ESP_LOGI(GATTS_TAG, "GATT write 0");
        task_run = false;
    } else if (val == 0x1) {
        ESP_LOGI(GATTS_TAG, "GATT write 1");
        task_run = true;
        const uint8_t v = 0x1; 
        esp_ble_gatts_set_attr_value(0x002B, 1, &v);
    } else {
        ESP_LOGE(GATTS_TAG, "Unknown notify value");
    }

    break;
}
case ESP_GATTS_EXEC_WRITE_EVT:
case ESP_GATTS_MTU_EVT:
case ESP_GATTS_CONF_EVT:
case ESP_GATTS_UNREG_EVT:
    break;
case ESP_GATTS_CREATE_EVT:
    ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d,  service_handle %d\n", param->create.status, param->create.service_handle);
    gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle;
    gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16;
    gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_A;
    //gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = GATTS_DESCR_UUID_TEST_A; 
    esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle);

    esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid,
                           ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
                           ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY, 
                           &gatts_demo_char1_val, NULL);
    break;
case ESP_GATTS_ADD_INCL_SRVC_EVT:
    break;
case ESP_GATTS_ADD_CHAR_EVT: {
    uint16_t length = 0;
    const uint8_t *prf_char;

    ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d,  attr_handle %d, service_handle %d\n",
            param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
    gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle;
    gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16;
    gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
    esp_ble_gatts_get_attr_value(param->add_char.attr_handle,  &length, &prf_char);

    ESP_LOGI(GATTS_TAG, "the gatts demo char length = %x\n", length);
    for(int i = 0; i < length; i++){
        ESP_LOGI(GATTS_TAG, "prf_char[%x] =%x\n",i,prf_char[i]);
    }

    if (param->add_char.char_uuid.uuid.uuid16 == GATTS_CHAR_UUID_TEST_A) {
        ccc_handle = param->add_char.attr_handle;
        ESP_LOGI(GATTS_TAG, "get target char handle=%d", ccc_handle);
    }

    esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid,
                                 ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
    break;
}
case ESP_GATTS_ADD_CHAR_DESCR_EVT: {
    ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d, desc UUID %04x, desc handle %d\n",
             param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle, param->add_char_descr.char_uuid.uuid.uuid16, param->add_char_descr.attr_handle);
    break;
}
case ESP_GATTS_DELETE_EVT:
    break;
case ESP_GATTS_START_EVT:
    ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n",
             param->start.status, param->start.service_handle);
    break;
case ESP_GATTS_STOP_EVT:
    break;
case ESP_GATTS_CONNECT_EVT:
    ESP_LOGI(GATTS_TAG, "CONNECT_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:, is_conn %d\n",
             param->connect.conn_id,
             param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2],
             param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5],
             param->connect.is_connected);
    gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id;

    client_if = gatts_if;
    client_conn = param->connect.conn_id;

    // turn on the LED to show that connection established
    gpio_set_level(LED_GPIO, 1);
    break;
case ESP_GATTS_DISCONNECT_EVT:
    esp_ble_gap_start_advertising(&test_adv_params);
    gpio_set_level(LED_GPIO, 0);    // turn off the LED to show BLE disconnected
    break;
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
case ESP_GATTS_CONGEST_EVT:
default:
    break;
}

}

static void gatts_profile_b_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_LOGI(GATTS_TAG, "REGISTER_APP_EVT, status %d, app_id %d\n", param->reg.status, param->reg.app_id); gl_profile_tab[PROFILE_B_APP_ID].service_id.is_primary = true; gl_profile_tab[PROFILE_B_APP_ID].service_id.id.inst_id = 0x00; gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16; gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_B;

    esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_B_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_B);
    break;
case ESP_GATTS_READ_EVT: {
    ESP_LOGI(GATTS_TAG, "GATT_READ_EVT, conn_id %d, trans_id %d, handle %d\n", param->read.conn_id, param->read.trans_id, param->read.handle);
    esp_gatt_rsp_t rsp;
    memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
    rsp.attr_value.handle = param->read.handle;
    rsp.attr_value.len = 4;
    rsp.attr_value.value[0] = 0xde;
    rsp.attr_value.value[1] = 0xed;
    rsp.attr_value.value[2] = 0xbe;
    rsp.attr_value.value[3] = 0xef;
    esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id,
                                ESP_GATT_OK, &rsp);
    break;
}
case ESP_GATTS_WRITE_EVT: {
    ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, conn_id %d, trans_id %d, handle %d\n", param->write.conn_id, param->write.trans_id, param->write.handle);
    ESP_LOGI(GATTS_TAG, "GATT_WRITE_EVT, value len %d, value %08x\n", param->write.len, *(uint32_t *)param->write.value);
    esp_gatt_rsp_t rsp;
    memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
    rsp.attr_value.handle = param->read.handle;
    rsp.attr_value.len = 4;
    rsp.attr_value.value[0] = 0xde;
    rsp.attr_value.value[1] = 0xed;
    rsp.attr_value.value[2] = 0xbe;
    rsp.attr_value.value[3] = 0xef;
    esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, &rsp);
    break;
}
case ESP_GATTS_EXEC_WRITE_EVT:
case ESP_GATTS_MTU_EVT:
case ESP_GATTS_CONF_EVT:
case ESP_GATTS_UNREG_EVT:
    break;
case ESP_GATTS_CREATE_EVT:
    ESP_LOGI(GATTS_TAG, "CREATE_SERVICE_EVT, status %d,  service_handle %d\n", param->create.status, param->create.service_handle);
    gl_profile_tab[PROFILE_B_APP_ID].service_handle = param->create.service_handle;
    gl_profile_tab[PROFILE_B_APP_ID].char_uuid.len = ESP_UUID_LEN_16;
    gl_profile_tab[PROFILE_B_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_B;

    esp_ble_gatts_start_service(gl_profile_tab[PROFILE_B_APP_ID].service_handle);

    esp_ble_gatts_add_char(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].char_uuid,
                           ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
                           ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY,
                           NULL, NULL);
    break;
case ESP_GATTS_ADD_INCL_SRVC_EVT:
    break;
case ESP_GATTS_ADD_CHAR_EVT:
    ESP_LOGI(GATTS_TAG, "ADD_CHAR_EVT, status %d,  attr_handle %d, service_handle %d\n",
             param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);

    gl_profile_tab[PROFILE_B_APP_ID].char_handle = param->add_char.attr_handle;
    gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.len = ESP_UUID_LEN_16;
    gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
    esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].descr_uuid,
                                 ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
                                 NULL, NULL);
    break;
case ESP_GATTS_ADD_CHAR_DESCR_EVT:
    ESP_LOGI(GATTS_TAG, "ADD_DESCR_EVT, status %d, attr_handle %d, service_handle %d\n",
             param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
    break;
case ESP_GATTS_DELETE_EVT:
    break;
case ESP_GATTS_START_EVT:
    ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, status %d, service_handle %d\n",
             param->start.status, param->start.service_handle);
    break;
case ESP_GATTS_STOP_EVT:
    break;
case ESP_GATTS_CONNECT_EVT:
    ESP_LOGI(GATTS_TAG, "SERVICE_START_EVT, conn_id %d, remote %02x:%02x:%02x:%02x:%02x:%02x:, is_conn %d\n",
             param->connect.conn_id,
             param->connect.remote_bda[0], param->connect.remote_bda[1], param->connect.remote_bda[2],
             param->connect.remote_bda[3], param->connect.remote_bda[4], param->connect.remote_bda[5],
             param->connect.is_connected);
    gl_profile_tab[PROFILE_B_APP_ID].conn_id = param->connect.conn_id;
    break;
case ESP_GATTS_DISCONNECT_EVT:
case ESP_GATTS_OPEN_EVT:
case ESP_GATTS_CANCEL_OPEN_EVT:
case ESP_GATTS_CLOSE_EVT:
case ESP_GATTS_LISTEN_EVT:
case ESP_GATTS_CONGEST_EVT:
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) { gl_profile_tab[param->reg.app_id].gatts_if = gatts_if; } else { ESP_LOGI(GATTS_TAG, "Reg app failed, app_id %04x, status %d\n", param->reg.app_id, param->reg.status); return; } }

/* If the gatts_if equal to profile A, call profile A cb handler,
 * so here call each profile's callback */
do {
    int idx;
    for (idx = 0; idx < PROFILE_NUM; idx++) {
        if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
                gatts_if == gl_profile_tab[idx].gatts_if) {
            if (gl_profile_tab[idx].gatts_cb) {
                gl_profile_tab[idx].gatts_cb(event, gatts_if, param);
            }
        }
    }
} while (0);

}

static void led_task(void arg) { while (1) { vTaskDelay(3000 / portTICK_RATE_MS); //ESP_LOGI(TAG, "led_task is running"); if (task_run) { ESP_LOGI(GATTS_TAG, "send notify handle=%d", ccc_handle); uint16_t notif_len = 2; uint8_t val2[2] = {0x11, 0x22}; esp_ble_gatts_send_indicate(client_if, client_conn, ccc_handle, notif_len, val2, false); //esp_ble_gatts_set_attr_value(ccc_handle, sizeof(notif_test_v), (uint8_t )&notif_test_v); if (notif_test_v == 1) { notif_test_v = 0; } else { notif_test_v = 1; } } } vTaskDelete(NULL); }

void app_main() { esp_err_t ret;

esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
ret = esp_bt_controller_init(&bt_cfg);

ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
if (ret) {
    ESP_LOGE(GATTS_TAG, "%s enable controller failed\n", __func__);
    return;
}
ret = esp_bluedroid_init();
if (ret) {
    ESP_LOGE(GATTS_TAG, "%s init bluetooth failed\n", __func__);
    return;
}
ret = esp_bluedroid_enable();
if (ret) {
    ESP_LOGE(GATTS_TAG, "%s enable bluetooth failed\n", __func__);
    return;
}

gpio_pad_select_gpio(LED_GPIO);
/* Set the GPIO as a push/pull output */
gpio_set_direction(LED_GPIO, GPIO_MODE_OUTPUT);
gpio_set_level(LED_GPIO, 0);

esp_ble_gatts_register_callback(gatts_event_handler);
esp_ble_gap_register_callback(gap_event_handler);
esp_ble_gatts_app_register(PROFILE_A_APP_ID);
esp_ble_gatts_app_register(PROFILE_B_APP_ID);

xTaskCreate(&led_task, "led_task", 2048, NULL, 6, NULL);

return;

} `

xiewenxiang commented 7 years ago

@Nicholas3388 Hi, Nicholas, The following code is untested:

  1. connected
  2. service search
  3. get char by test_service_id
  4. if (char_prop & 0x30) == 0x0, get next char
  5. if (char_prop & 0x30) != 0x0, get the char descr register notification for this char write this char descr
static uint16_t write_desc_value = 0;

static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if,esp_ble_gattc_cb_param_t *param)
{
    uint16_t conn_id = 0;
    esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *) param;

    switch (event) {
    case ESP_GATTC_OPEN_EVT:
        client_conn = p_data->open.conn_id;
        at_memcpy(server_dba, p_data->open.remote_bda, sizeof(esp_bd_addr_t));
        esp_ble_gattc_search_service(gattc_if, client_conn, NULL);
        break;
    case ESP_GATTC_SEARCH_RES_EVT:
        test_service_id.is_primary = p_data->search_res.srvc_id.is_primary;
        test_service_id.id.inst_id = p_data->search_res.srvc_id.id.inst_id;
        test_service_id.id.uuid.len = p_data->search_res.srvc_id.id.uuid.len;
        if (test_service_id.id.uuid.len == ESP_UUID_LEN_16) {
            test_service_id.id.uuid.uuid.uuid16 = p_data->search_res.srvc_id.id.uuid.uuid.uuid16;
        } else if (test_service_id.id.uuid.len == ESP_UUID_LEN_32) {
            test_service_id.id.uuid.uuid.uuid32 = p_data->search_res.srvc_id.id.uuid.uuid.uuid32;
        } else if (test_service_id.id.uuid.len == ESP_UUID_LEN_128) {
            for (int i = 0; i < 16; i++) {
                test_service_id.id.uuid.uuid.uuid128[i] = p_data->search_res.srvc_id.id.uuid.uuid.uuid128[i];
            }
        }
        break;
    case ESP_GATTC_SEARCH_CMPL_EVT:
        esp_ble_gattc_get_characteristic(gattc_if, client_conn,&test_service_id, NULL);
        break;
    case ESP_GATTC_GET_CHAR_EVT:
        if (p_data->get_char.status != ESP_GATT_OK) {
            break;
        }
        test_char_id.inst_id = p_data->get_char.char_id.inst_id;
        test_char_id.uuid.len = p_data->get_char.char_id.uuid.len;
        pGattc_char_node->char_prop = p_data->get_char.char_prop;
        if (test_char_id.uuid.len == ESP_UUID_LEN_16) {
            test_char_id.uuid.uuid.uuid16 = p_data->get_char.char_id.uuid.uuid.uuid16;
        } else if (test_char_id.uuid.len == ESP_UUID_LEN_32) {
            test_char_id.uuid.uuid.uuid32 = p_data->get_char.char_id.uuid.uuid.uuid32;
        } else if (test_char_id.uuid.len == ESP_UUID_LEN_128) {
            for (int i = 0; i < 16; i++) {
                test_char_id.uuid.uuid.uuid128[i] = p_data->get_char.char_id.uuid.uuid.uuid128[i];
            }
        }
        if(((p_data->get_char.char_prop)&0x10)||((p_data->get_char.char_prop)&0x20)){
            if(((p_data->get_char.char_prop)&0x10)){
                write_desc_value = 0x1;
            }else if(((p_data->get_char.char_prop)&0x20)){
                write_desc_value = 0x2;
            }
            esp_ble_gattc_get_descriptor(gattc_if, client_conn, &test_service_id, &test_char_id, NULL);
        }else{
            esp_ble_gattc_get_characteristic(gattc_if, client_conn, &test_service_id, &test_char_id);
        }
        break;
    case ESP_GATTC_GET_DESCR_EVT:
        if (p_data->get_descr.status != ESP_GATT_OK) {
            break;
        }
        notify_descr_id.inst_id = p_data->get_descr.descr_id.inst_id;
        notify_descr_id.uuid.len = p_data->get_descr.descr_id.uuid.len;

        if (notify_descr_id.uuid.len == ESP_UUID_LEN_16) {
            notify_descr_id.uuid.uuid.uuid16 = p_data->get_descr.descr_id.uuid.uuid.uuid16;
        } else if (notify_descr_id.uuid.len == ESP_UUID_LEN_32) {
            notify_descr_id.uuid.uuid.uuid32 = p_data->get_descr.descr_id.uuid.uuid.uuid32;
        } else if (notify_descr_id.uuid.len == ESP_UUID_LEN_128) {
            for (int i = 0; i < 16; i++) {
                notify_descr_id.uuid.uuid.uuid128[i] = p_data->get_descr.descr_id.uuid.uuid.uuid128[i];
            }
        }
        esp_ble_gattc_register_for_notify(gattc_if, server_dba,&test_service_id, &test_char_id);

        break;
    case ESP_GATTC_REG_FOR_NOTIFY_EVT:
        esp_ble_gattc_write_char_descr(
                gattc_if,
                client_conn,
                &test_service_id,
                &test_char_id,
                &notify_descr_id,
                sizeof(write_desc_value),
                (uint8_t *) &write_desc_value,
                ESP_GATT_WRITE_TYPE_NO_RSP,
                ESP_GATT_AUTH_REQ_NONE);

        esp_ble_gattc_get_characteristic(gattc_if, client_conn, &test_service_id, &test_char_id);
        break;
    case ESP_GATTC_WRITE_DESCR_EVT:
        break;
    case ESP_GATTC_NOTIFY_EVT:
        break;
    case ESP_BLE_EVT_CONN_DIR_ADV:
        break;
    default:
        break;
}
xiewenxiang commented 7 years ago

@Nicholas3388 Hi, Nicholas, can you receive indicate/noitification now?

Nicholas3388 commented 7 years ago

@xiewenxiang Hi, thanks for you code. Unfortunately, I still cannot receive notification now. I think my code is almost the same with your untested code. The character property is set as ESP_GATT_CHAR_PROP_BIT_NOTIFY on server, and on client I can search the character whose property is accurately notify. But the client cannot receive notification, when the server called esp_ble_gatts_send_indicate

By the way, in your code is it necessary to call esp_ble_gattc_get_characteristic after esp_ble_gattc_write_char_descr?

wolfking0815 commented 7 years ago

Hi,

I also met up with this issue. It seems that the esp_gattc_write_char_descriptor can not write the descriptor correctly. Because when I tried to write the descriptor, after I registered the notification, the BT will dump out "NO pending cmd" for this function. However, I can write the characteristic successfully. Any suggestions?

Thanks. kaikai

Nicholas3388 commented 7 years ago

@wolfking0815 There is no problem with writing characteristic. But I still cannot receive notifications between two ESP32 devices

danicampora commented 7 years ago

I am having this issue as welll... Has anyone had luck with this? I can register for Notifications from an smartphone, but not from a ESP32 acting as a GATT client.

TianHao-Yoursmake commented 7 years ago

@Nicholas3388 , @Weijian-Espressif will reply you and provide a demo.

Weijian-Espressif commented 7 years ago

@Nicholas3388, @danicampora , @wolfking0815 I provide you a demo. you can test it. gatts_demo.c.zip gattc_demo.c.zip

The client demo automatically connect the server demo, the clinet would enable the notify of server demo after connection is established. then the server demo would send some notify value to the client . The client will send back the value to the server after receiving the notify value.

if any question, let me know.

Nicholas3388 commented 7 years ago

@Weijian-Espressif @TianHao-Espressif Thanks. It works for me