Knight KE / Mbed OS Game_Master
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers main.cpp Source File

main.cpp

00001 /* mbed Microcontroller Library
00002  * Copyright (c) 2017 ARM Limited
00003  *
00004  * Licensed under the Apache License, Version 2.0 (the "License");
00005  * you may not use this file except in compliance with the License.
00006  * You may obtain a copy of the License at
00007  *
00008  *     http://www.apache.org/licenses/LICENSE-2.0
00009  *
00010  * Unless required by applicable law or agreed to in writing, software
00011  * distributed under the License is distributed on an "AS IS" BASIS,
00012  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013  * See the License for the specific language governing permissions and
00014  * limitations under the License.
00015  */
00016 #include "mbed.h"
00017 #include "greentea-client/test_env.h"
00018 #include "unity.h"
00019 #include "utest.h"
00020 #include "rtos.h"
00021 
00022 using namespace utest::v1;
00023 
00024 #define DELAY_MS 50
00025 #define DELTA_MS 5
00026 #define RESTART_DELAY_MS 10
00027 #define DELAY2_MS 30
00028 
00029 #if RESTART_DELAY_MS >= DELAY_MS
00030 #error invalid RESTART_DELAY_MS value
00031 #endif
00032 
00033 #if !DEVICE_USTICKER
00034   #error [NOT_SUPPORTED] test not supported
00035 #endif
00036 
00037 class Stopwatch: public Timer {
00038 private:
00039     Semaphore _sem;
00040 
00041 public:
00042     Stopwatch() :
00043             Timer(), _sem(1)
00044     {
00045     }
00046 
00047     ~Stopwatch()
00048     {
00049     }
00050 
00051     void start(void)
00052     {
00053         _sem.wait(0);
00054         Timer::start();
00055     }
00056 
00057     void stop(void)
00058     {
00059         Timer::stop();
00060         _sem.release();
00061     }
00062 
00063     int32_t wait_until_stopped(uint32_t millisec = osWaitForever)
00064     {
00065         core_util_critical_section_enter();
00066         int running = _running;
00067         core_util_critical_section_exit();
00068         if (!running) {
00069             return 1;
00070         }
00071         return _sem.wait(millisec);
00072     }
00073 };
00074 
00075 void sem_callback(Semaphore *sem)
00076 {
00077     sem->release();
00078 }
00079 
00080 /* In order to successfully run this test suite when compiled with --profile=debug
00081  * error() has to be redefined as noop.
00082  *
00083  * RtosTimer calls RTX API which uses Event Recorder functionality. When compiled
00084  * with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxTimerError() calls error()
00085  * which aborts test program.
00086  */
00087 #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED
00088 void error(const char* format, ...)
00089 {
00090     (void) format;
00091 }
00092 
00093 mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value, const char *filename, int line_number) 
00094 {
00095     return MBED_SUCCESS;
00096 }
00097 #endif
00098 
00099 /** Test one-shot not restarted when elapsed
00100  *
00101  * Given a one-shot RtosTimer
00102  * When the timer is started
00103  *     and given time elapses
00104  * Then timer stops
00105  *     and elapsed time matches given delay
00106  *     and timer stays stopped
00107  */
00108 void test_oneshot_not_restarted()
00109 {
00110     Stopwatch stopwatch;
00111     RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerOnce);
00112 
00113     stopwatch.start();
00114     osStatus status = rtostimer.start(DELAY_MS);
00115     TEST_ASSERT_EQUAL(osOK, status);
00116 
00117     int32_t slots = stopwatch.wait_until_stopped();
00118     TEST_ASSERT_EQUAL(1, slots);
00119     TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, stopwatch.read_ms());
00120     stopwatch.start();
00121 
00122     slots = stopwatch.wait_until_stopped(DELAY_MS + DELTA_MS);
00123     TEST_ASSERT_EQUAL(0, slots);
00124     status = rtostimer.stop();
00125     TEST_ASSERT_EQUAL(osErrorResource, status);
00126 }
00127 
00128 /** Test periodic repeats continuously
00129  *
00130  * Given a periodic RtosTimer
00131  * When timer is started
00132  *     and given time elapses
00133  * Then timer repeats its operation
00134  * When timer is stopped
00135  * Then timer stops operation
00136  */
00137 void test_periodic_repeats()
00138 {
00139     Stopwatch stopwatch;
00140     RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerPeriodic);
00141 
00142     stopwatch.start();
00143     osStatus status = rtostimer.start(DELAY_MS);
00144     TEST_ASSERT_EQUAL(osOK, status);
00145 
00146     int32_t slots = stopwatch.wait_until_stopped();
00147     int t1 = stopwatch.read_ms();
00148     stopwatch.reset();
00149     stopwatch.start();
00150     TEST_ASSERT_EQUAL(1, slots);
00151     TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, t1);
00152 
00153     slots = stopwatch.wait_until_stopped();
00154     TEST_ASSERT_EQUAL(1, slots);
00155     TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, stopwatch.read_ms());
00156     stopwatch.start();
00157 
00158     status = rtostimer.stop();
00159     TEST_ASSERT_EQUAL(osOK, status);
00160 
00161     slots = stopwatch.wait_until_stopped(DELAY_MS + DELTA_MS);
00162     TEST_ASSERT_EQUAL(0, slots);
00163     status = rtostimer.stop();
00164     TEST_ASSERT_EQUAL(osErrorResource, status);
00165 }
00166 
00167 /** Test timer can be started again
00168  *
00169  * Given a one-shot Rtosimer
00170  * When the timer is started
00171  *     and given time elapses
00172  * Then timer stops
00173  * When the timer is started again
00174  *     and given time elapses
00175  * Then timer stops again
00176  */
00177 void test_start_again()
00178 {
00179     Semaphore sem(0, 1);
00180     RtosTimer rtostimer(mbed::callback(sem_callback, &sem), osTimerOnce);
00181 
00182     osStatus status = rtostimer.start(DELAY_MS);
00183     TEST_ASSERT_EQUAL(osOK, status);
00184 
00185     int32_t slots = sem.wait(DELAY_MS + DELTA_MS);
00186     TEST_ASSERT_EQUAL(1, slots);
00187 
00188     status = rtostimer.stop();
00189     TEST_ASSERT_EQUAL(osErrorResource, status);
00190 
00191     status = rtostimer.start(DELAY_MS);
00192     TEST_ASSERT_EQUAL(osOK, status);
00193 
00194     slots = sem.wait(DELAY_MS + DELTA_MS);
00195     TEST_ASSERT_EQUAL(1, slots);
00196 
00197     status = rtostimer.stop();
00198     TEST_ASSERT_EQUAL(osErrorResource, status);
00199 }
00200 
00201 /** Test timer restart updates delay
00202  *
00203  * Given a one-shot RtosTimer
00204  * When the timer is started
00205  *     and @a start is called again with a different delay before given time elapses
00206  *     and updated delay elapses
00207  * Then timer stops
00208  *     and time elapsed since the second @a start call matches updated delay
00209  */
00210 void test_restart_updates_delay()
00211 {
00212     Stopwatch stopwatch;
00213     RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerOnce);
00214 
00215     stopwatch.start();
00216     osStatus status = rtostimer.start(DELAY_MS);
00217     TEST_ASSERT_EQUAL(osOK, status);
00218 
00219     int32_t slots = stopwatch.wait_until_stopped(RESTART_DELAY_MS);
00220     TEST_ASSERT_EQUAL(0, slots);
00221 
00222     stopwatch.reset();
00223     stopwatch.start();
00224     status = rtostimer.start(DELAY2_MS);
00225     TEST_ASSERT_EQUAL(osOK, status);
00226 
00227     slots = stopwatch.wait_until_stopped();
00228     TEST_ASSERT_EQUAL(1, slots);
00229     TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY2_MS, stopwatch.read_ms());
00230 
00231     status = rtostimer.stop();
00232     TEST_ASSERT_EQUAL(osErrorResource, status);
00233 }
00234 
00235 /** Test timer is created in stopped state
00236  *
00237  * Given a one-shot RtosTimer
00238  * When the timer has not been started
00239  * Then the timer is stopped
00240  */
00241 void test_created_stopped()
00242 {
00243     RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce);
00244     osStatus status = rtostimer.stop();
00245     TEST_ASSERT_EQUAL(osErrorResource, status);
00246 }
00247 
00248 /** Test one-shot can be stopped
00249  *
00250  * Given a one-shot RtosTimer
00251  * When the timer is started
00252  *     and timer is stopped while still running
00253  * Then timer stops operation
00254  */
00255 void test_stop()
00256 {
00257     Semaphore sem(0, 1);
00258     RtosTimer rtostimer(mbed::callback(sem_callback, &sem), osTimerOnce);
00259 
00260     osStatus status = rtostimer.start(DELAY_MS);
00261     TEST_ASSERT_EQUAL(osOK, status);
00262 
00263     int32_t slots = sem.wait(RESTART_DELAY_MS);
00264     TEST_ASSERT_EQUAL(0, slots);
00265 
00266     status = rtostimer.stop();
00267     TEST_ASSERT_EQUAL(osOK, status);
00268 
00269     slots = sem.wait(DELAY_MS + DELTA_MS);
00270     TEST_ASSERT_EQUAL(0, slots);
00271 
00272     status = rtostimer.stop();
00273     TEST_ASSERT_EQUAL(osErrorResource, status);
00274 }
00275 
00276 /** Test timer started with infinite delay
00277  *
00278  * Given a one-shot RtosTimer
00279  * When the timer is started with @a osWaitForever delay
00280  * Then @a start return status is @a osOK
00281  */
00282 void test_wait_forever()
00283 {
00284     RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce);
00285 
00286     osStatus status = rtostimer.start(osWaitForever);
00287     TEST_ASSERT_EQUAL(osOK, status);
00288 
00289     status = rtostimer.stop();
00290     TEST_ASSERT_EQUAL(osOK, status);
00291 }
00292 
00293 /** Test timer started with zero delay
00294  *
00295  * Given a one-shot RtosTimer
00296  * When the timer is started with 0 delay
00297  * Then @a start return status is @a osErrorParameter
00298  */
00299 void test_no_wait()
00300 {
00301     RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce);
00302 
00303     osStatus status = rtostimer.start(0);
00304     TEST_ASSERT_EQUAL(osErrorParameter, status);
00305 
00306     status = rtostimer.stop();
00307     TEST_ASSERT_EQUAL(osErrorResource, status);
00308 }
00309 
00310 void rtostimer_isr_call(RtosTimer *rtostimer)
00311 {
00312     osStatus status = rtostimer->start(DELAY_MS);
00313     TEST_ASSERT_EQUAL(osErrorISR, status);
00314 
00315     status = rtostimer->stop();
00316     TEST_ASSERT_EQUAL(osErrorISR, status);
00317 }
00318 
00319 /** Test timer method calls from an ISR fail
00320  *
00321  * Given a one-shot RtosTimer
00322  * When a timer method is called from an ISR
00323  * Then method return status is @a osErrorISR
00324  */
00325 void test_isr_calls_fail()
00326 {
00327     RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce);
00328 
00329     Ticker ticker;
00330     ticker.attach(mbed::callback(rtostimer_isr_call, &rtostimer), (float) DELAY_MS / 1000.0);
00331 
00332     wait_ms(DELAY_MS + DELTA_MS);
00333 }
00334 
00335 utest::v1::status_t test_setup(const size_t number_of_cases)
00336 {
00337     GREENTEA_SETUP(5, "default_auto");
00338     return verbose_test_setup_handler(number_of_cases);
00339 }
00340 
00341 Case cases[] = {
00342     Case("One-shot not restarted when elapsed", test_oneshot_not_restarted),
00343     Case("Periodic repeats continuously", test_periodic_repeats),
00344     Case("Stopped timer can be started again", test_start_again),
00345     Case("Restart changes timeout", test_restart_updates_delay),
00346     Case("Timer can be stopped", test_stop),
00347     Case("Timer is created in stopped state", test_created_stopped),
00348     Case("Timer started with infinite delay", test_wait_forever),
00349     Case("Timer started with zero delay", test_no_wait),
00350     Case("Calls from ISR fail", test_isr_calls_fail)
00351 };
00352 
00353 Specification specification(test_setup, cases);
00354 
00355 int main()
00356 {
00357     return !Harness::run(specification);
00358 }