~aleteoryx/muditaos

d9ae779a37f5d9efe5f18035f746420dd35306e1 — Borys Jelenski 5 years ago d976881
[EGD-5503] Add watchdog implementation

The system watchdog monitors whether there is message traffic
on the Bus. If no message was sent for an extended period of time,
a reset will occur. It should also protect against system-wide hangs.

On Linux, watchdog is simulated by a FreeRTOS task that will call exit
on timeout.
A module-bsp/board/linux/watchdog/software_watchdog.cpp => module-bsp/board/linux/watchdog/software_watchdog.cpp +59 -0
@@ 0,0 1,59 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "software_watchdog.hpp"
#include <module-os/RTOSWrapper/include/critical.hpp>
#include <module-os/RTOSWrapper/include/ticks.hpp>
#include <module-sys/Service/Common.hpp>
#include <module-utils/log/log.hpp>
#include <cstdlib>

namespace bsp::watchdog
{
    using namespace cpp_freertos;

    static constexpr uint16_t stackDepthWords = 256;

    SoftwareWatchdog::SoftwareWatchdog()
        : Thread("SW_Watchdog", stackDepthWords, static_cast<UBaseType_t>(sys::ServicePriority::Realtime))
    {}

    bool SoftwareWatchdog::init(TickType_t timeoutPeriodMs)
    {
#ifdef DISABLE_WATCHDOG
        return true;
#else
        timeoutPeriod      = pdMS_TO_TICKS(timeoutPeriodMs);
        const auto started = Start();

        if (started) {
            refresh();
        }

        return started;
#endif
    }

    void SoftwareWatchdog::refresh()
    {
#ifndef DISABLE_WATCHDOG
        // Critical section not required (atomic 32-bit writes)
        lastRefreshTimestamp = Ticks::GetTicks();
#endif
    }

    void SoftwareWatchdog::Run()
    {
        TickType_t lastTimeoutTimestamp = xTaskGetTickCount();

        while (true) {
            vTaskDelayUntil(&lastTimeoutTimestamp, timeoutPeriod);

            // Critical section not required (atomic 32-bit reads)
            if (lastTimeoutTimestamp - lastRefreshTimestamp >= timeoutPeriod) {
                LOG_FATAL("!!! Software watchdog timeout, exiting !!!");
                exit(EXIT_FAILURE);
            }
        }
    }
} // namespace bsp::watchdog

A module-bsp/board/linux/watchdog/software_watchdog.hpp => module-bsp/board/linux/watchdog/software_watchdog.hpp +28 -0
@@ 0,0 1,28 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <module-os/RTOSWrapper/include/thread.hpp>

namespace bsp::watchdog
{
    class SoftwareWatchdog : private cpp_freertos::Thread
    {
      public:
        SoftwareWatchdog();
        SoftwareWatchdog(const SoftwareWatchdog &) = delete;
        SoftwareWatchdog(SoftwareWatchdog &&)      = delete;
        SoftwareWatchdog &operator=(const SoftwareWatchdog &) = delete;
        SoftwareWatchdog &operator=(SoftwareWatchdog &&) = delete;

        bool init(TickType_t timeoutPeriodMs);
        void refresh();

      private:
        void Run() final;

        TickType_t timeoutPeriod        = 0;
        TickType_t lastRefreshTimestamp = 0;
    };
} // namespace bsp::watchdog

M module-bsp/board/linux/watchdog/watchdog.cpp => module-bsp/board/linux/watchdog/watchdog.cpp +12 -9
@@ 1,18 1,21 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "bsp/watchdog/watchdog.hpp"
#include "software_watchdog.hpp"
#include <bsp/watchdog/watchdog.hpp>

namespace bsp::watchdog
{
    __attribute__((weak)) void init()
    {}
    __attribute__((weak)) void system_reset()
    {}
    __attribute__((weak)) void pet()
    {}
    __attribute__((weak)) std::string reset_cause()
    static SoftwareWatchdog swWatchdog;

    bool init(unsigned int timeoutMs)
    {
        return swWatchdog.init(static_cast<TickType_t>(timeoutMs));
    }

    void refresh()
    {
        return {};
        swWatchdog.refresh();
    }
} // namespace bsp::watchdog

M module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp => module-bsp/board/rt1051/bsp/lpm/RT1051LPM.cpp +1 -2
@@ 40,8 40,7 @@ namespace bsp

    int32_t RT1051LPM::Reboot()
    {
        bsp::watchdog::init();
        bsp::watchdog::system_reset();
        NVIC_SystemReset();
        return 0;
    }


M module-bsp/board/rt1051/bsp/watchdog/watchdog.cpp => module-bsp/board/rt1051/bsp/watchdog/watchdog.cpp +29 -34
@@ 1,50 1,45 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "bsp/watchdog/watchdog.hpp"
extern "C"
{
#include "../../common/fsl_drivers/fsl_wdog.h"
#include "fsl_rtwdog.h"
}
#include <log/log.hpp>

#define WDOG_1_BASE          WDOG1
#define DEMO_WDOG_IRQHandler RTWDOG
#include <limits>

namespace bsp::watchdog
{
    void init()
    {
        wdog_config_t config;
        WDOG_GetDefaultConfig(&config);
        config.timeoutValue = 0xFF; /* Timeout value is (0xFF + 1)/2 = 125 sec. */
        WDOG_Init(WDOG_1_BASE, &config);
        LOG_INFO("wdog init done-");
    }
    void system_reset()
    bool init(unsigned int timeoutMs)
    {
        LOG_DEBUG("request system reset to watchdog");
        WDOG_TriggerSystemSoftwareReset(WDOG_1_BASE);
    }
        // 32.768kHz source clock divided by 256 prescaler
        static constexpr unsigned int clockFreqHz = 32768 / 256;

