1 /*
2  * Copyright (c) 2006-2019, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2021-08-12     luckyzjq     the first version
9  */
10 
11 #include <rtthread.h>
12 #include <stdlib.h>
13 #include "utest.h"
14 
15 #undef uassert_true
16 #define uassert_true(value)                                 \
17     do                                                      \
18     {                                                       \
19         if (!(value))                                       \
20         {                                                   \
21             __utest_assert(value, "(" #value ") is false"); \
22         }                                                   \
23     } while (0)
24 
25 /* notify user that the test is not corrupted */
26 #define PRINT_PROGRESS(id) LOG_I("Testing on %d", id)
27 
28 static rt_uint8_t timer_flag_oneshot[] = {
29     RT_TIMER_FLAG_ONE_SHOT,
30     RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_HARD_TIMER,
31     RT_TIMER_FLAG_ONE_SHOT | RT_TIMER_FLAG_SOFT_TIMER,
32 };
33 
34 static rt_uint8_t timer_flag_periodic[] = {
35     RT_TIMER_FLAG_PERIODIC,
36     RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_HARD_TIMER,
37     RT_TIMER_FLAG_PERIODIC | RT_TIMER_FLAG_SOFT_TIMER,
38 };
39 
40 typedef struct test_timer_struct
41 {
42     struct rt_timer static_timer; /* static timer handler */
43     rt_timer_t dynamic_timer;     /* dynamic timer pointer */
44     rt_tick_t expect_tick;        /* expect tick */
45     rt_ubase_t callbacks;         /* timer callback times */
46     rt_bool_t is_static;          /* static or dynamic timer */
47 } timer_struct;
48 static timer_struct timer;
49 
timer_oneshot(void * param)50 static void timer_oneshot(void *param)
51 {
52     timer_struct *timer_call;
53     timer_call = (timer_struct *)param;
54     timer_call->callbacks++;
55 
56     uassert_true(rt_tick_get() == timer_call->expect_tick);
57 }
58 
timer_periodic(void * param)59 static void timer_periodic(void *param)
60 {
61     rt_err_t result;
62     timer_struct *timer_call;
63     timer_call = (timer_struct *)param;
64     timer_call->callbacks++;
65 
66     uassert_true(rt_tick_get() == timer_call->expect_tick);
67 
68     if (timer_call->is_static)
69     {
70         timer_call->expect_tick = rt_tick_get() + timer_call->static_timer.init_tick;
71     }
72     else
73     {
74         timer_call->expect_tick = rt_tick_get() + timer_call->dynamic_timer->init_tick;
75     }
76 
77     if (timer_call->callbacks == 5)
78     {
79         /* periodic timer can stop */
80         if (timer_call->is_static)
81         {
82             result = rt_timer_stop(&timer_call->static_timer);
83         }
84         else
85         {
86             result = rt_timer_stop(timer_call->dynamic_timer);
87         }
88 
89         uassert_true(result == RT_EOK);
90     }
91 }
92 
test_static_timer(void)93 static void test_static_timer(void)
94 {
95     rt_err_t result;
96 
97     timer.callbacks = 0;
98     timer.is_static = RT_TRUE;
99 
100     /* one shot timer test */
101     for (int time_out = 1; time_out < 10; time_out++)
102     {
103         for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
104         {
105             rt_timer_init(&timer.static_timer,
106                           "static_timer",
107                           timer_oneshot,
108                           &timer,
109                           time_out,
110                           timer_flag_oneshot[i]);
111 
112             /* calc expect tick */
113             timer.expect_tick = rt_tick_get() + time_out;
114 
115             /* start timer */
116             result = rt_timer_start(&timer.static_timer);
117             uassert_true(result == RT_EOK);
118 
119             /* wait for timerout */
120             rt_thread_delay(3 * time_out + 1);
121 
122             uassert_true(timer.callbacks == 1);
123 
124             /* detach timer */
125             result = rt_timer_detach(&timer.static_timer);
126             uassert_true(result == RT_EOK);
127             timer.callbacks = 0;
128         }
129     }
130 
131     /* periodic timer test */
132     for (int time_out = 1; time_out < 10; time_out++)
133     {
134         for (int i = 0; i < sizeof(timer_flag_periodic); i++)
135         {
136             rt_timer_init(&timer.static_timer,
137                           "static_timer",
138                           timer_periodic,
139                           &timer,
140                           time_out,
141                           timer_flag_periodic[i]);
142 
143             /* calc expect tick */
144             timer.expect_tick = rt_tick_get() + time_out;
145 
146             /* start timer */
147             result = rt_timer_start(&timer.static_timer);
148             uassert_true(result == RT_EOK);
149 
150             /* wait for timerout */
151             rt_thread_delay(5 * time_out + 1);
152 
153             uassert_true(timer.callbacks >= 5);
154 
155             /* detach timer */
156             result = rt_timer_detach(&timer.static_timer);
157             uassert_true(result == RT_EOK);
158             timer.callbacks = 0;
159         }
160     }
161 }
162 
test_static_timer_start_twice(void)163 static void test_static_timer_start_twice(void)
164 {
165     rt_err_t result;
166 
167     timer.callbacks = 0;
168     timer.is_static = RT_TRUE;
169 
170     /* timer start twice test */
171     for (int time_out = 2; time_out < 10; time_out++)
172     {
173         for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
174         {
175             rt_timer_init(&timer.static_timer,
176                           "static_timer",
177                           timer_oneshot,
178                           &timer,
179                           time_out,
180                           timer_flag_oneshot[i]);
181 
182             /* calc expect tick */
183             timer.expect_tick = rt_tick_get() + time_out;
184 
185             /* start timer */
186             result = rt_timer_start(&timer.static_timer);
187             uassert_true(result == RT_EOK);
188 
189             rt_thread_delay(1);
190 
191             /* calc expect tick */
192             timer.expect_tick = rt_tick_get() + time_out;
193 
194             /* start timer */
195             result = rt_timer_start(&timer.static_timer);
196             uassert_true(result == RT_EOK);
197 
198             /* wait for timerout */
199             rt_thread_delay(3 * time_out + 1);
200 
201             uassert_true(timer.callbacks == 1);
202 
203             /* detach timer */
204             result = rt_timer_detach(&timer.static_timer);
205             uassert_true(result == RT_EOK);
206             timer.callbacks = 0;
207         }
208     }
209 }
210 
timer_control(void * param)211 static void timer_control(void *param)
212 {
213     rt_err_t result;
214     timer_struct *timer_call;
215     timer_call = (timer_struct *)param;
216     timer_call->callbacks++;
217 
218     uassert_true(rt_tick_get() == timer_call->expect_tick);
219 
220     /* periodic timer can stop */
221     if (timer_call->is_static)
222     {
223         result = rt_timer_stop(&timer_call->static_timer);
224     }
225     else
226     {
227         result = rt_timer_stop(timer_call->dynamic_timer);
228     }
229 
230     uassert_true(result == RT_EOK);
231 }
232 
test_static_timer_control(void)233 static void test_static_timer_control(void)
234 {
235     rt_err_t result;
236     int set_data;
237     int get_data;
238 
239     timer.callbacks = 0;
240     timer.is_static = RT_TRUE;
241 
242     rt_timer_init(&timer.static_timer,
243                   "static_timer",
244                   timer_control,
245                   &timer,
246                   5,
247                   RT_TIMER_FLAG_PERIODIC);
248 
249     /* test set data */
250     set_data = 10;
251     result = rt_timer_control(&timer.static_timer, RT_TIMER_CTRL_SET_TIME, &set_data);
252 
253     uassert_true(result == RT_EOK);
254 
255     /* test get data */
256     result = rt_timer_control(&timer.static_timer, RT_TIMER_CTRL_GET_TIME, &get_data);
257 
258     uassert_true(result == RT_EOK);
259     uassert_true(set_data == get_data);
260 
261     /* calc expect tick */
262     timer.expect_tick = rt_tick_get() + set_data;
263 
264     /* start timer */
265     result = rt_timer_start(&timer.static_timer);
266     uassert_true(result == RT_EOK);
267 
268     rt_thread_delay(3 * set_data + 1);
269 
270     /* detach timer */
271     result = rt_timer_detach(&timer.static_timer);
272     uassert_true(result == RT_EOK);
273     uassert_true(timer.callbacks == 1);
274 }
275 
timer_start_in_callback(void * param)276 static void timer_start_in_callback(void *param)
277 {
278     rt_err_t result;
279     timer_struct *timer_call;
280     timer_call = (timer_struct *)param;
281     timer_call->callbacks++;
282 
283     uassert_true(rt_tick_get() == timer_call->expect_tick);
284 
285     if (timer_call->is_static)
286     {
287         timer_call->expect_tick = rt_tick_get() + timer_call->static_timer.init_tick;
288         result = rt_timer_start(&timer_call->static_timer);
289     }
290     else
291     {
292         timer_call->expect_tick = rt_tick_get() + timer_call->dynamic_timer->init_tick;
293         result = rt_timer_start(timer_call->dynamic_timer);
294     }
295 
296     uassert_true(result == RT_EOK);
297 }
298 
timer_start_stop_in_callback(void * param)299 static void timer_start_stop_in_callback(void *param)
300 {
301     rt_err_t result;
302     timer_struct *timer_call;
303     timer_call = (timer_struct *)param;
304     timer_call->callbacks++;
305 
306     uassert_true(rt_tick_get() == timer_call->expect_tick);
307 
308     if (timer_call->is_static)
309     {
310         result = rt_timer_start(&timer_call->static_timer);
311     }
312     else
313     {
314         result = rt_timer_start(timer_call->dynamic_timer);
315     }
316 
317     uassert_true(result == RT_EOK);
318 
319     if (timer_call->is_static)
320     {
321         result = rt_timer_stop(&timer_call->static_timer);
322     }
323     else
324     {
325         result = rt_timer_stop(timer_call->dynamic_timer);
326     }
327 
328     uassert_true(result == RT_EOK);
329 }
330 
test_static_timer_op_in_callback(void)331 static void test_static_timer_op_in_callback(void)
332 {
333     rt_err_t result;
334 
335     timer.callbacks = 0;
336     timer.is_static = RT_TRUE;
337 
338     /* start in callback test */
339     for (int time_out = 1; time_out < 10; time_out++)
340     {
341         for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
342         {
343             rt_timer_init(&timer.static_timer,
344                           "static_timer",
345                           timer_start_in_callback,
346                           &timer,
347                           time_out,
348                           timer_flag_oneshot[i]);
349 
350             /* calc expect tick */
351             timer.expect_tick = rt_tick_get() + time_out;
352 
353             /* start timer */
354             result = rt_timer_start(&timer.static_timer);
355             uassert_true(result == RT_EOK);
356 
357             /* wait for timerout */
358             rt_thread_delay(5 * time_out + 1);
359 
360             uassert_true(timer.callbacks >= 5);
361 
362             /* detach timer */
363             result = rt_timer_detach(&timer.static_timer);
364             uassert_true(result == RT_EOK);
365 
366             timer.callbacks = 0;
367         }
368     }
369 
370     /* start & stop in callback test */
371     for (int time_out = 1; time_out < 10; time_out++)
372     {
373         for (int i = 0; i < sizeof(timer_flag_periodic); i++)
374         {
375             rt_timer_init(&timer.static_timer,
376                           "static_timer",
377                           timer_start_stop_in_callback,
378                           &timer,
379                           time_out,
380                           timer_flag_periodic[i]);
381 
382             /* calc expect tick */
383             timer.expect_tick = rt_tick_get() + time_out;
384 
385             /* start timer */
386             result = rt_timer_start(&timer.static_timer);
387 
388             uassert_true(result == RT_EOK);
389 
390             /* wait for timerout */
391             rt_thread_delay(3 * time_out + 1);
392 
393             uassert_true(timer.callbacks == 1);
394 
395             /* detach timer */
396             result = rt_timer_detach(&timer.static_timer);
397 
398             uassert_true(result == RT_EOK);
399 
400             timer.callbacks = 0;
401         }
402     }
403 }
404 
405 #ifdef RT_USING_HEAP
406 
test_dynamic_timer(void)407 static void test_dynamic_timer(void)
408 {
409     rt_err_t result;
410 
411     timer.callbacks = 0;
412     timer.is_static = RT_FALSE;
413 
414     /* one shot timer test */
415     for (int time_out = 1; time_out < 10; time_out++)
416     {
417         for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
418         {
419             timer.dynamic_timer = rt_timer_create("dynamic_timer",
420                                                   timer_oneshot,
421                                                   &timer,
422                                                   time_out,
423                                                   timer_flag_oneshot[i]);
424 
425             /* calc expect tick */
426             timer.expect_tick = rt_tick_get() + time_out;
427 
428             /* start timer */
429             result = rt_timer_start(timer.dynamic_timer);
430             uassert_true(result == RT_EOK);
431 
432             /* wait for timerout */
433             rt_thread_delay(3 * time_out + 1);
434             uassert_true(timer.callbacks == 1);
435 
436             /* detach timer */
437             result = rt_timer_delete(timer.dynamic_timer);
438             uassert_true(result == RT_EOK);
439             timer.callbacks = 0;
440         }
441     }
442 
443     /* periodic timer test */
444     for (int time_out = 1; time_out < 10; time_out++)
445     {
446         for (int i = 0; i < sizeof(timer_flag_periodic); i++)
447         {
448             timer.dynamic_timer = rt_timer_create("dynamic_timer",
449                                                   timer_periodic,
450                                                   &timer,
451                                                   time_out,
452                                                   timer_flag_periodic[i]);
453 
454             /* calc expect tick */
455             timer.expect_tick = rt_tick_get() + time_out;
456 
457             /* start timer */
458             result = rt_timer_start(timer.dynamic_timer);
459             uassert_true(result == RT_EOK);
460 
461             /* wait for timerout */
462             rt_thread_delay(5 * time_out + 1);
463             uassert_true(timer.callbacks >= 5);
464 
465             /* detach timer */
466             result = rt_timer_delete(timer.dynamic_timer);
467             uassert_true(result == RT_EOK);
468             timer.callbacks = 0;
469         }
470     }
471 }
472 
test_dynamic_timer_control(void)473 static void test_dynamic_timer_control(void)
474 {
475     rt_err_t result;
476     int set_data;
477     int get_data;
478 
479     timer.callbacks = 0;
480     timer.is_static = RT_FALSE;
481 
482     timer.dynamic_timer = rt_timer_create("dynamic_timer",
483                                           timer_control,
484                                           &timer,
485                                           5,
486                                           RT_TIMER_FLAG_PERIODIC);
487 
488     /* test set data */
489     set_data = 10;
490     result = rt_timer_control(timer.dynamic_timer, RT_TIMER_CTRL_SET_TIME, &set_data);
491     uassert_true(result == RT_EOK);
492 
493     /* test get data */
494     result = rt_timer_control(timer.dynamic_timer, RT_TIMER_CTRL_GET_TIME, &get_data);
495 
496     uassert_true(result == RT_EOK);
497     uassert_true(set_data == get_data);
498 
499     /* calc expect tick */
500     timer.expect_tick = rt_tick_get() + set_data;
501 
502     /* start timer */
503     result = rt_timer_start(timer.dynamic_timer);
504     uassert_true(result == RT_EOK);
505 
506     rt_thread_delay(3 * set_data + 1);
507 
508     /* detach timer */
509     result = rt_timer_delete(timer.dynamic_timer);
510     uassert_true(result == RT_EOK);
511     uassert_true(timer.callbacks == 1);
512 }
513 
test_dynamic_timer_start_twice(void)514 static void test_dynamic_timer_start_twice(void)
515 {
516     rt_err_t result;
517 
518     timer.callbacks = 0;
519     timer.is_static = RT_FALSE;
520 
521     /* timer start twice test */
522     for (int time_out = 2; time_out < 10; time_out++)
523     {
524         for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
525         {
526             timer.dynamic_timer = rt_timer_create("dynamic_timer",
527                                           timer_oneshot,
528                                           &timer,
529                                           time_out,
530                                           timer_flag_oneshot[i]);
531             /* calc expect tick */
532             timer.expect_tick = rt_tick_get() + time_out;
533 
534             /* start timer */
535             result = rt_timer_start(timer.dynamic_timer);
536             uassert_true(result == RT_EOK);
537 
538             rt_thread_delay(1);
539 
540             /* calc expect tick */
541             timer.expect_tick = rt_tick_get() + time_out;
542 
543             /* start timer */
544             result = rt_timer_start(timer.dynamic_timer);
545             uassert_true(result == RT_EOK);
546 
547             /* wait for timerout */
548             rt_thread_delay(3 * time_out + 1);
549 
550             uassert_true(timer.callbacks == 1);
551 
552             /* detach timer */
553             result = rt_timer_delete(timer.dynamic_timer);
554             uassert_true(result == RT_EOK);
555             timer.callbacks = 0;
556         }
557     }
558 }
559 
test_dynamic_timer_op_in_callback(void)560 static void test_dynamic_timer_op_in_callback(void)
561 {
562     rt_err_t result;
563 
564     timer.callbacks = 0;
565     timer.is_static = RT_FALSE;
566 
567     /* start in callback test */
568     for (int time_out = 1; time_out < 10; time_out++)
569     {
570         for (int i = 0; i < sizeof(timer_flag_oneshot); i++)
571         {
572             timer.dynamic_timer = rt_timer_create("dynamic_timer",
573                                       timer_start_in_callback,
574                                       &timer,
575                                       time_out,
576                                       timer_flag_oneshot[i]);
577 
578             /* calc expect tick */
579             timer.expect_tick = rt_tick_get() + time_out;
580 
581             /* start timer */
582             result = rt_timer_start(timer.dynamic_timer);
583             uassert_true(result == RT_EOK);
584 
585             /* wait for timerout */
586             rt_thread_delay(5 * time_out + 1);
587 
588             uassert_true(timer.callbacks >= 5);
589 
590             /* detach timer */
591             result = rt_timer_delete(timer.dynamic_timer);
592             uassert_true(result == RT_EOK);
593 
594             timer.callbacks = 0;
595         }
596     }
597 
598     /* start & stop in callback test */
599     for (int time_out = 1; time_out < 10; time_out++)
600     {
601         for (int i = 0; i < sizeof(timer_flag_periodic); i++)
602         {
603             timer.dynamic_timer = rt_timer_create("dynamic_timer",
604                                       timer_start_stop_in_callback,
605                                       &timer,
606                                       time_out,
607                                       timer_flag_periodic[i]);
608             /* calc expect tick */
609             timer.expect_tick = rt_tick_get() + time_out;
610 
611             /* start timer */
612             result = rt_timer_start(timer.dynamic_timer);
613 
614             uassert_true(result == RT_EOK);
615 
616             /* wait for timerout */
617             rt_thread_delay(3 * time_out + 1);
618 
619             uassert_true(timer.callbacks == 1);
620 
621             /* detach timer */
622             result = rt_timer_delete(timer.dynamic_timer);
623 
624             uassert_true(result == RT_EOK);
625 
626             timer.callbacks = 0;
627         }
628     }
629 }
630 #endif /* RT_USING_HEAP */
631 
632 #define TEST_TIME_S 60      // test 60 seconds
633 #define STRESS_TIMERS 100
634 
635 static struct rt_timer stress_timer[STRESS_TIMERS];
636 
timer_stress(void * param)637 static void timer_stress(void *param)
638 {
639     rt_timer_t stress_timer = (rt_timer_t)param;
640 
641     if (rand() % 2 == 0)
642     {
643         rt_timer_start(stress_timer);
644     }
645     else
646     {
647         rt_timer_stop(stress_timer);
648     }
649 }
650 
test_timer_stress(void)651 static void test_timer_stress(void)
652 {
653     rt_tick_t start;
654     rt_ubase_t iters = 0;
655     rt_ubase_t cur_tick;
656     rt_ubase_t next_print_time;
657 
658     LOG_I("timer stress test begin, it will take %d seconds", 3*TEST_TIME_S);
659 
660     for (int i = 0; i < sizeof(timer_flag_periodic); i++)
661     {
662         for (int j = 0; j < STRESS_TIMERS; j++)
663         {
664             rt_timer_init(&stress_timer[j],
665                   "stress_timer",
666                   timer_stress,
667                   &stress_timer[j],
668                   j + 1,
669                   timer_flag_periodic[i]);
670         }
671 
672         start = rt_tick_get();
673         cur_tick = rt_tick_get();
674         next_print_time = cur_tick + RT_TICK_PER_SECOND;
675         while (cur_tick - start <= TEST_TIME_S * RT_TICK_PER_SECOND)
676         {
677             for (int j = 0; j < STRESS_TIMERS; j++)
678             {
679                 if (rand() % 2 == 0)
680                 {
681                     rt_timer_start(&stress_timer[j]);
682                 }
683                 else
684                 {
685                     rt_timer_stop(&stress_timer[j]);
686                 }
687             }
688             iters ++;
689             cur_tick = rt_tick_get();
690             if (cur_tick > next_print_time)
691             {
692                 PRINT_PROGRESS(next_print_time);
693                 next_print_time = cur_tick + RT_TICK_PER_SECOND;
694             }
695         }
696 
697         for (int j = 0; j < STRESS_TIMERS; j++)
698         {
699             rt_timer_detach(&stress_timer[j]);
700         }
701     }
702 
703     LOG_I("success after %lu iterations", iters);
704 }
705 
utest_tc_init(void)706 static rt_err_t utest_tc_init(void)
707 {
708     timer.dynamic_timer = RT_NULL;
709     timer.callbacks = 0;
710 
711     return RT_EOK;
712 }
713 
utest_tc_cleanup(void)714 static rt_err_t utest_tc_cleanup(void)
715 {
716     timer.dynamic_timer = RT_NULL;
717     timer.callbacks = 0;
718 
719     return RT_EOK;
720 }
721 
testcase(void)722 static void testcase(void)
723 {
724     UTEST_UNIT_RUN(test_static_timer);
725     PRINT_PROGRESS(__LINE__);
726     UTEST_UNIT_RUN(test_static_timer_control);
727     PRINT_PROGRESS(__LINE__);
728     UTEST_UNIT_RUN(test_static_timer_start_twice);
729     PRINT_PROGRESS(__LINE__);
730     UTEST_UNIT_RUN(test_static_timer_op_in_callback);
731     PRINT_PROGRESS(__LINE__);
732 #ifdef RT_USING_HEAP
733     UTEST_UNIT_RUN(test_dynamic_timer);
734     PRINT_PROGRESS(__LINE__);
735     UTEST_UNIT_RUN(test_dynamic_timer_control);
736     PRINT_PROGRESS(__LINE__);
737     UTEST_UNIT_RUN(test_dynamic_timer_start_twice);
738     PRINT_PROGRESS(__LINE__);
739     UTEST_UNIT_RUN(test_dynamic_timer_op_in_callback);
740     PRINT_PROGRESS(__LINE__);
741 #endif /* RT_USING_HEAP */
742     UTEST_UNIT_RUN(test_timer_stress);
743     PRINT_PROGRESS(__LINE__);
744 }
745 UTEST_TC_EXPORT(testcase, "testcases.kernel.timer_tc", utest_tc_init, utest_tc_cleanup, 1000);
746 
747 /*********************** end of file ****************************/
748