Merge pull request #7582 from fkjagodzinski/test_update-sleep_manager

Update sleep manager tests
pull/8364/merge
Cruz Monrreal 2018-10-10 08:39:34 -05:00 committed by GitHub
commit 9deefe5de1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 565 additions and 113 deletions

View File

@ -25,26 +25,9 @@
#include "greentea-client/test_env.h"
#include "mbed_lp_ticker_wrapper.h"
#include "sleep_test_utils.h"
#include "sleep_api_tests.h"
#define US_PER_S 1000000
/* Flush serial buffer before deep sleep
*
* Since deepsleep() may shut down the UART peripheral, we wait for some time
* to allow for hardware serial buffers to completely flush.
*
* Take NUMAKER_PFM_NUC472 as an example:
* Its UART peripheral has 16-byte Tx FIFO. With baud rate set to 9600, flush
* Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 (ms). So set wait time to
* 20ms here for safe.
*
* This should be replaced with a better function that checks if the
* hardware buffers are empty. However, such an API does not exist now,
* so we'll use the busy_wait_ms() function for now.
*/
#define SERIAL_FLUSH_TIME_MS 20
using namespace utest::v1;
static char info[512] = {0};
@ -67,71 +50,6 @@ static const uint32_t sleep_mode_delta_us = (10 + 4 + 5);
* delta = default 10 ms + worst ticker resolution + extra time for code execution */
static const uint32_t deepsleep_mode_delta_us = (10000 + 125 + 5);
unsigned int ticks_to_us(unsigned int ticks, unsigned int freq)
{
return (unsigned int)((unsigned long long) ticks * US_PER_S / freq);
}
unsigned int us_to_ticks(unsigned int us, unsigned int freq)
{
return (unsigned int)((unsigned long long) us * freq / US_PER_S);
}
unsigned int overflow_protect(unsigned int timestamp, unsigned int ticker_width)
{
unsigned int counter_mask = ((1 << ticker_width) - 1);
return (timestamp & counter_mask);
}
bool compare_timestamps(unsigned int delta_ticks, unsigned int ticker_width, unsigned int expected, unsigned int actual)
{
const unsigned int counter_mask = ((1 << ticker_width) - 1);
const unsigned int lower_bound = ((expected - delta_ticks) & counter_mask);
const unsigned int upper_bound = ((expected + delta_ticks) & counter_mask);
if (lower_bound < upper_bound) {
if (actual >= lower_bound && actual <= upper_bound) {
return true;
} else {
return false;
}
} else {
if ((actual >= lower_bound && actual <= counter_mask) || (actual >= 0 && actual <= upper_bound)) {
return true;
} else {
return false;
}
}
}
void busy_wait_ms(int ms)
{
const ticker_info_t *info = us_ticker_get_info();
uint32_t mask = (1 << info->bits) - 1;
int delay = (int)((uint64_t)ms * info->frequency / 1000);
uint32_t prev = us_ticker_read();
while (delay > 0) {
uint32_t next = us_ticker_read();
delay -= (next - prev) & mask;
prev = next;
}
}
void us_ticker_isr(const ticker_data_t *const ticker_data)
{
us_ticker_clear_interrupt();
}
#ifdef DEVICE_LPTICKER
void lp_ticker_isr(const ticker_data_t *const ticker_data)
{
lp_ticker_clear_interrupt();
}
#endif
/* Test that wake-up time from sleep should be less than 10 us and
* high frequency ticker interrupt can wake-up target from sleep. */
void sleep_usticker_test()

View File

