/**
 * @file xmc_wdt.h
 * @date 2015-08-06
 *
 * @cond
 *****************************************************************************
 * XMClib v2.2.0 - XMC Peripheral Driver Library
 *
 * Copyright (c) 2015-2020, Infineon Technologies AG
 * All rights reserved.
 *
 * Boost Software License - Version 1.0 - August 17th, 2003
 *
 * Permission is hereby granted, free of charge, to any person or organization
 * obtaining a copy of the software and accompanying documentation covered by
 * this license (the "Software") to use, reproduce, display, distribute,
 * execute, and transmit the Software, and to prepare derivative works of the
 * Software, and to permit third-parties to whom the Software is furnished to
 * do so, all subject to the following:
 *
 * The copyright notices in the Software and this entire statement, including
 * the above license grant, this restriction and the following disclaimer,
 * must be included in all copies of the Software, in whole or in part, and
 * all derivative works of the Software, unless such copies or derivative
 * works are solely in the form of machine-executable object code generated by
 * a source language processor.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
 * SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
 * FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 *
 * To improve the quality of the software, users are encouraged to share
 * modifications, enhancements or bug fixes with Infineon Technologies AG
 * at XMCSupport@infineon.com.
 *****************************************************************************
 *
 * Change History
 * --------------
 *
 * 2015-02-20:
 *     - Initial <br>
 *     - Documentation updates <br>
 *
 * 2015-06-20:
 *     - Removed version macros and declaration of GetDriverVersion API <br>
 *
 * 2015-08-06:
 *     - Bug fix in XMC_WDT_SetDebugMode() API, Wrong register is being configured.<br>
 * @endcond
 */

#ifndef XMC_WDT_H
#define XMC_WDT_H

/*********************************************************************************************************************
 * HEADER FILES
 ********************************************************************************************************************/

#include "xmc_common.h"
#include "xmc_scu.h"
/**
 * @addtogroup XMClib XMC Peripheral Library
 * @{
 */

/**
 * @addtogroup WDT
 * @brief Watchdog driver for the XMC microcontroller family.
 *
 * The watchdog unit (WDT) improves the system integrity, by triggering the system reset request to bring the system
 * back from the unresponsive state to normal operation.
 *
 * This LLD provides the Configuration structure XMC_WDT_CONFIG_t and initialization function XMC_WDT_Init().\n
 * It can be used to:
 * -# Start or Stop the watchdog timer. (XMC_WDT_Start() and XMC_WDT_Stop())
 * -# Service the watchdog timer. (XMC_WDT_Service())
 * -# Configure the service window upper bound and lower bound timing values. (XMC_WDT_SetWindowBounds())
 * -# Enable the generation of the pre-warning event for the first overflow of the timer. (XMC_WDT_SetMode())
 * -# Clear the pre-warning alarm event. It is mandatory to clear the flag during pre-warning alarm ISR, to stop
      generating reset request for the second overflow of the timer. (XMC_WDT_ClearAlarm())
 * -# Suspend the watchdog timer during Debug HALT mode. (XMC_WDT_SetDebugMode())
 * -# Configure service indication pulse width.(XMC_WDT_SetServicePulseWidth())
 *
 * @{
 */

/*********************************************************************************************************************
 * MACROS
  ********************************************************************************************************************/

#define XMC_WDT_MAGIC_WORD             (0xABADCAFEU) /* Magic word to be written in Service Register (SRV), 
                                                          to service or feed the watchdog. */

/*********************************************************************************************************************
 * ENUMS
  ********************************************************************************************************************/

/**
 *  Defines working modes for watchdog. Use type XMC_WDT_MODE_t for this enum.
 */
typedef enum XMC_WDT_MODE
{
  XMC_WDT_MODE_TIMEOUT    = (uint32_t)0x0 << WDT_CTR_PRE_Pos, /**< Generates reset request as soon as the timer overflow
                                                                   occurs. */
  XMC_WDT_MODE_PREWARNING = (uint32_t)0x1 << WDT_CTR_PRE_Pos  /**< Generates an alarm event for the first overflow. And
                                                                   reset request after subsequent overflow, if not
                                                                   serviced after first overflow. */
} XMC_WDT_MODE_t;

