From bf7d29bf103c07043cb43f69f22843b421eddd1f Mon Sep 17 00:00:00 2001 From: zwsd Date: Fri, 29 Jul 2022 16:45:57 +0800 Subject: [PATCH] =?UTF-8?q?=E6=9B=B4=E6=94=B9=E6=96=87=E4=BB=B6=E5=90=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- main/main.c | 648 +++++++++++++++++++++++++++++++++++++++++++++++++ main/spp_client_demo.c | 648 ------------------------------------------------- 2 files changed, 648 insertions(+), 648 deletions(-) create mode 100644 main/main.c delete mode 100644 main/spp_client_demo.c diff --git a/main/main.c b/main/main.c new file mode 100644 index 0000000..60bc32e --- /dev/null +++ b/main/main.c @@ -0,0 +1,648 @@ +/* + This example code is in the Public Domain (or CC0 licensed, at your option.) + + Unless required by applicable law or agreed to in writing, this + software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + CONDITIONS OF ANY KIND, either express or implied. +*/ + +/**************************************************************************** +* +* This file is for ble spp client demo. +* +****************************************************************************/ + +#include +#include +#include +#include +#include "driver/uart.h" + +#include "esp_bt.h" +#include "nvs_flash.h" +#include "esp_bt_device.h" +#include "esp_gap_ble_api.h" +#include "esp_gattc_api.h" +#include "esp_gatt_defs.h" +#include "esp_bt_main.h" +#include "esp_system.h" +#include "esp_gatt_common_api.h" +#include "esp_log.h" +#include "freertos/FreeRTOS.h" + +#define GATTC_TAG "GATTC_SPP_DEMO" +#define PROFILE_NUM 1 +#define PROFILE_APP_ID 0 +#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 ESP_GATT_SPP_SERVICE_UUID {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E} +#define SCAN_ALL_THE_TIME 0 + +struct gattc_profile_inst { + esp_gattc_cb_t gattc_cb; + uint16_t gattc_if; + uint16_t app_id; + uint16_t conn_id; + uint16_t service_start_handle; + uint16_t service_end_handle; + uint16_t char_handle; + esp_bd_addr_t remote_bda; +}; + +enum{ + SPP_IDX_SVC, + + SPP_IDX_SPP_DATA_RECV_VAL, + + SPP_IDX_SPP_DATA_NTY_VAL, + SPP_IDX_SPP_DATA_NTF_CFG, + + SPP_IDX_SPP_COMMAND_VAL, + + SPP_IDX_SPP_STATUS_VAL, + SPP_IDX_SPP_STATUS_CFG, + +#ifdef SUPPORT_HEARTBEAT + SPP_IDX_SPP_HEARTBEAT_VAL, + SPP_IDX_SPP_HEARTBEAT_CFG, +#endif + + SPP_IDX_NB, +}; + +///Declare static functions +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 gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); + +/* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */ +static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = { + [PROFILE_APP_ID] = { + .gattc_cb = gattc_profile_event_handler, + .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ + }, +}; + +static esp_ble_scan_params_t ble_scan_params = { + .scan_type = BLE_SCAN_TYPE_ACTIVE, + .own_addr_type = BLE_ADDR_TYPE_PUBLIC, + .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, + .scan_interval = 0x50, + .scan_window = 0x30, + .scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE +}; + +static const char device_name[] = "yimei_ble"; +static bool is_connect = false; +static uint16_t spp_conn_id = 0; +static uint16_t spp_mtu_size = 23; +static uint16_t cmd = 0; +static uint16_t spp_srv_start_handle = 0; +static uint16_t spp_srv_end_handle = 0; +static uint16_t spp_gattc_if = 0xff; +static char * notify_value_p = NULL; +static int notify_value_offset = 0; +static int notify_value_count = 0; +static uint16_t count = SPP_IDX_NB; +static esp_gattc_db_elem_t *db = NULL; +static esp_ble_gap_cb_param_t scan_rst; +static xQueueHandle cmd_reg_queue = NULL; +QueueHandle_t spp_uart_queue = NULL; + +#ifdef SUPPORT_HEARTBEAT +static uint8_t heartbeat_s[9] = {'E','s','p','r','e','s','s','i','f'}; +static xQueueHandle cmd_heartbeat_queue = NULL; +#endif + +static esp_bt_uuid_t spp_service_uuid = { + .len = ESP_UUID_LEN_128, + .uuid = {.uuid128 = ESP_GATT_SPP_SERVICE_UUID,}, +}; + +static void notify_event_handler(esp_ble_gattc_cb_param_t * p_data) +{ + uint8_t handle = 0; + + if(p_data->notify.is_notify == true){ + ESP_LOGI(GATTC_TAG,"+NOTIFY:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len); + }else{ + ESP_LOGI(GATTC_TAG,"+INDICATE:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len); + } + handle = p_data->notify.handle; + if(db == NULL) { + ESP_LOGE(GATTC_TAG, " %s db is NULL\n", __func__); + return; + } + if(handle == db[SPP_IDX_SPP_DATA_NTY_VAL].attribute_handle){ +#ifdef SPP_DEBUG_MODE + esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len); +#else + if((p_data->notify.value[0] == '#')&&(p_data->notify.value[1] == '#')){ + if((++notify_value_count) != p_data->notify.value[3]){ + if(notify_value_p != NULL){ + free(notify_value_p); + } + notify_value_count = 0; + notify_value_p = NULL; + notify_value_offset = 0; + ESP_LOGE(GATTC_TAG,"notify value count is not continuous,%s\n",__func__); + return; + } + if(p_data->notify.value[3] == 1){ + notify_value_p = (char *)malloc(((spp_mtu_size-7)*(p_data->notify.value[2]))*sizeof(char)); + if(notify_value_p == NULL){ + ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__); + notify_value_count = 0; + return; + } + memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4)); + if(p_data->notify.value[2] == p_data->notify.value[3]){ + uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset)); + free(notify_value_p); + notify_value_p = NULL; + notify_value_offset = 0; + return; + } + notify_value_offset += (p_data->notify.value_len - 4); + }else if(p_data->notify.value[3] <= p_data->notify.value[2]){ + memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4)); + if(p_data->notify.value[3] == p_data->notify.value[2]){ + uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset)); + free(notify_value_p); + notify_value_count = 0; + notify_value_p = NULL; + notify_value_offset = 0; + return; + } + notify_value_offset += (p_data->notify.value_len - 4); + } + }else{ + uart_write_bytes(UART_NUM_0, (char *)(p_data->notify.value), p_data->notify.value_len); + } +#endif + }else if(handle == ((db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle)){ + esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len); + //TODO:server notify status characteristic + }else{ + esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len); + } +} + +static void free_gattc_srv_db(void) +{ + is_connect = false; + spp_gattc_if = 0xff; + spp_conn_id = 0; + spp_mtu_size = 23; + cmd = 0; + spp_srv_start_handle = 0; + spp_srv_end_handle = 0; + notify_value_p = NULL; + notify_value_offset = 0; + notify_value_count = 0; + if(db){ + free(db); + db = NULL; + } +} + +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; + esp_err_t err; + + switch(event){ + case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { + if((err = param->scan_param_cmpl.status) != ESP_BT_STATUS_SUCCESS){ + ESP_LOGE(GATTC_TAG, "Scan param set failed: %s", esp_err_to_name(err)); + break; + } + //the unit of the duration is second + uint32_t duration = 0xFFFF; + ESP_LOGI(GATTC_TAG, "Enable Ble Scan:during time 0x%04X minutes.",duration); + esp_ble_gap_start_scanning(duration); + break; + } + case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: + //scan start complete event to indicate scan start successfully or failed + if ((err = param->scan_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(GATTC_TAG, "Scan start failed: %s", esp_err_to_name(err)); + break; + } + ESP_LOGI(GATTC_TAG, "Scan start successed"); + break; + case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: + if ((err = param->scan_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS) { + ESP_LOGE(GATTC_TAG, "Scan stop failed: %s", esp_err_to_name(err)); + break; + } + ESP_LOGI(GATTC_TAG, "Scan stop successed"); + if (is_connect == false) { + ESP_LOGI(GATTC_TAG, "Connect to the remote device."); + esp_ble_gattc_open(gl_profile_tab[PROFILE_APP_ID].gattc_if, scan_rst.scan_rst.bda, scan_rst.scan_rst.ble_addr_type, true); + } + 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: + esp_log_buffer_hex(GATTC_TAG, scan_result->scan_rst.bda, 6); + ESP_LOGI(GATTC_TAG, "Searched Adv Data Len %d, Scan Response Len %d", scan_result->scan_rst.adv_data_len, scan_result->scan_rst.scan_rsp_len); + adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); + ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d", adv_name_len); + esp_log_buffer_char(GATTC_TAG, adv_name, adv_name_len); + ESP_LOGI(GATTC_TAG, "\n"); + if (adv_name != NULL) { + if ( strncmp((char *)adv_name, device_name, adv_name_len) == 0) { + memcpy(&(scan_rst), scan_result, sizeof(esp_ble_gap_cb_param_t)); + esp_ble_gap_stop_scanning(); + } + } + break; + case ESP_GAP_SEARCH_INQ_CMPL_EVT: + break; + default: + break; + } + break; + } + case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: + if ((err = param->adv_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS){ + ESP_LOGE(GATTC_TAG, "Adv stop failed: %s", esp_err_to_name(err)); + }else { + ESP_LOGI(GATTC_TAG, "Stop adv successfully"); + } + 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) +{ + ESP_LOGI(GATTC_TAG, "EVT %d, gattc if %d", event, gattc_if); + + /* If event is register event, store the gattc_if for each profile */ + if (event == ESP_GATTC_REG_EVT) { + if (param->reg.status == ESP_GATT_OK) { + gl_profile_tab[param->reg.app_id].gattc_if = gattc_if; + } else { + ESP_LOGI(GATTC_TAG, "Reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status); + return; + } + } + /* If the gattc_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 (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ + gattc_if == gl_profile_tab[idx].gattc_if) { + if (gl_profile_tab[idx].gattc_cb) { + gl_profile_tab[idx].gattc_cb(event, gattc_if, param); + } + } + } + } while (0); +} + +static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) +{ + esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; + + switch (event) { + case ESP_GATTC_REG_EVT: + ESP_LOGI(GATTC_TAG, "REG EVT, set scan params"); + esp_ble_gap_set_scan_params(&ble_scan_params); + break; + case ESP_GATTC_CONNECT_EVT: + ESP_LOGI(GATTC_TAG, "ESP_GATTC_CONNECT_EVT: conn_id=%d, gatt_if = %d", spp_conn_id, gattc_if); + ESP_LOGI(GATTC_TAG, "REMOTE BDA:"); + esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_APP_ID].remote_bda, sizeof(esp_bd_addr_t)); + spp_gattc_if = gattc_if; + is_connect = true; + spp_conn_id = p_data->connect.conn_id; + memcpy(gl_profile_tab[PROFILE_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t)); + esp_ble_gattc_search_service(spp_gattc_if, spp_conn_id, &spp_service_uuid); + break; + case ESP_GATTC_DISCONNECT_EVT: + ESP_LOGI(GATTC_TAG, "disconnect"); + free_gattc_srv_db(); + esp_ble_gap_start_scanning(SCAN_ALL_THE_TIME); + break; + case ESP_GATTC_SEARCH_RES_EVT: + ESP_LOGI(GATTC_TAG, "ESP_GATTC_SEARCH_RES_EVT: start_handle = %d, end_handle = %d",p_data->search_res.start_handle,p_data->search_res.end_handle); + for (int i = 15; i >= 0; i--) + { + ESP_LOGI("uuid","UUID[%d] = %d",i,p_data->search_res.srvc_id.uuid.uuid.uuid128[i]); + } + + spp_srv_start_handle = p_data->search_res.start_handle; + spp_srv_end_handle = p_data->search_res.end_handle; + break; + case ESP_GATTC_SEARCH_CMPL_EVT: + ESP_LOGI(GATTC_TAG, "SEARCH_CMPL: conn_id = %x, status %d", spp_conn_id, p_data->search_cmpl.status); + esp_ble_gattc_send_mtu_req(gattc_if, spp_conn_id); + break; + case ESP_GATTC_REG_FOR_NOTIFY_EVT: { + ESP_LOGI(GATTC_TAG,"Index = %d,status = %d,handle = %d\n",cmd, p_data->reg_for_notify.status, p_data->reg_for_notify.handle); + if(p_data->reg_for_notify.status != ESP_GATT_OK){ + ESP_LOGE(GATTC_TAG, "ESP_GATTC_REG_FOR_NOTIFY_EVT, status = %d", p_data->reg_for_notify.status); + break; + } + uint16_t notify_en = 1; + esp_ble_gattc_write_char_descr( + spp_gattc_if, + spp_conn_id, + (db+cmd+1)->attribute_handle, + sizeof(notify_en), + (uint8_t *)¬ify_en, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); + + break; + } + case ESP_GATTC_NOTIFY_EVT: + ESP_LOGI(GATTC_TAG,"ESP_GATTC_NOTIFY_EVT\n"); + notify_event_handler(p_data); + break; + case ESP_GATTC_READ_CHAR_EVT: + ESP_LOGI(GATTC_TAG,"ESP_GATTC_READ_CHAR_EVT\n"); + break; + case ESP_GATTC_WRITE_CHAR_EVT: + ESP_LOGI(GATTC_TAG,"ESP_GATTC_WRITE_CHAR_EVT:status = %d,handle = %d", param->write.status, param->write.handle); + if(param->write.status != ESP_GATT_OK){ + ESP_LOGE(GATTC_TAG, "ESP_GATTC_WRITE_CHAR_EVT, error status = %d", p_data->write.status); + break; + } + break; + case ESP_GATTC_PREP_WRITE_EVT: + break; + case ESP_GATTC_EXEC_EVT: + break; + case ESP_GATTC_WRITE_DESCR_EVT: + ESP_LOGI(GATTC_TAG,"ESP_GATTC_WRITE_DESCR_EVT: status =%d,handle = %d \n", p_data->write.status, p_data->write.handle); + if(p_data->write.status != ESP_GATT_OK){ + ESP_LOGE(GATTC_TAG, "ESP_GATTC_WRITE_DESCR_EVT, error status = %d", p_data->write.status); + break; + } + switch(cmd){ + case SPP_IDX_SPP_DATA_NTY_VAL: + cmd = SPP_IDX_SPP_STATUS_VAL; + xQueueSend(cmd_reg_queue, &cmd,10/portTICK_PERIOD_MS); + break; + case SPP_IDX_SPP_STATUS_VAL: +#ifdef SUPPORT_HEARTBEAT + cmd = SPP_IDX_SPP_HEARTBEAT_VAL; + xQueueSend(cmd_reg_queue, &cmd, 10/portTICK_PERIOD_MS); +#endif + break; +#ifdef SUPPORT_HEARTBEAT + case SPP_IDX_SPP_HEARTBEAT_VAL: + xQueueSend(cmd_heartbeat_queue, &cmd, 10/portTICK_PERIOD_MS); + break; +#endif + default: + break; + }; + break; + case ESP_GATTC_CFG_MTU_EVT: + if(p_data->cfg_mtu.status != ESP_OK){ + break; + } + ESP_LOGI(GATTC_TAG,"+MTU:%d\n", p_data->cfg_mtu.mtu); + spp_mtu_size = p_data->cfg_mtu.mtu; + + db = (esp_gattc_db_elem_t *)malloc(count*sizeof(esp_gattc_db_elem_t)); + if(db == NULL){ + ESP_LOGE(GATTC_TAG,"%s:malloc db falied\n",__func__); + break; + } + if(esp_ble_gattc_get_db(spp_gattc_if, spp_conn_id, spp_srv_start_handle, spp_srv_end_handle, db, &count) != ESP_GATT_OK){ + ESP_LOGE(GATTC_TAG,"%s:get db falied\n",__func__); + break; + } + if(count != SPP_IDX_NB){ + ESP_LOGE(GATTC_TAG,"%s:get db count != SPP_IDX_NB, count = %d, SPP_IDX_NB = %d\n",__func__,count,SPP_IDX_NB); + break; + } + for(int i = 0;i < SPP_IDX_NB;i++){ + switch((db+i)->type){ + case ESP_GATT_DB_PRIMARY_SERVICE: + ESP_LOGI(GATTC_TAG,"attr_type = PRIMARY_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ + (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); + break; + case ESP_GATT_DB_SECONDARY_SERVICE: + ESP_LOGI(GATTC_TAG,"attr_type = SECONDARY_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ + (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); + break; + case ESP_GATT_DB_CHARACTERISTIC: + ESP_LOGI(GATTC_TAG,"attr_type = CHARACTERISTIC,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ + (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); + break; + case ESP_GATT_DB_DESCRIPTOR: + ESP_LOGI(GATTC_TAG,"attr_type = DESCRIPTOR,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ + (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); + break; + case ESP_GATT_DB_INCLUDED_SERVICE: + ESP_LOGI(GATTC_TAG,"attr_type = INCLUDED_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ + (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); + break; + case ESP_GATT_DB_ALL: + ESP_LOGI(GATTC_TAG,"attr_type = ESP_GATT_DB_ALL,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ + (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); + break; + default: + break; + } + } + cmd = SPP_IDX_SPP_DATA_NTY_VAL; + xQueueSend(cmd_reg_queue, &cmd, 10/portTICK_PERIOD_MS); + break; + case ESP_GATTC_SRVC_CHG_EVT: + break; + default: + break; + } +} + +void spp_client_reg_task(void* arg) +{ + uint16_t cmd_id; + for(;;) { + vTaskDelay(100 / portTICK_PERIOD_MS); + if(xQueueReceive(cmd_reg_queue, &cmd_id, portMAX_DELAY)) { + if(db != NULL) { + if(cmd_id == SPP_IDX_SPP_DATA_NTY_VAL){ + ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_DATA_NTY_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_DATA_NTY_VAL)->attribute_handle); + esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_DATA_NTY_VAL)->attribute_handle); + }else if(cmd_id == SPP_IDX_SPP_STATUS_VAL){ + ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_STATUS_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle); + esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle); + } +#ifdef SUPPORT_HEARTBEAT + else if(cmd_id == SPP_IDX_SPP_HEARTBEAT_VAL){ + ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle); + esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle); + } +#endif + } + } + } +} + +#ifdef SUPPORT_HEARTBEAT +void spp_heart_beat_task(void * arg) +{ + uint16_t cmd_id; + + for(;;) { + vTaskDelay(50 / portTICK_PERIOD_MS); + if(xQueueReceive(cmd_heartbeat_queue, &cmd_id, portMAX_DELAY)) { + while(1){ + if((is_connect == true) && (db != NULL) && ((db+SPP_IDX_SPP_HEARTBEAT_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))){ + esp_ble_gattc_write_char( spp_gattc_if, + spp_conn_id, + (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle, + sizeof(heartbeat_s), + (uint8_t *)heartbeat_s, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); + vTaskDelay(5000 / portTICK_PERIOD_MS); + }else{ + ESP_LOGI(GATTC_TAG,"disconnect\n"); + break; + } + } + } + } +} +#endif + +void ble_client_appRegister(void) +{ + esp_err_t status; + char err_msg[20]; + + ESP_LOGI(GATTC_TAG, "register callback"); + + //register the scan callback function to the gap module + if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) { + ESP_LOGE(GATTC_TAG, "gap register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg))); + return; + } + //register the callback function to the gattc module + if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) { + ESP_LOGE(GATTC_TAG, "gattc register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg))); + return; + } + esp_ble_gattc_app_register(PROFILE_APP_ID); + + esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(200); + if (local_mtu_ret){ + ESP_LOGE(GATTC_TAG, "set local MTU failed: %s", esp_err_to_name_r(local_mtu_ret, err_msg, sizeof(err_msg))); + } + + cmd_reg_queue = xQueueCreate(10, sizeof(uint32_t)); + xTaskCreate(spp_client_reg_task, "spp_client_reg_task", 2048, NULL, 10, NULL); + +#ifdef SUPPORT_HEARTBEAT + cmd_heartbeat_queue = xQueueCreate(10, sizeof(uint32_t)); + xTaskCreate(spp_heart_beat_task, "spp_heart_beat_task", 2048, NULL, 10, NULL); +#endif +} + +void uart_task(void *pvParameters) +{ + uart_event_t event; + for (;;) { + //Waiting for UART event. + if (xQueueReceive(spp_uart_queue, (void * )&event, (portTickType)portMAX_DELAY)) { + switch (event.type) { + //Event of UART receving data + case UART_DATA: + if (event.size && (is_connect == true) && (db != NULL) && ((db+SPP_IDX_SPP_DATA_RECV_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))) { + uint8_t * temp = NULL; + temp = (uint8_t *)malloc(sizeof(uint8_t)*event.size); + if(temp == NULL){ + ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n", __func__, __LINE__); + break; + } + memset(temp, 0x0, event.size); + uart_read_bytes(UART_NUM_0,temp,event.size,portMAX_DELAY); + esp_ble_gattc_write_char( spp_gattc_if, + spp_conn_id, + (db+SPP_IDX_SPP_DATA_RECV_VAL)->attribute_handle, + event.size, + temp, + ESP_GATT_WRITE_TYPE_RSP, + ESP_GATT_AUTH_REQ_NONE); + free(temp); + } + break; + default: + break; + } + } + } + vTaskDelete(NULL); +} + +static void spp_uart_init(void) +{ + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_RTS, + .rx_flow_ctrl_thresh = 122, + .source_clk = UART_SCLK_APB, + }; + + //Install UART driver, and get the queue. + uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_uart_queue, 0); + //Set UART parameters + uart_param_config(UART_NUM_0, &uart_config); + //Set UART pins + uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL); +} + +void app_main(void) +{ + esp_err_t 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(); + + nvs_flash_init(); + ret = esp_bt_controller_init(&bt_cfg); + if (ret) { + ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret)); + return; + } + + ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); + if (ret) { + ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret)); + return; + } + + ESP_LOGI(GATTC_TAG, "%s init bluetooth\n", __func__); + ret = esp_bluedroid_init(); + if (ret) { + ESP_LOGE(GATTC_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret)); + return; + } + ret = esp_bluedroid_enable(); + if (ret) { + ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret)); + return; + } + + ble_client_appRegister(); + spp_uart_init(); +} diff --git a/main/spp_client_demo.c b/main/spp_client_demo.c deleted file mode 100644 index 60bc32e..0000000 --- a/main/spp_client_demo.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - This example code is in the Public Domain (or CC0 licensed, at your option.) - - Unless required by applicable law or agreed to in writing, this - software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR - CONDITIONS OF ANY KIND, either express or implied. -*/ - -/**************************************************************************** -* -* This file is for ble spp client demo. -* -****************************************************************************/ - -#include -#include -#include -#include -#include "driver/uart.h" - -#include "esp_bt.h" -#include "nvs_flash.h" -#include "esp_bt_device.h" -#include "esp_gap_ble_api.h" -#include "esp_gattc_api.h" -#include "esp_gatt_defs.h" -#include "esp_bt_main.h" -#include "esp_system.h" -#include "esp_gatt_common_api.h" -#include "esp_log.h" -#include "freertos/FreeRTOS.h" - -#define GATTC_TAG "GATTC_SPP_DEMO" -#define PROFILE_NUM 1 -#define PROFILE_APP_ID 0 -#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 ESP_GATT_SPP_SERVICE_UUID {0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E} -#define SCAN_ALL_THE_TIME 0 - -struct gattc_profile_inst { - esp_gattc_cb_t gattc_cb; - uint16_t gattc_if; - uint16_t app_id; - uint16_t conn_id; - uint16_t service_start_handle; - uint16_t service_end_handle; - uint16_t char_handle; - esp_bd_addr_t remote_bda; -}; - -enum{ - SPP_IDX_SVC, - - SPP_IDX_SPP_DATA_RECV_VAL, - - SPP_IDX_SPP_DATA_NTY_VAL, - SPP_IDX_SPP_DATA_NTF_CFG, - - SPP_IDX_SPP_COMMAND_VAL, - - SPP_IDX_SPP_STATUS_VAL, - SPP_IDX_SPP_STATUS_CFG, - -#ifdef SUPPORT_HEARTBEAT - SPP_IDX_SPP_HEARTBEAT_VAL, - SPP_IDX_SPP_HEARTBEAT_CFG, -#endif - - SPP_IDX_NB, -}; - -///Declare static functions -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 gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param); - -/* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */ -static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = { - [PROFILE_APP_ID] = { - .gattc_cb = gattc_profile_event_handler, - .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */ - }, -}; - -static esp_ble_scan_params_t ble_scan_params = { - .scan_type = BLE_SCAN_TYPE_ACTIVE, - .own_addr_type = BLE_ADDR_TYPE_PUBLIC, - .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL, - .scan_interval = 0x50, - .scan_window = 0x30, - .scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE -}; - -static const char device_name[] = "yimei_ble"; -static bool is_connect = false; -static uint16_t spp_conn_id = 0; -static uint16_t spp_mtu_size = 23; -static uint16_t cmd = 0; -static uint16_t spp_srv_start_handle = 0; -static uint16_t spp_srv_end_handle = 0; -static uint16_t spp_gattc_if = 0xff; -static char * notify_value_p = NULL; -static int notify_value_offset = 0; -static int notify_value_count = 0; -static uint16_t count = SPP_IDX_NB; -static esp_gattc_db_elem_t *db = NULL; -static esp_ble_gap_cb_param_t scan_rst; -static xQueueHandle cmd_reg_queue = NULL; -QueueHandle_t spp_uart_queue = NULL; - -#ifdef SUPPORT_HEARTBEAT -static uint8_t heartbeat_s[9] = {'E','s','p','r','e','s','s','i','f'}; -static xQueueHandle cmd_heartbeat_queue = NULL; -#endif - -static esp_bt_uuid_t spp_service_uuid = { - .len = ESP_UUID_LEN_128, - .uuid = {.uuid128 = ESP_GATT_SPP_SERVICE_UUID,}, -}; - -static void notify_event_handler(esp_ble_gattc_cb_param_t * p_data) -{ - uint8_t handle = 0; - - if(p_data->notify.is_notify == true){ - ESP_LOGI(GATTC_TAG,"+NOTIFY:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len); - }else{ - ESP_LOGI(GATTC_TAG,"+INDICATE:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len); - } - handle = p_data->notify.handle; - if(db == NULL) { - ESP_LOGE(GATTC_TAG, " %s db is NULL\n", __func__); - return; - } - if(handle == db[SPP_IDX_SPP_DATA_NTY_VAL].attribute_handle){ -#ifdef SPP_DEBUG_MODE - esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len); -#else - if((p_data->notify.value[0] == '#')&&(p_data->notify.value[1] == '#')){ - if((++notify_value_count) != p_data->notify.value[3]){ - if(notify_value_p != NULL){ - free(notify_value_p); - } - notify_value_count = 0; - notify_value_p = NULL; - notify_value_offset = 0; - ESP_LOGE(GATTC_TAG,"notify value count is not continuous,%s\n",__func__); - return; - } - if(p_data->notify.value[3] == 1){ - notify_value_p = (char *)malloc(((spp_mtu_size-7)*(p_data->notify.value[2]))*sizeof(char)); - if(notify_value_p == NULL){ - ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__); - notify_value_count = 0; - return; - } - memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4)); - if(p_data->notify.value[2] == p_data->notify.value[3]){ - uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset)); - free(notify_value_p); - notify_value_p = NULL; - notify_value_offset = 0; - return; - } - notify_value_offset += (p_data->notify.value_len - 4); - }else if(p_data->notify.value[3] <= p_data->notify.value[2]){ - memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4)); - if(p_data->notify.value[3] == p_data->notify.value[2]){ - uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset)); - free(notify_value_p); - notify_value_count = 0; - notify_value_p = NULL; - notify_value_offset = 0; - return; - } - notify_value_offset += (p_data->notify.value_len - 4); - } - }else{ - uart_write_bytes(UART_NUM_0, (char *)(p_data->notify.value), p_data->notify.value_len); - } -#endif - }else if(handle == ((db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle)){ - esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len); - //TODO:server notify status characteristic - }else{ - esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len); - } -} - -static void free_gattc_srv_db(void) -{ - is_connect = false; - spp_gattc_if = 0xff; - spp_conn_id = 0; - spp_mtu_size = 23; - cmd = 0; - spp_srv_start_handle = 0; - spp_srv_end_handle = 0; - notify_value_p = NULL; - notify_value_offset = 0; - notify_value_count = 0; - if(db){ - free(db); - db = NULL; - } -} - -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; - esp_err_t err; - - switch(event){ - case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: { - if((err = param->scan_param_cmpl.status) != ESP_BT_STATUS_SUCCESS){ - ESP_LOGE(GATTC_TAG, "Scan param set failed: %s", esp_err_to_name(err)); - break; - } - //the unit of the duration is second - uint32_t duration = 0xFFFF; - ESP_LOGI(GATTC_TAG, "Enable Ble Scan:during time 0x%04X minutes.",duration); - esp_ble_gap_start_scanning(duration); - break; - } - case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT: - //scan start complete event to indicate scan start successfully or failed - if ((err = param->scan_start_cmpl.status) != ESP_BT_STATUS_SUCCESS) { - ESP_LOGE(GATTC_TAG, "Scan start failed: %s", esp_err_to_name(err)); - break; - } - ESP_LOGI(GATTC_TAG, "Scan start successed"); - break; - case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT: - if ((err = param->scan_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS) { - ESP_LOGE(GATTC_TAG, "Scan stop failed: %s", esp_err_to_name(err)); - break; - } - ESP_LOGI(GATTC_TAG, "Scan stop successed"); - if (is_connect == false) { - ESP_LOGI(GATTC_TAG, "Connect to the remote device."); - esp_ble_gattc_open(gl_profile_tab[PROFILE_APP_ID].gattc_if, scan_rst.scan_rst.bda, scan_rst.scan_rst.ble_addr_type, true); - } - 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: - esp_log_buffer_hex(GATTC_TAG, scan_result->scan_rst.bda, 6); - ESP_LOGI(GATTC_TAG, "Searched Adv Data Len %d, Scan Response Len %d", scan_result->scan_rst.adv_data_len, scan_result->scan_rst.scan_rsp_len); - adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len); - ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d", adv_name_len); - esp_log_buffer_char(GATTC_TAG, adv_name, adv_name_len); - ESP_LOGI(GATTC_TAG, "\n"); - if (adv_name != NULL) { - if ( strncmp((char *)adv_name, device_name, adv_name_len) == 0) { - memcpy(&(scan_rst), scan_result, sizeof(esp_ble_gap_cb_param_t)); - esp_ble_gap_stop_scanning(); - } - } - break; - case ESP_GAP_SEARCH_INQ_CMPL_EVT: - break; - default: - break; - } - break; - } - case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT: - if ((err = param->adv_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS){ - ESP_LOGE(GATTC_TAG, "Adv stop failed: %s", esp_err_to_name(err)); - }else { - ESP_LOGI(GATTC_TAG, "Stop adv successfully"); - } - 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) -{ - ESP_LOGI(GATTC_TAG, "EVT %d, gattc if %d", event, gattc_if); - - /* If event is register event, store the gattc_if for each profile */ - if (event == ESP_GATTC_REG_EVT) { - if (param->reg.status == ESP_GATT_OK) { - gl_profile_tab[param->reg.app_id].gattc_if = gattc_if; - } else { - ESP_LOGI(GATTC_TAG, "Reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status); - return; - } - } - /* If the gattc_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 (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */ - gattc_if == gl_profile_tab[idx].gattc_if) { - if (gl_profile_tab[idx].gattc_cb) { - gl_profile_tab[idx].gattc_cb(event, gattc_if, param); - } - } - } - } while (0); -} - -static void gattc_profile_event_handler(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param) -{ - esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param; - - switch (event) { - case ESP_GATTC_REG_EVT: - ESP_LOGI(GATTC_TAG, "REG EVT, set scan params"); - esp_ble_gap_set_scan_params(&ble_scan_params); - break; - case ESP_GATTC_CONNECT_EVT: - ESP_LOGI(GATTC_TAG, "ESP_GATTC_CONNECT_EVT: conn_id=%d, gatt_if = %d", spp_conn_id, gattc_if); - ESP_LOGI(GATTC_TAG, "REMOTE BDA:"); - esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_APP_ID].remote_bda, sizeof(esp_bd_addr_t)); - spp_gattc_if = gattc_if; - is_connect = true; - spp_conn_id = p_data->connect.conn_id; - memcpy(gl_profile_tab[PROFILE_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t)); - esp_ble_gattc_search_service(spp_gattc_if, spp_conn_id, &spp_service_uuid); - break; - case ESP_GATTC_DISCONNECT_EVT: - ESP_LOGI(GATTC_TAG, "disconnect"); - free_gattc_srv_db(); - esp_ble_gap_start_scanning(SCAN_ALL_THE_TIME); - break; - case ESP_GATTC_SEARCH_RES_EVT: - ESP_LOGI(GATTC_TAG, "ESP_GATTC_SEARCH_RES_EVT: start_handle = %d, end_handle = %d",p_data->search_res.start_handle,p_data->search_res.end_handle); - for (int i = 15; i >= 0; i--) - { - ESP_LOGI("uuid","UUID[%d] = %d",i,p_data->search_res.srvc_id.uuid.uuid.uuid128[i]); - } - - spp_srv_start_handle = p_data->search_res.start_handle; - spp_srv_end_handle = p_data->search_res.end_handle; - break; - case ESP_GATTC_SEARCH_CMPL_EVT: - ESP_LOGI(GATTC_TAG, "SEARCH_CMPL: conn_id = %x, status %d", spp_conn_id, p_data->search_cmpl.status); - esp_ble_gattc_send_mtu_req(gattc_if, spp_conn_id); - break; - case ESP_GATTC_REG_FOR_NOTIFY_EVT: { - ESP_LOGI(GATTC_TAG,"Index = %d,status = %d,handle = %d\n",cmd, p_data->reg_for_notify.status, p_data->reg_for_notify.handle); - if(p_data->reg_for_notify.status != ESP_GATT_OK){ - ESP_LOGE(GATTC_TAG, "ESP_GATTC_REG_FOR_NOTIFY_EVT, status = %d", p_data->reg_for_notify.status); - break; - } - uint16_t notify_en = 1; - esp_ble_gattc_write_char_descr( - spp_gattc_if, - spp_conn_id, - (db+cmd+1)->attribute_handle, - sizeof(notify_en), - (uint8_t *)¬ify_en, - ESP_GATT_WRITE_TYPE_RSP, - ESP_GATT_AUTH_REQ_NONE); - - break; - } - case ESP_GATTC_NOTIFY_EVT: - ESP_LOGI(GATTC_TAG,"ESP_GATTC_NOTIFY_EVT\n"); - notify_event_handler(p_data); - break; - case ESP_GATTC_READ_CHAR_EVT: - ESP_LOGI(GATTC_TAG,"ESP_GATTC_READ_CHAR_EVT\n"); - break; - case ESP_GATTC_WRITE_CHAR_EVT: - ESP_LOGI(GATTC_TAG,"ESP_GATTC_WRITE_CHAR_EVT:status = %d,handle = %d", param->write.status, param->write.handle); - if(param->write.status != ESP_GATT_OK){ - ESP_LOGE(GATTC_TAG, "ESP_GATTC_WRITE_CHAR_EVT, error status = %d", p_data->write.status); - break; - } - break; - case ESP_GATTC_PREP_WRITE_EVT: - break; - case ESP_GATTC_EXEC_EVT: - break; - case ESP_GATTC_WRITE_DESCR_EVT: - ESP_LOGI(GATTC_TAG,"ESP_GATTC_WRITE_DESCR_EVT: status =%d,handle = %d \n", p_data->write.status, p_data->write.handle); - if(p_data->write.status != ESP_GATT_OK){ - ESP_LOGE(GATTC_TAG, "ESP_GATTC_WRITE_DESCR_EVT, error status = %d", p_data->write.status); - break; - } - switch(cmd){ - case SPP_IDX_SPP_DATA_NTY_VAL: - cmd = SPP_IDX_SPP_STATUS_VAL; - xQueueSend(cmd_reg_queue, &cmd,10/portTICK_PERIOD_MS); - break; - case SPP_IDX_SPP_STATUS_VAL: -#ifdef SUPPORT_HEARTBEAT - cmd = SPP_IDX_SPP_HEARTBEAT_VAL; - xQueueSend(cmd_reg_queue, &cmd, 10/portTICK_PERIOD_MS); -#endif - break; -#ifdef SUPPORT_HEARTBEAT - case SPP_IDX_SPP_HEARTBEAT_VAL: - xQueueSend(cmd_heartbeat_queue, &cmd, 10/portTICK_PERIOD_MS); - break; -#endif - default: - break; - }; - break; - case ESP_GATTC_CFG_MTU_EVT: - if(p_data->cfg_mtu.status != ESP_OK){ - break; - } - ESP_LOGI(GATTC_TAG,"+MTU:%d\n", p_data->cfg_mtu.mtu); - spp_mtu_size = p_data->cfg_mtu.mtu; - - db = (esp_gattc_db_elem_t *)malloc(count*sizeof(esp_gattc_db_elem_t)); - if(db == NULL){ - ESP_LOGE(GATTC_TAG,"%s:malloc db falied\n",__func__); - break; - } - if(esp_ble_gattc_get_db(spp_gattc_if, spp_conn_id, spp_srv_start_handle, spp_srv_end_handle, db, &count) != ESP_GATT_OK){ - ESP_LOGE(GATTC_TAG,"%s:get db falied\n",__func__); - break; - } - if(count != SPP_IDX_NB){ - ESP_LOGE(GATTC_TAG,"%s:get db count != SPP_IDX_NB, count = %d, SPP_IDX_NB = %d\n",__func__,count,SPP_IDX_NB); - break; - } - for(int i = 0;i < SPP_IDX_NB;i++){ - switch((db+i)->type){ - case ESP_GATT_DB_PRIMARY_SERVICE: - ESP_LOGI(GATTC_TAG,"attr_type = PRIMARY_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ - (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); - break; - case ESP_GATT_DB_SECONDARY_SERVICE: - ESP_LOGI(GATTC_TAG,"attr_type = SECONDARY_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ - (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); - break; - case ESP_GATT_DB_CHARACTERISTIC: - ESP_LOGI(GATTC_TAG,"attr_type = CHARACTERISTIC,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ - (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); - break; - case ESP_GATT_DB_DESCRIPTOR: - ESP_LOGI(GATTC_TAG,"attr_type = DESCRIPTOR,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ - (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); - break; - case ESP_GATT_DB_INCLUDED_SERVICE: - ESP_LOGI(GATTC_TAG,"attr_type = INCLUDED_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ - (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); - break; - case ESP_GATT_DB_ALL: - ESP_LOGI(GATTC_TAG,"attr_type = ESP_GATT_DB_ALL,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",\ - (db+i)->attribute_handle, (db+i)->start_handle, (db+i)->end_handle, (db+i)->properties, (db+i)->uuid.uuid.uuid16); - break; - default: - break; - } - } - cmd = SPP_IDX_SPP_DATA_NTY_VAL; - xQueueSend(cmd_reg_queue, &cmd, 10/portTICK_PERIOD_MS); - break; - case ESP_GATTC_SRVC_CHG_EVT: - break; - default: - break; - } -} - -void spp_client_reg_task(void* arg) -{ - uint16_t cmd_id; - for(;;) { - vTaskDelay(100 / portTICK_PERIOD_MS); - if(xQueueReceive(cmd_reg_queue, &cmd_id, portMAX_DELAY)) { - if(db != NULL) { - if(cmd_id == SPP_IDX_SPP_DATA_NTY_VAL){ - ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_DATA_NTY_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_DATA_NTY_VAL)->attribute_handle); - esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_DATA_NTY_VAL)->attribute_handle); - }else if(cmd_id == SPP_IDX_SPP_STATUS_VAL){ - ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_STATUS_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle); - esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_STATUS_VAL)->attribute_handle); - } -#ifdef SUPPORT_HEARTBEAT - else if(cmd_id == SPP_IDX_SPP_HEARTBEAT_VAL){ - ESP_LOGI(GATTC_TAG,"Index = %d,UUID = 0x%04x, handle = %d \n", cmd_id, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->uuid.uuid.uuid16, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle); - esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda, (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle); - } -#endif - } - } - } -} - -#ifdef SUPPORT_HEARTBEAT -void spp_heart_beat_task(void * arg) -{ - uint16_t cmd_id; - - for(;;) { - vTaskDelay(50 / portTICK_PERIOD_MS); - if(xQueueReceive(cmd_heartbeat_queue, &cmd_id, portMAX_DELAY)) { - while(1){ - if((is_connect == true) && (db != NULL) && ((db+SPP_IDX_SPP_HEARTBEAT_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))){ - esp_ble_gattc_write_char( spp_gattc_if, - spp_conn_id, - (db+SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle, - sizeof(heartbeat_s), - (uint8_t *)heartbeat_s, - ESP_GATT_WRITE_TYPE_RSP, - ESP_GATT_AUTH_REQ_NONE); - vTaskDelay(5000 / portTICK_PERIOD_MS); - }else{ - ESP_LOGI(GATTC_TAG,"disconnect\n"); - break; - } - } - } - } -} -#endif - -void ble_client_appRegister(void) -{ - esp_err_t status; - char err_msg[20]; - - ESP_LOGI(GATTC_TAG, "register callback"); - - //register the scan callback function to the gap module - if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) { - ESP_LOGE(GATTC_TAG, "gap register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg))); - return; - } - //register the callback function to the gattc module - if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) { - ESP_LOGE(GATTC_TAG, "gattc register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg))); - return; - } - esp_ble_gattc_app_register(PROFILE_APP_ID); - - esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(200); - if (local_mtu_ret){ - ESP_LOGE(GATTC_TAG, "set local MTU failed: %s", esp_err_to_name_r(local_mtu_ret, err_msg, sizeof(err_msg))); - } - - cmd_reg_queue = xQueueCreate(10, sizeof(uint32_t)); - xTaskCreate(spp_client_reg_task, "spp_client_reg_task", 2048, NULL, 10, NULL); - -#ifdef SUPPORT_HEARTBEAT - cmd_heartbeat_queue = xQueueCreate(10, sizeof(uint32_t)); - xTaskCreate(spp_heart_beat_task, "spp_heart_beat_task", 2048, NULL, 10, NULL); -#endif -} - -void uart_task(void *pvParameters) -{ - uart_event_t event; - for (;;) { - //Waiting for UART event. - if (xQueueReceive(spp_uart_queue, (void * )&event, (portTickType)portMAX_DELAY)) { - switch (event.type) { - //Event of UART receving data - case UART_DATA: - if (event.size && (is_connect == true) && (db != NULL) && ((db+SPP_IDX_SPP_DATA_RECV_VAL)->properties & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR | ESP_GATT_CHAR_PROP_BIT_WRITE))) { - uint8_t * temp = NULL; - temp = (uint8_t *)malloc(sizeof(uint8_t)*event.size); - if(temp == NULL){ - ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n", __func__, __LINE__); - break; - } - memset(temp, 0x0, event.size); - uart_read_bytes(UART_NUM_0,temp,event.size,portMAX_DELAY); - esp_ble_gattc_write_char( spp_gattc_if, - spp_conn_id, - (db+SPP_IDX_SPP_DATA_RECV_VAL)->attribute_handle, - event.size, - temp, - ESP_GATT_WRITE_TYPE_RSP, - ESP_GATT_AUTH_REQ_NONE); - free(temp); - } - break; - default: - break; - } - } - } - vTaskDelete(NULL); -} - -static void spp_uart_init(void) -{ - uart_config_t uart_config = { - .baud_rate = 115200, - .data_bits = UART_DATA_8_BITS, - .parity = UART_PARITY_DISABLE, - .stop_bits = UART_STOP_BITS_1, - .flow_ctrl = UART_HW_FLOWCTRL_RTS, - .rx_flow_ctrl_thresh = 122, - .source_clk = UART_SCLK_APB, - }; - - //Install UART driver, and get the queue. - uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_uart_queue, 0); - //Set UART parameters - uart_param_config(UART_NUM_0, &uart_config); - //Set UART pins - uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); - xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL); -} - -void app_main(void) -{ - esp_err_t 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(); - - nvs_flash_init(); - ret = esp_bt_controller_init(&bt_cfg); - if (ret) { - ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret)); - return; - } - - ret = esp_bt_controller_enable(ESP_BT_MODE_BLE); - if (ret) { - ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret)); - return; - } - - ESP_LOGI(GATTC_TAG, "%s init bluetooth\n", __func__); - ret = esp_bluedroid_init(); - if (ret) { - ESP_LOGE(GATTC_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret)); - return; - } - ret = esp_bluedroid_enable(); - if (ret) { - ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret)); - return; - } - - ble_client_appRegister(); - spp_uart_init(); -}