Skip to content

Commit aaa15bc

Browse files
Extends test set for Ticker class (round 2)
1 parent 943fc32 commit aaa15bc

File tree

1 file changed

+224
-58
lines changed

1 file changed

+224
-58
lines changed

TESTS/mbed_drivers/ticker/main.cpp

Lines changed: 224 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,108 +1,127 @@
1-
/*
2-
* Copyright (c) 2013-2016, ARM Limited, All Rights Reserved
3-
* SPDX-License-Identifier: Apache-2.0
1+
/* mbed Microcontroller Library
2+
* Copyright (c) 2013-2017 ARM Limited
43
*
5-
* Licensed under the Apache License, Version 2.0 (the "License"); you may
6-
* not use this file except in compliance with the License.
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
76
* You may obtain a copy of the License at
87
*
9-
* http://www.apache.org/licenses/LICENSE-2.0
8+
* http://www.apache.org/licenses/LICENSE-2.0
109
*
1110
* Unless required by applicable law or agreed to in writing, software
12-
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13-
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1413
* See the License for the specific language governing permissions and
1514
* limitations under the License.
1615
*/
17-
18-
19-
/*
20-
* Tests is to measure the accuracy of Ticker over a period of time
21-
*
22-
*
23-
* 1) DUT would start to update callback_trigger_count every milli sec, in 2x callback we use 2 tickers
24-
* to update the count alternatively.
25-
* 2) Host would query what is current count base_time, Device responds by the callback_trigger_count
26-
* 3) Host after waiting for measurement stretch. It will query for device time again final_time.
27-
* 4) Host computes the drift considering base_time, final_time, transport delay and measurement stretch
28-
* 5) Finally host send the results back to device pass/fail based on tolerance.
29-
* 6) More details on tests can be found in timing_drift_auto.py
30-
*/
31-
3216
#include "mbed.h"
3317
#include "greentea-client/test_env.h"
3418
#include "utest/utest.h"
3519
#include "unity/unity.h"
3620

37-
using namespace utest::v1;
21+
22+
using utest::v1::Case;
3823

3924
#define ONE_MILLI_SEC 1000
25+
#define TICKER_COUNT 16
26+
#define MULTI_TICKER_TIME_MS 100
4027
volatile uint32_t callback_trigger_count = 0;
4128
static const int test_timeout = 240;
4229
static const int total_ticks = 10;
4330

31+
32+
/* Tolerance is quite arbitrary due to large number of boards with varying level of accuracy */
33+
#define TOLERANCE_US 1000
34+
35+
volatile uint32_t ticker_callback_flag;
36+
volatile uint32_t multi_counter;
37+
4438
DigitalOut led1(LED1);
4539
DigitalOut led2(LED2);
4640

4741
Ticker *volatile ticker1;
4842
Ticker *volatile ticker2;
43+
Timer gtimer;
4944

5045
volatile int ticker_count = 0;
5146
volatile bool print_tick = false;
5247

5348
void ticker_callback_1_switch_to_2(void);
5449
void ticker_callback_2_switch_to_1(void);
5550

