main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2022 Espressif Systems (Shanghai) CO LTD
  3. *
  4. * SPDX-License-Identifier: Unlicense OR CC0-1.0
  5. */
  6. #include "esp_log.h"
  7. #include "nvs_flash.h"
  8. /* BLE */
  9. #include "nimble/nimble_port.h"
  10. #include "nimble/nimble_port_freertos.h"
  11. #include "host/ble_hs.h"
  12. #include "host/util/util.h"
  13. #include "console/console.h"
  14. #include "services/gap/ble_svc_gap.h"
  15. #include "ble_spp_client.h"
  16. #include "driver/uart.h"
  17. #define PEER_ADDR_VAL_SIZE 6
  18. static const char *tag = "NimBLE_SPP_BLE_CENT";
  19. static int ble_spp_client_gap_event(struct ble_gap_event *event, void *arg);
  20. QueueHandle_t spp_common_uart_queue = NULL;
  21. void ble_store_config_init(void);
  22. uint16_t attribute_handle[CONFIG_BT_NIMBLE_MAX_CONNECTIONS + 1];
  23. static void ble_spp_client_scan(void);
  24. static ble_addr_t connected_addr[CONFIG_BT_NIMBLE_MAX_CONNECTIONS + 1];
  25. static void
  26. ble_spp_client_set_handle(const struct peer *peer)
  27. {
  28. const struct peer_chr *chr;
  29. chr = peer_chr_find_uuid(peer,
  30. BLE_UUID16_DECLARE(GATT_SPP_SVC_UUID),
  31. BLE_UUID16_DECLARE(GATT_SPP_CHR_UUID));
  32. attribute_handle[peer->conn_handle] = chr->chr.val_handle;
  33. }
  34. /**
  35. * Called when service discovery of the specified peer has completed.
  36. */
  37. static void
  38. ble_spp_client_on_disc_complete(const struct peer *peer, int status, void *arg)
  39. {
  40. if (status != 0) {
  41. /* Service discovery failed. Terminate the connection. */
  42. MODLOG_DFLT(ERROR, "Error: Service discovery failed; status=%d "
  43. "conn_handle=%d\n", status, peer->conn_handle);
  44. ble_gap_terminate(peer->conn_handle, BLE_ERR_REM_USER_CONN_TERM);
  45. return;
  46. }
  47. /* Service discovery has completed successfully. Now we have a complete
  48. * list of services, characteristics, and descriptors that the peer
  49. * supports.
  50. */
  51. MODLOG_DFLT(INFO, "Service discovery complete; status=%d "
  52. "conn_handle=%d\n", status, peer->conn_handle);
  53. ble_spp_client_set_handle(peer);
  54. #if CONFIG_BT_NIMBLE_MAX_CONNECTIONS > 1
  55. ble_spp_client_scan();
  56. #endif
  57. }
  58. /**
  59. * Initiates the GAP general discovery procedure.
  60. */
  61. static void
  62. ble_spp_client_scan(void)
  63. {
  64. uint8_t own_addr_type;
  65. struct ble_gap_disc_params disc_params;
  66. int rc;
  67. /* Figure out address to use while advertising (no privacy for now) */
  68. rc = ble_hs_id_infer_auto(0, &own_addr_type);
  69. if (rc != 0) {
  70. MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
  71. return;
  72. }
  73. /* Tell the controller to filter duplicates; we don't want to process
  74. * repeated advertisements from the same device.
  75. */
  76. disc_params.filter_duplicates = 1;
  77. /**
  78. * Perform a passive scan. I.e., don't send follow-up scan requests to
  79. * each advertiser.
  80. */
  81. disc_params.passive = 1;
  82. /* Use defaults for the rest of the parameters. */
  83. disc_params.itvl = 0;
  84. disc_params.window = 0;
  85. disc_params.filter_policy = 0;
  86. disc_params.limited = 0;
  87. rc = ble_gap_disc(own_addr_type, BLE_HS_FOREVER, &disc_params,
  88. ble_spp_client_gap_event, NULL);
  89. if (rc != 0) {
  90. MODLOG_DFLT(ERROR, "Error initiating GAP discovery procedure; rc=%d\n",
  91. rc);
  92. }
  93. }
  94. /**
  95. * Indicates whether we should try to connect to the sender of the specified
  96. * advertisement. The function returns a positive result if the device
  97. * advertises connectability and support for the Alert Notification service.
  98. */
  99. static int
  100. ble_spp_client_should_connect(const struct ble_gap_disc_desc *disc)
  101. {
  102. struct ble_hs_adv_fields fields;
  103. int rc;
  104. int i;
  105. /* Check if device is already connected or not */
  106. for ( i = 0; i <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
  107. if (memcmp(&connected_addr[i].val, disc->addr.val, PEER_ADDR_VAL_SIZE) == 0) {
  108. MODLOG_DFLT(DEBUG, "Device already connected");
  109. return 0;
  110. }
  111. }
  112. /* The device has to be advertising connectability. */
  113. if (disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_ADV_IND &&
  114. disc->event_type != BLE_HCI_ADV_RPT_EVTYPE_DIR_IND) {
  115. return 0;
  116. }
  117. rc = ble_hs_adv_parse_fields(&fields, disc->data, disc->length_data);
  118. if (rc != 0) {
  119. return 0;
  120. }
  121. /* The device has to advertise support for the SPP
  122. * service (0xABF0).
  123. */
  124. for (i = 0; i < fields.num_uuids16; i++) {
  125. if (ble_uuid_u16(&fields.uuids16[i].u) == GATT_SPP_SVC_UUID) {
  126. return 1;
  127. }
  128. }
  129. return 0;
  130. }
  131. /**
  132. * Connects to the sender of the specified advertisement of it looks
  133. * interesting. A device is "interesting" if it advertises connectability and
  134. * support for the Alert Notification service.
  135. */
  136. static void
  137. ble_spp_client_connect_if_interesting(const struct ble_gap_disc_desc *disc)
  138. {
  139. uint8_t own_addr_type;
  140. int rc;
  141. /* Don't do anything if we don't care about this advertiser. */
  142. if (!ble_spp_client_should_connect(disc)) {
  143. return;
  144. }
  145. /* Scanning must be stopped before a connection can be initiated. */
  146. rc = ble_gap_disc_cancel();
  147. if (rc != 0) {
  148. MODLOG_DFLT(DEBUG, "Failed to cancel scan; rc=%d\n", rc);
  149. return;
  150. }
  151. /* Figure out address to use for connect (no privacy for now) */
  152. rc = ble_hs_id_infer_auto(0, &own_addr_type);
  153. if (rc != 0) {
  154. MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
  155. return;
  156. }
  157. /* Try to connect the the advertiser. Allow 30 seconds (30000 ms) for
  158. * timeout.
  159. */
  160. rc = ble_gap_connect(own_addr_type, &disc->addr, 30000, NULL,
  161. ble_spp_client_gap_event, NULL);
  162. if (rc != 0) {
  163. MODLOG_DFLT(ERROR, "Error: Failed to connect to device; addr_type=%d "
  164. "addr=%s; rc=%d\n",
  165. disc->addr.type, addr_str(disc->addr.val), rc);
  166. return;
  167. }
  168. }
  169. /**
  170. * The nimble host executes this callback when a GAP event occurs. The
  171. * application associates a GAP event callback with each connection that is
  172. * established. ble_spp_client uses the same callback for all connections.
  173. *
  174. * @param event The event being signalled.
  175. * @param arg Application-specified argument; unused by
  176. * ble_spp_client.
  177. *
  178. * @return 0 if the application successfully handled the
  179. * event; nonzero on failure. The semantics
  180. * of the return code is specific to the
  181. * particular GAP event being signalled.
  182. */
  183. static int
  184. ble_spp_client_gap_event(struct ble_gap_event *event, void *arg)
  185. {
  186. struct ble_gap_conn_desc desc;
  187. struct ble_hs_adv_fields fields;
  188. int rc;
  189. switch (event->type) {
  190. case BLE_GAP_EVENT_DISC:
  191. rc = ble_hs_adv_parse_fields(&fields, event->disc.data,
  192. event->disc.length_data);
  193. if (rc != 0) {
  194. return 0;
  195. }
  196. /* An advertisment report was received during GAP discovery. */
  197. print_adv_fields(&fields);
  198. /* Try to connect to the advertiser if it looks interesting. */
  199. ble_spp_client_connect_if_interesting(&event->disc);
  200. return 0;
  201. case BLE_GAP_EVENT_CONNECT:
  202. /* A new connection was established or a connection attempt failed. */
  203. if (event->connect.status == 0) {
  204. /* Connection successfully established. */
  205. MODLOG_DFLT(INFO, "Connection established ");
  206. rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
  207. assert(rc == 0);
  208. memcpy(&connected_addr[event->connect.conn_handle].val, desc.peer_id_addr.val,
  209. PEER_ADDR_VAL_SIZE);
  210. print_conn_desc(&desc);
  211. MODLOG_DFLT(INFO, "\n");
  212. /* Remember peer. */
  213. rc = peer_add(event->connect.conn_handle);
  214. if (rc != 0) {
  215. MODLOG_DFLT(ERROR, "Failed to add peer; rc=%d\n", rc);
  216. return 0;
  217. }
  218. /* Perform service discovery. */
  219. rc = peer_disc_all(event->connect.conn_handle,
  220. ble_spp_client_on_disc_complete, NULL);
  221. if (rc != 0) {
  222. MODLOG_DFLT(ERROR, "Failed to discover services; rc=%d\n", rc);
  223. return 0;
  224. }
  225. } else {
  226. /* Connection attempt failed; resume scanning. */
  227. MODLOG_DFLT(ERROR, "Error: Connection failed; status=%d\n",
  228. event->connect.status);
  229. ble_spp_client_scan();
  230. }
  231. return 0;
  232. case BLE_GAP_EVENT_DISCONNECT:
  233. /* Connection terminated. */
  234. MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
  235. print_conn_desc(&event->disconnect.conn);
  236. MODLOG_DFLT(INFO, "\n");
  237. /* Forget about peer. */
  238. memset(&connected_addr[event->disconnect.conn.conn_handle].val, 0, PEER_ADDR_VAL_SIZE);
  239. attribute_handle[event->disconnect.conn.conn_handle] = 0;
  240. peer_delete(event->disconnect.conn.conn_handle);
  241. /* Resume scanning. */
  242. ble_spp_client_scan();
  243. return 0;
  244. case BLE_GAP_EVENT_DISC_COMPLETE:
  245. MODLOG_DFLT(INFO, "discovery complete; reason=%d\n",
  246. event->disc_complete.reason);
  247. return 0;
  248. case BLE_GAP_EVENT_NOTIFY_RX:
  249. /* Peer sent us a notification or indication. */
  250. MODLOG_DFLT(INFO, "received %s; conn_handle=%d attr_handle=%d "
  251. "attr_len=%d\n",
  252. event->notify_rx.indication ?
  253. "indication" :
  254. "notification",
  255. event->notify_rx.conn_handle,
  256. event->notify_rx.attr_handle,
  257. OS_MBUF_PKTLEN(event->notify_rx.om));
  258. /* Attribute data is contained in event->notify_rx.om. Use
  259. * `os_mbuf_copydata` to copy the data received in notification mbuf */
  260. return 0;
  261. case BLE_GAP_EVENT_MTU:
  262. MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
  263. event->mtu.conn_handle,
  264. event->mtu.channel_id,
  265. event->mtu.value);
  266. return 0;
  267. default:
  268. return 0;
  269. }
  270. }
  271. static void
  272. ble_spp_client_on_reset(int reason)
  273. {
  274. MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
  275. }
  276. static void
  277. ble_spp_client_on_sync(void)
  278. {
  279. int rc;
  280. /* Make sure we have proper identity address set (public preferred) */
  281. rc = ble_hs_util_ensure_addr(0);
  282. assert(rc == 0);
  283. /* Begin scanning for a peripheral to connect to. */
  284. ble_spp_client_scan();
  285. }
  286. void ble_spp_client_host_task(void *param)
  287. {
  288. ESP_LOGI(tag, "BLE Host Task Started");
  289. /* This function will return only when nimble_port_stop() is executed */
  290. nimble_port_run();
  291. nimble_port_freertos_deinit();
  292. }
  293. void ble_client_uart_task(void *pvParameters)
  294. {
  295. ESP_LOGI(tag, "BLE client UART task started");
  296. int rc;
  297. int i;
  298. uart_event_t event;
  299. for (;;) {
  300. //Waiting for UART event.
  301. if (xQueueReceive(spp_common_uart_queue, (void * )&event, (TickType_t)portMAX_DELAY)) {
  302. switch (event.type) {
  303. //Event of UART receving data
  304. case UART_DATA:
  305. if (event.size) {
  306. /* Writing characteristics */
  307. uint8_t *temp = NULL;
  308. temp = (uint8_t *)malloc(sizeof(uint8_t) * event.size);
  309. if (temp == NULL) {
  310. ESP_LOGE(tag, "malloc failed,%s L#%d", __func__, __LINE__);
  311. break;
  312. }
  313. memset(temp, 0x0, event.size);
  314. uart_read_bytes(UART_NUM_0, temp, event.size, portMAX_DELAY);
  315. for ( i = 0; i <= CONFIG_BT_NIMBLE_MAX_CONNECTIONS; i++) {
  316. if (attribute_handle[i] != 0) {
  317. rc = ble_gattc_write_flat(i, attribute_handle[i], temp, event.size, NULL, NULL);
  318. if (rc == 0) {
  319. ESP_LOGI(tag, "Write in uart task success!");
  320. } else {
  321. ESP_LOGI(tag, "Error in writing characteristic rc=%d", rc);
  322. }
  323. vTaskDelay(10);
  324. }
  325. }
  326. free(temp);
  327. }
  328. break;
  329. default:
  330. break;
  331. }
  332. }
  333. }
  334. vTaskDelete(NULL);
  335. }
  336. static void ble_spp_uart_init(void)
  337. {
  338. uart_config_t uart_config = {
  339. .baud_rate = 115200,
  340. .data_bits = UART_DATA_8_BITS,
  341. .parity = UART_PARITY_DISABLE,
  342. .stop_bits = UART_STOP_BITS_1,
  343. .flow_ctrl = UART_HW_FLOWCTRL_RTS,
  344. .rx_flow_ctrl_thresh = 122,
  345. .source_clk = UART_SCLK_DEFAULT,
  346. };
  347. //Install UART driver, and get the queue.
  348. uart_driver_install(UART_NUM_0, 4096, 8192, 10, &spp_common_uart_queue, 0);
  349. //Set UART parameters
  350. uart_param_config(UART_NUM_0, &uart_config);
  351. //Set UART pins
  352. uart_set_pin(UART_NUM_0, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
  353. xTaskCreate(ble_client_uart_task, "uTask", 4096, (void *)UART_NUM_0, 8, NULL);
  354. }
  355. void
  356. app_main(void)
  357. {
  358. int rc;
  359. /* Initialize NVS — it is used to store PHY calibration data */
  360. esp_err_t ret = nvs_flash_init();
  361. if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  362. ESP_ERROR_CHECK(nvs_flash_erase());
  363. ret = nvs_flash_init();
  364. }
  365. ESP_ERROR_CHECK(ret);
  366. ret = nimble_port_init();
  367. if (ret != ESP_OK) {
  368. MODLOG_DFLT(ERROR, "Failed to init nimble %d \n", ret);
  369. return;
  370. }
  371. /* Initialize UART driver and start uart task */
  372. ble_spp_uart_init();
  373. /* Configure the host. */
  374. ble_hs_cfg.reset_cb = ble_spp_client_on_reset;
  375. ble_hs_cfg.sync_cb = ble_spp_client_on_sync;
  376. ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
  377. /* Initialize data structures to track connected peers. */
  378. rc = peer_init(MYNEWT_VAL(BLE_MAX_CONNECTIONS), 64, 64, 64);
  379. assert(rc == 0);
  380. /* Set the default device name. */
  381. rc = ble_svc_gap_device_name_set("nimble-ble-spp-client");
  382. assert(rc == 0);
  383. /* XXX Need to have template for store */
  384. ble_store_config_init();
  385. nimble_port_freertos_init(ble_spp_client_host_task);
  386. }