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