/**
 *******************************************************************************
 * @file    dpm32m0xx_tim.c
 *
 * @brief   Source file for TIM firmware driver.
 *          This file provides firmware functions to manage the following
 *          functionalities of the TIM peripheral:
 *            + Timer management
 *            + Interrupts, DMA 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_TIMx, ENABLE).

      (#) Program the required configuration through following parameters:
          reload value, counter cycle, interrupt and DMA using the TIM_Init()
          function.

      (#) Enable the NVIC and the corresponding interrupt using the function
         TIM_IntCmd() if you need to use interrupt mode.

      (#) When using the DMA mode.
        (+) Configure the DMA using DMA_Init() function.
        (+) Active the needed channel Request using TIM_DMACmd() function.

      (#) Enable the TIM using the TIM_Cmd() function.

      (#) Modify reload and counter values using TIM_SetAutoReload() and
          TIM_SetCounter() function. Read reload and counter values using
          TIM_GetAutoReload() and TIM_GetCounter();

      (#) TIM interrupt configuration:
        (+) To activate the TIM interrupt, using TIM_IntCmd() functions.
        (+) Check on TIM interrupt occur flags using the function
            TIM_GetIntFlagStatus().
        (+) Clear TIM interrupt flags using the function TIM_ClearIntFlag().

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

#include "dpm32m0xx_tim.h"


/**
 *******************************************************************************
 * @brief   Deinitializes the TIMx peripheral registers to their default reset values.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @retval  None.
 ******************************************************************************/
void TIM_DeInit(TIM_Type* TIMx)
{
  /* Reset TIMx control register. */
  TIMx->CR = (uint32_t)0x00000000;

  /* Reset TIMx auto reload register. */
  TIMx->ARR = (uint32_t)0x00000000;

  /* Clear TIMx interrupt flag. */
  TIMx->SR = TIM_SR_IF_Msk;
}

/**
 *******************************************************************************
 * @brief   Initializes the TIMx peripheral according to the specified parameters
 *          in the TIM_InitType.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @param   [in]  TIM_InitType: Structure pointer of TIMx configuration.
 * @retval  None.
 ******************************************************************************/
void TIM_Init(TIM_Type* TIMx, TIM_InitTypeStruct* TIM_InitType)
{
  uint32_t tmpReg = 0UL;

  /* Parameters check. */
  PARAM_ASSERT(IS_TIM_PERIPH(TIMx));
  PARAM_ASSERT(IS_TIM_COUNTER_MODE(TIM_InitType->TIM_CounterCycle));
#if defined (DPM32M08x) || defined (DPM32M05x)
  PARAM_ASSERT(IS_FUNCTION_STATE(TIM_InitType->TIM_DMAState));
#endif /* DPM32M08x || DPM32M05x */
  PARAM_ASSERT(IS_FUNCTION_STATE(TIM_InitType->TIM_IntState));

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

#if defined (DPM32M08x) || defined (DPM32M05x)
  /* Clear TIMx MODE,IE,DE bit. */
  tmpReg &= ~(TIM_CR_SINGLE_Msk | TIM_CR_IE_Msk | TIM_CR_DE_Msk);
#else
  /* Clear TIMx MODE,IE,DE bit. */
  tmpReg &= ~(TIM_CR_SINGLE_Msk | TIM_CR_IE_Msk);
#endif /* DPM32M08x || DPM32M05x */

  /* Set TIMx mode bit according to TIM_InitType. */
  tmpReg |= (uint32_t)(TIM_InitType->TIM_CounterCycle);

  if(DISABLE != TIM_InitType->TIM_IntState)
  {
    /* Enable TIMx interrupt. */
    tmpReg |= TIM_CR_IE_Msk;
  }

#if defined (DPM32M08x) || defined (DPM32M05x)

  if(DISABLE != TIM_InitType->TIM_DMAState)
  {
    /* Enable TIMx interrupt. */
    tmpReg |= TIM_CR_DE_Msk;
  }

#endif /* DPM32M08x || DPM32M05x */

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

  /* Sets the TIMx auto reload register value. */
  TIMx->ARR = TIM_InitType->TIM_ReloadValue;
}

