multi_rtimer.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301
  1. /*!
  2. * \file multi_rtimer.c
  3. *
  4. * \brief Timer objects and scheduling management implementation
  5. *
  6. * \copyright Revised BSD License, see section \ref LICENSE.
  7. *
  8. * \code
  9. * ______ _
  10. * / _____) _ | |
  11. * ( (____ _____ ____ _| |_ _____ ____| |__
  12. * \____ \| ___ | (_ _) ___ |/ ___) _ \
  13. * _____) ) ____| | | || |_| ____( (___| | | |
  14. * (______/|_____)_|_|_| \__)_____)\____)_| |_|
  15. * (C)2013-2017 Semtech
  16. *
  17. * \endcode
  18. *
  19. * \author Miguel Luis ( Semtech )
  20. *
  21. * \author Gregory Cristian ( Semtech )
  22. *
  23. * \author Forest-Rain
  24. */
  25. #include <rthw.h>
  26. #include <rtdevice.h>
  27. #include <rtthread.h>
  28. #include "board.h"
  29. #include "hw_rtc_stm32l.h"
  30. #include "multi_rtimer.h"
  31. /*!
  32. * Safely execute call back
  33. */
  34. #define EXECUTE_CALLBACK( _callback_ ) \
  35. do \
  36. { \
  37. if( _callback_ == NULL ) \
  38. { \
  39. while( 1 ); \
  40. } \
  41. else \
  42. { \
  43. _callback_( ); \
  44. } \
  45. }while( 0 );
  46. /*!
  47. * Timers list head pointer
  48. */
  49. static timer_event_t *timer_list_head = NULL;
  50. /*!
  51. * \brief Sets a timeout with the duration "timestamp"
  52. *
  53. * \param [IN] timestamp Delay duration
  54. */
  55. static void rtimer_set_timeout( timer_event_t *obj );
  56. /*!
  57. * \brief Check if the Object to be added is not already in the list
  58. *
  59. * \param [IN] timestamp Delay duration
  60. * \retval true (the object is already in the list) or false
  61. */
  62. static bool rtimer_exists( timer_event_t *obj );
  63. void rtimer_init( timer_event_t *obj, void ( *callback )( void ) )
  64. {
  65. obj->Timestamp = 0;
  66. obj->ReloadValue = 0;
  67. obj->IsStarted = false;
  68. obj->IsNext2Expire = false;
  69. obj->Callback = callback;
  70. obj->Context = NULL;
  71. obj->Next = NULL;
  72. }
  73. static void rtimer_reload(void)
  74. {
  75. // Start the next timer_list_head if it exists AND NOT running
  76. if( ( timer_list_head != NULL ) && ( timer_list_head->IsNext2Expire == false ) )
  77. {
  78. rtimer_set_timeout( timer_list_head );
  79. }
  80. }
  81. void rtimer_start( timer_event_t *obj )
  82. {
  83. uint32_t elapsedTime = 0;
  84. timer_event_t **target = &timer_list_head;
  85. CRITICAL_SECTION_BEGIN( );
  86. if( ( obj == NULL ) || ( rtimer_exists( obj ) == true ) )
  87. {
  88. CRITICAL_SECTION_END( );
  89. return;
  90. }
  91. obj->Timestamp = obj->ReloadValue;
  92. obj->IsStarted = true;
  93. obj->IsNext2Expire = false;
  94. obj->Next = NULL;
  95. // The timer list is automatically sorted. The timer list head always contains the next timer to expire.
  96. if( timer_list_head == NULL )
  97. {
  98. rtc_set_timer_context( );
  99. }
  100. else
  101. {
  102. elapsedTime = rtc_get_timer_elapsed_time( );
  103. obj->Timestamp += elapsedTime;
  104. for(; *target; target = &((*target)->Next) )
  105. {
  106. if(((*target)->Timestamp > obj->Timestamp))
  107. {
  108. (*target)->IsNext2Expire = false;
  109. obj->Next = *target;
  110. break;
  111. }
  112. }
  113. }
  114. *target = obj;
  115. // Start the next timer_list_head if it exists AND NOT running
  116. rtimer_reload();
  117. CRITICAL_SECTION_END( );
  118. }
  119. void rtimer_stop( timer_event_t *obj )
  120. {
  121. CRITICAL_SECTION_BEGIN( );
  122. timer_event_t **target = &timer_list_head;
  123. // List is empty or the obj to stop does not exist
  124. if( ( timer_list_head == NULL ) || ( obj == NULL ) )
  125. {
  126. CRITICAL_SECTION_END( );
  127. return;
  128. }
  129. obj->IsStarted = false;
  130. // Stop the Head and RTC Timeout
  131. if( timer_list_head == obj )
  132. {
  133. // The head is already running
  134. if( timer_list_head->IsNext2Expire == true )
  135. {
  136. timer_list_head->IsNext2Expire = false;
  137. if( timer_list_head->Next != NULL )
  138. {
  139. timer_list_head = timer_list_head->Next;
  140. rtimer_set_timeout( timer_list_head );
  141. }
  142. else
  143. {
  144. rtc_stop_alarm( );
  145. timer_list_head = NULL;
  146. }
  147. CRITICAL_SECTION_END( );
  148. return;
  149. }
  150. }
  151. // Stop an object within the list
  152. for(; *target; target = &((*target)->Next) )
  153. {
  154. if( *target == obj )
  155. {
  156. *target = obj->Next;
  157. break;
  158. }
  159. }
  160. CRITICAL_SECTION_END( );
  161. }
  162. static bool rtimer_exists( timer_event_t *obj )
  163. {
  164. timer_event_t* cur = timer_list_head;
  165. while( cur != NULL )
  166. {
  167. if( cur == obj )
  168. {
  169. return true;
  170. }
  171. cur = cur->Next;
  172. }
  173. return false;
  174. }
  175. void rtimer_reset( timer_event_t *obj )
  176. {
  177. rtimer_stop( obj );
  178. rtimer_start( obj );
  179. }
  180. void rtimer_set_value( timer_event_t *obj, uint32_t value )
  181. {
  182. uint32_t minValue = 0;
  183. uint32_t ticks = rtc_ms2tick( value );
  184. rtimer_stop( obj );
  185. minValue = rtc_get_minimum_timeout( );
  186. if( ticks < minValue )
  187. {
  188. ticks = minValue;
  189. }
  190. obj->Timestamp = ticks;
  191. obj->ReloadValue = ticks;
  192. }
  193. TimerTime_t rtimer_get_current_time( void )
  194. {
  195. uint32_t now = rtc_get_timer_value( );
  196. return rtc_tick2ms( now );
  197. }
  198. static void rtimer_set_timeout( timer_event_t *obj )
  199. {
  200. int32_t minTicks= rtc_get_minimum_timeout( );
  201. obj->IsNext2Expire = true;
  202. // In case deadline too soon
  203. if( obj->Timestamp < ( rtc_get_timer_elapsed_time( ) + minTicks ) )
  204. {
  205. obj->Timestamp = rtc_get_timer_elapsed_time( ) + minTicks;
  206. }
  207. rtc_set_alarm( obj->Timestamp );
  208. }
  209. void rtimer_irq_handler( void )
  210. {
  211. timer_event_t** target = &timer_list_head;
  212. timer_event_t* cur;
  213. uint32_t old = rtc_get_timer_context( );
  214. uint32_t now = rtc_set_timer_context( );
  215. // intentional wrap around
  216. uint32_t deltaContext = now - old;
  217. // Update timeStamp based upon new Time Reference
  218. // because delta context should never exceed 2^32
  219. if( timer_list_head != NULL )
  220. {
  221. for(; (*target)->Next; target = &((*target)->Next) )
  222. {
  223. if( (*target)->Next->Timestamp > deltaContext )
  224. {
  225. (*target)->Next->Timestamp -= deltaContext;
  226. }
  227. else
  228. {
  229. (*target)->Next->Timestamp = 0;
  230. }
  231. }
  232. // Execute immediately the alarm callback
  233. cur = timer_list_head;
  234. timer_list_head = timer_list_head->Next;
  235. cur->IsStarted = false;
  236. EXECUTE_CALLBACK( cur->Callback );
  237. }
  238. // Remove all the expired object from the list
  239. while( ( timer_list_head != NULL ) && ( timer_list_head->Timestamp < rtc_get_timer_elapsed_time( ) ) )
  240. {
  241. cur = timer_list_head;
  242. timer_list_head = timer_list_head->Next;
  243. cur->IsStarted = false;
  244. EXECUTE_CALLBACK( cur->Callback );
  245. }
  246. // Start the next timer_list_head if it exists AND NOT running
  247. rtimer_reload();
  248. }
  249. TimerTime_t rtimer_temp_compensation( TimerTime_t period, float temperature )
  250. {
  251. return rtc_temp_compensation( period, temperature );
  252. }
  253. void rtimer_process( void )
  254. {
  255. rtc_process( );
  256. }