diff --git a/TESTS/mbed_drivers/watchdog/Watchdog_tests.h b/TESTS/mbed_drivers/watchdog/Watchdog_tests.h new file mode 100644 index 0000000000..cf2d6da30a --- /dev/null +++ b/TESTS/mbed_drivers/watchdog/Watchdog_tests.h @@ -0,0 +1,108 @@ +/* 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 drivers_watchdog_tests + * @{ + */ + +#ifndef MBED_DRIVERS_WATCHDOG_TESTS_H +#define MBED_DRIVERS_WATCHDOG_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test max_timeout is valid + * + * Given a device supporting Watchdog driver API + * When @a Watchdog::max_timeout() is called + * Then the returned value is greater than 1 + */ +void test_max_timeout_is_valid(); + +/** Test watchdog can be stopped + * + * Given a platform with a support for disabling a running watchdog + * When watchdog is not running and @a Watchdog::stop() is called + * Then WATCHDOG_STATUS_OK is returned + * When watchdog is running + * and @a Watchdog::stop() is called before timeout + * Then WATCHDOG_STATUS_OK is returned + * and watchdog does not reset the device + * When watchdog has already been stopped and @a Watchdog::stop() is called + * Then WATCHDOG_STATUS_OK is returned + */ +void test_stop(); + +/** Test restart watchdog multiple times + * + * Given @a max_timeout value returned by @a Watchdog::max_timeout() + * and @a Watchdog::start() called multiple times + * When @a timeout is set to max_timeout - delta + * Then return value of @a Watchdog::start() is @a WATCHDOG_STATUS_OK + * and @a Watchdog::reload_value() returns max_timeout - delta + * When @a timeout is set to max_timeout + * Then return value of @a Watchdog::start() is @a WATCHDOG_STATUS_OK + * and @a Watchdog::reload_value() returns max_timeout + * When @a timeout is set to max_timeout + delta + * Then return value of @a Watchdog::start() is @a WATCHDOG_STATUS_INVALID_ARGUMENT + * and @a Watchdog::reload_value() returns previously set value (max_timeout) + * When @a timeout is set to 0 + * Then return value of @a Watchdog::start() is @a WATCHDOG_STATUS_INVALID_ARGUMENT + * and @a Watchdog::reload_value() returns previously set value (max_timeout) + */ +void test_restart(); + +/** Test start with 0 ms + * + * Given a device supporting Watchdog driver API + * When @a timeout is set to 0 ms + * Then return value of Watchdog::start() is @a WATCHDOG_STATUS_INVALID_ARGUMENT + */ +void test_start_zero(); + +/** Test start with a valid config + * + * Given a device supporting Watchdog driver API + * When @a timeout is set to value X within platform's timeout range + * Then return value of Watchdog::start() is @a WATCHDOG_STATUS_OK + * and @a Watchdog::reload_value() returns X + */ +template +void test_start(); + +/** Test start with a max_timeout + * + * Given @a max_timeout value returned by @a Watchdog::max_timeout() + * When @a timeout is set to max_timeout + * Then return value of Watchdog::start() is @a WATCHDOG_STATUS_OK + * and @a Watchdog::reload_value() returns max_timeout + */ +void test_start_max_timeout(); + +/** Test start with a timeout value exceeding max_timeout + * + * Given a device supporting Watchdog driver API + * When @a timeout is set to max_timeout + 1 + * Then return value of Watchdog::start() is @a WATCHDOG_STATUS_INVALID_ARGUMENT + */ +void test_start_max_timeout_exceeded(); + +#endif + +#endif + +/** @}*/ + diff --git a/TESTS/mbed_drivers/watchdog/main.cpp b/TESTS/mbed_drivers/watchdog/main.cpp new file mode 100644 index 0000000000..386593e172 --- /dev/null +++ b/TESTS/mbed_drivers/watchdog/main.cpp @@ -0,0 +1,221 @@ +/* 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. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#endif + +#define __STDC_LIMIT_MACROS +#include +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "drivers/Watchdog.h" +#include "Watchdog_tests.h" + +/* This is platform specific and depends on the watchdog timer implementation, + * e.g. STM32F4 uses 32kHz internal RC oscillator to clock the IWDG, so + * when the prescaler divider is set to max value of 256 the resolution + * drops to 8 ms. + */ +#define WORST_TIMEOUT_RESOLUTION_MS 8UL + +#define TIMEOUT_DELTA_MS (WORST_TIMEOUT_RESOLUTION_MS) +#define WDG_TIMEOUT_MS 500UL + +#define MSG_VALUE_DUMMY "0" +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_DEVICE_RESET "reset_on_case_teardown" + +int CASE_INDEX_START; +int CASE_INDEX_CURRENT; + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +void test_max_timeout_is_valid() +{ + Watchdog watchdog; + TEST_ASSERT(watchdog.max_timeout() > 1UL); +} + +void test_stop() +{ + Watchdog watchdog; + if (watchdog.stop() == WATCHDOG_STATUS_NOT_SUPPORTED) { + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.stop()); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(WDG_TIMEOUT_MS)); + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.stop()); + // Make sure that a disabled watchdog does not reset the core. + wait_ms(WDG_TIMEOUT_MS + TIMEOUT_DELTA_MS); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.stop()); +} + +void test_restart() +{ + Watchdog watchdog; + watchdog.start(watchdog.max_timeout()); + uint64_t timeout = watchdog.max_timeout() - 2ULL * WORST_TIMEOUT_RESOLUTION_MS; + watchdog_status_t status = watchdog.start(timeout); + + if (status == WATCHDOG_STATUS_NOT_SUPPORTED) { + TEST_IGNORE_MESSAGE("Updating watchdog config not supported for this platform"); + return; + } + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, status); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, timeout, watchdog.reload_value()); + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(watchdog.max_timeout())); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); + + timeout = watchdog.max_timeout() + 2ULL * WORST_TIMEOUT_RESOLUTION_MS; + // Make sure requested timeout does not overflow uint32_t. + if (timeout <= UINT32_MAX) { + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_INVALID_ARGUMENT, watchdog.start(timeout)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); + } + + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_INVALID_ARGUMENT, watchdog.start(0UL)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); +} + +utest::v1::status_t case_setup_sync_on_reset(const Case * const source, const size_t index_of_case) +{ + CASE_INDEX_CURRENT = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t case_teardown_sync_on_reset(const Case * const source, const size_t passed, const size_t failed, + const utest::v1::failure_t failure) +{ + utest::v1::status_t status = utest::v1::greentea_case_teardown_handler(source, passed, failed, failure); + if (failed) { + /* Return immediately and skip the device reset, if the test case failed. + * Provided that the device won't be restarted by other means (i.e. watchdog timer), + * this should allow the test suite to finish in a defined manner + * and report failure to host. + * In case of watchdog reset during test suite teardown, the loss of serial + * connection is possible, so the host-test-runner may return 'TIMEOUT' + * instead of 'FAIL'. + */ + return status; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, CASE_INDEX_START + CASE_INDEX_CURRENT); + utest_printf("The device will now restart.\n"); + wait_ms(10); // Wait for the serial buffers to flush. + NVIC_SystemReset(); + return status; // Reset is instant so this line won't be reached. +} + +void test_start_zero() +{ + Watchdog watchdog; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_INVALID_ARGUMENT, watchdog.start(0UL)); +} + +template +void test_start() +{ + Watchdog watchdog; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(timeout_ms)); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, timeout_ms, watchdog.reload_value()); +} + +void test_start_max_timeout() +{ + Watchdog watchdog; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(watchdog.max_timeout())); + TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, watchdog.max_timeout(), watchdog.reload_value()); +} + +void test_start_max_timeout_exceeded() +{ + Watchdog watchdog; + uint64_t timeout = watchdog.max_timeout() + 2ULL * WORST_TIMEOUT_RESOLUTION_MS; + // Make sure requested timeout does not overflow uint32_t. + if (timeout > UINT32_MAX) { + TEST_IGNORE_MESSAGE("Requested timeout overflows uint32_t -- ignoring test case."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_INVALID_ARGUMENT, watchdog.start(timeout)); +} + +int testsuite_setup_sync_on_reset(const size_t number_of_cases) +{ + GREENTEA_SETUP(45, "sync_on_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + char *tailptr = NULL; + CASE_INDEX_START = (int) strtol(value, &tailptr, 10); + if (*tailptr != '\0' || CASE_INDEX_START < 0) { + utest_printf("Invalid start case index received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("Starting with test case index %i of all %i defined test cases.\n", CASE_INDEX_START, number_of_cases); + return CASE_INDEX_START; +} + +Case cases[] = { + Case("max_timeout is valid", test_max_timeout_is_valid), + Case("Stop", test_stop), + Case("Restart multiple times", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_restart, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + + // Do not set watchdog timeout shorter than 500 ms as it may cause the + // host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' if watchdog + // performs reset during test suite teardown. + Case("Start, 500 ms", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_start<500UL>, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + Case("Start, max_timeout", (utest::v1::case_setup_handler_t) case_setup_sync_on_reset, + test_start_max_timeout, (utest::v1::case_teardown_handler_t) case_teardown_sync_on_reset), + + Case("Start, 0 ms", test_start_zero), + Case("Start, max_timeout exceeded", test_start_max_timeout_exceeded), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup_sync_on_reset, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +} diff --git a/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h b/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h new file mode 100644 index 0000000000..e4add3a50a --- /dev/null +++ b/TESTS/mbed_drivers/watchdog_reset/Watchdog_reset_tests.h @@ -0,0 +1,77 @@ +/* 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 drivers_watchdog_tests + * @{ + */ + +#ifndef MBED_DRIVERS_WATCHDOG_RESET_TESTS_H +#define MBED_DRIVERS_WATCHDOG_RESET_TESTS_H + +#if DEVICE_WATCHDOG + +/** Test watchdog reset + * + * Given a device with a watchdog started + * When a watchdog timeout expires + * Then the device is restarted + */ +void test_simple_reset(); + +/** Test watchdog reset in sleep mode + * + * Given a device supporting sleep mode, with a watchdog started + * When the device is in sleep mode and watchdog timeout expires + * Then the device is restarted + */ +void test_sleep_reset(); + +/** Test watchdog reset in deepsleep mode + * + * Given a device supporting deepsleep mode, with watchdog started + * When the device is in deepsleep mode and watchdog timeout expires + * Then the device is restarted + */ +void test_deepsleep_reset(); + +/** Test stopped watchdog can be started again and reset the device + * + * Given a device supporting 'disable_watchdog' feature, with watchdog started + * When the watchdog is stopped before timeout expires + * Then the device is not restarted + * When the watchdog is started again and it's timeout expires + * Then the device is restarted + */ +void test_restart_reset(); + +/** Test kicking the watchdog prevents reset + * + * Given a device with watchdog started + * When the watchdog is kicked before timeout expires + * Then the device restart is prevented + * When the watchdog is *NOT* kicked again before next timeout expires + * Then the device is restarted + * + */ +void test_kick_reset(); + +#endif + +#endif + +/** @}*/ + diff --git a/TESTS/mbed_drivers/watchdog_reset/main.cpp b/TESTS/mbed_drivers/watchdog_reset/main.cpp new file mode 100644 index 0000000000..45d8e941c8 --- /dev/null +++ b/TESTS/mbed_drivers/watchdog_reset/main.cpp @@ -0,0 +1,285 @@ +/* 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. + */ +#if !DEVICE_WATCHDOG +#error [NOT_SUPPORTED] Watchdog not supported for this target +#endif + +#include "greentea-client/test_env.h" +#include "utest/utest.h" +#include "unity/unity.h" +#include "drivers/Watchdog.h" +#include "Watchdog_reset_tests.h" +#include "mbed.h" + +#define TIMEOUT_MS 500UL +#define TIMEOUT_DELTA_MS 50UL + +#define MSG_VALUE_DUMMY "0" +#define CASE_DATA_INVALID 0xffffffffUL +#define CASE_DATA_PHASE2_OK 0xfffffffeUL + +#define MSG_VALUE_LEN 24 +#define MSG_KEY_LEN 24 + +#define MSG_KEY_DEVICE_READY "ready" +#define MSG_KEY_START_CASE "start_case" +#define MSG_KEY_DEVICE_RESET "dev_reset" + +using utest::v1::Case; +using utest::v1::Specification; +using utest::v1::Harness; + +struct testcase_data { + int index; + int start_index; + uint32_t received_data; +}; + +void release_sem(Semaphore *sem) +{ + sem->release(); +} + +testcase_data current_case; + +bool send_reset_notification(testcase_data * tcdata, uint32_t delay_ms) +{ + char msg_value[12]; + int str_len = snprintf(msg_value, sizeof msg_value, "%02x,%08lx", tcdata->start_index + tcdata->index, delay_ms); + if (str_len != (sizeof msg_value) - 1) { + utest_printf("Failed to compose a value string to be sent to host."); + return false; + } + greentea_send_kv(MSG_KEY_DEVICE_RESET, msg_value); + return true; +} + +void test_simple_reset() +{ + // Phase 2. -- verify the test results. + // Verify if this test case passed based on data received from host. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + // Init the watchdog and wait for a device reset. + Watchdog watchdog; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during wait_ms() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +#if DEVICE_SLEEP +void test_sleep_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + Watchdog watchdog; + Semaphore sem(0, 1); + Timeout timeout; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + sleep_manager_lock_deep_sleep(); + timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); + if (sleep_manager_can_deep_sleep()) { + TEST_ASSERT_MESSAGE(0, "Deepsleep should be disallowed."); + return; + } + while (sem.wait(0) != 1) { + sleep(); // Device reset expected. + } + sleep_manager_unlock_deep_sleep(); + + // Watchdog reset should have occurred during sleep() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +#if DEVICE_LOWPOWERTIMER +void test_deepsleep_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + Watchdog watchdog; + Semaphore sem(0, 1); + LowPowerTimeout lp_timeout; + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); + wait_ms(10); // Wait for the serial buffers to flush. + if (!sleep_manager_can_deep_sleep()) { + TEST_ASSERT_MESSAGE(0, "Deepsleep should be allowed."); + } + while (sem.wait(0) != 1) { + sleep(); // Device reset expected. + } + + // Watchdog reset should have occurred during that sleep() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} +#endif +#endif + +void test_restart_reset() +{ + Watchdog watchdog; + if (watchdog.stop() == WATCHDOG_STATUS_NOT_SUPPORTED) { + TEST_IGNORE_MESSAGE("Disabling watchdog not supported for this platform"); + return; + } + + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + wait_ms(TIMEOUT_MS / 2UL); + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.stop()); + // Check that stopping the watchdog prevents a device reset. + wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_DELTA_MS); + + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during that wait() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +void test_kick_reset() +{ + // Phase 2. -- verify the test results. + if (current_case.received_data != CASE_DATA_INVALID) { + TEST_ASSERT_EQUAL(CASE_DATA_PHASE2_OK, current_case.received_data); + current_case.received_data = CASE_DATA_INVALID; + return; + } + + // Phase 1. -- run the test code. + Watchdog watchdog; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, watchdog.start(TIMEOUT_MS)); + for (int i = 3; i; i--) { + wait_ms(TIMEOUT_MS / 2UL); + watchdog.kick(); + } + if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); + return; + } + wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + + // Watchdog reset should have occurred during that wait() above; + + watchdog.kick(); // Just to buy some time for testsuite failure handling. + TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); +} + +utest::v1::status_t case_setup(const Case * const source, const size_t index_of_case) +{ + current_case.index = index_of_case; + return utest::v1::greentea_case_setup_handler(source, index_of_case); +} + +int testsuite_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(90, "watchdog_reset"); + utest::v1::status_t status = utest::v1::greentea_test_setup_handler(number_of_cases); + if (status != utest::v1::STATUS_CONTINUE) { + return status; + } + + char key[MSG_KEY_LEN + 1] = { }; + char value[MSG_VALUE_LEN + 1] = { }; + + greentea_send_kv(MSG_KEY_DEVICE_READY, MSG_VALUE_DUMMY); + greentea_parse_kv(key, value, MSG_KEY_LEN, MSG_VALUE_LEN); + + if (strcmp(key, MSG_KEY_START_CASE) != 0) { + utest_printf("Invalid message key.\n"); + return utest::v1::STATUS_ABORT; + } + + int num_args = sscanf(value, "%02x,%08lx", &(current_case.start_index), &(current_case.received_data)); + if (num_args == 0 || num_args == EOF) { + utest_printf("Invalid data received from host\n"); + return utest::v1::STATUS_ABORT; + } + + utest_printf("This test suite is composed of %i test cases. Starting at index %i.\n", number_of_cases, + current_case.start_index); + return current_case.start_index; +} + +Case cases[] = { + Case("Watchdog reset", case_setup, test_simple_reset), +#if DEVICE_SLEEP + Case("Watchdog reset in sleep mode", case_setup, test_sleep_reset), +#if DEVICE_LOWPOWERTIMER + Case("Watchdog reset in deepsleep mode", case_setup, test_deepsleep_reset), +#endif +#endif + Case("Watchdog started again", case_setup, test_restart_reset), + Case("Kicking the watchdog prevents reset", case_setup, test_kick_reset), +}; + +Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); + +int main() +{ + // Harness will start with a test case index provided by host script. + return !Harness::run(specification); +}