1 /*
2  * Copyright (C) 2015-2017 Alibaba Group Holding Limited
3  */
4 
5 #include "k_api.h"
6 
7 #if (RHINO_CONFIG_TIMER > 0)
timer_list_pri_insert(klist_t * head,ktimer_t * timer)8 static void timer_list_pri_insert(klist_t *head, ktimer_t *timer)
9 {
10     tick_t    val;
11     klist_t  *q;
12     klist_t  *start;
13     klist_t  *end;
14     ktimer_t *task_iter_temp;
15 
16     start = head;
17     end   = head;
18 
19     val   = timer->remain;
20 
21     for (q = start->next; q != end; q = q->next) {
22         task_iter_temp = krhino_list_entry(q, ktimer_t, timer_list);
23         if ((task_iter_temp->match - g_timer_count) > val) {
24             break;
25         }
26     }
27 
28     klist_insert(q, &timer->timer_list);
29 }
30 
timer_list_rm(ktimer_t * timer)31 static void timer_list_rm(ktimer_t *timer)
32 {
33     klist_t *head;
34 
35     head = timer->to_head;
36     if (head != NULL) {
37         klist_rm(&timer->timer_list);
38         timer->to_head = NULL;
39     }
40 }
41 
timer_create(ktimer_t * timer,const name_t * name,timer_cb_t cb,tick_t first,tick_t round,void * arg,uint8_t auto_run,uint8_t mm_alloc_flag)42 static kstat_t timer_create(ktimer_t *timer, const name_t *name, timer_cb_t cb, tick_t first,
43                             tick_t round, void *arg, uint8_t auto_run, uint8_t mm_alloc_flag)
44 {
45     kstat_t err = RHINO_SUCCESS;
46 
47     NULL_PARA_CHK(timer);
48     NULL_PARA_CHK(name);
49     NULL_PARA_CHK(cb);
50 
51     if (first == 0u) {
52         return RHINO_INV_PARAM;
53     }
54 
55     if (first > RHINO_MAX_TICKS) {
56         return RHINO_INV_PARAM;
57     }
58 
59     if (round > RHINO_MAX_TICKS) {
60         return RHINO_INV_PARAM;
61     }
62 
63     timer->name          = name;
64     timer->cb            = cb;
65     timer->init_count    = first;
66     timer->round_ticks   = round;
67     timer->remain        = 0u;
68     timer->match         = 0u;
69     timer->timer_state   = TIMER_DEACTIVE;
70     timer->to_head       = NULL;
71     timer->mm_alloc_flag = mm_alloc_flag;
72     timer->timer_cb_arg  = arg;
73 
74     klist_init(&timer->timer_list);
75 
76     timer->obj_type = RHINO_TIMER_OBJ_TYPE;
77 
78     if (auto_run > 0u) {
79         err = krhino_timer_start(timer);
80     }
81 
82     TRACE_TIMER_CREATE(krhino_cur_task_get(), timer);
83 
84     return err;
85 }
86 
krhino_timer_create(ktimer_t * timer,const name_t * name,timer_cb_t cb,tick_t first,tick_t round,void * arg,uint8_t auto_run)87 kstat_t krhino_timer_create(ktimer_t *timer, const name_t *name, timer_cb_t cb,
88                             tick_t first, tick_t round, void *arg, uint8_t auto_run)
89 {
90     return timer_create(timer, name, cb, first, round, arg, auto_run, K_OBJ_STATIC_ALLOC);
91 }
92 
krhino_timer_del(ktimer_t * timer)93 kstat_t krhino_timer_del(ktimer_t *timer)
94 {
95     k_timer_queue_cb cb;
96 
97     NULL_PARA_CHK(timer);
98 
99     cb.timer  = timer;
100     cb.cb_num = TIMER_CMD_DEL;
101 
102     return krhino_buf_queue_send(&g_timer_queue, &cb, sizeof(k_timer_queue_cb));
103 }
104 
105 #if (RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)
krhino_timer_dyn_create(ktimer_t ** timer,const name_t * name,timer_cb_t cb,tick_t first,tick_t round,void * arg,uint8_t auto_run)106 kstat_t krhino_timer_dyn_create(ktimer_t **timer, const name_t *name, timer_cb_t cb,
107                                 tick_t first, tick_t round, void *arg, uint8_t auto_run)
108 {
109     kstat_t   ret;
110     ktimer_t *timer_obj;
111 
112     NULL_PARA_CHK(timer);
113 
114     timer_obj = krhino_mm_alloc(sizeof(ktimer_t));
115     if (timer_obj == NULL) {
116         return RHINO_NO_MEM;
117     }
118 
119     ret = timer_create(timer_obj, name, cb, first, round, arg, auto_run, K_OBJ_DYN_ALLOC);
120     if (ret != RHINO_SUCCESS) {
121         krhino_mm_free(timer_obj);
122         return ret;
123     }
124 
125    *timer = timer_obj;
126 
127     return ret;
128 }
129 
krhino_timer_dyn_del(ktimer_t * timer)130 kstat_t krhino_timer_dyn_del(ktimer_t *timer)
131 {
132     k_timer_queue_cb cb;
133 
134     NULL_PARA_CHK(timer);
135 
136     cb.timer  = timer;
137     cb.cb_num = TIMER_CMD_DYN_DEL;
138 
139     return krhino_buf_queue_send(&g_timer_queue, &cb, sizeof(k_timer_queue_cb));
140 }
141 #endif
142 
krhino_timer_start(ktimer_t * timer)143 kstat_t krhino_timer_start(ktimer_t *timer)
144 {
145     k_timer_queue_cb cb;
146 
147     NULL_PARA_CHK(timer);
148 
149     cb.timer  = timer;
150     cb.cb_num = TIMER_CMD_START;
151 
152     return krhino_buf_queue_send(&g_timer_queue, &cb, sizeof(k_timer_queue_cb));
153 }
154 
krhino_timer_stop(ktimer_t * timer)155 kstat_t krhino_timer_stop(ktimer_t *timer)
156 {
157     k_timer_queue_cb cb;
158 
159     NULL_PARA_CHK(timer);
160 
161     cb.timer  = timer;
162     cb.cb_num = TIMER_CMD_STOP;
163 
164     return krhino_buf_queue_send(&g_timer_queue, &cb, sizeof(k_timer_queue_cb));
165 }
166 
krhino_timer_change(ktimer_t * timer,tick_t first,tick_t round)167 kstat_t krhino_timer_change(ktimer_t *timer, tick_t first, tick_t round)
168 {
169     k_timer_queue_cb cb;
170 
171     NULL_PARA_CHK(timer);
172 
173     if (first == 0u) {
174         return RHINO_INV_PARAM;
175     }
176 
177     if (first > RHINO_MAX_TICKS) {
178         return RHINO_INV_PARAM;
179     }
180 
181     if (round > RHINO_MAX_TICKS) {
182         return RHINO_INV_PARAM;
183     }
184 
185     cb.timer   = timer;
186     cb.first   = first;
187     cb.u.round = round;
188     cb.cb_num  = TIMER_CMD_CHG;
189 
190     return krhino_buf_queue_send(&g_timer_queue, &cb, sizeof(k_timer_queue_cb));
191 }
192 
krhino_timer_arg_change(ktimer_t * timer,void * arg)193 kstat_t krhino_timer_arg_change(ktimer_t *timer, void *arg)
194 {
195     k_timer_queue_cb cb;
196 
197     NULL_PARA_CHK(timer);
198 
199     cb.timer  = timer;
200     cb.u.arg  = arg;
201     cb.cb_num = TIMER_ARG_CHG;
202 
203     return krhino_buf_queue_send(&g_timer_queue, &cb, sizeof(k_timer_queue_cb));
204 }
205 
krhino_timer_arg_change_auto(ktimer_t * timer,void * arg)206 kstat_t krhino_timer_arg_change_auto(ktimer_t *timer, void *arg)
207 {
208     k_timer_queue_cb cb;
209 
210     NULL_PARA_CHK(timer);
211 
212     cb.timer  = timer;
213     cb.u.arg  = arg;
214     cb.cb_num = TIMER_ARG_CHG_AUTO;
215 
216     return krhino_buf_queue_send(&g_timer_queue, &cb, sizeof(k_timer_queue_cb));
217 }
218 
timer_cb_proc(void)219 static void timer_cb_proc(void)
220 {
221     klist_t  *q;
222     klist_t  *start;
223     klist_t  *end;
224     ktimer_t *timer;
225 
226     tick_i_t delta;
227 
228     start = end = &g_timer_head;
229 
230     for (q = start->next; q != end; q = q->next) {
231         timer = krhino_list_entry(q, ktimer_t, timer_list);
232         delta = (tick_i_t)timer->match - (tick_i_t)g_timer_count;
233 
234         if (delta <= 0) {
235             timer->cb(timer, timer->timer_cb_arg);
236             timer_list_rm(timer);
237 
238             if (timer->round_ticks > 0u) {
239                 timer->remain  =  timer->round_ticks;
240                 timer->match   =  g_timer_count + timer->remain;
241                 timer->to_head = &g_timer_head;
242                 timer_list_pri_insert(&g_timer_head, timer);
243             } else {
244                 timer->timer_state = TIMER_DEACTIVE;
245             }
246         } else {
247             break;
248         }
249     }
250 }
251 
cmd_proc(k_timer_queue_cb * cb,uint8_t cmd)252 static void cmd_proc(k_timer_queue_cb *cb, uint8_t cmd)
253 {
254     ktimer_t *timer = cb->timer;
255 
256     if (timer->obj_type != RHINO_TIMER_OBJ_TYPE) {
257         return;
258     }
259 
260     switch (cmd) {
261         case TIMER_CMD_START:
262             if (timer->timer_state == TIMER_ACTIVE) {
263                 break;
264             }
265 
266             timer->match   =  g_timer_count + timer->init_count;
267             /* sort by remain time */
268             timer->remain  =  timer->init_count;
269             /* used by timer delete */
270             timer->to_head = &g_timer_head;
271             timer_list_pri_insert(&g_timer_head, timer);
272             timer->timer_state = TIMER_ACTIVE;
273             break;
274         case TIMER_CMD_STOP:
275             if (timer->timer_state == TIMER_DEACTIVE) {
276                 break;
277             }
278             timer_list_rm(timer);
279             timer->timer_state = TIMER_DEACTIVE;
280             break;
281         case TIMER_CMD_CHG:
282             if (cb->first == 0u) {
283                 break;
284             }
285 
286             if (timer->timer_state != TIMER_DEACTIVE) {
287                 /* should stop timer before change attributes */
288                 break;
289             }
290 
291             timer->init_count  = cb->first;
292             timer->round_ticks = cb->u.round;
293             break;
294         case TIMER_ARG_CHG:
295             if (timer->timer_state != TIMER_DEACTIVE) {
296                 break;
297             }
298 
299             timer->timer_cb_arg = cb->u.arg;
300             break;
301         case TIMER_CMD_DEL:
302             if (timer->timer_state != TIMER_DEACTIVE) {
303                 break;
304             }
305 
306             if (timer->mm_alloc_flag != K_OBJ_STATIC_ALLOC) {
307                 break;
308             }
309 
310             timer->obj_type = RHINO_OBJ_TYPE_NONE;
311             TRACE_TIMER_DEL(krhino_cur_task_get(), timer);
312             break;
313 #if (RHINO_CONFIG_KOBJ_DYN_ALLOC > 0)
314         case TIMER_CMD_DYN_DEL:
315             if (timer->timer_state != TIMER_DEACTIVE) {
316                 break;
317             }
318 
319             if (timer->mm_alloc_flag != K_OBJ_DYN_ALLOC) {
320                 break;
321             }
322 
323             timer->obj_type = RHINO_OBJ_TYPE_NONE;
324             TRACE_TIMER_DEL(krhino_cur_task_get(), timer);
325             krhino_mm_free(timer);
326             break;
327 #endif
328         default:
329             k_err_proc(RHINO_SYS_FATAL_ERR);
330             break;
331     }
332 
333 }
334 
timer_cmd_proc(k_timer_queue_cb * cb)335 static void timer_cmd_proc(k_timer_queue_cb *cb)
336 {
337     if (cb->cb_num == TIMER_ARG_CHG_AUTO) {
338         cmd_proc(cb, TIMER_CMD_STOP);
339         cmd_proc(cb, TIMER_ARG_CHG);
340         cmd_proc(cb, TIMER_CMD_START);
341     } else {
342         cmd_proc(cb, cb->cb_num);
343     }
344 }
345 
timer_task(void * pa)346 static void timer_task(void *pa)
347 {
348     ktimer_t         *timer;
349     k_timer_queue_cb  cb_msg;
350     kstat_t           err;
351     tick_t            tick_start;
352     tick_t            tick_end;
353     tick_i_t          delta;
354     size_t            msg_size;
355 
356     (void)pa;
357 
358     while (RHINO_TRUE) {
359         err      = krhino_buf_queue_recv(&g_timer_queue, RHINO_WAIT_FOREVER, &cb_msg, &msg_size);
360         tick_end = krhino_sys_tick_get();
361 
362         if (err == RHINO_SUCCESS) {
363             g_timer_count = tick_end;
364         } else {
365             k_err_proc(RHINO_SYS_FATAL_ERR);
366         }
367 
368         timer_cmd_proc(&cb_msg);
369 
370         while (!is_klist_empty(&g_timer_head)) {
371             timer = krhino_list_entry(g_timer_head.next, ktimer_t, timer_list);
372             tick_start = krhino_sys_tick_get();
373             delta = (tick_i_t)timer->match - (tick_i_t)tick_start;
374             if (delta > 0) {
375                 err = krhino_buf_queue_recv(&g_timer_queue, (tick_t)delta, &cb_msg, &msg_size);
376                 tick_end = krhino_sys_tick_get();
377                 if (err == RHINO_BLK_TIMEOUT) {
378                     g_timer_count = tick_end;
379                 } else if (err == RHINO_SUCCESS) {
380                     g_timer_count = tick_end;
381                     timer_cb_proc();
382                     timer_cmd_proc(&cb_msg);
383                 } else {
384                     k_err_proc(RHINO_SYS_FATAL_ERR);
385                 }
386             } else {
387                 g_timer_count = tick_start;
388             }
389                 timer_cb_proc();
390         }
391     }
392 }
393 
ktimer_init(void)394 void ktimer_init(void)
395 {
396     klist_init(&g_timer_head);
397 
398     krhino_fix_buf_queue_create(&g_timer_queue, "timer_queue", timer_queue_cb,
399                                 sizeof(k_timer_queue_cb), RHINO_CONFIG_TIMER_MSG_NUM);
400 
401     krhino_task_create(&g_timer_task, "timer_task", NULL,
402                        RHINO_CONFIG_TIMER_TASK_PRI, 0u, g_timer_task_stack,
403                        RHINO_CONFIG_TIMER_TASK_STACK_SIZE, timer_task, 1u);
404 }
405 #endif /* RHINO_CONFIG_TIMER */
406 
407