/**
 *  Defines debug behaviour of watchdog when the CPU enters HALT mode. Use type XMC_WDT_DEBUG_MODE_t for this enum.
 */
typedef enum XMC_WDT_DEBUG_MODE
{
  XMC_WDT_DEBUG_MODE_STOP = (uint32_t)0x0 << WDT_CTR_DSP_Pos, /**< Watchdog counter is paused during debug halt. */
  XMC_WDT_DEBUG_MODE_RUN  = (uint32_t)0x1 << WDT_CTR_DSP_Pos  /**< Watchdog counter is not paused during debug halt. */
} XMC_WDT_DEBUG_MODE_t;

/*********************************************************************************************************************
 * DATA STRUCTURES
  ********************************************************************************************************************/
/* Anonymous structure/union guard start */
#if defined(__CC_ARM)
#pragma push
#pragma anon_unions
#elif defined(__TASKING__)
#pragma warning 586
#endif

/**
 * Structure for initializing watchdog timer. Use type XMC_WDT_CONFIG_t for this structure.
 */
typedef struct XMC_WDT_CONFIG
{
  uint32_t window_upper_bound; /**< Upper bound for service window (WUB). Reset request is generated up on overflow of
                                    timer. ALways upper bound value has to be more than lower bound value. If it is set
                                    lower than WLB, triggers a system reset after timer crossed upper bound value.\n
                                    Range: [0H to FFFFFFFFH] */
  uint32_t window_lower_bound; /**< Lower bound for servicing window (WLB). Setting the lower bound to 0H disables the
                                    window mechanism.\n
                                    Range: [0H to FFFFFFFFH] */
  union
  {
    struct
    {
      uint32_t : 1;
      uint32_t prewarn_mode : 1;        /**< Pre-warning mode (PRE). This accepts boolean values as input. */
      uint32_t : 2;
      uint32_t run_in_debug_mode : 1;   /**< Watchdog timer behaviour during debug (DSP). This accepts boolean values as input. */
      uint32_t : 3;
      uint32_t service_pulse_width : 8; /**< Service Indication Pulse Width (SPW). Generated Pulse width is of (SPW+1),
                                             in fwdt cycles.\n
                                             Range: [0H to FFH] */
      uint32_t : 16;
    };
    uint32_t wdt_ctr; /* Value of operation mode control register (CTR). It’s bit fields are represented by above
                           union members. */
  };
} XMC_WDT_CONFIG_t;
/* Anonymous structure/union guard end */
#if defined(__CC_ARM)
#pragma pop
#elif defined(__TASKING__)
#pragma warning restore
#endif
/*********************************************************************************************************************
 * API PROTOTYPES
  ********************************************************************************************************************/

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @param None
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * \if XMC4
 * Enables watchdog clock and releases watchdog reset.\n
 * \endif
 * \if XMC1
 * Enables watchdog clock.\n
 * \endif
 * \par
 * This API is invoked by XMC_WDT_Init() and therefore no need to call it explicitly during watchdog initialization
 * sequence. Invoke this API to enable watchdog once again if the watchdog is disabled by invoking XMC_WDT_Disable().
 *
 * \par<b>Note:</b><br>
 * \if XMC4
 * 1. It is required to configure the watchdog, again after invoking XMC_WDT_Disable(). Since all the registers are
 *    reset with default values.
 * \endif
 * \if XMC1
 * 1. Not required to configure the watchdog again after invoking XMC_WDT_Disable(). Since the registers retains with
 *    the configured values.
 * \endif
 * \par<b>Related APIs:</b><BR>
 * XMC_WDT_Init(), XMC_WDT_Disable()
 */
void XMC_WDT_Enable(void);

/**
 * @param None
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * \if XMC4
 * Disables the clock and resets watchdog timer.\n
 * \endif
 * \if XMC1
 * Disables the clock to the watchdog timer.\n
 * \endif
 *
 * \par<b>Note:</b><br>
 * \if XMC4
 * 1. Resets the registers with default values. So XMC_WDT_Init() has to be invoked again to configure the watchdog.
 * \endif
 * \if XMC1
 * 1. After invoking XMC_WDT_Disable(), all register values are displayed with 0F in debugger. Once enabled by
      calling XMC_WDT_Enable(), previous configured register values are displayed. No need to invoke XMC_WDT_Init()
      again.
 * \endif
 * \par<b>Related APIs:</b><BR>
 * XMC_WDT_Enable()
 */