@ -0,0 +1,114 @@
/* 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.
*/
/**
* @addtogroup hal_sleep_test_utils
* @{
*/
#ifndef MBED_SLEEP_TEST_UTILS_H
#define MBED_SLEEP_TEST_UTILS_H
#include "hal/ticker_api.h"
#include "hal/us_ticker_api.h"
#include "hal/lp_ticker_api.h"
/* Flush serial buffer before deep sleep
*
* Since deepsleep() may shut down the UART peripheral, we wait for some time
* to allow for hardware serial buffers to completely flush.
*
* Take NUMAKER_PFM_NUC472 as an example:
* Its UART peripheral has 16-byte Tx FIFO. With baud rate set to 9600, flush
* Tx FIFO would take: 16 * 8 * 1000 / 9600 = 13.3 (ms). So set wait time to
* 20ms here for safe.
*
* This should be replaced with a better function that checks if the
* hardware buffers are empty. However, such an API does not exist now,
* so we'll use the busy_wait_ms() function for now.
*/
#define SERIAL_FLUSH_TIME_MS 20
#define US_PER_S 1000000
unsigned int ticks_to_us(unsigned int ticks, unsigned int freq)
{
return (unsigned int) ((unsigned long long) ticks * US_PER_S / freq);
}
unsigned int us_to_ticks(unsigned int us, unsigned int freq)
{
return (unsigned int) ((unsigned long long) us * freq / US_PER_S);
}
unsigned int overflow_protect(unsigned int timestamp, unsigned int ticker_width)
{
unsigned int counter_mask = ((1 << ticker_width) - 1);
return (timestamp & counter_mask);
}
bool compare_timestamps(unsigned int delta_ticks, unsigned int ticker_width, unsigned int expected, unsigned int actual)
{
const unsigned int counter_mask = ((1 << ticker_width) - 1);
const unsigned int lower_bound = ((expected - delta_ticks) & counter_mask);
const unsigned int upper_bound = ((expected + delta_ticks) & counter_mask);
if (lower_bound < upper_bound) {
if (actual >= lower_bound && actual <= upper_bound) {
return true;
} else {
return false;
}
} else {
if ((actual >= lower_bound && actual <= counter_mask) || (actual >= 0 && actual <= upper_bound)) {
return true;
} else {
return false;
}
}
}
void busy_wait_ms(int ms)
{
const ticker_info_t *info = us_ticker_get_info();
uint32_t mask = (1 << info->bits) - 1;
int delay = (int) ((uint64_t) ms * info->frequency / 1000);
uint32_t prev = us_ticker_read();
while (delay > 0) {
uint32_t next = us_ticker_read();
delay -= (next - prev) & mask;
prev = next;
}
}
void us_ticker_isr(const ticker_data_t * const ticker_data)
{
us_ticker_clear_interrupt();
}
#ifdef DEVICE_LPTICKER
void lp_ticker_isr(const ticker_data_t * const ticker_data)
{
lp_ticker_clear_interrupt();
}
#endif
#endif
/** @}*/

View File

