/**
 *******************************************************************************
 * @file    dpm32m0xx_i2c.c
 *
 * @brief   This file provides firmware functions to manage the following
 *          functionalities of the Inter-integrated circuit (I2C)
 *           + Initialization and Configuration
 *           + Data transfers functions
 *           + DMA transfers management
 *           + Interrupts, events 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(I2C, ENABLE).

      (#) Enable SDA and SCL GPIO clocks using
          RCC_AHBPeriphClockCmd(RCC_AHB_PERIPH_GPIO, ENABLE) function.

      (#) Peripheral's alternate function:
        (+) Connect the pin to the desired peripherals' Alternate
            Function (AF) using GPIO_AltFuncConfig() function.
        (+) Configure the desired pin in alternate function by:
            GPIO_InitStruct->GPIO_Mode = GPIO_MODE_ALT_FUNC.
        (+) Select the type, pull-up/pull-down and output speed via
            GPIO_PuPd, GPIO_OType and GPIO_Speed members.
        (+) Call GPIO_Init() function.

      (#) Program the Timing, prescaler, digital filter, mode, own address,
          address mode, stretch and general call using the I2C_Init() function.

      (#) Enable the NVIC and the corresponding interrupt using the function
          I2C_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 I2C_DMACmd() function.

      (#) Enable the I2C using the I2C_Cmd() function.

      (#) Enable the DMA using the DMA_Cmd() function when using DMA mode in the
          transfers.

      (#) Data transfers using the I2C_SendData() and I2C_ReceiveData() function.

      (#) I2C interrupt configuration:
        (+) To activate the I2C interrupt, using I2C_IntCmd() functions.
        (+) Check on I2C interrupt enable flags using the function
            I2C_GetIntCmdStatus().
        (+) Check on I2C interrupt occur flags using the function
            I2C_GetIntFlagStatus().
        (+) Clear I2C interrupt flags using the function I2C_ClearIntFlag().

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

#include "dpm32m0xx_i2c.h"



/**
 *******************************************************************************
 * @brief  De-initialize the I2C peripheral registers to their default reset values.
 * @retval None.
 ******************************************************************************/
void I2C_DeInit(void)
{
  /* Reset I2C CR1 register. */
  I2C->CR1 = (uint32_t)0xB0000000;
  /* Reset I2C CR2 register. */
  I2C->CR2 = (uint32_t)0x00000000;

  /* Reset I2C TIMING register. */
  I2C->TIMING = (uint32_t)0x00420F13;
  /* Reset I2C OAR register. */
  I2C->OAR = (uint32_t)0x00000000;
}

/**
 *******************************************************************************
 * @brief  Initializes the I2C peripheral according to the specified
 *         parameters in the I2C_InitType.
 * @param  [in]  I2C_InitType: Pointer to a I2C_InitTypeStruct structure that
 *               contains the configuration information for the specified I2C peripheral.
 * @retval None.
 ******************************************************************************/
