Marco Zecchini
/
Example_RTOS
Rtos API example
Diff: mbed-os/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp
- Revision:
- 0:9fca2b23d0ba
diff -r 000000000000 -r 9fca2b23d0ba mbed-os/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-os/TESTS/mbedmicro-rtos-mbed/event_flags/main.cpp Sat Feb 23 12:13:36 2019 +0000 @@ -0,0 +1,377 @@ +/* + * Copyright (c) 2013-2017, ARM Limited, All Rights Reserved + * 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 "unity/unity.h" +#include "utest/utest.h" + +using utest::v1::Case; + +#if defined(MBED_RTOS_SINGLE_THREAD) + #error [NOT_SUPPORTED] test not supported +#endif + +#define THREAD_STACK_SIZE 320 /* 512B stack on GCC_ARM compiler cause out of memory on some 16kB RAM boards e.g. NUCLEO_F070RB */ + +#define MAX_FLAG_POS 30 +#define PROHIBITED_FLAG_POS 31 + +/* flags */ +#define FLAG01 0x1FFF /* 00000000000000000001111111111111 */ +#define FLAG02 0x3FFE000 /* 00000011111111111110000000000000 */ +#define FLAG03 0x7C000000 /* 01111100000000000000000000000000 */ +#define PROHIBITED_FLAG 0x80000000 /* 10000000000000000000000000000000 */ +#define NO_FLAGS 0x0 + +Semaphore sync_sem(0, 1); + +/* In order to successfully run this test suite when compiled with --profile=debug + * error() has to be redefined as noop. + * + * EventFlags calls RTX API which uses Event Recorder functionality. When compiled + * with MBED_TRAP_ERRORS_ENABLED=1 (set in debug profile) EvrRtxEventFlagsError() calls error() + * which aborts test program. + */ +#if defined(MBED_TRAP_ERRORS_ENABLED) && MBED_TRAP_ERRORS_ENABLED +void error(const char* format, ...) { + (void) format; +} +#endif + +template<uint32_t flags, uint32_t wait_ms> +void send_thread(EventFlags *ef) +{ + for (uint32_t i = 0; i <= MAX_FLAG_POS; i++) { + const uint32_t flag = flags & (1 << i); + if (flag) { + ef->set(flag); + Thread::wait(wait_ms); + } + } +} + +template<uint32_t flags, uint32_t wait_ms> +void send_thread_sync(EventFlags *ef) +{ + for (uint32_t i = 0; i <= MAX_FLAG_POS; i++) { + const uint32_t flag = flags & (1 << i); + if (flag) { + sync_sem.wait(); + ef->set(flag); + Thread::wait(wait_ms); + } + } +} + +template<uint32_t flags> +void wait_thread_all(EventFlags *ef) +{ + uint32_t ret, flags_after_clear; + ret = ef->wait_all(flags); + flags_after_clear = ef->get(); + TEST_ASSERT(flags | ret); + TEST_ASSERT(flags | ~flags_after_clear); +} + + +/** Test if get on empty EventFlags object return NO_FLAGS + + Given a empty EventFlags object + When call @a get + Then @a get return status is NO_FLAGS + */ +void test_empty_get(void) +{ + EventFlags ev; + uint32_t flags; + + flags = ev.get(); + TEST_ASSERT_EQUAL(NO_FLAGS, flags); +} + +/** Test if clear on empty EventFlags object return NO_FLAGS + + Given a empty EventFlags object + When call @a clear(NO_FLAGS) + Then @a clear return status is NO_FLAGS + */ +void test_empty_clear(void) +{ + EventFlags ev; + uint32_t flags; + + flags = ev.clear(NO_FLAGS); + TEST_ASSERT_EQUAL(NO_FLAGS, flags); +} + +/** Test if set on empty EventFlags object return NO_FLAGS + + Given a empty EventFlags object + When call @a set(NO_FLAGS) + Then @a set return status is NO_FLAGS + */ +void test_empty_set(void) +{ + EventFlags ev; + uint32_t flags; + + flags = ev.set(NO_FLAGS); + TEST_ASSERT_EQUAL(NO_FLAGS, flags); +} + +/** Test if call of set/clean with PROHIBITED_FLAG doesn't invalidates object flags + + Given a EventFlags object with all flags already set + When call @a clear(PROHIBITED_FLAG) with prohibited flag + Then @a clear return status is osFlagsErrorParameter and object flags stays unchanged + When call @a set(PROHIBITED_FLAG) with prohibited flag + Then @a set return status is osFlagsErrorParameter and object flags stays 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_prohibited(void) +{ + EventFlags ev; + uint32_t flags; + + ev.set(FLAG01 | FLAG02 | FLAG03); + + flags = ev.clear(PROHIBITED_FLAG); + TEST_ASSERT_EQUAL(osFlagsErrorParameter, flags); + + flags = ev.get(); + TEST_ASSERT_EQUAL(FLAG01 | FLAG02 | FLAG03, flags); + + flags = ev.set(PROHIBITED_FLAG); + TEST_ASSERT_EQUAL(osFlagsErrorParameter, flags); + + flags = ev.get(); + TEST_ASSERT_EQUAL(FLAG01 | FLAG02 | FLAG03, flags); +} + +/** Test set/get/clear for full flag range + + Given a EventFlags object + When call @a clear + Then @a clear return status is already set flags + When call @a set with specified flag + Then @a set return status is flags after setting + When call @a get + Then @a get return status is set flags + */ +void test_set_get_clear_full_flag_range(void) +{ + EventFlags ev; + uint32_t flag, flags, ret; + + flags = NO_FLAGS; + for (int i = 0; i <= MAX_FLAG_POS; i++) { + ret = ev.clear(); + TEST_ASSERT_EQUAL(flags, ret); + flags = 1 << i; + ret = ev.set(flags); + TEST_ASSERT_EQUAL(flags, ret); + ret = ev.get(); + TEST_ASSERT_EQUAL(flags, ret); + } + + ev.clear(); + flags = NO_FLAGS; + for (int i = 0; i <= MAX_FLAG_POS; i++) { + ret = ev.clear(NO_FLAGS); + TEST_ASSERT_EQUAL(flags, ret); + flag = 1 << i; + flags |= flag; + ret = ev.set(flag); + TEST_ASSERT_EQUAL(flags, ret); + ret = ev.get(); + TEST_ASSERT_EQUAL(flags, ret); + } +} + +/** Test if multi-threaded flag set cause wait_all to return + + Given a EventFlags object and three threads are started in parallel + When threads set specified flags + Then main thread waits until receive all of them + */ +void test_multi_thread_all(void) +{ + EventFlags ef; + Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); + thread1.start(callback(send_thread<FLAG01, 1>, &ef)); + thread2.start(callback(send_thread<FLAG02, 2>, &ef)); + thread3.start(callback(send_thread<FLAG03, 3>, &ef)); + + uint32_t ret = ef.wait_all(FLAG01 | FLAG02 | FLAG03); + TEST_ASSERT_EQUAL(FLAG01 | FLAG02 | FLAG03, ret); +} + +/** Test if multi-threaded flag set cause wait_any to return + + Given a EventFlags object and three threads are started in parallel + When threads set specified flags + Then main thread waits until receive all of them + */ +void test_multi_thread_any(void) +{ + EventFlags ef; + uint32_t ret; + Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); + thread1.start(callback(send_thread<FLAG01, 1>, &ef)); + thread2.start(callback(send_thread<FLAG02, 1>, &ef)); + thread3.start(callback(send_thread<FLAG03, 1>, &ef)); + + for (int i = 0; i <= MAX_FLAG_POS; i++) { + uint32_t flag = 1 << i; + ret = ef.wait_any(flag); + TEST_ASSERT(flag | ret); + } + ret = ef.get(); + TEST_ASSERT_EQUAL(NO_FLAGS, ret); +} + +/** Test if multi-threaded flag set cause wait_any(with timeout) to return + + Given a EventFlags object and thread is running + When main thread call @ wait_any with timeout + Then when timeout expires @ wait_any return status is osFlagsErrorTimeout + When main thread call @ wait_any with timeout and thread set specified flags + Then main thread waits until receive all of them and @ wait_any return status is wait flag + */ +void test_multi_thread_any_timeout(void) +{ + EventFlags ef; + uint32_t ret; + Thread thread(osPriorityNormal, THREAD_STACK_SIZE); + thread.start(callback(send_thread_sync<FLAG01 | FLAG02 | FLAG03, 1>, &ef)); + + for (int i = 0; i <= MAX_FLAG_POS; i++) { + uint32_t flag = 1 << i; + + ret = ef.wait_any(flag, 10); + TEST_ASSERT_EQUAL(osFlagsErrorTimeout, ret); + + sync_sem.release(); + ret = ef.wait_any(flag, 10); + TEST_ASSERT_EQUAL(flag, ret); + } + ret = ef.get(); + TEST_ASSERT_EQUAL(NO_FLAGS, ret); +} + +/** Test if multi-threaded flag set cause wait_any(without clear) to return + + Given a EventFlags object and three threads are started in parallel + When threads set specified flags + Then main thread waits until receive all of them + */ +void test_multi_thread_any_no_clear(void) +{ + EventFlags ef; + uint32_t ret; + Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); + thread1.start(callback(send_thread<FLAG01, 1>, &ef)); + thread2.start(callback(send_thread<FLAG02, 1>, &ef)); + thread3.start(callback(send_thread<FLAG03, 1>, &ef)); + + for (int i = 0; i <= MAX_FLAG_POS; i++) { + uint32_t flag = 1 << i; + ret = ef.wait_any(flag, osWaitForever, false); + TEST_ASSERT(flag | ret); + ret = ef.clear(flag); + TEST_ASSERT(ret < osFlagsError); + } + ret = ef.get(); + TEST_ASSERT_EQUAL(NO_FLAGS, ret); +} + +/** Test multi-threaded wait_any + + Given a EventFlags object and three threads are started in parallel + When flags are set in main thread + Then other threads waits until receive all of them + */ +void test_multi_thread_all_many_wait(void) +{ + EventFlags ef; + { + Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); + thread1.start(callback(wait_thread_all<FLAG01>, &ef)); + thread2.start(callback(wait_thread_all<FLAG02>, &ef)); + thread3.start(callback(wait_thread_all<FLAG03>, &ef)); + + ef.set(FLAG01 | FLAG02 | FLAG03); + thread1.join(); + thread2.join(); + thread3.join(); + TEST_ASSERT_EQUAL(NO_FLAGS, ef.get()); + } + + { + Thread thread1(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread2(osPriorityNormal, THREAD_STACK_SIZE); + Thread thread3(osPriorityNormal, THREAD_STACK_SIZE); + thread1.start(callback(wait_thread_all<FLAG01>, &ef)); + thread2.start(callback(wait_thread_all<FLAG02>, &ef)); + thread3.start(callback(wait_thread_all<FLAG03>, &ef)); + + ef.set(FLAG01); + thread1.join(); + ef.set(FLAG02); + thread2.join(); + ef.set(FLAG03); + thread3.join(); + TEST_ASSERT_EQUAL(NO_FLAGS, ef.get()); + } +} + +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(10, "default_auto"); + return utest::v1::verbose_test_setup_handler(number_of_cases); +} + +Case cases[] = { + Case("Test empty clear", test_empty_clear), + Case("Test empty get", test_empty_get), + Case("Test empty set", test_empty_set), + Case("Test clear/set with prohibited flag", test_prohibited), + Case("Test set/get/clear for full flag range", test_set_get_clear_full_flag_range), + Case("Test multi-threaded wait_all", test_multi_thread_all), + Case("Test multi-threaded wait_any", test_multi_thread_any), + Case("Test multi-threaded wait_all many wait", test_multi_thread_all_many_wait), + Case("Test multi-threaded wait_any timeout", test_multi_thread_any_timeout), + Case("Test multi-threaded wait_any no clear", test_multi_thread_any_no_clear) +}; + +utest::v1::Specification specification(test_setup, cases); + +int main() +{ + return !utest::v1::Harness::run(specification); +}