1 // Copyright 2015-2017 Espressif Systems (Shanghai) PTE LTD
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
7 // http://www.apache.org/licenses/LICENSE-2.0
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
17 /****************************************************************************
19 * This file is for ble spp client demo.
21 ****************************************************************************/
27 #include "controller.h"
28 #include "driver/uart.h"
31 #include "nvs_flash.h"
32 #include "esp_bt_device.h"
33 #include "esp_gap_ble_api.h"
34 #include "esp_gattc_api.h"
35 #include "esp_gatt_defs.h"
36 #include "esp_bt_main.h"
37 #include "esp_system.h"
39 #include "esp_gatt_common_api.h"
41 #define GATTC_TAG "GATTC_SPP_DEMO"
42 #ifdef SUPPORT_NEW_GATTC_API
44 #define PROFILE_APP_ID 0
45 #define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
46 #define BT_BD_ADDR_HEX(addr) addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]
48 #define SPP_SRV_INDEX 1
49 #define SPP_DATA_RECV_CHAR_INDEX 1
50 #define SPP_DATA_NTFY_CHAR_INDEX 2
51 #define SPP_CMD_CHAR_INDEX 3
52 #define SPP_STATUS_CHAR_INDEX 4
53 #define SPP_HEARTBEAT_CHAR_INDEX 5
57 //#define SUPPORT_HEARTBEAT
60 typedef struct spp_ble_gattc_char_descr {
63 esp_gatt_id_t descr_id;
64 struct spp_ble_gattc_char_descr *next;
65 } spp_ble_gattc_char_descr_t;
67 typedef struct spp_ble_gattc_char {
71 esp_gatt_srvc_id_t srvc_id;
72 esp_gatt_id_t char_id;
73 esp_gatt_char_prop_t char_prop;
74 spp_ble_gattc_char_descr_t * char_descr;
75 struct spp_ble_gattc_char *next;
76 } spp_ble_gattc_char_t;
80 spp_ble_gattc_char_t * pfirst;
81 spp_ble_gattc_char_t * plast;
82 } spp_ble_gattc_char_head;
84 typedef struct at_ble_gattc_srv {
87 esp_gatt_srvc_id_t srvc_id;
88 spp_ble_gattc_char_head * gattc_srv_char_head;
89 struct at_ble_gattc_srv *next;
90 } spp_ble_gattc_srv_t;
94 spp_ble_gattc_srv_t * pfirst;
95 spp_ble_gattc_srv_t * plast;
96 } spp_ble_gattc_srv_head;
98 static spp_ble_gattc_srv_head pAtGattcSrvHead = {
104 struct gattc_profile_inst {
105 esp_gattc_cb_t gattc_cb;
109 esp_bd_addr_t remote_bda;
112 ///Declare static functions
113 static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
114 static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param);
115 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);
117 /* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */
118 static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {
120 .gattc_cb = gattc_profile_event_handler,
121 .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
125 static esp_ble_scan_params_t ble_scan_params = {
126 .scan_type = BLE_SCAN_TYPE_ACTIVE,
127 .own_addr_type = BLE_ADDR_TYPE_PUBLIC,
128 .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
129 .scan_interval = 0x50,
134 static const char device_name[] = "ESP_SPP_SERVER";
135 static bool is_connect = false;
136 static uint16_t spp_conn_id = 0;
137 static uint16_t spp_mtu_size = 23;
138 static uint16_t cmd = 0;
139 static uint16_t wr_descr_ccc_num = 0;
140 static uint16_t spp_gattc_if = 0xff;
141 static int need_notify_number = 0;
142 static int char_descr_index_count = 0;
143 static char * notify_value_p = NULL;
144 static int notify_value_offset = 0;
145 static int notify_value_count = 0;
146 static spp_ble_gattc_srv_t * temp_srv_p = NULL;
147 static spp_ble_gattc_char_t * notify_char_pp = NULL;
148 static spp_ble_gattc_char_t notify_char_p[3] ;
149 static spp_ble_gattc_char_t * temp_gattc_char_p1 = NULL;
150 static spp_ble_gattc_char_descr_t * notify_char_descr_p[2] = {NULL,NULL};
151 static spp_ble_gattc_char_descr_t * temp_char_descr_p = NULL;
152 static spp_ble_gattc_char_head * pGattcCharHead = NULL;
153 static esp_ble_gap_cb_param_t scan_rst;
154 static xQueueHandle cmd_reg_queue = NULL;
155 static xQueueHandle cmd_read_queue = NULL;
156 QueueHandle_t spp_uart_queue = NULL;
157 #ifdef SUPPORT_HEARTBEAT
158 static uint8_t heartbeat_s[9] = {'E','s','p','r','e','s','s','i','f'};
159 static xQueueHandle cmd_heartbeat_queue = NULL;
162 static void print_srv_node(void)
164 temp_srv_p = pAtGattcSrvHead.pfirst;
166 if(temp_srv_p == NULL){
167 ESP_LOGE(GATTC_TAG, "temp_srv_p == NULL,%s L#%d\n",__func__,__LINE__);
169 temp_srv_p = pAtGattcSrvHead.pfirst;
170 while(temp_srv_p != NULL){
171 ESP_LOGI(GATTC_TAG,"+SRV:No.%d,UUID:0x%04x\n", temp_srv_p->index,temp_srv_p->srvc_id.id.uuid.uuid.uuid16);
172 temp_srv_p = temp_srv_p->next;
176 static void get_char_and_descr(void)
178 pGattcCharHead = (spp_ble_gattc_char_head *)malloc(sizeof(spp_ble_gattc_char_head));
179 if(pGattcCharHead == NULL){
180 ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
184 pGattcCharHead->len = 0;
185 pGattcCharHead->pfirst = NULL;
186 pGattcCharHead->plast = NULL;
187 pAtGattcSrvHead.pfirst->gattc_srv_char_head = pGattcCharHead;
188 temp_srv_p = pAtGattcSrvHead.pfirst;
190 esp_ble_gattc_get_characteristic(spp_gattc_if, temp_srv_p->conn_id, &temp_srv_p->srvc_id, NULL);
193 static void Characteristic_Rd(int32_t srv_index,int32_t char_index)
195 spp_ble_gattc_char_t * pGattc_char_node = NULL;
197 temp_srv_p = pAtGattcSrvHead.pfirst;
198 if(temp_srv_p == NULL) {
199 ESP_LOGE(GATTC_TAG, "temp_srv_p == NULL,%s L#%d\n",__func__,__LINE__);
203 temp_srv_p = temp_srv_p->next;
204 if (temp_srv_p == NULL) {
205 ESP_LOGE(GATTC_TAG, "temp_srv_p == NULL,%s L#%d\n",__func__,__LINE__);
209 pGattcCharHead = temp_srv_p->gattc_srv_char_head;
210 if(pGattcCharHead == NULL){
211 ESP_LOGE(GATTC_TAG, "pGattcCharHead == NULL,%s L#%d\n",__func__,__LINE__);
215 pGattc_char_node = pGattcCharHead->pfirst;
216 if(pGattc_char_node == NULL) {
217 ESP_LOGE(GATTC_TAG, "pGattc_char_node == NULL,%s L#%d\n",__func__,__LINE__);
221 pGattc_char_node = pGattc_char_node->next;
222 if(pGattc_char_node == NULL){
223 ESP_LOGE(GATTC_TAG, "pGattc_char_node == NULL,%s L#%d\n",__func__,__LINE__);
228 esp_ble_gattc_read_char(spp_gattc_if, pGattc_char_node->conn_id, &pGattc_char_node->srvc_id, &pGattc_char_node->char_id, ESP_GATT_AUTH_REQ_NONE);
231 static void Characteristic_Wr(int32_t srv_index,int32_t char_index,char * s ,size_t length)
233 future_t **future_p = NULL;
235 spp_ble_gattc_char_t * pGattc_char_node;
236 uint8_t * spp_gattc_wr_buffer = NULL;
243 temp_srv_p = pAtGattcSrvHead.pfirst;
244 if(temp_srv_p == NULL) {
245 ESP_LOGE(GATTC_TAG, "temp_srv_p == NULL,%s L#%d\n",__func__,__LINE__);
249 temp_srv_p = temp_srv_p->next;
250 if (temp_srv_p == NULL) {
251 ESP_LOGE(GATTC_TAG, "temp_srv_p == NULL,%s L#%d\n",__func__,__LINE__);
256 pGattcCharHead = temp_srv_p->gattc_srv_char_head;
257 if(pGattcCharHead == NULL){
258 ESP_LOGE(GATTC_TAG, "pGattcCharHead == NULL,%s L#%d\n",__func__,__LINE__);
261 pGattc_char_node = pGattcCharHead->pfirst;
262 if (pGattc_char_node == NULL) {
263 ESP_LOGE(GATTC_TAG, "pGattc_char_node == NULL,%s L#%d\n",__func__,__LINE__);
267 pGattc_char_node = pGattc_char_node->next;
268 if(pGattc_char_node == NULL){
269 ESP_LOGE(GATTC_TAG, "pGattc_char_node == NULL,%s L#%d\n",__func__,__LINE__);
274 spp_gattc_wr_buffer = (uint8_t *)malloc(sizeof(uint8_t)*(len));
275 if(spp_gattc_wr_buffer == NULL){
276 ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
279 memcpy(spp_gattc_wr_buffer,s,len);
281 if((pGattc_char_node->char_prop & (ESP_GATT_CHAR_PROP_BIT_WRITE_NR|ESP_GATT_CHAR_PROP_BIT_WRITE)) == 0){
282 ESP_LOGE(GATTC_TAG,"char_prop do not allow write\n");
283 free(spp_gattc_wr_buffer);
287 future_p = btc_main_get_future_p(BTC_MAIN_ENABLE_FUTURE);
288 *future_p = future_new();
289 if (*future_p == NULL) {
290 ESP_LOGE(GATTC_TAG,"%s failed\n", __func__);
293 esp_ble_gattc_write_char(spp_gattc_if, pGattc_char_node->conn_id, &pGattc_char_node->srvc_id, &pGattc_char_node->char_id, len,spp_gattc_wr_buffer, ESP_GATT_WRITE_TYPE_RSP, ESP_GATT_AUTH_REQ_NONE);
294 free(spp_gattc_wr_buffer);
295 if(future_await(*future_p) == FUTURE_FAIL) {
296 ESP_LOGE(GATTC_TAG,"%s failed\n", __func__);
303 static void store_srv_info(esp_ble_gattc_cb_param_t * p_data)
305 spp_ble_gattc_srv_t * pGattc_srv_node = NULL;
307 pGattc_srv_node = (spp_ble_gattc_srv_t *)malloc(sizeof(spp_ble_gattc_srv_t));
308 if (pGattc_srv_node == NULL) {
309 ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
312 pGattc_srv_node->conn_id = p_data->search_res.conn_id;
313 pGattc_srv_node->next = NULL;
314 pGattc_srv_node->gattc_srv_char_head = NULL;
315 pGattc_srv_node->index = pAtGattcSrvHead.len + 1;
316 pGattc_srv_node->srvc_id.is_primary = p_data->search_res.srvc_id.is_primary;
317 pGattc_srv_node->srvc_id.id.inst_id = p_data->search_res.srvc_id.id.inst_id;
318 pGattc_srv_node->srvc_id.id.uuid.len = p_data->search_res.srvc_id.id.uuid.len;
319 pGattc_srv_node->srvc_id.id.uuid.uuid.uuid16 = p_data->search_res.srvc_id.id.uuid.uuid.uuid16;
321 if (pAtGattcSrvHead.len == 0) {
322 pAtGattcSrvHead.len++;
323 pAtGattcSrvHead.pfirst = pGattc_srv_node;
324 pAtGattcSrvHead.plast = pGattc_srv_node;
326 pAtGattcSrvHead.len++;
327 pAtGattcSrvHead.plast->next = pGattc_srv_node;
328 pAtGattcSrvHead.plast = pGattc_srv_node;
332 static void store_char_info(esp_ble_gattc_cb_param_t * p_data)
334 spp_ble_gattc_char_t * pGattc_char_node = NULL;
336 pGattc_char_node = (spp_ble_gattc_char_t *)malloc(sizeof(spp_ble_gattc_char_t));
337 if(pGattc_char_node == NULL){
338 ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
341 pGattc_char_node->srv_index = temp_srv_p->index;
342 pGattc_char_node->char_descr = NULL;
343 pGattc_char_node->conn_id = p_data->get_char.conn_id;
344 pGattc_char_node->next = NULL;
345 pGattc_char_node->index = pGattcCharHead->len + 1;
346 pGattc_char_node->srvc_id.is_primary = p_data->get_char.srvc_id.is_primary;
347 pGattc_char_node->srvc_id.id.inst_id = p_data->get_char.srvc_id.id.inst_id;
348 pGattc_char_node->srvc_id.id.uuid.len = p_data->get_char.srvc_id.id.uuid.len;
349 pGattc_char_node->srvc_id.id.uuid.uuid.uuid16 = p_data->get_char.srvc_id.id.uuid.uuid.uuid16;
351 pGattc_char_node->char_id.inst_id = p_data->get_char.char_id.inst_id;
352 pGattc_char_node->char_id.uuid.len = p_data->get_char.char_id.uuid.len;
353 pGattc_char_node->char_prop = p_data->get_char.char_prop;
354 pGattc_char_node->char_id.uuid.uuid.uuid16 = p_data->get_char.char_id.uuid.uuid.uuid16;
356 temp_gattc_char_p1 = pGattc_char_node;
358 if (pGattcCharHead->len == 0) {
359 pGattcCharHead->len++;
360 pGattcCharHead->pfirst = pGattc_char_node;
361 pGattcCharHead->plast = pGattc_char_node;
363 pGattcCharHead->len++;
364 pGattcCharHead->plast->next = pGattc_char_node;
365 pGattcCharHead->plast = pGattc_char_node;
367 esp_ble_gattc_get_descriptor(spp_gattc_if, pGattc_char_node->conn_id, &pGattc_char_node->srvc_id, &pGattc_char_node->char_id, NULL);
370 static void store_desc_info(esp_ble_gattc_cb_param_t * p_data)
372 spp_ble_gattc_char_descr_t * pGattc_char_node_descr = NULL;
374 temp_char_descr_p = temp_gattc_char_p1->char_descr;
375 pGattc_char_node_descr = (spp_ble_gattc_char_descr_t *)malloc(sizeof(spp_ble_gattc_char_descr_t));
376 if(pGattc_char_node_descr == NULL){
377 ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
380 pGattc_char_node_descr->conn_id = p_data->get_descr.conn_id;
381 pGattc_char_node_descr->char_descr_index = ++char_descr_index_count;
382 if (temp_char_descr_p == NULL)
383 temp_gattc_char_p1->char_descr = pGattc_char_node_descr;
385 while (temp_char_descr_p->next != NULL) {
386 temp_char_descr_p = temp_char_descr_p->next;
388 temp_char_descr_p->next = pGattc_char_node_descr;
390 pGattc_char_node_descr->next = NULL;
391 pGattc_char_node_descr->descr_id.inst_id = p_data->get_descr.descr_id.inst_id;
392 pGattc_char_node_descr->descr_id.uuid.len = p_data->get_descr.descr_id.uuid.len;
394 pGattc_char_node_descr->descr_id.uuid.uuid.uuid16 = p_data->get_descr.descr_id.uuid.uuid.uuid16;
395 if((p_data->get_descr.descr_id.uuid.uuid.uuid16 == 0x2902)&&(need_notify_number<3)){
396 memset(&(notify_char_p[need_notify_number]),0x0,sizeof(spp_ble_gattc_char_t));
397 memcpy(&(notify_char_p[need_notify_number]),temp_gattc_char_p1,sizeof(spp_ble_gattc_char_t));
398 notify_char_descr_p[need_notify_number] = pGattc_char_node_descr;
399 ESP_LOGI(GATTC_TAG,"need_notify_number=%d\n",need_notify_number);
400 ESP_LOGI(GATTC_TAG,"- srvc_id = 0x%04x, char_id = 0x%04x \n", notify_char_p[need_notify_number].srvc_id.id.uuid.uuid.uuid16, notify_char_p[need_notify_number].char_id.uuid.uuid.uuid16);
401 need_notify_number++;
403 esp_ble_gattc_get_descriptor(spp_gattc_if, temp_gattc_char_p1->conn_id, &temp_gattc_char_p1->srvc_id, &temp_gattc_char_p1->char_id, &pGattc_char_node_descr->descr_id);
406 static void notify_event_handler(esp_ble_gattc_cb_param_t * p_data)
408 uint8_t gattc_srv_index_for_port = 0;
409 uint8_t gattc_char_index_for_port = 0;
411 temp_srv_p = pAtGattcSrvHead.pfirst;
412 while(temp_srv_p != NULL){
413 if(temp_srv_p->srvc_id.id.uuid.uuid.uuid16 == p_data->notify.srvc_id.id.uuid.uuid.uuid16){
414 gattc_srv_index_for_port = temp_srv_p->index;
415 pGattcCharHead = temp_srv_p->gattc_srv_char_head;
416 if(pGattcCharHead != NULL){
417 notify_char_pp = pGattcCharHead->pfirst;
418 while(notify_char_pp != NULL){
419 if(notify_char_pp->char_id.uuid.uuid.uuid16== p_data->notify.char_id.uuid.uuid.uuid16){
420 gattc_char_index_for_port = notify_char_pp->index;
422 notify_char_pp = notify_char_pp->next;
426 temp_srv_p = temp_srv_p->next;
428 if(p_data->notify.is_notify == true){
429 ESP_LOGI(GATTC_TAG,"+NOTIFY:%d,%d,%d,",gattc_srv_index_for_port,gattc_char_index_for_port,p_data->notify.value_len);
431 ESP_LOGI(GATTC_TAG,"+INDICATE:%d,%d,%d,",gattc_srv_index_for_port,gattc_char_index_for_port,p_data->notify.value_len);
433 if((gattc_srv_index_for_port == SPP_SRV_INDEX)&&(gattc_char_index_for_port == SPP_DATA_NTFY_CHAR_INDEX)){
434 #ifdef SPP_DEBUG_MODE
435 esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len);
437 if((p_data->notify.value[0] == '#')&&(p_data->notify.value[1] == '#')){
438 if((++notify_value_count) != p_data->notify.value[3]){
439 if(notify_value_p != NULL){
440 free(notify_value_p);
442 notify_value_count = 0;
443 notify_value_p = NULL;
444 notify_value_offset = 0;
445 ESP_LOGE(GATTC_TAG,"notify value count is not continuous,%s\n",__func__);
448 if(p_data->notify.value[3] == 1){
449 notify_value_p = (char *)malloc(((spp_mtu_size-7)*(p_data->notify.value[2]))*sizeof(char));
450 if(notify_value_p == NULL){
451 ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
452 notify_value_count = 0;
455 memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4));
456 if(p_data->notify.value[2] == p_data->notify.value[3]){
457 uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
458 free(notify_value_p);
459 notify_value_p = NULL;
460 notify_value_offset = 0;
463 notify_value_offset += (p_data->notify.value_len - 4);
464 }else if(p_data->notify.value[3] <= p_data->notify.value[2]){
465 memcpy((notify_value_p + notify_value_offset),(p_data->notify.value + 4),(p_data->notify.value_len - 4));
466 if(p_data->notify.value[3] == p_data->notify.value[2]){
467 uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
468 free(notify_value_p);
469 notify_value_count = 0;
470 notify_value_p = NULL;
471 notify_value_offset = 0;
474 notify_value_offset += (p_data->notify.value_len - 4);
477 uart_write_bytes(UART_NUM_0, (char *)(p_data->notify.value), p_data->notify.value_len);
480 }else if((gattc_srv_index_for_port == SPP_SRV_INDEX)&&(gattc_char_index_for_port == SPP_STATUS_CHAR_INDEX)){
481 esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len);
482 //TODO:server notify status characteristic
484 esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len);
488 static void read_event_handler(esp_ble_gattc_cb_param_t * p_data)
490 uint8_t gattc_srv_index_for_port = 0;
491 uint8_t gattc_char_index_for_port = 0;
493 temp_srv_p = pAtGattcSrvHead.pfirst;
494 while(temp_srv_p != NULL){
495 if(temp_srv_p->srvc_id.id.uuid.uuid.uuid16 == p_data->notify.srvc_id.id.uuid.uuid.uuid16){
496 gattc_srv_index_for_port = temp_srv_p->index;
497 pGattcCharHead = temp_srv_p->gattc_srv_char_head;
498 if(pGattcCharHead != NULL){
499 notify_char_pp = pGattcCharHead->pfirst;
500 while(notify_char_pp != NULL){
501 if(notify_char_pp->char_id.uuid.uuid.uuid16== p_data->notify.char_id.uuid.uuid.uuid16){
502 gattc_char_index_for_port = notify_char_pp->index;
504 notify_char_pp = notify_char_pp->next;
508 temp_srv_p = temp_srv_p->next;
511 if((gattc_srv_index_for_port == SPP_SRV_INDEX)&&(gattc_char_index_for_port == SPP_STATUS_CHAR_INDEX)){
512 //TODO: read status characteristic
516 static void printf_char_and_descr(uint8_t srv_index)
518 spp_ble_gattc_char_t * temp_gattc_char_p = NULL;
519 spp_ble_gattc_char_descr_t * temp_gattc_char_descr_p = NULL;
521 temp_srv_p = pAtGattcSrvHead.pfirst;
523 if(temp_srv_p == NULL){
524 ESP_LOGE(GATTC_TAG, "srv = NULL\n");
527 temp_srv_p = temp_srv_p->next;
528 if(temp_srv_p == NULL){
529 ESP_LOGE(GATTC_TAG, "srv = NULL\n");
533 temp_gattc_char_p = temp_srv_p->gattc_srv_char_head->pfirst;
534 while(temp_gattc_char_p != NULL){
535 ESP_LOGI(GATTC_TAG,"+CHAR:%d,%d,UUID:0x%04x",temp_srv_p->index, temp_gattc_char_p->index,temp_gattc_char_p->char_id.uuid.uuid.uuid16);
537 temp_gattc_char_descr_p = temp_gattc_char_p->char_descr;
538 while(temp_gattc_char_descr_p != NULL){
539 ESP_LOGI(GATTC_TAG,"+DESC:%d,%d,%d,UUID:0x%04x",temp_srv_p->index, temp_gattc_char_p->index,temp_gattc_char_descr_p->char_descr_index,temp_gattc_char_descr_p->descr_id.uuid.uuid.uuid16);
540 temp_gattc_char_descr_p = temp_gattc_char_descr_p->next;
542 temp_gattc_char_p = temp_gattc_char_p->next;
547 static void free_gattc_srv_db(void)
549 spp_ble_gattc_srv_t * temp_service_p = NULL , * temp_service_pp = NULL;
550 spp_ble_gattc_char_head * temp_srv_char_head_p = NULL;
551 spp_ble_gattc_char_t * temp_gattc_char_node_p = NULL , *temp_gattc_char_node_pp =NULL;
552 spp_ble_gattc_char_descr_t * temp_gattc_char_descr_node_p = NULL,* temp_gattc_char_descr_node_pp = NULL;
554 temp_service_p = pAtGattcSrvHead.pfirst;
555 while(temp_service_p != NULL){
556 temp_srv_char_head_p = temp_service_p->gattc_srv_char_head;
557 temp_gattc_char_node_p = temp_srv_char_head_p->pfirst;
558 while(temp_gattc_char_node_p != NULL){
559 temp_gattc_char_node_pp = temp_gattc_char_node_p;
560 temp_gattc_char_descr_node_p = temp_gattc_char_node_pp->char_descr;
561 while(temp_gattc_char_descr_node_p != NULL){
562 temp_gattc_char_descr_node_pp = temp_gattc_char_descr_node_p;
563 temp_gattc_char_descr_node_p = temp_gattc_char_descr_node_p->next;
564 free(temp_gattc_char_descr_node_pp);
566 temp_gattc_char_node_p = temp_gattc_char_node_p->next;
567 free(temp_gattc_char_node_pp);
569 free(temp_srv_char_head_p);
571 temp_service_pp = temp_service_p;
572 temp_service_p = temp_service_p->next;
573 free(temp_service_pp);
575 pAtGattcSrvHead.len = 0;
576 pAtGattcSrvHead.pfirst = NULL;
577 pAtGattcSrvHead.plast = NULL;
582 wr_descr_ccc_num = 0;
584 need_notify_number = 0;
585 char_descr_index_count = 0;
586 notify_value_p = NULL;
587 notify_value_offset = 0;
588 notify_value_count = 0;
591 static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
593 uint8_t *adv_name = NULL;
594 uint8_t adv_name_len = 0;
597 case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT: {
598 if(param->scan_param_cmpl.status != ESP_BT_STATUS_SUCCESS){
599 ESP_LOGE(GATTC_TAG, "Scan param set failed");
602 //the unit of the duration is second
603 uint32_t duration = 0xFFFF;
604 ESP_LOGI(GATTC_TAG, "Enable Ble Scan:during time 0x%04X minutes.",duration);
605 esp_ble_gap_start_scanning(duration);
608 case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
609 //scan start complete event to indicate scan start successfully or failed
610 if (param->scan_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
611 ESP_LOGE(GATTC_TAG, "Scan start failed");
614 ESP_LOGI(GATTC_TAG, "Scan start successed");
616 case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
617 if (param->scan_stop_cmpl.status != ESP_BT_STATUS_SUCCESS) {
618 ESP_LOGE(GATTC_TAG, "Scan stop failed");
621 ESP_LOGI(GATTC_TAG, "Scan stop successed");
622 if (is_connect == false) {
623 ESP_LOGI(GATTC_TAG, "Connect to the remote device.");
624 esp_ble_gattc_open(gl_profile_tab[PROFILE_APP_ID].gattc_if, scan_rst.scan_rst.bda, true);
627 case ESP_GAP_BLE_SCAN_RESULT_EVT: {
628 esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
629 switch (scan_result->scan_rst.search_evt) {
630 case ESP_GAP_SEARCH_INQ_RES_EVT:
631 esp_log_buffer_hex(GATTC_TAG, scan_result->scan_rst.bda, 6);
632 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);
633 adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv,ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
634 ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d", adv_name_len);
635 esp_log_buffer_char(GATTC_TAG, adv_name, adv_name_len);
636 ESP_LOGI(GATTC_TAG, "\n");
637 if (adv_name != NULL) {
638 if ( strncmp((char *)adv_name, device_name, adv_name_len) == 0) {
639 memcpy(&(scan_rst), scan_result, sizeof(esp_ble_gap_cb_param_t));
640 esp_ble_gap_stop_scanning();
644 case ESP_GAP_SEARCH_INQ_CMPL_EVT:
651 case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
652 if (param->adv_stop_cmpl.status != ESP_BT_STATUS_SUCCESS){
653 ESP_LOGE(GATTC_TAG, "Adv stop failed");
655 ESP_LOGI(GATTC_TAG, "Stop adv successfully");
663 static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
665 ESP_LOGI(GATTC_TAG, "EVT %d, gattc if %d", event, gattc_if);
667 /* If event is register event, store the gattc_if for each profile */
668 if (event == ESP_GATTC_REG_EVT) {
669 if (param->reg.status == ESP_GATT_OK) {
670 gl_profile_tab[param->reg.app_id].gattc_if = gattc_if;
672 ESP_LOGI(GATTC_TAG, "Reg app failed, app_id %04x, status %d",param->reg.app_id,param->reg.status);
676 /* If the gattc_if equal to profile A, call profile A cb handler,
677 * so here call each profile's callback */
680 for (idx = 0; idx < PROFILE_NUM; idx++) {
681 if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
682 gattc_if == gl_profile_tab[idx].gattc_if) {
683 if (gl_profile_tab[idx].gattc_cb) {
684 gl_profile_tab[idx].gattc_cb(event, gattc_if, param);
691 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)
693 esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param;
696 case ESP_GATTC_REG_EVT:
697 ESP_LOGE(GATTC_TAG, "REG EVT, set scan params");
698 esp_ble_gap_set_scan_params(&ble_scan_params);
700 case ESP_GATTC_CONNECT_EVT:
701 spp_gattc_if = gattc_if;
703 spp_conn_id = p_data->connect.conn_id;
704 memcpy(gl_profile_tab[PROFILE_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
705 ESP_LOGI(GATTC_TAG, "ESP_GATTC_CONNECT_EVT: conn_id=%d, gatt_if = %d", spp_conn_id, gattc_if);
706 ESP_LOGI(GATTC_TAG, "REMOTE BDA:");
707 esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_APP_ID].remote_bda, sizeof(esp_bd_addr_t));
708 esp_ble_gattc_search_service(gattc_if, spp_conn_id, NULL);
710 case ESP_GATTC_DISCONNECT_EVT:
711 ESP_LOGI(GATTC_TAG, "disconnect");
713 esp_ble_gap_start_scanning(0xffff);
715 case ESP_GATTC_SEARCH_RES_EVT:
716 if((p_data->search_res.srvc_id.id.uuid.len == ESP_UUID_LEN_16)&&(p_data->search_res.srvc_id.id.uuid.uuid.uuid16 == 0x1800)){
717 ESP_LOGI(GATTC_TAG, "uuid == 0x1800\n");
720 if((p_data->search_res.srvc_id.id.uuid.len == ESP_UUID_LEN_16)&&(p_data->search_res.srvc_id.id.uuid.uuid.uuid16 == 0x1801)){
721 ESP_LOGI(GATTC_TAG, "uuid == 0x1801\n");
724 store_srv_info(p_data);
726 case ESP_GATTC_SEARCH_CMPL_EVT:
727 ESP_LOGI(GATTC_TAG, "SEARCH_CMPL: conn_id = %x, status %d", spp_conn_id, p_data->search_cmpl.status);
728 esp_ble_gattc_send_mtu_req(gattc_if,spp_conn_id);
730 case ESP_GATTC_GET_CHAR_EVT:
731 if (p_data->get_char.status != ESP_GATT_OK) {
732 printf_char_and_descr(SPP_SRV_INDEX);
733 xQueueSend(cmd_reg_queue,&cmd,10/portTICK_PERIOD_MS);
737 store_char_info(p_data);
739 case ESP_GATTC_GET_DESCR_EVT:
740 if (p_data->get_descr.status != ESP_GATT_OK) {
741 char_descr_index_count = 0;
742 esp_ble_gattc_get_characteristic(spp_gattc_if, temp_srv_p->conn_id, &temp_srv_p->srvc_id, &temp_gattc_char_p1->char_id);
745 store_desc_info(p_data);
747 case ESP_GATTC_REG_FOR_NOTIFY_EVT: {
748 ESP_LOGI(GATTC_TAG,"\nwr_descr_cmd = %d-- srvc_id = 0x%04x, char_id = 0x%04x, descr_id = 0x%04x \n",wr_descr_ccc_num , notify_char_p[wr_descr_ccc_num].srvc_id.id.uuid.uuid.uuid16, notify_char_p[wr_descr_ccc_num].char_id.uuid.uuid.uuid16,notify_char_descr_p[wr_descr_ccc_num]->descr_id.uuid.uuid.uuid16);
750 uint16_t notify_en = 1;
751 esp_ble_gattc_write_char_descr(
753 notify_char_p[wr_descr_ccc_num].conn_id,
754 &(notify_char_p[wr_descr_ccc_num].srvc_id),
755 &(notify_char_p[wr_descr_ccc_num].char_id),
756 ¬ify_char_descr_p[wr_descr_ccc_num]->descr_id,
758 (uint8_t *)¬ify_en,
759 ESP_GATT_WRITE_TYPE_RSP,
760 ESP_GATT_AUTH_REQ_NONE);
765 case ESP_GATTC_NOTIFY_EVT:
766 ESP_LOGI(GATTC_TAG,"ESP_GATTC_NOTIFY_EVT\n");
767 notify_event_handler(p_data);
769 case ESP_GATTC_READ_CHAR_EVT:
770 ESP_LOGI(GATTC_TAG,"ESP_GATTC_READ_CHAR_EVT\n");
771 read_event_handler(p_data);
773 case ESP_GATTC_WRITE_CHAR_EVT:
774 ESP_LOGI(GATTC_TAG,"ESP_GATTC_WRITE_CHAR_EVT:status=%d,srvc_uuid = 0x%04x, char_uuid = 0x%04x, descr_uuid=0x%04x \n",p_data->write.status , p_data->write.srvc_id.id.uuid.uuid.uuid16, p_data->write.char_id.uuid.uuid.uuid16, p_data->write.descr_id.uuid.uuid.uuid16);
775 if(param->write.status == ESP_GATT_OK){
776 if(param->write.char_id.uuid.uuid.uuid16 == 0xABF1){
777 future_ready(*btc_main_get_future_p(BTC_MAIN_ENABLE_FUTURE), FUTURE_SUCCESS);
781 case ESP_GATTC_PREP_WRITE_EVT:
783 case ESP_GATTC_EXEC_EVT:
785 case ESP_GATTC_WRITE_DESCR_EVT:
786 ESP_LOGI(GATTC_TAG,"ESP_GATTC_WRITE_DESCR_EVT: status =%d,srvc_uuid = 0x%04x, char_uuid = 0x%04x, descr_uuid=0x%04x \n",p_data->write.status,p_data->write.srvc_id.id.uuid.uuid.uuid16, p_data->write.char_id.uuid.uuid.uuid16, p_data->write.descr_id.uuid.uuid.uuid16);
787 xQueueSend(cmd_reg_queue,&cmd,10/portTICK_PERIOD_MS);
790 case ESP_GATTC_CFG_MTU_EVT:
791 if(p_data->cfg_mtu.status != ESP_OK){
794 ESP_LOGI(GATTC_TAG,"+MTU:%d\n", p_data->cfg_mtu.mtu);
795 spp_mtu_size = p_data->cfg_mtu.mtu;
797 get_char_and_descr();
799 case ESP_GATTC_SRVC_CHG_EVT:
806 void spp_client_reg_task(void* arg)
810 vTaskDelay(100 / portTICK_PERIOD_MS);
811 if(xQueueReceive(cmd_reg_queue, &cmd_id, portMAX_DELAY)) {
813 esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda ,&(notify_char_p[cmd_id].srvc_id), &(notify_char_p[cmd_id].char_id));
814 ESP_LOGI(GATTC_TAG,"No.%d-- srvc_id = 0x%04x, char_id = 0x%04x \n",cmd_id, notify_char_p[cmd_id].srvc_id.id.uuid.uuid.uuid16, notify_char_p[cmd_id].char_id.uuid.uuid.uuid16);
815 }else if(1 == cmd_id){
816 esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda ,&(notify_char_p[cmd_id].srvc_id), &(notify_char_p[cmd_id].char_id));
817 ESP_LOGI(GATTC_TAG,"No.%d-- srvc_id = 0x%04x, char_id = 0x%04x \n",cmd_id, notify_char_p[cmd_id].srvc_id.id.uuid.uuid.uuid16, notify_char_p[cmd_id].char_id.uuid.uuid.uuid16);
818 }else if(2 == cmd_id){
819 esp_ble_gattc_register_for_notify(spp_gattc_if, gl_profile_tab[PROFILE_APP_ID].remote_bda ,&(notify_char_p[cmd_id].srvc_id), &(notify_char_p[cmd_id].char_id));
820 ESP_LOGI(GATTC_TAG,"No.%d-- srvc_id = 0x%04x, char_id = 0x%04x \n",cmd_id, notify_char_p[cmd_id].srvc_id.id.uuid.uuid.uuid16, notify_char_p[cmd_id].char_id.uuid.uuid.uuid16);
822 #ifdef SUPPORT_HEARTBEAT
823 else if(3 == cmd_id){
824 xQueueSend(cmd_heartbeat_queue,&cmd,10/portTICK_PERIOD_MS);
831 #ifdef SUPPORT_HEARTBEAT
832 void spp_heart_beat_task(void * arg)
837 vTaskDelay(50 / portTICK_PERIOD_MS);
838 if(xQueueReceive(cmd_heartbeat_queue, &cmd_id, portMAX_DELAY)) {
840 if(is_connect == true){
841 Characteristic_Wr(SPP_SRV_INDEX,SPP_HEARTBEAT_CHAR_INDEX,(char *)heartbeat_s,sizeof(heartbeat_s));
842 vTaskDelay(5000 / portTICK_PERIOD_MS);
844 ESP_LOGI(GATTC_TAG,"disconnect\n");
853 void spp_client_read_task(void * arg)
856 int32_t srv_index = SPP_SRV_INDEX, char_index = SPP_STATUS_CHAR_INDEX;
859 vTaskDelay(50 / portTICK_PERIOD_MS);
860 if(xQueueReceive(cmd_read_queue, &cmd_id, portMAX_DELAY)) {
861 if(is_connect == true){
862 Characteristic_Rd(srv_index,char_index);
864 ESP_LOGI(GATTC_TAG,"disconnect\n");
870 void ble_client_appRegister(void)
874 ESP_LOGI(GATTC_TAG, "register callback");
876 //register the scan callback function to the gap module
877 if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK) {
878 ESP_LOGE(GATTC_TAG, "gap register error, error code = %x", status);
881 //register the callback function to the gattc module
882 if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK) {
883 ESP_LOGE(GATTC_TAG, "gattc register error, error code = %x", status);
886 esp_ble_gattc_app_register(PROFILE_APP_ID);
888 esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(200);
890 ESP_LOGE(GATTC_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
893 cmd_reg_queue = xQueueCreate(10, sizeof(uint32_t));
894 xTaskCreate(spp_client_reg_task, "spp_client_reg_task", 2048, NULL, 10, NULL);
896 #ifdef SUPPORT_HEARTBEAT
897 cmd_heartbeat_queue = xQueueCreate(10, sizeof(uint32_t));
898 xTaskCreate(spp_heart_beat_task, "spp_heart_beat_task", 2048, NULL, 10, NULL);
901 cmd_read_queue = xQueueCreate(10, sizeof(uint32_t));
902 xTaskCreate(spp_client_read_task, "spp_client_read_task", 2048, NULL, 10, NULL);
905 void uart_task(void *pvParameters)
909 //Waiting for UART event.
910 if (xQueueReceive(spp_uart_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
911 switch (event.type) {
912 //Event of UART receving data
915 uint8_t * temp = NULL;
916 temp = (uint8_t *)malloc(sizeof(uint8_t)*event.size);
918 ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n",__func__,__LINE__);
921 memset(temp,0x0,event.size);
922 uart_read_bytes(UART_NUM_0,temp,event.size,portMAX_DELAY);
923 Characteristic_Wr(SPP_SRV_INDEX,SPP_DATA_RECV_CHAR_INDEX,(char *)temp,event.size);
935 static void spp_uart_init(void)
937 uart_config_t uart_config = {
939 .data_bits = UART_DATA_8_BITS,
940 .parity = UART_PARITY_DISABLE,
941 .stop_bits = UART_STOP_BITS_1,
942 .flow_ctrl = UART_HW_FLOWCTRL_RTS,
943 .rx_flow_ctrl_thresh = 122,
946 //Set UART parameters
947 uart_param_config(UART_NUM_0, &uart_config);
949 uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
950 //Install UART driver, and get the queue.
951 uart_driver_install(UART_NUM_0, 4096, 8192, 10,&spp_uart_queue,0);
952 xTaskCreate(uart_task, "uTask", 2048, (void*)UART_NUM_0, 8, NULL);
959 esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
962 ret = esp_bt_controller_init(&bt_cfg);
964 ESP_LOGE(GATTC_TAG, "%s enable controller failed\n", __func__);
968 ret = esp_bt_controller_enable(ESP_BT_MODE_BTDM);
970 ESP_LOGE(GATTC_TAG, "%s enable controller failed\n", __func__);
974 ESP_LOGI(GATTC_TAG, "%s init bluetooth\n", __func__);
975 ret = esp_bluedroid_init();
977 ESP_LOGE(GATTC_TAG, "%s init bluetooth failed\n", __func__);
980 ret = esp_bluedroid_enable();
982 ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed\n", __func__);
986 #ifdef SUPPORT_NEW_GATTC_API
987 ble_client_appRegister();