    void pet()
    {
        WDOG_Refresh(WDOG_1_BASE);
        const unsigned int timeoutValueTicks = timeoutMs * clockFreqHz / 1000;
        if (timeoutValueTicks > std::numeric_limits<uint16_t>::max()) {
            return false;
        }

        rtwdog_config_t config      = {0};
        config.enableRtwdog         = true;
        config.clockSource          = kRTWDOG_ClockSource1;            // LPO_CLK clock (32.768kHz)
        config.prescaler            = kRTWDOG_ClockPrescalerDivide256; // 256 prescaler (effectively 128Hz clock)
        config.workMode.enableWait  = false;
        config.workMode.enableStop  = false;
        config.workMode.enableDebug = false; // If true, RTWDOG will run when target is halted
        config.testMode             = kRTWDOG_TestModeDisabled;
        config.enableUpdate         = true;
        config.enableInterrupt      = false;
        config.enableWindowMode     = false;
        config.windowValue          = 0;
        config.timeoutValue         = static_cast<uint16_t>(timeoutValueTicks);
        RTWDOG_Init(RTWDOG, &config);

        return true;
    }

    // taken straight from example wdog.c in NXP mcuxpresso
    std::string reset_cause()
    void refresh()
    {
        auto resetFlag = WDOG_GetStatusFlags(WDOG_1_BASE);
        switch (resetFlag & (kWDOG_PowerOnResetFlag | kWDOG_TimeoutResetFlag | kWDOG_SoftwareResetFlag)) {
        case kWDOG_PowerOnResetFlag:
            return ("Power On Reset");
        case kWDOG_TimeoutResetFlag:
            return ("Time Out Reset!");
        case kWDOG_SoftwareResetFlag:
            return ("Software Reset!");
        default:
            return ("Error status!");
        }
        RTWDOG_Refresh(RTWDOG);
    }
} // namespace bsp::watchdog

A module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.c => module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.c +151 -0
@@ 0,0 1,151 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2019 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include "fsl_rtwdog.h"

/* Component ID definition, used by tools. */
#ifndef FSL_COMPONENT_ID
#define FSL_COMPONENT_ID "platform.drivers.rtwdog"
#endif

/*******************************************************************************
 * Code
 ******************************************************************************/

/*!
 * brief Clears the RTWDOG flag.
 *
 * This function clears the RTWDOG status flag.
 *
 * Example to clear an interrupt flag:
 * code
 *   RTWDOG_ClearStatusFlags(wdog_base,kRTWDOG_InterruptFlag);
 * endcode
 * param base        RTWDOG peripheral base address.
 * param mask        The status flags to clear.
 *                    The parameter can be any combination of the following values:
 *                    arg kRTWDOG_InterruptFlag
 */
void RTWDOG_ClearStatusFlags(RTWDOG_Type *base, uint32_t mask)
{
    if ((mask & (uint32_t)kRTWDOG_InterruptFlag) != 0U)
    {
        base->CS |= RTWDOG_CS_FLG_MASK;
    }
}

/*!
 * brief Initializes the RTWDOG configuration structure.
 *
 * This function initializes the RTWDOG configuration structure to default values. The default
 * values are:
 * code
 *   rtwdogConfig->enableRtwdog = true;
 *   rtwdogConfig->clockSource = kRTWDOG_ClockSource1;
 *   rtwdogConfig->prescaler = kRTWDOG_ClockPrescalerDivide1;
 *   rtwdogConfig->workMode.enableWait = true;
 *   rtwdogConfig->workMode.enableStop = false;
 *   rtwdogConfig->workMode.enableDebug = false;
 *   rtwdogConfig->testMode = kRTWDOG_TestModeDisabled;
 *   rtwdogConfig->enableUpdate = true;
 *   rtwdogConfig->enableInterrupt = false;
 *   rtwdogConfig->enableWindowMode = false;
 *   rtwdogConfig->windowValue = 0U;
 *   rtwdogConfig->timeoutValue = 0xFFFFU;
 * endcode
 *
 * param config Pointer to the RTWDOG configuration structure.
 * see rtwdog_config_t
 */
void RTWDOG_GetDefaultConfig(rtwdog_config_t *config)
{
    assert(config != NULL);

    /* Initializes the configure structure to zero. */
    (void)memset(config, 0, sizeof(*config));

    config->enableRtwdog         = true;
    config->clockSource          = kRTWDOG_ClockSource1;
    config->prescaler            = kRTWDOG_ClockPrescalerDivide1;
    config->workMode.enableWait  = true;
    config->workMode.enableStop  = false;
    config->workMode.enableDebug = false;
    config->testMode             = kRTWDOG_TestModeDisabled;
    config->enableUpdate         = true;
    config->enableInterrupt      = false;
    config->enableWindowMode     = false;
    config->windowValue          = 0U;
    config->timeoutValue         = 0xFFFFU;
}

/*!
 * brief Initializes the RTWDOG module.
 *
 * This function initializes the RTWDOG.
 * To reconfigure the RTWDOG without forcing a reset first, enableUpdate must be set to true
 * in the configuration.
 *
 * Example:
 * code
 *   rtwdog_config_t config;
 *   RTWDOG_GetDefaultConfig(&config);
 *   config.timeoutValue = 0x7ffU;
 *   config.enableUpdate = true;
 *   RTWDOG_Init(wdog_base,&config);
 * endcode
 *
 * param base   RTWDOG peripheral base address.
 * param config The configuration of the RTWDOG.
 */
void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config)
{
    assert(NULL != config);

    uint32_t value        = 0U;
    uint32_t primaskValue = 0U;

    value = RTWDOG_CS_EN(config->enableRtwdog) | RTWDOG_CS_CLK(config->clockSource) |
            RTWDOG_CS_INT(config->enableInterrupt) | RTWDOG_CS_WIN(config->enableWindowMode) |
            RTWDOG_CS_UPDATE(config->enableUpdate) | RTWDOG_CS_DBG(config->workMode.enableDebug) |
            RTWDOG_CS_STOP(config->workMode.enableStop) | RTWDOG_CS_WAIT(config->workMode.enableWait) |
            RTWDOG_CS_PRES(config->prescaler) | RTWDOG_CS_CMD32EN(1U) | RTWDOG_CS_TST(config->testMode);

    /* Disable the global interrupts. Otherwise, an interrupt could effectively invalidate the unlock sequence
     * and the WCT may expire. After the configuration finishes, re-enable the global interrupts. */
    primaskValue = DisableGlobalIRQ();
    RTWDOG_Unlock(base);
    base->WIN   = config->windowValue;
    base->TOVAL = config->timeoutValue;
    base->CS    = value;
    while ((base->CS & RTWDOG_CS_RCS_MASK) == 0U)
    {
    }
    EnableGlobalIRQ(primaskValue);
}

