main.c 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /*
  2. * SPDX-FileCopyrightText: 2021-2023 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_dynamic_service.h"
  16. #define BLE_DYNAMIC_SERVICE_ADD 1
  17. #define BLE_DYNAMIC_SERVICE_DELETE 0
  18. extern const struct ble_gatt_svc_def gatt_svr_svcs[];
  19. static const char *tag = "NimBLE_DYNAMIC_SERVICE";
  20. static int dynamic_service_gap_event(struct ble_gap_event *event, void *arg);
  21. static uint8_t own_addr_type;
  22. /**
  23. * Logs information about a connection to the console.
  24. */
  25. static void
  26. dynamic_service_print_conn_desc(struct ble_gap_conn_desc *desc)
  27. {
  28. MODLOG_DFLT(INFO, "handle=%d our_ota_addr_type=%d our_ota_addr=",
  29. desc->conn_handle, desc->our_ota_addr.type);
  30. print_addr(desc->our_ota_addr.val);
  31. MODLOG_DFLT(INFO, " our_id_addr_type=%d our_id_addr=",
  32. desc->our_id_addr.type);
  33. print_addr(desc->our_id_addr.val);
  34. MODLOG_DFLT(INFO, " peer_ota_addr_type=%d peer_ota_addr=",
  35. desc->peer_ota_addr.type);
  36. print_addr(desc->peer_ota_addr.val);
  37. MODLOG_DFLT(INFO, " peer_id_addr_type=%d peer_id_addr=",
  38. desc->peer_id_addr.type);
  39. print_addr(desc->peer_id_addr.val);
  40. MODLOG_DFLT(INFO, " conn_itvl=%d conn_latency=%d supervision_timeout=%d "
  41. "encrypted=%d authenticated=%d bonded=%d\n",
  42. desc->conn_itvl, desc->conn_latency,
  43. desc->supervision_timeout,
  44. desc->sec_state.encrypted,
  45. desc->sec_state.authenticated,
  46. desc->sec_state.bonded);
  47. }
  48. /**
  49. * Enables advertising with the following parameters:
  50. * o General discoverable mode.
  51. * o Undirected connectable mode.
  52. */
  53. static void
  54. dynamic_service_advertise(void)
  55. {
  56. struct ble_gap_adv_params adv_params;
  57. struct ble_hs_adv_fields fields;
  58. const char *name;
  59. int rc;
  60. /**
  61. * Set the advertisement data included in our advertisements:
  62. * o Flags (indicates advertisement type and other general info).
  63. * o Advertising tx power.
  64. * o Device name.
  65. * o 16-bit service UUIDs (alert notifications).
  66. */
  67. memset(&fields, 0, sizeof fields);
  68. /* Advertise two flags:
  69. * o Discoverability in forthcoming advertisement (general)
  70. * o BLE-only (BR/EDR unsupported).
  71. */
  72. fields.flags = BLE_HS_ADV_F_DISC_GEN |
  73. BLE_HS_ADV_F_BREDR_UNSUP;
  74. /* Indicate that the TX power level field should be included; have the
  75. * stack fill this value automatically. This is done by assigning the
  76. * special value BLE_HS_ADV_TX_PWR_LVL_AUTO.
  77. */
  78. fields.tx_pwr_lvl_is_present = 1;
  79. fields.tx_pwr_lvl = BLE_HS_ADV_TX_PWR_LVL_AUTO;
  80. name = ble_svc_gap_device_name();
  81. fields.name = (uint8_t *)name;
  82. fields.name_len = strlen(name);
  83. fields.name_is_complete = 1;
  84. fields.uuids16 = (ble_uuid16_t[]) {
  85. BLE_UUID16_INIT(GATT_SVR_SVC_ALERT_UUID)
  86. };
  87. fields.num_uuids16 = 1;
  88. fields.uuids16_is_complete = 1;
  89. rc = ble_gap_adv_set_fields(&fields);
  90. if (rc != 0) {
  91. MODLOG_DFLT(ERROR, "error setting advertisement data; rc=%d\n", rc);
  92. return;
  93. }
  94. /* Begin advertising. */
  95. memset(&adv_params, 0, sizeof adv_params);
  96. adv_params.conn_mode = BLE_GAP_CONN_MODE_UND;
  97. adv_params.disc_mode = BLE_GAP_DISC_MODE_GEN;
  98. rc = ble_gap_adv_start(own_addr_type, NULL, BLE_HS_FOREVER,
  99. &adv_params, dynamic_service_gap_event, NULL);
  100. if (rc != 0) {
  101. MODLOG_DFLT(ERROR, "error enabling advertisement; rc=%d\n", rc);
  102. return;
  103. }
  104. }
  105. /**
  106. * The nimble host executes this callback when a GAP event occurs. The
  107. * application associates a GAP event callback with each connection that forms.
  108. * dynamic_service uses the same callback for all connections.
  109. *
  110. * @param event The type of event being signalled.
  111. * @param ctxt Various information pertaining to the event.
  112. * @param arg Application-specified argument; unused by
  113. * dynamic_service.
  114. *
  115. * @return 0 if the application successfully handled the
  116. * event; nonzero on failure. The semantics
  117. * of the return code is specific to the
  118. * particular GAP event being signalled.
  119. */
  120. static int
  121. dynamic_service_gap_event(struct ble_gap_event *event, void *arg)
  122. {
  123. struct ble_gap_conn_desc desc;
  124. int rc;
  125. switch (event->type) {
  126. case BLE_GAP_EVENT_CONNECT:
  127. /* A new connection was established or a connection attempt failed. */
  128. MODLOG_DFLT(INFO, "connection %s; status=%d ",
  129. event->connect.status == 0 ? "established" : "failed",
  130. event->connect.status);
  131. if (event->connect.status == 0) {
  132. rc = ble_gap_conn_find(event->connect.conn_handle, &desc);
  133. assert(rc == 0);
  134. dynamic_service_print_conn_desc(&desc);
  135. }
  136. MODLOG_DFLT(INFO, "\n");
  137. if (event->connect.status != 0) {
  138. /* Connection failed; resume advertising. */
  139. dynamic_service_advertise();
  140. }
  141. return 0;
  142. case BLE_GAP_EVENT_DISCONNECT:
  143. MODLOG_DFLT(INFO, "disconnect; reason=%d ", event->disconnect.reason);
  144. dynamic_service_print_conn_desc(&event->disconnect.conn);
  145. MODLOG_DFLT(INFO, "\n");
  146. /* Connection terminated; resume advertising. */
  147. dynamic_service_advertise();
  148. return 0;
  149. case BLE_GAP_EVENT_CONN_UPDATE:
  150. /* The central has updated the connection parameters. */
  151. MODLOG_DFLT(INFO, "connection updated; status=%d ",
  152. event->conn_update.status);
  153. rc = ble_gap_conn_find(event->conn_update.conn_handle, &desc);
  154. assert(rc == 0);
  155. dynamic_service_print_conn_desc(&desc);
  156. MODLOG_DFLT(INFO, "\n");
  157. return 0;
  158. case BLE_GAP_EVENT_ADV_COMPLETE:
  159. MODLOG_DFLT(INFO, "advertise complete; reason=%d",
  160. event->adv_complete.reason);
  161. dynamic_service_advertise();
  162. return 0;
  163. case BLE_GAP_EVENT_NOTIFY_TX:
  164. MODLOG_DFLT(INFO, "notify_tx event; conn_handle=%d attr_handle=%d "
  165. "status=%d is_indication=%d",
  166. event->notify_tx.conn_handle,
  167. event->notify_tx.attr_handle,
  168. event->notify_tx.status,
  169. event->notify_tx.indication);
  170. return 0;
  171. case BLE_GAP_EVENT_SUBSCRIBE:
  172. MODLOG_DFLT(INFO, "subscribe event; conn_handle=%d attr_handle=%d "
  173. "reason=%d prevn=%d curn=%d previ=%d curi=%d\n",
  174. event->subscribe.conn_handle,
  175. event->subscribe.attr_handle,
  176. event->subscribe.reason,
  177. event->subscribe.prev_notify,
  178. event->subscribe.cur_notify,
  179. event->subscribe.prev_indicate,
  180. event->subscribe.cur_indicate);
  181. return 0;
  182. case BLE_GAP_EVENT_MTU:
  183. MODLOG_DFLT(INFO, "mtu update event; conn_handle=%d cid=%d mtu=%d\n",
  184. event->mtu.conn_handle,
  185. event->mtu.channel_id,
  186. event->mtu.value);
  187. return 0;
  188. }
  189. return 0;
  190. }
  191. static void
  192. dynamic_service_on_reset(int reason)
  193. {
  194. MODLOG_DFLT(ERROR, "Resetting state; reason=%d\n", reason);
  195. }
  196. static void
  197. dynamic_service_on_sync(void)
  198. {
  199. int rc;
  200. /* Make sure we have proper identity address set (public preferred) */
  201. rc = ble_hs_util_ensure_addr(0);
  202. assert(rc == 0);
  203. /* Figure out address to use while advertising (no privacy for now) */
  204. rc = ble_hs_id_infer_auto(0, &own_addr_type);
  205. if (rc != 0) {
  206. MODLOG_DFLT(ERROR, "error determining address type; rc=%d\n", rc);
  207. return;
  208. }
  209. /* Printing ADDR */
  210. uint8_t addr_val[6] = {0};
  211. rc = ble_hs_id_copy_addr(own_addr_type, addr_val, NULL);
  212. MODLOG_DFLT(INFO, "Device Address: ");
  213. print_addr(addr_val);
  214. MODLOG_DFLT(INFO, "\n");
  215. /* Begin advertising. */
  216. dynamic_service_advertise();
  217. }
  218. void dynamic_service_host_task(void *param)
  219. {
  220. ESP_LOGI(tag, "BLE Host Task Started");
  221. /* This function will return only when nimble_port_stop() is executed */
  222. nimble_port_run();
  223. nimble_port_freertos_deinit();
  224. }
  225. void
  226. app_main(void)
  227. {
  228. int rc;
  229. /* Initialize NVS — it is used to store PHY calibration data */
  230. esp_err_t ret = nvs_flash_init();
  231. if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
  232. ESP_ERROR_CHECK(nvs_flash_erase());
  233. ret = nvs_flash_init();
  234. }
  235. ESP_ERROR_CHECK(ret);
  236. ret = nimble_port_init();
  237. if (ret != ESP_OK) {
  238. ESP_LOGE(tag, "Failed to init nimble %d ", ret);
  239. return;
  240. }
  241. /* Initialize the NimBLE host configuration. */
  242. ble_hs_cfg.reset_cb = dynamic_service_on_reset;
  243. ble_hs_cfg.sync_cb = dynamic_service_on_sync;
  244. ble_hs_cfg.gatts_register_cb = gatt_svr_register_cb;
  245. ble_hs_cfg.store_status_cb = ble_store_util_status_rr;
  246. rc = gatt_svr_init();
  247. assert(rc == 0);
  248. /* Set the default device name. */
  249. rc = ble_svc_gap_device_name_set("ble-dynamic-service");
  250. assert(rc == 0);
  251. nimble_port_freertos_init(dynamic_service_host_task);
  252. while(1) {
  253. vTaskDelay(15000 / portTICK_PERIOD_MS);
  254. MODLOG_DFLT(INFO, "Adding Dynamic service");
  255. /* add services defined in gatt_svr_svcs */
  256. dynamic_service(BLE_DYNAMIC_SERVICE_ADD, gatt_svr_svcs, NULL);
  257. /* 15 seconds delay before deleting the service */
  258. vTaskDelay(15000 / portTICK_PERIOD_MS);
  259. MODLOG_DFLT(INFO, "Deleting service");
  260. /* Delete the first service in the list */
  261. dynamic_service(BLE_DYNAMIC_SERVICE_DELETE, NULL, gatt_svr_svcs[0].uuid);
  262. }
  263. }