56-
void ticker_callback_0(void) {
51+
void increment_ticker_counter(void)
52+
{
5753
++callback_trigger_count;
5854
}
5955

60-
void ticker_callback_1_led(void) {
56+
void switch_led1_state(void)
57+
{
6158
led1 = !led1;
6259
}
6360

64-
void ticker_callback_2_led(void) {
61+
void switch_led2_state(void)
62+
{
6563
led2 = !led2;
6664
}
6765

68-
void ticker_callback_1_switch_to_2(void) {
66+
void ticker_callback_1_switch_to_2(void)
67+
{
6968
++callback_trigger_count;
7069
// If ticker is NULL then it is being or has been deleted
7170
if (ticker1) {
7271
ticker1->detach();
7372
ticker1->attach_us(ticker_callback_2_switch_to_1, ONE_MILLI_SEC);
7473
}
75-
ticker_callback_1_led();
74+
switch_led1_state();
7675
}
7776

78-
void ticker_callback_2_switch_to_1(void) {
77+
void ticker_callback_2_switch_to_1(void)
78+
{
7979
++callback_trigger_count;
8080
// If ticker is NULL then it is being or has been deleted
8181
if (ticker2) {
8282
ticker2->detach();
8383
ticker2->attach_us(ticker_callback_1_switch_to_2, ONE_MILLI_SEC);
8484
}
85-
ticker_callback_2_led();
85+
switch_led2_state();
8686
}
8787

88-
void wait_and_print() {
89-
while (ticker_count <= total_ticks) {
90-
if (print_tick) {
91-
print_tick = false;
92-
greentea_send_kv("tick", ticker_count++);
93-
}
94-
}
88+
89+
void sem_release(Semaphore *sem)
90+
{
91+
sem->release();
9592
}
9693

97-
void test_case_1x_ticker() {
9894

95+
void stop_gtimer_set_flag(void)
96+
{
97+
gtimer.stop();
98+
core_util_atomic_incr_u32((uint32_t*)&ticker_callback_flag, 1);
99+
}
100+
101+
void increment_multi_counter(void)
102+
{
103+
core_util_atomic_incr_u32((uint32_t*)&multi_counter, 1);
104+
}
105+
106+
107+
/* Tests is to measure the accuracy of Ticker over a period of time
108+
*
109+
* 1) DUT would start to update callback_trigger_count every milli sec, in 2x callback we use 2 tickers
110+
* to update the count alternatively.
111+
* 2) Host would query what is current count base_time, Device responds by the callback_trigger_count
112+
* 3) Host after waiting for measurement stretch. It will query for device time again final_time.
113+
* 4) Host computes the drift considering base_time, final_time, transport delay and measurement stretch
114+
* 5) Finally host send the results back to device pass/fail based on tolerance.
115+
* 6) More details on tests can be found in timing_drift_auto.py
116+
*/
117+
void test_case_1x_ticker()
118+
{
99119
char _key[11] = { };
100120
char _value[128] = { };
101-
uint8_t results_size = 0;
102121
int expected_key = 1;
103122

104123
greentea_send_kv("timing_drift_check_start", 0);
105-
ticker1->attach_us(&ticker_callback_0, ONE_MILLI_SEC);
124+
ticker1->attach_us(&increment_ticker_counter, ONE_MILLI_SEC);
106125

107126
// wait for 1st signal from host
108127
do {
@@ -119,13 +138,12 @@ void test_case_1x_ticker() {
119138
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
120139

121140
TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
122-
123141
}
124142

125-
void test_case_2x_callbacks() {
143+
void test_case_2x_callbacks()
144+
{
126145
char _key[11] = { };
127146
char _value[128] = { };
128-
uint8_t results_size = 0;
129147
int expected_key = 1;
130148

131149
led1 = 0;
@@ -150,50 +168,198 @@ void test_case_2x_callbacks() {
150168
greentea_parse_kv(_key, _value, sizeof(_key), sizeof(_value));
151169

152170
TEST_ASSERT_EQUAL_STRING_MESSAGE("pass", _key,"Host side script reported a fail...");
171+
}
172+
173+
/** Test many tickers run one after the other
174+
175+
Given many Tickers
176+
When schedule them one after the other with the same time intervals
177+
Then tickers properly execute callbacks
178+
When schedule them one after the other with the different time intervals
179+
Then tickers properly execute callbacks
180+
*/
181+
void test_multi_ticker(void)
182+
{
183+
Ticker ticker[TICKER_COUNT];
184+
const uint32_t extra_wait = 5; // extra 5ms wait time
185+
186+
multi_counter = 0;
187+
for (int i = 0; i < TICKER_COUNT; i++) {
188+
ticker[i].attach_us(callback(increment_multi_counter), MULTI_TICKER_TIME_MS * 1000);
189+
}
190+
191+
Thread::wait(MULTI_TICKER_TIME_MS + extra_wait);
192+
for (int i = 0; i < TICKER_COUNT; i++) {
193+
ticker[i].detach();
194+
}
195+
TEST_ASSERT_EQUAL(TICKER_COUNT, multi_counter);
196+
197+
multi_counter = 0;
198+
for (int i = 0; i < TICKER_COUNT; i++) {
199+
ticker[i].attach_us(callback(increment_multi_counter), (MULTI_TICKER_TIME_MS + i) * 1000);
200+
}
201+
202+
Thread::wait(MULTI_TICKER_TIME_MS + TICKER_COUNT + extra_wait);
203+
for (int i = 0; i < TICKER_COUNT; i++) {
204+
ticker[i].detach();
205+
}
206+
TEST_ASSERT_EQUAL(TICKER_COUNT, multi_counter);
207+
}
208+
209+
/** Test multi callback time
210+
211+
Given a Ticker
212+
When the callback is attached multiple times
213+
Then ticker properly execute callback multiple times
214+
*/
215+
void test_multi_call_time(void)
216+
{
217+
Ticker ticker;
218+
int time_diff;
219+
const int attach_count = 10;
220+
221+
for (int i = 0; i < attach_count; i++) {
222+
ticker_callback_flag = 0;
223+
gtimer.reset();
224+
225+
gtimer.start();
226+
ticker.attach_us(callback(stop_gtimer_set_flag), MULTI_TICKER_TIME_MS * 1000);
227+
while(!ticker_callback_flag);
228+
time_diff = gtimer.read_us();
229+
230+
TEST_ASSERT_UINT32_WITHIN(TOLERANCE_US, MULTI_TICKER_TIME_MS * 1000, time_diff);
231+
}
232+
}
153233

234+
/** Test if detach cancel scheduled callback event
235+
236+
Given a Ticker with callback attached
237+
When the callback is detached
238+
Then the callback is not being called
239+
*/
240+
void test_detach(void)
241+
{
242+
Ticker ticker;
243+
int32_t ret;
244+
const float ticker_time_s = 0.1f;
245+
const uint32_t wait_time_ms = 500;
246+
Semaphore sem(0, 1);
247+
248+
ticker.attach(callback(sem_release, &sem), ticker_time_s);
249+
250+
ret = sem.wait();
251+
TEST_ASSERT_TRUE(ret > 0);
252+
253+
ret = sem.wait();
254+
ticker.detach(); /* cancel */
255+
TEST_ASSERT_TRUE(ret > 0);
256+
257+
ret = sem.wait(wait_time_ms);
258+
TEST_ASSERT_EQUAL(0, ret);
154259
}
155260

156-
utest::v1::status_t one_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case) {
261+
/** Test single callback time via attach
262+
263+
Given a Ticker
264+
When callback attached with time interval specified
265+
Then ticker properly executes callback within a specified time interval
266+
*/
267+
template<us_timestamp_t DELAY_US>
268+
void test_attach_time(void)
269+
{
270+
Ticker ticker;
271+
ticker_callback_flag = 0;
272+
273+
gtimer.reset();
274+
gtimer.start();
275+
ticker.attach(callback(stop_gtimer_set_flag), ((float)DELAY_US) / 1000000.0f);
276+
while(!ticker_callback_flag);
277+
ticker.detach();
278+
const int time_diff = gtimer.read_us();
279+
280+
TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US, DELAY_US, time_diff);
281+
}
282+
283+
/** Test single callback time via attach_us
284+
285+
Given a Ticker
286+
When callback attached with time interval specified
287+
Then ticker properly executes callback within a specified time interval
288+
*/
289+
template<us_timestamp_t DELAY_US>
290+
void test_attach_us_time(void)
291+
{
292+
Ticker ticker;
293+
ticker_callback_flag = 0;
294+
295+
gtimer.reset();
296+
gtimer.start();
297+
ticker.attach_us(callback(stop_gtimer_set_flag), DELAY_US);
298+
while(!ticker_callback_flag);
299+
ticker.detach();
300+
const int time_diff = gtimer.read_us();
301+
302+
TEST_ASSERT_UINT64_WITHIN(TOLERANCE_US, DELAY_US, time_diff);
303+
}
304+
305+
306+
utest::v1::status_t one_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
307+
{
157308
ticker1 = new Ticker();
158309
return greentea_case_setup_handler(source, index_of_case);
159310
}
160311

161-
utest::v1::status_t two_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case) {
312+
utest::v1::status_t two_ticker_case_setup_handler_t(const Case *const source, const size_t index_of_case)
313+
{
162314
ticker1 = new Ticker();
163315
ticker2 = new Ticker();
164-
return greentea_case_setup_handler(source, index_of_case);
316+
return utest::v1::greentea_case_setup_handler(source, index_of_case);
165317
}
166318

167-
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) {
319+
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)
320+
{
168321
Ticker *temp1 = ticker1;
169322
ticker1 = NULL;
170323
delete temp1;
171-
return greentea_case_teardown_handler(source, passed, failed, reason);
324+
return utest::v1::greentea_case_teardown_handler(source, passed, failed, reason);
172325
}
173326

174-
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) {
327+
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)
328+
{
175329
Ticker *temp1 = ticker1;
176330
Ticker *temp2 = ticker2;
177331
ticker1 = NULL;
178332
ticker2 = NULL;
179333
delete temp1;
180334
delete temp2;
181-
return greentea_case_teardown_handler(source, passed, failed, reason);
335+
return utest::v1::greentea_case_teardown_handler(source, passed, failed, reason);
182336
}
183337

338+
184339
// Test cases
185340
Case cases[] = {
186-
Case("Timers: 1x ticker", one_ticker_case_setup_handler_t,test_case_1x_ticker, one_ticker_case_teardown_handler_t),
187-
Case("Timers: 2x callbacks", two_ticker_case_setup_handler_t,test_case_2x_callbacks, two_ticker_case_teardown_handler_t),
341+
Case("Test attach for 0.01s and time measure", test_attach_time<10000>),
342+
Case("Test attach_us for 10ms and time measure", test_attach_us_time<10000>),
343+
Case("Test attach for 0.1s and time measure", test_attach_time<100000>),
344+
Case("Test attach_us for 100ms and time measure", test_attach_us_time<100000>),
345+
Case("Test attach for 0.5s and time measure", test_attach_time<500000>),
346+
Case("Test attach_us for 500ms and time measure", test_attach_us_time<500000>),
347+
Case("Test detach", test_detach),
348+
Case("Test multi call and time measure", test_multi_call_time),
349+
Case("Test multi ticker", test_multi_ticker),
350+
Case("Test timers: 1x ticker", one_ticker_case_setup_handler_t,test_case_1x_ticker, one_ticker_case_teardown_handler_t),
351+
Case("Test timers: 2x callbacks", two_ticker_case_setup_handler_t,test_case_2x_callbacks, two_ticker_case_teardown_handler_t)
188352
};
189353

190-
utest::v1::status_t greentea_test_setup(const size_t number_of_cases) {
354+
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
355+
{
191356
GREENTEA_SETUP(test_timeout, "timing_drift_auto");
192-
return greentea_test_setup_handler(number_of_cases);
357+
return utest::v1::greentea_test_setup_handler(number_of_cases);
193358
}
194359

195-
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
360+
utest::v1::Specification specification(greentea_test_setup, cases, utest::v1::greentea_test_teardown_handler);
196361

197-
int main() {
198-
Harness::run(specification);
362+
int main()
363+
{
364+
utest::v1::Harness::run(specification);
199365
}

0 commit comments

Comments
 (0)