ble_ots_oacp.c 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. /**
  2. * Copyright (c) 2017 - 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. #include "ble_ots_oacp.h"
  41. #include <string.h>
  42. #include "fds.h"
  43. #include "crc32.h"
  44. #include "ble_ots.h"
  45. #include "ble_ots_l2cap.h"
  46. #include "ble_ots_object.h"
  47. #define NRF_LOG_MODULE_NAME ble_ots_oacp
  48. #include "nrf_log.h"
  49. NRF_LOG_MODULE_REGISTER();
  50. #define OTS_FILE_ID 1234
  51. #define OTS_FDS_KEY 4321
  52. #define OACP_INDICATION_LEN 3 /**< Indication data length. */
  53. /**@brief Function for interception of GATT errors and @ref nrf_ble_gq errors.
  54. *
  55. * @param[in] nrf_error Error code.
  56. * @param[in] p_ctx Parameter from the event handler.
  57. * @param[in] conn_handle Connection handle.
  58. */
  59. static void gatt_error_handler(uint32_t nrf_error,
  60. void * p_ctx,
  61. uint16_t conn_handle)
  62. {
  63. ble_ots_t * p_ots = (ble_ots_t *)p_ctx;
  64. if (p_ots->error_handler != NULL)
  65. {
  66. p_ots->error_handler(nrf_error);
  67. }
  68. }
  69. /**@brief Checks if the cccd handle is configured for indication
  70. *
  71. * @param[in] cccd_handle The CCCD handle.
  72. */
  73. static bool is_cccd_configured(ble_ots_oacp_t * const p_ots_oacp)
  74. {
  75. uint32_t err_code;
  76. uint8_t cccd_value_buf[BLE_CCCD_VALUE_LEN];
  77. bool is_oacp_indic_enabled = false;
  78. ble_gatts_value_t gatts_value;
  79. uint16_t cccd_handle = p_ots_oacp->oacp_handles.cccd_handle;
  80. uint16_t conn_handle = p_ots_oacp->p_ots->conn_handle;
  81. // Initialize value struct.
  82. memset(&gatts_value, 0, sizeof(gatts_value));
  83. gatts_value.len = BLE_CCCD_VALUE_LEN;
  84. gatts_value.offset = 0;
  85. gatts_value.p_value = cccd_value_buf;
  86. err_code = sd_ble_gatts_value_get(conn_handle,
  87. cccd_handle,
  88. &gatts_value);
  89. if (err_code == BLE_ERROR_GATTS_SYS_ATTR_MISSING)
  90. {
  91. is_oacp_indic_enabled = false;
  92. }
  93. else if (err_code != NRF_SUCCESS)
  94. {
  95. // Report error to application
  96. if (p_ots_oacp->p_ots->error_handler != NULL)
  97. {
  98. p_ots_oacp->p_ots->error_handler(err_code);
  99. }
  100. }
  101. else
  102. {
  103. is_oacp_indic_enabled = ble_srv_is_indication_enabled(cccd_value_buf);
  104. }
  105. return is_oacp_indic_enabled;
  106. }
  107. /** @brief This is the l2cap connection oriented channel event handler.
  108. *
  109. * @param[in] p_ots_l2cap Pointer to the l2cap module
  110. * @param[in] p_evt The pointer to the event.
  111. */
  112. static void ots_l2cap_evt_handler(ble_ots_l2cap_t * p_ots_l2cap, ble_ots_l2cap_evt_t * p_evt)
  113. {
  114. uint32_t err_code;
  115. switch (p_evt->type)
  116. {
  117. case BLE_OTS_L2CAP_EVT_CH_CONNECTED:
  118. NRF_LOG_INFO("BLE_OTS_L2CAP_EVT_CH_CONNECTED.");
  119. break;
  120. case BLE_OTS_L2CAP_EVT_CH_DISCONNECTED:
  121. NRF_LOG_INFO("BLE_OTS_L2CAP_EVT_CH_DISCONNECTED.");
  122. break;
  123. case BLE_OTS_L2CAP_EVT_SEND_COMPLETE:
  124. NRF_LOG_INFO("BLE_OTS_L2CAP_EVT_SEND_COMPLETE.");
  125. p_ots_l2cap->p_ots_oacp->p_ots->p_current_object->is_locked = false;
  126. break;
  127. case BLE_OTS_L2CAP_EVT_RECV_COMPLETE:
  128. NRF_LOG_INFO("BLE_OTS_L2CAP_EVT_RECV_COMPLETE.");
  129. memcpy(p_ots_l2cap->p_ots_oacp->p_ots->p_current_object->data,
  130. p_ots_l2cap->rx_params.sdu_buf.p_data,
  131. p_ots_l2cap->rx_params.sdu_buf.len);
  132. err_code = ble_ots_object_set_current_size(&p_ots_l2cap->p_ots_oacp->p_ots->object_chars,
  133. p_ots_l2cap->p_ots_oacp->p_ots->p_current_object,
  134. p_ots_l2cap->p_ots_oacp->p_ots->p_current_object->current_size);
  135. if (err_code != NRF_SUCCESS)
  136. {
  137. NRF_LOG_ERROR("ble_ots_object_set_current_size returned error 0x%x", err_code);
  138. }
  139. ble_ots_evt_t evt;
  140. evt.type = BLE_OTS_EVT_OBJECT_RECEIVED;
  141. p_ots_l2cap->p_ots_oacp->p_ots->evt_handler(p_ots_l2cap->p_ots_oacp->p_ots, &evt);
  142. break;
  143. }
  144. }
  145. /**@brief Adds the OACP characteristic
  146. *
  147. * @param[in] p_ots_oacp Pointer to the OACP structure.
  148. * @param[in] service_handle The service handle to attach the characteristic to.
  149. * @param[in] write_access The write security level for the OACP value handle.
  150. * @param[in] cccd_write_access The write security level for the OACP cccd handle.
  151. *
  152. * @return NRF_SUCCESS When added successfully, else an error code from characteristic_add().
  153. */
  154. static uint32_t oacp_char_add(ble_ots_oacp_t * const p_ots_oacp,
  155. uint16_t service_handle,
  156. security_req_t write_access,
  157. security_req_t cccd_write_access)
  158. {
  159. ble_add_char_params_t add_char_params;
  160. memset(&add_char_params, 0, sizeof(add_char_params));
  161. add_char_params.uuid = BLE_UUID_OTS_OACP;
  162. add_char_params.uuid_type = BLE_UUID_TYPE_BLE;
  163. add_char_params.max_len = BLE_OTS_MAX_OACP_SIZE;
  164. add_char_params.init_len = 0;
  165. add_char_params.is_var_len = 1;
  166. add_char_params.char_props.indicate = true;
  167. add_char_params.char_props.write = true;
  168. add_char_params.cccd_write_access = cccd_write_access;
  169. add_char_params.is_defered_write = true;
  170. add_char_params.write_access = write_access;
  171. return characteristic_add(service_handle,
  172. &add_char_params,
  173. &p_ots_oacp->oacp_handles);
  174. }
  175. /**@brief Handling the OACP write procedure.
  176. *
  177. * @details The object is opened, and a l2cap transfer is started.
  178. *
  179. * @param[in] p_ots_oacp Pointer to the OACP structure.
  180. * @param[in] offset The offset for where the read should start.
  181. * @param[in] length The length of the read.
  182. */
  183. static inline ble_ots_oacp_res_code_t oacp_write_proc(ble_ots_oacp_t * p_ots_oacp,
  184. uint32_t offset,
  185. uint32_t length,
  186. uint8_t mode)
  187. {
  188. uint32_t err_code;
  189. if (p_ots_oacp->p_ots->p_current_object == NULL)
  190. {
  191. return BLE_OTS_OACP_RES_INV_OBJ;
  192. }
  193. if (p_ots_oacp->p_ots->p_current_object->is_valid == false)
  194. {
  195. return BLE_OTS_OACP_RES_INV_OBJ;
  196. }
  197. if (p_ots_oacp->p_ots->p_current_object->properties.decoded.is_write_permitted == false)
  198. {
  199. return BLE_OTS_OACP_RES_NOT_PERMITTED;
  200. }
  201. if (ble_ots_l2cap_is_channel_available(&p_ots_oacp->ots_l2cap) == false)
  202. {
  203. return BLE_OTS_OACP_RES_CHAN_UNAVAIL;
  204. }
  205. if (length + offset > p_ots_oacp->p_ots->p_current_object->alloc_len)
  206. {
  207. return BLE_OTS_OACP_RES_INV_PARAM;
  208. }
  209. if (p_ots_oacp->p_ots->p_current_object->is_locked)
  210. {
  211. return BLE_OTS_OACP_RES_OBJ_LOCKED;
  212. }
  213. err_code = ble_ots_l2cap_start_recv(&p_ots_oacp->ots_l2cap, length);
  214. if (err_code != NRF_SUCCESS)
  215. {
  216. return BLE_OTS_OACP_RES_OPER_FAILED;
  217. }
  218. ble_ots_evt_t ble_ots_evt;
  219. ble_ots_evt.type = BLE_OTS_EVT_OACP;
  220. ble_ots_evt.evt.oacp_evt.type = BLE_OTS_OACP_EVT_REQ_WRITE;
  221. ble_ots_evt.evt.oacp_evt.evt.p_object = p_ots_oacp->p_ots->p_current_object;
  222. p_ots_oacp->p_ots->p_current_object->current_size = length;
  223. p_ots_oacp->p_ots->evt_handler(p_ots_oacp->p_ots, &ble_ots_evt);
  224. return BLE_OTS_OACP_RES_SUCCESS;
  225. }
  226. /**@brief Handling the OACP read procedure.
  227. *
  228. * @details The object is opened, and a l2cap transfer is started.
  229. *
  230. * @param[in] p_ots_oacp Pointer to the OACP structure.
  231. * @param[in] offset The offset for where the read should start.
  232. * @param[in] length The length of the read.
  233. */
  234. static inline ble_ots_oacp_res_code_t oacp_read_proc(ble_ots_oacp_t * p_ots_oacp,
  235. uint32_t offset,
  236. uint32_t length)
  237. {
  238. if (p_ots_oacp->p_ots->p_current_object == NULL)
  239. {
  240. return BLE_OTS_OACP_RES_INV_OBJ;
  241. }
  242. if (p_ots_oacp->p_ots->p_current_object->is_valid == false)
  243. {
  244. return BLE_OTS_OACP_RES_INV_OBJ;
  245. }
  246. if (p_ots_oacp->p_ots->p_current_object->properties.decoded.is_read_permitted == false)
  247. {
  248. return BLE_OTS_OACP_RES_NOT_PERMITTED;
  249. }
  250. if (ble_ots_l2cap_is_channel_available(&p_ots_oacp->ots_l2cap) == false)
  251. {
  252. return BLE_OTS_OACP_RES_CHAN_UNAVAIL;
  253. }
  254. if (length + offset > p_ots_oacp->p_ots->p_current_object->current_size)
  255. {
  256. return BLE_OTS_OACP_RES_INV_PARAM;
  257. }
  258. if (p_ots_oacp->p_ots->p_current_object->is_locked)
  259. {
  260. return BLE_OTS_OACP_RES_OBJ_LOCKED;
  261. }
  262. ble_ots_evt_t ble_ots_evt;
  263. ble_ots_evt.type = BLE_OTS_EVT_OACP;
  264. ble_ots_evt.evt.oacp_evt.type = BLE_OTS_OACP_EVT_REQ_READ;
  265. ble_ots_evt.evt.oacp_evt.evt.p_object = p_ots_oacp->p_ots->p_current_object;
  266. p_ots_oacp->p_ots->evt_handler(p_ots_oacp->p_ots, &ble_ots_evt);
  267. ret_code_t err_code = ble_ots_l2cap_obj_send(&p_ots_oacp->ots_l2cap,
  268. p_ots_oacp->p_ots->p_current_object->data,
  269. p_ots_oacp->p_ots->p_current_object->current_size);
  270. if (err_code != NRF_SUCCESS)
  271. {
  272. NRF_LOG_ERROR("ble_ots_l2cap_obj_send returned error 0x%x", err_code);
  273. }
  274. return BLE_OTS_OACP_RES_SUCCESS;
  275. }
  276. /**@brief Handling the OACP abort procedure.
  277. *
  278. * @details The transmission is aborted.
  279. *
  280. * @param[in] p_ots_oacp Pointer to the OACP structure.
  281. */
  282. static inline ble_ots_oacp_res_code_t oacp_abort_proc(ble_ots_oacp_t * p_ots_oacp)
  283. {
  284. uint32_t err_code;
  285. err_code = ble_ots_l2cap_abort_transmission(&p_ots_oacp->ots_l2cap);
  286. if (err_code != NRF_SUCCESS)
  287. {
  288. return BLE_OTS_OACP_RES_OPER_FAILED;
  289. }
  290. p_ots_oacp->p_ots->p_current_object->is_locked = false;
  291. ble_ots_evt_t ble_ots_evt;
  292. ble_ots_evt.type = BLE_OTS_EVT_OACP;
  293. ble_ots_evt.evt.oacp_evt.type = BLE_OTS_OACP_EVT_ABORT;
  294. ble_ots_evt.evt.oacp_evt.evt.p_object = p_ots_oacp->p_ots->p_current_object;
  295. p_ots_oacp->p_ots->evt_handler(p_ots_oacp->p_ots, &ble_ots_evt);
  296. return BLE_OTS_OACP_RES_SUCCESS;
  297. }
  298. /**@brief Sending the oacp procedure response back to the client.
  299. *
  300. * @details Encodes and sends the response.
  301. *
  302. * @param[in] p_ots_oacp Pointer to the OACP structure.
  303. * @param[in] req_op_code The operation code of the procedure.
  304. * @param[in] result_code The result of the procedure.
  305. * @param[in] conn_handle The connection handle to send the result to.
  306. */
  307. static uint32_t ble_ots_oacp_response_send(ble_ots_oacp_t * p_ots_oacp,
  308. ble_ots_oacp_proc_type_t req_op_code,
  309. ble_ots_oacp_res_code_t result_code,
  310. uint16_t conn_handle)
  311. {
  312. uint16_t index = 0;
  313. uint8_t data[OACP_INDICATION_LEN];
  314. nrf_ble_gq_req_t ots_req;
  315. data[index++] = BLE_OTS_OACP_PROC_RESP;
  316. // Encode the Request Op code
  317. data[index++] = (uint8_t)req_op_code;
  318. // Encode the Result code.
  319. data[index++] = (uint8_t)result_code;
  320. memset(&ots_req, 0, sizeof(nrf_ble_gq_req_t));
  321. ots_req.type = NRF_BLE_GQ_REQ_GATTS_HVX;
  322. ots_req.error_handler.cb = gatt_error_handler;
  323. ots_req.error_handler.p_ctx = p_ots_oacp->p_ots;
  324. ots_req.params.gatts_hvx.type = BLE_GATT_HVX_INDICATION;
  325. ots_req.params.gatts_hvx.handle = p_ots_oacp->oacp_handles.value_handle;
  326. ots_req.params.gatts_hvx.offset = 0;
  327. ots_req.params.gatts_hvx.p_data = data;
  328. ots_req.params.gatts_hvx.p_len = &index;
  329. return nrf_ble_gq_item_add(p_ots_oacp->p_ots->p_gatt_queue,
  330. &ots_req,
  331. conn_handle);
  332. }
  333. /**@brief Decode an OACP command, and extract its data.
  334. *
  335. * @param[in] p_ble_write_evt The write event from BLE stack.
  336. * @param[out] p_proc The decoded OACP procedure is sent out.
  337. *
  338. * @return BLE_OTS_WRITE_SUCCESS If the filter was decoded correctly, else an error code.
  339. */
  340. static inline ble_ots_oacp_res_code_t decode_oacp_command(ble_gatts_evt_write_t const * p_ble_write_evt,
  341. ble_ots_oacp_proc_t * p_proc)
  342. {
  343. uint32_t index = 0;
  344. p_proc->type = (ble_ots_oacp_proc_type_t)p_ble_write_evt->data[index++];
  345. switch (p_proc->type)
  346. {
  347. case BLE_OTS_OACP_PROC_READ:
  348. if (p_ble_write_evt->len !=
  349. sizeof(p_proc->params.read_params.offset)
  350. + sizeof(p_proc->params.read_params.length)
  351. + index)
  352. {
  353. return BLE_OTS_OACP_RES_INV_PARAM;
  354. }
  355. /*lint --e{415} --e{416} -save suppress Warning 415: Likely access of out-of-bounds pointer */
  356. p_proc->params.read_params.offset = uint32_decode(&(p_ble_write_evt->data[index]));
  357. index += 4;
  358. p_proc->params.read_params.length = uint32_decode(&(p_ble_write_evt->data[index]));
  359. /*lint -restore*/
  360. break;
  361. //return BLE_OTS_OACP_RES_SUCCESS;
  362. case BLE_OTS_OACP_PROC_WRITE:
  363. p_proc->params.write_params.offset = uint32_decode(&(p_ble_write_evt->data[index]));
  364. index += sizeof(uint32_t);
  365. p_proc->params.write_params.length = uint32_decode(&(p_ble_write_evt->data[index]));
  366. index += sizeof(uint32_t);
  367. p_proc->params.write_params.write_mode = p_ble_write_evt->data[index];
  368. break;
  369. default:
  370. // No implementation needed
  371. break;
  372. }
  373. return BLE_OTS_OACP_RES_SUCCESS;
  374. }
  375. /**@brief Function for handling the BLE_GAP_EVT_DISCONNECTED event.
  376. *
  377. * @param[in] p_ots_oacp OTS OACP Structure.
  378. * @param[in] p_ble_evt Pointer to the event received from BLE stack.
  379. */
  380. static inline void on_disconnect(ble_ots_oacp_t * p_ots_oacp, ble_evt_t const * p_ble_evt)
  381. {
  382. uint32_t err_code;
  383. err_code = fds_gc();
  384. if (err_code != NRF_SUCCESS)
  385. {
  386. p_ots_oacp->p_ots->error_handler(err_code);
  387. }
  388. }
  389. /**@brief Function for handling the write events to the Blood Pressure Measurement characteristic.
  390. *
  391. * @param[in] p_bps Blood Pressure Service structure.
  392. * @param[in] p_evt_write Write event received from the BLE stack.
  393. */
  394. static void on_cccd_write(ble_ots_oacp_t * p_ots_oacp, ble_gatts_evt_write_t const * p_evt_write)
  395. {
  396. if (p_evt_write->len == 2)
  397. {
  398. // CCCD written, update indication state
  399. if (p_ots_oacp->p_ots->evt_handler != NULL)
  400. {
  401. ble_ots_evt_t evt;
  402. if (ble_srv_is_indication_enabled(p_evt_write->data))
  403. {
  404. evt.type = BLE_OTS_EVT_INDICATION_ENABLED;
  405. }
  406. else
  407. {
  408. evt.type = BLE_OTS_EVT_INDICATION_DISABLED;
  409. }
  410. p_ots_oacp->p_ots->evt_handler(p_ots_oacp->p_ots, &evt);
  411. }
  412. }
  413. }
  414. static void on_oacp_write(ble_ots_oacp_t * p_ots_oacp, ble_gatts_evt_write_t const * p_ble_evt_write)
  415. {
  416. ret_code_t err_code;
  417. ble_ots_oacp_res_code_t oacp_status;
  418. ble_ots_oacp_proc_t oacp_proc;
  419. ble_gatts_rw_authorize_reply_params_t auth_reply;
  420. memset(&auth_reply, 0, sizeof(auth_reply));
  421. auth_reply.type = BLE_GATTS_AUTHORIZE_TYPE_WRITE;
  422. auth_reply.params.write.offset = 0;
  423. auth_reply.params.write.len = 0;
  424. auth_reply.params.write.p_data = NULL;
  425. auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
  426. auth_reply.params.write.update = 1;
  427. if(is_cccd_configured(p_ots_oacp))
  428. {
  429. auth_reply.params.write.gatt_status = BLE_GATT_STATUS_SUCCESS;
  430. err_code = sd_ble_gatts_rw_authorize_reply(p_ots_oacp->p_ots->conn_handle, &auth_reply);
  431. if (err_code != NRF_SUCCESS && p_ots_oacp->p_ots->error_handler != NULL)
  432. {
  433. p_ots_oacp->p_ots->error_handler(err_code);
  434. }
  435. }
  436. else
  437. {
  438. NRF_LOG_DEBUG("OACD indications not enabled.");
  439. auth_reply.params.write.gatt_status = BLE_GATT_STATUS_ATTERR_CPS_CCCD_CONFIG_ERROR;
  440. err_code = sd_ble_gatts_rw_authorize_reply(p_ots_oacp->p_ots->conn_handle, &auth_reply);
  441. if (err_code != NRF_SUCCESS && p_ots_oacp->p_ots->error_handler != NULL)
  442. {
  443. p_ots_oacp->p_ots->error_handler(err_code);
  444. }
  445. return;
  446. }
  447. memset(&oacp_proc, 0, sizeof(oacp_proc));
  448. oacp_status = decode_oacp_command(p_ble_evt_write, &oacp_proc);
  449. if (oacp_status == BLE_OTS_OACP_RES_SUCCESS)
  450. {
  451. oacp_status = ble_ots_oacp_do_proc(p_ots_oacp, &oacp_proc);
  452. }
  453. err_code = ble_ots_oacp_response_send(p_ots_oacp,
  454. oacp_proc.type,
  455. oacp_status,
  456. p_ots_oacp->p_ots->conn_handle);
  457. if (err_code != NRF_SUCCESS)
  458. {
  459. p_ots_oacp->p_ots->error_handler(err_code);
  460. }
  461. }
  462. /**@brief Function for handling the Write event.
  463. *
  464. * @param[in] p_bps Blood Pressure Service structure.
  465. * @param[in] p_ble_evt Event received from the BLE stack.
  466. */
  467. static void on_write(ble_ots_oacp_t * p_ots_oacp, ble_evt_t const * p_ble_evt)
  468. {
  469. ble_gatts_evt_write_t const * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
  470. if (p_evt_write->handle == p_ots_oacp->p_ots->oacp_chars.oacp_handles.cccd_handle)
  471. {
  472. on_cccd_write(p_ots_oacp, p_evt_write);
  473. }
  474. }
  475. static void on_rw_authorize_request(ble_ots_oacp_t * p_ots_oacp, ble_gatts_evt_t const * p_gatts_evt)
  476. {
  477. ble_gatts_evt_rw_authorize_request_t const * p_auth_req =
  478. &p_gatts_evt->params.authorize_request;
  479. if (p_auth_req->type == BLE_GATTS_AUTHORIZE_TYPE_WRITE)
  480. {
  481. if ( (p_gatts_evt->params.authorize_request.request.write.op
  482. != BLE_GATTS_OP_PREP_WRITE_REQ)
  483. && (p_gatts_evt->params.authorize_request.request.write.op
  484. != BLE_GATTS_OP_EXEC_WRITE_REQ_NOW)
  485. && (p_gatts_evt->params.authorize_request.request.write.op
  486. != BLE_GATTS_OP_EXEC_WRITE_REQ_CANCEL)
  487. )
  488. {
  489. if (p_auth_req->request.write.handle == p_ots_oacp->p_ots->oacp_chars.oacp_handles.value_handle)
  490. {
  491. on_oacp_write(p_ots_oacp, &p_auth_req->request.write);
  492. }
  493. }
  494. }
  495. }
  496. void ble_ots_oacp_on_ble_evt(ble_ots_oacp_t * p_ots_oacp, ble_evt_t const * p_ble_evt)
  497. {
  498. if ((p_ots_oacp == NULL) || (p_ble_evt == NULL))
  499. {
  500. return;
  501. }
  502. ble_ots_l2cap_on_ble_evt(&p_ots_oacp->ots_l2cap, p_ble_evt);
  503. switch (p_ble_evt->header.evt_id)
  504. {
  505. case BLE_GAP_EVT_DISCONNECTED:
  506. on_disconnect(p_ots_oacp, p_ble_evt);
  507. break;
  508. case BLE_GATTS_EVT_WRITE:
  509. on_write(p_ots_oacp, p_ble_evt);
  510. break;
  511. case BLE_GATTS_EVT_RW_AUTHORIZE_REQUEST:
  512. on_rw_authorize_request(p_ots_oacp, &p_ble_evt->evt.gatts_evt);
  513. break;
  514. default:
  515. // No implementation needed.
  516. break;
  517. }
  518. }
  519. uint32_t ble_ots_oacp_init(ble_ots_oacp_t * p_ots_oacp, ble_ots_oacp_init_t * p_ots_oacp_init)
  520. {
  521. uint32_t err_code;
  522. if (p_ots_oacp == NULL || p_ots_oacp_init == NULL)
  523. {
  524. return NRF_ERROR_NULL;
  525. }
  526. p_ots_oacp->p_ots = p_ots_oacp_init->p_ots;
  527. p_ots_oacp->on_create_obj_properties_raw = p_ots_oacp_init->on_create_obj_properties_raw;
  528. ble_ots_l2cap_init_t l2cap_init;
  529. l2cap_init.p_ots_oacp = p_ots_oacp;
  530. l2cap_init.evt_handler = ots_l2cap_evt_handler;
  531. l2cap_init.p_transfer_buffer = p_ots_oacp_init->p_l2cap_buffer;
  532. l2cap_init.buffer_len = p_ots_oacp_init->l2cap_buffer_len;
  533. err_code = ble_ots_l2cap_init(&p_ots_oacp->ots_l2cap, &l2cap_init);
  534. if (err_code != NRF_SUCCESS)
  535. {
  536. return err_code;
  537. }
  538. return oacp_char_add(p_ots_oacp,
  539. p_ots_oacp->p_ots->service_handle,
  540. p_ots_oacp_init->write_access,
  541. p_ots_oacp_init->cccd_write_access);
  542. }
  543. ble_ots_oacp_res_code_t ble_ots_oacp_do_proc(ble_ots_oacp_t * p_ots_oacp,
  544. ble_ots_oacp_proc_t * p_oacp_proc)
  545. {
  546. if (p_ots_oacp == NULL || p_oacp_proc == NULL)
  547. {
  548. return BLE_OTS_OACP_RES_INV_PARAM;
  549. }
  550. ble_ots_oacp_res_code_t oacp_status;
  551. switch (p_oacp_proc->type)
  552. {
  553. case BLE_OTS_OACP_PROC_WRITE:
  554. oacp_status = oacp_write_proc(p_ots_oacp,
  555. p_oacp_proc->params.write_params.offset,
  556. p_oacp_proc->params.write_params.length,
  557. p_oacp_proc->params.write_params.write_mode);
  558. break;
  559. case BLE_OTS_OACP_PROC_READ:
  560. oacp_status = oacp_read_proc(p_ots_oacp,
  561. p_oacp_proc->params.read_params.offset,
  562. p_oacp_proc->params.read_params.length);
  563. break;
  564. case BLE_OTS_OACP_PROC_ABORT:
  565. oacp_status = oacp_abort_proc(p_ots_oacp);
  566. break;
  567. default:
  568. // Unsupported op code.
  569. oacp_status = BLE_OTS_OACP_RES_OPCODE_NOT_SUP;
  570. }
  571. return oacp_status;
  572. }