@ -16,46 +16,286 @@
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include <limits.h>
#include "mbed.h"
#include "mbed_lp_ticker_wrapper.h"
#include "../sleep/sleep_test_utils.h"
#include "sleep_manager_api_tests.h"
#if !DEVICE_SLEEP
#error [NOT_SUPPORTED] test not supported
#endif
using namespace utest::v1;
#define SLEEP_DURATION_US 20000ULL
#define DEEP_SLEEP_TEST_CHECK_WAIT_US 2000
#define DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US 500
void sleep_manager_deepsleep_counter_test()
using utest::v1::Case;
using utest::v1::Specification;
using utest::v1::Harness;
static uint32_t num_test_errors = 0UL;
mbed_error_status_t mbed_error(mbed_error_status_t error_status, const char *error_msg, unsigned int error_value,
const char *filename, int line_number)
{
bool deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_TRUE(deep_sleep_allowed);
(void) error_status;
(void) error_msg;
(void) error_value;
(void) filename;
(void) line_number;
num_test_errors++;
return MBED_SUCCESS;
}
void test_lock_unlock()
{
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
sleep_manager_lock_deep_sleep();
deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_FALSE(deep_sleep_allowed);
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
sleep_manager_unlock_deep_sleep();
deep_sleep_allowed = sleep_manager_can_deep_sleep_test_check();
TEST_ASSERT_TRUE(deep_sleep_allowed);
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
}
utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
void test_lone_unlock()
{
greentea_case_failure_abort_handler(source, reason);
return STATUS_CONTINUE;
uint32_t expected_err_count = num_test_errors + 1;
sleep_manager_unlock_deep_sleep();
TEST_ASSERT_EQUAL_UINT32(expected_err_count, num_test_errors);
// Make sure upcoming tests won't be broken.
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
}
utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
void test_lock_eq_ushrt_max()
{
GREENTEA_SETUP(20, "default_auto");
return greentea_test_setup_handler(number_of_cases);
uint32_t lock_count = 0;
while (lock_count < USHRT_MAX) {
sleep_manager_lock_deep_sleep();
lock_count++;
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
}
while (lock_count > 1) {
sleep_manager_unlock_deep_sleep();
lock_count--;
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
}
sleep_manager_unlock_deep_sleep();
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
}
void test_lock_gt_ushrt_max()
{
uint32_t lock_count = 0;
while (lock_count < USHRT_MAX) {
sleep_manager_lock_deep_sleep();
lock_count++;
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
}
uint32_t expected_err_count = num_test_errors + 1;
sleep_manager_lock_deep_sleep();
TEST_ASSERT_EQUAL_UINT32(expected_err_count, num_test_errors);
// Make sure upcoming tests won't be broken.
while (lock_count > 0) {
sleep_manager_unlock_deep_sleep();
lock_count--;
}
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
}
#if DEVICE_LPTICKER
#if DEVICE_USTICKER
utest::v1::status_t testcase_setup(const Case * const source, const size_t index_of_case)
{
// Suspend the RTOS kernel scheduler to prevent interference with duration of sleep.
osKernelSuspend();
#if DEVICE_LPTICKER
ticker_suspend(get_lp_ticker_data());
#if (LPTICKER_DELAY_TICKS > 0)
// Suspend the low power ticker wrapper to prevent interference with deep sleep lock.
lp_ticker_wrapper_suspend();
#endif
#endif
ticker_suspend(get_us_ticker_data());
// Make sure HAL tickers are initialized.
us_ticker_init();
#if DEVICE_LPTICKER
lp_ticker_init();
#endif
return utest::v1::greentea_case_setup_handler(source, index_of_case);
}
utest::v1::status_t testcase_teardown(const Case * const source, const size_t passed, const size_t failed,
const utest::v1::failure_t failure)
{
ticker_resume(get_us_ticker_data());
#if DEVICE_LPTICKER
#if (LPTICKER_DELAY_TICKS > 0)
lp_ticker_wrapper_resume();
#endif
ticker_resume(get_lp_ticker_data());
#endif
osKernelResume(0);
return utest::v1::greentea_case_teardown_handler(source, passed, failed, failure);
}
/* This test is based on the fact that the high-speed clocks are turned off
* in deep sleep mode but remain on in the ordinary sleep mode. Low-speed
* clocks stay on for both sleep and deep sleep modes.
*
* The type of sleep that was actually used by sleep_manager_sleep_auto()
* can be detected by comparing times measured by us and lp tickers.
*/
void test_sleep_auto()
{
const ticker_info_t *us_ticker_info = get_us_ticker_data()->interface->get_info();
const unsigned us_ticker_mask = ((1 << us_ticker_info->bits) - 1);
const ticker_irq_handler_type us_ticker_irq_handler_org = set_us_ticker_irq_handler(us_ticker_isr);
const ticker_info_t *lp_ticker_info = get_lp_ticker_data()->interface->get_info();
const unsigned lp_ticker_mask = ((1 << lp_ticker_info->bits) - 1);
const ticker_irq_handler_type lp_ticker_irq_handler_org = set_lp_ticker_irq_handler(lp_ticker_isr);
us_timestamp_t us_ts1, us_ts2, lp_ts1, lp_ts2, us_diff1, us_diff2, lp_diff1, lp_diff2;
sleep_manager_lock_deep_sleep();
uint32_t lp_wakeup_ts_raw = lp_ticker_read() + us_to_ticks(SLEEP_DURATION_US, lp_ticker_info->frequency);
timestamp_t lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, lp_ticker_info->bits);
lp_ticker_set_interrupt(lp_wakeup_ts);
us_ts1 = ticks_to_us(us_ticker_read(), us_ticker_info->frequency);
lp_ts1 = ticks_to_us(lp_ticker_read(), lp_ticker_info->frequency);
sleep_manager_sleep_auto();
us_ts2 = ticks_to_us(us_ticker_read(), us_ticker_info->frequency);
us_diff1 = (us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1);
lp_ts2 = ticks_to_us(lp_ticker_read(), lp_ticker_info->frequency);
lp_diff1 = (lp_ts1 <= lp_ts2) ? (lp_ts2 - lp_ts1) : (lp_ticker_mask - lp_ts1 + lp_ts2 + 1);
// Deep sleep locked -- ordinary sleep mode used:
// * us_ticker powered ON,
// * lp_ticker powered ON,
// so both should increment equally.
// Verify us and lp tickers incremented equally, with 10% tolerance.
TEST_ASSERT_UINT64_WITHIN_MESSAGE(
SLEEP_DURATION_US / 10ULL, lp_diff1, us_diff1,
"Deep sleep mode locked, but still used");
sleep_manager_unlock_deep_sleep();
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
// Wait for hardware serial buffers to flush.
busy_wait_ms(SERIAL_FLUSH_TIME_MS);
lp_wakeup_ts_raw = lp_ticker_read() + us_to_ticks(SLEEP_DURATION_US, lp_ticker_info->frequency);
lp_wakeup_ts = overflow_protect(lp_wakeup_ts_raw, lp_ticker_info->bits);
lp_ticker_set_interrupt(lp_wakeup_ts);
us_ts1 = ticks_to_us(us_ticker_read(), us_ticker_info->frequency);
lp_ts1 = ticks_to_us(lp_ticker_read(), lp_ticker_info->frequency);
sleep_manager_sleep_auto();
us_ts2 = ticks_to_us(us_ticker_read(), us_ticker_info->frequency);
us_diff2 = (us_ts1 <= us_ts2) ? (us_ts2 - us_ts1) : (us_ticker_mask - us_ts1 + us_ts2 + 1);
lp_ts2 = ticks_to_us(lp_ticker_read(), lp_ticker_info->frequency);
lp_diff2 = (lp_ts1 <= lp_ts2) ? (lp_ts2 - lp_ts1) : (lp_ticker_mask - lp_ts1 + lp_ts2 + 1);
// Deep sleep unlocked -- deep sleep mode used:
// * us_ticker powered OFF,
// * lp_ticker powered ON.
// The us_ticker increment represents only the code execution time
// and should be much shorter than both:
// 1. current lp_ticker increment,
// 2. previous us_ticker increment (locked sleep test above)
// Verify that the current us_ticker increment:
// 1. is at most 10% of lp_ticker increment
// 2. is at most 10% of previous us_ticker increment.
TEST_ASSERT_MESSAGE(us_diff2 < lp_diff2 / 10ULL, "Deep sleep mode unlocked, but not used");
TEST_ASSERT_MESSAGE(us_diff2 < us_diff1 / 10ULL, "Deep sleep mode unlocked, but not used");
set_us_ticker_irq_handler(us_ticker_irq_handler_org);
set_lp_ticker_irq_handler(lp_ticker_irq_handler_org);
}
#endif
void test_lock_unlock_test_check()
{
// Make sure HAL tickers are initialized.
ticker_read(get_us_ticker_data());
ticker_read(get_lp_ticker_data());
// Use LowPowerTimer instead of Timer to prevent deep sleep lock.
LowPowerTimer lp_timer;
us_timestamp_t exec_time_unlocked, exec_time_locked;
LowPowerTimeout lp_timeout;
// Deep sleep unlocked:
// * sleep_manager_can_deep_sleep() returns true,
// * sleep_manager_can_deep_sleep_test_check() returns true instantly.
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
lp_timer.start();
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check());
lp_timer.stop();
exec_time_unlocked = lp_timer.read_high_resolution_us();
// Deep sleep locked:
// * sleep_manager_can_deep_sleep() returns false,
// * sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay.
sleep_manager_lock_deep_sleep();
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
lp_timer.reset();
lp_timer.start();
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep_test_check());
lp_timer.stop();
exec_time_locked = lp_timer.read_high_resolution_us();
TEST_ASSERT_UINT64_WITHIN(DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US,
exec_time_locked - exec_time_unlocked);
// Deep sleep unlocked with a 1 ms delay:
// * sleep_manager_can_deep_sleep() returns false,
// * sleep_manager_can_deep_sleep_test_check() returns true with a 1 ms delay,
// * sleep_manager_can_deep_sleep() returns true when checked again.
lp_timer.reset();
lp_timeout.attach_us(mbed::callback(sleep_manager_unlock_deep_sleep_internal),
DEEP_SLEEP_TEST_CHECK_WAIT_US / 2);
lp_timer.start();
TEST_ASSERT_FALSE(sleep_manager_can_deep_sleep());
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep_test_check());
lp_timer.stop();
TEST_ASSERT_UINT64_WITHIN(DEEP_SLEEP_TEST_CHECK_WAIT_DELTA_US, DEEP_SLEEP_TEST_CHECK_WAIT_US / 2,
lp_timer.read_high_resolution_us());
TEST_ASSERT_TRUE(sleep_manager_can_deep_sleep());
}
#endif
utest::v1::status_t testsuite_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10, "default_auto");
return utest::v1::greentea_test_setup_handler(number_of_cases);
}
Case cases[] = {
Case("sleep manager - deep sleep counter", sleep_manager_deepsleep_counter_test, greentea_failure_handler),
Case("deep sleep lock/unlock", test_lock_unlock),
Case("deep sleep unbalanced unlock", test_lone_unlock),
Case("deep sleep locked USHRT_MAX times", test_lock_eq_ushrt_max),
Case("deep sleep locked more than USHRT_MAX times", test_lock_gt_ushrt_max),
#if DEVICE_LPTICKER
#if DEVICE_USTICKER
Case("sleep_auto calls sleep/deep sleep based on lock",
(utest::v1::case_setup_handler_t) testcase_setup,
test_sleep_auto,
(utest::v1::case_teardown_handler_t) testcase_teardown),
#endif
Case("deep sleep lock/unlock test_check", test_lock_unlock_test_check),
#endif
};
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);
Specification specification(testsuite_setup, cases);
int main()
{
Harness::run(specification);
return !Harness::run(specification);
}