/*!
 * brief De-initializes the RTWDOG module.
 *
 * This function shuts down the RTWDOG.
 * Ensure that the WDOG_CS.UPDATE is 1, which means that the register update is enabled.
 *
 * param base   RTWDOG peripheral base address.
 */
void RTWDOG_Deinit(RTWDOG_Type *base)
{
    uint32_t primaskValue = 0U;

    /* Disable the global interrupts */
    primaskValue = DisableGlobalIRQ();
    RTWDOG_Unlock(base);
    RTWDOG_Disable(base);
    EnableGlobalIRQ(primaskValue);
}

A module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.h => module-bsp/board/rt1051/common/fsl_drivers/fsl_rtwdog.h +425 -0
@@ 0,0 1,425 @@
/*
 * Copyright (c) 2016, Freescale Semiconductor, Inc.
 * Copyright 2016-2020 NXP
 * All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */
#ifndef _FSL_RTWDOG_H_
#define _FSL_RTWDOG_H_

#include "fsl_common.h"

/*!
 * @addtogroup rtwdog
 * @{
 */

/*******************************************************************************
 * Definitions
 *******************************************************************************/
/*! @name Unlock sequence */
/*@{*/
#define WDOG_FIRST_WORD_OF_UNLOCK  (RTWDOG_UPDATE_KEY & 0xFFFFU)          /*!< First word of unlock sequence */
#define WDOG_SECOND_WORD_OF_UNLOCK ((RTWDOG_UPDATE_KEY >> 16U) & 0xFFFFU) /*!< Second word of unlock sequence */
/*@}*/

/*! @name Refresh sequence */
/*@{*/
#define WDOG_FIRST_WORD_OF_REFRESH  (RTWDOG_REFRESH_KEY & 0xFFFFU)          /*!< First word of refresh sequence */
#define WDOG_SECOND_WORD_OF_REFRESH ((RTWDOG_REFRESH_KEY >> 16U) & 0xFFFFU) /*!< Second word of refresh sequence */
/*@}*/
/*! @name Driver version */
/*@{*/
/*! @brief RTWDOG driver version 2.1.2. */
#define FSL_RTWDOG_DRIVER_VERSION (MAKE_VERSION(2, 1, 2))
/*@}*/

/*! @brief Describes RTWDOG clock source. */
typedef enum _rtwdog_clock_source
{
    kRTWDOG_ClockSource0 = 0U, /*!< Clock source 0 */
    kRTWDOG_ClockSource1 = 1U, /*!< Clock source 1 */
    kRTWDOG_ClockSource2 = 2U, /*!< Clock source 2 */
    kRTWDOG_ClockSource3 = 3U, /*!< Clock source 3 */
} rtwdog_clock_source_t;

/*! @brief Describes the selection of the clock prescaler. */
typedef enum _rtwdog_clock_prescaler
{
    kRTWDOG_ClockPrescalerDivide1   = 0x0U, /*!< Divided by 1 */
    kRTWDOG_ClockPrescalerDivide256 = 0x1U, /*!< Divided by 256 */
} rtwdog_clock_prescaler_t;

/*! @brief Defines RTWDOG work mode. */
typedef struct _rtwdog_work_mode
{
    bool enableWait;  /*!< Enables or disables RTWDOG in wait mode */
    bool enableStop;  /*!< Enables or disables RTWDOG in stop mode */
    bool enableDebug; /*!< Enables or disables RTWDOG in debug mode */
} rtwdog_work_mode_t;

/*! @brief Describes RTWDOG test mode. */
typedef enum _rtwdog_test_mode
{
    kRTWDOG_TestModeDisabled = 0U, /*!< Test Mode disabled */
    kRTWDOG_UserModeEnabled  = 1U, /*!< User Mode enabled */
    kRTWDOG_LowByteTest      = 2U, /*!< Test Mode enabled, only low byte is used */
    kRTWDOG_HighByteTest     = 3U, /*!< Test Mode enabled, only high byte is used */
} rtwdog_test_mode_t;

/*! @brief Describes RTWDOG configuration structure. */
typedef struct _rtwdog_config
{
    bool enableRtwdog;                  /*!< Enables or disables RTWDOG */
    rtwdog_clock_source_t clockSource;  /*!< Clock source select */
    rtwdog_clock_prescaler_t prescaler; /*!< Clock prescaler value */
    rtwdog_work_mode_t workMode;        /*!< Configures RTWDOG work mode in debug stop and wait mode */
    rtwdog_test_mode_t testMode;        /*!< Configures RTWDOG test mode */
    bool enableUpdate;                  /*!< Update write-once register enable */
    bool enableInterrupt;               /*!< Enables or disables RTWDOG interrupt */
    bool enableWindowMode;              /*!< Enables or disables RTWDOG window mode */
    uint16_t windowValue;               /*!< Window value */
    uint16_t timeoutValue;              /*!< Timeout value */
} rtwdog_config_t;

/*!
 * @brief RTWDOG interrupt configuration structure.
 *
 * This structure contains the settings for all of the RTWDOG interrupt configurations.
 */
enum _rtwdog_interrupt_enable_t
{
    kRTWDOG_InterruptEnable = RTWDOG_CS_INT_MASK, /*!< Interrupt is generated before forcing a reset */
};

/*!
 * @brief RTWDOG status flags.
 *
 * This structure contains the RTWDOG status flags for use in the RTWDOG functions.
 */
enum _rtwdog_status_flags_t
{
    kRTWDOG_RunningFlag   = RTWDOG_CS_EN_MASK,  /*!< Running flag, set when RTWDOG is enabled */
    kRTWDOG_InterruptFlag = RTWDOG_CS_FLG_MASK, /*!< Interrupt flag, set when interrupt occurs */
};

/*******************************************************************************
 * API
 *******************************************************************************/

