Marco Zecchini
/
Example_RTOS
Rtos API example
Diff: mbed-os/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp
- Revision:
- 0:9fca2b23d0ba
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os/TESTS/mbedmicro-rtos-mbed/rtostimer/main.cpp Sat Feb 23 12:13:36 2019 +0000 @@ -0,0 +1,349 @@ +/* mbed Microcontroller Library + * Copyright (c) 2017 ARM Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "mbed.h" +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" +#include "rtos.h" + +using namespace utest::v1; + +#define DELAY_MS 50 +#define DELTA_MS 5 +#define RESTART_DELAY_MS 10 +#define DELAY2_MS 30 + +#if RESTART_DELAY_MS >= DELAY_MS +#error invalid RESTART_DELAY_MS value +#endif + +class Stopwatch: public Timer { +private: + Semaphore _sem; + +public: + Stopwatch() : + Timer(), _sem(1) + { + } + + ~Stopwatch() + { + } + + void start(void) + { + _sem.wait(0); + Timer::start(); + } + + void stop(void) + { + Timer::stop(); + _sem.release(); + } + + int32_t wait_until_stopped(uint32_t millisec = osWaitForever) + { + core_util_critical_section_enter(); + int running = _running; + core_util_critical_section_exit(); + if (!running) { + return 1; + } + return _sem.wait(millisec); + } +}; + +void sem_callback(Semaphore *sem) +{ + sem->release(); +} + +/* In order to successfully run this test suite when compiled with --profile=debug + * error() has to be redefined as noop. + * + * RtosTimer calls RTX API which uses Event Recorder functionality. When compiled + * with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxTimerError() calls error() + * which aborts test program. + */ +#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED +void error(const char* format, ...) +{ + (void) format; +} +#endif + +/** Test one-shot not restarted when elapsed + * + * Given a one-shot RtosTimer + * When the timer is started + * and given time elapses + * Then timer stops + * and elapsed time matches given delay + * and timer stays stopped + */ +void test_oneshot_not_restarted() +{ + Stopwatch stopwatch; + RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerOnce); + + stopwatch.start(); + osStatus status = rtostimer.start(DELAY_MS); + TEST_ASSERT_EQUAL(osOK, status); + + int32_t slots = stopwatch.wait_until_stopped(); + TEST_ASSERT_EQUAL(1, slots); + TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, stopwatch.read_ms()); + stopwatch.start(); + + slots = stopwatch.wait_until_stopped(DELAY_MS + DELTA_MS); + TEST_ASSERT_EQUAL(0, slots); + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osErrorResource, status); +} + +/** Test periodic repeats continuously + * + * Given a periodic RtosTimer + * When timer is started + * and given time elapses + * Then timer repeats its operation + * When timer is stopped + * Then timer stops operation + */ +void test_periodic_repeats() +{ + Stopwatch stopwatch; + RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerPeriodic); + + stopwatch.start(); + osStatus status = rtostimer.start(DELAY_MS); + TEST_ASSERT_EQUAL(osOK, status); + + int32_t slots = stopwatch.wait_until_stopped(); + int t1 = stopwatch.read_ms(); + stopwatch.reset(); + stopwatch.start(); + TEST_ASSERT_EQUAL(1, slots); + TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, t1); + + slots = stopwatch.wait_until_stopped(); + TEST_ASSERT_EQUAL(1, slots); + TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY_MS, stopwatch.read_ms()); + stopwatch.start(); + + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osOK, status); + + slots = stopwatch.wait_until_stopped(DELAY_MS + DELTA_MS); + TEST_ASSERT_EQUAL(0, slots); + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osErrorResource, status); +} + +/** Test timer can be started again + * + * Given a one-shot Rtosimer + * When the timer is started + * and given time elapses + * Then timer stops + * When the timer is started again + * and given time elapses + * Then timer stops again + */ +void test_start_again() +{ + Semaphore sem(0, 1); + RtosTimer rtostimer(mbed::callback(sem_callback, &sem), osTimerOnce); + + osStatus status = rtostimer.start(DELAY_MS); + TEST_ASSERT_EQUAL(osOK, status); + + int32_t slots = sem.wait(DELAY_MS + DELTA_MS); + TEST_ASSERT_EQUAL(1, slots); + + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osErrorResource, status); + + status = rtostimer.start(DELAY_MS); + TEST_ASSERT_EQUAL(osOK, status); + + slots = sem.wait(DELAY_MS + DELTA_MS); + TEST_ASSERT_EQUAL(1, slots); + + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osErrorResource, status); +} + +/** Test timer restart updates delay + * + * Given a one-shot RtosTimer + * When the timer is started + * and @a start is called again with a different delay before given time elapses + * and updated delay elapses + * Then timer stops + * and time elapsed since the second @a start call matches updated delay + */ +void test_restart_updates_delay() +{ + Stopwatch stopwatch; + RtosTimer rtostimer(mbed::callback(&stopwatch, &Stopwatch::stop), osTimerOnce); + + stopwatch.start(); + osStatus status = rtostimer.start(DELAY_MS); + TEST_ASSERT_EQUAL(osOK, status); + + int32_t slots = stopwatch.wait_until_stopped(RESTART_DELAY_MS); + TEST_ASSERT_EQUAL(0, slots); + + stopwatch.reset(); + stopwatch.start(); + status = rtostimer.start(DELAY2_MS); + TEST_ASSERT_EQUAL(osOK, status); + + slots = stopwatch.wait_until_stopped(); + TEST_ASSERT_EQUAL(1, slots); + TEST_ASSERT_INT_WITHIN(DELTA_MS, DELAY2_MS, stopwatch.read_ms()); + + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osErrorResource, status); +} + +/** Test timer is created in stopped state + * + * Given a one-shot RtosTimer + * When the timer has not been started + * Then the timer is stopped + */ +void test_created_stopped() +{ + RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce); + osStatus status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osErrorResource, status); +} + +/** Test one-shot can be stopped + * + * Given a one-shot RtosTimer + * When the timer is started + * and timer is stopped while still running + * Then timer stops operation + */ +void test_stop() +{ + Semaphore sem(0, 1); + RtosTimer rtostimer(mbed::callback(sem_callback, &sem), osTimerOnce); + + osStatus status = rtostimer.start(DELAY_MS); + TEST_ASSERT_EQUAL(osOK, status); + + int32_t slots = sem.wait(RESTART_DELAY_MS); + TEST_ASSERT_EQUAL(0, slots); + + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osOK, status); + + slots = sem.wait(DELAY_MS + DELTA_MS); + TEST_ASSERT_EQUAL(0, slots); + + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osErrorResource, status); +} + +/** Test timer started with infinite delay + * + * Given a one-shot RtosTimer + * When the timer is started with @a osWaitForever delay + * Then @a start return status is @a osOK + */ +void test_wait_forever() +{ + RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce); + + osStatus status = rtostimer.start(osWaitForever); + TEST_ASSERT_EQUAL(osOK, status); + + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osOK, status); +} + +/** Test timer started with zero delay + * + * Given a one-shot RtosTimer + * When the timer is started with 0 delay + * Then @a start return status is @a osErrorParameter + */ +void test_no_wait() +{ + RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce); + + osStatus status = rtostimer.start(0); + TEST_ASSERT_EQUAL(osErrorParameter, status); + + status = rtostimer.stop(); + TEST_ASSERT_EQUAL(osErrorResource, status); +} + +void rtostimer_isr_call(RtosTimer *rtostimer) +{ + osStatus status = rtostimer->start(DELAY_MS); + TEST_ASSERT_EQUAL(osErrorISR, status); + + status = rtostimer->stop(); + TEST_ASSERT_EQUAL(osErrorISR, status); +} + +/** Test timer method calls from an ISR fail + * + * Given a one-shot RtosTimer + * When a timer method is called from an ISR + * Then method return status is @a osErrorISR + */ +void test_isr_calls_fail() +{ + RtosTimer rtostimer(mbed::callback(sem_callback, (Semaphore *) NULL), osTimerOnce); + + Ticker ticker; + ticker.attach(mbed::callback(rtostimer_isr_call, &rtostimer), (float) DELAY_MS / 1000.0); + + wait_ms(DELAY_MS + DELTA_MS); +} + +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(5, "default_auto"); + return verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("One-shot not restarted when elapsed", test_oneshot_not_restarted), + Case("Periodic repeats continuously", test_periodic_repeats), + Case("Stopped timer can be started again", test_start_again), + Case("Restart changes timeout", test_restart_updates_delay), + Case("Timer can be stopped", test_stop), + Case("Timer is created in stopped state", test_created_stopped), + Case("Timer started with infinite delay", test_wait_forever), + Case("Timer started with zero delay", test_no_wait), + Case("Calls from ISR fail", test_isr_calls_fail) +}; + +Specification specification(test_setup, cases); + +int main() +{ + return !Harness::run(specification); +}