/**
  ******************************************************************************
 *
 * @file        Sample_I2C_Filter.c
 *
 * @brief       This is the C code format sample file for I2C.
 *              include function :
 *                  I2C Module Initial : void Sample_I2C0_Init(void);
 *                  Bus Start : Sample_StatusTypeDef I2C_BusStart(void);
 *                  Master Bus Stop : Sample_StatusTypeDef I2C_Master_BusStop(void);
 *                  Data Transmit : Sample_StatusTypeDef I2C_Transmiter(uint8_t* TxData);
 *                  Receive Data : Sample_StatusTypeDef I2C_Receive(uint8_t *RxData, uint8_t Acknowledge);
 *                  Access 24C EEPROM Sample Code : void Sample_I2C0_Code(void);
 *
 * @par         Project
 *              MG32
 * @version     V1.01
 * @date        2023/05/29
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2023 MegaWin Technology Co., Ltd.
 *              All rights reserved.
 *
 ******************************************************************************
 * @par Disclaimer
 * The Demo software is provided "AS IS" without any warranty, either
 * expressed or implied, including, but not limited to, the implied warranties
 * of merchantability and fitness for a particular purpose. The author will
 * not be liable for any special, incidental, consequential or indirect
 * damages due to loss of data or any other reason.
 * These statements agree with the world wide and local dictated laws about
 * authorship and violence against these laws.
 *******************************************************************************
 *******************************************************************************
 */

/* Includes ------------------------------------------------------------------*/
#include "MG32_DRV.h"

/* Private includes ----------------------------------------------------------*/
/* External functions --------------------------------------------------------*/

/* Private define ------------------------------------------------------------*/
#define I2C_ACK     1   /*!< I2C Ack bit State                              */
#define I2C_NACK    0   /*!< I2C Ack bit State                              */

/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/

/**
 *******************************************************************************
 * Sample function return state
 *******************************************************************************
 */
typedef enum{
    SUCCESS  = 0x00,    /*!< Success    */
    FAILURE  = 0x01,    /*!< Failure    */
    OK       = 0x00,    /*!< OK         */
    ERROR    = 0x01,    /*!< Error      */
    BUSY     = 0x02,    /*!< Busy       */
    TIMEOUT  = 0x03,    /*!< Timout     */
}Sample_StatusTypeDef;

/* Private variables ---------------------------------------------------------*/
static __IO uint8_t I2C0_TxBuff[64];
static __IO uint8_t I2C0_RxBuff[64];

/* Private function prototypes -----------------------------------------------*/
/* Private user code ---------------------------------------------------------*/
/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
Sample_StatusTypeDef fI2C_BusStart(I2C_Struct* I2Cx);
Sample_StatusTypeDef fI2C_Master_BusStop(I2C_Struct* I2Cx);
Sample_StatusTypeDef fI2C_Transmiter(I2C_Struct* I2Cx, uint8_t* TxData);
Sample_StatusTypeDef fI2C_Receive(I2C_Struct* I2Cx, uint8_t *RxData, uint8_t Acknowledge);

void Sample_I2C0_Init(void);
void Sample_I2C0_Code(void);

/**
 *******************************************************************************
 * @brief       Initialize the I2C peripheral
 * @details     1 NVIC Config.
 *      \n      2 I2C Initial
 *      \n      2.1 I2C Output Clock Config 
 *      \n      2.2 I2C OwnAddress Config
 *      \n      2.3 I2C Interrupt Config
 *      \n      2.4 I2C Enable
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                Sample_I2C_Init();
 * @endcode     
 * @par         Modify
 *              void Sample_I2C_Init(void)
 *******************************************************************************
 */
