es_adv_timing.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220
  1. /**
  2. * Copyright (c) 2016 - 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 "app_timer.h"
  41. #include "es_adv_timing.h"
  42. #include "es_adv_timing_resolver.h"
  43. #include "es_slot.h"
  44. APP_TIMER_DEF(m_es_adv_interval_timer); //!< Timer for advertising the set of slots.
  45. APP_TIMER_DEF(m_es_slot_timer); //!< Timer for advertising individual slots.
  46. static nrf_ble_escs_adv_interval_t m_current_adv_interval; //!< Current advertisement interval.
  47. static es_adv_timing_callback_t m_timing_mgr_callback; //!< Registered callback.
  48. static es_adv_timing_resolver_result_t m_adv_timing_result; //!< Current advertising timing result.
  49. static bool m_non_conn_adv_active; //!< Is the beacon advertising non-conn advertisements?
  50. /**@brief Function for invoking registered callback.
  51. *
  52. * @param[in] p_evt Event to issue to callback.
  53. */
  54. static void invoke_callback(const es_adv_timing_evt_t * p_evt)
  55. {
  56. if (m_timing_mgr_callback != NULL && m_non_conn_adv_active)
  57. {
  58. m_timing_mgr_callback(p_evt);
  59. }
  60. }
  61. #if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
  62. static bool frame_to_adv_is_tlm(const es_adv_timing_evt_t * p_evt)
  63. {
  64. const es_slot_reg_t * p_reg = es_slot_get_registry();
  65. return (p_reg->tlm_configured &&
  66. (p_evt->slot_no == p_reg->tlm_slot || p_evt->evt_id == ES_ADV_TIMING_EVT_ADV_ETLM));
  67. }
  68. static bool tlm_should_be_advertised(uint32_t adv_event_cnt)
  69. {
  70. return (adv_event_cnt % APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO) == 0;
  71. }
  72. #endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
  73. /**@brief Timeout handler for the advertisement slot timer. */
  74. static void adv_slot_timeout(void * p_context)
  75. {
  76. ret_code_t err_code;
  77. uint32_t active_slot_index = (uint32_t)p_context;
  78. es_adv_timing_evt_t evt;
  79. evt.slot_no = m_adv_timing_result.timing_results[active_slot_index].slot_no;
  80. evt.evt_id = m_adv_timing_result.timing_results[active_slot_index].is_etlm
  81. ? ES_ADV_TIMING_EVT_ADV_ETLM
  82. : ES_ADV_TIMING_EVT_ADV_SLOT;
  83. // Trigger an event for the next slot if this slot is not the last to be advertised in this event.
  84. // Note: since we check 'm_adv_timing_result.len_timing_results > 1' we can safely cast the result of
  85. // the subtraction to a uint32.
  86. if (m_non_conn_adv_active && \
  87. m_adv_timing_result.len_timing_results > 1 && \
  88. active_slot_index < (uint32_t)(m_adv_timing_result.len_timing_results - 1))
  89. {
  90. err_code = app_timer_start( m_es_slot_timer,
  91. APP_TIMER_TICKS(m_adv_timing_result.timing_results[active_slot_index].delay_ms),
  92. (void*)(active_slot_index + 1));
  93. APP_ERROR_CHECK(err_code);
  94. }
  95. #if APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
  96. static uint32_t adv_event_cnt = 0;
  97. if (active_slot_index == 0)
  98. {
  99. adv_event_cnt++;
  100. }
  101. if (frame_to_adv_is_tlm(&evt) && !tlm_should_be_advertised(adv_event_cnt))
  102. {
  103. return;
  104. }
  105. #endif // APP_CONFIG_TLM_ADV_INTERLEAVE_RATIO > 1
  106. invoke_callback(&evt);
  107. }
  108. /**@brief Timeout handler for the advertisement interval timer. */
  109. static void adv_interval_timeout(void * p_context)
  110. {
  111. if (es_slot_get_registry()->num_configured_slots > 0)
  112. {
  113. // Trigger slot timeout for advertising the first slot.
  114. // Note: The slot number is not the index in the slot registry, it is the index of the active slots.
  115. adv_slot_timeout(NULL);
  116. }
  117. if (m_non_conn_adv_active)
  118. {
  119. uint32_t err_code = app_timer_start(m_es_adv_interval_timer,
  120. APP_TIMER_TICKS(m_current_adv_interval),
  121. NULL);
  122. APP_ERROR_CHECK(err_code);
  123. }
  124. }
  125. void es_adv_timing_timers_init(void)
  126. {
  127. ret_code_t err_code;
  128. err_code = app_timer_create(&m_es_adv_interval_timer,
  129. APP_TIMER_MODE_SINGLE_SHOT,
  130. adv_interval_timeout);
  131. APP_ERROR_CHECK(err_code);
  132. err_code = app_timer_create(&m_es_slot_timer,
  133. APP_TIMER_MODE_SINGLE_SHOT,
  134. adv_slot_timeout);
  135. APP_ERROR_CHECK(err_code);
  136. }
  137. /**@brief Function for finding and setting advertisement timing configuration. */
  138. static void adv_timing_set(void)
  139. {
  140. ret_code_t err_code;
  141. const es_slot_reg_t * p_reg = es_slot_get_registry();
  142. es_adv_timing_resolver_input_t resolver_input = {
  143. .adv_interval = m_current_adv_interval,
  144. .p_result = &m_adv_timing_result,
  145. .num_slots_configured = p_reg->num_configured_slots,
  146. .p_slots_configured = p_reg->slots_configured,
  147. .num_eid_slots_configured = p_reg->num_configured_eid_slots,
  148. .p_eid_slots_configured = p_reg->eid_slots_configured,
  149. .tlm_configured = p_reg->tlm_configured,
  150. .tlm_slot = p_reg->tlm_slot};
  151. err_code = es_adv_timing_resolve(&resolver_input);
  152. APP_ERROR_CHECK(err_code);
  153. }
  154. void es_adv_timing_start(uint16_t adv_interval)
  155. {
  156. ret_code_t err_code;
  157. const es_slot_reg_t * p_reg = es_slot_get_registry();
  158. m_non_conn_adv_active = true;
  159. if (p_reg->num_configured_slots > 0)
  160. {
  161. m_current_adv_interval = adv_interval;
  162. err_code = app_timer_start(m_es_adv_interval_timer,
  163. APP_TIMER_TICKS(m_current_adv_interval),
  164. NULL);
  165. APP_ERROR_CHECK(err_code);
  166. adv_timing_set();
  167. }
  168. }
  169. void es_adv_timing_stop(void)
  170. {
  171. m_non_conn_adv_active = false; // Stops timers from being re-fired.
  172. }
  173. void es_adv_timing_init(es_adv_timing_callback_t p_handler)
  174. {
  175. m_non_conn_adv_active = false;
  176. m_timing_mgr_callback = p_handler;
  177. memset(&m_adv_timing_result, 0, sizeof(m_adv_timing_result));
  178. }