/**
 *******************************************************************************
 * @file    dpm32m0xx_i2c.h
 *
 * @brief   Header file for I2C firmware driver.
 *
 * @author  DPM
 *
 * @version V1.0.0
 *
 * @date    2023-11-01
 *
 *******************************************************************************/

#ifndef __DPM32M0XX_I2C_H__
#define __DPM32M0XX_I2C_H__


#ifdef __cplusplus
extern "C" {
#endif

#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wpadded"
#endif

#include "dpm32m0xx.h"


#if defined (DPM32M08x) || defined (DPM32M05x) || defined (DPM32M03x) || \
    defined (DPM32M036) || defined (DPM32M030) || defined (DPM32M015)

/**
 ******************************************************************************
 * @brief I2C mode (Master/Slave) enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_MODE_MASTER = 0x00UL,                                /*!< I2C slave mode.  */
  I2C_MODE_SLAVE                                           /*!< I2C master mode. */
} I2C_ModeEnum;


/**
 ******************************************************************************
 * @brief I2C addressing mode enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_ADDRESSING_MODE_7BIT = 0x00UL,                       /*!< 7-bit address mode.     */
  I2C_ADDRESSING_MODE_10BIT,                               /*!< 10-bit address mode.    */
  I2C_ADDRESSING_MODE_NO_ADDR                              /*!< No address filter mode. */
} I2C_AddressingModeEnum;


/**
 ******************************************************************************
 * @brief I2C no stretch mode enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_NOSTRETCH_MODE_DISABLE = 0x00UL,                     /*!< Enable no stretch mode. */
  I2C_NOSTRETCH_MODE_ENABLE                              /*!< Disable no stretch mode.  */
} I2C_NoStretchModeEnum;


/**
 ******************************************************************************
 * @brief I2C general call mode enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_GENERALCALL_MODE_DISABLE = 0x00UL,                   /*!< Disable general call mode. */
  I2C_GENERALCALL_MODE_ENABLE                              /*!< Enable general call mode.  */
} I2C_GeneralCallModeEnum;


/**
 ******************************************************************************
 * @brief I2C master mode read and write direction enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_DIRECTION_TRANSMITTER = 0x00UL,                      /*!< Master request transmitted direction. */
  I2C_DIRECTION_RECEIVER                                   /*!< Master request receiving direction.   */
} I2C_DirectionEnum;


#if defined (DPM32M08x) || defined (DPM32M05x)
/**
 ******************************************************************************
 * @brief I2C DMA request enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_DMA_REQ_TX = I2C_CR1_TX_DMAEN_Msk,           /*!< Tx buffer DMA transfer request. */
  I2C_DMA_REQ_RX = I2C_CR1_RX_DMAEN_Msk            /*!< Rx buffer DMA transfer request. */
} I2C_DMAReqEnum;
#endif /* DPM32M08x || DPM32M05x */


/**
 ******************************************************************************
 * @brief I2C registers enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_REGISTER_CR1       = ((uint8_t)0x00),           /*!< I2C control register 1.            */
  I2C_REGISTER_CR2       = ((uint8_t)0x04),           /*!< I2C control register 2.            */
  I2C_REGISTER_ISR       = ((uint8_t)0x08),           /*!< I2C Interrupt and Status Register. */
  I2C_REGISTER_TIMING    = ((uint8_t)0x0C),           /*!< I2C Timing control Register.       */
  I2C_REGISTER_ADDR_SELF = ((uint8_t)0x10),           /*!< I2C self address Register.         */
  I2C_REGISTER_TX_BUF    = ((uint8_t)0x14),           /*!< I2C Transfer Buffer Register .     */
  I2C_REGISTER_RX_BUF    = ((uint8_t)0x18)            /*!< I2C Receive Buffer Register.       */
} I2C_RegisterEnum;