#if defined(__cplusplus)
extern "C" {
#endif /* __cplusplus */

/*!
 * @name RTWDOG Initialization and De-initialization
 * @{
 */

/*!
 * @brief Initializes the RTWDOG configuration structure.
 *
 * This function initializes the RTWDOG configuration structure to default values. The default
 * values are:
 * @code
 *   rtwdogConfig->enableRtwdog = true;
 *   rtwdogConfig->clockSource = kRTWDOG_ClockSource1;
 *   rtwdogConfig->prescaler = kRTWDOG_ClockPrescalerDivide1;
 *   rtwdogConfig->workMode.enableWait = true;
 *   rtwdogConfig->workMode.enableStop = false;
 *   rtwdogConfig->workMode.enableDebug = false;
 *   rtwdogConfig->testMode = kRTWDOG_TestModeDisabled;
 *   rtwdogConfig->enableUpdate = true;
 *   rtwdogConfig->enableInterrupt = false;
 *   rtwdogConfig->enableWindowMode = false;
 *   rtwdogConfig->windowValue = 0U;
 *   rtwdogConfig->timeoutValue = 0xFFFFU;
 * @endcode
 *
 * @param config Pointer to the RTWDOG configuration structure.
 * @see rtwdog_config_t
 */
void RTWDOG_GetDefaultConfig(rtwdog_config_t *config);

/*!
 * @brief Initializes the RTWDOG module.
 *
 * This function initializes the RTWDOG.
 * To reconfigure the RTWDOG without forcing a reset first, enableUpdate must be set to true
 * in the configuration.
 *
 * Example:
 * @code
 *   rtwdog_config_t config;
 *   RTWDOG_GetDefaultConfig(&config);
 *   config.timeoutValue = 0x7ffU;
 *   config.enableUpdate = true;
 *   RTWDOG_Init(wdog_base,&config);
 * @endcode
 *
 * @param base   RTWDOG peripheral base address.
 * @param config The configuration of the RTWDOG.
 */

#if defined(DOXYGEN_OUTPUT) && DOXYGEN_OUTPUT
void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config);
#else
AT_QUICKACCESS_SECTION_CODE(void RTWDOG_Init(RTWDOG_Type *base, const rtwdog_config_t *config));
#endif

/*!
 * @brief De-initializes the RTWDOG module.
 *
 * This function shuts down the RTWDOG.
 * Ensure that the WDOG_CS.UPDATE is 1, which means that the register update is enabled.
 *
 * @param base   RTWDOG peripheral base address.
 */
void RTWDOG_Deinit(RTWDOG_Type *base);

/* @} */

/*!
 * @name RTWDOG functional Operation
 * @{
 */

/*!
 * @brief Enables the RTWDOG module.
 *
 * This function writes a value into the WDOG_CS register to enable the RTWDOG.
 * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and
 * this register has not been written in this WCT while the function is called.
 *
 * @param base RTWDOG peripheral base address.
 */
static inline void RTWDOG_Enable(RTWDOG_Type *base)
{
    base->CS |= RTWDOG_CS_EN_MASK;
}

/*!
 * @brief Disables the RTWDOG module.
 *
 * This function writes a value into the WDOG_CS register to disable the RTWDOG.
 * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and
 * this register has not been written in this WCT while the function is called.
 *
 * @param base RTWDOG peripheral base address
 */
static inline void RTWDOG_Disable(RTWDOG_Type *base)
{
    base->CS &= ~RTWDOG_CS_EN_MASK;
}

/*!
 * @brief Enables the RTWDOG interrupt.
 *
 * This function writes a value into the WDOG_CS register to enable the RTWDOG interrupt.
 * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and
 * this register has not been written in this WCT while the function is called.
 *
 * @param base RTWDOG peripheral base address.
 * @param mask The interrupts to enable.
 *        The parameter can be a combination of the following source if defined:
 *        @arg kRTWDOG_InterruptEnable
 */
static inline void RTWDOG_EnableInterrupts(RTWDOG_Type *base, uint32_t mask)
{
    base->CS |= mask;
}

/*!
 * @brief Disables the RTWDOG interrupt.
 *
 * This function writes a value into the WDOG_CS register to disable the RTWDOG interrupt.
 * The WDOG_CS register is a write-once register. Ensure that the WCT window is still open and
 * this register has not been written in this WCT while the function is called.
 *
 * @param base RTWDOG peripheral base address.
 * @param mask The interrupts to disabled.
 *        The parameter can be a combination of the following source if defined:
 *        @arg kRTWDOG_InterruptEnable
 */
static inline void RTWDOG_DisableInterrupts(RTWDOG_Type *base, uint32_t mask)
{
    base->CS &= ~mask;
}

/*!
 * @brief Gets the RTWDOG all status flags.
 *
 * This function gets all status flags.
 *
 * Example to get the running flag:
 * @code
 *   uint32_t status;
 *   status = RTWDOG_GetStatusFlags(wdog_base) & kRTWDOG_RunningFlag;
 * @endcode
 * @param base        RTWDOG peripheral base address
 * @return            State of the status flag: asserted (true) or not-asserted (false). @see _rtwdog_status_flags_t
 *                    - true: related status flag has been set.
 *                    - false: related status flag is not set.
 */
static inline uint32_t RTWDOG_GetStatusFlags(RTWDOG_Type *base)
{
    return (base->CS & (RTWDOG_CS_EN_MASK | RTWDOG_CS_FLG_MASK));
}

/*!
 * @brief Enables/disables the window mode.
 *
 * @param base   RTWDOG peripheral base address.
 * @param enable Enables(true) or disables(false) the feature.
 */
static inline void RTWDOG_EnableWindowMode(RTWDOG_Type *base, bool enable)
{
    if (enable)
    {
        base->CS |= RTWDOG_CS_WIN_MASK;
    }
    else
    {
        base->CS &= ~RTWDOG_CS_WIN_MASK;
    }
}

/*!
 * @brief Converts raw count value to millisecond.
 *
 * Note that if the clock frequency is too high the timeout period can be less than 1 ms.
 * In this case this api will return 0 value.
 *
 * @param base          RTWDOG peripheral base address.
 * @param count         Raw count value.
 * @param clockFreqInHz The frequency of the clock source RTWDOG uses.
 */
