mirror of https://github.com/ARMmbed/mbed-os.git
Watchdog: remove VirtualWatchdog
We will provide documentation how to create your own VirtualWatchdog. It's simple, create timeout and watchdog objects. This class brought lot of discussion and questions. After our refactor we made this class just a linked list of objects - something tickers can do as well (they already have linked list) and handling hw should be done via Watchdog due to the limitations (timeout can be set only once per app!).pull/10857/head
parent
968e270b0b
commit
25fbd3956b
|
@ -1,66 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018-2019 Arm Limited and affiliates.
|
||||
* 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.
|
||||
*/
|
||||
#ifdef DEVICE_WATCHDOG
|
||||
|
||||
#include "Watchdog.h"
|
||||
|
||||
namespace mbed {
|
||||
|
||||
static uint32_t _timeout = 0;
|
||||
|
||||
Watchdog::Watchdog() : _running(false)
|
||||
{
|
||||
}
|
||||
|
||||
Watchdog::~Watchdog()
|
||||
{
|
||||
}
|
||||
|
||||
bool Watchdog::start(uint32_t timeout)
|
||||
{
|
||||
_timeout = timeout;
|
||||
_running = true;
|
||||
return _running;
|
||||
}
|
||||
|
||||
bool Watchdog::stop()
|
||||
{
|
||||
_running = false;
|
||||
return _running;
|
||||
}
|
||||
|
||||
void Watchdog::kick()
|
||||
{
|
||||
}
|
||||
|
||||
bool Watchdog::is_running() const
|
||||
{
|
||||
return _running;
|
||||
}
|
||||
|
||||
uint32_t Watchdog::get_timeout() const
|
||||
{
|
||||
return _timeout;
|
||||
}
|
||||
|
||||
uint32_t Watchdog::get_max_timeout() const
|
||||
{
|
||||
return 0xFFFFFFFF;
|
||||
}
|
||||
|
||||
} // namespace mbed
|
||||
#endif // DEVICE_WATCHDOG
|
|
@ -1,138 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2018, Arm Limited and affiliates.
|
||||
* 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 "gtest/gtest.h"
|
||||
#include "gmock/gmock.h"
|
||||
#include "VirtualWatchdog.h"
|
||||
|
||||
class TestVirtualWatchdog : public testing::Test {
|
||||
public:
|
||||
static uint32_t expect_assert_count;
|
||||
static uint32_t expect_reset_count;
|
||||
protected:
|
||||
virtual void SetUp() {}
|
||||
virtual void TearDown() {}
|
||||
};
|
||||
|
||||
uint32_t TestVirtualWatchdog::expect_assert_count = 0;
|
||||
uint32_t TestVirtualWatchdog::expect_reset_count = 0;
|
||||
|
||||
void mbed_assert_internal(const char *expr, const char *file, int line)
|
||||
{
|
||||
TestVirtualWatchdog::expect_assert_count++;
|
||||
}
|
||||
|
||||
void mock_system_reset()
|
||||
{
|
||||
TestVirtualWatchdog::expect_reset_count++;
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_constructor)
|
||||
{
|
||||
EXPECT_LE(sizeof(mbed::VirtualWatchdog), 1024);
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_constructor_with_default_value)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog;
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_start_pass)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
watchdog.start();
|
||||
watchdog.stop();
|
||||
EXPECT_EQ(0, TestVirtualWatchdog::expect_assert_count);
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_kick_pass)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
watchdog.start();
|
||||
watchdog.kick();
|
||||
watchdog.stop();
|
||||
EXPECT_EQ(0, TestVirtualWatchdog::expect_assert_count);
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_stop_fail)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
watchdog.start();
|
||||
watchdog.stop();
|
||||
watchdog.stop();
|
||||
EXPECT_EQ(1, TestVirtualWatchdog::expect_assert_count);
|
||||
TestVirtualWatchdog::expect_assert_count = 0;
|
||||
}
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_kick_fail)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
watchdog.kick();
|
||||
EXPECT_EQ(1, TestVirtualWatchdog::expect_assert_count);
|
||||
TestVirtualWatchdog::expect_assert_count = 0;
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_start_kick_pass)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
mbed::VirtualWatchdog watchdog1(600, "watchdog_unittest_1");
|
||||
mbed::VirtualWatchdog watchdog2(700, "watchdog_unittest_2");
|
||||
watchdog.start();
|
||||
watchdog1.start();
|
||||
watchdog2.start();
|
||||
watchdog1.kick();
|
||||
watchdog.kick();
|
||||
watchdog2.kick();
|
||||
watchdog1.stop();
|
||||
watchdog.stop();
|
||||
watchdog2.stop();
|
||||
EXPECT_EQ(0, TestVirtualWatchdog::expect_assert_count);
|
||||
EXPECT_EQ(0, TestVirtualWatchdog::expect_reset_count);
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_start_process_pass)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
watchdog.start();
|
||||
watchdog.kick();
|
||||
watchdog.stop();
|
||||
EXPECT_EQ(0, TestVirtualWatchdog::expect_assert_count);
|
||||
EXPECT_EQ(0, TestVirtualWatchdog::expect_reset_count);
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_start_process_fail)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
mbed::VirtualWatchdog watchdog1(500, "watchdog_unittest-1");
|
||||
watchdog.start();
|
||||
watchdog1.start();
|
||||
watchdog1.kick();
|
||||
watchdog.stop();
|
||||
watchdog1.stop();
|
||||
EXPECT_EQ(0, TestVirtualWatchdog::expect_assert_count);
|
||||
EXPECT_EQ(0, TestVirtualWatchdog::expect_reset_count);
|
||||
TestVirtualWatchdog::expect_reset_count = 0;
|
||||
}
|
||||
|
||||
TEST_F(TestVirtualWatchdog, virtualwdog_start_fail)
|
||||
{
|
||||
mbed::VirtualWatchdog watchdog(500, "watchdog_unittest");
|
||||
watchdog.start();
|
||||
watchdog.start();
|
||||
watchdog.stop();
|
||||
EXPECT_EQ(1, TestVirtualWatchdog::expect_assert_count);
|
||||
TestVirtualWatchdog::expect_assert_count = 0;
|
||||
}
|
|
@ -1,27 +0,0 @@
|
|||
|
||||
####################
|
||||
# UNIT TESTS
|
||||
####################
|
||||
set(TEST_SUITE_NAME "VirtualWatchdog")
|
||||
|
||||
# Add test specific include paths
|
||||
set(unittest-includes ${unittest-includes}
|
||||
.
|
||||
../hal
|
||||
)
|
||||
|
||||
# Source files
|
||||
set(unittest-sources
|
||||
../drivers/VirtualWatchdog.cpp
|
||||
)
|
||||
|
||||
# Test files
|
||||
set(unittest-test-sources
|
||||
drivers/VirtualWatchdog/test_virtualwatchdog.cpp
|
||||
drivers/VirtualWatchdog/Watchdog.cpp
|
||||
stubs/mbed_critical_stub.c
|
||||
)
|
||||
|
||||
# defines
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEVICE_WATCHDOG -DMBED_WDOG_ASSERT=1")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEVICE_WATCHDOG -DMBED_WDOG_ASSERT=1")
|
|
@ -1,140 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Arm Limited and affiliates.
|
||||
* 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.
|
||||
*/
|
||||
#ifdef DEVICE_WATCHDOG
|
||||
|
||||
#include "drivers/VirtualWatchdog.h"
|
||||
|
||||
#define MS_TO_US(x) ((x) * 1000)
|
||||
#define US_TO_MS(x) ((x) / 1000)
|
||||
|
||||
namespace mbed {
|
||||
|
||||
#if DEVICE_LPTICKER
|
||||
SingletonPtr<LowPowerTicker> VirtualWatchdog::_ticker;
|
||||
#else
|
||||
SingletonPtr<Ticker> VirtualWatchdog::_ticker;
|
||||
#endif
|
||||
|
||||
VirtualWatchdog *VirtualWatchdog::_first = NULL;
|
||||
bool VirtualWatchdog::_is_hw_watchdog_running = false;
|
||||
us_timestamp_t VirtualWatchdog::_ticker_timeout = 0;
|
||||
|
||||
VirtualWatchdog::VirtualWatchdog(uint32_t timeout, const char *const str) : _name(str)
|
||||
{
|
||||
_current_count = 0;
|
||||
_is_initialized = false;
|
||||
_next = NULL;
|
||||
_timeout = timeout;
|
||||
// start watchdog
|
||||
Watchdog &watchdog = Watchdog::get_instance();
|
||||
if (!_is_hw_watchdog_running) {
|
||||
if (watchdog.is_running() == true) {
|
||||
MBED_MAKE_ERROR(MBED_MODULE_DRIVER_WATCHDOG, MBED_ERROR_INITIALIZATION_FAILED);
|
||||
}
|
||||
watchdog.start(timeout);
|
||||
_ticker_timeout = MS_TO_US(timeout / 2);
|
||||
if (_ticker_timeout == 0) {
|
||||
_ticker_timeout = 1;
|
||||
}
|
||||
_ticker->attach_us(callback(this, &VirtualWatchdog::process), _ticker_timeout);
|
||||
_is_hw_watchdog_running = true;
|
||||
}
|
||||
}
|
||||
|
||||
VirtualWatchdog::~VirtualWatchdog()
|
||||
{
|
||||
if (_is_initialized) {
|
||||
stop();
|
||||
// we do not need to stop hw watchdog, it's ticking by itself
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualWatchdog::start()
|
||||
{
|
||||
MBED_ASSERT(!_is_initialized);
|
||||
core_util_critical_section_enter();
|
||||
add_to_list();
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
|
||||
void VirtualWatchdog::kick()
|
||||
{
|
||||
MBED_ASSERT(_is_initialized);
|
||||
core_util_critical_section_enter();
|
||||
_current_count = 0;
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void VirtualWatchdog::stop()
|
||||
{
|
||||
MBED_ASSERT(_is_initialized);
|
||||
core_util_critical_section_enter();
|
||||
remove_from_list();
|
||||
core_util_critical_section_exit();
|
||||
}
|
||||
|
||||
void VirtualWatchdog::add_to_list()
|
||||
{
|
||||
this->_next = _first;
|
||||
_first = this;
|
||||
_is_initialized = true;
|
||||
}
|
||||
|
||||
void VirtualWatchdog::remove_from_list()
|
||||
{
|
||||
VirtualWatchdog *cur_ptr = _first, *prev_ptr = NULL;
|
||||
while (cur_ptr != NULL) {
|
||||
if (cur_ptr == this) {
|
||||
if (cur_ptr == _first) {
|
||||
prev_ptr = _first;
|
||||
_first = cur_ptr->_next;
|
||||
prev_ptr->_next = NULL;
|
||||
} else {
|
||||
prev_ptr->_next = cur_ptr->_next;
|
||||
cur_ptr->_next = NULL;
|
||||
}
|
||||
_is_initialized = false;
|
||||
break;
|
||||
} else {
|
||||
prev_ptr = cur_ptr;
|
||||
cur_ptr = cur_ptr->_next;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void VirtualWatchdog::process()
|
||||
{
|
||||
Watchdog::get_instance().kick();
|
||||
VirtualWatchdog *cur_ptr = _first;
|
||||
while (cur_ptr != NULL) {
|
||||
if (cur_ptr->_is_initialized) {
|
||||
if (cur_ptr->_current_count > cur_ptr->_timeout) {
|
||||
system_reset();
|
||||
} else {
|
||||
cur_ptr->_current_count += US_TO_MS(_ticker_timeout);
|
||||
}
|
||||
|
||||
}
|
||||
cur_ptr = cur_ptr->_next;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif // DEVICE_WATCHDOG
|
|
@ -1,147 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2019 Arm Limited and affiliates.
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef MBED_VIRTUAL_WATCHDOG_H
|
||||
#define MBED_VIRTUAL_WATCHDOG_H
|
||||
|
||||
#ifdef DEVICE_WATCHDOG
|
||||
|
||||
#include <cstdio>
|
||||
#include "platform/mbed_error.h"
|
||||
#include "platform/mbed_critical.h"
|
||||
#include "platform/mbed_power_mgmt.h"
|
||||
#include "platform/mbed_assert.h"
|
||||
#include "platform/SingletonPtr.h"
|
||||
#include "drivers/Watchdog.h"
|
||||
|
||||
#if DEVICE_LPTICKER
|
||||
#include "drivers/LowPowerTicker.h"
|
||||
#else
|
||||
#include "drivers/Ticker.h"
|
||||
#endif
|
||||
namespace mbed {
|
||||
|
||||
/** \addtogroup drivers */
|
||||
|
||||
/** VirtualWatchdog should be used for applications where you use multiple services requiring watchdog functionality.
|
||||
* Use `Watchdog` driver for simple uses cases like bootloader. Do not use both drivers at the same time - VirtualWatchdog will error
|
||||
* if it is not the only owner of the watchdog.
|
||||
*
|
||||
* A system timer that will reset the system in the case of system failures or
|
||||
* malfunctions.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
*
|
||||
* VirtualWatchdog virtual_watchdog(300,"Software Watchdog");
|
||||
* virtual_watchdog.start();
|
||||
*
|
||||
* while (true) {
|
||||
* virtual_watchdog.kick();
|
||||
*
|
||||
* // Application code
|
||||
* }
|
||||
* @endcode
|
||||
* @ingroup drivers
|
||||
*/
|
||||
class VirtualWatchdog {
|
||||
public:
|
||||
|
||||
/** Constructor configured with timeout and name for this software watchdog instance.
|
||||
*
|
||||
* Note, the first instance of VirtualWatchog configures the hardware watchdog peripheral (uses timeout value passed here).
|
||||
*
|
||||
* @param timeout Timer timeout
|
||||
* @param str The name for this watchdog timer
|
||||
*
|
||||
*/
|
||||
VirtualWatchdog(uint32_t timeout = 1000, const char *const str = NULL);
|
||||
|
||||
~VirtualWatchdog();
|
||||
public:
|
||||
|
||||
/** Start an independent watchdog timer with specified parameters in the constructor.
|
||||
*
|
||||
* Assert for multiple calls of start.
|
||||
*/
|
||||
void start();
|
||||
|
||||
/** This stops the watchdog timer.
|
||||
*
|
||||
* Calling this function disables any running
|
||||
* watchdog timers if the platform supports them.
|
||||
*
|
||||
* Assert without calling start.
|
||||
*/
|
||||
void stop();
|
||||
|
||||
/** This function refreshes the watchdog timer.
|
||||
*
|
||||
* Call this function periodically before the watchdog times out.
|
||||
* Otherwise, the system resets.
|
||||
*
|
||||
* If the watchdog timer is not running, this function does nothing.
|
||||
*/
|
||||
void kick();
|
||||
|
||||
protected:
|
||||
|
||||
/** Use add_to_list to store the registered user in the list.
|
||||
* This API is only used to call from start.
|
||||
*/
|
||||
void add_to_list();
|
||||
|
||||
/** Use remove_from_list to remove the entry from the list.
|
||||
* This API is only used to call from stop.
|
||||
*
|
||||
*/
|
||||
void remove_from_list();
|
||||
|
||||
private:
|
||||
/** Periodic ticker handler to go through all the registered user/threads of watchdog.
|
||||
*
|
||||
* Otherwise, the system resets.
|
||||
*/
|
||||
void process();
|
||||
|
||||
uint32_t _timeout; //_timeout initialized via constructor while creating instance of this class
|
||||
const char *_name; //To store the details of user
|
||||
uint32_t _current_count; //this parameter is used to reset everytime threads/user calls kick
|
||||
bool _is_initialized; //To control start and stop functionality
|
||||
static bool _is_hw_watchdog_running; // track we are the first owner of watchdog
|
||||
static VirtualWatchdog *_first; //List to store the user/threads who called start
|
||||
VirtualWatchdog *_next;
|
||||
|
||||
#if DEVICE_LPTICKER
|
||||
/** Create singleton instance of LowPowerTicker for watchdog periodic call back of kick.
|
||||
*/
|
||||
static SingletonPtr<LowPowerTicker> _ticker;
|
||||
#else
|
||||
/** Create singleton instance of Ticker for watchdog periodic call back of kick.
|
||||
*/
|
||||
static SingletonPtr<Ticker> _ticker;
|
||||
#endif
|
||||
static us_timestamp_t _ticker_timeout;
|
||||
};
|
||||
|
||||
} // namespace mbed
|
||||
|
||||
#endif // DEVICE_WATCHDOG
|
||||
#endif // MBED_VIRTUAL_WATCHDOG_H
|
|
@ -31,7 +31,7 @@ namespace mbed {
|
|||
|
||||
/** \addtogroup drivers */
|
||||
/** Hardware system timer that will reset the system in the case of system failures or
|
||||
* malfunctions. There is only one instance in the system (for multiple system timers, see VirtualWatchdog driver).
|
||||
* malfunctions. There is only one instance in the system.
|
||||
*
|
||||
* Example:
|
||||
* @code
|
||||
|
|
Loading…
Reference in New Issue