/**
 ******************************************************************************
 * @brief I2C interrupt type enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_INT_TYPE_TXC     = I2C_CR1_TXC_IE_Msk,          /*!< I2C Master Write Complete Interrupt.  */
  I2C_INT_TYPE_TXE     = I2C_CR1_TXE_IE_Msk,          /*!< Transfer Buffer Empty Interrupt.      */
  I2C_INT_TYPE_RXNE    = I2C_CR1_RXNE_IE_Msk,         /*!< Receive Buffer Not Empty Interrupt.   */
  I2C_INT_TYPE_ADDRM   = I2C_CR1_ADDRM_IE_Msk,        /*!< Address match Interrupt (slave only). */
  I2C_INT_TYPE_STOPF   = I2C_CR1_STOPF_IE_Msk,        /*!< Stop detection Interrupt.             */
  I2C_INT_TYPE_NACKF   = I2C_CR1_NACKF_IE_Msk,        /*!< Not acknowledge received Interrupt.   */
  I2C_INT_TYPE_GC      = I2C_CR1_GC_IE_Msk,           /*!< General call Interrupt.               */
  I2C_INT_TYPE_RXC     = I2C_CR1_RXC_IE_Msk,          /*!< I2C Master Read Complete Interrupt.   */
  I2C_INT_TYPE_ERR     = I2C_CR1_ERR_IE_Msk,          /*!< Communication error Interrupt.        */
  I2C_INT_TYPE_START   = I2C_CR1_STARTF_IE_Msk        /*!< Start detection Interrupt.            */
} I2C_IntTypeEnum;


/**
 ******************************************************************************
 * @brief I2C interrupt flag type enumeration.
 *****************************************************************************/
typedef enum
{
  I2C_INT_FLAG_TXC          = I2C_ISR_TXC_Msk,            /*!< I2C bus completes sending 1 byte data flag.         */
  I2C_INT_FLAG_TXE          = I2C_ISR_TXE_Msk,            /*!< Send data buffer is empty detection flag.           */
  I2C_INT_FLAG_RXNE         = I2C_ISR_RXNE_Msk,           /*!< Receive data buffer is not empty detection flag.    */
  I2C_INT_FLAG_ADDRM        = I2C_ISR_ADDRM_Msk,          /*!< I2C slave mode bus address match detection flag.    */
  I2C_INT_FLAG_STOPF        = I2C_ISR_STOPF_Msk,          /*!< I2C bus stop signal detection flag.                 */
  I2C_INT_FLAG_NACKF        = I2C_ISR_NACKF_Msk,          /*!< I2C bus does not respond to detection flag.         */
  I2C_INT_FLAG_RXC_RE       = I2C_ISR_RXC_RE_Msk,         /*!< Continuous read data completion flag (master only). */
  I2C_INT_FLAG_RXC          = I2C_ISR_RXC_Msk,            /*!< Read data completed flag (master only).             */
  I2C_INT_FLAG_GC           = I2C_ISR_GC_Msk,             /*!< General call matched flag.                          */
  I2C_INT_FLAG_ARBI_LOST    = I2C_ISR_ARBI_LOST_Msk,      /*!< Arbitration lost flag.                              */
  I2C_INT_FLAG_BUS_ERR      = I2C_ISR_BUS_ERR_Msk,        /*!< Bus error flag.                                     */
  I2C_INT_FLAG_OVRR_UDRR    = I2C_ISR_OVRR_UDRR_Msk,      /*!< Overrun/Underrun flag.                              */
  I2C_INT_FLAG_DIR          = I2C_ISR_DIR_Msk,            /*!< Transfer direction flag (Slave mode).               */
  I2C_INT_FLAG_BUSY         = I2C_ISR_BUSY_Msk,           /*!< Bus busy flag.                                      */
  I2C_INT_FLAG_STARTF       = I2C_ISR_STARTF_Msk,         /*!< Start detection flag.                               */
  I2C_INT_FLAG_TIMEOUT      = I2C_ISR_TIMEOUT_Msk         /*!< Timeout or SDA LOW detection flag.                  */
} I2C_IntFlagEnum;

/**
 ******************************************************************************
 * @brief I2C initialization structure definition.
 *****************************************************************************/
typedef struct
{
  uint32_t I2C_Timing;            /*!< Specifies the I2C_TIMINGR_register value.
                                       This parameter can be a number between 0x00 and 0x3FFFFFFF    */

  uint32_t I2C_Prescaler;         /*!< Specify the I2C prescaler value.
                                       This parameter can be a number between 0x00 and 0x1F.
                                       @note The default value is 0x16, and the prescaler value
                                             T(presc) = (PRESC+1) x T(pclk).                         */

  uint32_t I2C_DigitalFilter;     /*!< Configures the digital noise filter.
                                       This parameter can be a number between 0x00 and 0x0F          */

  uint32_t I2C_Mode;              /*!< Specifies the I2C mode.
                                       This parameter can be a value of @ref I2C_ModeEnum            */

  uint32_t I2C_OwnAddress;        /*!< Specifies the device own address.
                                       This parameter can be a 7-bit or 10-bit address               */

  uint32_t I2C_AddressingMode;    /*!< Specifies if 7-bit or 10-bit addressing mode is selected.
                                       This parameter can be a value of @ref I2C_AddressingModeEnum  */

  uint32_t I2C_NoStretchMode;     /*!< Specifies if nostretch mode is selected.
                                       This parameter can be a value of @ref I2C_NoStretchModeEnum   */

  uint32_t I2C_GeneralCallMode;   /*!< Specifies if general call mode is selected.
                                       This parameter can be a value of @ref I2C_GeneralCallModeEnum */

} I2C_InitTypeStruct;