void Sample_I2C0_Init(void)
{
    PIN_InitTypeDef PINX_InitStruct;

  // 1.0 GPIO IOMB Filter Config
    GPIO_PortFilterClockSource_Select(IOMB, GPIO_FT_CLK_AHB);          // Port Filter Enable

  // 1.1 I2c AFS Pin Config
    PINX_InitStruct.PINX_Pin                = (PX_Pin_10 | PX_Pin_11);
    PINX_InitStruct.PINX_Mode               = PINX_Mode_OpenDrain_O;
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Enable;
    PINX_InitStruct.PINX_Speed              = PINX_Speed_High;
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    //PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_1;
                                                                       // Filter Clock         || Filter Div 1 Pulse Time  || By Pass Pulse Time
                                                                       // AHB = 48MHz(20.83nS) || 64nS(52.0 ~ 62.5ns)      || 38ns(31.25 ~ 41.6nS)
                                                                       // AHB = 24MHz(41.66ns) || 122nS(83.2 ~ 125nS)      || 84ns(41.6 ~ 83.2nS)
                                                                       // AHB = 12MHz(83.33ns) ||      (166.4 ~ 250nS)     || 162ns(125 ~ 166.4nS)

    PINX_InitStruct.PINX_Inverse            = PINX_Inverse_Disable;
    PINX_InitStruct.PINX_Alternate_Function = 2;
    GPIO_PortMode_Config(IOMB, &PINX_InitStruct);

  // 2.1 I2C0 Output Clock Config
    //SCL Clock = CK_I2C_PR / Prescaler / Divider / (HT + LT), Must HT >=5 LT >= 4.
    I2C_Cmd(I2C0, DISABLE);
    I2C_SetClockSource(I2C0,I2C_CLK_SRC_PROC);          // CK_I2C0_PR : 22.1184MHz
    I2C_SetClockPrescaler(I2C0, I2C_CLK_PSC_1);         // 11.0592MHz
    I2C_SetClockDivider(I2C0, I2C_CLK_DIV_1);           // 11.0592MHz
    I2C_SetSCLHighTime(I2C0, 5);                        // High Time Must >= 5CLK, 
    I2C_SetSCLLowTime(I2C0, 4);                         // Low Time Must >= 4CLK
                                                        // SCL 394971.428Hz
    I2C_SetPreDriveTime(I2C0, I2C_PDRV_0T);

  // 2.2 I2C OwnAddress Config
    I2C_SetSlaveAddress(I2C0, I2C_SADR_1, 0xAA);        //
    I2C_SetSlaveAddress(I2C0, I2C_SADR_2, 0x54);        //
    I2C_GeneralCallAddress_Cmd(I2C0, DISABLE);          //
    I2C_SlaveAddressDetect_Cmd(I2C0, (I2C_SADR_0 | I2C_SADR_1 | I2C_SADR_2), ENABLE);

  // 2.3 Disable I2C Interrupt Config 
    I2C_IT_Config(I2C0, I2C_IT_EVENT, DISABLE);
    I2C_ITEA_Cmd(I2C0, DISABLE);

  // 2.4 I2C Enable
    I2C_Cmd(I2C0, ENABLE);

  // 3 NVIC Interrupt Config
    // NVIC_EnableIRQ(I2Cx_IRQn);
    // NVIC_SetPriority(I2Cx_IRQn, 3);                                         // Suggest SYSTICK Priority = 0
}

/**
 *******************************************************************************
 * @brief       I2C Output Bus Start
 * @details     Output Bus Start
 * @param[in]   I2Cx : I2C pointer to a I2C_Struct structure that contains the 
 *                     configuration information for the specified I2Cx.
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
 *              fI2C_BusStart(I2C0);
 *              fI2C_BusStart(I2C1);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef fI2C_BusStart(I2C_Struct* I2Cx)
 *******************************************************************************
 */
Sample_StatusTypeDef fI2C_BusStart(I2C_Struct* I2Cx)
{
    uint8_t lEventCode;

    lEventCode = I2C_GetEventCode(I2Cx);
    if(lEventCode != 0xF8)
    {
        while(I2C_GetEventFlag(I2Cx) != 0);
        lEventCode = I2C_GetEventCode(I2Cx);
    }

    switch (lEventCode){
        case 0x08:
        case 0x10:
            return SUCCESS;

        default:

        case 0xF8:
            Set_STOP_CLR(I2Cx);
            Set_START_SET(I2Cx);
            I2C_ClearEventFlag(I2Cx);
            while(I2C_GetEventFlag(I2Cx) != 0);
            return SUCCESS;
    }
}

/**
 *******************************************************************************
 * @brief       I2C Master Output Bus Stop
 * @details     Master Output Bus Stop
 * @param[in]   I2Cx : I2C pointer to a I2C_Struct structure that contains the 
 *                     configuration information for the specified I2Cx.
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                fI2C_Master_BusStop(I2C0);
                fI2C_Master_BusStop(I2C1);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef fI2C_Master_BusStop(I2C_Struct* I2Cx)
 *******************************************************************************
 */