void XMC_WDT_Disable(void);

/**
 * @param config pointer to a constant watchdog configuration data structure. Refer data structure XMC_WDT_CONFIG_t
 *               for detail.
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * Initializes and configures watchdog with configuration data pointed by \a config.\n
 * \par
 * It invokes XMC_WDT_Enable() to enable clock and release reset. Then configures the lower and upper window bounds,
 * working mode (timeout/pre-warning), debug behaviour and service request indication pulse width.
 *
 * \par<b>Note:</b><br>
 * 1. With out invoking this XMC_WDT_Init() or XMC_WDT_Enable(), invocation of other APIs like XMC_WDT_SetWindowBounds(),
 *    XMC_WDT_SetMode(), XMC_WDT_SetServicePulseWidth(), XMC_WDT_SetDebugMode(), XMC_WDT_Start(), XMC_WDT_GetCounter(),
 *    XMC_WDT_Service(), XMC_WDT_ClearAlarm() has no affect.
 */
void XMC_WDT_Init(const XMC_WDT_CONFIG_t *const config);

/**
 * @param lower_bound specifies watchdog window lower bound in terms of watchdog clock (fWDT) cycles.
 *                    Range: [0H to FFFFFFFFH].
 * @param upper_bound specifies watchdog window upper bound in terms of watchdog clock (fWDT) cycles.
 *                    Range: [0H to FFFFFFFFH].
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * Sets watchdog window lower and upper bounds by updating WLB and WUB registers.\n
 * \par
 * Window lower and upper bounds are set during initialization in XMC_WDT_Init(). Invoke this API to alter the values as
 * needed later in the program. This upper bound and lower bound can be calculated by using the below formula\n
 *       upper_bound or lower_bound = desired_boundary_time(sec) * fwdt(hz)
 *
 * \par<b>Note:</b>
 * 1. Always ensure that upper_bound is greater than the lower_bound value. If not, whenever timer crosses the
 *    upper_bound value it triggers the reset(wdt_rst_req) of the controller.
 */
__STATIC_INLINE void XMC_WDT_SetWindowBounds(uint32_t lower_bound, uint32_t upper_bound)
{
  WDT->WLB = lower_bound;
  WDT->WUB = upper_bound;
}

/**
 * @param mode is one of the working modes of the watchdog timer, i.e timeout or pre-warning. Refer @ref XMC_WDT_MODE_t
 *             for valid values.
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * Sets watchdog working mode (timeout or pre-warning) by updating PRE bit of CTR register.\n
 * \par
 * The working mode is set during initialization in XMC_WDT_Init(). Invoke this API to alter the mode as needed later in
 * the program.
 */
__STATIC_INLINE void XMC_WDT_SetMode(XMC_WDT_MODE_t mode)
{
  WDT->CTR = (WDT->CTR & (uint32_t)~WDT_CTR_PRE_Msk) | (uint32_t)mode;
}

/**
 * @param service_pulse_width specifies Service indication pulse width in terms of fwdt.
 *                            Range: [0H – FFH].
 * @return None
 *
 * \par<b>Description:</b><br>
 * Sets service indication pulse width by updating SPW bit field of CTR register.\n
 * \par
 * The service indication pulse (with width service_pulse_width + 1 in fwdt cycles) is generated on successful servicing
 * or feeding of watchdog. The pulse width is initially set during initialization in XMC_WDT_Init(). Invoke this API to
 * alter the width as needed later in the program.
 */
__STATIC_INLINE void XMC_WDT_SetServicePulseWidth(uint8_t service_pulse_width)
{
  WDT->CTR = (WDT->CTR & (uint32_t)~WDT_CTR_SPW_Msk) | ((uint32_t)service_pulse_width << WDT_CTR_SPW_Pos);
}

