diff --git a/TESTS/mbed_drivers/reset_reason/main.cpp b/TESTS/mbed_drivers/reset_reason/main.cpp index a72796f8799..6299d869373 100644 --- a/TESTS/mbed_drivers/reset_reason/main.cpp +++ b/TESTS/mbed_drivers/reset_reason/main.cpp @@ -29,7 +29,6 @@ #define MSG_VALUE_WATCHDOG_STATUS "wdg_present" #define WDG_TIMEOUT_MS 50UL -#define WDG_TIMEOUT_DELTA_MS 50UL #else #define MSG_VALUE_WATCHDOG_STATUS "no_wdg" @@ -50,6 +49,8 @@ #define MSG_KEY_RESET_REASON "reason" #define MSG_KEY_DEVICE_RESET "reset" +#define SERIAL_FLUSH_TIME_MS 20 + typedef enum { CMD_STATUS_CONTINUE, CMD_STATUS_ERROR @@ -91,7 +92,7 @@ static cmd_status_t handle_command(const char *key, const char *value) if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_NVIC) == 0) { greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); - wait_ms(10); // Wait for the serial buffers to flush. + wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. NVIC_SystemReset(); TEST_ASSERT_MESSAGE(0, "NVIC_SystemReset did not reset the device as expected."); return CMD_STATUS_ERROR; @@ -100,13 +101,13 @@ static cmd_status_t handle_command(const char *key, const char *value) #if DEVICE_WATCHDOG if (strcmp(key, MSG_KEY_DEVICE_RESET) == 0 && strcmp(value, MSG_VALUE_DEVICE_RESET_WATCHDOG) == 0) { greentea_send_kv(MSG_KEY_DEVICE_RESET, MSG_VALUE_DEVICE_RESET_ACK); - wait_ms(10); // Wait for the serial buffers to flush. + wait_ms(SERIAL_FLUSH_TIME_MS); // Wait for the serial buffers to flush. watchdog_config_t config = { .timeout_ms = WDG_TIMEOUT_MS }; if (hal_watchdog_init(&config) != WATCHDOG_STATUS_OK) { TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error."); return CMD_STATUS_ERROR; } - wait_ms(WDG_TIMEOUT_MS + WDG_TIMEOUT_DELTA_MS); + wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value. TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); return CMD_STATUS_ERROR; } diff --git a/TESTS/mbed_hal/reset_reason/main.cpp b/TESTS/mbed_hal/reset_reason/main.cpp index 2dc68f63557..63136d3c0b8 100644 --- a/TESTS/mbed_hal/reset_reason/main.cpp +++ b/TESTS/mbed_hal/reset_reason/main.cpp @@ -29,7 +29,6 @@ #define MSG_VALUE_WATCHDOG_STATUS "wdg_present" #define WDG_TIMEOUT_MS 50UL -#define WDG_TIMEOUT_DELTA_MS 50UL #else #define MSG_VALUE_WATCHDOG_STATUS "no_wdg" @@ -115,7 +114,7 @@ static cmd_status_t handle_command(const char *key, const char *value) TEST_ASSERT_MESSAGE(0, "hal_watchdog_init() error."); return CMD_STATUS_ERROR; } - wait_ms(WDG_TIMEOUT_MS + WDG_TIMEOUT_DELTA_MS); + wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value. TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); return CMD_STATUS_ERROR; } diff --git a/TESTS/mbed_hal/watchdog/main.cpp b/TESTS/mbed_hal/watchdog/main.cpp index c22d1e9623a..a21d2ea91f2 100644 --- a/TESTS/mbed_hal/watchdog/main.cpp +++ b/TESTS/mbed_hal/watchdog/main.cpp @@ -28,18 +28,12 @@ #include -/* 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) +/* The shortest timeout value, this test suite is able to handle correctly. */ +#define WDG_MIN_TIMEOUT_MS 50UL -// Do not set watchdog timeout shorter than 50 ms as it may cause the -// host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' if watchdog -// performs reset during test suite teardown. +// Do not set watchdog timeout shorter than WDG_MIN_TIMEOUT_MS, as it may +// cause the host-test-runner return 'TIMEOUT' instead of 'FAIL' / 'PASS' +// if watchdog performs reset during test suite teardown. #define WDG_TIMEOUT_MS 100UL #define MSG_VALUE_DUMMY "0" @@ -115,7 +109,7 @@ void test_stop() TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&WDG_CONFIG_DEFAULT)); TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); // Make sure that a disabled watchdog does not reset the core. - wait_ms(WDG_TIMEOUT_MS + TIMEOUT_DELTA_MS); + wait_ms(2 * WDG_TIMEOUT_MS); // Watchdog should fire before twice the timeout value. TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); } @@ -129,16 +123,27 @@ void test_update_config() } watchdog_config_t config = WDG_CONFIG_DEFAULT; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value()); - - config.timeout_ms = features.max_timeout - 2 * WORST_TIMEOUT_RESOLUTION_MS; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value()); - - config.timeout_ms = features.max_timeout; - TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, config.timeout_ms, hal_watchdog_get_reload_value()); + uint32_t timeouts[] = { + features.max_timeout / 4, + features.max_timeout / 8, + features.max_timeout / 16 + }; + int num_timeouts = sizeof timeouts / sizeof timeouts[0]; + + for (size_t i = 0; i < num_timeouts; i++) { + if (timeouts[i] < WDG_MIN_TIMEOUT_MS) { + TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case."); + return; + } + + config.timeout_ms = timeouts[i]; + TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); + uint32_t reload_value = hal_watchdog_get_reload_value(); + // The watchdog should trigger at, or after the timeout value. + TEST_ASSERT(reload_value >= timeouts[i]); + // The watchdog should trigger before twice the timeout value. + TEST_ASSERT(reload_value < 2 * timeouts[i]); + } } utest::v1::status_t case_setup_sync_on_reset(const Case *const source, const size_t index_of_case) @@ -186,9 +191,17 @@ utest::v1::status_t case_teardown_wdg_stop_or_reset(const Case *const source, co template void test_init() { - watchdog_config_t config = { timeout_ms }; + if (timeout_ms < WDG_MIN_TIMEOUT_MS) { + TEST_IGNORE_MESSAGE("Requested timeout value is too short -- ignoring test case."); + return; + } + watchdog_config_t config = { .timeout_ms = timeout_ms }; TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, timeout_ms, hal_watchdog_get_reload_value()); + uint32_t reload_value = hal_watchdog_get_reload_value(); + // The watchdog should trigger at, or after the timeout value. + TEST_ASSERT(reload_value >= timeout_ms); + // The watchdog should trigger before twice the timeout value. + TEST_ASSERT(reload_value < 2 * timeout_ms); } void test_init_max_timeout() @@ -196,7 +209,8 @@ void test_init_max_timeout() watchdog_features_t features = hal_watchdog_get_platform_features(); watchdog_config_t config = { .timeout_ms = features.max_timeout }; TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - TEST_ASSERT_UINT32_WITHIN(WORST_TIMEOUT_RESOLUTION_MS, features.max_timeout, hal_watchdog_get_reload_value()); + // The watchdog should trigger at, or after the timeout value. + TEST_ASSERT(hal_watchdog_get_reload_value() >= features.max_timeout); } int testsuite_setup_sync_on_reset(const size_t number_of_cases) diff --git a/TESTS/mbed_hal/watchdog/watchdog_api_tests.h b/TESTS/mbed_hal/watchdog/watchdog_api_tests.h index e89cf4317ab..a01401a5ce4 100644 --- a/TESTS/mbed_hal/watchdog/watchdog_api_tests.h +++ b/TESTS/mbed_hal/watchdog/watchdog_api_tests.h @@ -65,32 +65,22 @@ void test_stop(); /** Test Watchdog init multiple times * - * Given @a max_timeout value returned by @a hal_watchdog_get_platform_features(): - * - * Given @a config.timeout_ms is set to WDG_TIMEOUT_MS, - * when @a hal_watchdog_init() is called, - * then @a WATCHDOG_STATUS_OK is returned - * and @a hal_watchdog_get_reload_value() returns WDG_TIMEOUT_MS. - * - * Given @a config.timeout_ms is set to max_timeout-delta, - * when @a hal_watchdog_init() is called, - * then @a WATCHDOG_STATUS_OK is returned - * and @a hal_watchdog_get_reload_value() returns max_timeout-delta. - * - * Given @a config.timeout_ms is set to max_timeout, - * when @a hal_watchdog_init() is called, - * then @a WATCHDOG_STATUS_OK is returned - * and @a hal_watchdog_get_reload_value() returns max_timeout. + * Given a set of unique timeout values, + * when @a config.timeout_ms is set to each of these values (T), + * then, for every value T, @a hal_watchdog_init() returns @a WATCHDOG_STATUS_OK + * and @a hal_watchdog_get_reload_value() returns a reload value R + * and T <= R < 2 * T. */ void test_update_config(); /** Test Watchdog init with a valid config * - * Given @a config.timeout_ms is set to X ms, + * Given @a config.timeout_ms is set to T ms, * which is within supported Watchdog timeout range, * when @a hal_watchdog_init() is called, * then @a WATCHDOG_STATUS_OK is returned - * and @a hal_watchdog_get_reload_value() returns X. + * and @a hal_watchdog_get_reload_value() returns a reload value R + * and T <= R < 2 * T. */ template void test_init(); diff --git a/TESTS/mbed_hal/watchdog_reset/main.cpp b/TESTS/mbed_hal/watchdog_reset/main.cpp index 2fbf4d304e6..34e2d81e029 100644 --- a/TESTS/mbed_hal/watchdog_reset/main.cpp +++ b/TESTS/mbed_hal/watchdog_reset/main.cpp @@ -25,15 +25,8 @@ #include "watchdog_reset_tests.h" #include "mbed.h" -#if TARGET_NUMAKER_PFM_NANO130 -/* On NUMAKER_PFM_NANO130 target, WDT's clock source is fixed to LIRC, which is more - * inaccurate than other targets. Enlarge this delta define to pass this test. */ -#define TIMEOUT_MS 500UL -#define TIMEOUT_DELTA_MS 100UL -#else #define TIMEOUT_MS 100UL -#define TIMEOUT_DELTA_MS 10UL -#endif +#define KICK_ADVANCE_MS 10UL #define MSG_VALUE_DUMMY "0" #define CASE_DATA_INVALID 0xffffffffUL @@ -103,12 +96,13 @@ void test_simple_reset() // Phase 1. -- run the test code. // Init the watchdog and wait for a device reset. watchdog_config_t config = { TIMEOUT_MS }; - if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) { TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); return; } TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + // Watchdog should fire before twice the timeout value. + wait_ms(2 * TIMEOUT_MS); // Device reset expected. // Watchdog reset should have occurred during wait_ms() above; @@ -130,23 +124,22 @@ void test_sleep_reset() watchdog_config_t config = { TIMEOUT_MS }; Semaphore sem(0, 1); Timeout timeout; - if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) { TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); return; } TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); sleep_manager_lock_deep_sleep(); - timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); + // Watchdog should fire before twice the timeout value. + timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_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. - } + sem.wait(); // Device reset expected. sleep_manager_unlock_deep_sleep(); - // Watchdog reset should have occurred during sleep() above; + // Watchdog reset should have occurred during sem.wait() (sleep) above; hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); @@ -166,21 +159,20 @@ void test_deepsleep_reset() watchdog_config_t config = { TIMEOUT_MS }; Semaphore sem(0, 1); LowPowerTimeout lp_timeout; - if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) { TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); return; } TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (TIMEOUT_MS + TIMEOUT_DELTA_MS)); + // Watchdog should fire before twice the timeout value. + lp_timeout.attach_us(mbed::callback(release_sem, &sem), 1000ULL * (2 * TIMEOUT_MS)); wait_ms(SERIAL_FLUSH_TIME_MS); // 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. - } + sem.wait(); // Device reset expected. - // Watchdog reset should have occurred during that sleep() above; + // Watchdog reset should have occurred during sem.wait() (deepsleep) above; hal_watchdog_kick(); // Just to buy some time for testsuite failure handling. TEST_ASSERT_MESSAGE(0, "Watchdog did not reset the device as expected."); @@ -209,14 +201,17 @@ void test_restart_reset() wait_ms(TIMEOUT_MS / 2UL); TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_stop()); // Check that stopping the Watchdog prevents a device reset. - wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_DELTA_MS); + // The watchdog should trigger at, or after the timeout value. + // The watchdog should trigger before twice the timeout value. + wait_ms(TIMEOUT_MS / 2UL + TIMEOUT_MS); - if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) { TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); return; } TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); - wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + // Watchdog should fire before twice the timeout value. + wait_ms(2 * TIMEOUT_MS); // Device reset expected. // Watchdog reset should have occurred during that wait() above; @@ -237,14 +232,17 @@ void test_kick_reset() watchdog_config_t config = { TIMEOUT_MS }; TEST_ASSERT_EQUAL(WATCHDOG_STATUS_OK, hal_watchdog_init(&config)); for (int i = 3; i; i--) { - wait_ms(TIMEOUT_MS / 2UL); + // The reset is prevented as long as the watchdog is kicked + // anytime before the timeout. + wait_ms(TIMEOUT_MS - KICK_ADVANCE_MS); hal_watchdog_kick(); } - if (send_reset_notification(¤t_case, TIMEOUT_MS + TIMEOUT_DELTA_MS) == false) { + if (send_reset_notification(¤t_case, 2 * TIMEOUT_MS) == false) { TEST_ASSERT_MESSAGE(0, "Dev-host communication error."); return; } - wait_ms(TIMEOUT_MS + TIMEOUT_DELTA_MS); // Device reset expected. + // Watchdog should fire before twice the timeout value. + wait_ms(2 * TIMEOUT_MS); // Device reset expected. // Watchdog reset should have occurred during that wait() above; diff --git a/TESTS/mbed_hal/watchdog_timing/main.cpp b/TESTS/mbed_hal/watchdog_timing/main.cpp index 19eab7d58f9..c3d151c1701 100644 --- a/TESTS/mbed_hal/watchdog_timing/main.cpp +++ b/TESTS/mbed_hal/watchdog_timing/main.cpp @@ -47,7 +47,7 @@ struct testcase_data { testcase_data current_case; -template +template void test_timing() { watchdog_features_t features = hal_watchdog_get_platform_features(); @@ -57,9 +57,15 @@ void test_timing() } // Phase 2. -- verify the test results. - // Verify the heartbeat time span sent by host is within given delta. + // Verify the heartbeat time span sent by host is within given range: + // 1. The watchdog should trigger at, or after the timeout value. + // 2. The watchdog should trigger before twice the timeout value. if (current_case.received_data != CASE_DATA_INVALID) { - TEST_ASSERT_UINT32_WITHIN(delta_ms, timeout_ms, current_case.received_data); + // Provided the watchdog works as expected, the last timestamp received + // by the host will always be before the expected reset time. Because + // of that, the constraint no 1. is not verified. + TEST_ASSERT(current_case.received_data > 0); + TEST_ASSERT(current_case.received_data < 2 * timeout_ms); current_case.received_data = CASE_DATA_INVALID; return; } @@ -141,10 +147,10 @@ int testsuite_setup(const size_t number_of_cases) } Case cases[] = { - Case("Timing, 200 ms", case_setup, test_timing<200UL, 55UL>), - Case("Timing, 500 ms", case_setup, test_timing<500UL, 130UL>), - Case("Timing, 1000 ms", case_setup, test_timing<1000UL, 255UL>), - Case("Timing, 3000 ms", case_setup, test_timing<3000UL, 380UL>), + Case("Timing, 200 ms", case_setup, test_timing<200UL>), + Case("Timing, 500 ms", case_setup, test_timing<500UL>), + Case("Timing, 1000 ms", case_setup, test_timing<1000UL>), + Case("Timing, 3000 ms", case_setup, test_timing<3000UL>), }; Specification specification((utest::v1::test_setup_handler_t) testsuite_setup, cases); diff --git a/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h b/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h index daba3cb3cea..89672dd8f8a 100644 --- a/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h +++ b/TESTS/mbed_hal/watchdog_timing/watchdog_timing_tests.h @@ -34,8 +34,8 @@ * * Phase 2. * Given a device restarted by the watchdog timer, - * when the device receives time measurement from the host, - * then time measured by host equals X ms. + * when the device receives time measurement T from the host, + * then X <= T < 2 * X. */ template void test_timing(); diff --git a/TESTS/mbed_platform/watchdog_mgr_reset/main.cpp b/TESTS/mbed_platform/watchdog_mgr_reset/main.cpp index df6e5b211ab..3b6fe952e2a 100644 --- a/TESTS/mbed_platform/watchdog_mgr_reset/main.cpp +++ b/TESTS/mbed_platform/watchdog_mgr_reset/main.cpp @@ -26,8 +26,6 @@ #include "watchdog_mgr_reset_tests.h" #include "mbed.h" -#define TIMEOUT_DELTA_MS 50UL - #define MSG_VALUE_DUMMY "0" #define CASE_DATA_INVALID 0xffffffffUL #define CASE_DATA_PHASE2_OK 0xfffffffeUL @@ -49,11 +47,6 @@ struct testcase_data { 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) diff --git a/hal/watchdog_api.h b/hal/watchdog_api.h index e7fe9da6d71..fcd9f369bfc 100644 --- a/hal/watchdog_api.h +++ b/hal/watchdog_api.h @@ -2,6 +2,7 @@ /** @{*/ /* 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. @@ -26,10 +27,7 @@ /** * \defgroup hal_watchdog Watchdog HAL API - * @{ - */ - -/** \file watchdog_api.h + * Low-level interface to the Independent Watchdog Timer of a target. * * This module provides platform independent access to the system watchdog timer * which is an embedded peripheral that will reset the system in the case of @@ -38,12 +36,29 @@ * The watchdog timer initialises a system timer with a time period specified in * the configuration. This timer counts down and triggers a system reset when it * wraps. To prevent the system reset the timer must be continually - * kicked/refreshed by calling hal_watchdog_kick which will reset the countdown + * kicked/refreshed by calling ::hal_watchdog_kick which will reset the countdown * to the user specified reset value. * - * The Watchdog timer must continue to operate in low power modes. It - * must count down and trigger a reset from within both sleep and deep sleep - * modes unless the chip is woken to refresh the timer. + * # Defined behavior + * * Sleep and debug modes don't stop the watchdog timer from counting down. + * * The function ::hal_watchdog_init is safe to call repeatedly. The + * function's implementation must not do anything if ::hal_watchdog_init has + * already initialized the hardware watchdog timer. + * * Maximum supported timeout is `UINT32_MAX` milliseconds; minimum timeout + * is 1 millisecond. + * * The watchdog should trigger at or after the timeout value. + * * The watchdog should trigger before twice the timeout value. + * + * # Undefined behavior + * * Calling any function other than ::hal_watchdog_init or + * ::hal_watchdog_get_platform_features before you have initialized the watchdog. + * + * # Notes + * * A software reset may not stop the watchdog timer; the behavior is platform specific. + * + * @see hal_watchdog_tests + * + * @{ */ typedef struct {