View File

@ -0,0 +1,102 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 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.
*/
/**
* @addtogroup hal_sleep_manager_tests
* @{
*/
#ifndef MBED_HAL_SLEEP_MANAGER_API_TESTS_H
#define MBED_HAL_SLEEP_MANAGER_API_TESTS_H
#if DEVICE_SLEEP
/** Test lock/unlock
*
* Given no prior calls to lock/unlock
* When the deep sleep status is checked
* Then the deep sleep is allowed
*
* When the lock function is called
* Then the deep sleep is not allowed
*
* When the unlock function is called
* Then the deep sleep is allowed again
*/
void test_lock_unlock();
/** Test an unbalanced unlock call
*
* Given the deep sleep has not been locked
* When the deep sleep mode is unlocked
* Then an mbed_error is raised
*/
void test_lone_unlock();
/** Test lock USHRT_MAX times
*
* Given a device with sleep mode support
* When deep sleep mode is locked USHRT_MAX times
* Then the deep sleep mode is locked
*
* When unlock is called repeatedly
* Then deep sleep mode stays locked until the number
* of unlock calls is equal to number of lock calls
*/
void test_lock_eq_ushrt_max();
/** Test lock more than USHRT_MAX times
*
* Given the deep sleep has already been locked USHRT_MAX times
* When the deep sleep mode is locked again
* Then an mbed_error is raised
*/
void test_lock_gt_ushrt_max();
/** Test sleep_auto calls sleep and deep sleep based on lock
*
* Given a device with sleep mode support
* When the deep sleep mode is locked
* Then sleep_auto uses sleep mode
*
* When the deep sleep mode is unlocked
* Then sleep_auto uses deep sleep mode
*/
void test_sleep_auto();
/** Test lock/unlock test_check fun
*
* Given the deep sleep has not been locked
* When the deep sleep status is checked
* Then sleep_manager_can_deep_sleep() returns true
* and sleep_manager_can_deep_sleep_test_check() returns true instantly.
*
* When the deep sleep mode is locked
* Then sleep_manager_can_deep_sleep() returns false
* and sleep_manager_can_deep_sleep_test_check() returns false with 2 ms delay.
*
* When the deep sleep mode is unlocked with a 1 ms delay
* Then sleep_manager_can_deep_sleep() returns false
* and sleep_manager_can_deep_sleep_test_check() returns true with 1 ms delay
* and sleep_manager_can_deep_sleep() returns true when checked again.
*/
void test_lock_unlock_test_check();
#endif
#endif
/** @}*/

