/**
 *******************************************************************************
 * @file    dpm32m0xx_pvd.c
 *
 * @brief   Source file for PVD firmware driver.
 *          This file provides firmware functions to manage the following
 *          functionalities of the PVD peripheral :
 *           + Initialization and Configuration
 *           + Interrupts and flags management
 *
 * @author  DPM
 *
 * @version V1.0.0
 *
 * @date    2023-11-01
 *
 * @verbatim
 ===============================================================================
                       ##### How to use this driver #####
 ===============================================================================
    [..]
      (#) Enable peripheral clock using the following functions
          RCC_APBPeriphClockCmd(RCC_APB_PERIPH_PVD, ENABLE).

      (#) Program the Trigger type, trigger result, reference voltage and filter
          using the PVD_Init() function.

      (#) Enable the PVD using the PVD_Cmd() function.

      (#) Get ready status and compare result using the PVD_GetReadyFlagStatus()
          and PVD_GetResFlagStatus() function.

      (#) PVD interrupt configuration:
        (+) To activate the PVD interrupt, using PVD_IntCmd() functions.
        (+) Check on PVD interrupt occur flags using the function
            PVD_GetIntFlagStatus().
        (+) Clear PVD interrupt flags using the function PVD_ClearIntFlag().

 * @endverbatim
 *******************************************************************************/

#include "dpm32m0xx_pvd.h"



/**
 *******************************************************************************
 * @brief   Deinitializes the PVD peripheral registers to their default reset values.
 * @retval  None.
 ******************************************************************************/
void PVD_DeInit(void)
{
  /* Reset PVD control register. */
  PVD->CR = (uint32_t)0x00000000;

  /* Clear interrupt flag. */
  PVD->SR = PVD_SR_IF_Msk;
}

/**
 *******************************************************************************
 * @brief   Initializes the PVD peripheral according to the specified parameters
 *          in the PVD_InitType.
 * @param   [in]  PVD_InitType: Structure pointer of PVD configuration.
 * @retval  None.
 ******************************************************************************/
void PVD_Init(PVD_InitTypeStruct* PVD_InitType)
{
  uint32_t tmpReg = 0UL;

  /* Parameters check. */
  PARAM_ASSERT(IS_PVD_TRIGGER_TYPE(PVD_InitType->PVD_TriggerType));
  PARAM_ASSERT(IS_PVD_TRIGGER_RESULT(PVD_InitType->PVD_TriggerResult));
  PARAM_ASSERT(IS_PVD_VREF_SEL(PVD_InitType->PVD_VrefSel));
  PARAM_ASSERT(IS_PVD_FILTER_LEN(PVD_InitType->PVD_Filter.FiltLen));
  PARAM_ASSERT(IS_PVD_FILTER_SAMPLE(PVD_InitType->PVD_Filter.FiltSample));
  PARAM_ASSERT(IS_FUNCTION_STATE(PVD_InitType->PVD_Filter.FiltState));

  /* Read the value of the PVD control register. */
  tmpReg = PVD->CR;

  /* Clear PVD TRIG_TYPE[1:0],TRIG_RESULT,REF_SEL[3:0],FLT_LEN[1:0],FLT_SAMPLE[1:0] bits. */
  tmpReg &= ~(PVD_CR_TRIG_TYPE_Msk | PVD_CR_TRIG_RESULT_Msk | PVD_CR_REF_SEL_Msk \
              | PVD_CR_FLT_LEN_Msk | PVD_CR_FLT_SAMPLE_Msk);

  /* Set PVD TRIG_TYPE[1:0] bits according to PVD_InitType. */
  tmpReg |= (uint32_t)(PVD_InitType->PVD_TriggerType);

  /* Set PVD TRIG_RESULT bit according to PVD_InitType. */
  tmpReg |= (uint32_t)(PVD_InitType->PVD_TriggerResult);

  /* Set PVD REF_SEL[3:0] bits according to PVD_InitType. */
  tmpReg |= (uint32_t)(PVD_InitType->PVD_VrefSel);

  /* Set PVD FLT_LEN[1:0] bits according to PVD_InitType. */
  tmpReg |= (uint32_t)(PVD_InitType->PVD_Filter.FiltLen);

  /* Set PVD FLT_SAMPLE[1:0] bits according to PVD_InitType. */
  tmpReg |= (uint32_t)(PVD_InitType->PVD_Filter.FiltSample);

  if(DISABLE != PVD_InitType->PVD_Filter.FiltState)
  {
    /* Enable PVD filter. */
    tmpReg |= PVD_CR_FLT_EN_Msk;
  }
  else
  {
    /* Disable PVD filter. */
    tmpReg &= ~PVD_CR_FLT_EN_Msk;
  }

  /* Store the new value. */
  PVD->CR = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Initialize the PVD_InitType with default parameters.
 * @param   [in]  PVD_InitType: Pointer to a PVD_InitTypeStruct structure
 *                which will be initialized.
 * @retval  None.
 ******************************************************************************/
void PVD_StructInit(PVD_InitTypeStruct* PVD_InitType)
{
  PVD_InitType->PVD_TriggerType = PVD_TRIGGER_TYPE_FALLING;
  PVD_InitType->PVD_TriggerResult = PVD_TRIGGER_RESULT_INT;
  PVD_InitType->PVD_VrefSel = PVD_VREF_SEL_22;
  PVD_InitType->PVD_Filter.FiltLen = PVD_FILTER_LEN8;
  PVD_InitType->PVD_Filter.FiltSample = PVD_FILTER_SAMPLE_PCLK4;
  PVD_InitType->PVD_Filter.FiltState = ENABLE;
}

/**
 *******************************************************************************
 * @brief   Enables or disables the specified PVD peripheral.
 * @param   [in]  NewState: This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void PVD_Cmd(FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable PVD. */
    PVD->CR |= PVD_CR_EN_Msk;
  }
  else
  {
    /* Disable PVD. */
    PVD->CR &= ~PVD_CR_EN_Msk;
  }
}

