mirror of https://github.com/ARMmbed/mbed-os.git
				
				
				
			
						commit
						cbb8a1f994
					
				| 
						 | 
				
			
			@ -0,0 +1,367 @@
 | 
			
		|||
/* 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 TEST_DELAY_MS 50
 | 
			
		||||
#define TEST_DELAY2_MS 30
 | 
			
		||||
#define TEST_DELAY_MS_DELTA 1
 | 
			
		||||
#define TEST_RESTART_DELAY_MS 10
 | 
			
		||||
 | 
			
		||||
#if TEST_RESTART_DELAY_MS >= TEST_DELAY_MS
 | 
			
		||||
#error invalid TEST_RESTART_DELAY_MS value
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
void timer_callback(void const *arg)
 | 
			
		||||
{
 | 
			
		||||
    Semaphore *sem = (Semaphore *) arg;
 | 
			
		||||
    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 timer
 | 
			
		||||
 * 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()
 | 
			
		||||
{
 | 
			
		||||
    Semaphore sem(1);
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
 | 
			
		||||
    osStatus stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
 | 
			
		||||
    Timer t;
 | 
			
		||||
    sem.wait(0);
 | 
			
		||||
    stat = timer.start(TEST_DELAY_MS);
 | 
			
		||||
    t.start();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    int32_t slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    t.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, slots);
 | 
			
		||||
    TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, TEST_DELAY_MS * 1000, t.read_us());
 | 
			
		||||
 | 
			
		||||
    slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, slots);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test periodic repeats continuously
 | 
			
		||||
 *
 | 
			
		||||
 * Given a periodic timer
 | 
			
		||||
 * 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()
 | 
			
		||||
{
 | 
			
		||||
    Semaphore sem(1);
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerPeriodic);
 | 
			
		||||
    osStatus stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
 | 
			
		||||
    Timer t;
 | 
			
		||||
    sem.wait(0);
 | 
			
		||||
    stat = timer.start(TEST_DELAY_MS);
 | 
			
		||||
    t.start();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    int32_t slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    int t1 = t.read_us();
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, slots);
 | 
			
		||||
    TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, TEST_DELAY_MS * 1000, t1);
 | 
			
		||||
 | 
			
		||||
    slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    t.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, slots);
 | 
			
		||||
    TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, TEST_DELAY_MS * 1000, t.read_us() - t1);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, slots);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test timer can be restarted
 | 
			
		||||
 *
 | 
			
		||||
 * Given a one-shot timer
 | 
			
		||||
 * When the timer is started
 | 
			
		||||
 *     and @a start is called again before given time elapses
 | 
			
		||||
 *     and given time elapses
 | 
			
		||||
 * Then timer stops
 | 
			
		||||
 *     and elapsed time is greater than original delay
 | 
			
		||||
 */
 | 
			
		||||
void test_restart()
 | 
			
		||||
{
 | 
			
		||||
    Semaphore sem(1);
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
 | 
			
		||||
    osStatus stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
 | 
			
		||||
    Timer t;
 | 
			
		||||
    sem.wait(0);
 | 
			
		||||
    stat = timer.start(TEST_DELAY_MS);
 | 
			
		||||
    t.start();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    int32_t slots = sem.wait(TEST_RESTART_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, slots);
 | 
			
		||||
 | 
			
		||||
    stat = timer.start(TEST_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    t.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, slots);
 | 
			
		||||
    TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, (TEST_DELAY_MS + TEST_RESTART_DELAY_MS) * 1000, t.read_us());
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test timer can be started again
 | 
			
		||||
 *
 | 
			
		||||
 * Given a one-shot timer
 | 
			
		||||
 * 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(1);
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
 | 
			
		||||
    osStatus stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
 | 
			
		||||
    sem.wait(0);
 | 
			
		||||
    stat = timer.start(TEST_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    int32_t slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, slots);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
 | 
			
		||||
    stat = timer.start(TEST_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, slots);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test timer restart updates delay
 | 
			
		||||
 *
 | 
			
		||||
 * Given a one-shot timer
 | 
			
		||||
 * 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()
 | 
			
		||||
{
 | 
			
		||||
    Semaphore sem(1);
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
 | 
			
		||||
    osStatus stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
 | 
			
		||||
    sem.wait(0);
 | 
			
		||||
    stat = timer.start(TEST_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    int32_t slots = sem.wait(TEST_RESTART_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, slots);
 | 
			
		||||
 | 
			
		||||
    Timer t;
 | 
			
		||||
    stat = timer.start(TEST_DELAY2_MS);
 | 
			
		||||
    t.start();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    slots = sem.wait(TEST_DELAY2_MS + 1);
 | 
			
		||||
    t.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(1, slots);
 | 
			
		||||
    TEST_ASSERT_INT_WITHIN(TEST_DELAY_MS_DELTA * 1000, TEST_DELAY2_MS * 1000, t.read_us());
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test timer is created in stopped state
 | 
			
		||||
 *
 | 
			
		||||
 * Given a one-shot timer
 | 
			
		||||
 * When the timer has not been started
 | 
			
		||||
 * Then the timer is stopped
 | 
			
		||||
 */
 | 
			
		||||
void test_created_stopped()
 | 
			
		||||
{
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) NULL), osTimerOnce);
 | 
			
		||||
    osStatus stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test one-shot can be stopped
 | 
			
		||||
 *
 | 
			
		||||
 * Given a one-shot timer
 | 
			
		||||
 * When the timer is started
 | 
			
		||||
 *     and timer is stopped while still running
 | 
			
		||||
 * Then timer stops operation
 | 
			
		||||
 */
 | 
			
		||||
