gatts_demo.c 35 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Unlicense OR CC0-1.0
  5. */
  6. /****************************************************************************
  7. *
  8. * This demo showcases BLE GATT server. It can send adv data, be connected by client.
  9. * Run the gatt_client demo, the client demo will automatically connect to the gatt_server demo.
  10. * Client demo will enable gatt_server's notify after connection. The two devices will then exchange
  11. * data.
  12. *
  13. ****************************************************************************/
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <string.h>
  17. #include <inttypes.h>
  18. #include "freertos/FreeRTOS.h"
  19. #include "freertos/task.h"
  20. #include "freertos/event_groups.h"
  21. #include "esp_system.h"
  22. #include "esp_log.h"
  23. #include "nvs_flash.h"
  24. #include "esp_bt.h"
  25. #include "esp_gap_ble_api.h"
  26. #include "esp_gatts_api.h"
  27. #include "esp_bt_defs.h"
  28. #include "esp_bt_main.h"
  29. #include "esp_bt_device.h"
  30. #include "esp_gatt_common_api.h"
  31. #include "sdkconfig.h"
  32. #define GATTS_TAG "GATTS_DEMO"
  33. ///Declare the static function
  34. static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
  35. static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param);
  36. #define GATTS_SERVICE_UUID_TEST_A 0x00FF
  37. #define GATTS_CHAR_UUID_TEST_A 0xFF01
  38. #define GATTS_DESCR_UUID_TEST_A 0x3333
  39. #define GATTS_NUM_HANDLE_TEST_A 4
  40. #define GATTS_SERVICE_UUID_TEST_B 0x00EE
  41. #define GATTS_CHAR_UUID_TEST_B 0xEE01
  42. #define GATTS_DESCR_UUID_TEST_B 0x2222
  43. #define GATTS_NUM_HANDLE_TEST_B 4
  44. static char test_device_name[ESP_BLE_ADV_NAME_LEN_MAX] = "ESP_GATTS_DEMO";
  45. #define TEST_MANUFACTURER_DATA_LEN 17
  46. #define GATTS_DEMO_CHAR_VAL_LEN_MAX 0x40
  47. #define PREPARE_BUF_MAX_SIZE 1024
  48. static uint8_t char1_str[] = {0x11,0x22,0x33};
  49. static uint16_t descr_value = 0x0;
  50. /**
  51. * Current MTU size for the active connection.
  52. *
  53. * This simplified implementation assumes a single connection.
  54. * For multi-connection scenarios, the MTU should be stored per connection ID.
  55. */
  56. static uint16_t local_mtu = 23;
  57. static uint8_t char_value_read[CONFIG_EXAMPLE_CHAR_READ_DATA_LEN] = {0xDE,0xED,0xBE,0xEF};
  58. static esp_gatt_char_prop_t a_property = 0;
  59. static esp_gatt_char_prop_t b_property = 0;
  60. static esp_attr_value_t gatts_demo_char1_val =
  61. {
  62. .attr_max_len = GATTS_DEMO_CHAR_VAL_LEN_MAX,
  63. .attr_len = sizeof(char1_str),
  64. .attr_value = char1_str,
  65. };
  66. static uint8_t adv_config_done = 0;
  67. #define adv_config_flag (1 << 0)
  68. #define scan_rsp_config_flag (1 << 1)
  69. #ifdef CONFIG_EXAMPLE_SET_RAW_ADV_DATA
  70. static uint8_t raw_adv_data[] = {
  71. /* Flags */
  72. 0x02, ESP_BLE_AD_TYPE_FLAG, 0x06, // Length 2, Data Type ESP_BLE_AD_TYPE_FLAG, Data 1 (LE General Discoverable Mode, BR/EDR Not Supported)
  73. /* TX Power Level */
  74. 0x02, ESP_BLE_AD_TYPE_TX_PWR, 0xEB, // Length 2, Data Type ESP_BLE_AD_TYPE_TX_PWR, Data 2 (-21)
  75. /* Complete 16-bit Service UUIDs */
  76. 0x03, ESP_BLE_AD_TYPE_16SRV_CMPL, 0xAB, 0xCD // Length 3, Data Type ESP_BLE_AD_TYPE_16SRV_CMPL, Data 3 (UUID)
  77. };
  78. static uint8_t raw_scan_rsp_data[] = {
  79. /* Complete Local Name */
  80. 0x0F, ESP_BLE_AD_TYPE_NAME_CMPL, 'E', 'S', 'P', '_', 'G', 'A', 'T', 'T', 'S', '_', 'D', 'E', 'M', 'O' // Length 15, Data Type ESP_BLE_AD_TYPE_NAME_CMPL, Data (ESP_GATTS_DEMO)
  81. };
  82. #else
  83. static uint8_t adv_service_uuid128[32] = {
  84. /* LSB <--------------------------------------------------------------------------------> MSB */
  85. //first uuid, 16bit, [12],[13] is the value
  86. 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xEE, 0x00, 0x00, 0x00,
  87. //second uuid, 32bit, [12], [13], [14], [15] is the value
  88. 0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80, 0x00, 0x10, 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00,
  89. };
  90. // The length of adv data must be less than 31 bytes
  91. //static uint8_t test_manufacturer[TEST_MANUFACTURER_DATA_LEN] = {0x12, 0x23, 0x45, 0x56};
  92. //adv data
  93. static esp_ble_adv_data_t adv_data = {
  94. .set_scan_rsp = false,
  95. .include_name = true,
  96. .include_txpower = false,
  97. .min_interval = 0x0006, //slave connection min interval, Time = min_interval * 1.25 msec
  98. .max_interval = 0x0010, //slave connection max interval, Time = max_interval * 1.25 msec
  99. .appearance = 0x00,
  100. .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
  101. .p_manufacturer_data = NULL, //&test_manufacturer[0],
  102. .service_data_len = 0,
  103. .p_service_data = NULL,
  104. .service_uuid_len = sizeof(adv_service_uuid128),
  105. .p_service_uuid = adv_service_uuid128,
  106. .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
  107. };
  108. // scan response data
  109. static esp_ble_adv_data_t scan_rsp_data = {
  110. .set_scan_rsp = true,
  111. .include_name = true,
  112. .include_txpower = true,
  113. //.min_interval = 0x0006,
  114. //.max_interval = 0x0010,
  115. .appearance = 0x00,
  116. .manufacturer_len = 0, //TEST_MANUFACTURER_DATA_LEN,
  117. .p_manufacturer_data = NULL, //&test_manufacturer[0],
  118. .service_data_len = 0,
  119. .p_service_data = NULL,
  120. .service_uuid_len = sizeof(adv_service_uuid128),
  121. .p_service_uuid = adv_service_uuid128,
  122. .flag = (ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SPT),
  123. };
  124. #endif /* CONFIG_SET_RAW_ADV_DATA */
  125. static esp_ble_adv_params_t adv_params = {
  126. .adv_int_min = 0x20,
  127. .adv_int_max = 0x40,
  128. .adv_type = ADV_TYPE_IND,
  129. .own_addr_type = BLE_ADDR_TYPE_PUBLIC,
  130. //.peer_addr =
  131. //.peer_addr_type =
  132. .channel_map = ADV_CHNL_ALL,
  133. .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
  134. };
  135. #define PROFILE_NUM 2
  136. #define PROFILE_A_APP_ID 0
  137. #define PROFILE_B_APP_ID 1
  138. struct gatts_profile_inst {
  139. esp_gatts_cb_t gatts_cb;
  140. uint16_t gatts_if;
  141. uint16_t app_id;
  142. uint16_t conn_id;
  143. uint16_t service_handle;
  144. esp_gatt_srvc_id_t service_id;
  145. uint16_t char_handle;
  146. esp_bt_uuid_t char_uuid;
  147. esp_gatt_perm_t perm;
  148. esp_gatt_char_prop_t property;
  149. uint16_t descr_handle;
  150. esp_bt_uuid_t descr_uuid;
  151. };
  152. /* One gatt-based profile one app_id and one gatts_if, this array will store the gatts_if returned by ESP_GATTS_REG_EVT */
  153. static struct gatts_profile_inst gl_profile_tab[PROFILE_NUM] = {
  154. [PROFILE_A_APP_ID] = {
  155. .gatts_cb = gatts_profile_a_event_handler,
  156. .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
  157. },
  158. [PROFILE_B_APP_ID] = {
  159. .gatts_cb = gatts_profile_b_event_handler, /* This demo does not implement, similar as profile A */
  160. .gatts_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
  161. },
  162. };
  163. typedef struct {
  164. uint8_t *prepare_buf;
  165. int prepare_len;
  166. } prepare_type_env_t;
  167. static prepare_type_env_t a_prepare_write_env;
  168. static prepare_type_env_t b_prepare_write_env;
  169. void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
  170. void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param);
  171. static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
  172. {
  173. switch (event) {
  174. #ifdef CONFIG_SET_RAW_ADV_DATA
  175. case ESP_GAP_BLE_ADV_DATA_RAW_SET_COMPLETE_EVT:
  176. adv_config_done &= (~adv_config_flag);
  177. if (adv_config_done==0){
  178. esp_ble_gap_start_advertising(&adv_params);
  179. }
  180. break;
  181. case ESP_GAP_BLE_SCAN_RSP_DATA_RAW_SET_COMPLETE_EVT:
  182. adv_config_done &= (~scan_rsp_config_flag);
  183. if (adv_config_done==0){
  184. esp_ble_gap_start_advertising(&adv_params);
  185. }
  186. break;
  187. #else
  188. case ESP_GAP_BLE_ADV_DATA_SET_COMPLETE_EVT:
  189. adv_config_done &= (~adv_config_flag);
  190. if (adv_config_done == 0){
  191. esp_ble_gap_start_advertising(&adv_params);
  192. }
  193. break;
  194. case ESP_GAP_BLE_SCAN_RSP_DATA_SET_COMPLETE_EVT:
  195. adv_config_done &= (~scan_rsp_config_flag);
  196. if (adv_config_done == 0){
  197. esp_ble_gap_start_advertising(&adv_params);
  198. }
  199. break;
  200. #endif
  201. case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
  202. //advertising start complete event to indicate advertising start successfully or failed
  203. if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
  204. ESP_LOGE(GATTS_TAG, "Advertising start failed, status %d", param->adv_start_cmpl.status);
  205. break;
  206. }
  207. ESP_LOGI(GATTS_TAG, "Advertising start successfully");
  208. break;
  209. case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
  210. if (param->adv_start_cmpl.status != ESP_BT_STATUS_SUCCESS) {
  211. ESP_LOGE(GATTS_TAG, "Advertising stop failed, status %d", param->adv_stop_cmpl.status);
  212. break;
  213. }
  214. ESP_LOGI(GATTS_TAG, "Advertising stop successfully");
  215. break;
  216. case ESP_GAP_BLE_UPDATE_CONN_PARAMS_EVT:
  217. ESP_LOGI(GATTS_TAG, "Connection params update, status %d, conn_int %d, latency %d, timeout %d",
  218. param->update_conn_params.status,
  219. param->update_conn_params.conn_int,
  220. param->update_conn_params.latency,
  221. param->update_conn_params.timeout);
  222. break;
  223. case ESP_GAP_BLE_SET_PKT_LENGTH_COMPLETE_EVT:
  224. ESP_LOGI(GATTS_TAG, "Packet length update, status %d, rx %d, tx %d",
  225. param->pkt_data_length_cmpl.status,
  226. param->pkt_data_length_cmpl.params.rx_len,
  227. param->pkt_data_length_cmpl.params.tx_len);
  228. break;
  229. default:
  230. break;
  231. }
  232. }
  233. void example_write_event_env(esp_gatt_if_t gatts_if, prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
  234. esp_gatt_status_t status = ESP_GATT_OK;
  235. if (param->write.need_rsp){
  236. if (param->write.is_prep) {
  237. if (param->write.offset > PREPARE_BUF_MAX_SIZE) {
  238. status = ESP_GATT_INVALID_OFFSET;
  239. } else if ((param->write.offset + param->write.len) > PREPARE_BUF_MAX_SIZE) {
  240. status = ESP_GATT_INVALID_ATTR_LEN;
  241. }
  242. if (status == ESP_GATT_OK && prepare_write_env->prepare_buf == NULL) {
  243. prepare_write_env->prepare_buf = (uint8_t *)malloc(PREPARE_BUF_MAX_SIZE*sizeof(uint8_t));
  244. prepare_write_env->prepare_len = 0;
  245. if (prepare_write_env->prepare_buf == NULL) {
  246. ESP_LOGE(GATTS_TAG, "Gatt_server prep no mem");
  247. status = ESP_GATT_NO_RESOURCES;
  248. }
  249. }
  250. esp_gatt_rsp_t *gatt_rsp = (esp_gatt_rsp_t *)malloc(sizeof(esp_gatt_rsp_t));
  251. if (gatt_rsp) {
  252. gatt_rsp->attr_value.len = param->write.len;
  253. gatt_rsp->attr_value.handle = param->write.handle;
  254. gatt_rsp->attr_value.offset = param->write.offset;
  255. gatt_rsp->attr_value.auth_req = ESP_GATT_AUTH_REQ_NONE;
  256. memcpy(gatt_rsp->attr_value.value, param->write.value, param->write.len);
  257. esp_err_t response_err = esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, gatt_rsp);
  258. if (response_err != ESP_OK){
  259. ESP_LOGE(GATTS_TAG, "Send response error\n");
  260. }
  261. free(gatt_rsp);
  262. } else {
  263. ESP_LOGE(GATTS_TAG, "malloc failed, no resource to send response error\n");
  264. status = ESP_GATT_NO_RESOURCES;
  265. }
  266. if (status != ESP_GATT_OK){
  267. return;
  268. }
  269. memcpy(prepare_write_env->prepare_buf + param->write.offset,
  270. param->write.value,
  271. param->write.len);
  272. prepare_write_env->prepare_len += param->write.len;
  273. }else{
  274. esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, status, NULL);
  275. }
  276. }
  277. }
  278. void example_exec_write_event_env(prepare_type_env_t *prepare_write_env, esp_ble_gatts_cb_param_t *param){
  279. if (param->exec_write.exec_write_flag == ESP_GATT_PREP_WRITE_EXEC){
  280. ESP_LOG_BUFFER_HEX(GATTS_TAG, prepare_write_env->prepare_buf, prepare_write_env->prepare_len);
  281. }else{
  282. ESP_LOGI(GATTS_TAG,"Prepare write cancel");
  283. }
  284. if (prepare_write_env->prepare_buf) {
  285. free(prepare_write_env->prepare_buf);
  286. prepare_write_env->prepare_buf = NULL;
  287. }
  288. prepare_write_env->prepare_len = 0;
  289. }
  290. static void gatts_profile_a_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
  291. switch (event) {
  292. case ESP_GATTS_REG_EVT:
  293. ESP_LOGI(GATTS_TAG, "GATT server register, status %d, app_id %d, gatts_if %d", param->reg.status, param->reg.app_id, gatts_if);
  294. gl_profile_tab[PROFILE_A_APP_ID].service_id.is_primary = true;
  295. gl_profile_tab[PROFILE_A_APP_ID].service_id.id.inst_id = 0x00;
  296. gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16;
  297. gl_profile_tab[PROFILE_A_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_A;
  298. esp_err_t set_dev_name_ret = esp_ble_gap_set_device_name(test_device_name);
  299. if (set_dev_name_ret){
  300. ESP_LOGE(GATTS_TAG, "set device name failed, error code = %x", set_dev_name_ret);
  301. }
  302. #ifdef CONFIG_EXAMPLE_SET_RAW_ADV_DATA
  303. esp_err_t raw_adv_ret = esp_ble_gap_config_adv_data_raw(raw_adv_data, sizeof(raw_adv_data));
  304. if (raw_adv_ret){
  305. ESP_LOGE(GATTS_TAG, "config raw adv data failed, error code = %x ", raw_adv_ret);
  306. }
  307. adv_config_done |= adv_config_flag;
  308. esp_err_t raw_scan_ret = esp_ble_gap_config_scan_rsp_data_raw(raw_scan_rsp_data, sizeof(raw_scan_rsp_data));
  309. if (raw_scan_ret){
  310. ESP_LOGE(GATTS_TAG, "config raw scan rsp data failed, error code = %x", raw_scan_ret);
  311. }
  312. adv_config_done |= scan_rsp_config_flag;
  313. #else
  314. //config adv data
  315. esp_err_t ret = esp_ble_gap_config_adv_data(&adv_data);
  316. if (ret){
  317. ESP_LOGE(GATTS_TAG, "config adv data failed, error code = %x", ret);
  318. }
  319. adv_config_done |= adv_config_flag;
  320. //config scan response data
  321. ret = esp_ble_gap_config_adv_data(&scan_rsp_data);
  322. if (ret){
  323. ESP_LOGE(GATTS_TAG, "config scan response data failed, error code = %x", ret);
  324. }
  325. adv_config_done |= scan_rsp_config_flag;
  326. #endif
  327. esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_A_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_A);
  328. break;
  329. case ESP_GATTS_READ_EVT: {
  330. ESP_LOGI(GATTS_TAG,
  331. "Characteristic read request: conn_id=%d, trans_id=%" PRIu32 ", handle=%d, is_long=%d, offset=%d, need_rsp=%d",
  332. param->read.conn_id, param->read.trans_id, param->read.handle,
  333. param->read.is_long, param->read.offset, param->read.need_rsp);
  334. // If no response is needed, exit early (stack handles it automatically)
  335. if (!param->read.need_rsp) {
  336. return;
  337. }
  338. esp_gatt_rsp_t rsp;
  339. memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
  340. rsp.attr_value.handle = param->read.handle;
  341. // Handle descriptor read request
  342. if (param->read.handle == gl_profile_tab[PROFILE_A_APP_ID].descr_handle) {
  343. memcpy(rsp.attr_value.value, &descr_value, 2);
  344. rsp.attr_value.len = 2;
  345. esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
  346. return;
  347. }
  348. // Handle characteristic read request
  349. if (param->read.handle == gl_profile_tab[PROFILE_A_APP_ID].char_handle) {
  350. uint16_t offset = param->read.offset;
  351. // Validate read offset
  352. if (param->read.is_long && offset > CONFIG_EXAMPLE_CHAR_READ_DATA_LEN) {
  353. ESP_LOGW(GATTS_TAG, "Read offset (%d) out of range (0-%d)", offset, CONFIG_EXAMPLE_CHAR_READ_DATA_LEN);
  354. rsp.attr_value.len = 0;
  355. esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_INVALID_OFFSET, &rsp);
  356. return;
  357. }
  358. // Determine response length based on MTU
  359. uint16_t mtu_size = local_mtu - 1; // ATT header (1 byte)
  360. uint16_t send_len = (CONFIG_EXAMPLE_CHAR_READ_DATA_LEN - offset > mtu_size) ? mtu_size : (CONFIG_EXAMPLE_CHAR_READ_DATA_LEN - offset);
  361. memcpy(rsp.attr_value.value, &char_value_read[offset], send_len);
  362. rsp.attr_value.len = send_len;
  363. // Send response to GATT client
  364. esp_err_t err = esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id, ESP_GATT_OK, &rsp);
  365. if (err != ESP_OK) {
  366. ESP_LOGE(GATTS_TAG, "Failed to send response: %s", esp_err_to_name(err));
  367. }
  368. }
  369. break;
  370. }
  371. case ESP_GATTS_WRITE_EVT: {
  372. ESP_LOGI(GATTS_TAG, "Characteristic write, conn_id %d, trans_id %" PRIu32 ", handle %d", param->write.conn_id, param->write.trans_id, param->write.handle);
  373. if (!param->write.is_prep){
  374. ESP_LOGI(GATTS_TAG, "value len %d, value ", param->write.len);
  375. ESP_LOG_BUFFER_HEX(GATTS_TAG, param->write.value, param->write.len);
  376. if (gl_profile_tab[PROFILE_A_APP_ID].descr_handle == param->write.handle && param->write.len == 2){
  377. descr_value = param->write.value[1]<<8 | param->write.value[0];
  378. if (descr_value == 0x0001){
  379. if (a_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY){
  380. ESP_LOGI(GATTS_TAG, "Notification enable");
  381. uint8_t notify_data[15];
  382. for (int i = 0; i < sizeof(notify_data); ++i)
  383. {
  384. notify_data[i] = i%0xff;
  385. }
  386. //the size of notify_data[] need less than MTU size
  387. esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_A_APP_ID].char_handle,
  388. sizeof(notify_data), notify_data, false);
  389. }
  390. }else if (descr_value == 0x0002){
  391. if (a_property & ESP_GATT_CHAR_PROP_BIT_INDICATE){
  392. ESP_LOGI(GATTS_TAG, "Indication enable");
  393. uint8_t indicate_data[15];
  394. for (int i = 0; i < sizeof(indicate_data); ++i)
  395. {
  396. indicate_data[i] = i%0xff;
  397. }
  398. //the size of indicate_data[] need less than MTU size
  399. esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_A_APP_ID].char_handle,
  400. sizeof(indicate_data), indicate_data, true);
  401. }
  402. }
  403. else if (descr_value == 0x0000){
  404. ESP_LOGI(GATTS_TAG, "Notification/Indication disable");
  405. }else{
  406. ESP_LOGE(GATTS_TAG, "Unknown descriptor value");
  407. ESP_LOG_BUFFER_HEX(GATTS_TAG, param->write.value, param->write.len);
  408. }
  409. }
  410. }
  411. example_write_event_env(gatts_if, &a_prepare_write_env, param);
  412. break;
  413. }
  414. case ESP_GATTS_EXEC_WRITE_EVT:
  415. ESP_LOGI(GATTS_TAG,"Execute write");
  416. esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
  417. example_exec_write_event_env(&a_prepare_write_env, param);
  418. break;
  419. case ESP_GATTS_MTU_EVT:
  420. ESP_LOGI(GATTS_TAG, "MTU exchange, MTU %d", param->mtu.mtu);
  421. local_mtu = param->mtu.mtu;
  422. break;
  423. case ESP_GATTS_UNREG_EVT:
  424. break;
  425. case ESP_GATTS_CREATE_EVT:
  426. ESP_LOGI(GATTS_TAG, "Service create, status %d, service_handle %d", param->create.status, param->create.service_handle);
  427. gl_profile_tab[PROFILE_A_APP_ID].service_handle = param->create.service_handle;
  428. gl_profile_tab[PROFILE_A_APP_ID].char_uuid.len = ESP_UUID_LEN_16;
  429. gl_profile_tab[PROFILE_A_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_A;
  430. esp_ble_gatts_start_service(gl_profile_tab[PROFILE_A_APP_ID].service_handle);
  431. a_property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
  432. esp_err_t add_char_ret = esp_ble_gatts_add_char(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].char_uuid,
  433. ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
  434. a_property,
  435. &gatts_demo_char1_val, NULL);
  436. if (add_char_ret){
  437. ESP_LOGE(GATTS_TAG, "add char failed, error code =%x",add_char_ret);
  438. }
  439. break;
  440. case ESP_GATTS_ADD_INCL_SRVC_EVT:
  441. break;
  442. case ESP_GATTS_ADD_CHAR_EVT: {
  443. uint16_t length = 0;
  444. const uint8_t *prf_char;
  445. ESP_LOGI(GATTS_TAG, "Characteristic add, status %d, attr_handle %d, service_handle %d",
  446. param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
  447. gl_profile_tab[PROFILE_A_APP_ID].char_handle = param->add_char.attr_handle;
  448. gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.len = ESP_UUID_LEN_16;
  449. gl_profile_tab[PROFILE_A_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
  450. esp_err_t get_attr_ret = esp_ble_gatts_get_attr_value(param->add_char.attr_handle, &length, &prf_char);
  451. if (get_attr_ret == ESP_FAIL){
  452. ESP_LOGE(GATTS_TAG, "ILLEGAL HANDLE");
  453. }
  454. ESP_LOGI(GATTS_TAG, "the gatts demo char length = %x", length);
  455. for(int i = 0; i < length; i++){
  456. ESP_LOGI(GATTS_TAG, "prf_char[%x] =%x",i,prf_char[i]);
  457. }
  458. esp_err_t add_descr_ret = esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_A_APP_ID].service_handle, &gl_profile_tab[PROFILE_A_APP_ID].descr_uuid,
  459. ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE, NULL, NULL);
  460. if (add_descr_ret){
  461. ESP_LOGE(GATTS_TAG, "add char descr failed, error code =%x", add_descr_ret);
  462. }
  463. break;
  464. }
  465. case ESP_GATTS_ADD_CHAR_DESCR_EVT:
  466. gl_profile_tab[PROFILE_A_APP_ID].descr_handle = param->add_char_descr.attr_handle;
  467. ESP_LOGI(GATTS_TAG, "Descriptor add, status %d, attr_handle %d, service_handle %d",
  468. param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
  469. break;
  470. case ESP_GATTS_DELETE_EVT:
  471. break;
  472. case ESP_GATTS_START_EVT:
  473. ESP_LOGI(GATTS_TAG, "Service start, status %d, service_handle %d",
  474. param->start.status, param->start.service_handle);
  475. break;
  476. case ESP_GATTS_STOP_EVT:
  477. break;
  478. case ESP_GATTS_CONNECT_EVT: {
  479. esp_ble_conn_update_params_t conn_params = {0};
  480. memcpy(conn_params.bda, param->connect.remote_bda, sizeof(esp_bd_addr_t));
  481. /* For the IOS system, please reference the apple official documents about the ble connection parameters restrictions. */
  482. conn_params.latency = 0;
  483. conn_params.max_int = 0x20; // max_int = 0x20*1.25ms = 40ms
  484. conn_params.min_int = 0x10; // min_int = 0x10*1.25ms = 20ms
  485. conn_params.timeout = 400; // timeout = 400*10ms = 4000ms
  486. ESP_LOGI(GATTS_TAG, "Connected, conn_id %u, remote "ESP_BD_ADDR_STR"",
  487. param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda));
  488. gl_profile_tab[PROFILE_A_APP_ID].conn_id = param->connect.conn_id;
  489. //start sent the update connection parameters to the peer device.
  490. esp_ble_gap_update_conn_params(&conn_params);
  491. break;
  492. }
  493. case ESP_GATTS_DISCONNECT_EVT:
  494. ESP_LOGI(GATTS_TAG, "Disconnected, remote "ESP_BD_ADDR_STR", reason 0x%02x",
  495. ESP_BD_ADDR_HEX(param->disconnect.remote_bda), param->disconnect.reason);
  496. esp_ble_gap_start_advertising(&adv_params);
  497. local_mtu = 23; // Reset MTU for a single connection
  498. break;
  499. case ESP_GATTS_CONF_EVT:
  500. ESP_LOGI(GATTS_TAG, "Confirm receive, status %d, attr_handle %d", param->conf.status, param->conf.handle);
  501. if (param->conf.status != ESP_GATT_OK){
  502. ESP_LOG_BUFFER_HEX(GATTS_TAG, param->conf.value, param->conf.len);
  503. }
  504. break;
  505. case ESP_GATTS_OPEN_EVT:
  506. case ESP_GATTS_CANCEL_OPEN_EVT:
  507. case ESP_GATTS_CLOSE_EVT:
  508. case ESP_GATTS_LISTEN_EVT:
  509. case ESP_GATTS_CONGEST_EVT:
  510. default:
  511. break;
  512. }
  513. }
  514. static void gatts_profile_b_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param) {
  515. switch (event) {
  516. case ESP_GATTS_REG_EVT:
  517. ESP_LOGI(GATTS_TAG, "GATT server register, status %d, app_id %d, gatts_if %d", param->reg.status, param->reg.app_id, gatts_if);
  518. gl_profile_tab[PROFILE_B_APP_ID].service_id.is_primary = true;
  519. gl_profile_tab[PROFILE_B_APP_ID].service_id.id.inst_id = 0x00;
  520. gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.len = ESP_UUID_LEN_16;
  521. gl_profile_tab[PROFILE_B_APP_ID].service_id.id.uuid.uuid.uuid16 = GATTS_SERVICE_UUID_TEST_B;
  522. esp_ble_gatts_create_service(gatts_if, &gl_profile_tab[PROFILE_B_APP_ID].service_id, GATTS_NUM_HANDLE_TEST_B);
  523. break;
  524. case ESP_GATTS_READ_EVT: {
  525. ESP_LOGI(GATTS_TAG, "Characteristic read, conn_id %d, trans_id %" PRIu32 ", handle %d", param->read.conn_id, param->read.trans_id, param->read.handle);
  526. esp_gatt_rsp_t rsp;
  527. memset(&rsp, 0, sizeof(esp_gatt_rsp_t));
  528. rsp.attr_value.handle = param->read.handle;
  529. rsp.attr_value.len = 4;
  530. rsp.attr_value.value[0] = 0xde;
  531. rsp.attr_value.value[1] = 0xed;
  532. rsp.attr_value.value[2] = 0xbe;
  533. rsp.attr_value.value[3] = 0xef;
  534. esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id,
  535. ESP_GATT_OK, &rsp);
  536. break;
  537. }
  538. case ESP_GATTS_WRITE_EVT: {
  539. ESP_LOGI(GATTS_TAG, "Characteristic write, conn_id %d, trans_id %" PRIu32 ", handle %d", param->write.conn_id, param->write.trans_id, param->write.handle);
  540. if (!param->write.is_prep){
  541. ESP_LOGI(GATTS_TAG, "value len %d, value ", param->write.len);
  542. ESP_LOG_BUFFER_HEX(GATTS_TAG, param->write.value, param->write.len);
  543. if (gl_profile_tab[PROFILE_B_APP_ID].descr_handle == param->write.handle && param->write.len == 2){
  544. uint16_t descr_value= param->write.value[1]<<8 | param->write.value[0];
  545. if (descr_value == 0x0001){
  546. if (b_property & ESP_GATT_CHAR_PROP_BIT_NOTIFY) {
  547. ESP_LOGI(GATTS_TAG, "Notification enable");
  548. uint8_t notify_data[15];
  549. for (int i = 0; i < sizeof(notify_data); ++i)
  550. {
  551. notify_data[i] = i%0xff;
  552. }
  553. //the size of notify_data[] need less than MTU size
  554. esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_B_APP_ID].char_handle,
  555. sizeof(notify_data), notify_data, false);
  556. }
  557. }else if (descr_value == 0x0002){
  558. if (b_property & ESP_GATT_CHAR_PROP_BIT_INDICATE){
  559. ESP_LOGI(GATTS_TAG, "Indication enable");
  560. uint8_t indicate_data[15];
  561. for (int i = 0; i < sizeof(indicate_data); ++i)
  562. {
  563. indicate_data[i] = i%0xff;
  564. }
  565. //the size of indicate_data[] need less than MTU size
  566. esp_ble_gatts_send_indicate(gatts_if, param->write.conn_id, gl_profile_tab[PROFILE_B_APP_ID].char_handle,
  567. sizeof(indicate_data), indicate_data, true);
  568. }
  569. }
  570. else if (descr_value == 0x0000){
  571. ESP_LOGI(GATTS_TAG, "Notification/Indication disable");
  572. }else{
  573. ESP_LOGE(GATTS_TAG, "Unknown value");
  574. }
  575. }
  576. }
  577. example_write_event_env(gatts_if, &b_prepare_write_env, param);
  578. break;
  579. }
  580. case ESP_GATTS_EXEC_WRITE_EVT:
  581. ESP_LOGI(GATTS_TAG,"Execute write");
  582. esp_ble_gatts_send_response(gatts_if, param->write.conn_id, param->write.trans_id, ESP_GATT_OK, NULL);
  583. example_exec_write_event_env(&b_prepare_write_env, param);
  584. break;
  585. case ESP_GATTS_MTU_EVT:
  586. ESP_LOGI(GATTS_TAG, "MTU exchange, MTU %d", param->mtu.mtu);
  587. break;
  588. case ESP_GATTS_UNREG_EVT:
  589. break;
  590. case ESP_GATTS_CREATE_EVT:
  591. ESP_LOGI(GATTS_TAG, "Service create, status %d, service_handle %d", param->create.status, param->create.service_handle);
  592. gl_profile_tab[PROFILE_B_APP_ID].service_handle = param->create.service_handle;
  593. gl_profile_tab[PROFILE_B_APP_ID].char_uuid.len = ESP_UUID_LEN_16;
  594. gl_profile_tab[PROFILE_B_APP_ID].char_uuid.uuid.uuid16 = GATTS_CHAR_UUID_TEST_B;
  595. esp_ble_gatts_start_service(gl_profile_tab[PROFILE_B_APP_ID].service_handle);
  596. b_property = ESP_GATT_CHAR_PROP_BIT_READ | ESP_GATT_CHAR_PROP_BIT_WRITE | ESP_GATT_CHAR_PROP_BIT_NOTIFY;
  597. esp_err_t add_char_ret =esp_ble_gatts_add_char( gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].char_uuid,
  598. ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
  599. b_property,
  600. NULL, NULL);
  601. if (add_char_ret){
  602. ESP_LOGE(GATTS_TAG, "add char failed, error code =%x",add_char_ret);
  603. }
  604. break;
  605. case ESP_GATTS_ADD_INCL_SRVC_EVT:
  606. break;
  607. case ESP_GATTS_ADD_CHAR_EVT:
  608. ESP_LOGI(GATTS_TAG, "Characteristic add, status %d, attr_handle %d, service_handle %d",
  609. param->add_char.status, param->add_char.attr_handle, param->add_char.service_handle);
  610. gl_profile_tab[PROFILE_B_APP_ID].char_handle = param->add_char.attr_handle;
  611. gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.len = ESP_UUID_LEN_16;
  612. gl_profile_tab[PROFILE_B_APP_ID].descr_uuid.uuid.uuid16 = ESP_GATT_UUID_CHAR_CLIENT_CONFIG;
  613. esp_ble_gatts_add_char_descr(gl_profile_tab[PROFILE_B_APP_ID].service_handle, &gl_profile_tab[PROFILE_B_APP_ID].descr_uuid,
  614. ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
  615. NULL, NULL);
  616. break;
  617. case ESP_GATTS_ADD_CHAR_DESCR_EVT:
  618. gl_profile_tab[PROFILE_B_APP_ID].descr_handle = param->add_char_descr.attr_handle;
  619. ESP_LOGI(GATTS_TAG, "Descriptor add, status %d, attr_handle %d, service_handle %d",
  620. param->add_char_descr.status, param->add_char_descr.attr_handle, param->add_char_descr.service_handle);
  621. break;
  622. case ESP_GATTS_DELETE_EVT:
  623. break;
  624. case ESP_GATTS_START_EVT:
  625. ESP_LOGI(GATTS_TAG, "Service start, status %d, service_handle %d",
  626. param->start.status, param->start.service_handle);
  627. break;
  628. case ESP_GATTS_STOP_EVT:
  629. break;
  630. case ESP_GATTS_CONNECT_EVT:
  631. ESP_LOGI(GATTS_TAG, "Connected, conn_id %d, remote "ESP_BD_ADDR_STR"",
  632. param->connect.conn_id, ESP_BD_ADDR_HEX(param->connect.remote_bda));
  633. gl_profile_tab[PROFILE_B_APP_ID].conn_id = param->connect.conn_id;
  634. break;
  635. case ESP_GATTS_CONF_EVT:
  636. ESP_LOGI(GATTS_TAG, "Confirm receive, status %d, attr_handle %d", param->conf.status, param->conf.handle);
  637. if (param->conf.status != ESP_GATT_OK){
  638. ESP_LOG_BUFFER_HEX(GATTS_TAG, param->conf.value, param->conf.len);
  639. }
  640. break;
  641. case ESP_GATTS_DISCONNECT_EVT:
  642. case ESP_GATTS_OPEN_EVT:
  643. case ESP_GATTS_CANCEL_OPEN_EVT:
  644. case ESP_GATTS_CLOSE_EVT:
  645. case ESP_GATTS_LISTEN_EVT:
  646. case ESP_GATTS_CONGEST_EVT:
  647. default:
  648. break;
  649. }
  650. }
  651. static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatts_if, esp_ble_gatts_cb_param_t *param)
  652. {
  653. /* If event is register event, store the gatts_if for each profile */
  654. if (event == ESP_GATTS_REG_EVT) {
  655. if (param->reg.status == ESP_GATT_OK) {
  656. gl_profile_tab[param->reg.app_id].gatts_if = gatts_if;
  657. } else {
  658. ESP_LOGI(GATTS_TAG, "Reg app failed, app_id %04x, status %d",
  659. param->reg.app_id,
  660. param->reg.status);
  661. return;
  662. }
  663. }
  664. /* If the gatts_if equal to profile A, call profile A cb handler,
  665. * so here call each profile's callback */
  666. do {
  667. int idx;
  668. for (idx = 0; idx < PROFILE_NUM; idx++) {
  669. if (gatts_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
  670. gatts_if == gl_profile_tab[idx].gatts_if) {
  671. if (gl_profile_tab[idx].gatts_cb) {
  672. gl_profile_tab[idx].gatts_cb(event, gatts_if, param);
  673. }
  674. }
  675. }
  676. } while (0);
  677. }
  678. void app_main(void)
  679. {
  680. esp_err_t ret;
  681. // Initialize NVS.
  682. ret = nvs_flash_init();
  683. if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  684. ESP_ERROR_CHECK(nvs_flash_erase());
  685. ret = nvs_flash_init();
  686. }
  687. ESP_ERROR_CHECK( ret );
  688. #if CONFIG_EXAMPLE_CI_PIPELINE_ID
  689. memcpy(test_device_name, esp_bluedroid_get_example_name(), ESP_BLE_ADV_NAME_LEN_MAX);
  690. #endif
  691. ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
  692. esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
  693. ret = esp_bt_controller_init(&bt_cfg);
  694. if (ret) {
  695. ESP_LOGE(GATTS_TAG, "%s initialize controller failed: %s", __func__, esp_err_to_name(ret));
  696. return;
  697. }
  698. ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
  699. if (ret) {
  700. ESP_LOGE(GATTS_TAG, "%s enable controller failed: %s", __func__, esp_err_to_name(ret));
  701. return;
  702. }
  703. ret = esp_bluedroid_init();
  704. if (ret) {
  705. ESP_LOGE(GATTS_TAG, "%s init bluetooth failed: %s", __func__, esp_err_to_name(ret));
  706. return;
  707. }
  708. ret = esp_bluedroid_enable();
  709. if (ret) {
  710. ESP_LOGE(GATTS_TAG, "%s enable bluetooth failed: %s", __func__, esp_err_to_name(ret));
  711. return;
  712. }
  713. // Note: Avoid performing time-consuming operations within callback functions.
  714. ret = esp_ble_gatts_register_callback(gatts_event_handler);
  715. if (ret){
  716. ESP_LOGE(GATTS_TAG, "gatts register error, error code = %x", ret);
  717. return;
  718. }
  719. ret = esp_ble_gap_register_callback(gap_event_handler);
  720. if (ret){
  721. ESP_LOGE(GATTS_TAG, "gap register error, error code = %x", ret);
  722. return;
  723. }
  724. ret = esp_ble_gatts_app_register(PROFILE_A_APP_ID);
  725. if (ret){
  726. ESP_LOGE(GATTS_TAG, "gatts app register error, error code = %x", ret);
  727. return;
  728. }
  729. ret = esp_ble_gatts_app_register(PROFILE_B_APP_ID);
  730. if (ret){
  731. ESP_LOGE(GATTS_TAG, "gatts app register error, error code = %x", ret);
  732. return;
  733. }
  734. esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(500);
  735. if (local_mtu_ret){
  736. ESP_LOGE(GATTS_TAG, "set local MTU failed, error code = %x", local_mtu_ret);
  737. }
  738. return;
  739. }