ble_conn_params.c 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /* Copyright (c) 2012 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 "ble_conn_params.h"
  13. #include <stdlib.h>
  14. #include "nordic_common.h"
  15. #include "ble_hci.h"
  16. #include "app_timer.h"
  17. #include "ble_srv_common.h"
  18. #include "app_util.h"
  19. static ble_conn_params_init_t m_conn_params_config; /**< Configuration as specified by the application. */
  20. static ble_gap_conn_params_t m_preferred_conn_params; /**< Connection parameters preferred by the application. */
  21. static uint8_t m_update_count; /**< Number of Connection Parameter Update messages that has currently been sent. */
  22. static uint16_t m_conn_handle; /**< Current connection handle. */
  23. static ble_gap_conn_params_t m_current_conn_params; /**< Connection parameters received in the most recent Connect event. */
  24. APP_TIMER_DEF(m_conn_params_timer_id); /**< Connection parameters timer. */
  25. static bool m_change_param = false;
  26. static bool is_conn_params_ok(ble_gap_conn_params_t * p_conn_params)
  27. {
  28. // Check if interval is within the acceptable range.
  29. // NOTE: Using max_conn_interval in the received event data because this contains
  30. // the client's connection interval.
  31. if (
  32. (p_conn_params->max_conn_interval >= m_preferred_conn_params.min_conn_interval)
  33. &&
  34. (p_conn_params->max_conn_interval <= m_preferred_conn_params.max_conn_interval)
  35. )
  36. {
  37. return true;
  38. }
  39. else
  40. {
  41. return false;
  42. }
  43. }
  44. static void update_timeout_handler(void * p_context)
  45. {
  46. UNUSED_PARAMETER(p_context);
  47. if (m_conn_handle != BLE_CONN_HANDLE_INVALID)
  48. {
  49. // Check if we have reached the maximum number of attempts
  50. m_update_count++;
  51. if (m_update_count <= m_conn_params_config.max_conn_params_update_count)
  52. {
  53. uint32_t err_code;
  54. // Parameters are not ok, send connection parameters update request.
  55. err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params);
  56. if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
  57. {
  58. m_conn_params_config.error_handler(err_code);
  59. }
  60. }
  61. else
  62. {
  63. m_update_count = 0;
  64. // Negotiation failed, disconnect automatically if this has been configured
  65. if (m_conn_params_config.disconnect_on_fail)
  66. {
  67. uint32_t err_code;
  68. err_code = sd_ble_gap_disconnect(m_conn_handle, BLE_HCI_CONN_INTERVAL_UNACCEPTABLE);
  69. if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
  70. {
  71. m_conn_params_config.error_handler(err_code);
  72. }
  73. }
  74. // Notify the application that the procedure has failed
  75. if (m_conn_params_config.evt_handler != NULL)
  76. {
  77. ble_conn_params_evt_t evt;
  78. evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
  79. m_conn_params_config.evt_handler(&evt);
  80. }
  81. }
  82. }
  83. }
  84. uint32_t ble_conn_params_init(const ble_conn_params_init_t * p_init)
  85. {
  86. uint32_t err_code;
  87. m_conn_params_config = *p_init;
  88. m_change_param = false;
  89. if (p_init->p_conn_params != NULL)
  90. {
  91. m_preferred_conn_params = *p_init->p_conn_params;
  92. // Set the connection params in stack
  93. err_code = sd_ble_gap_ppcp_set(&m_preferred_conn_params);
  94. if (err_code != NRF_SUCCESS)
  95. {
  96. return err_code;
  97. }
  98. }
  99. else
  100. {
  101. // Fetch the connection params from stack
  102. err_code = sd_ble_gap_ppcp_get(&m_preferred_conn_params);
  103. if (err_code != NRF_SUCCESS)
  104. {
  105. return err_code;
  106. }
  107. }
  108. m_conn_handle = BLE_CONN_HANDLE_INVALID;
  109. m_update_count = 0;
  110. return app_timer_create(&m_conn_params_timer_id,
  111. APP_TIMER_MODE_SINGLE_SHOT,
  112. update_timeout_handler);
  113. }
  114. uint32_t ble_conn_params_stop(void)
  115. {
  116. return app_timer_stop(m_conn_params_timer_id);
  117. }
  118. static void conn_params_negotiation(void)
  119. {
  120. // Start negotiation if the received connection parameters are not acceptable
  121. if (!is_conn_params_ok(&m_current_conn_params))
  122. {
  123. uint32_t err_code;
  124. uint32_t timeout_ticks;
  125. if (m_change_param)
  126. {
  127. // Notify the application that the procedure has failed
  128. if (m_conn_params_config.evt_handler != NULL)
  129. {
  130. ble_conn_params_evt_t evt;
  131. evt.evt_type = BLE_CONN_PARAMS_EVT_FAILED;
  132. m_conn_params_config.evt_handler(&evt);
  133. }
  134. }
  135. else
  136. {
  137. if (m_update_count == 0)
  138. {
  139. // First connection parameter update
  140. timeout_ticks = m_conn_params_config.first_conn_params_update_delay;
  141. }
  142. else
  143. {
  144. timeout_ticks = m_conn_params_config.next_conn_params_update_delay;
  145. }
  146. err_code = app_timer_start(m_conn_params_timer_id, timeout_ticks, NULL);
  147. if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
  148. {
  149. m_conn_params_config.error_handler(err_code);
  150. }
  151. }
  152. }
  153. else
  154. {
  155. // Notify the application that the procedure has succeded
  156. if (m_conn_params_config.evt_handler != NULL)
  157. {
  158. ble_conn_params_evt_t evt;
  159. evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
  160. m_conn_params_config.evt_handler(&evt);
  161. }
  162. }
  163. m_change_param = false;
  164. }
  165. static void on_connect(ble_evt_t * p_ble_evt)
  166. {
  167. // Save connection parameters
  168. m_conn_handle = p_ble_evt->evt.gap_evt.conn_handle;
  169. m_current_conn_params = p_ble_evt->evt.gap_evt.params.connected.conn_params;
  170. m_update_count = 0; // Connection parameter negotiation should re-start every connection
  171. // Check if we shall handle negotiation on connect
  172. if (m_conn_params_config.start_on_notify_cccd_handle == BLE_GATT_HANDLE_INVALID)
  173. {
  174. conn_params_negotiation();
  175. }
  176. }
  177. static void on_disconnect(ble_evt_t * p_ble_evt)
  178. {
  179. uint32_t err_code;
  180. m_conn_handle = BLE_CONN_HANDLE_INVALID;
  181. // Stop timer if running
  182. m_update_count = 0; // Connection parameters updates should happen during every connection
  183. err_code = app_timer_stop(m_conn_params_timer_id);
  184. if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
  185. {
  186. m_conn_params_config.error_handler(err_code);
  187. }
  188. }
  189. static void on_write(ble_evt_t * p_ble_evt)
  190. {
  191. ble_gatts_evt_write_t * p_evt_write = &p_ble_evt->evt.gatts_evt.params.write;
  192. // Check if this the correct CCCD
  193. if (
  194. (p_evt_write->handle == m_conn_params_config.start_on_notify_cccd_handle)
  195. &&
  196. (p_evt_write->len == 2)
  197. )
  198. {
  199. // Check if this is a 'start notification'
  200. if (ble_srv_is_notification_enabled(p_evt_write->data))
  201. {
  202. // Do connection parameter negotiation if necessary
  203. conn_params_negotiation();
  204. }
  205. else
  206. {
  207. uint32_t err_code;
  208. // Stop timer if running
  209. err_code = app_timer_stop(m_conn_params_timer_id);
  210. if ((err_code != NRF_SUCCESS) && (m_conn_params_config.error_handler != NULL))
  211. {
  212. m_conn_params_config.error_handler(err_code);
  213. }
  214. }
  215. }
  216. }
  217. static void on_conn_params_update(ble_evt_t * p_ble_evt)
  218. {
  219. // Copy the parameters
  220. m_current_conn_params = p_ble_evt->evt.gap_evt.params.conn_param_update.conn_params;
  221. conn_params_negotiation();
  222. }
  223. void ble_conn_params_on_ble_evt(ble_evt_t * p_ble_evt)
  224. {
  225. switch (p_ble_evt->header.evt_id)
  226. {
  227. case BLE_GAP_EVT_CONNECTED:
  228. on_connect(p_ble_evt);
  229. break;
  230. case BLE_GAP_EVT_DISCONNECTED:
  231. on_disconnect(p_ble_evt);
  232. break;
  233. case BLE_GATTS_EVT_WRITE:
  234. on_write(p_ble_evt);
  235. break;
  236. case BLE_GAP_EVT_CONN_PARAM_UPDATE:
  237. on_conn_params_update(p_ble_evt);
  238. break;
  239. default:
  240. // No implementation needed.
  241. break;
  242. }
  243. }
  244. uint32_t ble_conn_params_change_conn_params(ble_gap_conn_params_t * new_params)
  245. {
  246. uint32_t err_code;
  247. m_preferred_conn_params = *new_params;
  248. // Set the connection params in stack
  249. err_code = sd_ble_gap_ppcp_set(&m_preferred_conn_params);
  250. if (err_code == NRF_SUCCESS)
  251. {
  252. if (!is_conn_params_ok(&m_current_conn_params))
  253. {
  254. m_change_param = true;
  255. err_code = sd_ble_gap_conn_param_update(m_conn_handle, &m_preferred_conn_params);
  256. m_update_count = 1;
  257. }
  258. else
  259. {
  260. // Notify the application that the procedure has succeded
  261. if (m_conn_params_config.evt_handler != NULL)
  262. {
  263. ble_conn_params_evt_t evt;
  264. evt.evt_type = BLE_CONN_PARAMS_EVT_SUCCEEDED;
  265. m_conn_params_config.evt_handler(&evt);
  266. }
  267. err_code = NRF_SUCCESS;
  268. }
  269. }
  270. return err_code;
  271. }