View File

@ -13,10 +13,11 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "utest/utest.h"
#include "unity/unity.h"
#include "greentea-client/test_env.h"
#include "mbed.h"
#include "sleep_manager_api_racecondition_tests.h"
#if !DEVICE_SLEEP
#error [NOT_SUPPORTED] test not supported
@ -94,8 +95,8 @@ utest::v1::status_t greentea_test_setup(const size_t number_of_cases)
}
Case cases[] = {
Case("sleep manager HAL - locking multithreaded", sleep_manager_multithread_test),
Case("sleep manager HAL - locking IRQ", sleep_manager_irq_test),
Case("deep sleep lock/unlock is thread safe", sleep_manager_multithread_test),
Case("deep sleep lock/unlock is IRQ safe", sleep_manager_irq_test),
};
Specification specification(greentea_test_setup, cases, greentea_test_teardown_handler);

View File

@ -0,0 +1,43 @@
/* mbed Microcontroller Library
* Copyright (c) 2018 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.
*/
/**
* @addtogroup hal_sleep_manager_tests
* @{
*/
#ifndef MBED_HAL_SLEEP_MANAGER_API_RACECONDITION_TESTS_H
#define MBED_HAL_SLEEP_MANAGER_API_RACECONDITION_TESTS_H
/** Test lock/unlock is thread safe
*
* Given a device with sleep mode support
* When multiple threads are using the sleep manager API
* Then lock/unlock calls are thread safe
*/
void sleep_manager_multithread_test();
/** Test lock/unlock is IRQ safe
*
* Given a device with sleep mode support
* When the sleep manager API is used from IRQ and the main thread concurrently
* Then lock/unlock calls are IRQ safe
*/
void sleep_manager_irq_test();
#endif
/** @}*/

