/
main.cpp
544 lines (455 loc) · 19.3 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
/* mbed Microcontroller Library
* Copyright (c) 2017 ARM Limited
* SPDX-License-Identifier: Apache-2.0
*
* 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 "utest/utest.h"
#include "unity/unity.h"
using utest::v1::Case;
#if !DEVICE_USTICKER
#error [NOT_SUPPORTED] UsTicker need to be enabled for this test.
#else
#define ALL_SIGNALS 0x7fffffff
#define NO_SIGNALS 0x0
#define SIGNAL1 0x1
#define SIGNAL2 0x2
#define SIGNAL3 0x4
template <int32_t signals, uint32_t timeout, uint32_t test_val>
void run_signal_wait(void)
{
uint32_t ret = ThisThread::flags_wait_all_for(signals, timeout);
TEST_ASSERT_EQUAL(test_val, ret);
}
template <int32_t signals, int32_t test_val>
void run_clear(void)
{
int32_t ret = ThisThread::flags_clear(signals);
TEST_ASSERT_EQUAL(test_val, ret);
}
void run_multiple_wait_clear(int32_t signals1, int32_t signals2, int32_t test_val1, int32_t test_val2)
{
int32_t ret;
ret = ThisThread::flags_clear(signals1);
TEST_ASSERT_EQUAL(test_val1, ret);
ret = ThisThread::flags_clear(signals2);
TEST_ASSERT_EQUAL(test_val2, ret);
}
/** Validate that ticker callback to flags_clr(NO_SIGNALS) doesn't change main thread signals and return actual signals
Given main thread and ticker instance with callback registered
When callback calls @a flags_clear(NO_SIGNALS)
then callback @a flags_clear return status should be ALL_SIGNALS indicating that the signal is unchanged
*/
void test_clear_no_signals_with_ticker(void)
{
Ticker t;
osThreadFlagsSet(ThisThread::get_id(), ALL_SIGNALS);
t.attach_us([&] { run_multiple_wait_clear(NO_SIGNALS, NO_SIGNALS, ALL_SIGNALS, ALL_SIGNALS); }, 3000);
}
/** Validate all flags_clr clears the signal in one shot
Given main thread and ticker instance with callback registered
When callback calls @a flags_clear(ALL_SIGNALS) with all possible signals
then callback @a flags_clear(NO_SIGNALS) return status should be NO_SIGNALS(0) indicating all signals cleared correctly
*/
void test_clear_all_with_ticker(void)
{
Ticker t;
osThreadFlagsSet(ThisThread::get_id(), ALL_SIGNALS);
t.attach_us([&] { run_multiple_wait_clear(ALL_SIGNALS, NO_SIGNALS, ALL_SIGNALS, NO_SIGNALS); }, 3000);
}
/** Validate if any signals are set on ticker callback
Given main thread and ticker instance with callback registered
When callback calls @a flags_clear(NO_SIGNALS)
then callback @a flags_clear return status should be NO_SIGNALS(0) indicating no signals set
*/
void test_init_state_with_ticker(void)
{
Ticker t;
t.attach_us(callback(run_clear<NO_SIGNALS, NO_SIGNALS>), 3000);
}
/** Validate signal_wait return status if timeout specified
Given main thread and ticker instance with callback registered
When callback calls @a flags_wait_all_for(signals, timeout) with specified signals and timeout
then callback @a flags_wait_all_for timeout and return 0 indicating no signals set
*/
template <int32_t signals, uint32_t timeout, uint32_t status>
void test_wait_timeout_with_ticker(void)
{
Ticker t;
t.attach_us(callback(run_signal_wait<signals, timeout, status>), 3000);
}
void run_release_wait_signal_wait_callback()
{
osThreadFlagsSet(ThisThread::get_id(), ALL_SIGNALS);
}
/** Validate that call of signal_wait return correctly when thread has all signals already set
Given main thread and ticker instance with callback registered
When main thread @a flags_wait_all_for(ALL_SIGNALS, osWaitForever),
then main thread is blocked
when a callback calls @a osThreadFlagsSet set ALL_SIGNALS
then the main thread is unblocked from @ flags_wait_all_for with the return of ALL_SIGNALS set
*/
void test_wait_all_already_set_with_ticker(void)
{
Ticker t;
t.attach_us([&] { run_release_wait_signal_wait_callback(); }, 3000);
uint32_t ret = ThisThread::flags_wait_all_for(ALL_SIGNALS, osWaitForever);
TEST_ASSERT_EQUAL(ALL_SIGNALS, ret);
}
void run_release_wait_signal_set_callback(int32_t signal, osThreadId_t id)
{
int32_t ret;
if (signal == 0) {
for (int i = 0; i < 16; i++) {
int32_t signal = 1 << i;
ret = osThreadFlagsSet(id, signal);
}
} else {
ret = osThreadFlagsSet(id, signal);
}
}
/** Validate if wait_signal accumulate signals and return correctly when all signals set
Given the main thread and ticker instance with callback registered
When main thread @a flags_wait_all_for,
then main thread is blocked
when a callback calls @a osThreadFlagsSet in a loop to set 16 different signal
then the main thread is unblocked from @ flags_wait_all_for with the return of expected different signals set
*/
void test_wait_all_loop_with_ticker(void)
{
int32_t ret;
Semaphore sem(0, 1);
Ticker t;
osThreadId_t id = ThisThread::get_id();
t.attach_us([&] { run_release_wait_signal_set_callback(0, id); }, 4000);
ret = ThisThread::flags_wait_all_for((ALL_SIGNALS & 0xFFFF), osWaitForever, true);
TEST_ASSERT_EQUAL((ALL_SIGNALS & 0xFFFF), ret);
}
/** Validate if setting same signal twice cause any unwanted behaviour
Given the main thread and two ticker instance with callback registered
When main thread @a flags_wait_all_for,
then main thread is blocked
when a first callback calls @a osThreadFlagsSet set SIGNAL2 and
second callback calls @a osThreadFlagsSet set SIGNAL1 | SIGNAL2 | SIGNAL3 with SIGNAL2 set again
then the main thread is unblocked from @ flags_wait_all_for with return of expected signals set
*/
void test_set_double_with_ticker(void)
{
int32_t ret;
Ticker t1, t2;
osThreadId_t id = ThisThread::get_id();
t1.attach_us([&] { run_release_wait_signal_set_callback(SIGNAL2, id); }, 3000);
t2.attach_us([&] { run_release_wait_signal_set_callback(SIGNAL1 | SIGNAL2 | SIGNAL3, id); }, 4000);
ret = ThisThread::flags_wait_all_for((SIGNAL1 | SIGNAL2 | SIGNAL3), osWaitForever, true);
TEST_ASSERT_EQUAL(SIGNAL1 | SIGNAL2 | SIGNAL3, ret);
}
#if defined(MBED_CONF_RTOS_PRESENT)
#define TEST_STACK_SIZE 512
#define PROHIBITED_SIGNAL 0x80000000
#define MAX_FLAG_POS 30
struct Sync {
Sync(Semaphore &parent, Semaphore &child): sem_parent(parent), sem_child(child)
{}
Semaphore &sem_parent;
Semaphore &sem_child;
};
template <int32_t signals, uint32_t timeout, uint32_t test_val>
void run_release_signal_wait(Semaphore *sem)
{
sem->release();
uint32_t ret = ThisThread::flags_wait_all_for(signals, timeout);
TEST_ASSERT_EQUAL(test_val, ret);
}
template <int32_t signals, uint32_t timeout, uint32_t test_val>
void run_release_wait_signal_wait(Sync *sync)
{
sync->sem_parent.release();
sync->sem_child.acquire();
uint32_t ret = ThisThread::flags_wait_all_for(signals, timeout);
TEST_ASSERT_EQUAL(test_val, ret);
}
template <int32_t signals, int32_t test_val>
void run_wait_clear(Sync *sync)
{
sync->sem_parent.release();
sync->sem_child.acquire();
int32_t ret = ThisThread::flags_clear(signals);
TEST_ASSERT_EQUAL(test_val, ret);
}
void run_loop_wait_clear(Sync *sync)
{
int32_t signals = NO_SIGNALS;
for (int i = 0; i <= MAX_FLAG_POS; i++) {
int32_t signal = 1 << i;
signals |= signal;
sync->sem_child.acquire();
int32_t ret = ThisThread::flags_clear(NO_SIGNALS);
TEST_ASSERT_EQUAL(signals, ret);
sync->sem_parent.release();
}
}
template <int32_t signals1, int32_t signals2, int32_t test_val1, int32_t test_val2>
void run_double_wait_clear(Sync *sync)
{
int32_t ret;
sync->sem_parent.release();
sync->sem_child.acquire();
ret = ThisThread::flags_clear(signals1);
TEST_ASSERT_EQUAL(test_val1, ret);
ret = ThisThread::flags_clear(signals2);
TEST_ASSERT_EQUAL(test_val2, ret);
}
/** Validate that call signal_clr(NO_SIGNALS) doesn't change thread signals and return actual signals
Given two threads A & B are started, B with all signals already set
When thread B calls @a signal_clr(NO_SIGNALS)
Then thread B @a signal_clr status should be ALL_SIGNALS indicating that thread B state is unchanged
*/
void test_clear_no_signals(void)
{
Semaphore sem_parent(0, 1);
Semaphore sem_child(0, 1);
Sync sync(sem_parent, sem_child);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_double_wait_clear<NO_SIGNALS, NO_SIGNALS, ALL_SIGNALS, ALL_SIGNALS>, &sync));
sem_parent.acquire();
t.flags_set(ALL_SIGNALS);
sem_child.release();
t.join();
}
/** Validate if any signals are set on just created thread
Given the thread is running
When thread execute @a signal_clr(NO_SIGNALS)
Then thread @a signal_clr return status should be NO_SIGNALS(0) indicating no signals set
*/
void test_init_state(void)
{
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_clear<NO_SIGNALS, NO_SIGNALS>));
t.join();
}
/** Validate all signals set in one shot
Given two threads A & B are started
When thread A call @a flags_set(ALL_SIGNALS) with all possible signals
Then thread B @a signal_clr(NO_SIGNALS) status should be ALL_SIGNALS indicating all signals set correctly
*/
void test_set_all(void)
{
int32_t ret;
Semaphore sem_parent(0, 1);
Semaphore sem_child(0, 1);
Sync sync(sem_parent, sem_child);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_wait_clear<NO_SIGNALS, ALL_SIGNALS>, &sync));
sem_parent.acquire();
ret = t.flags_set(ALL_SIGNALS);
TEST_ASSERT_EQUAL(ALL_SIGNALS, ret);
sem_child.release();
t.join();
}
/** Validate that call flags_set with prohibited signal doesn't change thread signals
Given two threads A & B are started, B with all signals set
When thread A executes @a flags_set(PROHIBITED_SIGNAL) with prohibited signal
Then thread B @a signal_clr(NO_SIGNALS) status should be ALL_SIGNALS indicating that thread B signals are unchanged
@note Each signal has up to 31 event flags 0x1, 0x2, 0x4, 0x8, ..., 0x40000000
Most significant bit is reserved and thereby flag 0x80000000 is prohibited
*/
void test_set_prohibited(void)
{
int32_t ret;
Semaphore sem_parent(0, 1);
Semaphore sem_child(0, 1);
Sync sync(sem_parent, sem_child);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_wait_clear<NO_SIGNALS, ALL_SIGNALS>, &sync));
sem_parent.acquire();
t.flags_set(ALL_SIGNALS);
#if !MBED_TRAP_ERRORS_ENABLED
ret = t.flags_set(PROHIBITED_SIGNAL);
TEST_ASSERT_EQUAL(osErrorParameter, ret);
#endif
sem_child.release();
t.join();
}
/** Validate all signals clear in one shot
Given two threads A & B are started, B with all signals set
When thread B execute @a signal_clr(ALL_SIGNALS) with all possible signals
Then thread B @a signal_clr(NO_SIGNALS) status should be NO_SIGNALS(0) indicating all signals cleared correctly
*/
void test_clear_all(void)
{
Semaphore sem_parent(0, 1);
Semaphore sem_child(0, 1);
Sync sync(sem_parent, sem_child);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_double_wait_clear<ALL_SIGNALS, NO_SIGNALS, ALL_SIGNALS, NO_SIGNALS>, &sync));
sem_parent.acquire();
t.flags_set(ALL_SIGNALS);
sem_child.release();
t.join();
}
/** Validate all signals set one by one in loop
Given two threads A & B are started
When thread A executes @a flags_set(signal) in loop with all possible signals
*/
void test_set_all_loop(void)
{
int32_t ret;
Semaphore sem_parent(0, 1);
Semaphore sem_child(0, 1);
Sync sync(sem_parent, sem_child);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_loop_wait_clear, &sync));
int32_t signals = 0;
for (int i = 0; i <= MAX_FLAG_POS; i++) {
int32_t signal = 1 << i;
ret = t.flags_set(signal);
signals |= signal;
TEST_ASSERT_EQUAL(signals, ret);
sem_child.release();
sem_parent.acquire();
}
t.join();
}
/** Validate signal_wait return status if timeout specified
Given the thread is running
When thread executes @a flags_wait_all_for(signals, timeout) with specified signals and timeout
Then thread @a flags_wait_all_for return should be 0 indicating no flags set
*/
template <int32_t signals, uint32_t timeout, uint32_t status>
void test_wait_timeout(void)
{
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_signal_wait<signals, timeout, status>));
t.join();
}
/** Validate that call of signal_wait return correctly when thread has all signals already set
Given two threads A & B are started, B with all signals already set
When thread B executes @a signal_wait(ALL_SIGNALS, osWaitForever),
Then thread B @a flags_wait_all_for return immediately with ALL_SIGNALS indicating all wait signals was already set
*/
void test_wait_all_already_set(void)
{
Semaphore sem_parent(0, 1);
Semaphore sem_child(0, 1);
Sync sync(sem_parent, sem_child);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_release_wait_signal_wait<ALL_SIGNALS, osWaitForever, ALL_SIGNALS>, &sync));
sem_parent.acquire();
TEST_ASSERT_EQUAL(Thread::WaitingSemaphore, t.get_state());
t.flags_set(ALL_SIGNALS);
sem_child.release();
t.join();
}
/** Validate if signal_wait return correctly when all signals set
Given two threads A & B are started and B waiting for a thread flag to be set
When thread A executes @a flags_set(ALL_SIGNALS) with all possible signals
Then thread B @a flags_wait_all_for return is ALL_SIGNALS indicating all wait signals was set
*/
void test_wait_all(void)
{
Semaphore sem(0, 1);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_release_signal_wait<ALL_SIGNALS, osWaitForever, ALL_SIGNALS>, &sem));
sem.acquire();
TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state());
t.flags_set(ALL_SIGNALS);
t.join();
}
/** Validate if signal_wait accumulate signals and return correctly when all signals set
Given two threads A & B are started and B waiting for a thread signals to be set
When thread A executes @a flags_set setting all signals in loop
Then thread B @a flags_wait_all_for return is ALL_SIGNALS indicating that all wait signals was set
*/
void test_wait_all_loop(void)
{
int32_t ret;
Semaphore sem(0, 1);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_release_signal_wait<ALL_SIGNALS, osWaitForever, ALL_SIGNALS>, &sem));
sem.acquire();
TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state());
for (int i = 0; i < MAX_FLAG_POS; i++) {
int32_t signal = 1 << i;
ret = t.flags_set(signal);
}
ret = t.flags_set(1 << MAX_FLAG_POS);
TEST_ASSERT_EQUAL(NO_SIGNALS, ret);
t.join();
}
/** Validate if setting same signal twice cause any unwanted behaviour
Given two threads A & B are started and B waiting for a thread signals to be set
When thread A executes @a flags_set twice for the same signal
Then thread A @a flags_set status is current signal set
thread B @a flags_wait_all_for return indicates that all wait signals was set
*/
void test_set_double(void)
{
int32_t ret;
Semaphore sem(0, 1);
Thread t(osPriorityNormal, TEST_STACK_SIZE);
t.start(callback(run_release_signal_wait < SIGNAL1 | SIGNAL2 | SIGNAL3, osWaitForever, SIGNAL1 | SIGNAL2 | SIGNAL3 >, &sem));
sem.acquire();
TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state());
ret = t.flags_set(SIGNAL1);
TEST_ASSERT_EQUAL(SIGNAL1, ret);
ret = t.flags_set(SIGNAL2);
TEST_ASSERT_EQUAL(SIGNAL1 | SIGNAL2, ret);
ret = t.flags_set(SIGNAL2);
TEST_ASSERT_EQUAL(SIGNAL1 | SIGNAL2, ret);
TEST_ASSERT_EQUAL(Thread::WaitingThreadFlag, t.get_state());
ret = t.flags_set(SIGNAL3);
TEST_ASSERT_EQUAL(NO_SIGNALS, ret);
t.join();
}
#endif
utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(20, "default_auto");
return utest::v1::verbose_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("Validate that ticker callback flags_clear(NO_SIGNALS) doesn't change main thread flags and return actual flags", test_clear_no_signals_with_ticker),
Case("Validate if any flags are set on ticker callback", test_init_state_with_ticker),
Case("Validate all flags clear in one shot using ticker callback", test_clear_all_with_ticker),
Case("Validate ticker callback flags_wait return status if timeout specified: 0[ms] no flags", test_wait_timeout_with_ticker<0, 0, 0>),
Case("Validate ticker callback flags_wait return status if timeout specified: 0[ms] all flags", test_wait_timeout_with_ticker<ALL_SIGNALS, 0, 0>),
Case("Validate ticker callback flags_wait return status if timeout specified: 1[ms] no flags", test_wait_timeout_with_ticker<0, 1, 0>),
Case("Validate ticker callback flags_wait return status if timeout specified: 1[ms] all flags", test_wait_timeout_with_ticker<ALL_SIGNALS, 1, 0>),
Case("Validate that main thread call of flags_wait_all_for return correctly when ticker callback set all flags", test_wait_all_already_set_with_ticker),
Case("Validate if setting same flag twice cause any unwanted behaviour when ticker callbacks set", test_set_double_with_ticker),
Case("Validate if main thread flags_wait_all_for accumulate flags and return correctly when all flags set by ticker callback", test_wait_all_loop_with_ticker),
#if defined(MBED_CONF_RTOS_PRESENT)
Case("Validate that call flags_clear(NO_SIGNALS) doesn't change thread flags and return actual flags", test_clear_no_signals),
Case("Validate if any flags are set on just created thread", test_init_state),
Case("Validate all flags set in one shot", test_set_all),
Case("Validate that call flags_set with prohibited flag doesn't change thread flags", test_set_prohibited),
Case("Validate all flags clear in one shot", test_clear_all),
Case("Validate all flags set one by one in loop", test_set_all_loop),
Case("Validate flags_wait return status if timeout specified: 0[ms] no flags", test_wait_timeout<0, 0, 0>),
Case("Validate flags_wait return status if timeout specified: 0[ms] all flags", test_wait_timeout<ALL_SIGNALS, 0, 0>),
Case("Validate flags_wait return status if timeout specified: 1[ms] no flags", test_wait_timeout<0, 1, 0>),
Case("Validate flags_wait return status if timeout specified: 1[ms] all flags", test_wait_timeout<ALL_SIGNALS, 1, 0>),
Case("Validate that call of flags_wait_all_for return correctly when thread has all flags already set", test_wait_all_already_set),
Case("Validate if flags_wait_all_for return correctly when all flags set", test_wait_all),
Case("Validate if flags_wait_all_for accumulate flags and return correctly when all flags set", test_wait_all_loop),
Case("Validate if setting same flag twice cause any unwanted behaviour", test_set_double),
#endif
};
utest::v1::Specification specification(test_setup, cases);
int main()
{
return !utest::v1::Harness::run(specification);
}
#endif // !DEVICE_USTICKER