void I2C_Init(I2C_InitTypeStruct *I2C_InitType)
{
  uint32_t tmpReg = 0UL;

  /* Check the parameters */
  PARAM_ASSERT(IS_I2C_MODE(I2C_InitType->I2C_Mode));
  PARAM_ASSERT(IS_I2C_ADDRESSING_MODE(I2C_InitType->I2C_AddressingMode));
  PARAM_ASSERT(IS_I2C_DIGITALFILTER_VAL(I2C_InitType->I2C_DigitalFilter));
  PARAM_ASSERT(IS_I2C_GENERALCALL_MODE(I2C_InitType->I2C_GeneralCallMode));
  PARAM_ASSERT(IS_I2C_NOSTRETCH_MODE(I2C_InitType->I2C_NoStretchMode));
  PARAM_ASSERT(IS_I2C_OWNADDRESS_VAL(I2C_InitType->I2C_OwnAddress));
  PARAM_ASSERT(IS_I2C_PRESCALER_VAL(I2C_InitType->I2C_Prescaler));
  PARAM_ASSERT(IS_I2C_TIMING_VAL(I2C_InitType->I2C_Timing));

  /*---------------------------- I2C CR1 Configuration ------------------------*/
  /* Get the I2C CR1 value */
  tmpReg = I2C->CR1;

  /* Clear MS bits. */
  tmpReg &= ~(I2C_CR1_MS_Msk | I2C_CR1_NO_STRETCH_Msk | I2C_CR1_GC_EN_Msk \
              | I2C_CR1_DNF_Msk | I2C_CR1_PRESC_Msk | I2C_CR1_NOADDR_Msk);
  /* Set MS bits according to I2C_Mode. */
  tmpReg |= (((uint32_t)I2C_InitType->I2C_Mode) << I2C_CR1_MS_Pos);

  /* Set NO_STRETCH bits according to I2C_NoStretchMode. */
  tmpReg |= (((uint32_t)I2C_InitType->I2C_NoStretchMode) << I2C_CR1_NO_STRETCH_Pos);

  /* Set GC_EN bits according to I2C_GeneralCallMode. */
  tmpReg |= (((uint32_t)I2C_InitType->I2C_GeneralCallMode) << I2C_CR1_GC_EN_Pos);

  /* Set DNF[3:0] bits according to I2C_DigitalFilter. */
  tmpReg |= (((uint32_t)I2C_InitType->I2C_DigitalFilter) << I2C_CR1_DNF_Pos);

  /* Set PRESC[4:0] bits according to I2C_Prescaler. */
  tmpReg |= (((uint32_t)I2C_InitType->I2C_Prescaler) << I2C_CR1_PRESC_Pos);

  if(I2C_InitType->I2C_AddressingMode == I2C_ADDRESSING_MODE_NO_ADDR)
  {
    /* Set the NOADDR_FIL bit to 1. */
    tmpReg |= I2C_CR1_NOADDR_Msk;
  }
  else
  {
    /* Set the NOADDR_FIL bit to 0. */
    tmpReg &= ~I2C_CR1_NOADDR_Msk;
  }

  /* Write to I2C CR1 */
  I2C->CR1 = tmpReg;

  /*---------------------------- I2C TIMING Configuration ------------------------*/

  /* Clear SCLDEL_I[2:0], SDADEL_I[2:0], SCLDEL_O[3:0], SDADEL_O[3:0], SCLH[7:0] and SCLL[7:0] bits. */
  I2C->TIMING &= ~(I2C_TIMING_SCLDEL_I_Msk | I2C_TIMING_SDADEL_I_Msk | I2C_TIMING_SCLDEL_O_Msk | \
                   I2C_TIMING_SDADEL_O_Msk | I2C_TIMING_SCLH_Msk | I2C_TIMING_SCLL_Msk);
  /* Set SCLDEL_I[2:0], SDADEL_I[2:0], SCLDEL_O[3:0], SDADEL_O[3:0], SCLH[7:0] and SCLL[7:0] bits
     according to I2C_Timing. */
  I2C->TIMING = ((uint32_t)I2C_InitType->I2C_Timing);

  if(I2C_InitType->I2C_AddressingMode != I2C_ADDRESSING_MODE_NO_ADDR)
  {
    /*---------------------------- I2C CR2 Configuration ------------------------*/
    /* Get the I2C CR2 value */
    tmpReg = I2C->CR2;

    /* Clear ADDR10 bits. */
    tmpReg &= ~I2C_CR2_ADDR10_Msk;
    /* Set ADDR10 bits according to I2C_AddressingMode. */
    tmpReg |= (((uint32_t)I2C_InitType->I2C_AddressingMode) << I2C_CR2_ADDR10_Pos);

    /* Write to I2C CR2 */
    I2C->CR2 = tmpReg;

    /*---------------------------- I2C OAR Configuration ------------------------*/
    /* Get the I2C OAR value */
    tmpReg = I2C->OAR;

    /* Clear OWN_ADDR10,OWN_ADDR[9:0] bits. */
    tmpReg &= ~(I2C_OAR_OWN_ADDR10_Msk | I2C_OAR_OWN_ADDR_Msk);

    /* Set OWN_ADDR10 bits according to I2C_AddressingMode. */
    tmpReg |= (((uint32_t)I2C_InitType->I2C_AddressingMode) << I2C_OAR_OWN_ADDR10_Pos);

    /* Set OWN_ADDR[9:0] bits according to I2C_OwnAddress. */
    tmpReg |= (((uint32_t)I2C_InitType->I2C_OwnAddress) << I2C_OAR_OWN_ADDR_Pos);

    /* Write to I2C OAR */
    I2C->OAR = tmpReg;
  }
}

