Implement a secure ICS protocol targeting LoRa Node151 microcontroller for controlling irrigation.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

387 lines
9.2 KiB

  1. /*!
  2. * \file timer.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. #include "utilities.h"
  24. #include "board.h"
  25. #include "rtc-board.h"
  26. #include "timer.h"
  27. /*!
  28. * Safely execute call back
  29. */
  30. #define ExecuteCallBack( _callback_, context ) \
  31. do \
  32. { \
  33. if( _callback_ == NULL ) \
  34. { \
  35. while( 1 ); \
  36. } \
  37. else \
  38. { \
  39. _callback_( context ); \
  40. } \
  41. }while( 0 );
  42. /*!
  43. * Timers list head pointer
  44. */
  45. static TimerEvent_t *TimerListHead = NULL;
  46. /*!
  47. * \brief Adds or replace the head timer of the list.
  48. *
  49. * \remark The list is automatically sorted. The list head always contains the
  50. * next timer to expire.
  51. *
  52. * \param [IN] obj Timer object to be become the new head
  53. * \param [IN] remainingTime Remaining time of the previous head to be replaced
  54. */
  55. static void TimerInsertNewHeadTimer( TimerEvent_t *obj );
  56. /*!
  57. * \brief Adds a timer to the list.
  58. *
  59. * \remark The list is automatically sorted. The list head always contains the
  60. * next timer to expire.
  61. *
  62. * \param [IN] obj Timer object to be added to the list
  63. * \param [IN] remainingTime Remaining time of the running head after which the object may be added
  64. */
  65. static void TimerInsertTimer( TimerEvent_t *obj );
  66. /*!
  67. * \brief Sets a timeout with the duration "timestamp"
  68. *
  69. * \param [IN] timestamp Delay duration
  70. */
  71. static void TimerSetTimeout( TimerEvent_t *obj );
  72. /*!
  73. * \brief Check if the Object to be added is not already in the list
  74. *
  75. * \param [IN] timestamp Delay duration
  76. * \retval true (the object is already in the list) or false
  77. */
  78. static bool TimerExists( TimerEvent_t *obj );
  79. void TimerInit( TimerEvent_t *obj, void ( *callback )( void *context ) )
  80. {
  81. obj->Timestamp = 0;
  82. obj->ReloadValue = 0;
  83. obj->IsStarted = false;
  84. obj->IsNext2Expire = false;
  85. obj->Callback = callback;
  86. obj->Context = NULL;
  87. obj->Next = NULL;
  88. }
  89. void TimerSetContext( TimerEvent_t *obj, void* context )
  90. {
  91. obj->Context = context;
  92. }
  93. void TimerStart( TimerEvent_t *obj )
  94. {
  95. uint32_t elapsedTime = 0;
  96. CRITICAL_SECTION_BEGIN( );
  97. if( ( obj == NULL ) || ( TimerExists( obj ) == true ) )
  98. {
  99. CRITICAL_SECTION_END( );
  100. return;
  101. }
  102. obj->Timestamp = obj->ReloadValue;
  103. obj->IsStarted = true;
  104. obj->IsNext2Expire = false;
  105. if( TimerListHead == NULL )
  106. {
  107. RtcSetTimerContext( );
  108. // Inserts a timer at time now + obj->Timestamp
  109. TimerInsertNewHeadTimer( obj );
  110. }
  111. else
  112. {
  113. elapsedTime = RtcGetTimerElapsedTime( );
  114. obj->Timestamp += elapsedTime;
  115. if( obj->Timestamp < TimerListHead->Timestamp )
  116. {
  117. TimerInsertNewHeadTimer( obj );
  118. }
  119. else
  120. {
  121. TimerInsertTimer( obj );
  122. }
  123. }
  124. CRITICAL_SECTION_END( );
  125. }
  126. static void TimerInsertTimer( TimerEvent_t *obj )
  127. {
  128. TimerEvent_t* cur = TimerListHead;
  129. TimerEvent_t* next = TimerListHead->Next;
  130. while( cur->Next != NULL )
  131. {
  132. if( obj->Timestamp > next->Timestamp )
  133. {
  134. cur = next;
  135. next = next->Next;
  136. }
  137. else
  138. {
  139. cur->Next = obj;
  140. obj->Next = next;
  141. return;
  142. }
  143. }
  144. cur->Next = obj;
  145. obj->Next = NULL;
  146. }
  147. static void TimerInsertNewHeadTimer( TimerEvent_t *obj )
  148. {
  149. TimerEvent_t* cur = TimerListHead;
  150. if( cur != NULL )
  151. {
  152. cur->IsNext2Expire = false;
  153. }
  154. obj->Next = cur;
  155. TimerListHead = obj;
  156. TimerSetTimeout( TimerListHead );
  157. }
  158. bool TimerIsStarted( TimerEvent_t *obj )
  159. {
  160. return obj->IsStarted;
  161. }
  162. void TimerIrqHandler( void )
  163. {
  164. TimerEvent_t* cur;
  165. TimerEvent_t* next;
  166. uint32_t old = RtcGetTimerContext( );
  167. uint32_t now = RtcSetTimerContext( );
  168. uint32_t deltaContext = now - old; // intentional wrap around
  169. // Update timeStamp based upon new Time Reference
  170. // because delta context should never exceed 2^32
  171. if( TimerListHead != NULL )
  172. {
  173. for( cur = TimerListHead; cur->Next != NULL; cur = cur->Next )
  174. {
  175. next = cur->Next;
  176. if( next->Timestamp > deltaContext )
  177. {
  178. next->Timestamp -= deltaContext;
  179. }
  180. else
  181. {
  182. next->Timestamp = 0;
  183. }
  184. }
  185. }
  186. // Execute immediately the alarm callback
  187. if ( TimerListHead != NULL )
  188. {
  189. cur = TimerListHead;
  190. TimerListHead = TimerListHead->Next;
  191. cur->IsStarted = false;
  192. ExecuteCallBack( cur->Callback, cur->Context );
  193. }
  194. // Remove all the expired object from the list
  195. while( ( TimerListHead != NULL ) && ( TimerListHead->Timestamp < RtcGetTimerElapsedTime( ) ) )
  196. {
  197. cur = TimerListHead;
  198. TimerListHead = TimerListHead->Next;
  199. cur->IsStarted = false;
  200. ExecuteCallBack( cur->Callback, cur->Context );
  201. }
  202. // Start the next TimerListHead if it exists AND NOT running
  203. if( ( TimerListHead != NULL ) && ( TimerListHead->IsNext2Expire == false ) )
  204. {
  205. TimerSetTimeout( TimerListHead );
  206. }
  207. }
  208. void TimerStop( TimerEvent_t *obj )
  209. {
  210. CRITICAL_SECTION_BEGIN( );
  211. TimerEvent_t* prev = TimerListHead;
  212. TimerEvent_t* cur = TimerListHead;
  213. // List is empty or the obj to stop does not exist
  214. if( ( TimerListHead == NULL ) || ( obj == NULL ) )
  215. {
  216. CRITICAL_SECTION_END( );
  217. return;
  218. }
  219. obj->IsStarted = false;
  220. if( TimerListHead == obj ) // Stop the Head
  221. {
  222. if( TimerListHead->IsNext2Expire == true ) // The head is already running
  223. {
  224. TimerListHead->IsNext2Expire = false;
  225. if( TimerListHead->Next != NULL )
  226. {
  227. TimerListHead = TimerListHead->Next;
  228. TimerSetTimeout( TimerListHead );
  229. }
  230. else
  231. {
  232. RtcStopAlarm( );
  233. TimerListHead = NULL;
  234. }
  235. }
  236. else // Stop the head before it is started
  237. {
  238. if( TimerListHead->Next != NULL )
  239. {
  240. TimerListHead = TimerListHead->Next;
  241. }
  242. else
  243. {
  244. TimerListHead = NULL;
  245. }
  246. }
  247. }
  248. else // Stop an object within the list
  249. {
  250. while( cur != NULL )
  251. {
  252. if( cur == obj )
  253. {
  254. if( cur->Next != NULL )
  255. {
  256. cur = cur->Next;
  257. prev->Next = cur;
  258. }
  259. else
  260. {
  261. cur = NULL;
  262. prev->Next = cur;
  263. }
  264. break;
  265. }
  266. else
  267. {
  268. prev = cur;
  269. cur = cur->Next;
  270. }
  271. }
  272. }
  273. CRITICAL_SECTION_END( );
  274. }
  275. static bool TimerExists( TimerEvent_t *obj )
  276. {
  277. TimerEvent_t* cur = TimerListHead;
  278. while( cur != NULL )
  279. {
  280. if( cur == obj )
  281. {
  282. return true;
  283. }
  284. cur = cur->Next;
  285. }
  286. return false;
  287. }
  288. void TimerReset( TimerEvent_t *obj )
  289. {
  290. TimerStop( obj );
  291. TimerStart( obj );
  292. }
  293. void TimerSetValue( TimerEvent_t *obj, uint32_t value )
  294. {
  295. uint32_t minValue = 0;
  296. uint32_t ticks = RtcMs2Tick( value );
  297. TimerStop( obj );
  298. minValue = RtcGetMinimumTimeout( );
  299. if( ticks < minValue )
  300. {
  301. ticks = minValue;
  302. }
  303. obj->Timestamp = ticks;
  304. obj->ReloadValue = ticks;
  305. }
  306. TimerTime_t TimerGetCurrentTime( void )
  307. {
  308. uint32_t now = RtcGetTimerValue( );
  309. return RtcTick2Ms( now );
  310. }
  311. TimerTime_t TimerGetElapsedTime( TimerTime_t past )
  312. {
  313. if ( past == 0 )
  314. {
  315. return 0;
  316. }
  317. uint32_t nowInTicks = RtcGetTimerValue( );
  318. uint32_t pastInTicks = RtcMs2Tick( past );
  319. // Intentional wrap around. Works Ok if tick duration below 1ms
  320. return RtcTick2Ms( nowInTicks - pastInTicks );
  321. }
  322. static void TimerSetTimeout( TimerEvent_t *obj )
  323. {
  324. int32_t minTicks= RtcGetMinimumTimeout( );
  325. obj->IsNext2Expire = true;
  326. // In case deadline too soon
  327. if( obj->Timestamp < ( RtcGetTimerElapsedTime( ) + minTicks ) )
  328. {
  329. obj->Timestamp = RtcGetTimerElapsedTime( ) + minTicks;
  330. }
  331. RtcSetAlarm( obj->Timestamp );
  332. }
  333. TimerTime_t TimerTempCompensation( TimerTime_t period, float temperature )
  334. {
  335. return RtcTempCompensation( period, temperature );
  336. }
  337. void TimerProcess( void )
  338. {
  339. RtcProcess( );
  340. }