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
4
3
*
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.
7
6
* You may obtain a copy of the License at
8
7
*
9
- * http://www.apache.org/licenses/LICENSE-2.0
8
+ * http://www.apache.org/licenses/LICENSE-2.0
10
9
*
11
10
* 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.
14
13
* See the License for the specific language governing permissions and
15
14
* limitations under the License.
16
15
*/
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
-
32
16
#include " mbed.h"
33
17
#include " greentea-client/test_env.h"
34
18
#include " utest/utest.h"
35
19
#include " unity/unity.h"
36
20
37
- using namespace utest ::v1;
21
+
22
+ using utest::v1::Case;
38
23
39
24
#define ONE_MILLI_SEC 1000
25
+ #define TICKER_COUNT 16
26
+ #define MULTI_TICKER_TIME_MS 100
40
27
volatile uint32_t callback_trigger_count = 0 ;
41
28
static const int test_timeout = 240 ;
42
29
static const int total_ticks = 10 ;
43
30
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
+
44
38
DigitalOut led1 (LED1);
45
39
DigitalOut led2 (LED2);
46
40
47
41
Ticker *volatile ticker1;
48
42
Ticker *volatile ticker2;
43
+ Timer gtimer;
49
44
50
45
volatile int ticker_count = 0 ;
51
46
volatile bool print_tick = false ;
52
47
53
48
void ticker_callback_1_switch_to_2 (void );
54
49
void ticker_callback_2_switch_to_1 (void );
55
50
56
- void ticker_callback_0 (void ) {
51
+ void increment_ticker_counter (void )
52
+ {
57
53
++callback_trigger_count;
58
54
}
59
55
60
- void ticker_callback_1_led (void ) {
56
+ void switch_led1_state (void )
57
+ {
61
58
led1 = !led1;
62
59
}
63
60
64
- void ticker_callback_2_led (void ) {
61
+ void switch_led2_state (void )
62
+ {
65
63
led2 = !led2;
66
64
}
67
65
68
- void ticker_callback_1_switch_to_2 (void ) {
66
+ void ticker_callback_1_switch_to_2 (void )
67
+ {
69
68
++callback_trigger_count;
70
69
// If ticker is NULL then it is being or has been deleted
71
70
if (ticker1) {
72
71
ticker1->detach ();
73
72
ticker1->attach_us (ticker_callback_2_switch_to_1, ONE_MILLI_SEC);
74
73
}
75
- ticker_callback_1_led ();
74
+ switch_led1_state ();
76
75
}
77
76
78
- void ticker_callback_2_switch_to_1 (void ) {
77
+ void ticker_callback_2_switch_to_1 (void )
78
+ {
79
79
++callback_trigger_count;
80
80
// If ticker is NULL then it is being or has been deleted
81
81
if (ticker2) {
82
82
ticker2->detach ();
83
83
ticker2->attach_us (ticker_callback_1_switch_to_2, ONE_MILLI_SEC);
84
84
}
85
- ticker_callback_2_led ();
85
+ switch_led2_state ();
86
86
}
87
87
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 ();
95
92
}
96
93
97
- void test_case_1x_ticker () {
98
94
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
+ {
99
119
char _key[11 ] = { };
100
120
char _value[128 ] = { };
101
- uint8_t results_size = 0 ;
102
121
int expected_key = 1 ;
103
122
104
123
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);
106
125
107
126
// wait for 1st signal from host
108
127
do {
@@ -119,13 +138,12 @@ void test_case_1x_ticker() {
119
138
greentea_parse_kv (_key, _value, sizeof (_key), sizeof (_value));
120
139
121
140
TEST_ASSERT_EQUAL_STRING_MESSAGE (" pass" , _key," Host side script reported a fail..." );
122
-
123
141
}
124
142
125
- void test_case_2x_callbacks () {
143
+ void test_case_2x_callbacks ()
144
+ {
126
145
char _key[11 ] = { };
127
146
char _value[128 ] = { };
128
- uint8_t results_size = 0 ;
129
147
int expected_key = 1 ;
130
148
131
149
led1 = 0 ;
@@ -150,50 +168,198 @@ void test_case_2x_callbacks() {
150
168
greentea_parse_kv (_key, _value, sizeof (_key), sizeof (_value));
151
169
152
170
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
+ }
153
233
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);
154
259
}
155
260
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
+ {
157
308
ticker1 = new Ticker ();
158
309
return greentea_case_setup_handler (source, index_of_case);
159
310
}
160
311
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
+ {
162
314
ticker1 = new Ticker ();
163
315
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);
165
317
}
166
318
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
+ {
168
321
Ticker *temp1 = ticker1;
169
322
ticker1 = NULL ;
170
323
delete temp1;
171
- return greentea_case_teardown_handler (source, passed, failed, reason);
324
+ return utest::v1:: greentea_case_teardown_handler (source, passed, failed, reason);
172
325
}
173
326
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
+ {
175
329
Ticker *temp1 = ticker1;
176
330
Ticker *temp2 = ticker2;
177
331
ticker1 = NULL ;
178
332
ticker2 = NULL ;
179
333
delete temp1;
180
334
delete temp2;
181
- return greentea_case_teardown_handler (source, passed, failed, reason);
335
+ return utest::v1:: greentea_case_teardown_handler (source, passed, failed, reason);
182
336
}
183
337
338
+
184
339
// Test cases
185
340
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 )
188
352
};
189
353
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
+ {
191
356
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);
193
358
}
194
359
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);
196
361
197
- int main () {
198
- Harness::run (specification);
362
+ int main ()
363
+ {
364
+ utest::v1::Harness::run (specification);
199
365
}
0 commit comments