/**
 *******************************************************************************
 * @brief  Fills each I2C_InitType member with its default value.
 * @param  [out] I2C_InitType: Pointer to a I2C_InitTypeStruct structure
 *               which will be initialized.
 * @retval None.
 ******************************************************************************/
void I2C_StructInit(I2C_InitTypeStruct *I2C_InitType)
{
  /*---------------- Reset I2C init structure parameters values --------------*/
  /* Initialize the I2C_Mode member */
  I2C_InitType->I2C_Mode = I2C_MODE_MASTER;
  /* Initialize the I2C_AddressingMode member */
  I2C_InitType->I2C_AddressingMode = I2C_ADDRESSING_MODE_7BIT;
  /* Initialize the I2C_DigitalFilter member */
  I2C_InitType->I2C_DigitalFilter = 0;
  /* Initialize the I2C_GeneralCallMode member */
  I2C_InitType->I2C_GeneralCallMode = I2C_GENERALCALL_MODE_DISABLE;
  /* Initialize the I2C_NoStretchMode member */
  I2C_InitType->I2C_NoStretchMode = I2C_NOSTRETCH_MODE_DISABLE;
  /* Initialize the I2C_OwnAddress member */
  I2C_InitType->I2C_OwnAddress = 0;
  /* Initialize the I2C_Prescaler member */
  I2C_InitType->I2C_Prescaler = 0x16;
  /* Initialize the I2C_Timing member */
  I2C_InitType->I2C_Timing = 0x00420F13;
}

/**
 *******************************************************************************
 * @brief  Enables or disables the specified I2C peripheral.
 * @param  [in]  State: new state of the I2C peripheral.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disbale I2C peripheral.
 *                 @arg ENABLE: enable I2C peripheral.
 * @retval None.
 ******************************************************************************/
void I2C_Cmd(FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable the selected I2C peripheral */
    I2C->CR1 |= I2C_CR1_EN_Msk;
  }
  else
  {
    /* Disable the selected I2C peripheral */
    I2C->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_EN_Msk);
  }
}

/**
 *******************************************************************************
 * @brief  I2C software reset.
 * @retval None.
 ******************************************************************************/
void I2C_SoftwareResetCmd(void)
{
  /* Disable peripheral */
  I2C->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_EN_Msk);

  /* Perform a dummy read to delay the disable of peripheral for minimum
     3 APB clock cycles to perform the software reset functionality */
  *(__IO uint32_t *)(uint32_t)I2C;

  /* Enable peripheral */
  I2C->CR1 |= I2C_CR1_EN_Msk;
}

/**
 *******************************************************************************
 * @brief  Enables or disables the I2C Clock stretching.
 * @note   Used to disable clock stretching in slave mode, must remain cleared
 *         in master mode.
 * @param  [in]  State: new state of the I2C peripheral.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disbale Clock stretching.
 *                 @arg ENABLE: enable Clock stretching.
 * @retval None.
 ******************************************************************************/
void I2C_StretchClockCmd(FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable clock stretching */
    I2C->CR1 |= I2C_CR1_NO_STRETCH_Msk;
  }
  else
  {
    /* Disable clock stretching  */
    I2C->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_NO_STRETCH_Msk);
  }
}

/**
 *******************************************************************************
 * @brief  Enables or disables the I2C general call mode.
 * @param  [in]  State: new state of the I2C peripheral.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disbale general call mode.
 *                 @arg ENABLE: enable general call mode.
 * @retval None.
 ******************************************************************************/
void I2C_GeneralCallCmd(FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable general call mode */
    I2C->CR1 |= I2C_CR1_GC_EN_Msk;
  }
  else
  {
    /* Disable general call mode */
    I2C->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_GC_EN_Msk);
  }
}

/**
 *******************************************************************************
 * @brief  Enables or disables the I2C no addressiong mode.
 * @note   It is used to start data communication of non-self address in slave mode.
 * @param  [in]  State: new state of the I2C peripheral.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disbale no addressiong mode.
 *                 @arg ENABLE: enable no addressiong mode.
 * @retval None.
 ******************************************************************************/
void I2C_NoAddressingModeCmd(FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable no addressing mode */
    I2C->CR1 |= I2C_CR1_NOADDR_Msk;
  }
  else
  {
    /* Disable no addressing mode */
    I2C->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_NOADDR_Msk);
  }
}