void test_stop()
 | 
			
		||||
{
 | 
			
		||||
    Semaphore sem(1);
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) &sem), osTimerOnce);
 | 
			
		||||
    osStatus stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
 | 
			
		||||
    sem.wait(0);
 | 
			
		||||
    stat = timer.start(TEST_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    int32_t slots = sem.wait(TEST_RESTART_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, slots);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    slots = sem.wait(TEST_DELAY_MS + 1);
 | 
			
		||||
    TEST_ASSERT_EQUAL(0, slots);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test timer started with infinite delay
 | 
			
		||||
 *
 | 
			
		||||
 * Given a one-shot timer
 | 
			
		||||
 * When the timer is started with @a osWaitForever delay
 | 
			
		||||
 * Then @a start return status is @a osOK
 | 
			
		||||
 */
 | 
			
		||||
void test_wait_forever()
 | 
			
		||||
{
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) NULL), osTimerOnce);
 | 
			
		||||
 | 
			
		||||
    osStatus stat = timer.start(osWaitForever);
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osOK, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test timer started with zero delay
 | 
			
		||||
 *
 | 
			
		||||
 * Given a one-shot timer
 | 
			
		||||
 * When the timer is started with 0 delay
 | 
			
		||||
 * Then @a start return status is @a osErrorParameter
 | 
			
		||||
 */
 | 
			
		||||
void test_no_wait()
 | 
			
		||||
{
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) NULL), osTimerOnce);
 | 
			
		||||
 | 
			
		||||
    osStatus stat = timer.start(0);
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorParameter, stat);
 | 
			
		||||
 | 
			
		||||
    stat = timer.stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorResource, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void timer_isr_call(void const *arg)
 | 
			
		||||
{
 | 
			
		||||
    RtosTimer *timer = (RtosTimer *) arg;
 | 
			
		||||
    osStatus stat = timer->start(TEST_DELAY_MS);
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorISR, stat);
 | 
			
		||||
 | 
			
		||||
    stat = timer->stop();
 | 
			
		||||
    TEST_ASSERT_EQUAL(osErrorISR, stat);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/** Test timer method calls from an ISR fail
 | 
			
		||||
 *
 | 
			
		||||
 * Given a one-shot timer
 | 
			
		||||
 * When a timer method is called from an ISR
 | 
			
		||||
 * Then method return status is @a osErrorISR
 | 
			
		||||
 */
 | 
			
		||||
void test_isr_calls_fail()
 | 
			
		||||
{
 | 
			
		||||
    RtosTimer timer(mbed::callback(timer_callback, (void const *) NULL), osTimerOnce);
 | 
			
		||||
 | 
			
		||||
    Ticker ticker;
 | 
			
		||||
    ticker.attach(mbed::callback(timer_isr_call, (void const *) &timer), (float) TEST_DELAY_MS / 1000.0);
 | 
			
		||||
 | 
			
		||||
    wait_ms(TEST_DELAY_MS + 1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
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("Test one-shot not restarted when elapsed", test_oneshot_not_restarted),
 | 
			
		||||
    Case("Test periodic repeats continuously", test_periodic_repeats),
 | 
			
		||||
    Case("Test timer can be restarted while running", test_restart),
 | 
			
		||||
    Case("Test stopped timer can be started again", test_start_again),
 | 
			
		||||
    Case("Test restart changes timeout", test_restart_updates_delay),
 | 
			
		||||
    Case("Test can be stopped", test_stop),
 | 
			
		||||
    Case("Test timer is created in stopped state", test_created_stopped),
 | 
			
		||||
    Case("Test timer started with infinite delay", test_wait_forever),
 | 
			
		||||
    Case("Test timer started with zero delay", test_no_wait),
 | 
			
		||||
    Case("Test calls from ISR fail", test_isr_calls_fail)
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
Specification specification(test_setup, cases);
 | 
			
		||||
 | 
			
		||||
int main()
 | 
			
		||||
{
 | 
			
		||||
    return !Harness::run(specification);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -131,13 +131,21 @@ public:
 | 
			
		|||
    }
 | 
			
		||||
 | 
			
		||||
    /** Stop the timer.
 | 
			
		||||
      @return  status code that indicates the execution status of the function.
 | 
			
		||||
      @return  status code that indicates the execution status of the function:
 | 
			
		||||
          @a osOK the timer has been stopped.
 | 
			
		||||
          @a osErrorISR @a stop cannot be called from interrupt service routines.
 | 
			
		||||
          @a osErrorParameter internal error.
 | 
			
		||||
          @a osErrorResource the timer is not running.
 | 
			
		||||
    */
 | 
			
		||||
    osStatus stop(void);
 | 
			
		||||
 | 
			
		||||
    /** Start the timer.
 | 
			
		||||
      @param   millisec  time delay value of the timer.
 | 
			
		||||
      @return  status code that indicates the execution status of the function.
 | 
			
		||||
    /** Start or restart the timer.
 | 
			
		||||
      @param   millisec  non-zero value of the timer.
 | 
			
		||||
      @return  status code that indicates the execution status of the function:
 | 
			
		||||
          @a osOK the timer has been started or restarted.
 | 
			
		||||
          @a osErrorISR @a start cannot be called from interrupt service routines.
 | 
			
		||||
          @a osErrorParameter internal error or incorrect parameter value.
 | 
			
		||||
          @a osErrorResource internal error (the timer is in an invalid timer state).
 | 
			
		||||
    */
 | 
			
		||||
    osStatus start(uint32_t millisec);
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue