timer.c 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391
  1. /*
  2. * File : timer.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006, RT-Thread Development Team
  5. *
  6. * The license and distribution terms for this file may be
  7. * found in the file LICENSE in this distribution or at
  8. * http://openlab.rt-thread.com/license/LICENSE
  9. *
  10. * Change Logs:
  11. * Date Author Notes
  12. * 2006-03-12 Bernard first version
  13. * 2006-04-29 Bernard implement thread timer
  14. * 2006-06-04 Bernard implement rt_timer_control
  15. * 2006-08-10 Bernard fix the periodic timer bug
  16. * 2006-09-03 Bernard implement rt_timer_detach
  17. */
  18. #include <rtthread.h>
  19. #include <rthw.h>
  20. #include "kservice.h"
  21. /* #define TIMER_DEBUG */
  22. static rt_list_t rt_timer_list;
  23. #ifdef RT_USING_HOOK
  24. extern void (*rt_object_take_hook)(struct rt_object* object);
  25. extern void (*rt_object_put_hook)(struct rt_object* object);
  26. static void (*rt_timer_timeout_hook)(struct rt_timer* timer);
  27. /**
  28. * @addtogroup Hook
  29. */
  30. /*@{*/
  31. /**
  32. * This function will set a hook function, which will be invoked when timer
  33. * is timeout.
  34. *
  35. * @param hook the hook function
  36. */
  37. void rt_timer_timeout_sethook(void (*hook)(struct rt_timer* timer))
  38. {
  39. rt_timer_timeout_hook = hook;
  40. }
  41. /*@}*/
  42. #endif
  43. /**
  44. * @ingroup SystemInit
  45. *
  46. * This function will init system timer
  47. *
  48. */
  49. void rt_system_timer_init()
  50. {
  51. rt_list_init(&rt_timer_list);
  52. }
  53. static void _rt_timer_init(rt_timer_t timer,
  54. void (*timeout)(void* parameter), void* parameter,
  55. rt_tick_t time, rt_uint8_t flag)
  56. {
  57. /* set flag */
  58. timer->parent.flag = flag;
  59. /* set deactivated */
  60. timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  61. timer->timeout_func = timeout;
  62. timer->parameter = parameter;
  63. timer->timeout_tick = 0;
  64. timer->init_tick = time;
  65. /* init timer list */
  66. rt_list_init(&(timer->list));
  67. }
  68. /**
  69. * @addtogroup Clock
  70. */
  71. /*@{*/
  72. /**
  73. * This function will init a timer, normally this function is used to initialize
  74. * a static timer object.
  75. *
  76. * @param timer the static timer object
  77. * @param name the name of timer
  78. * @param timeout the timeout function
  79. * @param parameter the parameter of timeout function
  80. * @param time the tick of timer
  81. * @param flag the flag of timer
  82. */
  83. void rt_timer_init(rt_timer_t timer,
  84. const char* name,
  85. void (*timeout)(void* parameter), void* parameter,
  86. rt_tick_t time, rt_uint8_t flag)
  87. {
  88. /* timer check */
  89. RT_ASSERT(timer != RT_NULL);
  90. /* timer object init */
  91. rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);
  92. _rt_timer_init(timer, timeout, parameter, time, flag);
  93. }
  94. /**
  95. * This function will detach a timer from timer management.
  96. *
  97. * @param timer the static timer object
  98. *
  99. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  100. */
  101. rt_err_t rt_timer_detach(rt_timer_t timer)
  102. {
  103. register rt_base_t level;
  104. /* timer check */
  105. RT_ASSERT(timer != RT_NULL);
  106. /* disable interrupt */
  107. level = rt_hw_interrupt_disable();
  108. /* remove it from timer list */
  109. rt_list_remove(&(timer->list));
  110. /* enable interrupt */
  111. rt_hw_interrupt_enable(level);
  112. rt_object_detach((rt_object_t)timer);
  113. return -RT_EOK;
  114. }
  115. #ifdef RT_USING_HEAP
  116. /**
  117. * This function will create a timer
  118. *
  119. * @param name the name of timer
  120. * @param timeout the timeout function
  121. * @param parameter the parameter of timeout function
  122. * @param time the tick of timer
  123. * @param flag the flag of timer
  124. *
  125. * @return the created timer object
  126. */
  127. rt_timer_t rt_timer_create(const char* name, void (*timeout)(void* parameter), void* parameter, rt_tick_t time, rt_uint8_t flag)
  128. {
  129. struct rt_timer* timer;
  130. /* allocate a object */
  131. timer = (struct rt_timer*)rt_object_allocate(RT_Object_Class_Timer, name);
  132. if (timer == RT_NULL)
  133. {
  134. return RT_NULL;
  135. }
  136. _rt_timer_init(timer, timeout, parameter, time, flag);
  137. return timer;
  138. }
  139. /**
  140. * This function will delete a timer and release timer memory
  141. *
  142. * @param timer the timer to be deleted
  143. *
  144. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  145. *
  146. */
  147. rt_err_t rt_timer_delete(rt_timer_t timer)
  148. {
  149. register rt_base_t level;
  150. /* timer check */
  151. RT_ASSERT(timer != RT_NULL);
  152. /* disable interrupt */
  153. level = rt_hw_interrupt_disable();
  154. /* remove it from timer list */
  155. rt_list_remove(&(timer->list));
  156. /* enable interrupt */
  157. rt_hw_interrupt_enable(level);
  158. rt_object_delete((rt_object_t)timer);
  159. return -RT_EOK;
  160. }
  161. #endif
  162. /**
  163. * This function will start the timer
  164. *
  165. * @param timer the timer to be started
  166. *
  167. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  168. *
  169. */
  170. rt_err_t rt_timer_start(rt_timer_t timer)
  171. {
  172. rt_list_t *n;
  173. struct rt_timer* t;
  174. register rt_base_t level;
  175. /* timer check */
  176. RT_ASSERT(timer != RT_NULL);
  177. if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) return -RT_ERROR;
  178. #ifdef RT_USING_HOOK
  179. if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(timer->parent));
  180. #endif
  181. timer->timeout_tick = rt_tick_get() + timer->init_tick;
  182. /* disable interrupt */
  183. level = rt_hw_interrupt_disable();
  184. /* insert timer to system timer list */
  185. for (n = rt_timer_list.next; n != &rt_timer_list; n = n->next)
  186. {
  187. t = rt_list_entry(n, struct rt_timer, list);
  188. if (t->timeout_tick > timer->timeout_tick)
  189. {
  190. rt_list_insert_before(n, &(timer->list));
  191. break;
  192. }
  193. }
  194. /* no found suitable position in timer list */
  195. if (n == &rt_timer_list)
  196. {
  197. rt_list_insert_before(n, &(timer->list));
  198. }
  199. timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
  200. /* enable interrupt */
  201. rt_hw_interrupt_enable(level);
  202. return -RT_EOK;
  203. }
  204. /**
  205. * This function will stop the timer
  206. *
  207. * @param timer the timer to be stopped
  208. *
  209. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  210. *
  211. */
  212. rt_err_t rt_timer_stop(rt_timer_t timer)
  213. {
  214. register rt_base_t level;
  215. /* timer check */
  216. RT_ASSERT(timer != RT_NULL);
  217. if(!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) return -RT_ERROR;
  218. #ifdef RT_USING_HOOK
  219. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(timer->parent));
  220. #endif
  221. /* disable interrupt */
  222. level = rt_hw_interrupt_disable();
  223. /* change stat */
  224. timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  225. /* remove it from timer list */
  226. rt_list_remove(&(timer->list));
  227. /* enable interrupt */
  228. rt_hw_interrupt_enable(level);
  229. return RT_EOK;
  230. }
  231. /**
  232. * This function will get or set some options of the timer
  233. *
  234. * @param timer the timer to be get or set
  235. * @param cmd the control command
  236. * @param arg the argument
  237. *
  238. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  239. *
  240. */
  241. rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg)
  242. {
  243. /* timer check */
  244. RT_ASSERT(timer != RT_NULL);
  245. switch (cmd)
  246. {
  247. case RT_TIMER_CTRL_GET_TIME:
  248. *(rt_tick_t*)arg = timer->init_tick;
  249. break;
  250. case RT_TIMER_CTRL_SET_TIME:
  251. timer->init_tick = *(rt_tick_t*)arg;
  252. break;
  253. case RT_TIMER_CTRL_SET_ONESHOT:
  254. timer->parent.flag &= ~(1 << RT_TIMER_FLAG_PERIODIC);
  255. break;
  256. case RT_TIMER_CTRL_SET_PERIODIC:
  257. timer->parent.flag |= (1 << RT_TIMER_FLAG_PERIODIC);
  258. break;
  259. }
  260. return RT_EOK;
  261. }
  262. /**
  263. * This function will check timer list, if a timeout event happens, the
  264. * corresponding timeout function will be invoked.
  265. *
  266. */
  267. void rt_timer_check()
  268. {
  269. rt_tick_t current_tick;
  270. rt_list_t *n;
  271. struct rt_timer *t;
  272. register rt_base_t level;
  273. #ifdef TIMER_DEBUG
  274. rt_kprintf("timer check enter\n");
  275. #endif
  276. current_tick = rt_tick_get();
  277. /* disable interrupt */
  278. level = rt_hw_interrupt_disable();
  279. for (n = rt_timer_list.next; n != &(rt_timer_list); )
  280. {
  281. t = rt_list_entry(n, struct rt_timer, list);
  282. if (current_tick >= t->timeout_tick)
  283. {
  284. #ifdef RT_USING_HOOK
  285. if (rt_timer_timeout_hook != RT_NULL) rt_timer_timeout_hook(t);
  286. #endif
  287. /* move node to the next */
  288. n = n->next;
  289. /* remove timer from timer list firstly */
  290. rt_list_remove(&(t->list));
  291. /* call timeout function */
  292. t->timeout_func(t->parameter);
  293. /* reget tick */
  294. current_tick = rt_tick_get();
  295. #ifdef TIMER_DEBUG
  296. rt_kprintf("current tick: %d\n", current_tick);
  297. #endif
  298. if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
  299. (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  300. {
  301. /* start it */
  302. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  303. rt_timer_start(t);
  304. }
  305. else
  306. {
  307. /* stop timer */
  308. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  309. }
  310. }
  311. else break;
  312. }
  313. /* enable interrupt */
  314. rt_hw_interrupt_enable(level);
  315. #ifdef TIMER_DEBUG
  316. rt_kprintf("timer check leave\n");
  317. #endif
  318. }
  319. /*@}*/