/**
 *******************************************************************************
 * @brief  Enables or disables the I2C 10-bit addressiong mode.
 * @param  [in]  State: new state of the I2C peripheral.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disbale 10-bit addressiong mode.
 *                 @arg ENABLE: enable 10-bit addressiong mode.
 * @retval None.
 ******************************************************************************/
void I2C_10BitAddressingModeCmd(FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable target address 10-bit address mode */
    I2C->CR2 |= I2C_CR2_ADDR10_Msk;
    /* Enable own address 10-bit address mode */
    I2C->OAR |= I2C_OAR_OWN_ADDR10_Msk;
  }
  else
  {
    /* Disable target address 10-bit address mode */
    I2C->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_ADDR10_Msk);
    /* Disable own address 10-bit address mode */
    I2C->OAR &= (uint32_t)~((uint32_t)I2C_OAR_OWN_ADDR10_Msk);
  }
}

/**
 *******************************************************************************
 * @brief  Enable or disable multi-master mode address president failure I2C switch to slave.
 * @note   It is used to switch to the slave function when the I2C address president
 *         fails in multi-master mode.
 * @param  [in]  State: new state of the I2C peripheral.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disbale I2C switch to slave.
 *                 @arg ENABLE: enable I2C switch to slave.
 * @retval None.
 ******************************************************************************/
void I2C_SwitchSlaveCmd(FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable switch slave mode.*/
    I2C->CR1 |= I2C_CR1_DIS_SLAVE_Msk;
  }
  else
  {
    /* Disable switch slave mode. */
    I2C->CR1 &= (uint32_t)~((uint32_t)I2C_CR1_DIS_SLAVE_Msk);
  }
}

/**
 *******************************************************************************
 * @brief  Timeout interrupt threshold configuration in I2C slave mode.
 * @note   It is used to detect SCL counting at high level and SDA low level.
 * @param  [in]  Timeout: timeout register configuration values for I2C Peripherals.
 *               Any value of @ref 0x00~0x07.
 *                 @arg 0x00: Disable SDA timeout interrupt.
 *                 @arg 0x01: Enable SDA timeout interrupt, the timeout
 *                            threshold is (2^0 x 2^12) Tpclk.
 *                 @arg 0x02: Enable SDA timeout interrupt, the timeout
 *                            threshold is (2^2 x 2^12) Tpclk.
 *                 @arg 0x03: Enable SDA timeout interrupt, the timeout
 *                            threshold is (2^4 x 2^12) Tpclk.
 *                 @arg 0x04: Enable SDA timeout interrupt, the timeout
 *                            threshold is (2^6 x 2^12) Tpclk.
 *                 @arg 0x05: Enable SDA timeout interrupt, the timeout
 *                            threshold is (2^8 x 2^12) Tpclk.
 *                 @arg 0x06: Disable SDA timeout interrupt.
 *                 @arg 0x07: Disable SDA timeout interrupt.
 * @retval None.
 ******************************************************************************/
void I2C_SlaveTimeoutConfig(uint8_t Timeout)
{
  uint32_t tmpReg = 0UL;

  /* Get the old register value */
  tmpReg = I2C->CR1;

  /* Reset I2C TIMEOUT_SEL bit [2:0] */
  tmpReg &= (uint32_t)~((uint32_t)I2C_CR1_TIMEOUT_SEL_Msk);

  /* Set I2C TIMEOUT_SEL */
  tmpReg |= (((uint32_t)Timeout) << I2C_CR1_TIMEOUT_SEL_Pos);

  /* Store the new register value */
  I2C->CR1 = tmpReg;
}

/**
 *******************************************************************************
 * @brief  Enable or disable I2C master mode continuous read operation.
 * @param  [in]  State: new state of the I2C peripheral.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disbale continuous reading of data.
 *                 @arg ENABLE: enable continuous reading of data.
 * @retval None.
 ******************************************************************************/
void I2C_ReloadCmd(FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable reload mode */
    I2C->CR2 |= I2C_CR2_RELOAD_Msk;
  }
  else
  {
    /* Disable reload mode  */
    I2C->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_RELOAD_Msk);
  }
}

/**
 *******************************************************************************
 * @brief  I2C Master Mode Read Data Configuration Read Data Bytes.
 * @note   It is used to read the data byte count, and the M_RXC interrupt status
 *         will be generated after reaching the count value.
 * @param  [in]  Bytes: the number of bytes that I2C needs to read.
 *               Any value of @ref 0x00~0xFF.
 * @retval None.
 ******************************************************************************/
void I2C_NumberOfBytesConfig(uint8_t Bytes)
{
  uint32_t tmpReg = 0UL;

  /* Get the old register value */
  tmpReg = I2C->CR2;

  /* Reset I2C BYTES_NUM bit [7:0] */
  tmpReg &= (uint32_t)~((uint32_t)I2C_CR2_BYTES_NUM_Msk);

  /* Set I2C BYTES_NUM */
  tmpReg |= (((uint32_t)Bytes) << I2C_CR2_BYTES_NUM_Pos);

  /* Store the new register value */
  I2C->CR2 = tmpReg;
}

/**
 *******************************************************************************
 * @brief  Clear I2C transmit data buffer register.
 * @note   It is used to clear the I2C_TDR register data, write 1 by software,
 *         and clear it by hardware.
 * @retval None.
 ******************************************************************************/
void I2C_ClearTxBuffer(void)
{
  /* Clear I2C_TDR */
  I2C->CR2 |= I2C_CR2_TXE_SET_Msk;
}

/**
 *******************************************************************************
 * @brief  I2C slave mode NACK response enable.
 * @note   It is used to generate a negative response to the received address or
 *         communication data in the slave mode. It is set to 1 by software,
 *         and the negative response is cleared by hardware.
 * @retval None.
 ******************************************************************************/
void I2C_NackConf(void)
{
  /* Enable NACK */
  I2C->CR2 |= I2C_CR2_NACK_Msk;
}

/**
 *******************************************************************************
 * @brief  Configures the slave address to be transmitted after start generation.
 * @note   This function should be called before generating start condition.
 * @param  [in]  Address: specifies the slave address to be programmed.
 *                        Any value of @ref 0x00~0x03FF.
 * @retval None.
 ******************************************************************************/
void I2C_TargetAddressConfig(uint16_t Address)
{
  uint32_t tmpReg = 0UL;

  /* Get the old register value */
  tmpReg = I2C->CR2;

  /* Reset I2C SADDR bit [9:0] */
  tmpReg &= (uint32_t)~((uint32_t)I2C_CR2_SADDR_Msk);

  /* Set I2C SADDR */
  tmpReg |= (((uint32_t)Address) << I2C_CR2_SADDR_Pos);

  /* Store the new register value */
  I2C->CR2 = tmpReg;
}

/**
 *******************************************************************************
 * @brief  Configures the type of transfer request for the master.
 * @param  [in]  I2C_Direction: specifies the transfer request direction to be programmed.
 *               Any value of @ref I2C_DirectionEnum.
 *                 @arg I2C_DIRECTION_TRANSMITTER: master request a write transfer.
 *                 @arg I2C_DIRECTION_RECEIVER: master request a read transfer
 * @retval None.
 ******************************************************************************/
void I2C_TransferDirectionConfig(I2C_DirectionEnum I2C_Direction)
{
  uint32_t tmpReg = 0UL;

  /* Get the old register value */
  tmpReg = I2C->CR2;

  /* Reset I2C WR bit */
  tmpReg &= (uint32_t)~((uint32_t)I2C_CR2_WR_Msk);

  /* Set I2C WR */
  tmpReg |= (((uint32_t)I2C_Direction) << I2C_CR2_WR_Pos);

  /* Store the new register value */
  I2C->CR2 = tmpReg;
}

/**
 *******************************************************************************
 * @brief  Generates I2C communication START condition.
 * @retval None.
 ******************************************************************************/
void I2C_GenerateSTART(void)
{
  /* Clear START_STOP[1:0] bits. */
  I2C->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_START_STOP_Msk);

  /* Generates I2C communication START condition. */
  I2C->CR2 |= (((uint32_t)0x01) << I2C_CR2_START_STOP_Pos);
}

/**
 *******************************************************************************
 * @brief  Generates I2C communication STOP condition.
 * @retval None.
 ******************************************************************************/
void I2C_GenerateSTOP(void)
{
  /* Clear START_STOP[1:0] bits. */
  I2C->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_START_STOP_Msk);

  /* Generates I2C communication STOP condition. */
  I2C->CR2 |= (((uint32_t)0x02) << I2C_CR2_START_STOP_Pos);
}

/**
 *******************************************************************************
 * @brief  Generates I2C communication RESTART condition.
 * @retval None.
 ******************************************************************************/
void I2C_GenerateRESTART(void)
{
  /* Clear START_STOP[1:0] bits. */
  I2C->CR2 &= (uint32_t)~((uint32_t)I2C_CR2_START_STOP_Msk);

  /* Generates I2C communication RESTART condition. */
  I2C->CR2 |= (((uint32_t)0x03) << I2C_CR2_START_STOP_Pos);
}

/**
 *******************************************************************************
 * @brief  Returns the I2C slave received request.
 * @retval I2C_DirectionEnum: The counter value.
 *                Any value of @ref I2C_DirectionEnum.
 *                  @arg I2C_DIRECTION_TRANSMITTER: master request a write transfer.
 *                  @arg I2C_DIRECTION_RECEIVER: master request a read transfer
 ******************************************************************************/
I2C_DirectionEnum I2C_GetTransferDirection(void)
{
  I2C_DirectionEnum direction = I2C_DIRECTION_TRANSMITTER;

  /* If write transfer is requested */
  if((I2C->ISR & I2C_ISR_DIR_Msk) != RESET)
  {
    /* write transfer is requested */
    direction = I2C_DIRECTION_RECEIVER;
  }
  else
  {
    /* Read transfer is requested */
    direction = I2C_DIRECTION_TRANSMITTER;
  }

  /* Returns the I2C transfer direction */
  return direction;
}

/**
 *******************************************************************************
 * @brief  Configure the transfer request type in slave mode.
 * @note   It is used to manually configure the transfer direction in slave mode without address.
 * @param  [in]  I2C_Direction: specifies the transfer request direction to be programmed.
 *               Any value of @ref I2C_DirectionEnum.
 *                 @arg I2C_DIRECTION_TRANSMITTER: transfer request.
 *                 @arg I2C_DIRECTION_RECEIVER: receiver request
 * @retval None.
 ******************************************************************************/
void I2C_SlaveTransferDirectionConfig(I2C_DirectionEnum I2C_Direction)
{
  if(I2C_Direction != I2C_DIRECTION_RECEIVER)
  {
    I2C->ISR |= I2C_ISR_DIR_Msk;
  }
  else
  {
    I2C->ISR &= (uint32_t)~I2C_ISR_DIR_Msk;
  }
}

/**
 *******************************************************************************
 * @brief  Reads the specified I2C register and returns its value.
 * @param  [in]  I2C_Register: I2C_Register: specifies the register to read.
 *               Any value of @ref I2C_RegisterEnum.
 *                 @arg I2C_REGISTER_CR1: CR1 register.
 *                 @arg I2C_REGISTER_CR2: CR2 register.
 *                 @arg I2C_REGISTER_ISR: ISR register.
 *                 @arg I2C_REGISTER_TIMING: TIMING register.
 *                 @arg I2C_REGISTER_OAR: OAR register.
 *                 @arg I2C_REGISTER_TDR: TDR register.
 *                 @arg I2C_REGISTER_RDR: RDR register.
 * @retval None.
 ******************************************************************************/
uint32_t I2C_ReadRegister(I2C_RegisterEnum I2C_Register)
{
  __IO uint32_t tmp = 0;

  tmp = (uint32_t)I2C;
  tmp += I2C_Register;

  /* Return the selected register value */
  return (*(__IO uint32_t *) tmp);
}

/**
 *******************************************************************************
 * @brief  Sends a data byte through the I2C peripheral.
 * @param  [in]  Data: Byte to be transmitted.
 * @retval None.
 ******************************************************************************/
void I2C_SendData(uint8_t Data)
{
  /* Write in the TDR register the data to be sent */
  I2C->TDR = (uint8_t)Data;
}

/**
 *******************************************************************************
 * @brief  Returns the most recent received data by the I2C peripheral.
 * @retval uint8_t: The value of the received data.
 ******************************************************************************/
uint8_t I2C_ReceiveData(void)
{
  /* Return the data in the RDR register */
  return (uint8_t)I2C->RDR;
}

#if defined (DPM32M08x) || defined (DPM32M05x)
/**
 *******************************************************************************
 * @brief  Enables or disables the I2C DMA interface.
 * @param  [in]  I2C_DMAReq: specifies the I2C DMA transfer request to be enabled or disabled.
 *               Any value of @ref I2C_RegisterEnum.
 *                 @arg I2C_DMA_REQ_TX: tx buffer DMA transfer request.
 *                 @arg I2C_DMA_REQ_RX: rx buffer DMA transfer request.
 * @param  [in]  State: new state of the selected I2C DMA transfer request.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disable DMA transfer request.
 *                 @arg ENABLE: enable DMA transfer request.
 * @retval None.
 ******************************************************************************/
void I2C_DMACmd(I2C_DMAReqEnum I2C_DMAReq, FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable the selected I2C DMA requests */
    I2C->CR1 |= I2C_DMAReq;
  }
  else
  {
    /* Disable the selected I2C DMA requests */
    I2C->CR1 &= (uint32_t)~I2C_DMAReq;
  }
}

#endif /* DPM32M08x || DPM32M05x */

/**
 *******************************************************************************
 * @brief  Enables or disables the specified I2C interrupts.
 * @param  [in]  I2C_IntType: specifies the I2C interrupts sources to be enabled or disabled.
 *               Any value of @ref I2C_IntTypeEnum.
 *                 @arg I2C_INT_TYPE_START: start detection Interrupt.
 *                 @arg I2C_INT_TYPE_ERR: communication error Interrupt.
 *                 @arg I2C_INT_TYPE_M_RXC: I2C Master Read Complete Interrupt.
 *                 @arg I2C_INT_TYPE_GC: general call Interrupt.
 *                 @arg I2C_INT_TYPE_RX_NACK: not acknowledge received Interrupt.
 *                 @arg I2C_INT_TYPE_RX_STOP: stop detection Interrupt.
 *                 @arg I2C_INT_TYPE_ADDRM: address match Interrupt.
 *                 @arg I2C_INT_TYPE_RXNE: receive Buffer Not Empty Interrupt.
 *                 @arg I2C_INT_TYPE_TXE: transfer Buffer Empty Interrupt.
 *                 @arg I2C_INT_TYPE_M_TXC: I2C Master Write Complete Interrupt.
 * @param  [in]  state: new state of the specified I2C interrupts.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: disbale I2C interrupt.
 *                 @arg ENABLE: enable I2C interrupt.
 * @retval None.
 ******************************************************************************/
void I2C_IntCmd(I2C_IntTypeEnum I2C_IntType, FunctionalState State)
{
  if(State != DISABLE)
  {
    /* Enable the selected I2C interrupts */
    I2C->CR1 |= I2C_IntType;
  }
  else
  {
    /* Disable the selected I2C interrupts */
    I2C->CR1 &= (uint32_t)~I2C_IntType;
  }
}

/**
 *******************************************************************************
 * @brief  Get the specified I2C interrupt has enable or not.
 * @param  [in]  I2C_IntType: specifies the I2C interrupt source to get enabled status.
 *               Any value of @ref I2C_IntTypeEnum.
 *                 @arg I2C_INT_TYPE_START: start detection Interrupt.
 *                 @arg I2C_INT_TYPE_ERR: communication error Interrupt.
 *                 @arg I2C_INT_TYPE_M_RXC: I2C Master Read Complete Interrupt.
 *                 @arg I2C_INT_TYPE_GC: general call Interrupt.
 *                 @arg I2C_INT_TYPE_RX_NACK: not acknowledge received Interrupt.
 *                 @arg I2C_INT_TYPE_RX_STOP: stop detection Interrupt.
 *                 @arg I2C_INT_TYPE_ADDRM: address match Interrupt.
 *                 @arg I2C_INT_TYPE_RXNE: receive Buffer Not Empty Interrupt.
 *                 @arg I2C_INT_TYPE_TXE: transfer Buffer Empty Interrupt.
 *                 @arg I2C_INT_TYPE_M_TXC: I2C Master Write Complete Interrupt.
 * @retval  FunctionalState: Interrupt enable bit has enable or not.
 *               Any value of @ref FunctionalState.
 *                 @arg DISABLE: Interrupt is disable.
 *                 @arg ENABLE: Interrupt is enable.
 ******************************************************************************/
FunctionalState I2C_GetIntCmdStatus(I2C_IntTypeEnum I2C_IntType)
{
  FunctionalState state = DISABLE;

  if(RESET != (I2C->CR1 & I2C_IntType))
  {
    /* Interrupt is enable. */
    state = ENABLE;
  }
  else
  {
    /* Interrupt is disbale. */
    state = DISABLE;
  }

  /* Return the status of the interrupt enable bit. */
  return state;
}

