1 // Copyright 2018 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.
15 #include <sys/param.h>
17 #include <esp_gatt_common_api.h>
18 #include <esp_gap_bt_api.h>
20 #include <protocomm.h>
21 #include <protocomm_ble.h>
23 #include "protocomm_priv.h"
24 #include "simple_ble.h"
26 #define CHAR_VAL_LEN_MAX (256 + 1)
27 #define PREPARE_BUF_MAX_SIZE CHAR_VAL_LEN_MAX
29 static const char *TAG = "protocomm_ble";
31 /* BLE specific configuration parameters */
32 static const uint16_t primary_service_uuid = ESP_GATT_UUID_PRI_SERVICE;
33 static const uint16_t character_declaration_uuid = ESP_GATT_UUID_CHAR_DECLARE;
34 static const uint16_t character_user_description = ESP_GATT_UUID_CHAR_DESCRIPTION;
35 static const uint8_t character_prop_read_write = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE;
36 static const uint8_t ble_advertisement_flags = ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT;
50 static prepare_type_env_t prepare_write_env;
52 typedef struct name_uuid128 {
54 uint8_t uuid128[ESP_UUID_LEN_128];
57 typedef struct _protocomm_ble {
59 name_uuid128_t *g_nu_lookup;
60 ssize_t g_nu_lookup_count;
62 uint8_t *service_uuid;
63 uint8_t *raw_adv_data_p;
64 uint8_t raw_adv_data_len;
65 uint8_t *raw_scan_rsp_data_p;
66 uint8_t raw_scan_rsp_data_len;
67 } _protocomm_ble_internal_t;
69 static _protocomm_ble_internal_t *protoble_internal;
71 static esp_ble_adv_params_t adv_params = {
74 .adv_type = ADV_TYPE_IND,
75 .own_addr_type = BLE_ADDR_TYPE_PUBLIC,
76 .channel_map = ADV_CHNL_ALL,
77 .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
80 static char* protocomm_ble_device_name = NULL;
82 static void hexdump(const char *msg, uint8_t *buf, int len)
84 ESP_LOGD(TAG, "%s:", msg);
85 ESP_LOG_BUFFER_HEX_LEVEL(TAG, buf, len, ESP_LOG_DEBUG);
88 static const uint16_t *uuid128_to_16(const uint8_t *uuid128)
90 return (const uint16_t *) &uuid128[12];
93 static const char *handle_to_handler(uint16_t handle)
95 const uint8_t *uuid128 = simple_ble_get_uuid128(handle);
99 for (int i = 0; i < protoble_internal->g_nu_lookup_count; i++) {
100 if (*uuid128_to_16(protoble_internal->g_nu_lookup[i].uuid128) == *uuid128_to_16(uuid128)) {
101 return protoble_internal->g_nu_lookup[i].name;
107 static void transport_simple_ble_read(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
109 static const uint8_t *read_buf = NULL;
110 static uint16_t read_len = 0;
111 esp_gatt_status_t status = ESP_OK;
113 ESP_LOGD(TAG, "Inside read w/ session - %d on param %d %d",
114 param->read.conn_id, param->read.handle, read_len);
116 ESP_LOGD(TAG, "Reading attr value first time");
117 status = esp_ble_gatts_get_attr_value(param->read.handle, &read_len, &read_buf);
119 ESP_LOGD(TAG, "Subsequent read request for attr value");
122 esp_gatt_rsp_t gatt_rsp = {0};
123 gatt_rsp.attr_value.len = MIN(read_len, (protoble_internal->gatt_mtu - 1));
124 gatt_rsp.attr_value.handle = param->read.handle;
125 gatt_rsp.attr_value.offset = param->read.offset;
126 gatt_rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
127 if (gatt_rsp.attr_value.len && read_buf) {
128 memcpy(gatt_rsp.attr_value.value,
129 read_buf + param->read.offset,
130 gatt_rsp.attr_value.len);
132 read_len -= gatt_rsp.attr_value.len;
133 esp_err_t err = esp_ble_gatts_send_response(gatts_if, param->read.conn_id,
134 param->read.trans_id, status, &gatt_rsp);
136 ESP_LOGE(TAG, "Send response error in read");
140 static esp_err_t prepare_write_event_env(esp_gatt_if_t gatts_if,
141 esp_ble_gatts_cb_param_t *param)
143 ESP_LOGD(TAG, "prepare write, handle = %d, value len = %d",
144 param->write.handle, param->write.len);
145 esp_gatt_status_t status = ESP_GATT_OK;
146 if (prepare_write_env.prepare_buf == NULL) {
147 prepare_write_env.prepare_buf = (uint8_t *) malloc(PREPARE_BUF_MAX_SIZE * sizeof(uint8_t));
148 if (prepare_write_env.prepare_buf == NULL) {
149 ESP_LOGE(TAG, "%s , failed tp allocate preparebuf", __func__);
150 status = ESP_GATT_NO_RESOURCES;
152 /* prepare_write_env.prepare_len = 0; */
154 if (param->write.offset > PREPARE_BUF_MAX_SIZE) {
155 status = ESP_GATT_INVALID_OFFSET;
156 } else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
157 status = ESP_GATT_INVALID_ATTR_LEN;
160 memcpy(prepare_write_env.prepare_buf + param->write.offset,
163 prepare_write_env.prepare_len += param->write.len;
164 prepare_write_env.handle = param->write.handle;
165 if (param->write.need_rsp) {
166 esp_gatt_rsp_t gatt_rsp = {0};
167 gatt_rsp.attr_value.len = param->write.len;
168 gatt_rsp.attr_value.handle = param->write.handle;
169 gatt_rsp.attr_value.offset = param->write.offset;
170 gatt_rsp.attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
171 if (gatt_rsp.attr_value.len && param->write.value) {
172 memcpy(gatt_rsp.attr_value.value, param->write.value, param->write.len);
174 esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id,
175 param->write.trans_id, status,
177 if (response_err != ESP_OK) {
178 ESP_LOGE(TAG, "Send response error in prep write");
181 if (status != ESP_GATT_OK) {
182 if (prepare_write_env.prepare_buf) {
183 free(prepare_write_env.prepare_buf);
184 prepare_write_env.prepare_buf = NULL;
185 prepare_write_env.prepare_len = 0;
192 static void transport_simple_ble_write(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
194 uint8_t *outbuf = NULL;
198 ESP_LOGD(TAG, "Inside write with session - %d on attr handle - %d \nLen -%d IS Prep - %d",
199 param->write.conn_id, param->write.handle, param->write.len, param->write.is_prep);
201 if (param->write.is_prep) {
202 ret = prepare_write_event_env(gatts_if, param);
204 ESP_LOGE(TAG, "Error appending to prepare buffer");
208 ESP_LOGD(TAG, "is_prep not set");
211 ret = protocomm_req_handle(protoble_internal->pc_ble,
212 handle_to_handler(param->write.handle),
213 param->write.conn_id,
218 ret = esp_ble_gatts_set_attr_value(param->write.handle, outlen, outbuf);
220 ESP_LOGE(TAG, "Failed to set the session attribute value");
222 ret = esp_ble_gatts_send_response(gatts_if, param->write.conn_id,
223 param->write.trans_id, ESP_GATT_OK, NULL);
225 ESP_LOGE(TAG, "Send response error in write");
227 hexdump("Response from write", outbuf, outlen);
230 ESP_LOGE(TAG, "Invalid content received, killing connection");
231 esp_ble_gatts_close(gatts_if, param->write.conn_id);
238 static void transport_simple_ble_exec_write(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
241 uint8_t *outbuf = NULL;
243 ESP_LOGD(TAG, "Inside exec_write w/ session - %d", param->exec_write.conn_id);
245 if ((param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC)
247 prepare_write_env.prepare_buf) {
248 err = protocomm_req_handle(protoble_internal->pc_ble,
249 handle_to_handler(prepare_write_env.handle),
250 param->exec_write.conn_id,
251 prepare_write_env.prepare_buf,
252 prepare_write_env.prepare_len,
256 ESP_LOGE(TAG, "Invalid content received, killing connection");
257 esp_ble_gatts_close(gatts_if, param->exec_write.conn_id);
259 hexdump("Response from exec write", outbuf, outlen);
260 esp_ble_gatts_set_attr_value(prepare_write_env.handle, outlen, outbuf);
263 if (prepare_write_env.prepare_buf) {
264 free(prepare_write_env.prepare_buf);
265 prepare_write_env.prepare_buf = NULL;
266 prepare_write_env.prepare_len = 0;
269 err = esp_ble_gatts_send_response(gatts_if, param->exec_write.conn_id, param->exec_write.trans_id, ESP_GATT_OK, NULL);
271 ESP_LOGE(TAG, "Send response error in exec write");
278 static void transport_simple_ble_disconnect(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
281 ESP_LOGD(TAG, "Inside disconnect w/ session - %d", param->disconnect.conn_id);
282 if (protoble_internal->pc_ble->sec &&
283 protoble_internal->pc_ble->sec->close_transport_session) {
284 ret = protoble_internal->pc_ble->sec->close_transport_session(protoble_internal->pc_ble->sec_inst,
285 param->disconnect.conn_id);
287 ESP_LOGE(TAG, "error closing the session after disconnect");
290 protoble_internal->gatt_mtu = ESP_GATT_DEF_BLE_MTU_SIZE;
293 static void transport_simple_ble_connect(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
296 ESP_LOGD(TAG, "Inside BLE connect w/ conn_id - %d", param->connect.conn_id);
297 if (protoble_internal->pc_ble->sec &&
298 protoble_internal->pc_ble->sec->new_transport_session) {
299 ret = protoble_internal->pc_ble->sec->new_transport_session(protoble_internal->pc_ble->sec_inst,
300 param->connect.conn_id);
302 ESP_LOGE(TAG, "error creating the session");
307 static void transport_simple_ble_set_mtu(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
309 protoble_internal->gatt_mtu = param->mtu.mtu;
313 static esp_err_t protocomm_ble_add_endpoint(const char *ep_name,
314 protocomm_req_handler_t req_handler,
317 /* Endpoint UUID already added when protocomm_ble_start() was called */
321 static esp_err_t protocomm_ble_remove_endpoint(const char *ep_name)
323 /* Endpoint UUID will be removed when protocomm_ble_stop() is called */
327 static ssize_t populate_gatt_db(esp_gatts_attr_db_t **gatt_db_generated)
330 /* Each endpoint requires 3 attributes:
331 * 1) for Characteristic Declaration
332 * 2) for Characteristic Value (for reading and writing to an endpoint)
333 * 3) for Characteristic User Description (endpoint name)
335 * Therefore, we need esp_gatts_attr_db_t of size 3 * number of endpoints + 1 for service
337 ssize_t gatt_db_generated_entries = 3 * protoble_internal->g_nu_lookup_count + 1;
339 *gatt_db_generated = (esp_gatts_attr_db_t *) malloc(sizeof(esp_gatts_attr_db_t) *
340 (gatt_db_generated_entries));
341 if ((*gatt_db_generated) == NULL) {
342 ESP_LOGE(TAG, "Failed to assign memory to gatt_db");
345 /* Declare service */
346 (*gatt_db_generated)[0].attr_control.auto_rsp = ESP_GATT_RSP_BY_APP;
348 (*gatt_db_generated)[0].att_desc.uuid_length = ESP_UUID_LEN_16;
349 (*gatt_db_generated)[0].att_desc.uuid_p = (uint8_t *) &primary_service_uuid;
350 (*gatt_db_generated)[0].att_desc.perm = ESP_GATT_PERM_READ;
351 (*gatt_db_generated)[0].att_desc.max_length = ESP_UUID_LEN_128;
352 (*gatt_db_generated)[0].att_desc.length = ESP_UUID_LEN_128;
353 (*gatt_db_generated)[0].att_desc.value = protoble_internal->service_uuid;
355 /* Declare characteristics */
356 for (i = 1 ; i < gatt_db_generated_entries ; i++) {
357 (*gatt_db_generated)[i].attr_control.auto_rsp = ESP_GATT_RSP_BY_APP;
360 /* Characteristic Declaration */
361 (*gatt_db_generated)[i].att_desc.perm = ESP_GATT_PERM_READ;
362 (*gatt_db_generated)[i].att_desc.uuid_length = ESP_UUID_LEN_16;
363 (*gatt_db_generated)[i].att_desc.uuid_p = (uint8_t *) &character_declaration_uuid;
364 (*gatt_db_generated)[i].att_desc.max_length = sizeof(uint8_t);
365 (*gatt_db_generated)[i].att_desc.length = sizeof(uint8_t);
366 (*gatt_db_generated)[i].att_desc.value = (uint8_t *) &character_prop_read_write;
367 } else if (i % 3 == 2) {
368 /* Characteristic Value */
369 (*gatt_db_generated)[i].att_desc.perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE;
370 (*gatt_db_generated)[i].att_desc.uuid_length = ESP_UUID_LEN_128;
371 (*gatt_db_generated)[i].att_desc.uuid_p = protoble_internal->g_nu_lookup[i / 3].uuid128;
372 (*gatt_db_generated)[i].att_desc.max_length = CHAR_VAL_LEN_MAX;
373 (*gatt_db_generated)[i].att_desc.length = 0;
374 (*gatt_db_generated)[i].att_desc.value = NULL;
376 /* Characteristic User Description (for keeping endpoint names) */
377 (*gatt_db_generated)[i].att_desc.perm = ESP_GATT_PERM_READ;
378 (*gatt_db_generated)[i].att_desc.uuid_length = ESP_UUID_LEN_16;
379 (*gatt_db_generated)[i].att_desc.uuid_p = (uint8_t *) &character_user_description;
380 (*gatt_db_generated)[i].att_desc.max_length = strlen(protoble_internal->g_nu_lookup[i / 3 - 1].name);
381 (*gatt_db_generated)[i].att_desc.length = (*gatt_db_generated)[i].att_desc.max_length;
382 (*gatt_db_generated)[i].att_desc.value = (uint8_t *) protoble_internal->g_nu_lookup[i / 3 - 1].name;
385 return gatt_db_generated_entries;
388 static void protocomm_ble_cleanup(void)
390 if (protoble_internal) {
391 if (protoble_internal->g_nu_lookup) {
392 for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) {
393 if (protoble_internal->g_nu_lookup[i].name) {
394 free((void *)protoble_internal->g_nu_lookup[i].name);
397 free(protoble_internal->g_nu_lookup);
399 free(protoble_internal->raw_adv_data_p);
400 free(protoble_internal->raw_scan_rsp_data_p);
401 free(protoble_internal);
402 protoble_internal = NULL;
404 if (protocomm_ble_device_name) {
405 free(protocomm_ble_device_name);
406 protocomm_ble_device_name = NULL;
410 esp_err_t protocomm_ble_start(protocomm_t *pc, const protocomm_ble_config_t *config)
412 if (!pc || !config || !config->device_name || !config->nu_lookup) {
413 return ESP_ERR_INVALID_ARG;
416 if (protoble_internal) {
417 ESP_LOGE(TAG, "Protocomm BLE already started");
421 /* Store BLE device name internally */
422 protocomm_ble_device_name = strdup(config->device_name);
423 if (protocomm_ble_device_name == NULL) {
424 ESP_LOGE(TAG, "Error allocating memory for storing BLE device name");
425 protocomm_ble_cleanup();
426 return ESP_ERR_NO_MEM;
429 protoble_internal = (_protocomm_ble_internal_t *) calloc(1, sizeof(_protocomm_ble_internal_t));
430 if (protoble_internal == NULL) {
431 ESP_LOGE(TAG, "Error allocating internal protocomm structure");
432 protocomm_ble_cleanup();
433 return ESP_ERR_NO_MEM;
436 protoble_internal->g_nu_lookup_count = config->nu_lookup_count;
437 protoble_internal->g_nu_lookup = malloc(config->nu_lookup_count * sizeof(name_uuid128_t));
438 if (protoble_internal->g_nu_lookup == NULL) {
439 ESP_LOGE(TAG, "Error allocating internal name UUID table");
440 protocomm_ble_cleanup();
441 return ESP_ERR_NO_MEM;
444 for (unsigned i = 0; i < protoble_internal->g_nu_lookup_count; i++) {
445 memcpy(protoble_internal->g_nu_lookup[i].uuid128, config->service_uuid, ESP_UUID_LEN_128);
446 memcpy((uint8_t *)uuid128_to_16(protoble_internal->g_nu_lookup[i].uuid128),
447 &config->nu_lookup[i].uuid, ESP_UUID_LEN_16);
449 protoble_internal->g_nu_lookup[i].name = strdup(config->nu_lookup[i].name);
450 if (protoble_internal->g_nu_lookup[i].name == NULL) {
451 ESP_LOGE(TAG, "Error allocating internal name UUID entry");
452 protocomm_ble_cleanup();
453 return ESP_ERR_NO_MEM;
457 pc->add_endpoint = protocomm_ble_add_endpoint;
458 pc->remove_endpoint = protocomm_ble_remove_endpoint;
459 protoble_internal->pc_ble = pc;
460 protoble_internal->gatt_mtu = ESP_GATT_DEF_BLE_MTU_SIZE;
462 /* The BLE advertisement data (max 31 bytes) consists of:
464 * Size : length (1 byte) + type (1 byte) + value (1 byte) = 3 bytes
465 * 2) Complete 128 bit UUID of the service -
466 * Size : length (1 byte) + type (1 byte) + value (16 bytes) = 18 bytes
468 * Remaining 31 - (3 + 18) = 10 bytes could be used for manufacturer data
469 * or something else in the future.
471 raw_data_info_t adv_data[] = {
473 .type = ESP_BLE_AD_TYPE_FLAG,
474 .length = sizeof(ble_advertisement_flags),
475 .data_p = (uint8_t *) &ble_advertisement_flags
477 { /* 128 bit Service UUID */
478 .type = ESP_BLE_AD_TYPE_128SRV_CMPL,
479 .length = ESP_UUID_LEN_128,
480 .data_p = (uint8_t *) config->service_uuid
484 /* Get the total raw data length required for above entries */
485 uint8_t adv_data_len = 0;
486 for (uint8_t i = 0; i < (sizeof(adv_data)/sizeof(adv_data[0])); i++) {
487 /* Add extra bytes required per entry, i.e.
488 * length (1 byte) + type (1 byte) = 2 bytes */
489 adv_data_len += adv_data[i].length + 2;
491 if (adv_data_len > ESP_BLE_ADV_DATA_LEN_MAX) {
492 ESP_LOGE(TAG, "Advertisement data too long = %d bytes", adv_data_len);
493 protocomm_ble_cleanup();
494 return ESP_ERR_NO_MEM;
497 /* Allocate memory for the raw advertisement data */
498 protoble_internal->raw_adv_data_len = adv_data_len;
499 protoble_internal->raw_adv_data_p = malloc(adv_data_len);
500 if (protoble_internal->raw_adv_data_p == NULL) {
501 ESP_LOGE(TAG, "Error allocating memory for raw advertisement data");
502 protocomm_ble_cleanup();
503 return ESP_ERR_NO_MEM;
506 /* Form the raw advertisement data using above entries */
507 for (uint8_t i = 0, len = 0; i < (sizeof(adv_data)/sizeof(adv_data[0])); i++) {
508 protoble_internal->raw_adv_data_p[len++] = adv_data[i].length + 1; // + 1 byte for type
509 protoble_internal->raw_adv_data_p[len++] = adv_data[i].type;
510 memcpy(&protoble_internal->raw_adv_data_p[len],
511 adv_data[i].data_p, adv_data[i].length);
513 if (adv_data[i].type == ESP_BLE_AD_TYPE_128SRV_CMPL) {
514 /* Remember where the primary service UUID is kept in the
515 * raw advertisement data, so that it can be used while
516 * populating the GATT database
518 protoble_internal->service_uuid = &protoble_internal->raw_adv_data_p[len];
521 len += adv_data[i].length;
524 size_t ble_devname_len = strlen(protocomm_ble_device_name);
525 /* The BLE scan response (31 bytes) consists of:
526 * 1) Device name (complete / incomplete) -
527 * Size : The maximum supported name length
528 * will be 31 - 2 (length + type) = 29 bytes
530 * Any remaining space may be used for accommodating
531 * other fields in the future
533 raw_data_info_t scan_resp_data[] = {
534 { /* If full device name can fit in the scan response then indicate
535 * that by setting type to "Complete Name", else set it to "Short Name"
536 * so that client can fetch full device name - after connecting - by
537 * reading the device name characteristic under GAP service */
538 .type = (ble_devname_len > (ESP_BLE_SCAN_RSP_DATA_LEN_MAX - 2) ?
539 ESP_BLE_AD_TYPE_NAME_SHORT : ESP_BLE_AD_TYPE_NAME_CMPL),
540 .length = MIN(ble_devname_len, (ESP_BLE_SCAN_RSP_DATA_LEN_MAX - 2)),
541 .data_p = (uint8_t *) protocomm_ble_device_name
545 /* Get the total raw scan response data length required for above entries */
546 uint8_t scan_resp_data_len = 0;
547 for (int i = 0; i < (sizeof(scan_resp_data)/sizeof(scan_resp_data[0])); i++) {
548 /* Add extra bytes required per entry, i.e.
549 * length (1 byte) + type (1 byte) = 2 bytes */
550 scan_resp_data_len += scan_resp_data[i].length + 2;
552 if (scan_resp_data_len > ESP_BLE_SCAN_RSP_DATA_LEN_MAX) {
553 ESP_LOGE(TAG, "Scan response data too long = %d bytes", scan_resp_data_len);
554 protocomm_ble_cleanup();
555 return ESP_ERR_NO_MEM;
558 /* Allocate memory for the raw scan response data */
559 protoble_internal->raw_scan_rsp_data_len = scan_resp_data_len;
560 protoble_internal->raw_scan_rsp_data_p = malloc(scan_resp_data_len);
561 if (protoble_internal->raw_scan_rsp_data_p == NULL) {
562 ESP_LOGE(TAG, "Error allocating memory for raw response data");
563 protocomm_ble_cleanup();
564 return ESP_ERR_NO_MEM;
567 /* Form the raw scan response data using above entries */
568 for (uint8_t i = 0, len = 0; i < (sizeof(scan_resp_data)/sizeof(scan_resp_data[0])); i++) {
569 protoble_internal->raw_scan_rsp_data_p[len++] = scan_resp_data[i].length + 1; // + 1 byte for type
570 protoble_internal->raw_scan_rsp_data_p[len++] = scan_resp_data[i].type;
571 memcpy(&protoble_internal->raw_scan_rsp_data_p[len],
572 scan_resp_data[i].data_p, scan_resp_data[i].length);
573 len += scan_resp_data[i].length;
576 simple_ble_cfg_t *ble_config = simple_ble_init();
577 if (ble_config == NULL) {
578 ESP_LOGE(TAG, "Ran out of memory for BLE config");
579 protocomm_ble_cleanup();
580 return ESP_ERR_NO_MEM;
583 /* Set function pointers required for simple BLE layer */
584 ble_config->read_fn = transport_simple_ble_read;
585 ble_config->write_fn = transport_simple_ble_write;
586 ble_config->exec_write_fn = transport_simple_ble_exec_write;
587 ble_config->disconnect_fn = transport_simple_ble_disconnect;
588 ble_config->connect_fn = transport_simple_ble_connect;
589 ble_config->set_mtu_fn = transport_simple_ble_set_mtu;
591 /* Set parameters required for advertising */
592 ble_config->adv_params = adv_params;
594 ble_config->raw_adv_data_p = protoble_internal->raw_adv_data_p;
595 ble_config->raw_adv_data_len = protoble_internal->raw_adv_data_len;
596 ble_config->raw_scan_rsp_data_p = protoble_internal->raw_scan_rsp_data_p;
597 ble_config->raw_scan_rsp_data_len = protoble_internal->raw_scan_rsp_data_len;
599 ble_config->device_name = protocomm_ble_device_name;
600 ble_config->gatt_db_count = populate_gatt_db(&ble_config->gatt_db);
602 if (ble_config->gatt_db_count == -1) {
603 ESP_LOGE(TAG, "Invalid GATT database count");
605 protocomm_ble_cleanup();
606 return ESP_ERR_INVALID_STATE;
609 esp_err_t err = simple_ble_start(ble_config);
611 ESP_LOGE(TAG, "simple_ble_start failed w/ error code 0x%x", err);
613 protocomm_ble_cleanup();
617 prepare_write_env.prepare_buf = NULL;
618 ESP_LOGD(TAG, "Waiting for client to connect ......");
622 esp_err_t protocomm_ble_stop(protocomm_t *pc)
625 (protoble_internal != NULL ) &&
626 (pc == protoble_internal->pc_ble)) {
627 esp_err_t ret = ESP_OK;
628 ret = simple_ble_stop();
630 ESP_LOGE(TAG, "BLE stop failed");
633 protocomm_ble_cleanup();
636 return ESP_ERR_INVALID_ARG;