timer.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  1. /*
  2. / _____) _ | |
  3. ( (____ _____ ____ _| |_ _____ ____| |__
  4. \____ \| ___ | (_ _) ___ |/ ___) _ \
  5. _____) ) ____| | | || |_| ____( (___| | | |
  6. (______/|_____)_|_|_| \__)_____)\____)_| |_|
  7. (C)2013 Semtech
  8. Description: Timer objects and scheduling management
  9. License: Revised BSD License, see LICENSE.TXT file include in the project
  10. Maintainer: Miguel Luis and Gregory Cristian
  11. */
  12. #include "board.h"
  13. #include "rtc-board.h"
  14. #include "timer-board.h"
  15. static bool LowPowerModeEnable = true;
  16. /*!
  17. * This flag is used to make sure we have looped through the main several time to avoid race issues
  18. */
  19. volatile uint8_t HasLoopedThroughMain = 0;
  20. /*!
  21. * Timers list head pointer
  22. */
  23. static TimerEvent_t *TimerListHead = NULL;
  24. /*!
  25. * \brief Adds or replace the head timer of the list.
  26. *
  27. * \remark The list is automatically sorted. The list head always contains the
  28. * next timer to expire.
  29. *
  30. * \param [IN] obj Timer object to be become the new head
  31. * \param [IN] remainingTime Remaining time of the previous head to be replaced
  32. */
  33. static void TimerInsertNewHeadTimer( TimerEvent_t *obj, uint32_t remainingTime );
  34. /*!
  35. * \brief Adds a timer to the list.
  36. *
  37. * \remark The list is automatically sorted. The list head always contains the
  38. * next timer to expire.
  39. *
  40. * \param [IN] obj Timer object to be added to the list
  41. * \param [IN] remainingTime Remaining time of the running head after which the object may be added
  42. */
  43. static void TimerInsertTimer( TimerEvent_t *obj, uint32_t remainingTime );
  44. /*!
  45. * \brief Sets a timeout with the duration "timestamp"
  46. *
  47. * \param [IN] timestamp Delay duration
  48. */
  49. static void TimerSetTimeout( TimerEvent_t *obj );
  50. /*!
  51. * \brief Check if the Object to be added is not already in the list
  52. *
  53. * \param [IN] timestamp Delay duration
  54. * \retval true (the object is already in the list) or false
  55. */
  56. static bool TimerExists( TimerEvent_t *obj );
  57. /*!
  58. * \brief Read the timer value of the currently running timer
  59. *
  60. * \retval value current timer value
  61. */
  62. uint32_t TimerGetValue( void );
  63. void TimerSetLowPowerEnable( bool enable )
  64. {
  65. LowPowerModeEnable = enable;
  66. }
  67. bool TimerGetLowPowerEnable( void )
  68. {
  69. return LowPowerModeEnable;
  70. }
  71. void TimerInit( TimerEvent_t *obj, void ( *callback )( void ) )
  72. {
  73. obj->Timestamp = 0;
  74. obj->ReloadValue = 0;
  75. obj->IsRunning = false;
  76. obj->Callback = callback;
  77. obj->Next = NULL;
  78. }
  79. void TimerStart( TimerEvent_t *obj )
  80. {
  81. uint32_t elapsedTime = 0;
  82. uint32_t remainingTime = 0;
  83. __disable_irq( );
  84. if( ( obj == NULL ) || ( TimerExists( obj ) == true ) )
  85. {
  86. __enable_irq( );
  87. return;
  88. }
  89. obj->Timestamp = obj->ReloadValue;
  90. obj->IsRunning = false;
  91. if( TimerListHead == NULL )
  92. {
  93. TimerInsertNewHeadTimer( obj, obj->Timestamp );
  94. }
  95. else
  96. {
  97. if( TimerListHead->IsRunning == true )
  98. {
  99. elapsedTime = TimerGetValue( );
  100. if( elapsedTime > TimerListHead->Timestamp )
  101. {
  102. elapsedTime = TimerListHead->Timestamp; // security but should never occur
  103. }
  104. remainingTime = TimerListHead->Timestamp - elapsedTime;
  105. }
  106. else
  107. {
  108. remainingTime = TimerListHead->Timestamp;
  109. }
  110. if( obj->Timestamp < remainingTime )
  111. {
  112. TimerInsertNewHeadTimer( obj, remainingTime );
  113. }
  114. else
  115. {
  116. TimerInsertTimer( obj, remainingTime );
  117. }
  118. }
  119. __enable_irq( );
  120. }
  121. static void TimerInsertTimer( TimerEvent_t *obj, uint32_t remainingTime )
  122. {
  123. uint32_t aggregatedTimestamp = 0; // hold the sum of timestamps
  124. uint32_t aggregatedTimestampNext = 0; // hold the sum of timestamps up to the next event
  125. TimerEvent_t* prev = TimerListHead;
  126. TimerEvent_t* cur = TimerListHead->Next;
  127. if( cur == NULL )
  128. { // obj comes just after the head
  129. obj->Timestamp -= remainingTime;
  130. prev->Next = obj;
  131. obj->Next = NULL;
  132. }
  133. else
  134. {
  135. aggregatedTimestamp = remainingTime;
  136. aggregatedTimestampNext = remainingTime + cur->Timestamp;
  137. while( prev != NULL )
  138. {
  139. if( aggregatedTimestampNext > obj->Timestamp )
  140. {
  141. obj->Timestamp -= aggregatedTimestamp;
  142. if( cur != NULL )
  143. {
  144. cur->Timestamp -= obj->Timestamp;
  145. }
  146. prev->Next = obj;
  147. obj->Next = cur;
  148. break;
  149. }
  150. else
  151. {
  152. prev = cur;
  153. cur = cur->Next;
  154. if( cur == NULL )
  155. { // obj comes at the end of the list
  156. aggregatedTimestamp = aggregatedTimestampNext;
  157. obj->Timestamp -= aggregatedTimestamp;
  158. prev->Next = obj;
  159. obj->Next = NULL;
  160. break;
  161. }
  162. else
  163. {
  164. aggregatedTimestamp = aggregatedTimestampNext;
  165. aggregatedTimestampNext = aggregatedTimestampNext + cur->Timestamp;
  166. }
  167. }
  168. }
  169. }
  170. }
  171. static void TimerInsertNewHeadTimer( TimerEvent_t *obj, uint32_t remainingTime )
  172. {
  173. TimerEvent_t* cur = TimerListHead;
  174. if( cur != NULL )
  175. {
  176. cur->Timestamp = remainingTime - obj->Timestamp;
  177. cur->IsRunning = false;
  178. }
  179. obj->Next = cur;
  180. obj->IsRunning = true;
  181. TimerListHead = obj;
  182. TimerSetTimeout( TimerListHead );
  183. }
  184. void TimerIrqHandler( void )
  185. {
  186. uint32_t elapsedTime = 0;
  187. if( LowPowerModeEnable == false )
  188. {
  189. if( TimerListHead == NULL )
  190. {
  191. return; // Only necessary when the standard timer is used as a time base
  192. }
  193. }
  194. elapsedTime = TimerGetValue( );
  195. if( elapsedTime > TimerListHead->Timestamp )
  196. {
  197. TimerListHead->Timestamp = 0;
  198. }
  199. else
  200. {
  201. TimerListHead->Timestamp -= elapsedTime;
  202. }
  203. while( ( TimerListHead != NULL ) && ( TimerListHead->Timestamp == 0 ) )
  204. {
  205. TimerEvent_t* elapsedTimer = TimerListHead;
  206. TimerListHead = TimerListHead->Next;
  207. if( elapsedTimer->Callback != NULL )
  208. {
  209. elapsedTimer->Callback( );
  210. }
  211. }
  212. // start the next TimerListHead if it exists
  213. if( TimerListHead != NULL )
  214. {
  215. TimerListHead->IsRunning = true;
  216. TimerSetTimeout( TimerListHead );
  217. }
  218. }
  219. void TimerStop( TimerEvent_t *obj )
  220. {
  221. __disable_irq( );
  222. uint32_t elapsedTime = 0;
  223. uint32_t remainingTime = 0;
  224. TimerEvent_t* prev = TimerListHead;
  225. TimerEvent_t* cur = TimerListHead;
  226. // List is empty or the Obj to stop does not exist
  227. if( ( TimerListHead == NULL ) || ( obj == NULL ) )
  228. {
  229. __enable_irq( );
  230. return;
  231. }
  232. if( TimerListHead == obj ) // Stop the Head
  233. {
  234. if( TimerListHead->IsRunning == true ) // The head is already running
  235. {
  236. elapsedTime = TimerGetValue( );
  237. if( elapsedTime > obj->Timestamp )
  238. {
  239. elapsedTime = obj->Timestamp;
  240. }
  241. remainingTime = obj->Timestamp - elapsedTime;
  242. if( TimerListHead->Next != NULL )
  243. {
  244. TimerListHead->IsRunning = false;
  245. TimerListHead = TimerListHead->Next;
  246. TimerListHead->Timestamp += remainingTime;
  247. TimerListHead->IsRunning = true;
  248. TimerSetTimeout( TimerListHead );
  249. }
  250. else
  251. {
  252. TimerListHead = NULL;
  253. }
  254. }
  255. else // Stop the head before it is started
  256. {
  257. if( TimerListHead->Next != NULL )
  258. {
  259. remainingTime = obj->Timestamp;
  260. TimerListHead = TimerListHead->Next;
  261. TimerListHead->Timestamp += remainingTime;
  262. }
  263. else
  264. {
  265. TimerListHead = NULL;
  266. }
  267. }
  268. }
  269. else // Stop an object within the list
  270. {
  271. remainingTime = obj->Timestamp;
  272. while( cur != NULL )
  273. {
  274. if( cur == obj )
  275. {
  276. if( cur->Next != NULL )
  277. {
  278. cur = cur->Next;
  279. prev->Next = cur;
  280. cur->Timestamp += remainingTime;
  281. }
  282. else
  283. {
  284. cur = NULL;
  285. prev->Next = cur;
  286. }
  287. break;
  288. }
  289. else
  290. {
  291. prev = cur;
  292. cur = cur->Next;
  293. }
  294. }
  295. }
  296. __enable_irq( );
  297. }
  298. static bool TimerExists( TimerEvent_t *obj )
  299. {
  300. TimerEvent_t* cur = TimerListHead;
  301. while( cur != NULL )
  302. {
  303. if( cur == obj )
  304. {
  305. return true;
  306. }
  307. cur = cur->Next;
  308. }
  309. return false;
  310. }
  311. void TimerReset( TimerEvent_t *obj )
  312. {
  313. TimerStop( obj );
  314. TimerStart( obj );
  315. }
  316. void TimerSetValue( TimerEvent_t *obj, uint32_t value )
  317. {
  318. uint32_t minValue = 0;
  319. TimerStop( obj );
  320. if( LowPowerModeEnable == true )
  321. {
  322. minValue = RtcGetMinimumTimeout( );
  323. }
  324. else
  325. {
  326. minValue = TimerHwGetMinimumTimeout( );
  327. }
  328. if( value < minValue )
  329. {
  330. value = minValue;
  331. }
  332. obj->Timestamp = value;
  333. obj->ReloadValue = value;
  334. }
  335. uint32_t TimerGetValue( void )
  336. {
  337. if( LowPowerModeEnable == true )
  338. {
  339. return RtcGetTimerElapsedTime( );
  340. }
  341. else
  342. {
  343. return TimerHwGetElapsedTime( );
  344. }
  345. }
  346. TimerTime_t TimerGetCurrentTime( void )
  347. {
  348. if( LowPowerModeEnable == true )
  349. {
  350. return RtcGetTimerValue( );
  351. }
  352. else
  353. {
  354. return TimerHwGetTime( );
  355. }
  356. }
  357. static void TimerSetTimeout( TimerEvent_t *obj )
  358. {
  359. HasLoopedThroughMain = 0;
  360. if( LowPowerModeEnable == true )
  361. {
  362. RtcSetTimeout( obj->Timestamp );
  363. }
  364. else
  365. {
  366. TimerHwStart( obj->Timestamp );
  367. }
  368. }
  369. void TimerLowPowerHandler( void )
  370. {
  371. if( ( TimerListHead != NULL ) && ( TimerListHead->IsRunning == true ) )
  372. {
  373. if( HasLoopedThroughMain < 5 )
  374. {
  375. HasLoopedThroughMain++;
  376. }
  377. else
  378. {
  379. HasLoopedThroughMain = 0;
  380. if( LowPowerModeEnable == true )
  381. {
  382. RtcEnterLowPowerStopMode( );
  383. }
  384. else
  385. {
  386. TimerHwEnterLowPowerStopMode( );
  387. }
  388. }
  389. }
  390. }