/**
 *******************************************************************************
 * @brief  Checks whether the specified I2C flag is set or not.
 * @param  [in]  I2C_IntFlag: specifies the flag to check.
 *               Any value of @ref I2C_IntFlagEnum.
 *                 @arg I2C_INT_FLAG_TIMEOUT: timeout or SDA LOW detection flag.
 *                 @arg I2C_INT_FLAG_RX_START: start detection flag.
 *                 @arg I2C_INT_FLAG_BUS_BUSY: bus busy flag.
 *                 @arg I2C_INT_FLAG_RX_DIR: transfer direction flag (Slave mode).
 *                 @arg I2C_INT_FLAG_OU_RUN: overrun/Underrun flag.
 *                 @arg I2C_INT_FLAG_BUS_ERR: bus error flag.
 *                 @arg I2C_INT_FLAG_ARBI_LOST: arbitration lost flag.
 *                 @arg I2C_INT_FLAG_GC: general call matched flag.
 *                 @arg I2C_INT_FLAG_M_RXC: I2C Read data completed flag (master only).
 *                 @arg I2C_INT_FLAG_M_RXC_RE: continuous read data completion flag (master only).
 *                 @arg I2C_INT_FLAG_RX_NACK: I2C bus does not respond to detection flag.
 *                 @arg I2C_INT_FLAG_RX_STOP: I2C bus stop signal detection flag.
 *                 @arg I2C_INT_FLAG_ADDRM: I2C slave mode bus address match detection flag.
 *                 @arg I2C_INT_FLAG_RXNE: receive data buffer is not empty detection flag.
 *                 @arg I2C_INT_FLAG_TXE: send data buffer is empty detection flag.
 *                 @arg I2C_INT_FLAG_M_TXC: I2C bus completes sending 1 byte data flag.
 * @retval FlagState: Interrupt flag has occurred or not.
 *               Any value of @ref FlagState.
 *                 @arg SET: Interrupt has occurred.
 *                 @arg RESET: Interrupt has not occurred.
 ******************************************************************************/
FlagState I2C_GetIntFlagStatus(I2C_IntFlagEnum I2C_IntFlag)
{
  FlagState state = RESET;

  if(RESET != (I2C->ISR & I2C_IntFlag))
  {
    /* Interrupt has occurred. */
    state = SET;
  }
  else
  {
    /* Interrupt has not occurred. */
    state = RESET;
  }

  /* Return the status of the interrupt flag bit. */
  return state;
}

/**
 *******************************************************************************
 * @brief  Clears the I2C interrupt flags.
 * @param  [in]  I2C_IntFlag: specifies the flag to check.
 *               Any value of @ref I2C_IntFlagEnum.
 *                 @arg I2C_INT_FLAG_TIMEOUT: timeout or SDA LOW detection flag.
 *                 @arg I2C_INT_FLAG_RX_START: start detection flag.
 *                 @arg I2C_INT_FLAG_BUS_BUSY: bus busy flag.
 *                 @arg I2C_INT_FLAG_RX_DIR: transfer direction flag (Slave mode).
 *                 @arg I2C_INT_FLAG_OU_RUN: overrun/Underrun flag.
 *                 @arg I2C_INT_FLAG_BUS_ERR: bus error flag.
 *                 @arg I2C_INT_FLAG_ARBI_LOST: arbitration lost flag.
 *                 @arg I2C_INT_FLAG_GC: general call matched flag.
 *                 @arg I2C_INT_FLAG_M_RXC: I2C Read data completed flag (master only).
 *                 @arg I2C_INT_FLAG_M_RXC_RE: continuous read data completion flag (master only).
 *                 @arg I2C_INT_FLAG_RX_NACK: I2C bus does not respond to detection flag.
 *                 @arg I2C_INT_FLAG_RX_STOP: I2C bus stop signal detection flag.
 *                 @arg I2C_INT_FLAG_ADDRM: I2C slave mode bus address match detection flag.
 *                 @arg I2C_INT_FLAG_RXNE: receive data buffer is not empty detection flag.
 *                 @arg I2C_INT_FLAG_TXE: send data buffer is empty detection flag.
 *                 @arg I2C_INT_FLAG_M_TXC: I2C bus completes sending 1 byte data flag.
 * @retval None.
 ******************************************************************************/
void I2C_ClearIntFlag(I2C_IntFlagEnum I2C_IntFlag)
{
  /* Clear interrupt flags.*/
  I2C->ISR = I2C_IntFlag;
}
