timer.c 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554
  1. /*
  2. * File : timer.c
  3. * This file is part of RT-Thread RTOS
  4. * COPYRIGHT (C) 2006 - 2009, 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_increase (void);
  288. #endif
  289. void rt_timer_check(void)
  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. /* increase soft timer tick */
  338. #ifdef RT_USING_TIMER_SOFT
  339. rt_soft_timer_tick_increase ( );
  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. void rt_soft_timer_tick_increase (void)
  351. {
  352. timer_ex_cnt++;
  353. if (timer_ex_cnt >= (RT_TICK_PER_SECOND / RT_TIMER_TICK_PER_SECOND))
  354. {
  355. timer_ex_cnt = 0;
  356. rt_sem_release(&timer_sem);
  357. }
  358. }
  359. /**
  360. * This function will check timer list, if a timeout event happens, the
  361. * corresponding timeout function will be invoked.
  362. *
  363. */
  364. void rt_soft_timer_check()
  365. {
  366. rt_tick_t current_tick;
  367. rt_list_t *n;
  368. struct rt_timer *t;
  369. #ifdef RT_TIMER_DEBUG
  370. rt_kprintf("software timer check enter\n");
  371. #endif
  372. current_tick = rt_tick_get();
  373. for (n = rt_soft_timer_list.next; n != &(rt_soft_timer_list); )
  374. {
  375. t = rt_list_entry(n, struct rt_timer, list);
  376. if (current_tick >= t->timeout_tick)
  377. {
  378. #ifdef RT_USING_HOOK
  379. if (rt_timer_timeout_hook != RT_NULL) rt_timer_timeout_hook(t);
  380. #endif
  381. /* move node to the next */
  382. n = n->next;
  383. /* remove timer from timer list firstly */
  384. rt_list_remove(&(t->list));
  385. /* call timeout function */
  386. t->timeout_func(t->parameter);
  387. /* reget tick */
  388. current_tick = rt_tick_get();
  389. #ifdef RT_TIMER_DEBUG
  390. rt_kprintf("current tick: %d\n", current_tick);
  391. #endif
  392. if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
  393. (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
  394. {
  395. /* start it */
  396. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  397. rt_timer_start(t);
  398. }
  399. else
  400. {
  401. /* stop timer */
  402. t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
  403. }
  404. }
  405. else break;
  406. }
  407. #ifdef RT_TIMER_DEBUG
  408. rt_kprintf("software timer check leave\n");
  409. #endif
  410. }
  411. /* system timer thread entry */
  412. static void rt_thread_timer_entry(void* parameter)
  413. {
  414. while (1)
  415. {
  416. /* take software timer semaphore */
  417. rt_sem_take(&timer_sem,RT_WAITING_FOREVER);
  418. /* lock scheduler */
  419. rt_enter_critical();
  420. /* check software timer */
  421. rt_soft_timer_check();
  422. /* unlock scheduler */
  423. rt_exit_critical();
  424. }
  425. }
  426. #endif
  427. /**
  428. * @ingroup SystemInit
  429. *
  430. * This function will init system timer
  431. *
  432. */
  433. void rt_system_timer_init()
  434. {
  435. rt_list_init(&rt_timer_list);
  436. #ifdef RT_USING_TIMER_SOFT
  437. rt_list_init(&rt_soft_timer_list);
  438. rt_sem_init(&timer_sem, "timer", 0, RT_IPC_FLAG_FIFO);
  439. #endif
  440. }
  441. /**
  442. * @ingroup SystemInit
  443. *
  444. * This function will init system timer thread
  445. *
  446. */
  447. void rt_system_timer_thread_init()
  448. {
  449. #ifdef RT_USING_TIMER_SOFT
  450. /* start software timer thread */
  451. rt_thread_init(&timer_thread,
  452. "timer",
  453. rt_thread_timer_entry, RT_NULL,
  454. &timer_thread_stack[0], sizeof(timer_thread_stack),
  455. RT_TIMER_THREAD_PRIO, 10);
  456. /* startup */
  457. rt_thread_startup(&timer_thread);
  458. #endif
  459. }
  460. /*@}*/