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
Martin Kojtal 2019-07-02 09:41:12 +01:00
parent 968e270b0b
commit 25fbd3956b
7 changed files with 1 additions and 520 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

1
mbed.h
View File

@ -75,7 +75,6 @@
#include "drivers/MbedCRC.h"
#include "drivers/QSPI.h"
#include "drivers/Watchdog.h"
#include "drivers/VirtualWatchdog.h"
// mbed Internal components
#include "drivers/ResetReason.h"