gatts_cache_manager.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369
  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 "gatts_cache_manager.h"
  13. #include <string.h>
  14. #include "ble_gap.h"
  15. #include "ble_conn_state.h"
  16. #include "peer_manager_types.h"
  17. #include "peer_manager_internal.h"
  18. #include "peer_database.h"
  19. #include "id_manager.h"
  20. #include "sdk_common.h"
  21. #define SYS_ATTR_SYS (BLE_GATTS_SYS_ATTR_FLAG_SYS_SRVCS) /**< Shorthand define for the flag for system attributes. */
  22. #define SYS_ATTR_USR (BLE_GATTS_SYS_ATTR_FLAG_USR_SRVCS) /**< Shorthand define for the flag for user attributes. */
  23. #define SYS_ATTR_BOTH (SYS_ATTR_SYS | SYS_ATTR_USR) /**< Shorthand define for the combined flags for system and user attributes. */
  24. /**@brief Structure containing the module variable(s) of the GSCM module.
  25. */
  26. typedef struct
  27. {
  28. gscm_evt_handler_t evt_handler; /**< The event handler to use for outbound GSCM events. */
  29. pm_peer_id_t current_sc_store_peer_id;
  30. } gscm_t;
  31. static gscm_t m_gscm =
  32. {
  33. .current_sc_store_peer_id = PM_PEER_ID_INVALID,
  34. }; /**< Instantiation of module variable(s). */
  35. #define MODULE_INITIALIZED (m_gscm.evt_handler != NULL)
  36. #include "sdk_macros.h"
  37. /**@brief Function for resetting the module variable(s) of the GSCM module.
  38. *
  39. * @param[out] p_gscm The instance to reset.
  40. */
  41. static void internal_state_reset(gscm_t * p_gscm)
  42. {
  43. memset(p_gscm, 0, sizeof(gscm_t));
  44. p_gscm->current_sc_store_peer_id = PM_PEER_ID_INVALID;
  45. }
  46. //lint -save -e550
  47. /**@brief Function for storing service_changed_pending = true to flash for all peers, in sequence.
  48. *
  49. * This function aborts if it gets @ref NRF_ERROR_BUSY when trying to store. A subsequent call will
  50. * continue where the last call was aborted.
  51. */
  52. static void service_changed_pending_set(void)
  53. {
  54. VERIFY_MODULE_INITIALIZED_VOID();
  55. static const bool service_changed_pending = true;
  56. ret_code_t err_code;
  57. //lint -save -e65 -e64
  58. pm_peer_data_const_t peer_data =
  59. {
  60. .data_id = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
  61. .length_words = PM_SC_STATE_N_WORDS(),
  62. .p_service_changed_pending = &service_changed_pending,
  63. };
  64. //lint -restore
  65. err_code = pdb_raw_store(m_gscm.current_sc_store_peer_id, &peer_data, NULL);
  66. while((m_gscm.current_sc_store_peer_id != PM_PEER_ID_INVALID) && (err_code != NRF_ERROR_BUSY))
  67. {
  68. m_gscm.current_sc_store_peer_id = pdb_next_peer_id_get(m_gscm.current_sc_store_peer_id);
  69. err_code = pdb_raw_store(m_gscm.current_sc_store_peer_id, &peer_data, NULL);
  70. }
  71. }
  72. //lint -restore
  73. /**@brief Event handler for events from the peer_database module.
  74. *
  75. * @param[in] p_event The event that has happend with peer id and flags.
  76. */
  77. static void pdb_evt_handler(pdb_evt_t const * p_event)
  78. {
  79. if (p_event->evt_id == PDB_EVT_RAW_STORED)
  80. {
  81. if (p_event->data_id == PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING)
  82. {
  83. ret_code_t err_code;
  84. pm_peer_data_flash_t peer_data;
  85. err_code = pdb_read_buf_get(p_event->peer_id, PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING, &peer_data, NULL);
  86. if (err_code == NRF_SUCCESS)
  87. {
  88. gscm_evt_t gscm_evt;
  89. gscm_evt.evt_id = GSCM_EVT_SC_STATE_STORED;
  90. gscm_evt.peer_id = p_event->peer_id;
  91. gscm_evt.params.sc_state_stored.state = &peer_data.p_service_changed_pending;
  92. m_gscm.evt_handler(&gscm_evt);
  93. }
  94. }
  95. }
  96. if (m_gscm.current_sc_store_peer_id != PM_PEER_ID_INVALID)
  97. {
  98. service_changed_pending_set();
  99. }
  100. }
  101. ret_code_t gscm_init(gscm_evt_handler_t evt_handler)
  102. {
  103. ret_code_t err_code;
  104. if (evt_handler == NULL)
  105. {
  106. err_code = NRF_ERROR_NULL;
  107. }
  108. else
  109. {
  110. err_code = pdb_register(pdb_evt_handler);
  111. if (err_code == NRF_SUCCESS)
  112. {
  113. internal_state_reset(&m_gscm);
  114. m_gscm.evt_handler = evt_handler;
  115. }
  116. }
  117. return err_code;
  118. }
  119. ret_code_t gscm_local_db_cache_update(uint16_t conn_handle)
  120. {
  121. VERIFY_MODULE_INITIALIZED();
  122. pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  123. ret_code_t err_code;
  124. if (peer_id == PM_PEER_ID_INVALID)
  125. {
  126. return BLE_ERROR_INVALID_CONN_HANDLE;
  127. }
  128. else
  129. {
  130. pm_peer_data_t peer_data;
  131. uint16_t n_bufs = 1;
  132. bool retry_with_bigger_buffer = false;
  133. do
  134. {
  135. retry_with_bigger_buffer = false;
  136. err_code = pdb_write_buf_get(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, n_bufs++, &peer_data);
  137. if (err_code == NRF_SUCCESS)
  138. {
  139. pm_peer_data_local_gatt_db_t * p_local_gatt_db = peer_data.p_local_gatt_db;
  140. p_local_gatt_db->flags = SYS_ATTR_BOTH;
  141. err_code = sd_ble_gatts_sys_attr_get(conn_handle, &p_local_gatt_db->data[0], &p_local_gatt_db->len, p_local_gatt_db->flags);
  142. if (err_code == NRF_SUCCESS)
  143. {
  144. err_code = pdb_write_buf_store(peer_id, PM_PEER_DATA_ID_GATT_LOCAL);
  145. }
  146. else
  147. {
  148. if (err_code == NRF_ERROR_DATA_SIZE)
  149. {
  150. // The sys attributes are bigger than the requested write buffer.
  151. retry_with_bigger_buffer = true;
  152. }
  153. else if (err_code == NRF_ERROR_NOT_FOUND)
  154. {
  155. // There are no sys attributes in the GATT db, so nothing needs to be stored.
  156. err_code = NRF_SUCCESS;
  157. }
  158. ret_code_t err_code_release = pdb_write_buf_release(peer_id, PM_PEER_DATA_ID_GATT_LOCAL);
  159. if (err_code_release != NRF_SUCCESS)
  160. {
  161. err_code = NRF_ERROR_INTERNAL;
  162. }
  163. }
  164. }
  165. else if (err_code == NRF_ERROR_INVALID_PARAM)
  166. {
  167. // The sys attributes are bigger than the entire write buffer.
  168. err_code = NRF_ERROR_DATA_SIZE;
  169. }
  170. } while (retry_with_bigger_buffer);
  171. }
  172. return err_code;
  173. }
  174. ret_code_t gscm_local_db_cache_apply(uint16_t conn_handle)
  175. {
  176. VERIFY_MODULE_INITIALIZED();
  177. pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  178. ret_code_t err_code;
  179. pm_peer_data_flash_t peer_data;
  180. uint8_t const * p_sys_attr_data = NULL;
  181. uint16_t sys_attr_len = 0;
  182. uint32_t sys_attr_flags = (SYS_ATTR_BOTH);
  183. bool all_attributes_applied = true;
  184. if (peer_id != PM_PEER_ID_INVALID)
  185. {
  186. err_code = pdb_read_buf_get(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, &peer_data, NULL);
  187. if (err_code == NRF_SUCCESS)
  188. {
  189. pm_peer_data_local_gatt_db_t const * p_local_gatt_db;
  190. p_local_gatt_db = peer_data.p_local_gatt_db;
  191. p_sys_attr_data = p_local_gatt_db->data;
  192. sys_attr_len = p_local_gatt_db->len;
  193. sys_attr_flags = p_local_gatt_db->flags;
  194. }
  195. }
  196. do
  197. {
  198. err_code = sd_ble_gatts_sys_attr_set(conn_handle, p_sys_attr_data, sys_attr_len, sys_attr_flags);
  199. if (err_code == NRF_ERROR_NO_MEM)
  200. {
  201. err_code = NRF_ERROR_BUSY;
  202. }
  203. else if (err_code == NRF_ERROR_INVALID_STATE)
  204. {
  205. err_code = NRF_SUCCESS;
  206. }
  207. else if (err_code == NRF_ERROR_INVALID_DATA)
  208. {
  209. all_attributes_applied = false;
  210. if (sys_attr_flags & SYS_ATTR_USR)
  211. {
  212. // Try setting only system attributes.
  213. sys_attr_flags = SYS_ATTR_SYS;
  214. }
  215. else if (p_sys_attr_data || sys_attr_len)
  216. {
  217. // Try reporting that none exist.
  218. p_sys_attr_data = NULL;
  219. sys_attr_len = 0;
  220. sys_attr_flags = SYS_ATTR_BOTH;
  221. }
  222. else
  223. {
  224. err_code = NRF_ERROR_INTERNAL;
  225. }
  226. }
  227. } while (err_code == NRF_ERROR_INVALID_DATA);
  228. if (!all_attributes_applied)
  229. {
  230. err_code = NRF_ERROR_INVALID_DATA;
  231. }
  232. return err_code;
  233. }
  234. ret_code_t gscm_local_db_cache_set(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
  235. {
  236. VERIFY_MODULE_INITIALIZED();
  237. pm_peer_data_const_t peer_data;
  238. memset(&peer_data, 0, sizeof(pm_peer_data_const_t));
  239. peer_data.data_id = PM_PEER_DATA_ID_GATT_LOCAL;
  240. peer_data.p_local_gatt_db = p_local_db;
  241. return pdb_raw_store(peer_id, &peer_data, NULL);
  242. }
  243. ret_code_t gscm_local_db_cache_get(pm_peer_id_t peer_id, pm_peer_data_local_gatt_db_t * p_local_db)
  244. {
  245. VERIFY_MODULE_INITIALIZED();
  246. pm_peer_data_t peer_data;
  247. memset(&peer_data, 0, sizeof(pm_peer_data_t));
  248. peer_data.p_local_gatt_db = p_local_db;
  249. return pdb_raw_read(peer_id, PM_PEER_DATA_ID_GATT_LOCAL, &peer_data);
  250. }
  251. void gscm_local_database_has_changed(void)
  252. {
  253. VERIFY_MODULE_INITIALIZED_VOID();
  254. m_gscm.current_sc_store_peer_id = pdb_next_peer_id_get(PM_PEER_ID_INVALID);
  255. service_changed_pending_set();
  256. }
  257. bool gscm_service_changed_ind_needed(uint16_t conn_handle)
  258. {
  259. ret_code_t err_code;
  260. pm_peer_data_flash_t peer_data;
  261. pm_peer_id_t peer_id = im_peer_id_get_by_conn_handle(conn_handle);
  262. err_code = pdb_read_buf_get(peer_id, PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING, &peer_data, NULL);
  263. if (err_code != NRF_SUCCESS)
  264. {
  265. return false;
  266. }
  267. return &peer_data.p_service_changed_pending;
  268. }
  269. ret_code_t gscm_service_changed_ind_send(uint16_t conn_handle)
  270. {
  271. static uint16_t start_handle = 0x0000;
  272. const uint16_t end_handle = 0xFFFF;
  273. ret_code_t err_code;
  274. do
  275. {
  276. err_code = sd_ble_gatts_service_changed(conn_handle, start_handle, end_handle);
  277. if (err_code == BLE_ERROR_INVALID_ATTR_HANDLE)
  278. {
  279. start_handle += 1;
  280. }
  281. } while (err_code == BLE_ERROR_INVALID_ATTR_HANDLE);
  282. return err_code;
  283. }
  284. void gscm_db_change_notification_done(pm_peer_id_t peer_id)
  285. {
  286. VERIFY_MODULE_INITIALIZED_VOID();
  287. static const bool service_changed_pending = false;
  288. //lint -save -e65 -e64
  289. pm_peer_data_const_t peer_data =
  290. {
  291. .data_id = PM_PEER_DATA_ID_SERVICE_CHANGED_PENDING,
  292. .length_words = PM_SC_STATE_N_WORDS(),
  293. .p_service_changed_pending = &service_changed_pending,
  294. };
  295. //lint -restore
  296. // Don't need to check return code, because all error conditions can be ignored.
  297. //lint -save -e550
  298. (void) pdb_raw_store(peer_id, &peer_data, NULL);
  299. //lint -restore
  300. }