/* SPI Param Check. */

#define IS_I2C_MODE(x)                (((x) == I2C_MODE_MASTER) || \
                                       ((x) == I2C_MODE_SLAVE))

#define IS_I2C_ADDRESSING_MODE(x)     (((x) == I2C_ADDRESSING_MODE_7BIT) || \
                                       ((x) == I2C_ADDRESSING_MODE_10BIT) || \
                                       ((x) == I2C_ADDRESSING_MODE_NO_ADDR))

#define IS_I2C_NOSTRETCH_MODE(x)      (((x) == I2C_NOSTRETCH_MODE_DISABLE) || \
                                       ((x) == I2C_NOSTRETCH_MODE_ENABLE))

#define IS_I2C_GENERALCALL_MODE(x)    (((x) == I2C_GENERALCALL_MODE_DISABLE) || \
                                       ((x) == I2C_GENERALCALL_MODE_ENABLE))

#define IS_I2C_TIMING_VAL(x)          (((x) <= 0x3FFFFFFF))

#define IS_I2C_PRESCALER_VAL(x)       (((x) <= 0x1F))

#define IS_I2C_DIGITALFILTER_VAL(x)   (((x) <= 0x0F))

#define IS_I2C_OWNADDRESS_VAL(x)      (((x) <= 0x03FF))



/* Initialization and Configuration functions. */
void                   I2C_DeInit(void);
void                   I2C_Init(I2C_InitTypeStruct *I2C_InitType);
void                   I2C_StructInit(I2C_InitTypeStruct *I2C_InitType);
void                   I2C_Cmd(FunctionalState State);
void                   I2C_SoftwareResetCmd(void);
void                   I2C_StretchClockCmd(FunctionalState State);
void                   I2C_GeneralCallCmd(FunctionalState State);
void                   I2C_NoAddressingModeCmd(FunctionalState State);
void                   I2C_10BitAddressingModeCmd(FunctionalState State);
void                   I2C_SwitchSlaveCmd(FunctionalState State);
void                   I2C_SlaveTimeoutConfig(uint8_t Timeout);


/* Communications handling functions ******************************************/
void                   I2C_ReloadCmd(FunctionalState State);
void                   I2C_NumberOfBytesConfig(uint8_t Bytes);
void                   I2C_ClearTxBuffer(void);
void                   I2C_NackConf(void);
void                   I2C_GenerateSTART(void);
void                   I2C_GenerateSTOP(void);
void                   I2C_GenerateRESTART(void);
void                   I2C_TransferDirectionConfig(I2C_DirectionEnum I2C_Direction);
void                   I2C_TargetAddressConfig(uint16_t Address);
I2C_DirectionEnum      I2C_GetTransferDirection(void);
void                   I2C_SlaveTransferDirectionConfig(I2C_DirectionEnum I2C_Direction);


/* I2C registers management functions *****************************************/
uint32_t               I2C_ReadRegister(I2C_RegisterEnum I2C_Register);


/* Data transfers management functions ****************************************/
void                   I2C_SendData(uint8_t Data);
uint8_t                I2C_ReceiveData(void);


#if defined (DPM32M08x)|| defined (DPM32M05x)
/* DMA transfers management functions *****************************************/
void                   I2C_DMACmd(I2C_DMAReqEnum I2C_DMAReq, FunctionalState State);
#endif /* DPM32M08x || DPM32M05x */

/* Interrupts and flags management functions **********************************/
void                   I2C_IntCmd(I2C_IntTypeEnum I2C_IntType, FunctionalState State);
FunctionalState        I2C_GetIntCmdStatus(I2C_IntTypeEnum I2C_IntType);
FlagState              I2C_GetIntFlagStatus(I2C_IntFlagEnum I2C_IntFlag);
void                   I2C_ClearIntFlag(I2C_IntFlagEnum I2C_IntFlag);



#if defined(__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050)
#pragma clang diagnostic pop
#endif

#endif /* DPM32M08x || DPM32M05x || DPM32M03x || DPM32M036 || DPM32M030 || DPM32M015 */

#ifdef __cplusplus
}
#endif

#endif /* __DPM32M0XX_I2C_H__ */