/**
 *******************************************************************************
 * @brief   Initialize the TIM_InitType with default parameters.
 * @param   [in]  TIM_InitType Pointer to a TIM_InitTypeStruct structure
 *                which will be initialized.
 * @retval  None.
 ******************************************************************************/
void TIM_StructInit(TIM_InitTypeStruct* TIM_InitType)
{
  TIM_InitType->TIM_ReloadValue = 0xFFFFFFFF;
  TIM_InitType->TIM_CounterCycle = TIM_COUNTER_CYCLE_PERIOD;
#if defined (DPM32M08x) || defined (DPM32M05x)
  TIM_InitType->TIM_DMAState = DISABLE;
#endif /* DPM32M08x || DPM32M05x */
  TIM_InitType->TIM_IntState = DISABLE;
}

/**
 *******************************************************************************
 * @brief   Enables or disables the specified TIM peripheral.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @param   [in]  NewState: This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void TIM_Cmd(TIM_Type* TIMx, FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable TIMx. */
    TIMx->CR |= TIM_CR_EN_Msk;
  }
  else
  {
    /* Disable TIMx. */
    TIMx->CR &= ~TIM_CR_EN_Msk;
  }
}

/**
 *******************************************************************************
 * @brief   Configuration the TIMx counter cycle.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @param   [in]  TIM_Cycle: Specifies TIMx counter cycle.
 * @retval  None.
 ******************************************************************************/
void TIM_CounterCycleConfig(TIM_Type* TIMx, TIM_CounterCycleEnum TIM_Cycle)
{
  uint32_t tmpReg = 0UL;

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

  /* Clear TIMx mode bit. */
  tmpReg &= ~TIM_CR_SINGLE_Msk;

  /* Set TIMx new counter cycle value. */
  tmpReg |= (uint32_t)(TIM_Cycle);

  TIMx->CR = tmpReg;
}

#if defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015)
/**
 *******************************************************************************
 * @brief   Configuration the TIMx trigger type.
 * @param   [in]  TIMx: Where x can be (0, 1, 2) to select the TIM peripheral.
 * @param   [in]  TIM_TriggerType: Specifies TIMx trigger type.
 * @retval  None.
 ******************************************************************************/
