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