static inline uint32_t RTWDOG_CountToMesec(RTWDOG_Type *base, uint32_t count, uint32_t clockFreqInHz)
{
    if ((base->CS & RTWDOG_CS_PRES_MASK) != 0U)
    {
        clockFreqInHz /= 256U;
    }
    return count * 1000U / clockFreqInHz;
}

/*!
 * @brief Clears the RTWDOG flag.
 *
 * This function clears the RTWDOG status flag.
 *
 * Example to clear an interrupt flag:
 * @code
 *   RTWDOG_ClearStatusFlags(wdog_base,kRTWDOG_InterruptFlag);
 * @endcode
 * @param base        RTWDOG peripheral base address.
 * @param mask        The status flags to clear.
 *                    The parameter can be any combination of the following values:
 *                    @arg kRTWDOG_InterruptFlag
 */
void RTWDOG_ClearStatusFlags(RTWDOG_Type *base, uint32_t mask);

/*!
 * @brief Sets the RTWDOG timeout value.
 *
 * This function writes a timeout value into the WDOG_TOVAL register.
 * The WDOG_TOVAL register is a write-once register. Ensure that the WCT window is still open and
 * this register has not been written in this WCT while the function is called.
 *
 * @param base RTWDOG peripheral base address
 * @param timeoutCount RTWDOG timeout value, count of RTWDOG clock ticks.
 */
static inline void RTWDOG_SetTimeoutValue(RTWDOG_Type *base, uint16_t timeoutCount)
{
    base->TOVAL = timeoutCount;
}

/*!
 * @brief Sets the RTWDOG window value.
 *
 * This function writes a window value into the WDOG_WIN register.
 * The WDOG_WIN register is a write-once register. Ensure that the WCT window is still open and
 * this register has not been written in this WCT while the function is called.
 *
 * @param base RTWDOG peripheral base address.
 * @param windowValue RTWDOG window value.
 */
static inline void RTWDOG_SetWindowValue(RTWDOG_Type *base, uint16_t windowValue)
{
    base->WIN = windowValue;
}

/*!
 * @brief Unlocks the RTWDOG register written.
 *
 * This function unlocks the RTWDOG register written.
 *
 * Before starting the unlock sequence and following the configuration, disable the global interrupts.
 * Otherwise, an interrupt could effectively invalidate the unlock sequence and the WCT may expire.
 * After the configuration finishes, re-enable the global interrupts.
 *
 * @param base RTWDOG peripheral base address
 */
__STATIC_FORCEINLINE void RTWDOG_Unlock(RTWDOG_Type *base)
{
    if (((base->CS) & RTWDOG_CS_CMD32EN_MASK) != 0U)
    {
        base->CNT = RTWDOG_UPDATE_KEY;
    }
    else
    {
        base->CNT = WDOG_FIRST_WORD_OF_UNLOCK;
        base->CNT = WDOG_SECOND_WORD_OF_UNLOCK;
    }
    while ((base->CS & RTWDOG_CS_ULK_MASK) == 0U)
    {
    }
}

/*!
 * @brief Refreshes the RTWDOG timer.
 *
 * This function feeds the RTWDOG.
 * This function should be called before the Watchdog timer is in timeout. Otherwise, a reset is asserted.
 *
 * @param base RTWDOG peripheral base address
 */
static inline void RTWDOG_Refresh(RTWDOG_Type *base)
{
    uint32_t primaskValue = 0U;
    primaskValue          = DisableGlobalIRQ();
    if (((base->CS) & RTWDOG_CS_CMD32EN_MASK) != 0U)
    {
        base->CNT = RTWDOG_REFRESH_KEY;
    }
    else
    {
        base->CNT = WDOG_FIRST_WORD_OF_REFRESH;
        base->CNT = WDOG_SECOND_WORD_OF_REFRESH;
    }
    EnableGlobalIRQ(primaskValue);
}

/*!
 * @brief Gets the RTWDOG counter value.
 *
 * This function gets the RTWDOG counter value.
 *
 * @param base RTWDOG peripheral base address.
 * @return     Current RTWDOG counter value.
 */
static inline uint16_t RTWDOG_GetCounterValue(RTWDOG_Type *base)
{
    return (uint16_t)base->CNT;
}

/*@}*/

#if defined(__cplusplus)
}
#endif /* __cplusplus */

/*! @}*/

#endif /* _FSL_RTWDOG_H_ */

M module-bsp/board/rt1051/common/startup_mimxrt1052.cpp => module-bsp/board/rt1051/common/startup_mimxrt1052.cpp +8 -44
@@ 1,6 1,3 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

//*****************************************************************************
// MIMXRT1052 startup code for use with MCUXpresso IDE
//


@@ 72,17 69,15 @@ extern "C"
{
#endif

//*****************************************************************************
// Variable to store CRP value in. Will be placed automatically
// by the linker when "Enable Code Read Protect" selected.
// See crp.h header for more information
//*****************************************************************************
//*****************************************************************************
// Declaration of external SystemInit function
//*****************************************************************************
#if defined(__USE_CMSIS)
    //*****************************************************************************
    // Variable to store CRP value in. Will be placed automatically
    // by the linker when "Enable Code Read Protect" selected.
    // See crp.h header for more information
    //*****************************************************************************
    //*****************************************************************************
    // Declaration of external SystemInit function
    //*****************************************************************************
    extern void SystemInit(void);
#endif // (__USE_CMSIS)

    //*****************************************************************************
    // Forward declaration of the core exception handlers.


@@ 703,24 698,7 @@ __attribute__((section(".after_vectors.reset"))) void ResetISR(void)
    // Disable interrupts
    __asm volatile("cpsid i");

#if defined(__USE_CMSIS)
    // If __USE_CMSIS defined, then call CMSIS SystemInit code
    SystemInit();
#else
    // Disable Watchdog
    volatile unsigned int *WDOG1_WCR = (unsigned int *)0x400B8000;
    *WDOG1_WCR                       = *WDOG1_WCR & ~(1 << 2);
    volatile unsigned int *WDOG2_WCR = (unsigned int *)0x400D0000;
    *WDOG2_WCR                       = *WDOG2_WCR & ~(1 << 2);
    // Write watchdog update key to unlock
    *((volatile unsigned int *)0x400BC004) = 0xD928C520;
    // Set timeout value
    *((volatile unsigned int *)0x400BC008) = 0xFFFF;
    // Now disable watchdog via control register
    volatile unsigned int *RTWDOG_CS = (unsigned int *)0x400BC000;
    *RTWDOG_CS                       = (*RTWDOG_CS & ~(1 << 7)) | (1 << 5);

#endif // (__USE_CMSIS)

    unsigned int LoadAddr, ExeAddr, SectionLen;
    unsigned int *SectionTableAddr;


@@ 747,20 725,6 @@ __attribute__((section(".after_vectors.reset"))) void ResetISR(void)
        bss_init(ExeAddr, SectionLen);
    }

