ChibiOS/RT Architecture - Reference Manual - Guides |
00001 /* 00002 ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio. 00003 00004 This file is part of ChibiOS/RT. 00005 00006 ChibiOS/RT is free software; you can redistribute it and/or modify 00007 it under the terms of the GNU General Public License as published by 00008 the Free Software Foundation; either version 3 of the License, or 00009 (at your option) any later version. 00010 00011 ChibiOS/RT is distributed in the hope that it will be useful, 00012 but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 GNU General Public License for more details. 00015 00016 You should have received a copy of the GNU General Public License 00017 along with this program. If not, see <http://www.gnu.org/licenses/>. 00018 00019 --- 00020 00021 A special exception to the GPL can be applied should you wish to distribute 00022 a combined work that includes ChibiOS/RT, without being obliged to provide 00023 the source code for any proprietary components. See the file exception.txt 00024 for full details of how and when the exception can be applied. 00025 */ 00026 00027 /** 00028 * @file test.c 00029 * @brief Tests support code. 00030 * 00031 * @addtogroup test 00032 * @{ 00033 */ 00034 00035 #include "ch.h" 00036 #include "hal.h" 00037 00038 #include "test.h" 00039 #include "testthd.h" 00040 #include "testsem.h" 00041 #include "testmtx.h" 00042 #include "testmsg.h" 00043 #include "testmbox.h" 00044 #include "testevt.h" 00045 #include "testheap.h" 00046 #include "testpools.h" 00047 #include "testdyn.h" 00048 #include "testqueues.h" 00049 #include "testbmk.h" 00050 00051 /* 00052 * Array of all the test patterns. 00053 */ 00054 static const struct testcase **patterns[] = { 00055 patternthd, 00056 patternsem, 00057 patternmtx, 00058 patternmsg, 00059 patternmbox, 00060 patternevt, 00061 patternheap, 00062 patternpools, 00063 patterndyn, 00064 patternqueues, 00065 patternbmk, 00066 NULL 00067 }; 00068 00069 static bool_t local_fail, global_fail; 00070 static unsigned failpoint; 00071 static char tokens_buffer[MAX_TOKENS]; 00072 static char *tokp; 00073 00074 /* 00075 * Static working areas, the following areas can be used for threads or 00076 * used as temporary buffers. 00077 */ 00078 union test_buffers test; 00079 00080 /* 00081 * Pointers to the spawned threads. 00082 */ 00083 Thread *threads[MAX_THREADS]; 00084 00085 /* 00086 * Pointers to the working areas. 00087 */ 00088 void * const wa[5] = {test.wa.T0, test.wa.T1, test.wa.T2, 00089 test.wa.T3, test.wa.T4}; 00090 00091 /* 00092 * Console output. 00093 */ 00094 static BaseChannel *chp; 00095 00096 /** 00097 * @brief Prints a decimal unsigned number. 00098 * 00099 * @param[in] n the number to be printed 00100 */ 00101 void test_printn(uint32_t n) { 00102 char buf[16], *p; 00103 00104 if (!n) 00105 chIOPut(chp, '0'); 00106 else { 00107 p = buf; 00108 while (n) 00109 *p++ = (n % 10) + '0', n /= 10; 00110 while (p > buf) 00111 chIOPut(chp, *--p); 00112 } 00113 } 00114 00115 /** 00116 * @brief Prints a line without final end-of-line. 00117 * 00118 * @param[in] msgp the message 00119 */ 00120 void test_print(char *msgp) { 00121 00122 while (*msgp) 00123 chIOPut(chp, *msgp++); 00124 } 00125 00126 /** 00127 * @brief Prints a line. 00128 * 00129 * @param[in] msgp the message 00130 */ 00131 void test_println(char *msgp) { 00132 00133 test_print(msgp); 00134 chIOPut(chp, '\r'); 00135 chIOPut(chp, '\n'); 00136 } 00137 00138 /* 00139 * Tokens. 00140 */ 00141 static void clear_tokens(void) { 00142 00143 tokp = tokens_buffer; 00144 } 00145 00146 static void print_tokens(void) { 00147 char *cp = tokens_buffer; 00148 00149 while (cp < tokp) 00150 chIOPut(chp, *cp++); 00151 } 00152 00153 /** 00154 * @brief Emits a token into the tokens buffer. 00155 * 00156 * @param[in] token the token as a char 00157 */ 00158 void test_emit_token(char token) { 00159 00160 chSysLock(); 00161 *tokp++ = token; 00162 chSysUnlock(); 00163 } 00164 00165 /* 00166 * Assertions. 00167 */ 00168 bool_t _test_fail(unsigned point) { 00169 00170 local_fail = TRUE; 00171 global_fail = TRUE; 00172 failpoint = point; 00173 return TRUE; 00174 } 00175 00176 bool_t _test_assert(unsigned point, bool_t condition) { 00177 00178 if (!condition) 00179 return _test_fail(point); 00180 return FALSE; 00181 } 00182 00183 bool_t _test_assert_sequence(unsigned point, char *expected) { 00184 char *cp = tokens_buffer; 00185 while (cp < tokp) { 00186 if (*cp++ != *expected++) 00187 return _test_fail(point); 00188 } 00189 if (*expected) 00190 return _test_fail(point); 00191 clear_tokens(); 00192 return FALSE; 00193 } 00194 00195 bool_t _test_assert_time_window(unsigned point, systime_t start, systime_t end) { 00196 00197 return _test_assert(point, chTimeIsWithin(start, end)); 00198 } 00199 00200 /* 00201 * Threads utils. 00202 */ 00203 00204 /** 00205 * @brief Pends a termination request in all the test-spawned threads. 00206 */ 00207 void test_terminate_threads(void) { 00208 int i; 00209 00210 for (i = 0; i < MAX_THREADS; i++) 00211 if (threads[i]) 00212 chThdTerminate(threads[i]); 00213 } 00214 00215 /** 00216 * @brief Waits for the completion of all the test-spawned threads. 00217 */ 00218 void test_wait_threads(void) { 00219 int i; 00220 00221 for (i = 0; i < MAX_THREADS; i++) 00222 if (threads[i] != NULL) { 00223 chThdWait(threads[i]); 00224 threads[i] = NULL; 00225 } 00226 } 00227 00228 #if CH_DBG_THREADS_PROFILING 00229 /** 00230 * @brief CPU pulse. 00231 * @note The current implementation is not totally reliable. 00232 * 00233 * @param[in] duration CPU pulse duration in milliseconds 00234 */ 00235 void test_cpu_pulse(unsigned duration) { 00236 systime_t start, end, now; 00237 00238 start = chThdSelf()->p_time; 00239 end = start + MS2ST(duration); 00240 do { 00241 now = chThdSelf()->p_time; 00242 #if defined(SIMULATOR) 00243 ChkIntSources(); 00244 #endif 00245 } 00246 while (end > start ? (now >= start) && (now < end) : 00247 (now >= start) || (now < end)); 00248 } 00249 #endif 00250 00251 /** 00252 * @brief Delays execution until next system time tick. 00253 */ 00254 systime_t test_wait_tick(void) { 00255 00256 chThdSleep(1); 00257 return chTimeNow(); 00258 } 00259 00260 /* 00261 * Timer utils. 00262 */ 00263 00264 /** @brief Set to @p TRUE when the test timer reaches its deadline.*/ 00265 bool_t test_timer_done; 00266 00267 static VirtualTimer vt; 00268 static void tmr(void *p) { 00269 (void)p; 00270 00271 test_timer_done = TRUE; 00272 } 00273 00274 /** 00275 * @brief Starts the test timer. 00276 * 00277 * @param[in] ms time in milliseconds 00278 */ 00279 void test_start_timer(unsigned ms) { 00280 00281 systime_t duration = MS2ST(ms); 00282 test_timer_done = FALSE; 00283 chSysLock(); 00284 chVTSetI(&vt, duration, tmr, NULL); 00285 chSysUnlock(); 00286 } 00287 00288 /* 00289 * Test suite execution. 00290 */ 00291 static void execute_test(const struct testcase *tcp) { 00292 int i; 00293 00294 /* Initialization */ 00295 clear_tokens(); 00296 local_fail = FALSE; 00297 for (i = 0; i < MAX_THREADS; i++) 00298 threads[i] = NULL; 00299 00300 if (tcp->setup != NULL) 00301 tcp->setup(); 00302 tcp->execute(); 00303 if (tcp->teardown != NULL) 00304 tcp->teardown(); 00305 00306 test_wait_threads(); 00307 } 00308 00309 static void print_line(void) { 00310 unsigned i; 00311 00312 for (i = 0; i < 76; i++) 00313 chIOPut(chp, '-'); 00314 chIOPut(chp, '\r'); 00315 chIOPut(chp, '\n'); 00316 } 00317 00318 /** 00319 * @brief Test execution thread function. 00320 * 00321 * @param[in] p pointer to a @p BaseChannel object for test output 00322 */ 00323 msg_t TestThread(void *p) { 00324 int i, j; 00325 00326 chp = p; 00327 test_println(""); 00328 test_println("*** ChibiOS/RT test suite"); 00329 test_println("***"); 00330 test_print("*** Kernel: "); 00331 test_println(CH_KERNEL_VERSION); 00332 #ifdef __GNUC__ 00333 test_print("*** GCC Version: "); 00334 test_println(__VERSION__); 00335 #endif 00336 test_print("*** Architecture: "); 00337 test_println(CH_ARCHITECTURE_NAME); 00338 #ifdef CH_CORE_VARIANT_NAME 00339 test_print("*** Core Variant: "); 00340 test_println(CH_CORE_VARIANT_NAME); 00341 #endif 00342 #ifdef PLATFORM_NAME 00343 test_print("*** Platform: "); 00344 test_println(PLATFORM_NAME); 00345 #endif 00346 #ifdef BOARD_NAME 00347 test_print("*** Test Board: "); 00348 test_println(BOARD_NAME); 00349 #endif 00350 test_println(""); 00351 00352 global_fail = FALSE; 00353 i = 0; 00354 while (patterns[i]) { 00355 j = 0; 00356 while (patterns[i][j]) { 00357 print_line(); 00358 test_print("--- Test Case "); 00359 test_printn(i + 1); 00360 test_print("."); 00361 test_printn(j + 1); 00362 test_print(" ("); 00363 test_print(patterns[i][j]->gettest()); 00364 test_println(")"); 00365 #if DELAY_BETWEEN_TESTS > 0 00366 chThdSleepMilliseconds(DELAY_BETWEEN_TESTS); 00367 #endif 00368 execute_test(patterns[i][j]); 00369 if (local_fail) { 00370 test_print("--- Result: FAILURE (#"); 00371 test_printn(failpoint); 00372 test_print(" ["); 00373 print_tokens(); 00374 test_println("])"); 00375 } 00376 else 00377 test_println("--- Result: SUCCESS"); 00378 j++; 00379 } 00380 i++; 00381 } 00382 print_line(); 00383 test_println(""); 00384 test_print("Final result: "); 00385 if (global_fail) 00386 test_println("FAILURE"); 00387 else 00388 test_println("SUCCESS"); 00389 00390 return (msg_t)global_fail; 00391 } 00392 00393 /** @} */