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