timer.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550
  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://www.rt-thread.org/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. * 2009-11-11 LiJin add soft timer
  18. */
  19. #include <rtthread.h>
  20. #include <rthw.h>
  21. #include "kservice.h"
  22. /* #define RT_TIMER_DEBUG */
  23. /* hard timer list */
  24. static rt_list_t rt_timer_list;
  25. #ifdef RT_USING_TIMER_SOFT
  26. /* soft timer list */
  27. static rt_list_t rt_soft_timer_list;
  28. #endif
  29. #ifdef RT_USING_HOOK
  30. extern void (*rt_object_take_hook)(struct rt_object* object);
  31. extern void (*rt_object_put_hook)(struct rt_object* object);
  32. static void (*rt_timer_timeout_hook)(struct rt_timer* timer);
  33. /**
  34. * @addtogroup Hook
  35. */
  36. /*@{*/
  37. /**
  38. * This function will set a hook function, which will be invoked when timer
  39. * is timeout.
  40. *
  41. * @param hook the hook function
  42. */
  43. void rt_timer_timeout_sethook(void (*hook)(struct rt_timer* timer))
  44. {
  45. rt_timer_timeout_hook = hook;
  46. }
  47. /*@}*/
  48. #endif
  49. static void _rt_timer_init(rt_timer_t timer,
  50. void (*timeout)(void* parameter), void* parameter,
  51. rt_tick_t time, rt_uint8_t flag)
  52. {
  53. /* set flag */
  54. timer->parent.flag = flag;
  55. /* set deactivated */
  56. timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  57. timer->timeout_func = timeout;
  58. timer->parameter = parameter;
  59. timer->timeout_tick = 0;
  60. timer->init_tick = time;
  61. /* init timer list */
  62. rt_list_init(&(timer->list));
  63. }
  64. /**
  65. * @addtogroup Clock
  66. */
  67. /*@{*/
  68. /**
  69. * This function will init a timer, normally this function is used to initialize
  70. * a static timer object.
  71. *
  72. * @param timer the static timer object
  73. * @param name the name of timer
  74. * @param timeout the timeout function
  75. * @param parameter the parameter of timeout function
  76. * @param time the tick of timer
  77. * @param flag the flag of timer
  78. */
  79. void rt_timer_init(rt_timer_t timer,
  80. const char* name,
  81. void (*timeout)(void* parameter), void* parameter,
  82. rt_tick_t time, rt_uint8_t flag)
  83. {
  84. /* timer check */
  85. RT_ASSERT(timer != RT_NULL);
  86. /* timer object init */
  87. rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);
  88. _rt_timer_init(timer, timeout, parameter, time, flag);
  89. }
  90. /**
  91. * This function will detach a timer from timer management.
  92. *
  93. * @param timer the static timer object
  94. *
  95. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  96. */
  97. rt_err_t rt_timer_detach(rt_timer_t timer)
  98. {
  99. register rt_base_t level;
  100. /* timer check */
  101. RT_ASSERT(timer != RT_NULL);
  102. /* disable interrupt */
  103. level = rt_hw_interrupt_disable();
  104. /* remove it from timer list */
  105. rt_list_remove(&(timer->list));
  106. /* enable interrupt */
  107. rt_hw_interrupt_enable(level);
  108. rt_object_detach((rt_object_t)timer);
  109. return -RT_EOK;
  110. }
  111. #ifdef RT_USING_HEAP
  112. /**
  113. * This function will create a timer
  114. *
  115. * @param name the name of timer
  116. * @param timeout the timeout function
  117. * @param parameter the parameter of timeout function
  118. * @param time the tick of timer
  119. * @param flag the flag of timer
  120. *
  121. * @return the created timer object
  122. */
  123. rt_timer_t rt_timer_create(const char* name, void (*timeout)(void* parameter), void* parameter, rt_tick_t time, rt_uint8_t flag)
  124. {
  125. struct rt_timer* timer;
  126. /* allocate a object */
  127. timer = (struct rt_timer*)rt_object_allocate(RT_Object_Class_Timer, name);
  128. if (timer == RT_NULL)
  129. {
  130. return RT_NULL;
  131. }
  132. _rt_timer_init(timer, timeout, parameter, time, flag);
  133. return timer;
  134. }
  135. /**
  136. * This function will delete a timer and release timer memory
  137. *
  138. * @param timer the timer to be deleted
  139. *
  140. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  141. *
  142. */
  143. rt_err_t rt_timer_delete(rt_timer_t timer)
  144. {
  145. register rt_base_t level;
  146. /* timer check */
  147. RT_ASSERT(timer != RT_NULL);
  148. /* disable interrupt */
  149. level = rt_hw_interrupt_disable();
  150. /* remove it from timer list */
  151. rt_list_remove(&(timer->list));
  152. /* enable interrupt */
  153. rt_hw_interrupt_enable(level);
  154. rt_object_delete((rt_object_t)timer);
  155. return -RT_EOK;
  156. }
  157. #endif
  158. /**
  159. * This function will start the timer
  160. *
  161. * @param timer the timer to be started
  162. *
  163. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  164. *
  165. */
  166. rt_err_t rt_timer_start(rt_timer_t timer)
  167. {
  168. rt_list_t *n;
  169. struct rt_timer* t;
  170. register rt_base_t level;
  171. /* timer check */
  172. RT_ASSERT(timer != RT_NULL);
  173. if (timer->parent.flag & RT_TIMER_FLAG_ACTIVATED) return -RT_ERROR;
  174. #ifdef RT_USING_HOOK
  175. if (rt_object_take_hook != RT_NULL) rt_object_take_hook(&(timer->parent));
  176. #endif
  177. timer->timeout_tick = rt_tick_get() + timer->init_tick;
  178. /* disable interrupt */
  179. level = rt_hw_interrupt_disable();
  180. #ifdef RT_USING_TIMER_SOFT
  181. if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
  182. {
  183. /* insert timer to soft timer list */
  184. for (n = rt_soft_timer_list.next; n != &rt_soft_timer_list; n = n->next)
  185. {
  186. t = rt_list_entry(n, struct rt_timer, list);
  187. if (t->timeout_tick > timer->timeout_tick)
  188. {
  189. rt_list_insert_before(n, &(timer->list));
  190. break;
  191. }
  192. }
  193. /* no found suitable position in timer list */
  194. if (n == &rt_soft_timer_list)
  195. {
  196. rt_list_insert_before(n, &(timer->list));
  197. }
  198. }
  199. else
  200. #endif
  201. {
  202. /* insert timer to system timer list */
  203. for (n = rt_timer_list.next; n != &rt_timer_list; n = n->next)
  204. {
  205. t = rt_list_entry(n, struct rt_timer, list);
  206. if (t->timeout_tick > timer->timeout_tick)
  207. {
  208. rt_list_insert_before(n, &(timer->list));
  209. break;
  210. }
  211. }
  212. /* no found suitable position in timer list */
  213. if (n == &rt_timer_list)
  214. {
  215. rt_list_insert_before(n, &(timer->list));
  216. }
  217. }
  218. timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
  219. /* enable interrupt */
  220. rt_hw_interrupt_enable(level);
  221. return -RT_EOK;
  222. }
  223. /**
  224. * This function will stop the timer
  225. *
  226. * @param timer the timer to be stopped
  227. *
  228. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  229. *
  230. */
  231. rt_err_t rt_timer_stop(rt_timer_t timer)
  232. {
  233. register rt_base_t level;
  234. /* timer check */
  235. RT_ASSERT(timer != RT_NULL);
  236. if(!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED)) return -RT_ERROR;
  237. #ifdef RT_USING_HOOK
  238. if (rt_object_put_hook != RT_NULL) rt_object_put_hook(&(timer->parent));
  239. #endif
  240. /* disable interrupt */
  241. level = rt_hw_interrupt_disable();
  242. /* change stat */
  243. timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  244. /* remove it from timer list */
  245. rt_list_remove(&(timer->list));
  246. /* enable interrupt */
  247. rt_hw_interrupt_enable(level);
  248. return RT_EOK;
  249. }
  250. /**
  251. * This function will get or set some options of the timer
  252. *
  253. * @param timer the timer to be get or set
  254. * @param cmd the control command
  255. * @param arg the argument
  256. *
  257. * @return the operation status, RT_EOK on OK; RT_ERROR on error
  258. *
  259. */
  260. rt_err_t rt_timer_control(rt_timer_t timer, rt_uint8_t cmd, void* arg)
  261. {
  262. /* timer check */
  263. RT_ASSERT(timer != RT_NULL);
  264. switch (cmd)
  265. {
  266. case RT_TIMER_CTRL_GET_TIME:
  267. *(rt_tick_t*)arg = timer->init_tick;
  268. break;
  269. case RT_TIMER_CTRL_SET_TIME:
  270. timer->init_tick = *(rt_tick_t*)arg;
  271. break;
  272. case RT_TIMER_CTRL_SET_ONESHOT:
  273. timer->parent.flag &= ~(1 << RT_TIMER_FLAG_PERIODIC);
  274. break;
  275. case RT_TIMER_CTRL_SET_PERIODIC:
  276. timer->parent.flag |= (1 << RT_TIMER_FLAG_PERIODIC);
  277. break;
  278. }
  279. return RT_EOK;
  280. }
  281. /**
  282. * This function will check timer list, if a timeout event happens, the
  283. * corresponding timeout function will be invoked.
  284. *
  285. */
  286. #ifdef RT_USING_TIMER_SOFT
  287. void rt_soft_timer_tick_hook (void);
  288. #endif
  289. void rt_timer_check()
  290. {
  291. rt_tick_t current_tick;
  292. rt_list_t *n;
  293. struct rt_timer *t;
  294. register rt_base_t level;
  295. #ifdef RT_TIMER_DEBUG
  296. rt_kprintf("timer check enter\n");
  297. #endif
  298. current_tick = rt_tick_get();
  299. /* disable interrupt */
  300. level = rt_hw_interrupt_disable();
  301. for (n = rt_timer_list.next; n != &(rt_timer_list); )
  302. {
  303. t = rt_list_entry(n, struct rt_timer, list);
  304. if (current_tick >= t->timeout_tick)
  305. {
  306. #ifdef RT_USING_HOOK
  307. if (rt_timer_timeout_hook != RT_NULL) rt_timer_timeout_hook(t);
  308. #endif
  309. /* move node to the next */
  310. n = n->next;
  311. /* remove timer from timer list firstly */
  312. rt_list_remove(&(t->list));
  313. /* call timeout function */
  314. t->timeout_func(t->parameter);
  315. /* reget tick */
  316. current_tick = rt_tick_get();
  317. #ifdef RT_TIMER_DEBUG
  318. rt_kprintf("current tick: %d\n", current_tick);
  319. #endif
  320. if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
  321. (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  322. {
  323. /* start it */
  324. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  325. rt_timer_start(t);
  326. }
  327. else
  328. {
  329. /* stop timer */
  330. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  331. }
  332. }
  333. else break;
  334. }
  335. /* enable interrupt */
  336. rt_hw_interrupt_enable(level);
  337. /**/
  338. #ifdef RT_USING_TIMER_SOFT
  339. rt_soft_timer_tick_hook ( );
  340. #endif
  341. #ifdef TIMER_DEBUG
  342. rt_kprintf("timer check leave\n");
  343. #endif
  344. }
  345. #ifdef RT_USING_TIMER_SOFT
  346. static struct rt_thread timer_thread;
  347. static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE];
  348. static struct rt_semaphore timer_sem;
  349. static rt_uint16_t timer_ex_cnt;
  350. rt_err_t timer_signal (void)
  351. {
  352. return rt_sem_release(&timer_sem);
  353. }
  354. void rt_soft_timer_tick_hook (void)
  355. {
  356. timer_ex_cnt++;
  357. if (timer_ex_cnt >= (RT_TICK_PER_SECOND / RT_TIMER_EX_TICKS_PER_SEC))
  358. {
  359. timer_ex_cnt = 0;
  360. timer_signal();
  361. }
  362. }
  363. /**
  364. * This function will check timer list, if a timeout event happens, the
  365. * corresponding timeout function will be invoked.
  366. *
  367. */
  368. void rt_soft_timer_check()
  369. {
  370. rt_tick_t current_tick;
  371. rt_list_t *n;
  372. struct rt_timer *t;
  373. #ifdef RT_TIMER_DEBUG
  374. rt_kprintf("software timer check enter\n");
  375. #endif
  376. current_tick = rt_tick_get();
  377. for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list); )
  378. {
  379. t = rt_list_entry(n, struct rt_timer, list);
  380. if (current_tick >= t->timeout_tick)
  381. {
  382. #ifdef RT_USING_HOOK
  383. if (rt_timer_timeout_hook != RT_NULL) rt_timer_timeout_hook(t);
  384. #endif
  385. /* move node to the next */
  386. n = n->next;
  387. /* remove timer from timer list firstly */
  388. rt_list_remove(&(t->list));
  389. /* call timeout function */
  390. t->timeout_func(t->parameter);
  391. /* reget tick */
  392. current_tick = rt_tick_get();
  393. #ifdef RT_TIMER_DEBUG
  394. rt_kprintf("current tick: %d\n", current_tick);
  395. #endif
  396. if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
  397. (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  398. {
  399. /* start it */
  400. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  401. rt_timer_start(t);
  402. }
  403. else
  404. {
  405. /* stop timer */
  406. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  407. }
  408. }
  409. else break;
  410. }
  411. #ifdef RT_TIMER_DEBUG
  412. rt_kprintf("software timer check leave\n");
  413. #endif
  414. }
  415. /* system timer thread entry */
  416. static void rt_thread_timer_entry(void* parameter)
  417. {
  418. while (1)
  419. {
  420. rt_sem_take(&timer_sem,RT_WAITING_FOREVER);
  421. /* lock scheduler */
  422. rt_enter_critical();
  423. /* check software timer */
  424. rt_soft_timer_check();
  425. /* unlock scheduler */
  426. rt_exit_critical();
  427. }
  428. }
  429. #endif
  430. /**
  431. * @ingroup SystemInit
  432. *
  433. * This function will init system timer
  434. *
  435. */
  436. void rt_system_timer_init()
  437. {
  438. rt_list_init(&rt_timer_list);
  439. #ifdef RT_USING_TIMER_SOFT
  440. rt_list_init(&rt_soft_timer_list);
  441. rt_sem_init(&timer_sem, "timer", 0, RT_IPC_FLAG_FIFO);
  442. /* start software timer thread */
  443. rt_thread_init(&timer_thread,
  444. "timer",
  445. rt_thread_timer_entry, RT_NULL,
  446. &timer_thread_stack[0], sizeof(timer_thread_stack),
  447. RT_TIMER_THREAD_PRIO, 10);
  448. /* startup */
  449. rt_thread_startup(&timer_thread);
  450. #endif
  451. }
  452. /*@}*/