/**
 *******************************************************************************
 * @brief   Set PVD trigger type.
 * @param   [in]  PVD_TriggerType: Specifies the PVD trigger type.
 *                This parameter can be a value of @ref PVD_TriggerTypeEnum.
 *                  @arg PVD_TRIGGER_TYPE_FALLING: Falling trigger.
 *                  @arg PVD_TRIGGER_TYPE_RISING: Rising trigger.
 *                  @arg PVD_TRIGGER_TYPE_LOW_LEVEL: Low level trigger.
 *                  @arg PVD_TRIGGER_TYPE_HIGH_LEVEL: High lelve trigger.
 * @retval  None.
 ******************************************************************************/
void PVD_SetTriggerType(PVD_TriggerTypeEnum PVD_TrigType)
{
  uint32_t tmpReg = 0UL;

  /* Read the value of the PVD control register. */
  tmpReg = PVD->CR;

  /* Clear PVD TRIG_TYPE[1:0] bits. */
  tmpReg &= ~PVD_CR_TRIG_TYPE_Msk;

  /* Set PVD TRIG_TYPE[1:0] bits according to PVD_InitType. */
  tmpReg |= (uint32_t)(PVD_TrigType);

  /* Store the new value. */
  PVD->CR = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Set PVD action after trigger.
 * @param   [in]  PVD_TriggerType: Specifies the PVD trigger type.
 *                This parameter can be a value of @ref PVD_TriggerResultEnum.
 *                  @arg PVD_TRIGGER_RESULT_INT: Trigger interrupt.
 *                  @arg PVD_TRIGGER_RESULT_RESET: Trigger system reset.
 * @retval  None.
 ******************************************************************************/
void PVD_SetTriggerResult(PVD_TriggerResultEnum PVD_TriggerResult)
{
  uint32_t tmpReg = 0UL;

  /* Read the value of the PVD control register. */
  tmpReg = PVD->CR;

  /* Clear PVD TRIG_RESULT bit. */
  tmpReg &= ~PVD_CR_TRIG_RESULT_Msk;

  /* Set PVD TRIG_RESULT bit according to PVD_InitType. */
  tmpReg |= (uint32_t)(PVD_TriggerResult);

  /* Store the new value. */
  PVD->CR = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Set PVD detection reference voltage.
 * @param   [in]  PVD_Vref: Specifies the PVD detection reference voltage.
 *                This parameter can be a value of @ref PVD_VrefSelEnum.
 *                  @arg PVD_VREF_SEL_22: Detection reference voltage is 2.2V.
 *                  @arg PVD_VREF_SEL_24: Detection reference voltage is 2.4V.
 *                  @arg PVD_VREF_SEL_26: Detection reference voltage is 2.6V.
 *                  @arg PVD_VREF_SEL_28: Detection reference voltage is 2.8V.
 *                  @arg PVD_VREF_SEL_30: Detection reference voltage is 3.0V.
 *                  @arg PVD_VREF_SEL_32: Detection reference voltage is 3.2V.
 *                  @arg PVD_VREF_SEL_34: Detection reference voltage is 3.4V.
 *                  @arg PVD_VREF_SEL_36: Detection reference voltage is 3.6V.
 *                  @arg PVD_VREF_SEL_38: Detection reference voltage is 3.8V.
 *                  @arg PVD_VREF_SEL_40: Detection reference voltage is 4.0V.
 * @retval  None.
 ******************************************************************************/
void PVD_SetVref(PVD_VrefSelEnum PVD_Vref)
{
  uint32_t tmpReg = 0UL;

  /* Read the value of the PVD control register. */
  tmpReg = PVD->CR;

  /* Clear PVD REF_SEL[3:0] bits. */
  tmpReg &= ~PVD_CR_REF_SEL_Msk;

  /* Set PVD REF_SEL[3:0] bits according to PVD_InitType. */
  tmpReg |= (uint32_t)(PVD_Vref);

  /* Store the new value. */
  PVD->CR = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Initializes the PVD filter according to the specified parameters in the PVD_FiltInitType.
 * @param   [in]  PVD_FiltInitType: Structure pointer of PVD filter configuration.
 * @retval  None.
 ******************************************************************************/
void PVD_FilterInit(PVD_FilterInitTypeStruct* PVD_FiltInitType)
{
  uint32_t tmpReg = 0UL;

  /* Parameters check. */
  PARAM_ASSERT(IS_PVD_FILTER_LEN(PVD_FiltInitType->FiltLen));
  PARAM_ASSERT(IS_PVD_FILTER_SAMPLE(PVD_FiltInitType->FiltSample));
  PARAM_ASSERT(IS_FUNCTION_STATE(PVD_FiltInitType->FiltState));

  /* Read the value of the PVD control register. */
  tmpReg = PVD->CR;

  /* Clear PVD FLT_LEN[1:0],FILT_SAMPLE[1:0],FILT_EN bits. */
  tmpReg &= ~(PVD_CR_FLT_LEN_Msk | PVD_CR_FLT_SAMPLE_Msk | PVD_CR_FLT_EN_Msk);

  /* Set PVD FLT_LEN[1:0] bits according to PVD_FiltInitType. */
  tmpReg |= (uint32_t)(PVD_FiltInitType->FiltLen);

  /* Set PVD FLT_SAMPLE[1:0] bits according to PVD_FiltInitType. */
  tmpReg |= (uint32_t)(PVD_FiltInitType->FiltSample);

  if(DISABLE != PVD_FiltInitType->FiltState)
  {
    /* Enable PVD filter. */
    tmpReg |= PVD_CR_FLT_EN_Msk;
  }

  /* Store the new value. */
  PVD->CR = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Enables or disables the PVD filter.
 * @param   [in]  NewState: This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void PVD_FilterCmd(FunctionalState NewState)
{
  /* Parameters check. */
  PARAM_ASSERT(IS_FUNCTION_STATE(NewState));

  if(DISABLE != NewState)
  {
    /* Enable PVD filter. */
    PVD->CR |= PVD_CR_FLT_EN_Msk;
  }
  else
  {
    /* Disable PVD filter. */
    PVD->CR &= ~PVD_CR_FLT_EN_Msk;
  }
}

/**
 *******************************************************************************
 * @brief   Enables or disables the PVD interrupt.
 * @param   [in]  NewState: This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void PVD_IntCmd(FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable PVD interrupt. */
    PVD->CR |= PVD_CR_IE_Msk;
  }
  else
  {
    /* Disable PVD interrupt. */
    PVD->CR &= ~PVD_CR_IE_Msk;
  }
}

/**
 *******************************************************************************
 * @brief   Get the PVD Interrup enable status.
 * @retval  FunctionalState: PVD Interrup enable status.
 ******************************************************************************/
FunctionalState PVD_GetIntCmdStatus(void)
{
  return (FunctionalState)((PVD->CR & PVD_CR_IE_Msk) ? ENABLE : DISABLE);
}

/**
 *******************************************************************************
 * @brief   Get PVD interrupt status.
 * @retval  FlagState: The new state of PVD interrupt(SET or RESET).
 ******************************************************************************/
FlagState PVD_GetIntFlagStatus(void)
{
  if((PVD->SR & PVD_SR_IF_Msk) != RESET)
  {
    return SET;
  }
  else
  {
    return RESET;
  }
}

/**
 *******************************************************************************
 * @brief   Clear PVD interrupt state.
 * @retval  None.
 ******************************************************************************/
void PVD_ClearIntFlag(void)
{
  /* Soft write 1 to clear interrupt status. */
  PVD->SR = PVD_SR_IF_Msk;
}

/**
 *******************************************************************************
 * @brief   Get PVD start counter ready status.
 * @retval  FlagState: The state of PVD start counter ready status(SET or RESET).
 ******************************************************************************/
FlagState PVD_GetReadyFlagStatus(void)
{
  if((PVD->SR & PVD_SR_RDY_Msk) != RESET)
  {
    return SET;
  }
  else
  {
    return RESET;
  }
}

/**
 *******************************************************************************
 * @brief   Get PVD output of multiplexer status.
 * @retval  FlagState: The state of output multiplexer status(SET or RESET).
 ******************************************************************************/
FlagState PVD_GetResFlagStatus(void)
{
  if((PVD->SR & PVD_SR_RES_Msk) != RESET)
  {
    return SET;
  }
  else
  {
    return RESET;
  }
}