void TIM_TriggerTypeConfig(TIM_Type* TIMx, TIM_TriggerTypeEnum TIM_TriggerType)
{
  uint32_t tmpReg = 0UL;

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

  /* Clear TIMx trigger type bit. */
  tmpReg &= ~TIM_CR_TRIG_TYPE_Msk;

  /* Set TIMx new trigger type value. */
  tmpReg |= (uint32_t)(TIM_TriggerType);

  TIMx->CR = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Configuration the TIMx trigger source.
 * @param   [in]  TIMx: Where x can be (0, 1, 2) to select the TIM peripheral.
 * @param   [in]  TIM_TriggerType: Specifies TIMx trigger source.
 * @retval  None.
 ******************************************************************************/
void TIM_TriggerSourceConfig(TIM_Type* TIMx, TIM_TriggerSourceEnum TIM_TriggerSource)
{
  uint32_t tmpReg = 0UL;

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

  /* Clear TIMx trigger source bit. */
  tmpReg &= ~TIM_CR_TRIG_SRC_Msk;

  /* Set TIMx new trigger source value. */
  tmpReg |= (uint32_t)(TIM_TriggerSource);

  TIMx->CR = tmpReg;
}

/**
 *******************************************************************************
 * @brief   Gets the TIMx busy register status.
 * @param   [in]  TIMx: Where x can be (0, 1, 2) to select the TIM peripheral.
 * @retval  FlagState: The new busy status of TIMx(SET or RESET).
 ******************************************************************************/
FlagState TIM_GetBusy(TIM_Type* TIMx)
{
  if((TIMx->SR & TIM_SR_BUSY_Msk) != RESET)
  {
    return SET;
  }
  else
  {
    return RESET;
  }
}
#endif /* DPM32M036 || DPM32M030 || DPM32M015 */

/**
 *******************************************************************************
 * @brief   Sets the TIMx auto reload register value.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @param   [in]  TIM_Value: Specifies the auto reload register new value.
 * @retval  None.
 ******************************************************************************/
void TIM_SetAutoReload(TIM_Type* TIMx, uint32_t TIM_Value)
{
  /* Set the auto reload register value. */
  TIMx->ARR = TIM_Value;
}

/**
 *******************************************************************************
 * @brief   Gets the TIMx auto reload register value.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @retval  uint32_t: Auto reload register value.
 ******************************************************************************/
uint32_t TIM_GetAutoReload(TIM_Type* TIMx)
{
  /* Get the auto reload register value. */
  return TIMx->ARR;
}

/**
 *******************************************************************************
 * @brief   Sets the TIMx counter register value.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @param   [in]  TIM_Value: Specifies the counter register new value.
 * @retval  None.
 ******************************************************************************/
void TIM_SetCounter(TIM_Type* TIMx, uint32_t TIM_Value)
{
  /* Set the counter register value. */
  TIMx->CNT = TIM_Value;
}

/**
 *******************************************************************************
 * @brief   Gets the TIMx Counter value.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @retval  uint32_t: Counter register value.
 ******************************************************************************/
uint32_t TIM_GetCounter(TIM_Type* TIMx)
{
  /* Get the Counter register value. */
  return TIMx->CNT;
}

#if defined (DPM32M08x) || defined (DPM32M05x)
/**
 *******************************************************************************
 * @brief   Enable or disable the specifies TIMx DMA function.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @param   [in]  NewState: This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void TIM_DMACmd(TIM_Type* TIMx, FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable TIMx interrupt functions. */
    TIMx->CR |= TIM_CR_DE_Msk;
  }
  else
  {
    /* Disable TIMx DMA functions. */
    TIMx->CR &= ~TIM_CR_DE_Msk;
  }
}

#endif  /* DPM32M08x || DPM32M05x */

/**
 *******************************************************************************
 * @brief   Enable or disable the specifies TIMx interrupt.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @param   [in]  NewState: This parameter can be: ENABLE or DISABLE.
 * @retval  None.
 ******************************************************************************/
void TIM_IntCmd(TIM_Type* TIMx, FunctionalState NewState)
{
  if(DISABLE != NewState)
  {
    /* Enable TIMx interrupt. */
    TIMx->CR |= TIM_CR_IE_Msk;
  }
  else
  {
    /* Disable TIMx interrupt. */
    TIMx->CR &= ~TIM_CR_IE_Msk;
  }
}

/**
 *******************************************************************************
 * @brief   Get specifies TIM interrupt enable status.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @retval  FunctionalState: The TIM interrupt state(ENABLE or DISABLE).
 ******************************************************************************/
FunctionalState TIM_GetIntCmdStatus(TIM_Type* TIMx)
{
  /* Return the status of the interrupt enable bit. */
  return (FunctionalState)((TIMx->CR & (TIM_CR_IE_Msk))
                           ? ENABLE : DISABLE);
}

/**
 *******************************************************************************
 * @brief   Get the specified TIMx interrupt status.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @retval  FlagState: The new state of TIMx interrupt(SET or RESET).
 ******************************************************************************/
FlagState TIM_GetIntFlagStatus(TIM_Type* TIMx)
{
  if((TIMx->SR & TIM_SR_IF_Msk) != RESET)
  {
    return SET;
  }
  else
  {
    return RESET;
  }
}

/**
 *******************************************************************************
 * @brief   Clear the specified TIMx interrupt state.
 * @param   [in]  TIMx: Where x can be (0, 1, 2, 3, 4, 5) to select the TIM peripheral.
 * @retval  None.
 ******************************************************************************/
void TIM_ClearIntFlag(TIM_Type* TIMx)
{
  /* Soft write 1 to clear interrupt status. */
  TIMx->SR = TIM_SR_IF_Msk;
}
