/**
 * @file xmc_wdt.h
 * @date 2015-08-06
 *
 * @cond
 *********************************************************************************************************************
 * XMClib v2.1.12 - XMC Peripheral Driver Library 
 *
 * Copyright (c) 2015-2017, Infineon Technologies AG
 * All rights reserved.                        
 *                                             
 * Redistribution and use in source and binary forms, with or without modification,are permitted provided that the 
 * following conditions are met:   
 *                                                                              
 * Redistributions of source code must retain the above copyright notice, this list of conditions and the following 
 * disclaimer.                        
 * 
 * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
 * disclaimer in the documentation and/or other materials provided with the distribution.                       
 * 
 * Neither the name of the copyright holders nor the names of its contributors may be used to endorse or promote 
 * products derived from this software without specific prior written permission.                                           
 *                                                                              
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE  
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE  FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR  
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
 * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.                                                  
 *                                                                              
 * To improve the quality of the software, users are encouraged to share modifications, enhancements or bug fixes with 
 * Infineon Technologies AG dave@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 */
