ble_ans_c.c 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530
  1. /**
  2. * Copyright (c) 2012 - 2020, Nordic Semiconductor ASA
  3. *
  4. * All rights reserved.
  5. *
  6. * Redistribution and use in source and binary forms, with or without modification,
  7. * are permitted provided that the following conditions are met:
  8. *
  9. * 1. Redistributions of source code must retain the above copyright notice, this
  10. * list of conditions and the following disclaimer.
  11. *
  12. * 2. Redistributions in binary form, except as embedded into a Nordic
  13. * Semiconductor ASA integrated circuit in a product or a software update for
  14. * such product, must reproduce the above copyright notice, this list of
  15. * conditions and the following disclaimer in the documentation and/or other
  16. * materials provided with the distribution.
  17. *
  18. * 3. Neither the name of Nordic Semiconductor ASA nor the names of its
  19. * contributors may be used to endorse or promote products derived from this
  20. * software without specific prior written permission.
  21. *
  22. * 4. This software, with or without modification, must only be used with a
  23. * Nordic Semiconductor ASA integrated circuit.
  24. *
  25. * 5. Any software provided in binary form under this license must not be reverse
  26. * engineered, decompiled, modified and/or disassembled.
  27. *
  28. * THIS SOFTWARE IS PROVIDED BY NORDIC SEMICONDUCTOR ASA "AS IS" AND ANY EXPRESS
  29. * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  30. * OF MERCHANTABILITY, NONINFRINGEMENT, AND FITNESS FOR A PARTICULAR PURPOSE ARE
  31. * DISCLAIMED. IN NO EVENT SHALL NORDIC SEMICONDUCTOR ASA OR CONTRIBUTORS BE
  32. * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  33. * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
  34. * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  35. * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  36. * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
  37. * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  38. *
  39. */
  40. /* Attention!
  41. * To maintain compliance with Nordic Semiconductor ASA's Bluetooth profile
  42. * qualification listings, this section of source code must not be modified.
  43. */
  44. #include "sdk_common.h"
  45. #if NRF_MODULE_ENABLED(BLE_ANS_C)
  46. #include "ble_ans_c.h"
  47. #include <string.h>
  48. #include <stdbool.h>
  49. #include "ble_err.h"
  50. #include "nrf_assert.h"
  51. #include "ble_db_discovery.h"
  52. #define NRF_LOG_MODULE_NAME ble_ans_c
  53. #include "nrf_log.h"
  54. NRF_LOG_MODULE_REGISTER();
  55. #define NOTIFICATION_DATA_LENGTH 2 /**< The mandatory length of the notification data. After the mandatory data, the optional message is located. */
  56. #define READ_DATA_LENGTH_MIN 1 /**< Minimum data length in a valid Alert Notification Read Response message. */
  57. #define WRITE_MESSAGE_LENGTH 2 /**< Length of the write message for CCCD and control point. */
  58. /**@brief Function for intercepting GATTC and @ref nrf_ble_gq errors.
  59. *
  60. * @param[in] nrf_error Error code.
  61. * @param[in] p_ctx Parameter from the event handler.
  62. * @param[in] conn_handle Connection handle.
  63. */
  64. static void gatt_error_handler(uint32_t nrf_error,
  65. void * p_ctx,
  66. uint16_t conn_handle)
  67. {
  68. ble_ans_c_t * p_ans = (ble_ans_c_t *)p_ctx;
  69. NRF_LOG_DEBUG("A GATT Client error has occurred on conn_handle: 0X%X", conn_handle);
  70. if (p_ans->error_handler != NULL)
  71. {
  72. p_ans->error_handler(nrf_error);
  73. }
  74. }
  75. /** @brief Function for copying a characteristic.
  76. */
  77. static void char_set(ble_gattc_char_t * p_dest_char, ble_gattc_char_t const * p_source_char)
  78. {
  79. memcpy(p_dest_char, p_source_char, sizeof(ble_gattc_char_t));
  80. }
  81. static void char_cccd_set(ble_gattc_desc_t * p_cccd, uint16_t cccd_handle)
  82. {
  83. p_cccd->handle = cccd_handle;
  84. }
  85. /** @brief Function for checking the presence of all the handles required by the client to use the server.
  86. */
  87. static bool is_valid_ans_srv_discovered(ble_ans_c_service_t const * p_srv)
  88. {
  89. if ((p_srv->alert_notif_ctrl_point.handle_value == BLE_GATT_HANDLE_INVALID) ||
  90. (p_srv->suported_new_alert_cat.handle_value == BLE_GATT_HANDLE_INVALID) ||
  91. (p_srv->suported_unread_alert_cat.handle_value == BLE_GATT_HANDLE_INVALID) ||
  92. (p_srv->new_alert.handle_value == BLE_GATT_HANDLE_INVALID) ||
  93. (p_srv->unread_alert_status.handle_value == BLE_GATT_HANDLE_INVALID) ||
  94. (p_srv->new_alert_cccd.handle == BLE_GATT_HANDLE_INVALID) ||
  95. (p_srv->unread_alert_cccd.handle == BLE_GATT_HANDLE_INVALID)
  96. )
  97. {
  98. // At least one required characteristic is missing on the server side.
  99. return false;
  100. }
  101. return true;
  102. }
  103. void ble_ans_c_on_db_disc_evt(ble_ans_c_t * p_ans, ble_db_discovery_evt_t const * p_evt)
  104. {
  105. ble_ans_c_evt_t evt;
  106. memset(&evt, 0, sizeof(ble_ans_c_evt_t));
  107. evt.conn_handle = p_evt->conn_handle;
  108. // Check if the Alert Notification Service is discovered.
  109. if (p_evt->evt_type == BLE_DB_DISCOVERY_COMPLETE
  110. &&
  111. p_evt->params.discovered_db.srv_uuid.uuid == BLE_UUID_ALERT_NOTIFICATION_SERVICE
  112. &&
  113. p_evt->params.discovered_db.srv_uuid.type == BLE_UUID_TYPE_BLE)
  114. {
  115. // Find the characteristics inside the service.
  116. for (uint8_t i = 0; i < p_evt->params.discovered_db.char_count; i++)
  117. {
  118. ble_gatt_db_char_t const * p_char = &(p_evt->params.discovered_db.charateristics[i]);
  119. switch (p_char->characteristic.uuid.uuid)
  120. {
  121. case BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR:
  122. NRF_LOG_DEBUG("Found Ctrlpt \r\n\r");
  123. char_set(&evt.data.service.alert_notif_ctrl_point, &p_char->characteristic);
  124. break;
  125. case BLE_UUID_UNREAD_ALERT_CHAR:
  126. NRF_LOG_DEBUG("Found Unread Alert \r\n\r");
  127. char_set(&evt.data.service.unread_alert_status, &p_char->characteristic);
  128. char_cccd_set(&evt.data.service.unread_alert_cccd,
  129. p_char->cccd_handle);
  130. break;
  131. case BLE_UUID_NEW_ALERT_CHAR:
  132. NRF_LOG_DEBUG("Found New Alert \r\n\r");
  133. char_set(&evt.data.service.new_alert, &p_char->characteristic);
  134. char_cccd_set(&evt.data.service.new_alert_cccd,
  135. p_char->cccd_handle);
  136. break;
  137. case BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR:
  138. NRF_LOG_DEBUG("Found supported unread alert category \r\n\r");
  139. char_set(&evt.data.service.suported_unread_alert_cat, &p_char->characteristic);
  140. break;
  141. case BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR:
  142. NRF_LOG_DEBUG("Found supported new alert category \r\n\r");
  143. char_set(&evt.data.service.suported_new_alert_cat, &p_char->characteristic);
  144. break;
  145. default:
  146. // No implementation needed.
  147. break;
  148. }
  149. }
  150. if (is_valid_ans_srv_discovered(&evt.data.service))
  151. {
  152. evt.evt_type = BLE_ANS_C_EVT_DISCOVERY_COMPLETE;
  153. }
  154. }
  155. else if ((p_evt->evt_type == BLE_DB_DISCOVERY_SRV_NOT_FOUND) ||
  156. (p_evt->evt_type == BLE_DB_DISCOVERY_ERROR))
  157. {
  158. evt.evt_type = BLE_ANS_C_EVT_DISCOVERY_FAILED;
  159. }
  160. else
  161. {
  162. return;
  163. }
  164. p_ans->evt_handler(&evt);
  165. }
  166. /**@brief Function for receiving and validating notifications received from the central.
  167. */
  168. static void event_notify(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
  169. {
  170. uint32_t message_length;
  171. ble_ans_c_evt_t event;
  172. ble_ans_alert_notification_t * p_alert = &event.data.alert;
  173. ble_gattc_evt_hvx_t const * p_notification = &p_ble_evt->evt.gattc_evt.params.hvx;
  174. // If the message is not valid, then ignore.
  175. event.evt_type = BLE_ANS_C_EVT_NOTIFICATION;
  176. if (p_notification->len < NOTIFICATION_DATA_LENGTH)
  177. {
  178. return;
  179. }
  180. message_length = p_notification->len - NOTIFICATION_DATA_LENGTH;
  181. if (p_notification->handle == p_ans->service.new_alert.handle_value)
  182. {
  183. BLE_UUID_COPY_INST(event.uuid, p_ans->service.new_alert.uuid);
  184. }
  185. else if (p_notification->handle == p_ans->service.unread_alert_status.handle_value)
  186. {
  187. BLE_UUID_COPY_INST(event.uuid, p_ans->service.unread_alert_status.uuid);
  188. }
  189. else
  190. {
  191. // Nothing to process.
  192. return;
  193. }
  194. p_alert->alert_category = p_notification->data[0];
  195. p_alert->alert_category_count = p_notification->data[1]; //lint !e415
  196. p_alert->alert_msg_length = (message_length > p_ans->message_buffer_size)
  197. ? p_ans->message_buffer_size
  198. : message_length;
  199. p_alert->p_alert_msg_buf = p_ans->p_message_buffer;
  200. memcpy(p_alert->p_alert_msg_buf,
  201. &p_notification->data[NOTIFICATION_DATA_LENGTH],
  202. p_alert->alert_msg_length); //lint !e416
  203. p_ans->evt_handler(&event);
  204. }
  205. /**@brief Function for validating and passing the response to the application,
  206. * when a read response is received.
  207. */
  208. static void event_read_rsp(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
  209. {
  210. ble_ans_c_evt_t event;
  211. ble_gattc_evt_read_rsp_t const * p_response;
  212. p_response = &p_ble_evt->evt.gattc_evt.params.read_rsp;
  213. event.evt_type = BLE_ANS_C_EVT_READ_RESP;
  214. if (p_response->len < READ_DATA_LENGTH_MIN)
  215. {
  216. return;
  217. }
  218. if (p_response->handle == p_ans->service.suported_new_alert_cat.handle_value)
  219. {
  220. BLE_UUID_COPY_INST(event.uuid, p_ans->service.suported_new_alert_cat.uuid);
  221. }
  222. else if (p_response->handle == p_ans->service.suported_unread_alert_cat.handle_value)
  223. {
  224. BLE_UUID_COPY_INST(event.uuid, p_ans->service.suported_unread_alert_cat.uuid);
  225. }
  226. else
  227. {
  228. // If the response is not valid, then ignore.
  229. return;
  230. }
  231. event.data.settings = *(ble_ans_alert_settings_t *)(p_response->data);
  232. if (p_response->len == READ_DATA_LENGTH_MIN)
  233. {
  234. // These variables must default to 0, if they are not returned by central.
  235. event.data.settings.ans_high_prioritized_alert_support = 0;
  236. event.data.settings.ans_instant_message_support = 0;
  237. }
  238. p_ans->evt_handler(&event);
  239. }
  240. /**@brief Function for disconnecting and cleaning the current service.
  241. */
  242. static void event_disconnect(ble_ans_c_t * p_ans, ble_evt_t const * p_ble_evt)
  243. {
  244. if (p_ans->conn_handle == p_ble_evt->evt.gap_evt.conn_handle)
  245. {
  246. p_ans->conn_handle = BLE_CONN_HANDLE_INVALID;
  247. // Clearing all data for the service also sets all handle values to @ref BLE_GATT_HANDLE_INVALID
  248. memset(&p_ans->service, 0, sizeof(ble_ans_c_service_t));
  249. // If there was a valid instance of IAS on the peer, send an event to the
  250. // application, so that it can do any cleanup related to this module.
  251. ble_ans_c_evt_t evt;
  252. evt.evt_type = BLE_ANS_C_EVT_DISCONN_COMPLETE;
  253. p_ans->evt_handler(&evt);
  254. }
  255. }
  256. /**@brief Function for handling of BLE stack events. */
  257. void ble_ans_c_on_ble_evt(ble_evt_t const * p_ble_evt, void * p_context)
  258. {
  259. ble_ans_c_t * p_ans = (ble_ans_c_t *)p_context;
  260. switch (p_ble_evt->header.evt_id)
  261. {
  262. case BLE_GATTC_EVT_HVX:
  263. event_notify(p_ans, p_ble_evt);
  264. break;
  265. case BLE_GATTC_EVT_READ_RSP:
  266. event_read_rsp(p_ans, p_ble_evt);
  267. break;
  268. case BLE_GAP_EVT_DISCONNECTED:
  269. event_disconnect(p_ans, p_ble_evt);
  270. break;
  271. }
  272. }
  273. uint32_t ble_ans_c_init(ble_ans_c_t * p_ans, ble_ans_c_init_t const * p_ans_init)
  274. {
  275. VERIFY_PARAM_NOT_NULL(p_ans);
  276. VERIFY_PARAM_NOT_NULL(p_ans_init);
  277. VERIFY_PARAM_NOT_NULL(p_ans_init->evt_handler);
  278. VERIFY_PARAM_NOT_NULL(p_ans_init->p_gatt_queue);
  279. // Clear all handles.
  280. memset(p_ans, 0, sizeof(ble_ans_c_t));
  281. p_ans->conn_handle = BLE_CONN_HANDLE_INVALID;
  282. p_ans->evt_handler = p_ans_init->evt_handler;
  283. p_ans->error_handler = p_ans_init->error_handler;
  284. p_ans->message_buffer_size = p_ans_init->message_buffer_size;
  285. p_ans->p_message_buffer = p_ans_init->p_message_buffer;
  286. p_ans->p_gatt_queue = p_ans_init->p_gatt_queue;
  287. BLE_UUID_BLE_ASSIGN(p_ans->service.service.uuid, BLE_UUID_ALERT_NOTIFICATION_SERVICE);
  288. BLE_UUID_BLE_ASSIGN(p_ans->service.new_alert.uuid, BLE_UUID_NEW_ALERT_CHAR);
  289. BLE_UUID_BLE_ASSIGN(p_ans->service.alert_notif_ctrl_point.uuid,
  290. BLE_UUID_ALERT_NOTIFICATION_CONTROL_POINT_CHAR);
  291. BLE_UUID_BLE_ASSIGN(p_ans->service.unread_alert_status.uuid, BLE_UUID_UNREAD_ALERT_CHAR);
  292. BLE_UUID_BLE_ASSIGN(p_ans->service.suported_new_alert_cat.uuid,
  293. BLE_UUID_SUPPORTED_NEW_ALERT_CATEGORY_CHAR);
  294. BLE_UUID_BLE_ASSIGN(p_ans->service.suported_unread_alert_cat.uuid,
  295. BLE_UUID_SUPPORTED_UNREAD_ALERT_CATEGORY_CHAR);
  296. BLE_UUID_BLE_ASSIGN(p_ans->service.new_alert_cccd.uuid, BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
  297. BLE_UUID_BLE_ASSIGN(p_ans->service.unread_alert_cccd.uuid,
  298. BLE_UUID_DESCRIPTOR_CLIENT_CHAR_CONFIG);
  299. return ble_db_discovery_evt_register(&p_ans->service.service.uuid);
  300. }
  301. /**@brief Function for creating a tx message for writing a CCCD.
  302. */
  303. static uint32_t cccd_configure(ble_ans_c_t const * const p_ans,
  304. uint16_t handle_cccd,
  305. bool notification_enable)
  306. {
  307. nrf_ble_gq_req_t cccd_req;
  308. uint16_t cccd_val = notification_enable ? BLE_GATT_HVX_NOTIFICATION : 0;
  309. uint8_t cccd[WRITE_MESSAGE_LENGTH];
  310. memset(&cccd_req, 0, sizeof(nrf_ble_gq_req_t));
  311. cccd[0] = LSB_16(cccd_val);
  312. cccd[1] = MSB_16(cccd_val);
  313. cccd_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
  314. cccd_req.error_handler.cb = gatt_error_handler;
  315. cccd_req.error_handler.p_ctx = (ble_ans_c_t *)p_ans;
  316. cccd_req.params.gattc_write.handle = handle_cccd;
  317. cccd_req.params.gattc_write.len = WRITE_MESSAGE_LENGTH;
  318. cccd_req.params.gattc_write.p_value = cccd;
  319. cccd_req.params.gattc_write.offset = 0;
  320. cccd_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
  321. return nrf_ble_gq_item_add(p_ans->p_gatt_queue, &cccd_req, p_ans->conn_handle);
  322. }
  323. uint32_t ble_ans_c_enable_notif_new_alert(ble_ans_c_t const * p_ans)
  324. {
  325. if (p_ans->conn_handle == BLE_CONN_HANDLE_INVALID)
  326. {
  327. return NRF_ERROR_INVALID_STATE;
  328. }
  329. else
  330. {
  331. return cccd_configure(p_ans,
  332. p_ans->service.new_alert_cccd.handle,
  333. true);
  334. }
  335. }
  336. uint32_t ble_ans_c_disable_notif_new_alert(ble_ans_c_t const * p_ans)
  337. {
  338. return cccd_configure(p_ans,
  339. p_ans->service.new_alert_cccd.handle,
  340. false);
  341. }
  342. uint32_t ble_ans_c_enable_notif_unread_alert(ble_ans_c_t const * p_ans)
  343. {
  344. if ( p_ans->conn_handle == BLE_CONN_HANDLE_INVALID)
  345. {
  346. return NRF_ERROR_INVALID_STATE;
  347. }
  348. return cccd_configure(p_ans,
  349. p_ans->service.unread_alert_cccd.handle,
  350. true);
  351. }
  352. uint32_t ble_ans_c_disable_notif_unread_alert(ble_ans_c_t const * p_ans)
  353. {
  354. return cccd_configure(p_ans,
  355. p_ans->service.unread_alert_cccd.handle,
  356. false);
  357. }
  358. uint32_t ble_ans_c_control_point_write(ble_ans_c_t const * p_ans,
  359. ble_ans_control_point_t const * p_control_point)
  360. {
  361. nrf_ble_gq_req_t gq_req;
  362. uint8_t write_data[WRITE_MESSAGE_LENGTH];
  363. write_data[0] = p_control_point->command;
  364. write_data[1] = p_control_point->category;
  365. memset(&gq_req, 0, sizeof(nrf_ble_gq_req_t));
  366. gq_req.type = NRF_BLE_GQ_REQ_GATTC_WRITE;
  367. gq_req.error_handler.cb = gatt_error_handler;
  368. gq_req.error_handler.p_ctx = (ble_ans_c_t *)p_ans;
  369. gq_req.params.gattc_write.handle = p_ans->service.alert_notif_ctrl_point.handle_value;
  370. gq_req.params.gattc_write.len = WRITE_MESSAGE_LENGTH;
  371. gq_req.params.gattc_write.p_value = write_data;
  372. gq_req.params.gattc_write.offset = 0;
  373. gq_req.params.gattc_write.write_op = BLE_GATT_OP_WRITE_REQ;
  374. return nrf_ble_gq_item_add(p_ans->p_gatt_queue, &gq_req, p_ans->conn_handle);
  375. }
  376. uint32_t ble_ans_c_new_alert_read(ble_ans_c_t const * p_ans)
  377. {
  378. nrf_ble_gq_req_t gq_req;
  379. memset(&gq_req, 0, sizeof(nrf_ble_gq_req_t));
  380. gq_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
  381. gq_req.error_handler.cb = gatt_error_handler;
  382. gq_req.error_handler.p_ctx = (ble_ans_c_t *)p_ans;
  383. gq_req.params.gattc_read.handle = p_ans->service.suported_new_alert_cat.handle_value;
  384. gq_req.params.gattc_read.offset = 0;
  385. return nrf_ble_gq_item_add(p_ans->p_gatt_queue, &gq_req, p_ans->conn_handle);
  386. }
  387. uint32_t ble_ans_c_unread_alert_read(ble_ans_c_t const * p_ans)
  388. {
  389. nrf_ble_gq_req_t gq_req;
  390. memset(&gq_req, 0, sizeof(nrf_ble_gq_req_t));
  391. gq_req.type = NRF_BLE_GQ_REQ_GATTC_READ;
  392. gq_req.error_handler.cb = gatt_error_handler;
  393. gq_req.error_handler.p_ctx = (ble_ans_c_t *)p_ans;
  394. gq_req.params.gattc_read.handle = p_ans->service.suported_unread_alert_cat.handle_value;
  395. gq_req.params.gattc_read.offset = 0;
  396. return nrf_ble_gq_item_add(p_ans->p_gatt_queue, &gq_req, p_ans->conn_handle);
  397. }
  398. uint32_t ble_ans_c_new_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category_id)
  399. {
  400. ble_ans_control_point_t control_point;
  401. control_point.command = ANS_NOTIFY_NEW_INCOMING_ALERT_IMMEDIATELY;
  402. control_point.category = category_id;
  403. return ble_ans_c_control_point_write(p_ans, &control_point);
  404. }
  405. uint32_t ble_ans_c_unread_alert_notify(ble_ans_c_t const * p_ans, ble_ans_category_id_t category_id)
  406. {
  407. ble_ans_control_point_t control_point;
  408. control_point.command = ANS_NOTIFY_UNREAD_CATEGORY_STATUS_IMMEDIATELY;
  409. control_point.category = category_id;
  410. return ble_ans_c_control_point_write(p_ans, &control_point);
  411. }
  412. uint32_t ble_ans_c_handles_assign(ble_ans_c_t * p_ans,
  413. uint16_t conn_handle,
  414. ble_ans_c_service_t const * p_peer_handles)
  415. {
  416. VERIFY_PARAM_NOT_NULL(p_ans);
  417. if (!is_valid_ans_srv_discovered(p_peer_handles))
  418. {
  419. return NRF_ERROR_INVALID_PARAM;
  420. }
  421. p_ans->conn_handle = conn_handle;
  422. if (p_peer_handles != NULL)
  423. {
  424. // Copy the handles from the discovered characteristics to the provided client instance.
  425. char_set(&p_ans->service.alert_notif_ctrl_point, &p_peer_handles->alert_notif_ctrl_point);
  426. char_set(&p_ans->service.suported_new_alert_cat, &p_peer_handles->suported_new_alert_cat);
  427. char_set(&p_ans->service.suported_unread_alert_cat, &p_peer_handles->suported_unread_alert_cat);
  428. char_set(&p_ans->service.new_alert, &p_peer_handles->new_alert);
  429. char_cccd_set(&p_ans->service.new_alert_cccd, p_peer_handles->new_alert_cccd.handle);
  430. char_set(&p_ans->service.unread_alert_status, &p_peer_handles->unread_alert_status);
  431. char_cccd_set(&p_ans->service.unread_alert_cccd, p_peer_handles->unread_alert_cccd.handle);
  432. }
  433. return nrf_ble_gq_conn_handle_register(p_ans->p_gatt_queue, conn_handle);
  434. }
  435. #endif // NRF_MODULE_ENABLED(BLE_ANS_C)