/**
 * @param debug_mode running state of watchdog during debug halt mode. Refer @ref XMC_WDT_DEBUG_MODE_t for
 *                   valid values.
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * Sets debug behaviour of watchdog by modifying DSP bit of CTR register.\n
 * \par
 * Depending upon DSP bit, the watchdog timer stops when CPU is in HALT mode. The debug behaviour is initially set as
 * XMC_WDT_DEBUG_MODE_STOP during initialization in XMC_WDT_Init(). Invoke this API to change the debug behaviour as
 * needed later in the program.
 */
__STATIC_INLINE void XMC_WDT_SetDebugMode(const XMC_WDT_DEBUG_MODE_t debug_mode)
{
  WDT->CTR = (WDT->CTR & (uint32_t)~WDT_CTR_DSP_Msk) | (uint32_t)debug_mode;
}

/**
 * @param None
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * Start the watchdog timer by setting ENB bit of CTR register.\n
 * \par
 * Invoke this API to start the watchdog after initialization, or to resume the watchdog when
 * paused by invoking XMC_WDT_Stop().
 *
 * \par<b>Related APIs:</b><BR>
 * XMC_WDT_Init(), XMC_WDT_Stop()
 */
__STATIC_INLINE void XMC_WDT_Start(void)
{
  WDT->CTR |= (uint32_t)WDT_CTR_ENB_Msk;
}

/**
 * @param None
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * Pauses watchdog timer by resetting ENB bit of CTR register.\n
 * \par
 * Invoke this API to pause the watchdog as needed in the program e.g. debugging through software control.
 *
 * \par<b>Related APIs:</b><BR>
 * XMC_WDT_Init(), XMC_WDT_Stop()
 */
__STATIC_INLINE void XMC_WDT_Stop(void)
{
  WDT->CTR &= (uint32_t)~WDT_CTR_ENB_Msk;
}

/**
 * @param None
 *
 * @return uint32_t Current count value of watchdog timer register (TIM).
 *                  Range: [0H to FFFFFFFFH]
 *
 * \par<b>Description:</b><br>
 * Reads current count of timer register (TIM).\n
 * \par
 * Invoke this API before servicing or feeding the watchdog to check whether count is between lower and upper
 * window bounds.
 *
 * \par<b>Related APIs:</b><BR>
 * XMC_WDT_Service()
 */
__STATIC_INLINE uint32_t XMC_WDT_GetCounter(void)
{
  return WDT->TIM;
}

/**
 * @param None
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * Services or feeds the watchdog by writing the Magic word in SRV register.\n
 * \par
 * Service watchdog when count value of watchdog timer is between lower and upper window bounds. Successful servicing
 * will reset watchdog timer (TIM register) to 0H and generate service indication pulse.
 *
 * \par<b>Note:</b><br>
 * 1. invoking this API when count value of watchdog timer is less than window lower bound results
 *    wrong servicing and immediately triggers reset request.
 *
 * \par<b>Related APIs:</b><BR>
 * XMC_WDT_GetCounter(), XMC_WDT_SetWindowBounds(), XMC_WDT_SetServicePulseWidth()
 */
__STATIC_INLINE void XMC_WDT_Service(void)
{
  WDT->SRV = XMC_WDT_MAGIC_WORD;
}

/**
 * @param None
 *
 * @return None
 *
 * \par<b>Description:</b><br>
 * Clears pre-warning alarm by setting ALMC bit in WDTCLR register.\n
 * \par
 * In pre-warning mode, first overflow of the timer upper window bound fires the pre-warning alarm. XMC_WDT_ClearAlarm()
 * must be invoked to clear the alarm alarm. After clearing of the alarm, watchdog timer must be serviced within valid
 * time window. Otherwise watchdog timer triggers the reset request up on crossing the upper bound value in a subsequent
 * cycle.
 *
 * \par<b>Related APIs:</b><BR>
 * XMC_WDT_Service(), XMC_WDT_SetMode()
 */
__STATIC_INLINE void XMC_WDT_ClearAlarm(void)
{
  WDT->WDTCLR = WDT_WDTCLR_ALMC_Msk;
}

#ifdef __cplusplus
}
#endif

/**
 * @}
 */

/**
 * @}
 */

#endif /* XMC_WDT_H */
