Marco Mayer / Mbed OS Queue
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 class Stopwatch: public Timer {
00034 private:
00035     Semaphore _sem;
00036 
00037 public:
00038     Stopwatch() :
00039             Timer(), _sem(1)
00040     {
00041     }
00042 
00043     ~Stopwatch()
00044     {
00045     }
00046 
00047     void start(void)
00048     {
00049         _sem.wait(0);
00050         Timer::start();
00051     }
00052 
00053     void stop(void)
00054     {
00055         Timer::stop();
00056         _sem.release();
00057     }
00058 
00059     int32_t wait_until_stopped(uint32_t millisec = osWaitForever)
00060     {
00061         core_util_critical_section_enter();
00062         int running = _running;
00063         core_util_critical_section_exit();
00064         if (!running) {
00065             return 1;
00066         }
00067         return _sem.wait(millisec);
00068     }
00069 };
00070 
00071 void sem_callback(Semaphore *sem)
00072 {
00073     sem->release();
00074 }
00075 
00076 /* In order to successfully run this test suite when compiled with --profile=debug
00077  * error() has to be redefined as noop.
00078  *
00079  * RtosTimer calls RTX API which uses Event Recorder functionality. When compiled
00080  * with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxTimerError() calls error()
00081  * which aborts test program.
00082  */
00083 #if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED
00084 void error(const char* format, ...)
00085 {
00086     (void) format;
00087 }
00088 #endif
00089 
00090 /** Test one-shot not restarted when elapsed
00091  *
00092  * Given a one-shot RtosTimer
00093  * When the timer is started
00094  *     and given time elapses
00095  * Then timer stops
00096  *     and elapsed time matches given delay
00097  *     and timer stays stopped
00098  */
00099 void test_oneshot_not_restarted()
00100 {
00101     Stopwatch stopwatch;
00102     RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerOnce);
00103 
00104     stopwatch.start();
00105     osStatus status = rtostimer.start(DELAY_MS);
00106     TEST_ASSERT_EQUAL(osOK, status);
00107 
00108     int32_t slots = stopwatch.wait_until_stopped();
00109     TEST_ASSERT_EQUAL(1, slots);
00110     TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, stopwatch.read_ms());
00111     stopwatch.start();
00112 
00113     slots = stopwatch.wait_until_stopped(DELAY_MS + DELTA_MS);
00114     TEST_ASSERT_EQUAL(0, slots);
00115     status = rtostimer.stop();
00116     TEST_ASSERT_EQUAL(osErrorResource, status);
00117 }
00118 
00119 /** Test periodic repeats continuously
00120  *
00121  * Given a periodic RtosTimer
00122  * When timer is started
00123  *     and given time elapses
00124  * Then timer repeats its operation
00125  * When timer is stopped
00126  * Then timer stops operation
00127  */
00128 void test_periodic_repeats()
00129 {
00130     Stopwatch stopwatch;
00131     RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerPeriodic);
00132 
00133     stopwatch.start();
00134     osStatus status = rtostimer.start(DELAY_MS);
00135     TEST_ASSERT_EQUAL(osOK, status);
00136 
00137     int32_t slots = stopwatch.wait_until_stopped();
00138     int t1 = stopwatch.read_ms();
00139     stopwatch.reset();
00140     stopwatch.start();
00141     TEST_ASSERT_EQUAL(1, slots);
00142     TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, t1);
00143 
00144     slots = stopwatch.wait_until_stopped();
00145     TEST_ASSERT_EQUAL(1, slots);
00146     TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, stopwatch.read_ms());
00147     stopwatch.start();
00148 
00149     status = rtostimer.stop();
00150     TEST_ASSERT_EQUAL(osOK, status);
00151 
00152     slots = stopwatch.wait_until_stopped(DELAY_MS + DELTA_MS);
00153     TEST_ASSERT_EQUAL(0, slots);
00154     status = rtostimer.stop();
00155     TEST_ASSERT_EQUAL(osErrorResource, status);
00156 }
00157 
00158 /** Test timer can be started again
00159  *
00160  * Given a one-shot Rtosimer
00161  * When the timer is started
00162  *     and given time elapses
00163  * Then timer stops
00164  * When the timer is started again
00165  *     and given time elapses
00166  * Then timer stops again
00167  */
00168 void test_start_again()
00169 {
00170     Semaphore sem(0, 1);
00171     RtosTimer rtostimer(mbed::callback(sem_callback, &sem), osTimerOnce);
00172 
00173     osStatus status = rtostimer.start(DELAY_MS);
00174     TEST_ASSERT_EQUAL(osOK, status);
00175 
00176     int32_t slots = sem.wait(DELAY_MS + DELTA_MS);
00177     TEST_ASSERT_EQUAL(1, slots);
00178 
00179     status = rtostimer.stop();
00180     TEST_ASSERT_EQUAL(osErrorResource, status);
00181 
00182     status = rtostimer.start(DELAY_MS);
00183     TEST_ASSERT_EQUAL(osOK, status);
00184 
00185     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 
00192 /** Test timer restart updates delay
00193  *
00194  * Given a one-shot RtosTimer
00195  * When the timer is started
00196  *     and @a start is called again with a different delay before given time elapses
00197  *     and updated delay elapses
00198  * Then timer stops
00199  *     and time elapsed since the second @a start call matches updated delay
00200  */
00201 void test_restart_updates_delay()
00202 {
00203     Stopwatch stopwatch;
00204     RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerOnce);
00205 
00206     stopwatch.start();
00207     osStatus status = rtostimer.start(DELAY_MS);
00208     TEST_ASSERT_EQUAL(osOK, status);
00209 
00210     int32_t slots = stopwatch.wait_until_stopped(RESTART_DELAY_MS);
00211     TEST_ASSERT_EQUAL(0, slots);
00212 
00213     stopwatch.reset();
00214     stopwatch.start();
00215     status = rtostimer.start(DELAY2_MS);
00216     TEST_ASSERT_EQUAL(osOK, status);
00217 
00218     slots = stopwatch.wait_until_stopped();
00219     TEST_ASSERT_EQUAL(1, slots);
00220     TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY2_MS, stopwatch.read_ms());
00221 
00222     status = rtostimer.stop();
00223     TEST_ASSERT_EQUAL(osErrorResource, status);
00224 }
00225 
00226 /** Test timer is created in stopped state
00227  *
00228  * Given a one-shot RtosTimer
00229  * When the timer has not been started
00230  * Then the timer is stopped
00231  */
00232 void test_created_stopped()
00233 {
00234     RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce);
00235     osStatus status = rtostimer.stop();
00236     TEST_ASSERT_EQUAL(osErrorResource, status);
00237 }
00238 
00239 /** Test one-shot can be stopped
00240  *
00241  * Given a one-shot RtosTimer
00242  * When the timer is started
00243  *     and timer is stopped while still running
00244  * Then timer stops operation
00245  */
00246 void test_stop()
00247 {
00248     Semaphore sem(0, 1);
00249     RtosTimer rtostimer(mbed::callback(sem_callback, &sem), osTimerOnce);
00250 
00251     osStatus status = rtostimer.start(DELAY_MS);
00252     TEST_ASSERT_EQUAL(osOK, status);
00253 
00254     int32_t slots = sem.wait(RESTART_DELAY_MS);
00255     TEST_ASSERT_EQUAL(0, slots);
00256 
00257     status = rtostimer.stop();
00258     TEST_ASSERT_EQUAL(osOK, status);
00259 
00260     slots = sem.wait(DELAY_MS + DELTA_MS);
00261     TEST_ASSERT_EQUAL(0, slots);
00262 
00263     status = rtostimer.stop();
00264     TEST_ASSERT_EQUAL(osErrorResource, status);
00265 }
00266 
00267 /** Test timer started with infinite delay
00268  *
00269  * Given a one-shot RtosTimer
00270  * When the timer is started with @a osWaitForever delay
00271  * Then @a start return status is @a osOK
00272  */
00273 void test_wait_forever()
00274 {
00275     RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce);
00276 
00277     osStatus status = rtostimer.start(osWaitForever);
00278     TEST_ASSERT_EQUAL(osOK, status);
00279 
00280     status = rtostimer.stop();
00281     TEST_ASSERT_EQUAL(osOK, status);
00282 }
00283 
00284 /** Test timer started with zero delay
00285  *
00286  * Given a one-shot RtosTimer
00287  * When the timer is started with 0 delay
00288  * Then @a start return status is @a osErrorParameter
00289  */
00290 void test_no_wait()
00291 {
00292     RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce);
00293 
00294     osStatus status = rtostimer.start(0);
00295     TEST_ASSERT_EQUAL(osErrorParameter, status);
00296 
00297     status = rtostimer.stop();
00298     TEST_ASSERT_EQUAL(osErrorResource, status);
00299 }
00300 
00301 void rtostimer_isr_call(RtosTimer *rtostimer)
00302 {
00303     osStatus status = rtostimer->start(DELAY_MS);
00304     TEST_ASSERT_EQUAL(osErrorISR, status);
00305 
00306     status = rtostimer->stop();
00307     TEST_ASSERT_EQUAL(osErrorISR, status);
00308 }
00309 
00310 /** Test timer method calls from an ISR fail
00311  *
00312  * Given a one-shot RtosTimer
00313  * When a timer method is called from an ISR
00314  * Then method return status is @a osErrorISR
00315  */
00316 void test_isr_calls_fail()
00317 {
00318     RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce);
00319 
00320     Ticker ticker;
00321     ticker.attach(mbed::callback(rtostimer_isr_call, &rtostimer), (float) DELAY_MS / 1000.0);
00322 
00323     wait_ms(DELAY_MS + DELTA_MS);
00324 }
00325 
00326 utest::v1::status_t test_setup(const size_t number_of_cases)
00327 {
00328     GREENTEA_SETUP(5, "default_auto");
00329     return verbose_test_setup_handler(number_of_cases);
00330 }
00331 
00332 Case cases[] = {
00333     Case("One-shot not restarted when elapsed", test_oneshot_not_restarted),
00334     Case("Periodic repeats continuously", test_periodic_repeats),
00335     Case("Stopped timer can be started again", test_start_again),
00336     Case("Restart changes timeout", test_restart_updates_delay),
00337     Case("Timer can be stopped", test_stop),
00338     Case("Timer is created in stopped state", test_created_stopped),
00339     Case("Timer started with infinite delay", test_wait_forever),
00340     Case("Timer started with zero delay", test_no_wait),
00341     Case("Calls from ISR fail", test_isr_calls_fail)
00342 };
00343 
00344 Specification specification(test_setup, cases);
00345 
00346 int main()
00347 {
00348     return !Harness::run(specification);
00349 }