diff --git a/drivers/VirtualWatchdog.cpp b/drivers/VirtualWatchdog.cpp new file mode 100644 index 0000000000..2aba84cae2 --- /dev/null +++ b/drivers/VirtualWatchdog.cpp @@ -0,0 +1,123 @@ +/* + * 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_VIRTUAL_WATCHDOG + +#include "VirtualWatchdog.h" + +namespace mbed { + +VirtualWatchdog *VirtualWatchdog::_first = NULL; +Watchdog VirtualWatchdog::*_watchdog = NULL; + +VirtualWatchdog::VirtualWatchdog(uint32_t timeout, const char *const str): _name(str) +{ + _current_count = 0; + _is_initialized = false; + _next = NULL; + _max_timeout = timeout; + // initialize watchdog, just once (driver Watchdog takes care of only one instance there) + if (_watchdog == NULL) { + _watchdog = new Watchdog(); + _watchdog.start(); + } +} + +VirtualWatchdog::~VirtualWatchdog() +{ + if (_is_initialized) { + stop(); + // if we are the last VirtualWatchdog in the system, make sure to turn off hw watchdog + if (_first == NULL) { + _watchdog.stop(); + delete _watchdog; + _watchdog = NULL; + } + } +} + +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(uint32_t elapsed_ms) +{ + VirtualWatchdog *cur_ptr = _first; + while (cur_ptr != NULL) { + if (cur_ptr->_current_count > cur_ptr->_max_timeout) { + system_reset(); + } else { + cur_ptr->_current_count += elapsed_ms; + } + cur_ptr = cur_ptr->_next; + } +} + + +} // namespace mbed + +#endif // DEVICE_VIRTUAL_WATCHDOG diff --git a/drivers/VirtualWatchdog.h b/drivers/VirtualWatchdog.h new file mode 100644 index 0000000000..2a41c65134 --- /dev/null +++ b/drivers/VirtualWatchdog.h @@ -0,0 +1,125 @@ +/* + * 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 +#include "mbed_error.h" +#include "platform/mbed_critical.h" +#include "platform/mbed_power_mgmt.h" +#include "mbed_assert.h" + +class Watchdog; + +namespace mbed { + +/** \addtogroup drivers */ + +/** 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 platform + */ +class VirtualWatchdog { +public: + + /** Constructor configured with timeout and name for this software watchdog instance. + * + */ + VirtualWatchdog(uint32_t timeout = 1, const char *const str = NULL); + ~VirtualWatchdog(); +public: + + /** Start an independent watchdog timer with specified parameters. + * + * 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(); + + /** mbed_watchdog_manager (runs by periodic call from ticker) used this API interface + * to go through all the registered user/threads of watchdog. + * + * @param elapsed_ms completed ticker callback elapsed milliseconds + * + * Call this function from mbed_watchdog_manager_kick to monitor all the + * user/threads alive states. + * + * Otherwise, the system resets. + */ + static void process(uint32_t elapsed_ms); +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: + uint32_t _max_timeout; //_max_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 VirtualWatchdog *_first; //List to store the user/threads who called start + VirtualWatchdog *_next; + static Watchdog *_watchdog; +}; + +} // namespace mbed + +#endif // DEVICE_WATCHDOG +#endif // MBED_VIRTUAL_WATCHDOG_H diff --git a/drivers/Watchdog.h b/drivers/Watchdog.h index 66d69be94e..f22c038623 100644 --- a/drivers/Watchdog.h +++ b/drivers/Watchdog.h @@ -24,6 +24,9 @@ #include "mbed_assert.h" #include "platform/mbed_critical.h" #include "watchdog_api.h" +#include "platform/NonCopyable.h" +#include "platform/SingletonPtr.h" +#include "drivers/LowPowerTicker.h" #include namespace mbed {