xref: /nrf52832-nimble/rt-thread/src/timer.c (revision 104654410c56c573564690304ae786df310c91fc)
1*10465441SEvalZero /*
2*10465441SEvalZero  * Copyright (c) 2006-2018, RT-Thread Development Team
3*10465441SEvalZero  *
4*10465441SEvalZero  * SPDX-License-Identifier: Apache-2.0
5*10465441SEvalZero  *
6*10465441SEvalZero  * Change Logs:
7*10465441SEvalZero  * Date           Author       Notes
8*10465441SEvalZero  * 2006-03-12     Bernard      first version
9*10465441SEvalZero  * 2006-04-29     Bernard      implement thread timer
10*10465441SEvalZero  * 2006-06-04     Bernard      implement rt_timer_control
11*10465441SEvalZero  * 2006-08-10     Bernard      fix the periodic timer bug
12*10465441SEvalZero  * 2006-09-03     Bernard      implement rt_timer_detach
13*10465441SEvalZero  * 2009-11-11     LiJin        add soft timer
14*10465441SEvalZero  * 2010-05-12     Bernard      fix the timer check bug.
15*10465441SEvalZero  * 2010-11-02     Charlie      re-implement tick overflow issue
16*10465441SEvalZero  * 2012-12-15     Bernard      fix the next timeout issue in soft timer
17*10465441SEvalZero  * 2014-07-12     Bernard      does not lock scheduler when invoking soft-timer
18*10465441SEvalZero  *                             timeout function.
19*10465441SEvalZero  */
20*10465441SEvalZero 
21*10465441SEvalZero #include <rtthread.h>
22*10465441SEvalZero #include <rthw.h>
23*10465441SEvalZero 
24*10465441SEvalZero /* hard timer list */
25*10465441SEvalZero static rt_list_t rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
26*10465441SEvalZero 
27*10465441SEvalZero #ifdef RT_USING_TIMER_SOFT
28*10465441SEvalZero #ifndef RT_TIMER_THREAD_STACK_SIZE
29*10465441SEvalZero #define RT_TIMER_THREAD_STACK_SIZE     512
30*10465441SEvalZero #endif
31*10465441SEvalZero 
32*10465441SEvalZero #ifndef RT_TIMER_THREAD_PRIO
33*10465441SEvalZero #define RT_TIMER_THREAD_PRIO           0
34*10465441SEvalZero #endif
35*10465441SEvalZero 
36*10465441SEvalZero /* soft timer list */
37*10465441SEvalZero static rt_list_t rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL];
38*10465441SEvalZero static struct rt_thread timer_thread;
39*10465441SEvalZero ALIGN(RT_ALIGN_SIZE)
40*10465441SEvalZero static rt_uint8_t timer_thread_stack[RT_TIMER_THREAD_STACK_SIZE];
41*10465441SEvalZero #endif
42*10465441SEvalZero 
43*10465441SEvalZero #ifdef RT_USING_HOOK
44*10465441SEvalZero extern void (*rt_object_take_hook)(struct rt_object *object);
45*10465441SEvalZero extern void (*rt_object_put_hook)(struct rt_object *object);
46*10465441SEvalZero static void (*rt_timer_enter_hook)(struct rt_timer *timer);
47*10465441SEvalZero static void (*rt_timer_exit_hook)(struct rt_timer *timer);
48*10465441SEvalZero 
49*10465441SEvalZero /**
50*10465441SEvalZero  * @addtogroup Hook
51*10465441SEvalZero  */
52*10465441SEvalZero 
53*10465441SEvalZero /**@{*/
54*10465441SEvalZero 
55*10465441SEvalZero /**
56*10465441SEvalZero  * This function will set a hook function, which will be invoked when enter
57*10465441SEvalZero  * timer timeout callback function.
58*10465441SEvalZero  *
59*10465441SEvalZero  * @param hook the hook function
60*10465441SEvalZero  */
rt_timer_enter_sethook(void (* hook)(struct rt_timer * timer))61*10465441SEvalZero void rt_timer_enter_sethook(void (*hook)(struct rt_timer *timer))
62*10465441SEvalZero {
63*10465441SEvalZero     rt_timer_enter_hook = hook;
64*10465441SEvalZero }
65*10465441SEvalZero 
66*10465441SEvalZero /**
67*10465441SEvalZero  * This function will set a hook function, which will be invoked when exit
68*10465441SEvalZero  * timer timeout callback function.
69*10465441SEvalZero  *
70*10465441SEvalZero  * @param hook the hook function
71*10465441SEvalZero  */
rt_timer_exit_sethook(void (* hook)(struct rt_timer * timer))72*10465441SEvalZero void rt_timer_exit_sethook(void (*hook)(struct rt_timer *timer))
73*10465441SEvalZero {
74*10465441SEvalZero     rt_timer_exit_hook = hook;
75*10465441SEvalZero }
76*10465441SEvalZero 
77*10465441SEvalZero /**@}*/
78*10465441SEvalZero #endif
79*10465441SEvalZero 
_rt_timer_init(rt_timer_t timer,void (* timeout)(void * parameter),void * parameter,rt_tick_t time,rt_uint8_t flag)80*10465441SEvalZero static void _rt_timer_init(rt_timer_t timer,
81*10465441SEvalZero                            void (*timeout)(void *parameter),
82*10465441SEvalZero                            void      *parameter,
83*10465441SEvalZero                            rt_tick_t  time,
84*10465441SEvalZero                            rt_uint8_t flag)
85*10465441SEvalZero {
86*10465441SEvalZero     int i;
87*10465441SEvalZero 
88*10465441SEvalZero     /* set flag */
89*10465441SEvalZero     timer->parent.flag  = flag;
90*10465441SEvalZero 
91*10465441SEvalZero     /* set deactivated */
92*10465441SEvalZero     timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
93*10465441SEvalZero 
94*10465441SEvalZero     timer->timeout_func = timeout;
95*10465441SEvalZero     timer->parameter    = parameter;
96*10465441SEvalZero 
97*10465441SEvalZero     timer->timeout_tick = 0;
98*10465441SEvalZero     timer->init_tick    = time;
99*10465441SEvalZero 
100*10465441SEvalZero     /* initialize timer list */
101*10465441SEvalZero     for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
102*10465441SEvalZero     {
103*10465441SEvalZero         rt_list_init(&(timer->row[i]));
104*10465441SEvalZero     }
105*10465441SEvalZero }
106*10465441SEvalZero 
107*10465441SEvalZero /* the fist timer always in the last row */
rt_timer_list_next_timeout(rt_list_t timer_list[])108*10465441SEvalZero static rt_tick_t rt_timer_list_next_timeout(rt_list_t timer_list[])
109*10465441SEvalZero {
110*10465441SEvalZero     struct rt_timer *timer;
111*10465441SEvalZero 
112*10465441SEvalZero     if (rt_list_isempty(&timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
113*10465441SEvalZero         return RT_TICK_MAX;
114*10465441SEvalZero 
115*10465441SEvalZero     timer = rt_list_entry(timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
116*10465441SEvalZero                           struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
117*10465441SEvalZero 
118*10465441SEvalZero     return timer->timeout_tick;
119*10465441SEvalZero }
120*10465441SEvalZero 
_rt_timer_remove(rt_timer_t timer)121*10465441SEvalZero rt_inline void _rt_timer_remove(rt_timer_t timer)
122*10465441SEvalZero {
123*10465441SEvalZero     int i;
124*10465441SEvalZero 
125*10465441SEvalZero     for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
126*10465441SEvalZero     {
127*10465441SEvalZero         rt_list_remove(&timer->row[i]);
128*10465441SEvalZero     }
129*10465441SEvalZero }
130*10465441SEvalZero 
131*10465441SEvalZero #if RT_DEBUG_TIMER
rt_timer_count_height(struct rt_timer * timer)132*10465441SEvalZero static int rt_timer_count_height(struct rt_timer *timer)
133*10465441SEvalZero {
134*10465441SEvalZero     int i, cnt = 0;
135*10465441SEvalZero 
136*10465441SEvalZero     for (i = 0; i < RT_TIMER_SKIP_LIST_LEVEL; i++)
137*10465441SEvalZero     {
138*10465441SEvalZero         if (!rt_list_isempty(&timer->row[i]))
139*10465441SEvalZero             cnt++;
140*10465441SEvalZero     }
141*10465441SEvalZero     return cnt;
142*10465441SEvalZero }
143*10465441SEvalZero 
rt_timer_dump(rt_list_t timer_heads[])144*10465441SEvalZero void rt_timer_dump(rt_list_t timer_heads[])
145*10465441SEvalZero {
146*10465441SEvalZero     rt_list_t *list;
147*10465441SEvalZero 
148*10465441SEvalZero     for (list = timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1].next;
149*10465441SEvalZero          list != &timer_heads[RT_TIMER_SKIP_LIST_LEVEL - 1];
150*10465441SEvalZero          list = list->next)
151*10465441SEvalZero     {
152*10465441SEvalZero         struct rt_timer *timer = rt_list_entry(list,
153*10465441SEvalZero                                                struct rt_timer,
154*10465441SEvalZero                                                row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
155*10465441SEvalZero         rt_kprintf("%d", rt_timer_count_height(timer));
156*10465441SEvalZero     }
157*10465441SEvalZero     rt_kprintf("\n");
158*10465441SEvalZero }
159*10465441SEvalZero #endif
160*10465441SEvalZero 
161*10465441SEvalZero /**
162*10465441SEvalZero  * @addtogroup Clock
163*10465441SEvalZero  */
164*10465441SEvalZero 
165*10465441SEvalZero /**@{*/
166*10465441SEvalZero 
167*10465441SEvalZero /**
168*10465441SEvalZero  * This function will initialize a timer, normally this function is used to
169*10465441SEvalZero  * initialize a static timer object.
170*10465441SEvalZero  *
171*10465441SEvalZero  * @param timer the static timer object
172*10465441SEvalZero  * @param name the name of timer
173*10465441SEvalZero  * @param timeout the timeout function
174*10465441SEvalZero  * @param parameter the parameter of timeout function
175*10465441SEvalZero  * @param time the tick of timer
176*10465441SEvalZero  * @param flag the flag of timer
177*10465441SEvalZero  */
rt_timer_init(rt_timer_t timer,const char * name,void (* timeout)(void * parameter),void * parameter,rt_tick_t time,rt_uint8_t flag)178*10465441SEvalZero void rt_timer_init(rt_timer_t  timer,
179*10465441SEvalZero                    const char *name,
180*10465441SEvalZero                    void (*timeout)(void *parameter),
181*10465441SEvalZero                    void       *parameter,
182*10465441SEvalZero                    rt_tick_t   time,
183*10465441SEvalZero                    rt_uint8_t  flag)
184*10465441SEvalZero {
185*10465441SEvalZero     /* timer check */
186*10465441SEvalZero     RT_ASSERT(timer != RT_NULL);
187*10465441SEvalZero 
188*10465441SEvalZero     /* timer object initialization */
189*10465441SEvalZero     rt_object_init((rt_object_t)timer, RT_Object_Class_Timer, name);
190*10465441SEvalZero 
191*10465441SEvalZero     _rt_timer_init(timer, timeout, parameter, time, flag);
192*10465441SEvalZero }
193*10465441SEvalZero RTM_EXPORT(rt_timer_init);
194*10465441SEvalZero 
195*10465441SEvalZero /**
196*10465441SEvalZero  * This function will detach a timer from timer management.
197*10465441SEvalZero  *
198*10465441SEvalZero  * @param timer the static timer object
199*10465441SEvalZero  *
200*10465441SEvalZero  * @return the operation status, RT_EOK on OK; RT_ERROR on error
201*10465441SEvalZero  */
rt_timer_detach(rt_timer_t timer)202*10465441SEvalZero rt_err_t rt_timer_detach(rt_timer_t timer)
203*10465441SEvalZero {
204*10465441SEvalZero     register rt_base_t level;
205*10465441SEvalZero 
206*10465441SEvalZero     /* timer check */
207*10465441SEvalZero     RT_ASSERT(timer != RT_NULL);
208*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
209*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&timer->parent));
210*10465441SEvalZero 
211*10465441SEvalZero     /* disable interrupt */
212*10465441SEvalZero     level = rt_hw_interrupt_disable();
213*10465441SEvalZero 
214*10465441SEvalZero     _rt_timer_remove(timer);
215*10465441SEvalZero 
216*10465441SEvalZero     /* enable interrupt */
217*10465441SEvalZero     rt_hw_interrupt_enable(level);
218*10465441SEvalZero 
219*10465441SEvalZero     rt_object_detach((rt_object_t)timer);
220*10465441SEvalZero 
221*10465441SEvalZero     return RT_EOK;
222*10465441SEvalZero }
223*10465441SEvalZero RTM_EXPORT(rt_timer_detach);
224*10465441SEvalZero 
225*10465441SEvalZero #ifdef RT_USING_HEAP
226*10465441SEvalZero /**
227*10465441SEvalZero  * This function will create a timer
228*10465441SEvalZero  *
229*10465441SEvalZero  * @param name the name of timer
230*10465441SEvalZero  * @param timeout the timeout function
231*10465441SEvalZero  * @param parameter the parameter of timeout function
232*10465441SEvalZero  * @param time the tick of timer
233*10465441SEvalZero  * @param flag the flag of timer
234*10465441SEvalZero  *
235*10465441SEvalZero  * @return the created timer object
236*10465441SEvalZero  */
rt_timer_create(const char * name,void (* timeout)(void * parameter),void * parameter,rt_tick_t time,rt_uint8_t flag)237*10465441SEvalZero rt_timer_t rt_timer_create(const char *name,
238*10465441SEvalZero                            void (*timeout)(void *parameter),
239*10465441SEvalZero                            void       *parameter,
240*10465441SEvalZero                            rt_tick_t   time,
241*10465441SEvalZero                            rt_uint8_t  flag)
242*10465441SEvalZero {
243*10465441SEvalZero     struct rt_timer *timer;
244*10465441SEvalZero 
245*10465441SEvalZero     /* allocate a object */
246*10465441SEvalZero     timer = (struct rt_timer *)rt_object_allocate(RT_Object_Class_Timer, name);
247*10465441SEvalZero     if (timer == RT_NULL)
248*10465441SEvalZero     {
249*10465441SEvalZero         return RT_NULL;
250*10465441SEvalZero     }
251*10465441SEvalZero 
252*10465441SEvalZero     _rt_timer_init(timer, timeout, parameter, time, flag);
253*10465441SEvalZero 
254*10465441SEvalZero     return timer;
255*10465441SEvalZero }
256*10465441SEvalZero RTM_EXPORT(rt_timer_create);
257*10465441SEvalZero 
258*10465441SEvalZero /**
259*10465441SEvalZero  * This function will delete a timer and release timer memory
260*10465441SEvalZero  *
261*10465441SEvalZero  * @param timer the timer to be deleted
262*10465441SEvalZero  *
263*10465441SEvalZero  * @return the operation status, RT_EOK on OK; RT_ERROR on error
264*10465441SEvalZero  */
rt_timer_delete(rt_timer_t timer)265*10465441SEvalZero rt_err_t rt_timer_delete(rt_timer_t timer)
266*10465441SEvalZero {
267*10465441SEvalZero     register rt_base_t level;
268*10465441SEvalZero 
269*10465441SEvalZero     /* timer check */
270*10465441SEvalZero     RT_ASSERT(timer != RT_NULL);
271*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
272*10465441SEvalZero     RT_ASSERT(rt_object_is_systemobject(&timer->parent) == RT_FALSE);
273*10465441SEvalZero 
274*10465441SEvalZero     /* disable interrupt */
275*10465441SEvalZero     level = rt_hw_interrupt_disable();
276*10465441SEvalZero 
277*10465441SEvalZero     _rt_timer_remove(timer);
278*10465441SEvalZero 
279*10465441SEvalZero     /* enable interrupt */
280*10465441SEvalZero     rt_hw_interrupt_enable(level);
281*10465441SEvalZero 
282*10465441SEvalZero     rt_object_delete((rt_object_t)timer);
283*10465441SEvalZero 
284*10465441SEvalZero     return RT_EOK;
285*10465441SEvalZero }
286*10465441SEvalZero RTM_EXPORT(rt_timer_delete);
287*10465441SEvalZero #endif
288*10465441SEvalZero 
289*10465441SEvalZero /**
290*10465441SEvalZero  * This function will start the timer
291*10465441SEvalZero  *
292*10465441SEvalZero  * @param timer the timer to be started
293*10465441SEvalZero  *
294*10465441SEvalZero  * @return the operation status, RT_EOK on OK, -RT_ERROR on error
295*10465441SEvalZero  */
rt_timer_start(rt_timer_t timer)296*10465441SEvalZero rt_err_t rt_timer_start(rt_timer_t timer)
297*10465441SEvalZero {
298*10465441SEvalZero     unsigned int row_lvl;
299*10465441SEvalZero     rt_list_t *timer_list;
300*10465441SEvalZero     register rt_base_t level;
301*10465441SEvalZero     rt_list_t *row_head[RT_TIMER_SKIP_LIST_LEVEL];
302*10465441SEvalZero     unsigned int tst_nr;
303*10465441SEvalZero     static unsigned int random_nr;
304*10465441SEvalZero 
305*10465441SEvalZero     /* timer check */
306*10465441SEvalZero     RT_ASSERT(timer != RT_NULL);
307*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
308*10465441SEvalZero 
309*10465441SEvalZero     /* stop timer firstly */
310*10465441SEvalZero     level = rt_hw_interrupt_disable();
311*10465441SEvalZero     /* remove timer from list */
312*10465441SEvalZero     _rt_timer_remove(timer);
313*10465441SEvalZero     /* change status of timer */
314*10465441SEvalZero     timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
315*10465441SEvalZero     rt_hw_interrupt_enable(level);
316*10465441SEvalZero 
317*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_take_hook, (&(timer->parent)));
318*10465441SEvalZero 
319*10465441SEvalZero     /*
320*10465441SEvalZero      * get timeout tick,
321*10465441SEvalZero      * the max timeout tick shall not great than RT_TICK_MAX/2
322*10465441SEvalZero      */
323*10465441SEvalZero     RT_ASSERT(timer->init_tick < RT_TICK_MAX / 2);
324*10465441SEvalZero     timer->timeout_tick = rt_tick_get() + timer->init_tick;
325*10465441SEvalZero 
326*10465441SEvalZero     /* disable interrupt */
327*10465441SEvalZero     level = rt_hw_interrupt_disable();
328*10465441SEvalZero 
329*10465441SEvalZero #ifdef RT_USING_TIMER_SOFT
330*10465441SEvalZero     if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
331*10465441SEvalZero     {
332*10465441SEvalZero         /* insert timer to soft timer list */
333*10465441SEvalZero         timer_list = rt_soft_timer_list;
334*10465441SEvalZero     }
335*10465441SEvalZero     else
336*10465441SEvalZero #endif
337*10465441SEvalZero     {
338*10465441SEvalZero         /* insert timer to system timer list */
339*10465441SEvalZero         timer_list = rt_timer_list;
340*10465441SEvalZero     }
341*10465441SEvalZero 
342*10465441SEvalZero     row_head[0]  = &timer_list[0];
343*10465441SEvalZero     for (row_lvl = 0; row_lvl < RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
344*10465441SEvalZero     {
345*10465441SEvalZero         for (; row_head[row_lvl] != timer_list[row_lvl].prev;
346*10465441SEvalZero              row_head[row_lvl]  = row_head[row_lvl]->next)
347*10465441SEvalZero         {
348*10465441SEvalZero             struct rt_timer *t;
349*10465441SEvalZero             rt_list_t *p = row_head[row_lvl]->next;
350*10465441SEvalZero 
351*10465441SEvalZero             /* fix up the entry pointer */
352*10465441SEvalZero             t = rt_list_entry(p, struct rt_timer, row[row_lvl]);
353*10465441SEvalZero 
354*10465441SEvalZero             /* If we have two timers that timeout at the same time, it's
355*10465441SEvalZero              * preferred that the timer inserted early get called early.
356*10465441SEvalZero              * So insert the new timer to the end the the some-timeout timer
357*10465441SEvalZero              * list.
358*10465441SEvalZero              */
359*10465441SEvalZero             if ((t->timeout_tick - timer->timeout_tick) == 0)
360*10465441SEvalZero             {
361*10465441SEvalZero                 continue;
362*10465441SEvalZero             }
363*10465441SEvalZero             else if ((t->timeout_tick - timer->timeout_tick) < RT_TICK_MAX / 2)
364*10465441SEvalZero             {
365*10465441SEvalZero                 break;
366*10465441SEvalZero             }
367*10465441SEvalZero         }
368*10465441SEvalZero         if (row_lvl != RT_TIMER_SKIP_LIST_LEVEL - 1)
369*10465441SEvalZero             row_head[row_lvl + 1] = row_head[row_lvl] + 1;
370*10465441SEvalZero     }
371*10465441SEvalZero 
372*10465441SEvalZero     /* Interestingly, this super simple timer insert counter works very very
373*10465441SEvalZero      * well on distributing the list height uniformly. By means of "very very
374*10465441SEvalZero      * well", I mean it beats the randomness of timer->timeout_tick very easily
375*10465441SEvalZero      * (actually, the timeout_tick is not random and easy to be attacked). */
376*10465441SEvalZero     random_nr++;
377*10465441SEvalZero     tst_nr = random_nr;
378*10465441SEvalZero 
379*10465441SEvalZero     rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - 1],
380*10465441SEvalZero                          &(timer->row[RT_TIMER_SKIP_LIST_LEVEL - 1]));
381*10465441SEvalZero     for (row_lvl = 2; row_lvl <= RT_TIMER_SKIP_LIST_LEVEL; row_lvl++)
382*10465441SEvalZero     {
383*10465441SEvalZero         if (!(tst_nr & RT_TIMER_SKIP_LIST_MASK))
384*10465441SEvalZero             rt_list_insert_after(row_head[RT_TIMER_SKIP_LIST_LEVEL - row_lvl],
385*10465441SEvalZero                                  &(timer->row[RT_TIMER_SKIP_LIST_LEVEL - row_lvl]));
386*10465441SEvalZero         else
387*10465441SEvalZero             break;
388*10465441SEvalZero         /* Shift over the bits we have tested. Works well with 1 bit and 2
389*10465441SEvalZero          * bits. */
390*10465441SEvalZero         tst_nr >>= (RT_TIMER_SKIP_LIST_MASK + 1) >> 1;
391*10465441SEvalZero     }
392*10465441SEvalZero 
393*10465441SEvalZero     timer->parent.flag |= RT_TIMER_FLAG_ACTIVATED;
394*10465441SEvalZero 
395*10465441SEvalZero     /* enable interrupt */
396*10465441SEvalZero     rt_hw_interrupt_enable(level);
397*10465441SEvalZero 
398*10465441SEvalZero #ifdef RT_USING_TIMER_SOFT
399*10465441SEvalZero     if (timer->parent.flag & RT_TIMER_FLAG_SOFT_TIMER)
400*10465441SEvalZero     {
401*10465441SEvalZero         /* check whether timer thread is ready */
402*10465441SEvalZero         if ((timer_thread.stat & RT_THREAD_STAT_MASK) == RT_THREAD_SUSPEND)
403*10465441SEvalZero         {
404*10465441SEvalZero             /* resume timer thread to check soft timer */
405*10465441SEvalZero             rt_thread_resume(&timer_thread);
406*10465441SEvalZero             rt_schedule();
407*10465441SEvalZero         }
408*10465441SEvalZero     }
409*10465441SEvalZero #endif
410*10465441SEvalZero 
411*10465441SEvalZero     return RT_EOK;
412*10465441SEvalZero }
413*10465441SEvalZero RTM_EXPORT(rt_timer_start);
414*10465441SEvalZero 
415*10465441SEvalZero /**
416*10465441SEvalZero  * This function will stop the timer
417*10465441SEvalZero  *
418*10465441SEvalZero  * @param timer the timer to be stopped
419*10465441SEvalZero  *
420*10465441SEvalZero  * @return the operation status, RT_EOK on OK, -RT_ERROR on error
421*10465441SEvalZero  */
rt_timer_stop(rt_timer_t timer)422*10465441SEvalZero rt_err_t rt_timer_stop(rt_timer_t timer)
423*10465441SEvalZero {
424*10465441SEvalZero     register rt_base_t level;
425*10465441SEvalZero 
426*10465441SEvalZero     /* timer check */
427*10465441SEvalZero     RT_ASSERT(timer != RT_NULL);
428*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
429*10465441SEvalZero 
430*10465441SEvalZero     if (!(timer->parent.flag & RT_TIMER_FLAG_ACTIVATED))
431*10465441SEvalZero         return -RT_ERROR;
432*10465441SEvalZero 
433*10465441SEvalZero     RT_OBJECT_HOOK_CALL(rt_object_put_hook, (&(timer->parent)));
434*10465441SEvalZero 
435*10465441SEvalZero     /* disable interrupt */
436*10465441SEvalZero     level = rt_hw_interrupt_disable();
437*10465441SEvalZero 
438*10465441SEvalZero     _rt_timer_remove(timer);
439*10465441SEvalZero 
440*10465441SEvalZero     /* enable interrupt */
441*10465441SEvalZero     rt_hw_interrupt_enable(level);
442*10465441SEvalZero 
443*10465441SEvalZero     /* change stat */
444*10465441SEvalZero     timer->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
445*10465441SEvalZero 
446*10465441SEvalZero     return RT_EOK;
447*10465441SEvalZero }
448*10465441SEvalZero RTM_EXPORT(rt_timer_stop);
449*10465441SEvalZero 
450*10465441SEvalZero /**
451*10465441SEvalZero  * This function will get or set some options of the timer
452*10465441SEvalZero  *
453*10465441SEvalZero  * @param timer the timer to be get or set
454*10465441SEvalZero  * @param cmd the control command
455*10465441SEvalZero  * @param arg the argument
456*10465441SEvalZero  *
457*10465441SEvalZero  * @return RT_EOK
458*10465441SEvalZero  */
rt_timer_control(rt_timer_t timer,int cmd,void * arg)459*10465441SEvalZero rt_err_t rt_timer_control(rt_timer_t timer, int cmd, void *arg)
460*10465441SEvalZero {
461*10465441SEvalZero     /* timer check */
462*10465441SEvalZero     RT_ASSERT(timer != RT_NULL);
463*10465441SEvalZero     RT_ASSERT(rt_object_get_type(&timer->parent) == RT_Object_Class_Timer);
464*10465441SEvalZero 
465*10465441SEvalZero     switch (cmd)
466*10465441SEvalZero     {
467*10465441SEvalZero     case RT_TIMER_CTRL_GET_TIME:
468*10465441SEvalZero         *(rt_tick_t *)arg = timer->init_tick;
469*10465441SEvalZero         break;
470*10465441SEvalZero 
471*10465441SEvalZero     case RT_TIMER_CTRL_SET_TIME:
472*10465441SEvalZero         timer->init_tick = *(rt_tick_t *)arg;
473*10465441SEvalZero         break;
474*10465441SEvalZero 
475*10465441SEvalZero     case RT_TIMER_CTRL_SET_ONESHOT:
476*10465441SEvalZero         timer->parent.flag &= ~RT_TIMER_FLAG_PERIODIC;
477*10465441SEvalZero         break;
478*10465441SEvalZero 
479*10465441SEvalZero     case RT_TIMER_CTRL_SET_PERIODIC:
480*10465441SEvalZero         timer->parent.flag |= RT_TIMER_FLAG_PERIODIC;
481*10465441SEvalZero         break;
482*10465441SEvalZero     }
483*10465441SEvalZero 
484*10465441SEvalZero     return RT_EOK;
485*10465441SEvalZero }
486*10465441SEvalZero RTM_EXPORT(rt_timer_control);
487*10465441SEvalZero 
488*10465441SEvalZero /**
489*10465441SEvalZero  * This function will check timer list, if a timeout event happens, the
490*10465441SEvalZero  * corresponding timeout function will be invoked.
491*10465441SEvalZero  *
492*10465441SEvalZero  * @note this function shall be invoked in operating system timer interrupt.
493*10465441SEvalZero  */
rt_timer_check(void)494*10465441SEvalZero void rt_timer_check(void)
495*10465441SEvalZero {
496*10465441SEvalZero     struct rt_timer *t;
497*10465441SEvalZero     rt_tick_t current_tick;
498*10465441SEvalZero     register rt_base_t level;
499*10465441SEvalZero 
500*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check enter\n"));
501*10465441SEvalZero 
502*10465441SEvalZero     current_tick = rt_tick_get();
503*10465441SEvalZero 
504*10465441SEvalZero     /* disable interrupt */
505*10465441SEvalZero     level = rt_hw_interrupt_disable();
506*10465441SEvalZero 
507*10465441SEvalZero     while (!rt_list_isempty(&rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]))
508*10465441SEvalZero     {
509*10465441SEvalZero         t = rt_list_entry(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next,
510*10465441SEvalZero                           struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
511*10465441SEvalZero 
512*10465441SEvalZero         /*
513*10465441SEvalZero          * It supposes that the new tick shall less than the half duration of
514*10465441SEvalZero          * tick max.
515*10465441SEvalZero          */
516*10465441SEvalZero         if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
517*10465441SEvalZero         {
518*10465441SEvalZero             RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));
519*10465441SEvalZero 
520*10465441SEvalZero             /* remove timer from timer list firstly */
521*10465441SEvalZero             _rt_timer_remove(t);
522*10465441SEvalZero 
523*10465441SEvalZero             /* call timeout function */
524*10465441SEvalZero             t->timeout_func(t->parameter);
525*10465441SEvalZero 
526*10465441SEvalZero             /* re-get tick */
527*10465441SEvalZero             current_tick = rt_tick_get();
528*10465441SEvalZero 
529*10465441SEvalZero             RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
530*10465441SEvalZero             RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
531*10465441SEvalZero 
532*10465441SEvalZero             if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
533*10465441SEvalZero                 (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
534*10465441SEvalZero             {
535*10465441SEvalZero                 /* start it */
536*10465441SEvalZero                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
537*10465441SEvalZero                 rt_timer_start(t);
538*10465441SEvalZero             }
539*10465441SEvalZero             else
540*10465441SEvalZero             {
541*10465441SEvalZero                 /* stop timer */
542*10465441SEvalZero                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
543*10465441SEvalZero             }
544*10465441SEvalZero         }
545*10465441SEvalZero         else
546*10465441SEvalZero             break;
547*10465441SEvalZero     }
548*10465441SEvalZero 
549*10465441SEvalZero     /* enable interrupt */
550*10465441SEvalZero     rt_hw_interrupt_enable(level);
551*10465441SEvalZero 
552*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_TIMER, ("timer check leave\n"));
553*10465441SEvalZero }
554*10465441SEvalZero 
555*10465441SEvalZero /**
556*10465441SEvalZero  * This function will return the next timeout tick in the system.
557*10465441SEvalZero  *
558*10465441SEvalZero  * @return the next timeout tick in the system
559*10465441SEvalZero  */
rt_timer_next_timeout_tick(void)560*10465441SEvalZero rt_tick_t rt_timer_next_timeout_tick(void)
561*10465441SEvalZero {
562*10465441SEvalZero     return rt_timer_list_next_timeout(rt_timer_list);
563*10465441SEvalZero }
564*10465441SEvalZero 
565*10465441SEvalZero #ifdef RT_USING_TIMER_SOFT
566*10465441SEvalZero /**
567*10465441SEvalZero  * This function will check timer list, if a timeout event happens, the
568*10465441SEvalZero  * corresponding timeout function will be invoked.
569*10465441SEvalZero  */
rt_soft_timer_check(void)570*10465441SEvalZero void rt_soft_timer_check(void)
571*10465441SEvalZero {
572*10465441SEvalZero     rt_tick_t current_tick;
573*10465441SEvalZero     rt_list_t *n;
574*10465441SEvalZero     struct rt_timer *t;
575*10465441SEvalZero 
576*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check enter\n"));
577*10465441SEvalZero 
578*10465441SEvalZero     current_tick = rt_tick_get();
579*10465441SEvalZero 
580*10465441SEvalZero     /* lock scheduler */
581*10465441SEvalZero     rt_enter_critical();
582*10465441SEvalZero 
583*10465441SEvalZero     for (n = rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1].next;
584*10465441SEvalZero          n != &(rt_soft_timer_list[RT_TIMER_SKIP_LIST_LEVEL - 1]);)
585*10465441SEvalZero     {
586*10465441SEvalZero         t = rt_list_entry(n, struct rt_timer, row[RT_TIMER_SKIP_LIST_LEVEL - 1]);
587*10465441SEvalZero 
588*10465441SEvalZero         /*
589*10465441SEvalZero          * It supposes that the new tick shall less than the half duration of
590*10465441SEvalZero          * tick max.
591*10465441SEvalZero          */
592*10465441SEvalZero         if ((current_tick - t->timeout_tick) < RT_TICK_MAX / 2)
593*10465441SEvalZero         {
594*10465441SEvalZero             RT_OBJECT_HOOK_CALL(rt_timer_enter_hook, (t));
595*10465441SEvalZero 
596*10465441SEvalZero             /* move node to the next */
597*10465441SEvalZero             n = n->next;
598*10465441SEvalZero 
599*10465441SEvalZero             /* remove timer from timer list firstly */
600*10465441SEvalZero             _rt_timer_remove(t);
601*10465441SEvalZero 
602*10465441SEvalZero             /* not lock scheduler when performing timeout function */
603*10465441SEvalZero             rt_exit_critical();
604*10465441SEvalZero             /* call timeout function */
605*10465441SEvalZero             t->timeout_func(t->parameter);
606*10465441SEvalZero 
607*10465441SEvalZero             /* re-get tick */
608*10465441SEvalZero             current_tick = rt_tick_get();
609*10465441SEvalZero 
610*10465441SEvalZero             RT_OBJECT_HOOK_CALL(rt_timer_exit_hook, (t));
611*10465441SEvalZero             RT_DEBUG_LOG(RT_DEBUG_TIMER, ("current tick: %d\n", current_tick));
612*10465441SEvalZero 
613*10465441SEvalZero             /* lock scheduler */
614*10465441SEvalZero             rt_enter_critical();
615*10465441SEvalZero 
616*10465441SEvalZero             if ((t->parent.flag & RT_TIMER_FLAG_PERIODIC) &&
617*10465441SEvalZero                 (t->parent.flag & RT_TIMER_FLAG_ACTIVATED))
618*10465441SEvalZero             {
619*10465441SEvalZero                 /* start it */
620*10465441SEvalZero                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
621*10465441SEvalZero                 rt_timer_start(t);
622*10465441SEvalZero             }
623*10465441SEvalZero             else
624*10465441SEvalZero             {
625*10465441SEvalZero                 /* stop timer */
626*10465441SEvalZero                 t->parent.flag &= ~RT_TIMER_FLAG_ACTIVATED;
627*10465441SEvalZero             }
628*10465441SEvalZero         }
629*10465441SEvalZero         else break; /* not check anymore */
630*10465441SEvalZero     }
631*10465441SEvalZero 
632*10465441SEvalZero     /* unlock scheduler */
633*10465441SEvalZero     rt_exit_critical();
634*10465441SEvalZero 
635*10465441SEvalZero     RT_DEBUG_LOG(RT_DEBUG_TIMER, ("software timer check leave\n"));
636*10465441SEvalZero }
637*10465441SEvalZero 
638*10465441SEvalZero /* system timer thread entry */
rt_thread_timer_entry(void * parameter)639*10465441SEvalZero static void rt_thread_timer_entry(void *parameter)
640*10465441SEvalZero {
641*10465441SEvalZero     rt_tick_t next_timeout;
642*10465441SEvalZero 
643*10465441SEvalZero     while (1)
644*10465441SEvalZero     {
645*10465441SEvalZero         /* get the next timeout tick */
646*10465441SEvalZero         next_timeout = rt_timer_list_next_timeout(rt_soft_timer_list);
647*10465441SEvalZero         if (next_timeout == RT_TICK_MAX)
648*10465441SEvalZero         {
649*10465441SEvalZero             /* no software timer exist, suspend self. */
650*10465441SEvalZero             rt_thread_suspend(rt_thread_self());
651*10465441SEvalZero             rt_schedule();
652*10465441SEvalZero         }
653*10465441SEvalZero         else
654*10465441SEvalZero         {
655*10465441SEvalZero             rt_tick_t current_tick;
656*10465441SEvalZero 
657*10465441SEvalZero             /* get current tick */
658*10465441SEvalZero             current_tick = rt_tick_get();
659*10465441SEvalZero 
660*10465441SEvalZero             if ((next_timeout - current_tick) < RT_TICK_MAX / 2)
661*10465441SEvalZero             {
662*10465441SEvalZero                 /* get the delta timeout tick */
663*10465441SEvalZero                 next_timeout = next_timeout - current_tick;
664*10465441SEvalZero                 rt_thread_delay(next_timeout);
665*10465441SEvalZero             }
666*10465441SEvalZero         }
667*10465441SEvalZero 
668*10465441SEvalZero         /* check software timer */
669*10465441SEvalZero         rt_soft_timer_check();
670*10465441SEvalZero     }
671*10465441SEvalZero }
672*10465441SEvalZero #endif
673*10465441SEvalZero 
674*10465441SEvalZero /**
675*10465441SEvalZero  * @ingroup SystemInit
676*10465441SEvalZero  *
677*10465441SEvalZero  * This function will initialize system timer
678*10465441SEvalZero  */
rt_system_timer_init(void)679*10465441SEvalZero void rt_system_timer_init(void)
680*10465441SEvalZero {
681*10465441SEvalZero     int i;
682*10465441SEvalZero 
683*10465441SEvalZero     for (i = 0; i < sizeof(rt_timer_list) / sizeof(rt_timer_list[0]); i++)
684*10465441SEvalZero     {
685*10465441SEvalZero         rt_list_init(rt_timer_list + i);
686*10465441SEvalZero     }
687*10465441SEvalZero }
688*10465441SEvalZero 
689*10465441SEvalZero /**
690*10465441SEvalZero  * @ingroup SystemInit
691*10465441SEvalZero  *
692*10465441SEvalZero  * This function will initialize system timer thread
693*10465441SEvalZero  */
rt_system_timer_thread_init(void)694*10465441SEvalZero void rt_system_timer_thread_init(void)
695*10465441SEvalZero {
696*10465441SEvalZero #ifdef RT_USING_TIMER_SOFT
697*10465441SEvalZero     int i;
698*10465441SEvalZero 
699*10465441SEvalZero     for (i = 0;
700*10465441SEvalZero          i < sizeof(rt_soft_timer_list) / sizeof(rt_soft_timer_list[0]);
701*10465441SEvalZero          i++)
702*10465441SEvalZero     {
703*10465441SEvalZero         rt_list_init(rt_soft_timer_list + i);
704*10465441SEvalZero     }
705*10465441SEvalZero 
706*10465441SEvalZero     /* start software timer thread */
707*10465441SEvalZero     rt_thread_init(&timer_thread,
708*10465441SEvalZero                    "timer",
709*10465441SEvalZero                    rt_thread_timer_entry,
710*10465441SEvalZero                    RT_NULL,
711*10465441SEvalZero                    &timer_thread_stack[0],
712*10465441SEvalZero                    sizeof(timer_thread_stack),
713*10465441SEvalZero                    RT_TIMER_THREAD_PRIO,
714*10465441SEvalZero                    10);
715*10465441SEvalZero 
716*10465441SEvalZero     /* startup */
717*10465441SEvalZero     rt_thread_startup(&timer_thread);
718*10465441SEvalZero #endif
719*10465441SEvalZero }
720*10465441SEvalZero 
721*10465441SEvalZero /**@}*/
722