View File

@ -163,6 +163,10 @@ void sleep_manager_lock_deep_sleep_internal(void)
if (deep_sleep_lock == USHRT_MAX) {
core_util_critical_section_exit();
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_OVERFLOW), "DeepSleepLock overflow (> USHRT_MAX)", deep_sleep_lock);
// When running sleep_manager tests, the mbed_error() is overridden
// and no longer calls mbed_halt_system(). Return to prevent
// execution of the following code.
return;
}
core_util_atomic_incr_u16(&deep_sleep_lock, 1);
core_util_critical_section_exit();
@ -174,6 +178,10 @@ void sleep_manager_unlock_deep_sleep_internal(void)
if (deep_sleep_lock == 0) {
core_util_critical_section_exit();
MBED_ERROR1(MBED_MAKE_ERROR(MBED_MODULE_HAL, MBED_ERROR_CODE_UNDERFLOW), "DeepSleepLock underflow (< 0)", deep_sleep_lock);
// When running sleep_manager tests, the mbed_error() is overridden
// and no longer calls mbed_halt_system(). Return to prevent
// execution of the following code.
return;
}
core_util_atomic_decr_u16(&deep_sleep_lock, 1);
core_util_critical_section_exit();

View File

@ -32,7 +32,8 @@
extern "C" {
#endif
/** Sleep manager API
/**
* @defgroup hal_sleep_manager Sleep manager API
* The sleep manager provides API to automatically select sleep mode.
*
* There are two sleep modes:
@ -43,6 +44,17 @@ extern "C" {
* are not allowed (=disabled) during the deepsleep. For instance, high frequency
* clocks.
*
* # Defined behavior
* * The lock is a counter
* * The lock can be locked up to USHRT_MAX - Verified by ::test_lock_eq_ushrt_max and ::test_lock_gt_ushrt_max
* * The lock has to be equally unlocked as locked - Verified by ::test_lone_unlock and ::test_lock_eq_ushrt_max
* * The function sleep_manager_lock_deep_sleep_internal() locks the automatic deep mode selection - Verified by ::test_lock_unlock
* * The function sleep_manager_unlock_deep_sleep_internal() unlocks the automatic deep mode selection - Verified by ::test_lock_unlock
* * The function sleep_manager_sleep_auto() chooses the sleep or deep sleep modes based on the lock - Verified by ::test_sleep_auto
* * The function sleep_manager_lock_deep_sleep_internal() is IRQ and thread safe - Verified by ::sleep_manager_multithread_test and ::sleep_manager_irq_test
* * The function sleep_manager_unlock_deep_sleep_internal() is IRQ and thread safe - Verified by ::sleep_manager_multithread_test and ::sleep_manager_irq_test
* * The function sleep_manager_sleep_auto() is IRQ and thread safe
*
* Example:
* @code
*
@ -63,7 +75,19 @@ extern "C" {
* return _sensor.start(event, callback);
* }
* @endcode
* @{
*/
/**
* @defgroup hal_sleep_manager_tests Sleep manager API tests
* Tests to validate the proper implementation of the sleep manager
*
* To run the sleep manager hal tests use the command:
*
* mbed test -t <toolchain> -m <target> -n tests-mbed_hal-sleep_manager*
*
*/
#ifdef MBED_SLEEP_TRACING_ENABLED
void sleep_tracker_lock(const char *const filename, int line);
@ -203,15 +227,6 @@ static inline void deepsleep(void)
#endif /* DEVICE_SLEEP */
}
/** Resets the processor and most of the sub-system
*
* @note Does not affect the debug sub-system
*/
static inline void system_reset(void)
{
NVIC_SystemReset();
}
/** Provides the time spent in sleep mode since boot.
*
* @return Time spent in sleep
@ -240,6 +255,17 @@ us_timestamp_t mbed_time_idle(void);
*/
us_timestamp_t mbed_uptime(void);
/** @}*/
/** Resets the processor and most of the sub-system
*
* @note Does not affect the debug sub-system
*/
static inline void system_reset(void)
{
NVIC_SystemReset();
}
#ifdef __cplusplus
}
#endif