Sample_StatusTypeDef fI2C_Master_BusStop(I2C_Struct* I2Cx)
{
    uint8_t lEventCode;

    while(I2C_GetEventFlag(I2Cx) != 0);
    lEventCode = I2C_GetEventCode(I2Cx);

    switch (lEventCode){
        case 0xF8:
        case 0xA0:
            return SUCCESS;

        default:
            Set_STA_STO_AA_010(I2Cx);
            I2C_ClearEventFlag(I2Cx);
            __I2C_WaitSTOClear(I2Cx);
            return SUCCESS;
    }
}

/**
 *******************************************************************************
 * @brief       I2C Transmiter Data
 * @details     Transmiter Data
 * @param[in]   I2Cx : I2C pointer to a I2C_Struct structure that contains the 
 *                     configuration information for the specified I2Cx.
 * @param[in]   TxData : Value of Output Data
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                fI2C_Transmiter(I2C0, (uint8_t *)&TxBuff)
                fI2C_Transmiter(I2C1, (uint8_t *)&TxBuff)
 * @endcode     
 * @par         Modify
 *              fI2C_Transmiter(I2C_Struct* I2Cx, uint8_t* TxData)
 *******************************************************************************
 */
Sample_StatusTypeDef fI2C_Transmiter(I2C_Struct* I2Cx, uint8_t* TxData)
{
    uint8_t lEventCode;

    while(I2C_GetEventFlag(I2Cx) != 0);
    lEventCode = I2C_GetEventCode(I2Cx);

    switch (lEventCode){
        case 0x08:
        case 0x10:
            Set_START_CLR(I2Cx);

          #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
            __attribute__((fallthrough));
          #endif

        case 0x18:
        case 0x20:
        case 0x28:
        case 0x30:
        case 0xB8:
            Set_ASSERT_ACKNOWLEDGE_SET(I2Cx);
            I2C_SendSBUF(I2Cx, *TxData);

          #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
            __attribute__((fallthrough));
          #endif

        case 0xA8:
        case 0xB0:
            I2C_ClearEventFlag(I2Cx);
            return SUCCESS;

        case 0xC0:
        default:
            return FAILURE;
    }
}

/**
 *******************************************************************************
 * @brief       I2C Receive Data
 * @details     Receive Data
 * @param[in]   I2Cx : I2C pointer to a I2C_Struct structure that contains the 
 *                     configuration information for the specified I2Cx.
 * @param[out]  RxData : Value of Receive Data.
 * @param[in]   Acknowledge : Freeback ACK / NACK to Transmiter.
 *          \n  0 : NACK
 *          \n  1 : ACK
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                fI2C_Receive(I2C0, (uint8_t *)&RxBuff, I2C_ACK);
                fI2C_Receive(I2C1, (uint8_t *)&RxBuff, I2C_NACK);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef fI2C_Receive(I2C_Struct* I2Cx, uint8_t *RxData, uint8_t Acknowledge)
 *******************************************************************************
 */
Sample_StatusTypeDef fI2C_Receive(I2C_Struct* I2Cx, uint8_t *RxData, uint8_t Acknowledge)
{
    uint8_t lEventCode;

    while(I2C_GetEventFlag(I2Cx) != 0);
    lEventCode = I2C_GetEventCode(I2Cx);
    switch (lEventCode){
        case 0x40:
        case 0x50:
        case 0x80:
        case 0x90:
            if(Acknowledge != 0)
                Set_ASSERT_ACKNOWLEDGE_SET(I2Cx);
            else
                Set_ASSERT_ACKNOWLEDGE_CLR(I2Cx);

        #if defined (__ARMCC_VERSION) && (__ARMCC_VERSION >= 6010050) /* ARM Compiler V6 */
        __attribute__((fallthrough));
        #endif

        case 0x88:
        case 0x98:
            I2C_ClearEventFlag(I2Cx);
            while(I2C_GetEventFlag(I2Cx) != 0);
            *RxData = I2C_ReceiveSBUF(I2Cx);
            return SUCCESS;

        case 0x60:
        case 0x68:
        case 0x70:
        case 0x78:
            I2C_ClearEventFlag(I2Cx);
            return SUCCESS;

        case 0xA0:
            I2C_ClearEventFlag(I2Cx);
            return FAILURE;
        default:
            return FAILURE;
    }
}

/**
 *******************************************************************************
 * @brief       Sample I2C0 Code
 * @details     I2C0 Sample Code
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                Sample_I2C0_Code();
 * @endcode     
 * @par         Modify
 *              void Sample_I2C0_Code(void)
 *******************************************************************************
 */