#if !defined(__USE_CMSIS)
    // Assume that if __USE_CMSIS defined, then CMSIS SystemInit code
    // will setup the VTOR register

    // Check to see if we are running the code from a non-zero
    // address (eg RAM, external flash), in which case we need
    // to modify the VTOR register to tell the CPU that the
    // vector table is located at a non-0x0 address.
    unsigned int *pSCB_VTOR = (unsigned int *)0xE000ED08;
    if ((unsigned int *)g_pfnVectors != (unsigned int *)0x00000000) {
        *pSCB_VTOR = (unsigned int)g_pfnVectors;
    }
#endif // (__USE_CMSIS)

#if defined(__cplusplus)
    //
    // Call C++ library initialisation

M module-bsp/board/rt1051/common/system_MIMXRT1051.c => module-bsp/board/rt1051/common/system_MIMXRT1051.c +22 -7
@@ 1,3 1,6 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/*
** ###################################################################
**     Processors:          MIMXRT1051CVJ5B


@@ 96,23 99,35 @@ void SystemInit(void)
    extern uint32_t g_pfnVectors[]; // Vector table defined in startup code
    SCB->VTOR = (uint32_t)g_pfnVectors;

    /* Disable Watchdog Power Down Counter */
    // Disable WDOGx Power Down Counter
    WDOG1->WMCR &= ~WDOG_WMCR_PDE_MASK;
    WDOG2->WMCR &= ~WDOG_WMCR_PDE_MASK;

    /* Watchdog disable */

#if (DISABLE_WDOG)
    // Disable WDOGx watchdogs timers
    if (WDOG1->WCR & WDOG_WCR_WDE_MASK) {
        WDOG1->WCR &= ~WDOG_WCR_WDE_MASK;
    }
    if (WDOG2->WCR & WDOG_WCR_WDE_MASK) {
        WDOG2->WCR &= ~WDOG_WCR_WDE_MASK;
    }
    RTWDOG->CNT   = 0xD928C520U; /* 0xD928C520U is the update key */

#if defined(DISABLE_WATCHDOG)
    // Write watchdog update key to unlock
    RTWDOG->CNT = 0xD928C520U;
    // Disable RTWDOG and allow configuration updates
    RTWDOG->TOVAL = 0xFFFF;
    RTWDOG->CS    = (uint32_t)((RTWDOG->CS) & ~RTWDOG_CS_EN_MASK) | RTWDOG_CS_UPDATE_MASK;
#endif /* (DISABLE_WDOG) */
    RTWDOG->CS    = (uint32_t)(((RTWDOG->CS) & ~RTWDOG_CS_EN_MASK) | RTWDOG_CS_UPDATE_MASK);
#else
    //
    // Perform preliminary RTWDOG configuration
    //
    // Write RTWDOG update key to unlock
    RTWDOG->CNT = 0xD928C520U;
    // Set timeout value (16s, assuming 128Hz clock - 32.768kHz after 256 prescaler)
    RTWDOG->TOVAL = 2048;
    // Enable RTWDOG, set 256 clock prescaler and allow configuration updates
    RTWDOG->CS = (uint32_t)((RTWDOG->CS) | RTWDOG_CS_EN_MASK | RTWDOG_CS_UPDATE_MASK | RTWDOG_CS_PRES_MASK);
