Extends test set for Ticker class (round 2)

pull/5261/head
Maciej Bocianski 2017-10-05 11:45:20 +02:00
parent 943fc32c73
commit aaa15bcf58
1 changed files with 265 additions and 99 deletions

View File

@ -1,24 +1,110 @@
/*
* Copyright (c) 2013-2016, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
/* mbed Microcontroller Library
* Copyright (c) 2013-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.
* 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
* 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.
* 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 "utest/utest.h"
#include "unity/unity.h"
/*
* Tests is to measure the accuracy of Ticker over a period of time
*
using utest::v1::Case;
#define ONE_MILLI_SEC 1000
#define TICKER_COUNT 16
#define MULTI_TICKER_TIME_MS 100
volatile uint32_t callback_trigger_count = 0;
static const int test_timeout = 240;
static const int total_ticks = 10;
/* Tolerance is quite arbitrary due to large number of boards with varying level of accuracy */
#define TOLERANCE_US 1000
volatile uint32_t ticker_callback_flag;
volatile uint32_t multi_counter;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
Ticker *volatile ticker1;
Ticker *volatile ticker2;
Timer gtimer;
volatile int ticker_count = 0;
volatile bool print_tick = false;
void ticker_callback_1_switch_to_2(void);
void ticker_callback_2_switch_to_1(void);
void increment_ticker_counter(void)
{
++callback_trigger_count;
}
void switch_led1_state(void)
{
led1 = !led1;
}
void switch_led2_state(void)
{
led2 = !led2;
}
void ticker_callback_1_switch_to_2(void)
{
++callback_trigger_count;
// If ticker is NULL then it is being or has been deleted
if (ticker1) {
ticker1->detach();
ticker1->attach_us(ticker_callback_2_switch_to_1, ONE_MILLI_SEC);
}
switch_led1_state();
}
void ticker_callback_2_switch_to_1(void)
{
++callback_trigger_count;
// If ticker is NULL then it is being or has been deleted
if (ticker2) {
ticker2->detach();
ticker2->attach_us(ticker_callback_1_switch_to_2, ONE_MILLI_SEC);
}
switch_led2_state();
}
void sem_release(Semaphore *sem)
{
sem->release();
}
void stop_gtimer_set_flag(void)
{
gtimer.stop();
core_util_atomic_incr_u32((uint32_t*)&ticker_callback_flag, 1);
}
void increment_multi_counter(void)
{
core_util_atomic_incr_u32((uint32_t*)&multi_counter, 1);
}
/* Tests is to measure the accuracy of Ticker over a period of time
*
* 1) DUT would start to update callback_trigger_count every milli sec, in 2x callback we use 2 tickers
* to update the count alternatively.
@ -28,81 +114,14 @@
* 5) Finally host send the results back to device pass/fail based on tolerance.
* 6) More details on tests can be found in timing_drift_auto.py
*/
#include "mbed.h"
#include "greentea-client/test_env.h"
#include "utest/utest.h"
#include "unity/unity.h"
using namespace utest::v1;
#define ONE_MILLI_SEC 1000
volatile uint32_t callback_trigger_count = 0;
static const int test_timeout = 240;
static const int total_ticks = 10;
DigitalOut led1(LED1);
DigitalOut led2(LED2);
Ticker *volatile ticker1;
Ticker *volatile ticker2;
volatile int ticker_count = 0;
volatile bool print_tick = false;
void ticker_callback_1_switch_to_2(void);
void ticker_callback_2_switch_to_1(void);
void ticker_callback_0(void) {
++callback_trigger_count;
}
void ticker_callback_1_led(void) {
led1 = !led1;
}
void ticker_callback_2_led(void) {
led2 = !led2;
}
void ticker_callback_1_switch_to_2(void) {
++callback_trigger_count;
// If ticker is NULL then it is being or has been deleted
if (ticker1) {
ticker1->detach();
ticker1->attach_us(ticker_callback_2_switch_to_1, ONE_MILLI_SEC);
}
ticker_callback_1_led();
}
void ticker_callback_2_switch_to_1(void) {
++callback_trigger_count;
// If ticker is NULL then it is being or has been deleted
if (ticker2) {
ticker2->detach();
ticker2->attach_us(ticker_callback_1_switch_to_2, ONE_MILLI_SEC);
}
ticker_callback_2_led();
}
void wait_and_print() {
while (ticker_count <= total_ticks) {
if (print_tick) {
print_tick = false;
greentea_send_kv("tick", ticker_count++);
}
}
}
void test_case_1x_ticker() {
void test_case_1x_ticker()
{
char _key[11] = { };
char _value[128] = { };
uint8_t results_size = 0;
int expected_key = 1;
greentea_send_kv("timing_drift_check_start", 0);
ticker1->attach_us(&ticker_callback_0, ONE_MILLI_SEC);
ticker1->attach_us(&increment_ticker_counter, ONE_MILLI_SEC);
// wait for 1st signal from host
do {
@ -119,13 +138,12 @@ void test_case_1x_ticker() {
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
}
void test_case_2x_callbacks() {
void test_case_2x_callbacks()
{
char _key[11] = { };
char _value[128] = { };
uint8_t results_size = 0;
int expected_key = 1;
led1 = 0;
@ -150,50 +168,198 @@ void test_case_2x_callbacks() {
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
}
utest::v1::status_t one_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case) {
/** Test many tickers run one after the other
Given many Tickers
When schedule them one after the other with the same time intervals
Then tickers properly execute callbacks
When schedule them one after the other with the different time intervals
Then tickers properly execute callbacks
*/
void test_multi_ticker(void)
{
Ticker ticker[TICKER_COUNT];
const uint32_t extra_wait = 5; // extra 5ms wait time
multi_counter = 0;
for (int i = 0; i < TICKER_COUNT; i++) {
ticker[i].attach_us(callback(increment_multi_counter), MULTI_TICKER_TIME_MS * 1000);
}
Thread::wait(MULTI_TICKER_TIME_MS + extra_wait);
for (int i = 0; i < TICKER_COUNT; i++) {
ticker[i].detach();
}
TEST_ASSERT_EQUAL(TICKER_COUNT, multi_counter);
multi_counter = 0;
for (int i = 0; i < TICKER_COUNT; i++) {
ticker[i].attach_us(callback(increment_multi_counter), (MULTI_TICKER_TIME_MS + i) * 1000);
}
Thread::wait(MULTI_TICKER_TIME_MS + TICKER_COUNT + extra_wait);
for (int i = 0; i < TICKER_COUNT; i++) {
ticker[i].detach();
}
TEST_ASSERT_EQUAL(TICKER_COUNT, multi_counter);
}
/** Test multi callback time
Given a Ticker
When the callback is attached multiple times
Then ticker properly execute callback multiple times
*/
void test_multi_call_time(void)
{
Ticker ticker;
int time_diff;
const int attach_count = 10;
for (int i = 0; i < attach_count; i++) {
ticker_callback_flag = 0;
gtimer.reset();
gtimer.start();
ticker.attach_us(callback(stop_gtimer_set_flag), MULTI_TICKER_TIME_MS * 1000);
while(!ticker_callback_flag);
time_diff = gtimer.read_us();
TEST_ASSERT_UINT32_WITHIN(TOLERANCE_US, MULTI_TICKER_TIME_MS * 1000, time_diff);
}
}
/** Test if detach cancel scheduled callback event
Given a Ticker with callback attached
When the callback is detached
Then the callback is not being called
*/
void test_detach(void)
{
Ticker ticker;
int32_t ret;
const float ticker_time_s = 0.1f;
const uint32_t wait_time_ms = 500;
Semaphore sem(0, 1);
ticker.attach(callback(sem_release, &sem), ticker_time_s);
ret = sem.wait();
TEST_ASSERT_TRUE(ret > 0);
ret = sem.wait();
ticker.detach(); /* cancel */
TEST_ASSERT_TRUE(ret > 0);
ret = sem.wait(wait_time_ms);
TEST_ASSERT_EQUAL(0, ret);
}
/** Test single callback time via attach
Given a Ticker
When callback attached with time interval specified
Then ticker properly executes callback within a specified time interval
*/
template<us_timestamp_t DELAY_US>
void test_attach_time(void)
{
Ticker ticker;
ticker_callback_flag = 0;
gtimer.reset();
gtimer.start();
ticker.attach(callback(stop_gtimer_set_flag), ((float)DELAY_US) / 1000000.0f);
while(!ticker_callback_flag);
ticker.detach();
const int time_diff = gtimer.read_us();
TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US, DELAY_US, time_diff);
}
/** Test single callback time via attach_us
Given a Ticker
When callback attached with time interval specified
Then ticker properly executes callback within a specified time interval
*/
template<us_timestamp_t DELAY_US>
void test_attach_us_time(void)
{
Ticker ticker;
ticker_callback_flag = 0;
gtimer.reset();
gtimer.start();
ticker.attach_us(callback(stop_gtimer_set_flag), DELAY_US);
while(!ticker_callback_flag);
ticker.detach();
const int time_diff = gtimer.read_us();
TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US, DELAY_US, time_diff);
}
utest::v1::status_t one_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
{
ticker1 = new Ticker();
return greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t two_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case) {
utest::v1::status_t two_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
{
ticker1 = new Ticker();
ticker2 = new Ticker();
return greentea_case_setup_handler(source, index_of_case);
return utest::v1::greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t one_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) {
utest::v1::status_t one_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, const utest::v1::failure_t reason)
{
Ticker *temp1 = ticker1;
ticker1 = NULL;
delete temp1;
return greentea_case_teardown_handler(source, passed, failed, reason);
return utest::v1::greentea_case_teardown_handler(source, passed, failed, reason);
}
utest::v1::status_t two_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, const failure_t reason) {
utest::v1::status_t two_ticker_case_teardown_handler_t(const Case *const source, const size_t passed, const size_t failed, const utest::v1::failure_t reason)
{
Ticker *temp1 = ticker1;
Ticker *temp2 = ticker2;
ticker1 = NULL;
ticker2 = NULL;
delete temp1;
delete temp2;
return greentea_case_teardown_handler(source, passed, failed, reason);
return utest::v1::greentea_case_teardown_handler(source, passed, failed, reason);
}
// Test cases
Case cases[] = {
Case("Timers: 1x ticker", one_ticker_case_setup_handler_t,test_case_1x_ticker, one_ticker_case_teardown_handler_t),
Case("Timers: 2x callbacks", two_ticker_case_setup_handler_t,test_case_2x_callbacks, two_ticker_case_teardown_handler_t),
Case("Test attach for 0.01s and time measure", test_attach_time<10000>),
Case("Test attach_us for 10ms and time measure", test_attach_us_time<10000>),
Case("Test attach for 0.1s and time measure", test_attach_time<100000>),
Case("Test attach_us for 100ms and time measure", test_attach_us_time<100000>),
Case("Test attach for 0.5s and time measure", test_attach_time<500000>),
Case("Test attach_us for 500ms and time measure", test_attach_us_time<500000>),
Case("Test detach", test_detach),
Case("Test multi call and time measure", test_multi_call_time),
Case("Test multi ticker", test_multi_ticker),
Case("Test timers: 1x ticker", one_ticker_case_setup_handler_t,test_case_1x_ticker, one_ticker_case_teardown_handler_t),
Case("Test timers: 2x callbacks", two_ticker_case_setup_handler_t,test_case_2x_callbacks, two_ticker_case_teardown_handler_t)
};
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(test_timeout, "timing_drift_auto");
return greentea_test_setup_handler(number_of_cases);
return utest::v1::greentea_test_setup_handler(number_of_cases);
}
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
utest::v1::Specification specification(greentea_test_setup, cases, utest::v1::greentea_test_teardown_handler);
int main() {
Harness::run(specification);
int main()
{
utest::v1::Harness::run(specification);
}