gatt_cache_manager.c 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /* Copyright (c) 2015 Nordic Semiconductor. All Rights Reserved.
  2. *
  3. * The information contained herein is property of Nordic Semiconductor ASA.
  4. * Terms and conditions of usage are described in detail in NORDIC
  5. * SEMICONDUCTOR STANDARD SOFTWARE LICENSE AGREEMENT.
  6. *
  7. * Licensees are granted free, non-transferable use of the information. NO
  8. * WARRANTY of ANY KIND is provided. This heading must NOT be removed from
  9. * the file.
  10. *
  11. */
  12. #include "gatt_cache_manager.h"
  13. #include "ble_gap.h"
  14. #include "ble_conn_state.h"
  15. #include "peer_manager_types.h"
  16. #include "peer_manager_internal.h"
  17. #include "peer_database.h"
  18. #include "id_manager.h"
  19. #include "security_dispatcher.h"
  20. #include "gatts_cache_manager.h"
  21. #include "gattc_cache_manager.h"
  22. #include "sdk_common.h"
  23. /**@brief Structure containing the module variable(s) of the GCM module.
  24. */
  25. typedef struct
  26. {
  27. gcm_evt_handler_t evt_handler; /**< The event handler to use for outbound GSCM events. */
  28. ble_conn_state_user_flag_id_t flag_id_local_db_update_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB update procedure. */
  29. ble_conn_state_user_flag_id_t flag_id_local_db_apply_pending; /**< Flag ID for flag collection to keep track of which connections need a local DB apply procedure. */
  30. ble_conn_state_user_flag_id_t flag_id_service_changed_pending; /**< Flag ID for flag collection to keep track of which connections need to be sent a service changed indication. */
  31. ble_conn_state_user_flag_id_t flag_id_service_changed_sent; /**< Flag ID for flag collection to keep track of which connections have been sent a service changed indication and are waiting for a handle value confirmation. */
  32. } gcm_t;
  33. static gcm_t m_gcm; /**< Instantiation of module variable(s). */
  34. #define MODULE_INITIALIZED (m_gcm.evt_handler != NULL)
  35. #include "sdk_macros.h"
  36. static void service_changed_pending_flags_check(void);
  37. /**@brief Function for resetting the module variable(s) of the GSCM module.
  38. *
  39. * @param[out] The instance to reset.
  40. */
  41. static void internal_state_reset(gcm_t * p_gcm)
  42. {
  43. memset(p_gcm, 0, sizeof(gcm_t));
  44. }
  45. /**@brief Function for checking a write event for whether a CCCD was written during the write
  46. * operation.
  47. *
  48. * @param[in] p_write_evt The parameters of the write event.
  49. *
  50. * @return Whether the write was on a CCCD.
  51. */
  52. static bool cccd_written(ble_gatts_evt_write_t * p_write_evt)
  53. {
  54. return ( (p_write_evt->op == BLE_GATTS_OP_WRITE_REQ)
  55. && (p_write_evt->uuid.type == BLE_UUID_TYPE_BLE)
  56. && (p_write_evt->uuid.uuid == BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG)
  57. );
  58. }
  59. /**@brief Function for performing the local DB update procedure in an event context, where no return
  60. * code can be given.
  61. *
  62. * @details This function will do the procedure, and check the result, set a flag if needed, and
  63. * send an event if needed.
  64. *
  65. * @param[in] conn_handle The connection to perform the procedure on.
  66. */
  67. static void local_db_apply_in_evt(uint16_t conn_handle)
  68. {
  69. bool set_procedure_as_pending = false;
  70. ret_code_t err_code;
  71. gcm_evt_t event;
  72. if (conn_handle == BLE_CONN_HANDLE_INVALID)
  73. {
  74. return;
  75. }
  76. err_code = gscm_local_db_cache_apply(conn_handle);
  77. switch(err_code)
  78. {
  79. case NRF_SUCCESS:
  80. event.evt_id = GCM_EVT_LOCAL_DB_CACHE_APPLIED;
  81. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  82. event.params.local_db_cache_applied.conn_handle = conn_handle;
  83. m_gcm.evt_handler(&event);
  84. break;
  85. case NRF_ERROR_BUSY:
  86. set_procedure_as_pending = true;
  87. break;
  88. case NRF_ERROR_INVALID_DATA:
  89. event.evt_id = GCM_EVT_ERROR_LOCAL_DB_CACHE_APPLY;
  90. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  91. event.params.error_local_db_cache_apply.conn_handle = conn_handle;
  92. m_gcm.evt_handler(&event);
  93. break;
  94. case BLE_ERROR_INVALID_CONN_HANDLE:
  95. /* Do nothing */
  96. break;
  97. default:
  98. event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
  99. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  100. event.params.error_unexpected.conn_handle = conn_handle;
  101. event.params.error_unexpected.error = err_code;
  102. m_gcm.evt_handler(&event);
  103. break;
  104. }
  105. ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_apply_pending, set_procedure_as_pending);
  106. }
  107. /**@brief Function for performing the local DB apply procedure in an event context, where no return
  108. * code can be given.
  109. *
  110. * @details This function will do the procedure, and check the result, set a flag if needed, and
  111. * send an event if needed.
  112. *
  113. * @param[in] conn_handle The connection to perform the procedure on.
  114. */
  115. static void local_db_update_in_evt(uint16_t conn_handle)
  116. {
  117. gcm_evt_t event;
  118. bool set_procedure_as_pending = false;
  119. ret_code_t err_code = gscm_local_db_cache_update(conn_handle);
  120. switch(err_code)
  121. {
  122. case NRF_SUCCESS:
  123. event.evt_id = GCM_EVT_LOCAL_DB_CACHE_UPDATED;
  124. event.params.local_db_cache_applied.conn_handle = conn_handle;
  125. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  126. m_gcm.evt_handler(&event);
  127. break;
  128. case BLE_ERROR_INVALID_CONN_HANDLE:
  129. /* Do nothing */
  130. break;
  131. case NRF_ERROR_BUSY:
  132. set_procedure_as_pending = true;
  133. break;
  134. case NRF_ERROR_DATA_SIZE:
  135. event.evt_id = GCM_EVT_ERROR_DATA_SIZE;
  136. event.params.error_data_size.conn_handle = conn_handle;
  137. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  138. m_gcm.evt_handler(&event);
  139. break;
  140. case NRF_ERROR_NO_MEM:
  141. event.evt_id = GCM_EVT_ERROR_STORAGE_FULL;
  142. event.params.error_no_mem.conn_handle = conn_handle;
  143. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  144. m_gcm.evt_handler(&event);
  145. break;
  146. default:
  147. event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
  148. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  149. event.params.error_unexpected.conn_handle = conn_handle;
  150. event.params.error_unexpected.error = err_code;
  151. m_gcm.evt_handler(&event);
  152. break;
  153. }
  154. ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_update_pending, set_procedure_as_pending);
  155. }
  156. /**@brief Function for sending a service changed indication in an event context, where no return
  157. * code can be given.
  158. *
  159. * @details This function will do the procedure, and check the result, set a flag if needed, and
  160. * send an event if needed.
  161. *
  162. * @param[in] conn_handle The connection to perform the procedure on.
  163. */
  164. static void service_changed_send_in_evt(uint16_t conn_handle)
  165. {
  166. gcm_evt_t event;
  167. bool sc_pending_state = true;
  168. bool sc_sent_state = false;
  169. ret_code_t err_code = gscm_service_changed_ind_send(conn_handle);
  170. switch(err_code)
  171. {
  172. case NRF_SUCCESS:
  173. sc_sent_state = true;
  174. event.evt_id = GCM_EVT_SERVICE_CHANGED_IND_SENT;
  175. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  176. event.params.service_changed_ind_sent.conn_handle = conn_handle;
  177. m_gcm.evt_handler(&event);
  178. break;
  179. case NRF_ERROR_BUSY:
  180. // Do nothing.
  181. break;
  182. case NRF_ERROR_INVALID_STATE:
  183. // CCCDs not enabled. Drop indication.
  184. // Fallthrough.
  185. case NRF_ERROR_NOT_SUPPORTED:
  186. // Service changed not supported. Drop indication.
  187. sc_pending_state = false;
  188. gscm_db_change_notification_done(im_peer_id_get_by_conn_handle(conn_handle));
  189. break;
  190. case BLE_ERROR_GATTS_SYS_ATTR_MISSING:
  191. local_db_apply_in_evt(conn_handle);
  192. break;
  193. case BLE_ERROR_INVALID_CONN_HANDLE:
  194. // Do nothing.
  195. break;
  196. default:
  197. event.evt_id = GCM_EVT_ERROR_UNEXPECTED;
  198. event.params.error_unexpected.conn_handle = conn_handle;
  199. event.params.error_unexpected.error = err_code;
  200. event.peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  201. m_gcm.evt_handler(&event);
  202. break;
  203. }
  204. ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_pending, sc_pending_state);
  205. ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_sent, sc_sent_state);
  206. }
  207. /**@brief Callback function for events from the GATT Cache Server Manager module.
  208. *
  209. * @param[in] p_event The event from the GATT Cache Server Manager module.
  210. */
  211. static void gscm_evt_handler(gscm_evt_t const * p_event)
  212. {
  213. gcm_evt_t event;
  214. event.peer_id = p_event->peer_id;
  215. switch (p_event->evt_id)
  216. {
  217. case GSCM_EVT_LOCAL_DB_CACHE_STORED:
  218. event.evt_id = GCM_EVT_LOCAL_DB_CACHE_STORED;
  219. m_gcm.evt_handler(&event);
  220. local_db_apply_in_evt(im_conn_handle_get(p_event->peer_id));
  221. break;
  222. case GSCM_EVT_LOCAL_DB_CACHE_UPDATED:
  223. event.evt_id = GCM_EVT_LOCAL_DB_CACHE_UPDATED;
  224. event.params.local_db_cache_updated.conn_handle = p_event->params.local_db_cache_updated.conn_handle;
  225. m_gcm.evt_handler(&event);
  226. break;
  227. case GSCM_EVT_SC_STATE_STORED:
  228. if (p_event->params.sc_state_stored.state)
  229. {
  230. uint16_t conn_handle = im_conn_handle_get(p_event->peer_id);
  231. if (conn_handle != BLE_CONN_HANDLE_INVALID)
  232. {
  233. ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_service_changed_pending, true);
  234. service_changed_pending_flags_check();
  235. }
  236. }
  237. break;
  238. }
  239. }
  240. /**@brief Callback function for events from the GATT Cache Client Manager module.
  241. *
  242. * @param[in] p_event The event from the GATT Cache Client Manager module.
  243. */
  244. static void gccm_evt_handler(gccm_evt_t const * p_event)
  245. {
  246. }
  247. /**@brief Callback function for events from the Identity Manager module.
  248. *
  249. * @param[in] p_event The event from the Identity Manager module.
  250. */
  251. static void im_evt_handler(im_evt_t const * p_event)
  252. {
  253. switch (p_event->evt_id)
  254. {
  255. case IM_EVT_BONDED_PEER_CONNECTED:
  256. local_db_apply_in_evt(p_event->conn_handle);
  257. if (gscm_service_changed_ind_needed(p_event->conn_handle))
  258. {
  259. ble_conn_state_user_flag_set(p_event->conn_handle, m_gcm.flag_id_service_changed_pending, true);
  260. }
  261. break;
  262. default:
  263. break;
  264. }
  265. }
  266. /**@brief Callback function for events from the Security Dispatcher module.
  267. *
  268. * @param[in] p_event The event from the Security Dispatcher module.
  269. */
  270. static void smd_evt_handler(smd_evt_t const * p_event)
  271. {
  272. switch (p_event->evt_id)
  273. {
  274. case SMD_EVT_BONDING_INFO_STORED:
  275. local_db_update_in_evt(p_event->conn_handle);
  276. break;
  277. default:
  278. break;
  279. }
  280. }
  281. ret_code_t gcm_init(gcm_evt_handler_t evt_handler)
  282. {
  283. VERIFY_PARAM_NOT_NULL(evt_handler);
  284. ret_code_t err_code;
  285. err_code = gscm_init(gscm_evt_handler);
  286. VERIFY_SUCCESS(err_code);
  287. err_code = gccm_init(gccm_evt_handler);
  288. VERIFY_SUCCESS(err_code);
  289. internal_state_reset(&m_gcm);
  290. m_gcm.evt_handler = evt_handler;
  291. err_code = im_register(im_evt_handler);
  292. VERIFY_SUCCESS(err_code);
  293. err_code = smd_register(smd_evt_handler);
  294. VERIFY_SUCCESS(err_code);
  295. m_gcm.flag_id_local_db_update_pending = ble_conn_state_user_flag_acquire();
  296. m_gcm.flag_id_local_db_apply_pending = ble_conn_state_user_flag_acquire();
  297. m_gcm.flag_id_service_changed_pending = ble_conn_state_user_flag_acquire();
  298. m_gcm.flag_id_service_changed_sent = ble_conn_state_user_flag_acquire();
  299. if ((m_gcm.flag_id_local_db_update_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
  300. || (m_gcm.flag_id_local_db_apply_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
  301. || (m_gcm.flag_id_service_changed_pending == BLE_CONN_STATE_USER_FLAG_INVALID)
  302. || (m_gcm.flag_id_service_changed_sent == BLE_CONN_STATE_USER_FLAG_INVALID))
  303. {
  304. err_code = NRF_ERROR_INTERNAL;
  305. }
  306. return err_code;
  307. }
  308. /**@brief Function for performing the Local DB apply procedure if it is pending on any connections.
  309. */
  310. static void apply_pending_flags_check(void)
  311. {
  312. sdk_mapped_flags_t apply_pending_flags;
  313. apply_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_local_db_apply_pending);
  314. if (sdk_mapped_flags_any_set(apply_pending_flags))
  315. {
  316. sdk_mapped_flags_key_list_t conn_handle_list;
  317. conn_handle_list = ble_conn_state_conn_handles();
  318. for (uint32_t i = 0; i < conn_handle_list.len; i++)
  319. {
  320. if (ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i], m_gcm.flag_id_local_db_apply_pending))
  321. {
  322. local_db_apply_in_evt(conn_handle_list.flag_keys[i]);
  323. }
  324. }
  325. }
  326. }
  327. /**@brief Function for performing the Local DB update procedure if it is pending on any connections.
  328. */
  329. static void update_pending_flags_check(void)
  330. {
  331. sdk_mapped_flags_t update_pending_flags;
  332. update_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_local_db_update_pending);
  333. if (sdk_mapped_flags_any_set(update_pending_flags))
  334. {
  335. sdk_mapped_flags_key_list_t conn_handle_list;
  336. conn_handle_list = ble_conn_state_conn_handles();
  337. for (uint32_t i = 0; i < conn_handle_list.len; i++)
  338. {
  339. if (ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i], m_gcm.flag_id_local_db_update_pending))
  340. {
  341. local_db_update_in_evt(conn_handle_list.flag_keys[i]);
  342. }
  343. }
  344. }
  345. }
  346. /**@brief Function for sending service changed indications if it is pending on any connections.
  347. */
  348. static void service_changed_pending_flags_check(void)
  349. {
  350. sdk_mapped_flags_t service_changed_pending_flags;
  351. service_changed_pending_flags = ble_conn_state_user_flag_collection(m_gcm.flag_id_service_changed_pending);
  352. if (sdk_mapped_flags_any_set(service_changed_pending_flags))
  353. {
  354. sdk_mapped_flags_key_list_t conn_handle_list;
  355. conn_handle_list = ble_conn_state_conn_handles();
  356. for (uint32_t i = 0; i < conn_handle_list.len; i++)
  357. {
  358. if ( ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i],
  359. m_gcm.flag_id_service_changed_pending)
  360. && !ble_conn_state_user_flag_get(conn_handle_list.flag_keys[i],
  361. m_gcm.flag_id_service_changed_sent))
  362. {
  363. service_changed_send_in_evt(conn_handle_list.flag_keys[i]);
  364. }
  365. }
  366. }
  367. }
  368. /**@brief Callback function for BLE events from the SoftDevice.
  369. *
  370. * @param[in] p_ble_evt The BLE event from the SoftDevice.
  371. */
  372. void gcm_ble_evt_handler(ble_evt_t * p_ble_evt)
  373. {
  374. gcm_evt_t event;
  375. switch(p_ble_evt->header.evt_id)
  376. {
  377. case BLE_GATTS_EVT_SYS_ATTR_MISSING:
  378. local_db_apply_in_evt(p_ble_evt->evt.gatts_evt.conn_handle);
  379. break;
  380. case BLE_GATTS_EVT_SC_CONFIRM:
  381. event.evt_id = GCM_EVT_SERVICE_CHANGED_IND_CONFIRMED;
  382. event.peer_id = im_peer_id_get_by_conn_handle(p_ble_evt->evt.gatts_evt.conn_handle);
  383. event.params.service_changed_ind_sent.conn_handle = p_ble_evt->evt.gatts_evt.conn_handle;
  384. gscm_db_change_notification_done(event.peer_id);
  385. ble_conn_state_user_flag_set(p_ble_evt->evt.gatts_evt.conn_handle, m_gcm.flag_id_service_changed_pending, false);
  386. m_gcm.evt_handler(&event);
  387. break;
  388. case BLE_GATTS_EVT_WRITE:
  389. if (cccd_written(&p_ble_evt->evt.gatts_evt.params.write))
  390. {
  391. local_db_update_in_evt(p_ble_evt->evt.gatts_evt.conn_handle);
  392. }
  393. break;
  394. }
  395. apply_pending_flags_check();
  396. update_pending_flags_check();
  397. service_changed_pending_flags_check();
  398. }
  399. ret_code_t gcm_remote_db_store(pm_peer_id_t peer_id,
  400. ble_gatt_db_srv_t * p_remote_db,
  401. uint32_t n_services)
  402. {
  403. VERIFY_MODULE_INITIALIZED();
  404. return gccm_remote_db_store(peer_id, p_remote_db, n_services);
  405. }
  406. ret_code_t gcm_remote_db_retrieve(pm_peer_id_t peer_id,
  407. ble_gatt_db_srv_t * p_remote_db,
  408. uint32_t * p_n_services)
  409. {
  410. VERIFY_MODULE_INITIALIZED();
  411. VERIFY_PARAM_NOT_NULL(p_remote_db);
  412. return gccm_remote_db_retrieve(peer_id, p_remote_db, p_n_services);
  413. }
  414. ret_code_t gcm_local_db_cache_update(uint16_t conn_handle)
  415. {
  416. VERIFY_MODULE_INITIALIZED();
  417. ret_code_t err_code = gscm_local_db_cache_update(conn_handle);
  418. bool set_procedure_as_pending = false;
  419. if (err_code == NRF_ERROR_BUSY)
  420. {
  421. set_procedure_as_pending = true;
  422. err_code = NRF_SUCCESS;
  423. }
  424. ble_conn_state_user_flag_set(conn_handle, m_gcm.flag_id_local_db_update_pending, set_procedure_as_pending);
  425. return err_code;
  426. }
  427. ret_code_t gcm_local_db_cache_set(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
  428. {
  429. VERIFY_MODULE_INITIALIZED();
  430. return gscm_local_db_cache_set(peer_id, p_local_db);
  431. }
  432. ret_code_t gcm_local_db_cache_get(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
  433. {
  434. VERIFY_MODULE_INITIALIZED();
  435. return gscm_local_db_cache_get(peer_id, p_local_db);
  436. }
  437. void gcm_local_database_has_changed(void)
  438. {
  439. gscm_local_database_has_changed();
  440. sdk_mapped_flags_key_list_t conn_handles = ble_conn_state_conn_handles();
  441. for (uint16_t i = 0; i < conn_handles.len; i++)
  442. {
  443. if (im_peer_id_get_by_conn_handle(conn_handles.flag_keys[i]) == PM_PEER_ID_INVALID)
  444. {
  445. ble_conn_state_user_flag_set(conn_handles.flag_keys[i], m_gcm.flag_id_service_changed_pending, true);
  446. }
  447. }
  448. service_changed_pending_flags_check();
  449. }