#endif // (DISABLE_WATCHDOG)

    /* Disable Systick which might be enabled by bootrom */
    if (SysTick->CTRL & SysTick_CTRL_ENABLE_Msk) {

M module-bsp/board/rt1051/common/system_MIMXRT1051.h => module-bsp/board/rt1051/common/system_MIMXRT1051.h +3 -4
@@ 1,3 1,6 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/*
** ###################################################################
**     Processors:          MIMXRT1051CVJ5B


@@ 84,10 87,6 @@ extern "C"

#include <stdint.h>

#ifndef DISABLE_WDOG
#define DISABLE_WDOG 1
#endif

    /* Define clock source values */

#define CPU_XTAL_CLK_HZ 24000000UL /* Value of the external crystal or oscillator clock frequency in Hz */

M module-bsp/bsp/watchdog/watchdog.hpp => module-bsp/bsp/watchdog/watchdog.hpp +5 -14
@@ 1,19 1,10 @@
#pragma once
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include <string>
#pragma once

namespace bsp::watchdog
{
    /// initializes and starts watchdog
    /// - for linux             - does nothing
    /// - for rt1051 debug      - initializes with maximum value (125 sec)
    /// - for rt1051 release    - initializes with maximum value (125 sec)
    void init();
    /// resets system
    /// - for linux - does nothing - consider just exit(0)
    void system_reset();
    /// update watchdog, so that it won't kick us
    void pet();
    /// get watchdog reset cause
    std::string reset_cause();
    bool init(unsigned int timeoutMs);
    void refresh();
}

D module-bsp/bsp/watchdog/watchdog_weak.cpp => module-bsp/bsp/watchdog/watchdog_weak.cpp +0 -0
M module-bsp/targets/Target_Linux.cmake => module-bsp/targets/Target_Linux.cmake +2 -0
@@ 30,6 30,8 @@ set(BOARD_SOURCES

        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/light_sensor/light_sensor.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/watchdog/software_watchdog.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/watchdog/watchdog.cpp"

        CACHE INTERNAL "")

M module-bsp/targets/Target_RT1051.cmake => module-bsp/targets/Target_RT1051.cmake +1 -0
@@ 32,6 32,7 @@ set(BOARD_SOURCES ${BOARD_SOURCES}
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_dmamux.c"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_edma.c"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_wdog.c"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_rtwdog.c"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/fsl_drivers/fsl_pwm.c"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/irq/irq_gpio.cpp"
	"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/common/audio.cpp"

M module-sys/CMakeLists.txt => module-sys/CMakeLists.txt +1 -0
@@ 23,6 23,7 @@ set(SOURCES
        ${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/DeviceManager.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/CpuGovernor.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/SystemManager/graph/TopologicalSort.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/SystemWatchdog/SystemWatchdog.cpp

        )


M module-sys/Service/BusProxy.cpp => module-sys/Service/BusProxy.cpp +14 -3
@@ 7,7 7,8 @@

namespace sys
{
    BusProxy::BusProxy(Service *owner) : owner{owner}, busImpl{std::make_unique<Bus>()}
    BusProxy::BusProxy(Service *owner, Watchdog &watchdog)
        : owner{owner}, watchdog{watchdog}, busImpl{std::make_unique<Bus>()}
    {
        channels.push_back(BusChannel::System); // Mandatory for each service.
    }


@@ 16,22 17,32 @@ namespace sys

    bool BusProxy::sendUnicast(std::shared_ptr<Message> message, const std::string &targetName)
    {
        return busImpl->SendUnicast(std::move(message), targetName, owner);
        auto ret = busImpl->SendUnicast(std::move(message), targetName, owner);
        if (ret) {
            watchdog.refresh();
        }
        return ret;
    }

    SendResult BusProxy::sendUnicast(std::shared_ptr<Message> message, const std::string &targetName, uint32_t timeout)
    {
        return busImpl->SendUnicast(std::move(message), targetName, owner, timeout);
        auto ret = busImpl->SendUnicast(std::move(message), targetName, owner, timeout);
        if (ret.first != ReturnCodes::Failure) {
            watchdog.refresh();
        }
        return ret;
    }

    void BusProxy::sendMulticast(std::shared_ptr<Message> message, BusChannel channel)
    {
        busImpl->SendMulticast(std::move(message), channel, owner);
        watchdog.refresh();
    }

    void BusProxy::sendBroadcast(std::shared_ptr<Message> message)
    {
        busImpl->SendBroadcast(std::move(message), owner);
        watchdog.refresh();
    }

    void BusProxy::sendResponse(std::shared_ptr<Message> response, std::shared_ptr<Message> request)

M module-sys/Service/BusProxy.hpp => module-sys/Service/BusProxy.hpp +3 -1
@@ 4,6 4,7 @@
#pragma once

#include "Message.hpp"
#include "Watchdog.hpp"

#include <cstdint>
#include <memory>


@@ 31,13 32,14 @@ namespace sys

      private:
        friend class Service;
        explicit BusProxy(Service *owner);
        explicit BusProxy(Service *owner, Watchdog &watchdog);

        void sendResponse(std::shared_ptr<Message> response, std::shared_ptr<Message> request);
        void connect();
        void disconnect();

        Service *owner;
        Watchdog &watchdog;
        std::unique_ptr<Bus> busImpl;
    };
} // namespace sys

M module-sys/Service/Service.cpp => module-sys/Service/Service.cpp +6 -5
@@ 49,11 49,12 @@ namespace sys
    using namespace cpp_freertos;
    using namespace std;

    Service::Service(std::string name, std::string parent, uint32_t stackDepth, ServicePriority priority)
    Service::Service(
        std::string name, std::string parent, uint32_t stackDepth, ServicePriority priority, Watchdog &watchdog)
        : cpp_freertos::Thread(name, stackDepth / 4 /* Stack depth in bytes */, static_cast<UBaseType_t>(priority)),
          parent(parent), bus{this}, mailbox(this), pingTimestamp(UINT32_MAX), isReady(false), enableRunLoop(false)
    {
    }
          parent(parent), bus(this, watchdog), mailbox(this), watchdog(watchdog), pingTimestamp(UINT32_MAX),
          isReady(false), enableRunLoop(false)
    {}

    Service::~Service()
    {


@@ 148,7 149,7 @@ namespace sys

    bool Service::connect(const type_info &type, MessageHandler handler)
    {
        auto idx   = type_index(type);
        auto idx = type_index(type);
        if (message_handlers.find(idx) == message_handlers.end()) {
            LOG_DEBUG("Registering new message handler on %s", type.name());
            message_handlers[idx] = handler;

M module-sys/Service/Service.hpp => module-sys/Service/Service.hpp +18 -13
@@ 9,18 9,20 @@
#include "Mailbox.hpp" // for Mailbox
#include "Message.hpp" // for MessagePointer
#include "ServiceManifest.hpp"
#include "thread.hpp" // for Thread
#include <algorithm>  // for find, max
#include <cstdint>    // for uint32_t, uint64_t
#include <functional> // for function
#include <iterator>   // for end
#include <map>        // for map
#include <memory>     // for allocator, shared_ptr, enable_shared_from_this
#include <string>     // for string
#include <typeindex>  // for type_index
#include <utility>    // for pair
#include <vector>     // for vector<>::iterator, vector
#include <typeinfo>   // for connect by type
#include "Watchdog.hpp"
#include "thread.hpp"                                   // for Thread
#include <module-sys/SystemWatchdog/SystemWatchdog.hpp> // for SystemWatchdog
#include <algorithm>                                    // for find, max
#include <cstdint>                                      // for uint32_t, uint64_t
#include <functional>                                   // for function
#include <iterator>                                     // for end
#include <map>                                          // for map
#include <memory>                                       // for allocator, shared_ptr, enable_shared_from_this
#include <string>                                       // for string
#include <typeindex>                                    // for type_index
#include <utility>                                      // for pair
#include <vector>                                       // for vector<>::iterator, vector
#include <typeinfo>                                     // for connect by type

namespace sys
{


@@ 41,7 43,8 @@ namespace sys
        Service(std::string name,
                std::string parent       = "",
                uint32_t stackDepth      = 4096,
                ServicePriority priority = ServicePriority::Idle);
                ServicePriority priority = ServicePriority::Idle,
                Watchdog &watchdog       = SystemWatchdog::getInstance());

        ~Service() override;



@@ 77,6 80,8 @@ namespace sys

        Mailbox<std::shared_ptr<Message>> mailbox;

        Watchdog &watchdog;

        uint32_t pingTimestamp;

        bool isReady;

A module-sys/Service/Watchdog.hpp => module-sys/Service/Watchdog.hpp +13 -0
@@ 0,0 1,13 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

namespace sys
{
    class Watchdog
    {
      public:
        virtual void refresh() = 0;
    };
} // namespace sys

M module-sys/Service/details/bus/Bus.cpp => module-sys/Service/details/bus/Bus.cpp +1 -0
@@ 7,6 7,7 @@
#include "Bus.hpp"

#include "module-sys/Service/Service.hpp"
#include "module-sys/SystemWatchdog/SystemWatchdog.hpp"
#include "module-os/CriticalSectionGuard.hpp"

#include "ticks.hpp"

A module-sys/SystemWatchdog/SystemWatchdog.cpp => module-sys/SystemWatchdog/SystemWatchdog.cpp +75 -0
@@ 0,0 1,75 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "SystemWatchdog.hpp"
#include "Service/Common.hpp"
#include "critical.hpp"
#include "ticks.hpp"
#include "bsp/watchdog/watchdog.hpp"
#include "log/log.hpp"

namespace sys
{
    using namespace cpp_freertos;

    static constexpr uint16_t stackDepthWords = 256;

    SystemWatchdog::SystemWatchdog()
        : Thread(threadName, stackDepthWords, static_cast<UBaseType_t>(ServicePriority::High))
    {}

    SystemWatchdog &SystemWatchdog::getInstance()
    {
        static SystemWatchdog watchdog;
        return watchdog;
    }

    bool SystemWatchdog::init()
    {
#ifdef DISABLE_WATCHDOG
        return true;
#else
        if (!bsp::watchdog::init(watchdogTimeoutPeriod)) {
            return false;
        }
        bsp::watchdog::refresh();

        if (!Start()) {
            return false;
        }

        refresh();

        return true;
#endif
    }

    void SystemWatchdog::refresh()
    {
#ifndef DISABLE_WATCHDOG
        // Critical section not required (atomic 32-bit writes)
        lastRefreshTimestamp = Ticks::GetTicks();
#endif
    }

    void SystemWatchdog::Run()
    {
        while (true) {
            vTaskDelay(checkPeriod);

            if (timeout_occurred) {
                continue;
            }

            // Critical section not required (atomic 32-bit reads)
            if (Ticks::GetTicks() - lastRefreshTimestamp >= refreshTimeoutPeriod) {
                // Allow HW watchdog timeout to occur
                timeout_occurred = true;
                LOG_FATAL("!!! System watchdog timeout, system will be resetted soon !!!");
            }
            else {
                bsp::watchdog::refresh();
            }
        }
    }
} // namespace sys

A module-sys/SystemWatchdog/SystemWatchdog.hpp => module-sys/SystemWatchdog/SystemWatchdog.hpp +59 -0
@@ 0,0 1,59 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

#include <module-sys/Service/Watchdog.hpp>
#include "thread.hpp"

namespace sys
{
    //
    // System watchdog
    //
    // System watchdog works in cooperation with an actual watchdog
    // (HW or simulated). After initialization, it expects to be continually
    // refreshed within a certain period of time.
    //
    // As long as its timing requirements are satisfied, it takes care
    // of refreshing the actual watchdog so a reset will not occur. Otherwise,
    // it will allow the actual watchdog to timeout causing a system reset.
    //
    class SystemWatchdog : public Watchdog, private cpp_freertos::Thread
    {
      public:
        static constexpr auto threadName = "System_Watchdog";

        SystemWatchdog(const SystemWatchdog &) = delete;
        SystemWatchdog(SystemWatchdog &&)      = delete;
        SystemWatchdog &operator=(const SystemWatchdog &) = delete;
        SystemWatchdog &operator=(SystemWatchdog &&) = delete;

        static SystemWatchdog &getInstance();

        // Initialize the actual watchdog and start the thread
        bool init();

        void refresh() override;

      private:
        SystemWatchdog();

        // Timeout period for refresh
        static constexpr TickType_t refreshTimeoutPeriod = pdMS_TO_TICKS(90000);
        // Timeout period for the actual watchdog
        static constexpr TickType_t watchdogTimeoutPeriod = pdMS_TO_TICKS(16000);
        // Period of actual watchdog refresh
        static constexpr TickType_t checkPeriod = pdMS_TO_TICKS(8000);

        void Run() final;

        TickType_t lastRefreshTimestamp = 0;
        bool timeout_occurred           = false;

        static_assert(sizeof(lastRefreshTimestamp) == 4 && alignof(decltype(lastRefreshTimestamp)) == 4,
                      "SystemWatchdog::lastRefreshTimestamp must be 32-bit long and properly aligned otherwise data "
                      "races may occur");
    };

} // namespace sys

M source/main.cpp => source/main.cpp +8 -0
@@ 51,6 51,7 @@
#include <phonenumbers/phonenumberutil.h>
#include <source/version.hpp>
#include <SystemManager/SystemManager.hpp>
#include <SystemWatchdog/SystemWatchdog.hpp>
#include <thread.hpp>
#include <vfs.hpp>



@@ 73,6 74,13 @@ int main()

    bsp::BoardInit();

    if (!sys::SystemWatchdog::getInstance().init()) {
        LOG_ERROR("System watchdog failed to initialize");
        // wait for the hardware watchdog (initialized in reset ISR) to reset the system
        while (1)
            ;
    }

    std::vector<std::unique_ptr<sys::BaseServiceCreator>> systemServices;
    systemServices.emplace_back(sys::CreatorFor<EventManager>());
#if ENABLE_FILEINDEXER_SERVICE