You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

749 lines
28 KiB

3 years ago
3 years ago
  1. /*
  2. This example code is in the Public Domain (or CC0 licensed, at your option.)
  3. Unless required by applicable law or agreed to in writing, this
  4. software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
  5. CONDITIONS OF ANY KIND, either express or implied.
  6. */
  7. /****************************************************************************
  8. *
  9. * This file is for ble spp client demo.
  10. *
  11. ****************************************************************************/
  12. #include <stdint.h>
  13. #include <string.h>
  14. #include <stdbool.h>
  15. #include <stdio.h>
  16. #include "driver/uart.h"
  17. #include "esp_bt.h"
  18. #include "nvs_flash.h"
  19. #include "esp_bt_device.h"
  20. #include "esp_gap_ble_api.h"
  21. #include "esp_gattc_api.h"
  22. #include "esp_gatt_defs.h"
  23. #include "esp_bt_main.h"
  24. #include "esp_system.h"
  25. #include "esp_gatt_common_api.h"
  26. #include "esp_log.h"
  27. #include "freertos/FreeRTOS.h"
  28. void motor_drive_hex_to_str(char *hex, int hex_len, char *str);
  29. #define GATTC_TAG "GATTC_SPP_DEMO"
  30. #define PROFILE_NUM 1
  31. #define PROFILE_APP_ID 0
  32. #define BT_BD_ADDR_STR "%02x:%02x:%02x:%02x:%02x:%02x"
  33. #define BT_BD_ADDR_HEX(addr) addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]
  34. #define ESP_GATT_SPP_SERVICE_UUID \
  35. { \
  36. 0x9E, 0xCA, 0xDC, 0x24, 0x0E, 0xE5, 0xA9, 0xE0, 0x93, 0xF3, 0xA3, 0xB5, 0x01, 0x00, 0x40, 0x6E \
  37. }
  38. #define SCAN_ALL_THE_TIME 0
  39. struct gattc_profile_inst
  40. {
  41. esp_gattc_cb_t gattc_cb;
  42. uint16_t gattc_if;
  43. uint16_t app_id;
  44. uint16_t conn_id;
  45. uint16_t service_start_handle;
  46. uint16_t service_end_handle;
  47. uint16_t char_handle;
  48. esp_bd_addr_t remote_bda;
  49. };
  50. enum
  51. {
  52. SPP_IDX_SVC,
  53. SPP_IDX_SPP_DATA_NTY_VAL,
  54. SPP_IDX_SPP_DATA_NTF_CFG,
  55. SPP_IDX_SPP_DATA_RECV_VAL,
  56. #ifdef SUPPORT_HEARTBEAT
  57. SPP_IDX_SPP_HEARTBEAT_VAL,
  58. SPP_IDX_SPP_HEARTBEAT_CFG,
  59. #endif
  60. SPP_IDX_NB,
  61. };
  62. /// Declare static functions
  63. static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param);
  64. static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param);
  65. 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);
  66. /* One gatt-based profile one app_id and one gattc_if, this array will store the gattc_if returned by ESP_GATTS_REG_EVT */
  67. static struct gattc_profile_inst gl_profile_tab[PROFILE_NUM] = {
  68. [PROFILE_APP_ID] = {
  69. .gattc_cb = gattc_profile_event_handler,
  70. .gattc_if = ESP_GATT_IF_NONE, /* Not get the gatt_if, so initial is ESP_GATT_IF_NONE */
  71. },
  72. };
  73. static esp_ble_scan_params_t ble_scan_params = {
  74. .scan_type = BLE_SCAN_TYPE_ACTIVE,
  75. .own_addr_type = BLE_ADDR_TYPE_PUBLIC,
  76. .scan_filter_policy = BLE_SCAN_FILTER_ALLOW_ALL,
  77. .scan_interval = 0x50,
  78. .scan_window = 0x30,
  79. .scan_duplicate = BLE_SCAN_DUPLICATE_DISABLE};
  80. static const char device_name[] = "yimei_ble";
  81. static bool is_connect = false;
  82. static uint16_t spp_conn_id = 0;
  83. static uint16_t spp_mtu_size = 23;
  84. static uint16_t cmd = 0;
  85. static uint16_t spp_srv_start_handle = 0;
  86. static uint16_t spp_srv_end_handle = 0;
  87. static uint16_t spp_gattc_if = 0xff;
  88. static char *notify_value_p = NULL;
  89. static int notify_value_offset = 0;
  90. static int notify_value_count = 0;
  91. static uint16_t count = SPP_IDX_NB;
  92. static esp_gattc_db_elem_t *db = NULL;
  93. static esp_ble_gap_cb_param_t scan_rst;
  94. static xQueueHandle cmd_reg_queue = NULL;
  95. QueueHandle_t spp_uart_queue = NULL;
  96. #ifdef SUPPORT_HEARTBEAT
  97. static uint8_t heartbeat_s[9] = {'E', 's', 'p', 'r', 'e', 's', 's', 'i', 'f'};
  98. static xQueueHandle cmd_heartbeat_queue = NULL;
  99. #endif
  100. static esp_bt_uuid_t spp_service_uuid = {
  101. .len = ESP_UUID_LEN_128,
  102. .uuid = {
  103. .uuid128 = ESP_GATT_SPP_SERVICE_UUID,
  104. },
  105. };
  106. static void notify_event_handler(esp_ble_gattc_cb_param_t *p_data)
  107. {
  108. uint8_t handle = 0;
  109. if (p_data->notify.is_notify == true)
  110. {
  111. ESP_LOGI(GATTC_TAG, "+NOTIFY:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len);
  112. }
  113. else
  114. {
  115. ESP_LOGI(GATTC_TAG, "+INDICATE:handle = %d,length = %d ", p_data->notify.handle, p_data->notify.value_len);
  116. }
  117. handle = p_data->notify.handle;
  118. if (db == NULL)
  119. {
  120. ESP_LOGE(GATTC_TAG, " %s db is NULL\n", __func__);
  121. return;
  122. }
  123. if (handle == db[SPP_IDX_SPP_DATA_NTY_VAL].attribute_handle)
  124. {
  125. #ifdef SPP_DEBUG_MODE
  126. esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len);
  127. #else
  128. if ((p_data->notify.value[0] == '#') && (p_data->notify.value[1] == '#'))
  129. {
  130. if ((++notify_value_count) != p_data->notify.value[3])
  131. {
  132. if (notify_value_p != NULL)
  133. {
  134. free(notify_value_p);
  135. }
  136. notify_value_count = 0;
  137. notify_value_p = NULL;
  138. notify_value_offset = 0;
  139. ESP_LOGE(GATTC_TAG, "notify value count is not continuous,%s\n", __func__);
  140. return;
  141. }
  142. if (p_data->notify.value[3] == 1)
  143. {
  144. notify_value_p = (char *)malloc(((spp_mtu_size - 7) * (p_data->notify.value[2])) * sizeof(char));
  145. if (notify_value_p == NULL)
  146. {
  147. ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n", __func__, __LINE__);
  148. notify_value_count = 0;
  149. return;
  150. }
  151. memcpy((notify_value_p + notify_value_offset), (p_data->notify.value + 4), (p_data->notify.value_len - 4));
  152. if (p_data->notify.value[2] == p_data->notify.value[3])
  153. {
  154. uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
  155. free(notify_value_p);
  156. notify_value_p = NULL;
  157. notify_value_offset = 0;
  158. return;
  159. }
  160. notify_value_offset += (p_data->notify.value_len - 4);
  161. }
  162. else if (p_data->notify.value[3] <= p_data->notify.value[2])
  163. {
  164. memcpy((notify_value_p + notify_value_offset), (p_data->notify.value + 4), (p_data->notify.value_len - 4));
  165. if (p_data->notify.value[3] == p_data->notify.value[2])
  166. {
  167. uart_write_bytes(UART_NUM_0, (char *)(notify_value_p), (p_data->notify.value_len - 4 + notify_value_offset));
  168. free(notify_value_p);
  169. notify_value_count = 0;
  170. notify_value_p = NULL;
  171. notify_value_offset = 0;
  172. return;
  173. }
  174. notify_value_offset += (p_data->notify.value_len - 4);
  175. }
  176. }
  177. else
  178. {
  179. uart_write_bytes(UART_NUM_0, (char *)(p_data->notify.value), p_data->notify.value_len);
  180. }
  181. #endif
  182. }
  183. // else if (handle == ((db + SPP_IDX_SPP_STATUS_VAL)->attribute_handle))
  184. // {
  185. // esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len);
  186. // // TODO:server notify status characteristic
  187. // }
  188. else
  189. {
  190. esp_log_buffer_char(GATTC_TAG, (char *)p_data->notify.value, p_data->notify.value_len);
  191. }
  192. }
  193. static void free_gattc_srv_db(void)
  194. {
  195. is_connect = false;
  196. spp_gattc_if = 0xff;
  197. spp_conn_id = 0;
  198. spp_mtu_size = 23;
  199. cmd = 0;
  200. spp_srv_start_handle = 0;
  201. spp_srv_end_handle = 0;
  202. notify_value_p = NULL;
  203. notify_value_offset = 0;
  204. notify_value_count = 0;
  205. if (db)
  206. {
  207. free(db);
  208. db = NULL;
  209. }
  210. }
  211. static void esp_gap_cb(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param)
  212. {
  213. uint8_t *adv_name = NULL;
  214. uint8_t adv_name_len = 0;
  215. esp_err_t err;
  216. switch (event)
  217. {
  218. case ESP_GAP_BLE_SCAN_PARAM_SET_COMPLETE_EVT:
  219. {
  220. if ((err = param->scan_param_cmpl.status) != ESP_BT_STATUS_SUCCESS)
  221. {
  222. ESP_LOGE(GATTC_TAG, "Scan param set failed: %s", esp_err_to_name(err));
  223. break;
  224. }
  225. // the unit of the duration is second
  226. uint32_t duration = 0xFFFF;
  227. ESP_LOGI(GATTC_TAG, "Enable Ble Scan:during time 0x%04X minutes.", duration);
  228. esp_ble_gap_start_scanning(duration);
  229. break;
  230. }
  231. case ESP_GAP_BLE_SCAN_START_COMPLETE_EVT:
  232. // scan start complete event to indicate scan start successfully or failed
  233. if ((err = param->scan_start_cmpl.status) != ESP_BT_STATUS_SUCCESS)
  234. {
  235. ESP_LOGE(GATTC_TAG, "Scan start failed: %s", esp_err_to_name(err));
  236. break;
  237. }
  238. ESP_LOGI(GATTC_TAG, "Scan start successed");
  239. break;
  240. case ESP_GAP_BLE_SCAN_STOP_COMPLETE_EVT:
  241. if ((err = param->scan_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS)
  242. {
  243. ESP_LOGE(GATTC_TAG, "Scan stop failed: %s", esp_err_to_name(err));
  244. break;
  245. }
  246. ESP_LOGI(GATTC_TAG, "Scan stop successed");
  247. if (is_connect == false)
  248. {
  249. ESP_LOGI(GATTC_TAG, "Connect to the remote device.");
  250. 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);
  251. }
  252. break;
  253. case ESP_GAP_BLE_SCAN_RESULT_EVT:
  254. {
  255. esp_ble_gap_cb_param_t *scan_result = (esp_ble_gap_cb_param_t *)param;
  256. switch (scan_result->scan_rst.search_evt)
  257. {
  258. case ESP_GAP_SEARCH_INQ_RES_EVT:
  259. esp_log_buffer_hex(GATTC_TAG, scan_result->scan_rst.bda, 6);
  260. 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);
  261. adv_name = esp_ble_resolve_adv_data(scan_result->scan_rst.ble_adv, ESP_BLE_AD_TYPE_NAME_CMPL, &adv_name_len);
  262. ESP_LOGI(GATTC_TAG, "Searched Device Name Len %d", adv_name_len);
  263. esp_log_buffer_char(GATTC_TAG, adv_name, adv_name_len);
  264. ESP_LOGI(GATTC_TAG, "\n");
  265. if (adv_name != NULL)
  266. {
  267. if (strncmp((char *)adv_name, device_name, adv_name_len) == 0)
  268. {
  269. memcpy(&(scan_rst), scan_result, sizeof(esp_ble_gap_cb_param_t));
  270. esp_ble_gap_stop_scanning();
  271. }
  272. }
  273. break;
  274. case ESP_GAP_SEARCH_INQ_CMPL_EVT:
  275. break;
  276. default:
  277. break;
  278. }
  279. break;
  280. }
  281. case ESP_GAP_BLE_ADV_STOP_COMPLETE_EVT:
  282. if ((err = param->adv_stop_cmpl.status) != ESP_BT_STATUS_SUCCESS)
  283. {
  284. ESP_LOGE(GATTC_TAG, "Adv stop failed: %s", esp_err_to_name(err));
  285. }
  286. else
  287. {
  288. ESP_LOGI(GATTC_TAG, "Stop adv successfully");
  289. }
  290. break;
  291. default:
  292. break;
  293. }
  294. }
  295. static void esp_gattc_cb(esp_gattc_cb_event_t event, esp_gatt_if_t gattc_if, esp_ble_gattc_cb_param_t *param)
  296. {
  297. ESP_LOGI(GATTC_TAG, "EVT %d, gattc if %d", event, gattc_if);
  298. /* If event is register event, store the gattc_if for each profile */
  299. if (event == ESP_GATTC_REG_EVT)
  300. {
  301. if (param->reg.status == ESP_GATT_OK)
  302. {
  303. gl_profile_tab[param->reg.app_id].gattc_if = gattc_if;
  304. }
  305. else
  306. {
  307. ESP_LOGI(GATTC_TAG, "Reg app failed, app_id %04x, status %d", param->reg.app_id, param->reg.status);
  308. return;
  309. }
  310. }
  311. /* If the gattc_if equal to profile A, call profile A cb handler,
  312. * so here call each profile's callback */
  313. do
  314. {
  315. int idx;
  316. for (idx = 0; idx < PROFILE_NUM; idx++)
  317. {
  318. if (gattc_if == ESP_GATT_IF_NONE || /* ESP_GATT_IF_NONE, not specify a certain gatt_if, need to call every profile cb function */
  319. gattc_if == gl_profile_tab[idx].gattc_if)
  320. {
  321. if (gl_profile_tab[idx].gattc_cb)
  322. {
  323. gl_profile_tab[idx].gattc_cb(event, gattc_if, param);
  324. }
  325. }
  326. }
  327. } while (0);
  328. }
  329. 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)
  330. {
  331. esp_ble_gattc_cb_param_t *p_data = (esp_ble_gattc_cb_param_t *)param;
  332. switch (event)
  333. {
  334. case ESP_GATTC_REG_EVT:
  335. ESP_LOGI(GATTC_TAG, "REG EVT, set scan params");
  336. esp_ble_gap_set_scan_params(&ble_scan_params);
  337. break;
  338. case ESP_GATTC_CONNECT_EVT:
  339. ESP_LOGI(GATTC_TAG, "ESP_GATTC_CONNECT_EVT: conn_id=%d, gatt_if = %d", spp_conn_id, gattc_if);
  340. ESP_LOGI(GATTC_TAG, "REMOTE BDA:");
  341. esp_log_buffer_hex(GATTC_TAG, gl_profile_tab[PROFILE_APP_ID].remote_bda, sizeof(esp_bd_addr_t));
  342. spp_gattc_if = gattc_if;
  343. is_connect = true;
  344. spp_conn_id = p_data->connect.conn_id;
  345. memcpy(gl_profile_tab[PROFILE_APP_ID].remote_bda, p_data->connect.remote_bda, sizeof(esp_bd_addr_t));
  346. esp_ble_gattc_search_service(spp_gattc_if, spp_conn_id, &spp_service_uuid);
  347. break;
  348. case ESP_GATTC_DISCONNECT_EVT:
  349. ESP_LOGI(GATTC_TAG, "disconnect");
  350. free_gattc_srv_db();
  351. esp_ble_gap_start_scanning(SCAN_ALL_THE_TIME);
  352. break;
  353. case ESP_GATTC_SEARCH_RES_EVT:
  354. 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);
  355. for (int i = 15; i >= 0; i--)
  356. {
  357. ESP_LOGI("uuid", "UUID[%d] = %d", i, p_data->search_res.srvc_id.uuid.uuid.uuid128[i]);
  358. }
  359. spp_srv_start_handle = p_data->search_res.start_handle;
  360. spp_srv_end_handle = p_data->search_res.end_handle;
  361. break;
  362. case ESP_GATTC_SEARCH_CMPL_EVT:
  363. ESP_LOGI(GATTC_TAG, "SEARCH_CMPL: conn_id = %x, status %d", spp_conn_id, p_data->search_cmpl.status);
  364. esp_ble_gattc_send_mtu_req(gattc_if, spp_conn_id);
  365. break;
  366. case ESP_GATTC_REG_FOR_NOTIFY_EVT:
  367. {
  368. ESP_LOGI(GATTC_TAG, "Index = %d,status = %d,handle = %d\n", cmd, p_data->reg_for_notify.status, p_data->reg_for_notify.handle);
  369. if (p_data->reg_for_notify.status != ESP_GATT_OK)
  370. {
  371. ESP_LOGE(GATTC_TAG, "ESP_GATTC_REG_FOR_NOTIFY_EVT, status = %d", p_data->reg_for_notify.status);
  372. break;
  373. }
  374. uint16_t notify_en = 1;
  375. esp_ble_gattc_write_char_descr(
  376. spp_gattc_if,
  377. spp_conn_id,
  378. (db + cmd + 1)->attribute_handle,
  379. sizeof(notify_en),
  380. (uint8_t *)&notify_en,
  381. ESP_GATT_WRITE_TYPE_RSP,
  382. ESP_GATT_AUTH_REQ_NONE);
  383. break;
  384. }
  385. case ESP_GATTC_NOTIFY_EVT:
  386. ESP_LOGI(GATTC_TAG, "ESP_GATTC_NOTIFY_EVT\n");
  387. notify_event_handler(p_data);
  388. break;
  389. case ESP_GATTC_READ_CHAR_EVT:
  390. ESP_LOGI(GATTC_TAG, "ESP_GATTC_READ_CHAR_EVT\n");
  391. break;
  392. case ESP_GATTC_WRITE_CHAR_EVT:
  393. ESP_LOGI(GATTC_TAG, "ESP_GATTC_WRITE_CHAR_EVT:status = %d,handle = %d", param->write.status, param->write.handle);
  394. if (param->write.status != ESP_GATT_OK)
  395. {
  396. ESP_LOGE(GATTC_TAG, "ESP_GATTC_WRITE_CHAR_EVT, error status = %d", p_data->write.status);
  397. break;
  398. }
  399. break;
  400. case ESP_GATTC_PREP_WRITE_EVT:
  401. break;
  402. case ESP_GATTC_EXEC_EVT:
  403. break;
  404. case ESP_GATTC_WRITE_DESCR_EVT:
  405. ESP_LOGI(GATTC_TAG, "ESP_GATTC_WRITE_DESCR_EVT: status =%d,handle = %d \n", p_data->write.status, p_data->write.handle);
  406. if (p_data->write.status != ESP_GATT_OK)
  407. {
  408. ESP_LOGE(GATTC_TAG, "ESP_GATTC_WRITE_DESCR_EVT, error status = %d", p_data->write.status);
  409. break;
  410. }
  411. switch (cmd)
  412. {
  413. case SPP_IDX_SPP_DATA_NTY_VAL:
  414. // cmd = SPP_IDX_SPP_STATUS_VAL;
  415. // ESP_LOGI("test","============cmd = %d========",cmd);
  416. // xQueueSend(cmd_reg_queue, &cmd,10/portTICK_PERIOD_MS);
  417. break;
  418. // case SPP_IDX_SPP_STATUS_VAL:
  419. // #ifdef SUPPORT_HEARTBEAT
  420. // cmd = SPP_IDX_SPP_HEARTBEAT_VAL;
  421. // xQueueSend(cmd_reg_queue, &cmd, 10 / portTICK_PERIOD_MS);
  422. // #endif
  423. // break;
  424. #ifdef SUPPORT_HEARTBEAT
  425. case SPP_IDX_SPP_HEARTBEAT_VAL:
  426. xQueueSend(cmd_heartbeat_queue, &cmd, 10 / portTICK_PERIOD_MS);
  427. break;
  428. #endif
  429. default:
  430. break;
  431. };
  432. break;
  433. case ESP_GATTC_CFG_MTU_EVT:
  434. if (p_data->cfg_mtu.status != ESP_OK)
  435. {
  436. break;
  437. }
  438. ESP_LOGI(GATTC_TAG, "+MTU:%d\n", p_data->cfg_mtu.mtu);
  439. spp_mtu_size = p_data->cfg_mtu.mtu;
  440. db = (esp_gattc_db_elem_t *)malloc(count * sizeof(esp_gattc_db_elem_t));
  441. if (db == NULL)
  442. {
  443. ESP_LOGE(GATTC_TAG, "%s:malloc db falied\n", __func__);
  444. break;
  445. }
  446. 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)
  447. {
  448. ESP_LOGE(GATTC_TAG, "%s:get db falied\n", __func__);
  449. break;
  450. }
  451. if (count != SPP_IDX_NB)
  452. {
  453. ESP_LOGE(GATTC_TAG, "%s:get db count != SPP_IDX_NB, count = %d, SPP_IDX_NB = %d\n", __func__, count, SPP_IDX_NB);
  454. break;
  455. }
  456. uint8_t strbuffer[38] = {0};
  457. for (int i = 0; i < SPP_IDX_NB; i++)
  458. {
  459. ESP_LOGI("==test==", "%d", (db + i)->type);
  460. switch ((db + i)->type)
  461. {
  462. case ESP_GATT_DB_PRIMARY_SERVICE:
  463. motor_drive_hex_to_str((char *)&(db + i)->uuid.uuid.uuid128, 16, (char *)&strbuffer);
  464. ESP_LOGI(GATTC_TAG, "attr_type = PRIMARY_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%s\n",
  465. (db + i)->attribute_handle, (db + i)->start_handle, (db + i)->end_handle, (db + i)->properties, strbuffer);
  466. break;
  467. case ESP_GATT_DB_SECONDARY_SERVICE:
  468. ESP_LOGI(GATTC_TAG, "attr_type = SECONDARY_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",
  469. (db + i)->attribute_handle, (db + i)->start_handle, (db + i)->end_handle, (db + i)->properties, (db + i)->uuid.uuid.uuid16);
  470. break;
  471. case ESP_GATT_DB_CHARACTERISTIC:
  472. motor_drive_hex_to_str((char *)&(db + i)->uuid.uuid.uuid128, 16, (char *)&strbuffer);
  473. ESP_LOGI(GATTC_TAG, "attr_type = CHARACTERISTIC,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%s\n",
  474. (db + i)->attribute_handle, (db + i)->start_handle, (db + i)->end_handle, (db + i)->properties, strbuffer);
  475. break;
  476. case ESP_GATT_DB_DESCRIPTOR:
  477. ESP_LOGI(GATTC_TAG, "attr_type = DESCRIPTOR,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",
  478. (db + i)->attribute_handle, (db + i)->start_handle, (db + i)->end_handle, (db + i)->properties, (db + i)->uuid.uuid.uuid16);
  479. break;
  480. case ESP_GATT_DB_INCLUDED_SERVICE:
  481. ESP_LOGI(GATTC_TAG, "attr_type = INCLUDED_SERVICE,attribute_handle=%d,start_handle=%d,end_handle=%d,properties=0x%x,uuid=0x%04x\n",
  482. (db + i)->attribute_handle, (db + i)->start_handle, (db + i)->end_handle, (db + i)->properties, (db + i)->uuid.uuid.uuid16);
  483. break;
  484. case ESP_GATT_DB_ALL:
  485. 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",
  486. (db + i)->attribute_handle, (db + i)->start_handle, (db + i)->end_handle, (db + i)->properties, (db + i)->uuid.uuid.uuid16);
  487. break;
  488. default:
  489. break;
  490. }
  491. }
  492. // cmd = SPP_IDX_SPP_DATA_NTY_VAL;
  493. // ESP_LOGI("test","============cmd = %d========",cmd);
  494. // xQueueSend(cmd_reg_queue, &cmd, 10/portTICK_PERIOD_MS);
  495. break;
  496. case ESP_GATTC_SRVC_CHG_EVT:
  497. break;
  498. default:
  499. break;
  500. }
  501. }
  502. void spp_client_reg_task(void *arg)
  503. {
  504. uint16_t cmd_id;
  505. for (;;)
  506. {
  507. vTaskDelay(100 / portTICK_PERIOD_MS);
  508. if (xQueueReceive(cmd_reg_queue, &cmd_id, portMAX_DELAY))
  509. {
  510. if (db != NULL)
  511. {
  512. if (cmd_id == SPP_IDX_SPP_DATA_NTY_VAL)
  513. {
  514. 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);
  515. 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);
  516. }
  517. // else if (cmd_id == SPP_IDX_SPP_STATUS_VAL)
  518. // {
  519. // 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);
  520. // 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);
  521. // }
  522. #ifdef SUPPORT_HEARTBEAT
  523. else if (cmd_id == SPP_IDX_SPP_HEARTBEAT_VAL)
  524. {
  525. 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);
  526. 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);
  527. }
  528. #endif
  529. }
  530. }
  531. }
  532. }
  533. #ifdef SUPPORT_HEARTBEAT
  534. void spp_heart_beat_task(void *arg)
  535. {
  536. uint16_t cmd_id;
  537. for (;;)
  538. {
  539. vTaskDelay(50 / portTICK_PERIOD_MS);
  540. if (xQueueReceive(cmd_heartbeat_queue, &cmd_id, portMAX_DELAY))
  541. {
  542. while (1)
  543. {
  544. 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)))
  545. {
  546. esp_ble_gattc_write_char(spp_gattc_if,
  547. spp_conn_id,
  548. (db + SPP_IDX_SPP_HEARTBEAT_VAL)->attribute_handle,
  549. sizeof(heartbeat_s),
  550. (uint8_t *)heartbeat_s,
  551. ESP_GATT_WRITE_TYPE_RSP,
  552. ESP_GATT_AUTH_REQ_NONE);
  553. vTaskDelay(5000 / portTICK_PERIOD_MS);
  554. }
  555. else
  556. {
  557. ESP_LOGI(GATTC_TAG, "disconnect\n");
  558. break;
  559. }
  560. }
  561. }
  562. }
  563. }
  564. #endif
  565. void ble_client_appRegister(void)
  566. {
  567. esp_err_t status;
  568. char err_msg[20];
  569. ESP_LOGI(GATTC_TAG, "register callback");
  570. // register the scan callback function to the gap module
  571. if ((status = esp_ble_gap_register_callback(esp_gap_cb)) != ESP_OK)
  572. {
  573. ESP_LOGE(GATTC_TAG, "gap register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg)));
  574. return;
  575. }
  576. // register the callback function to the gattc module
  577. if ((status = esp_ble_gattc_register_callback(esp_gattc_cb)) != ESP_OK)
  578. {
  579. ESP_LOGE(GATTC_TAG, "gattc register error: %s", esp_err_to_name_r(status, err_msg, sizeof(err_msg)));
  580. return;
  581. }
  582. esp_ble_gattc_app_register(PROFILE_APP_ID);
  583. esp_err_t local_mtu_ret = esp_ble_gatt_set_local_mtu(200);
  584. if (local_mtu_ret)
  585. {
  586. ESP_LOGE(GATTC_TAG, "set local MTU failed: %s", esp_err_to_name_r(local_mtu_ret, err_msg, sizeof(err_msg)));
  587. }
  588. cmd_reg_queue = xQueueCreate(10, sizeof(uint32_t));
  589. xTaskCreate(spp_client_reg_task, "spp_client_reg_task", 2048, NULL, 10, NULL);
  590. #ifdef SUPPORT_HEARTBEAT
  591. cmd_heartbeat_queue = xQueueCreate(10, sizeof(uint32_t));
  592. xTaskCreate(spp_heart_beat_task, "spp_heart_beat_task", 2048, NULL, 10, NULL);
  593. #endif
  594. }
  595. void uart_task(void *pvParameters)
  596. {
  597. uart_event_t event;
  598. for (;;)
  599. {
  600. // Waiting for UART event.
  601. if (xQueueReceive(spp_uart_queue, (void *)&event, (portTickType)portMAX_DELAY))
  602. {
  603. switch (event.type)
  604. {
  605. // Event of UART receving data
  606. case UART_DATA:
  607. 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)))
  608. {
  609. uint8_t *temp = NULL;
  610. temp = (uint8_t *)malloc(sizeof(uint8_t) * event.size);
  611. if (temp == NULL)
  612. {
  613. ESP_LOGE(GATTC_TAG, "malloc failed,%s L#%d\n", __func__, __LINE__);
  614. break;
  615. }
  616. memset(temp, 0x0, event.size);
  617. uart_read_bytes(UART_NUM_0, temp, event.size, portMAX_DELAY);
  618. esp_ble_gattc_write_char(spp_gattc_if,
  619. spp_conn_id,
  620. (db + SPP_IDX_SPP_DATA_RECV_VAL)->attribute_handle,
  621. event.size,
  622. temp,
  623. ESP_GATT_WRITE_TYPE_RSP,
  624. ESP_GATT_AUTH_REQ_NONE);
  625. free(temp);
  626. }
  627. break;
  628. default:
  629. break;
  630. }
  631. }
  632. }
  633. vTaskDelete(NULL);
  634. }
  635. static void spp_uart_init(void)
  636. {
  637. uart_config_t uart_config = {
  638. .baud_rate = 115200,
  639. .data_bits = UART_DATA_8_BITS,
  640. .parity = UART_PARITY_DISABLE,
  641. .stop_bits = UART_STOP_BITS_1,
  642. .flow_ctrl = UART_HW_FLOWCTRL_RTS,
  643. .rx_flow_ctrl_thresh = 122,
  644. .source_clk = UART_SCLK_APB,
  645. };
  646. // Install UART driver, and get the queue.
  647. uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_uart_queue, 0);
  648. // Set UART parameters
  649. uart_param_config(UART_NUM_0, &uart_config);
  650. // Set UART pins
  651. uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  652. xTaskCreate(uart_task, "uTask", 2048, (void *)UART_NUM_0, 8, NULL);
  653. }
  654. void app_main(void)
  655. {
  656. esp_err_t ret;
  657. ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
  658. esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
  659. nvs_flash_init();
  660. ret = esp_bt_controller_init(&bt_cfg);
  661. if (ret)
  662. {
  663. ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
  664. return;
  665. }
  666. ret = esp_bt_controller_enable(ESP_BT_MODE_BLE);
  667. if (ret)
  668. {
  669. ESP_LOGE(GATTC_TAG, "%s enable controller failed: %s\n", __func__, esp_err_to_name(ret));
  670. return;
  671. }
  672. ESP_LOGI(GATTC_TAG, "%s init bluetooth\n", __func__);
  673. ret = esp_bluedroid_init();
  674. if (ret)
  675. {
  676. ESP_LOGE(GATTC_TAG, "%s init bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
  677. return;
  678. }
  679. ret = esp_bluedroid_enable();
  680. if (ret)
  681. {
  682. ESP_LOGE(GATTC_TAG, "%s enable bluetooth failed: %s\n", __func__, esp_err_to_name(ret));
  683. return;
  684. }
  685. ble_client_appRegister();
  686. spp_uart_init();
  687. }
  688. void motor_drive_hex_to_str(char *hex, int hex_len, char *str)
  689. {
  690. int i, pos = 0;
  691. for (i = (hex_len - 1); i >= 0; i--)
  692. {
  693. sprintf(str + pos, "%02x", hex[i]);
  694. pos += 2;
  695. }
  696. }