Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Timeout rescheduling test #12942

Merged
merged 2 commits into from
May 15, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 13 additions & 27 deletions TESTS/mbed_drivers/lp_timeout/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,51 +37,37 @@ utest::v1::status_t greentea_failure_handler(const Case *const source, const fai
}

Case cases[] = {
Case("Callback called once (attach)", test_single_call<AttachTester<LowPowerTimeout> >),
Case("Callback called once (attach_us)", test_single_call<AttachUSTester<LowPowerTimeout> >),
Case("Callback called once", test_single_call<LowPowerTimeout>),

Case("Callback not called when cancelled (attach)", test_cancel<AttachTester<LowPowerTimeout> >),
Case("Callback not called when cancelled (attach_us)", test_cancel<AttachUSTester<LowPowerTimeout> >),
Case("Callback not called when cancelled", test_cancel<LowPowerTimeout>),

Case("Callback override (attach)", test_override<AttachTester<LowPowerTimeout> >),
Case("Callback override (attach_us)", test_override<AttachUSTester<LowPowerTimeout> >),
Case("Callback override", test_override<LowPowerTimeout>),

Case("Multiple timeouts running in parallel (attach)", test_multiple<AttachTester<LowPowerTimeout> >),
Case("Multiple timeouts running in parallel (attach_us)", test_multiple<AttachUSTester<LowPowerTimeout> >),
Case("Multiple timeouts running in parallel", test_multiple<LowPowerTimeout>),

Case("Zero delay (attach)", test_no_wait<AttachTester<LowPowerTimeout> >),
Case("Zero delay (attach_us)", test_no_wait<AttachUSTester<LowPowerTimeout> >),
Case("Zero delay", test_no_wait<LowPowerTimeout>),

Case("10 ms delay accuracy (attach)", test_delay_accuracy<AttachTester<LowPowerTimeout>, 10000, SHORT_DELTA_US>,
greentea_failure_handler),
Case("10 ms delay accuracy (attach_us)", test_delay_accuracy<AttachUSTester<LowPowerTimeout>, 10000, SHORT_DELTA_US>,
greentea_failure_handler),
Case("Reschedule in callback", test_reschedule<LowPowerTimeout>),

Case("1 s delay accuracy (attach)", test_delay_accuracy<AttachTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
Case("1 s delay accuracy (attach_us)", test_delay_accuracy<AttachUSTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
Case("10 ms delay accuracy", test_delay_accuracy<LowPowerTimeout, 10000, SHORT_DELTA_US>,
greentea_failure_handler),

Case("5 s delay accuracy (attach)", test_delay_accuracy<AttachTester<LowPowerTimeout>, 5000000, LONG_DELTA_US>,
Case("1 s delay accuracy (attach)", test_delay_accuracy<LowPowerTimeout, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
Case("5 s delay accuracy (attach_us)", test_delay_accuracy<AttachUSTester<LowPowerTimeout>, 5000000, LONG_DELTA_US>,

Case("5 s delay accuracy (attach)", test_delay_accuracy<LowPowerTimeout, 5000000, LONG_DELTA_US>,
greentea_failure_handler),

#if DEVICE_SLEEP
Case("1 s delay during sleep (attach)", test_sleep<AttachTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
Case("1 s delay during sleep (attach_us)", test_sleep<AttachUSTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
Case("1 s delay during sleep (attach)", test_sleep<LowPowerTimeout, 1000000, LONG_DELTA_US>,
greentea_failure_handler),

Case("1 s delay during deepsleep (attach)", test_deepsleep<AttachTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
Case("1 s delay during deepsleep (attach_us)", test_deepsleep<AttachUSTester<LowPowerTimeout>, 1000000, LONG_DELTA_US>,
Case("1 s delay during deepsleep (attach)", test_deepsleep<LowPowerTimeout, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
#endif

#if !defined(SKIP_TIME_DRIFT_TESTS)
Case("Timing drift (attach)", test_drift<AttachTester<LowPowerTimeout> >),
Case("Timing drift (attach_us)", test_drift<AttachUSTester<LowPowerTimeout> >),
Case("Timing drift (attach)", test_drift<LowPowerTimeout>),
#endif
};

Expand Down
36 changes: 12 additions & 24 deletions TESTS/mbed_drivers/timeout/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,46 +33,34 @@ utest::v1::status_t greentea_failure_handler(const Case *const source, const fai
}

Case cases[] = {
Case("Callback called once (attach)", test_single_call<AttachTester<Timeout> >),
Case("Callback called once (attach_us)", test_single_call<AttachUSTester<Timeout> >),
Case("Callback called once", test_single_call<Timeout>),

Case("Callback not called when cancelled (attach)", test_cancel<AttachTester<Timeout> >),
Case("Callback not called when cancelled (attach_us)", test_cancel<AttachUSTester<Timeout> >),
Case("Callback not called when cancelled", test_cancel<Timeout>),

Case("Callback override (attach)", test_override<AttachTester<Timeout> >),
Case("Callback override (attach_us)", test_override<AttachUSTester<Timeout> >),
Case("Callback override", test_override<Timeout>),

Case("Multiple timeouts running in parallel (attach)", test_multiple<AttachTester<Timeout> >),
Case("Multiple timeouts running in parallel (attach_us)", test_multiple<AttachUSTester<Timeout> >),
Case("Multiple timeouts running in parallel", test_multiple<Timeout>),

Case("Zero delay (attach)", test_no_wait<AttachTester<Timeout> >),
Case("Zero delay (attach_us)", test_no_wait<AttachUSTester<Timeout> >),
Case("Zero delay", test_no_wait<Timeout>),

Case("10 ms delay accuracy (attach)", test_delay_accuracy<AttachTester<Timeout>, 10000, SHORT_DELTA_US>,
greentea_failure_handler),
Case("10 ms delay accuracy (attach_us)", test_delay_accuracy<AttachUSTester<Timeout>, 10000, SHORT_DELTA_US>,
greentea_failure_handler),
Case("Reschedule in callback", test_reschedule<Timeout>),

Case("1 s delay accuracy (attach)", test_delay_accuracy<AttachTester<Timeout>, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
Case("1 s delay accuracy (attach_us)", test_delay_accuracy<AttachUSTester<Timeout>, 1000000, LONG_DELTA_US>,
Case("10 ms delay accuracy", test_delay_accuracy<Timeout, 10000, SHORT_DELTA_US>,
greentea_failure_handler),

Case("5 s delay accuracy (attach)", test_delay_accuracy<AttachTester<Timeout>, 5000000, LONG_DELTA_US>,
Case("1 s delay accuracy", test_delay_accuracy<Timeout, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
Case("5 s delay accuracy (attach_us)", test_delay_accuracy<AttachUSTester<Timeout>, 5000000, LONG_DELTA_US>,

Case("5 s delay accuracy", test_delay_accuracy<Timeout, 5000000, LONG_DELTA_US>,
greentea_failure_handler),

#if DEVICE_SLEEP
Case("1 s delay during sleep (attach)", test_sleep<AttachTester<Timeout>, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
Case("1 s delay during sleep (attach_us)", test_sleep<AttachUSTester<Timeout>, 1000000, LONG_DELTA_US>,
Case("1 s delay during sleep", test_sleep<Timeout, 1000000, LONG_DELTA_US>,
greentea_failure_handler),
#endif

#if !defined(SKIP_TIME_DRIFT_TESTS)
Case("Timing drift (attach)", test_drift<AttachTester<Timeout> >),
Case("Timing drift (attach_us)", test_drift<AttachUSTester<Timeout> >),
Case("Timing drift", test_drift<Timeout>),
#endif
};

Expand Down
98 changes: 50 additions & 48 deletions TESTS/mbed_drivers/timeout/timeout_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,12 @@
#include "mbed.h"
#include "unity/unity.h"

using namespace std::chrono;

#define NUM_TIMEOUTS 16
#define DRIFT_TEST_PERIOD_US 10000
const microseconds DRIFT_TEST_PERIOD = 10ms;

const float TEST_DELAY_S = 0.01;
const uint32_t TEST_DELAY_MS = 1000.0F * TEST_DELAY_S;
const us_timestamp_t TEST_DELAY_US = 1000000.0F * TEST_DELAY_S;
const milliseconds TEST_DELAY = 10ms;

/* Timeouts are quite arbitrary due to large number of boards with varying level of accuracy */
#define LONG_DELTA_US (100000)
Expand All @@ -41,24 +41,6 @@ void cnt_callback(volatile uint32_t *cnt)
(*cnt)++;
}

template<typename TimeoutType>
class AttachTester: public TimeoutType {
public:
void attach_callback(Callback<void()> func, us_timestamp_t delay_us)
{
TimeoutType::attach(func, (float) delay_us / 1000000.0f);
}
};

template<typename TimeoutType>
class AttachUSTester: public TimeoutType {
public:
void attach_callback(Callback<void()> func, us_timestamp_t delay_us)
{
TimeoutType::attach_us(func, delay_us);
}
};

/** Template for tests: callback called once
*
* Test callback called once
Expand All @@ -77,15 +59,15 @@ void test_single_call(void)
Semaphore sem(0, 1);
T timeout;

timeout.attach_callback(mbed::callback(sem_callback, &sem), TEST_DELAY_US);
timeout.attach(mbed::callback(sem_callback, &sem), TEST_DELAY);

bool acquired = sem.try_acquire();
TEST_ASSERT_FALSE(acquired);

acquired = sem.try_acquire_for(TEST_DELAY_MS + 2);
acquired = sem.try_acquire_for(TEST_DELAY + 2ms);
TEST_ASSERT_TRUE(acquired);

acquired = sem.try_acquire_for(TEST_DELAY_MS + 2);
acquired = sem.try_acquire_for(TEST_DELAY + 2ms);
TEST_ASSERT_FALSE(acquired);

timeout.detach();
Expand All @@ -109,13 +91,13 @@ void test_cancel(void)
Semaphore sem(0, 1);
T timeout;

timeout.attach_callback(mbed::callback(sem_callback, &sem), 2.0f * TEST_DELAY_US);
timeout.attach(mbed::callback(sem_callback, &sem), 2 * TEST_DELAY);

bool acquired = sem.try_acquire_for(TEST_DELAY_MS);
bool acquired = sem.try_acquire_for(TEST_DELAY);
TEST_ASSERT_FALSE(acquired);
timeout.detach();

acquired = sem.try_acquire_for(TEST_DELAY_MS + 2);
acquired = sem.try_acquire_for(TEST_DELAY + 2ms);
TEST_ASSERT_FALSE(acquired);
}

Expand All @@ -142,13 +124,13 @@ void test_override(void)
Semaphore sem2(0, 1);
T timeout;

timeout.attach_callback(mbed::callback(sem_callback, &sem1), 2.0f * TEST_DELAY_US);
timeout.attach(mbed::callback(sem_callback, &sem1), 2 * TEST_DELAY);

bool acquired = sem1.try_acquire_for(TEST_DELAY_MS);
bool acquired = sem1.try_acquire_for(TEST_DELAY);
TEST_ASSERT_FALSE(acquired);
timeout.attach_callback(mbed::callback(sem_callback, &sem2), 2.0f * TEST_DELAY_US);
timeout.attach(mbed::callback(sem_callback, &sem2), 2 * TEST_DELAY);

acquired = sem2.try_acquire_for(2 * TEST_DELAY_MS + 2);
acquired = sem2.try_acquire_for(2 * TEST_DELAY + 2ms);
TEST_ASSERT_TRUE(acquired);
acquired = sem1.try_acquire();
TEST_ASSERT_FALSE(acquired);
Expand Down Expand Up @@ -176,9 +158,9 @@ void test_multiple(void)
volatile uint32_t callback_count = 0;
T timeouts[NUM_TIMEOUTS];
for (size_t i = 0; i < NUM_TIMEOUTS; i++) {
timeouts[i].attach_callback(mbed::callback(cnt_callback, &callback_count), TEST_DELAY_US);
timeouts[i].attach(mbed::callback(cnt_callback, &callback_count), TEST_DELAY);
}
ThisThread::sleep_for(TEST_DELAY_MS + 2);
ThisThread::sleep_for(TEST_DELAY + 2ms);
TEST_ASSERT_EQUAL(NUM_TIMEOUTS, callback_count);
}

Expand All @@ -200,7 +182,7 @@ void test_no_wait(void)
for (int i = 0; i < 100; i++) {
Semaphore sem(0, 1);
T timeout;
timeout.attach_callback(mbed::callback(sem_callback, &sem), 0ULL);
timeout.attach(mbed::callback(sem_callback, &sem), 0s);
bool sem_acquired = sem.try_acquire();
TEST_ASSERT_EQUAL(true, sem_acquired);
timeout.detach();
Expand All @@ -227,11 +209,11 @@ void test_delay_accuracy(void)
Timer timer;

timer.start();
timeout.attach_callback(mbed::callback(sem_callback, &sem), delay_us);
timeout.attach(mbed::callback(sem_callback, &sem), microseconds(delay_us));

sem.acquire();
timer.stop();
TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.read_high_resolution_us());
TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.elapsed_time().count());

timeout.detach();
}
Expand Down Expand Up @@ -262,15 +244,15 @@ void test_sleep(void)

sleep_manager_lock_deep_sleep();
timer.start();
timeout.attach_callback(mbed::callback(sem_callback, &sem), delay_us);
timeout.attach(mbed::callback(sem_callback, &sem), microseconds(delay_us));

bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_FALSE_MESSAGE(deep_sleep_allowed, "Deep sleep should be disallowed");
sem.acquire();
timer.stop();

sleep_manager_unlock_deep_sleep();
TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.read_high_resolution_us());
TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.elapsed_time().count());

timeout.detach();
}
Expand Down Expand Up @@ -316,17 +298,17 @@ void test_deepsleep(void)
* hardware buffers are empty. However, such an API does not exist now,
* so we'll use the ThisThread::sleep_for() function for now.
*/
ThisThread::sleep_for(20);
ThisThread::sleep_for(20ms);

timer.start();
timeout.attach_callback(mbed::callback(sem_callback, &sem), delay_us);
timeout.attach(mbed::callback(sem_callback, &sem), microseconds(delay_us));

bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_TRUE_MESSAGE(deep_sleep_allowed, "Deep sleep should be allowed");
sem.acquire();
timer.stop();

TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.read_high_resolution_us());
TEST_ASSERT_UINT64_WITHIN(delta_us, delay_us, timer.elapsed_time().count());

timeout.detach();
}
Expand All @@ -336,14 +318,14 @@ void test_deepsleep(void)
template<typename TimeoutTesterType>
class TimeoutDriftTester {
public:
TimeoutDriftTester(us_timestamp_t period = 1000) :
TimeoutDriftTester(microseconds period = 1ms) :
_callback_count(0), _period(period), _timeout()
{
}

void reschedule_callback(void)
{
_timeout.attach_callback(mbed::callback(this, &TimeoutDriftTester::reschedule_callback), _period);
_timeout.attach(mbed::callback(this, &TimeoutDriftTester::reschedule_callback), _period);
_callback_count++;
}

Expand All @@ -359,10 +341,30 @@ class TimeoutDriftTester {

private:
volatile uint32_t _callback_count;
us_timestamp_t _period;
microseconds _period;
TimeoutTesterType _timeout;
};

/** Template for tests: rescheduling
*
* Given a Timeout object
* When a callback is attached with that reattaches itself, with @a attach()
* Then the callback is called repeatedly
*
* Given a Timeout object
* When a callback is attached with that reattaches itself, with @a attach_us()
* Then the callback is called repeatedly
*/
template<typename T>
void test_reschedule(void)
{
TimeoutDriftTester<T> timeout(TEST_DELAY);

timeout.reschedule_callback();
ThisThread::sleep_for(TEST_DELAY * 5);
TEST_ASSERT(timeout.get_callback_count() >= 3);
}

/** Template for tests: accuracy of timeout delay scheduled repeatedly
*
* Test time drift -- device part
Expand All @@ -389,7 +391,7 @@ void test_drift(void)
char _key[11] = { };
char _value[128] = { };
int expected_key = 1;
TimeoutDriftTester<T> timeout(DRIFT_TEST_PERIOD_US);
TimeoutDriftTester<T> timeout(DRIFT_TEST_PERIOD);

greentea_send_kv("timing_drift_check_start", 0);
timeout.reschedule_callback();
Expand All @@ -400,11 +402,11 @@ void test_drift(void)
expected_key = strcmp(_key, "base_time");
} while (expected_key);

greentea_send_kv(_key, timeout.get_callback_count() * DRIFT_TEST_PERIOD_US);
greentea_send_kv(_key, timeout.get_callback_count() * DRIFT_TEST_PERIOD.count());

// wait for 2nd signal from host
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
greentea_send_kv(_key, timeout.get_callback_count() * DRIFT_TEST_PERIOD_US);
greentea_send_kv(_key, timeout.get_callback_count() * DRIFT_TEST_PERIOD.count());

timeout.detach_callback();

Expand Down