1
0

tc_comm.c 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. /*
  2. * Copyright (c) 2006-2021, RT-Thread Development Team
  3. *
  4. * SPDX-License-Identifier: Apache-2.0
  5. *
  6. * Change Logs:
  7. *
  8. */
  9. #include "tc_comm.h"
  10. #ifdef RT_USING_FINSH
  11. #include <finsh.h>
  12. #endif
  13. #ifdef RT_USING_TC
  14. #define TC_PRIORITY 25
  15. #define TC_STACK_SIZE 0x400
  16. static rt_uint8_t _tc_stat;
  17. static struct rt_semaphore _tc_sem;
  18. static struct rt_thread _tc_thread;
  19. static rt_uint8_t _tc_stack[TC_STACK_SIZE];
  20. static char _tc_prefix[64];
  21. static const char* _tc_current;
  22. static void (*_tc_cleanup)(void) = RT_NULL;
  23. static rt_uint32_t _tc_scale = 1;
  24. static rt_uint32_t _tc_loop;
  25. void tc_thread_entry(void* parameter)
  26. {
  27. unsigned int fail_count = 0;
  28. struct finsh_syscall* index;
  29. /* create tc semaphore */
  30. rt_sem_init(&_tc_sem, "tc", 0, RT_IPC_FLAG_PRIO);
  31. do {
  32. for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index))
  33. {
  34. /* search testcase */
  35. if (rt_strstr(index->name, _tc_prefix) == index->name)
  36. {
  37. long tick;
  38. _tc_current = index->name + 4;
  39. rt_kprintf("Run TestCase: %s\n", _tc_current);
  40. _tc_stat = TC_STAT_PASSED | TC_STAT_RUNNING;
  41. tick = index->func();
  42. if (tick > 0)
  43. {
  44. /* Make sure we are going to be blocked. */
  45. rt_sem_control(&_tc_sem, RT_IPC_CMD_RESET, 0);
  46. rt_sem_take(&_tc_sem, tick * _tc_scale);
  47. }
  48. if (_tc_cleanup != RT_NULL)
  49. {
  50. /* perform testcase cleanup */
  51. _tc_cleanup();
  52. _tc_cleanup = RT_NULL;
  53. }
  54. if (_tc_stat & TC_STAT_RUNNING)
  55. {
  56. rt_kprintf("TestCase[%s] exit with stat TC_STAT_RUNNING."
  57. " Please fix the TC.\n",
  58. _tc_current);
  59. /* If the TC forgot to clear the flag, we do it. */
  60. _tc_stat &= ~TC_STAT_RUNNING;
  61. }
  62. if (_tc_stat & TC_STAT_FAILED)
  63. {
  64. rt_kprintf("TestCase[%s] failed\n", _tc_current);
  65. fail_count++;
  66. }
  67. else
  68. {
  69. rt_kprintf("TestCase[%s] passed\n", _tc_current);
  70. }
  71. }
  72. }
  73. } while (_tc_loop);
  74. rt_kprintf("RT-Thread TestCase Running Done!\n");
  75. if (fail_count)
  76. {
  77. rt_kprintf("%d tests failed\n", fail_count);
  78. }
  79. else
  80. {
  81. rt_kprintf("All tests passed\n");
  82. }
  83. /* detach tc semaphore */
  84. rt_sem_detach(&_tc_sem);
  85. }
  86. void tc_stop()
  87. {
  88. _tc_loop = 0;
  89. rt_thread_delay(10 * RT_TICK_PER_SECOND);
  90. if (_tc_thread.stat != RT_THREAD_INIT)
  91. {
  92. /* lock scheduler */
  93. rt_enter_critical();
  94. /* detach old tc thread */
  95. rt_thread_detach(&_tc_thread);
  96. rt_sem_detach(&_tc_sem);
  97. /* unlock scheduler */
  98. rt_exit_critical();
  99. }
  100. rt_thread_delay(RT_TICK_PER_SECOND/2);
  101. }
  102. FINSH_FUNCTION_EXPORT(tc_stop, stop testcase thread);
  103. void tc_done(rt_uint8_t stat)
  104. {
  105. _tc_stat |= stat;
  106. _tc_stat &= ~TC_STAT_RUNNING;
  107. /* release semaphore */
  108. rt_sem_release(&_tc_sem);
  109. }
  110. void tc_stat(rt_uint8_t stat)
  111. {
  112. if (stat & TC_STAT_FAILED)
  113. {
  114. rt_kprintf("TestCases[%s] failed\n", _tc_current);
  115. }
  116. _tc_stat |= stat;
  117. }
  118. void tc_cleanup(void (*cleanup)())
  119. {
  120. _tc_cleanup = cleanup;
  121. }
  122. void tc_start(const char* tc_prefix)
  123. {
  124. rt_err_t result;
  125. /* tesecase prefix is null */
  126. if (tc_prefix == RT_NULL)
  127. {
  128. rt_kprintf("TestCase Usage: tc_start(prefix)\n\n");
  129. rt_kprintf("list_tc() can list all testcases.\n");
  130. return ;
  131. }
  132. /* init tc thread */
  133. if (_tc_stat & TC_STAT_RUNNING)
  134. {
  135. /* stop old tc thread */
  136. tc_stop();
  137. }
  138. rt_memset(_tc_prefix, 0, sizeof(_tc_prefix));
  139. rt_snprintf(_tc_prefix, sizeof(_tc_prefix), "_tc_%s", tc_prefix);
  140. result = rt_thread_init(&_tc_thread, "tc",
  141. tc_thread_entry, RT_NULL,
  142. &_tc_stack[0], sizeof(_tc_stack),
  143. TC_PRIORITY - 3, 5);
  144. /* set tc stat */
  145. _tc_stat = TC_STAT_RUNNING | TC_STAT_FAILED;
  146. if (result == RT_EOK)
  147. rt_thread_startup(&_tc_thread);
  148. }
  149. FINSH_FUNCTION_EXPORT(tc_start, start testcase with testcase prefix or name);
  150. void tc_loop(const char *tc_prefix)
  151. {
  152. _tc_loop = 1;
  153. tc_start(tc_prefix);
  154. }
  155. FINSH_FUNCTION_EXPORT(tc_loop, start testcase with testcase prefix or name in loop mode);
  156. void list_tc()
  157. {
  158. struct finsh_syscall* index;
  159. rt_kprintf("TestCases List:\n");
  160. for (index = _syscall_table_begin; index < _syscall_table_end; FINSH_NEXT_SYSCALL(index))
  161. {
  162. /* search testcase */
  163. if (rt_strstr(index->name, "_tc_") == index->name)
  164. {
  165. #ifdef FINSH_USING_DESCRIPTION
  166. rt_kprintf("%-16s -- %s\n", index->name + 4, index->desc);
  167. #else
  168. rt_kprintf("%s\n", index->name + 4);
  169. #endif
  170. }
  171. }
  172. }
  173. FINSH_FUNCTION_EXPORT(list_tc, list all testcases);
  174. #endif