/* mbed Microcontroller Library * Copyright (c) 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. * 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; volatile bool callback_called; void tiemout_callback(void) { callback_called = true; } template void critical_section_raii_recursive(Timeout &timeout) { static uint32_t depth = 0; CriticalSectionLock cs; depth++; TEST_ASSERT_TRUE(core_util_in_critical_section()); if(depth < N) { critical_section_raii_recursive(timeout); } else { // max depth reached - do the test const us_timestamp_t timeout_time_us = 1; const int wait_time_us = timeout_time_us * 100; timeout.attach_us(callback(tiemout_callback), timeout_time_us); wait_us(wait_time_us); } TEST_ASSERT_TRUE(core_util_in_critical_section()); TEST_ASSERT_FALSE(callback_called); } /** Template for tests Test C API of critical section Given a Timeout with callback attached When before critical section Then interrupts are enabled and timeout callback is fired When inside critical section Then interrupts are disabled and timeout callback is blocked When after critical section Then interrupts are enabled and timeout callback is fired Test C API of critical section - nested lock Given a Timeout with callback attached When before critical section Then interrupts are enabled and timeout callback is fired When inside nested critical section Then interrupts are disabled and timeout callback is blocked When after critical section Then interrupts are enabled and timeout callback is fired */ template void test_C_API(void) { Timeout timeout; const us_timestamp_t timeout_time_us = 1; const int wait_time_us = timeout_time_us * 100; TEST_ASSERT_FALSE(core_util_in_critical_section()); callback_called = false; timeout.attach_us(callback(tiemout_callback), timeout_time_us); wait_us(wait_time_us); TEST_ASSERT_TRUE(callback_called); for(int i = 0; i < N; i++) { core_util_critical_section_enter(); TEST_ASSERT_TRUE(core_util_in_critical_section()); } callback_called = false; timeout.attach_us(callback(tiemout_callback), timeout_time_us); wait_us(wait_time_us); TEST_ASSERT_FALSE(callback_called); TEST_ASSERT_TRUE(core_util_in_critical_section()); for(int i = 0; i < N - 1; i++) { core_util_critical_section_exit(); TEST_ASSERT_TRUE(core_util_in_critical_section()); TEST_ASSERT_FALSE(callback_called); } core_util_critical_section_exit(); TEST_ASSERT_FALSE(core_util_in_critical_section()); TEST_ASSERT_TRUE(callback_called); } /** Template for tests Test C++ API of critical section constructor/destructor Given a Timeout with callback attached When before critical section Then interrupts are enabled and timeout callback is fired When inside critical section Then interrupts are disabled and timeout callback is blocked When after critical section Then interrupts are enabled and timeout callback is fired Test C++ API of critical section constructor/destructor - nested lock Given a Timeout with callback attached When before critical section Then interrupts are enabled and timeout callback is fired When inside nested critical section Then interrupts are disabled and timeout callback is blocked When after critical section Then interrupts are enabled and timeout callback is fired */ template void test_CPP_API_constructor_destructor(void) { Timeout timeout; const us_timestamp_t timeout_time_us = 1; const int wait_time_us = timeout_time_us * 100; TEST_ASSERT_FALSE(core_util_in_critical_section()); callback_called = false; timeout.attach_us(callback(tiemout_callback), timeout_time_us); wait_us(wait_time_us); TEST_ASSERT_TRUE(callback_called); callback_called = false; critical_section_raii_recursive(timeout); TEST_ASSERT_FALSE(core_util_in_critical_section()); TEST_ASSERT_TRUE(callback_called); } /** Template for tests Test C++ API of critical section enable/disable Given a Timeout with attached callback When before critical section Then interrupts are enabled and timeout callback is fired When inside critical section Then interrupts are disabled and timeout callback is blocked When after critical section Then interrupts are enabled and timeout callback is fired Test C++ API of critical section enable/disable - nested lock Given a Timeout with attached callback When before critical section Then interrupts are enabled and timeout callback is fired When inside nested critical section Then interrupts are disabled and timeout callback is blocked When after critical section Then interrupts are enabled and timeout callback is fired */ template void test_CPP_API_enable_disable(void) { Timeout timeout; const us_timestamp_t timeout_time_us = 1; const int wait_time_us = timeout_time_us * 100; TEST_ASSERT_FALSE(core_util_in_critical_section()); callback_called = false; timeout.attach_us(callback(tiemout_callback), timeout_time_us); wait_us(wait_time_us); TEST_ASSERT_TRUE(callback_called); for(int i = 0; i < N; i++) { CriticalSectionLock::enable(); TEST_ASSERT_TRUE(core_util_in_critical_section()); } callback_called = false; timeout.attach_us(callback(tiemout_callback), timeout_time_us); wait_us(wait_time_us); TEST_ASSERT_FALSE(callback_called); TEST_ASSERT_TRUE(core_util_in_critical_section()); for(int i = 0; i < N - 1; i++) { CriticalSectionLock::disable(); TEST_ASSERT_TRUE(core_util_in_critical_section()); TEST_ASSERT_FALSE(callback_called); } CriticalSectionLock::disable(); TEST_ASSERT_FALSE(core_util_in_critical_section()); TEST_ASSERT_TRUE(callback_called); } 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 critical section C API", test_C_API<1>), Case("Test critical section C API nested lock", test_C_API<10>), Case("Test critical section C++ API constructor/destructor", test_CPP_API_constructor_destructor<1>), Case("Test critical section C++ API constructor/destructor nested lock", test_CPP_API_constructor_destructor<10>), Case("Test critical section C++ API enable/disable", test_CPP_API_enable_disable<1>), Case("Test critical section C++ API enable/disable nested lock", test_CPP_API_enable_disable<10>) }; utest::v1::Specification specification(test_setup, cases); int main() { return !utest::v1::Harness::run(specification); }