void Sample_I2C0_Code(void)
{
    uint8_t lTemp = 0;

//-----------------------------------------------------------------------------
    I2C0_RxBuff[6] = I2C0_TxBuff[0] = 0xFF;
    I2C0_RxBuff[5] = I2C0_TxBuff[1] = 0x00;
    I2C0_RxBuff[4] = I2C0_TxBuff[2] = 0x33;
    I2C0_RxBuff[3] = I2C0_TxBuff[3] = 0xCC;
    I2C0_RxBuff[2] = I2C0_TxBuff[4] = 0x55;
    I2C0_RxBuff[1] = I2C0_TxBuff[5] = 0xAA;
    I2C0_RxBuff[0] = I2C0_TxBuff[6] = 0x66;
    I2C0_RxBuff[0] = I2C0_TxBuff[6] = 0x99;

//-----------------------------------------------------------------------------
    fI2C_BusStart(I2C0);                              // Output Bus Start

    lTemp = 0xA0;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Address 0xA0, Transmiter Slave Device Addree and Read / Write

    lTemp = 0x00;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output 24C Memory Address 0x00

    lTemp = 0x00;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output 24C Memory Address 0x00

    lTemp = 0x33;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data1 0x33

    lTemp = 0xCC;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data2 0xCC

    lTemp = 0x55;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data3 0x55

    lTemp = 0xAA;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data4 0xAA

    lTemp = 0x66;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data5 0x66

    lTemp = 0x99;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data6 0x99

    lTemp = 0xFF;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data7 0xFF

    lTemp = 0xFF;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data8 0xFF

    fI2C_Master_BusStop(I2C0);                        // Output Bus Stop

    Delay(5);                                        // Write cycle time (byte or page)

//-----------------------------------------------------------------------------
    fI2C_BusStart(I2C0);                              // Output Bus Start

    lTemp = I2C0_TxBuff[0];
    lTemp = 0xA0;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Address 0xA0, Transmiter Slave Device Addree and Read / Write

    lTemp = 0x00;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output 24C Memory Address 0x00

    lTemp = 0x08;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output 24C Memory Address 0x00

    lTemp = 0x00;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data1 0x00

    lTemp = 0x11;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data2 0x11

    lTemp = 0x22;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data3 0x22

    lTemp = 0x33;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data4 0x33

    lTemp = 0x44;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data5 0x44

    lTemp = 0x55;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data6 0x55

    lTemp = 0x66;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data7 0x66

    lTemp = 0x77;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Data8 0x77

    fI2C_Master_BusStop(I2C0);                        // Output Bus Stop

    Delay(5);                                        // Write cycle time (byte or page)

//-----------------------------------------------------------------------------
    fI2C_BusStart(I2C0);                              // Output Repeat Start

    lTemp = 0xA0;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Device Address 0xA0, Transmiter Slave Device Addree and Read / Write

    lTemp = 0x00;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output 24C Memory Address 0x00

    lTemp = 0x00;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output 24C Memory Address 0x00

    fI2C_BusStart(I2C0);                              // Output Repeat Start
    lTemp = 0xA1;
    fI2C_Transmiter(I2C0, (uint8_t *)&lTemp);         // Output Device Address 0xA1, Transmiter Slave Device Addree and Read / Write

    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 0
    I2C0_RxBuff[0] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 1
    I2C0_RxBuff[1] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 2
    I2C0_RxBuff[2] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 3
    I2C0_RxBuff[3] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 4
    I2C0_RxBuff[4] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 5
    I2C0_RxBuff[5] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 6
    I2C0_RxBuff[6] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 7
    I2C0_RxBuff[7] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 8
    I2C0_RxBuff[8] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 9
    I2C0_RxBuff[9] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 10
    I2C0_RxBuff[10] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 11
    I2C0_RxBuff[11] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 12
    I2C0_RxBuff[12] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 13
    I2C0_RxBuff[13] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 14
    I2C0_RxBuff[14] = lTemp;
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);   // Receive Data Byte 15
    I2C0_RxBuff[15] = lTemp;

    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_NACK);  // Receive Data Byte 16  (Last Byte).
    I2C0_RxBuff[16] = lTemp;
    fI2C_Master_BusStop(I2C0);

//-----------------------------------------------------------------------------
    fI2C_Receive(I2C0, (uint8_t *)&lTemp, I2C_ACK);
}

