/**
  ******************************************************************************
 *
 * @file        Sample_I2C_ColorSensor_TCS34725.c
 *
 * @brief       This is the C code format sample file for I2C.
 *              include function :
 *                  Sample_I2C_ColorSeneor_TCS34725 : 
 *                  TCS34725_Init : 
 *                  TCS34725_SetLight : 
 *                  TCS34725_Disable : 
 *                  TCS34725_Get_RGBData : 
 *                  TCS34725_Get_RGB888 : 
 *                  TCS34725_Get_RGB565 : 
 *                  TCS34725_Get_Lux : 
 *                  TCS34725_GetLux_Interrupt : 
 *                  I2C Module Initial : void Sample_I2C_Init(void);
 *                  Bus Start : Sample_StatusTypeDef I2C0_BusStart(void);
 *                  Master Bus Stop : Sample_StatusTypeDef I2C0_Master_BusStop(void);
 *                  Data Transmit : Sample_StatusTypeDef I2C0_Transmiter(uint8_t* TxData);
 *                  Receive Data : Sample_StatusTypeDef I2C0_Receive(uint8_t *RxData, uint8_t Acknowledge);
 *
 * @par         Project
 *              MG32
 * @version     V1.00
 * @date        2023/05/10
 * @author      Megawin Software Center
 * @copyright   Copyright (c) 2021 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 "math.h"
#include "MG32_DRV.h"
#include "MG32_CSC_Init.h"

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

/* Private define ------------------------------------------------------------*/

/**
* Pin
**/
#define TCS34725_INT_PIN            PB7     /*!< for TCS34725 External Interrupt Pin                                */
#define TCS34725_INT_PORT           GPIOB   /*!< for TCS34725 External Interrupt Port                               */

/**
* Device address
**/
// I2C 7-bit address 0x29, 8-bit address 0x52
#define TCS34725_ADDRESS          (0x29<<1) /*!<                                                                    */

/**
* Register
**/
#define TCS34725_CMD_BIT          0x80  /*!< Select Command Register. Must write as 1 when addressing COMMAND register. */
#define TCS34725_CMD_Read_Byte    0x00  /*!< Repeated byte protocol transaction                                     */
#define TCS34725_CMD_Read_Word    0x20  /*!< Auto-increment protocol transaction                                    */
#define TCS34725_CMD_Clear_INT    0x66  /*!< RGBC Interrupt flag clear                                              */

#define TCS34725_ENABLE           0x00  /*!< Enable Register                                                        */
#define TCS34725_ENABLE_AIEN      0x10  /*!< RGBC Interrupt Enable                                                  */
#define TCS34725_ENABLE_WEN       0x08  /*!< Wait enable - Writing 1 activates the wait timer                       */
#define TCS34725_ENABLE_AEN       0x02  /*!< RGBC Enable - Writing 1 actives the ADC, 0 disables it                 */
#define TCS34725_ENABLE_PON       0x01  /*!< Power on - Writing 1 activates the internal oscillator, 0 disables it  */

#define TCS34725_ATIME            0x01  /*!< Integration time */
#define TCS34725_WTIME            0x03  /*!< Wait time (if TCS34725_ENABLE_WEN is asserted)                         */
#define TCS34725_WTIME_2_4MS      0xFF  /*!< WLONG0 = 2.4ms   WLONG1 = 0.029s                                       */
#define TCS34725_WTIME_204MS      0xAB  /*!< WLONG0 = 204ms   WLONG1 = 2.45s                                        */
#define TCS34725_WTIME_614MS      0x00  /*!< WLONG0 = 614ms   WLONG1 = 7.4s                                         */

#define TCS34725_AILTL            0x04  /*!< Clear channel lower interrupt threshold                                */
#define TCS34725_AILTH            0x05  /*!< Clear channel lower interrupt threshold                                */
#define TCS34725_AIHTL            0x06  /*!< Clear channel upper interrupt threshold                                */
#define TCS34725_AIHTH            0x07  /*!< Clear channel upper interrupt threshold                                */

#define TCS34725_PERS             0x0C  /*!< Persistence register - basic SW filtering mechanism for interrupts     */
#define TCS34725_PERS_NONE        0x00  /*!< Every RGBC cycle generates an interrupt                                */
#define TCS34725_PERS_1_CYCLE     0x01  /*!< 1 clean channel value outside threshold range generates an interrupt   */
#define TCS34725_PERS_2_CYCLE     0x02  /*!< 2 clean channel values outside threshold range generates an interrupt  */
#define TCS34725_PERS_3_CYCLE     0x03  /*!< 3 clean channel values outside threshold range generates an interrupt  */
#define TCS34725_PERS_5_CYCLE     0x04  /*!< 5 clean channel values outside threshold range generates an interrupt  */
#define TCS34725_PERS_10_CYCLE    0x05  /*!< 10 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_15_CYCLE    0x06  /*!< 15 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_20_CYCLE    0x07  /*!< 20 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_25_CYCLE    0x08  /*!< 25 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_30_CYCLE    0x09  /*!< 30 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_35_CYCLE    0x0a  /*!< 35 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_40_CYCLE    0x0b  /*!< 40 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_45_CYCLE    0x0c  /*!< 45 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_50_CYCLE    0x0d  /*!< 50 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_55_CYCLE    0x0e  /*!< 55 clean channel values outside threshold range generates an interrupt */
#define TCS34725_PERS_60_CYCLE    0x0f  /*!< 60 clean channel values outside threshold range generates an interrupt */

#define TCS34725_CONFIG           0x0D  /*!<  Configuration Register                                                */
#define TCS34725_CONFIG_WLONG     0x02  /*!< Choose between short and long (12x) wait times via TCS34725_WTIME      */

#define TCS34725_CONTROL          0x0F  /*!< Set the gain level for the sensor                                      */
#define TCS34725_ID               0x12  /*!< 0x44 = TCS34721/TCS34725, 0x4D = TCS34723/TCS34727                     */

#define TCS34725_STATUS           0x13  /*!< Status Register provides the internal status of the device             */
#define TCS34725_STATUS_AINT      0x10  /*!< RGBC Clean channel interrupt                                           */
#define TCS34725_STATUS_AVALID    0x01  /*!< Indicates that the RGBC channels have completed an integration cycle   */

#define TCS34725_CDATAL           0x14  /*!< Clear channel data low byte                                            */
#define TCS34725_CDATAH           0x15  /*!< Clear channel data high byte                                           */
#define TCS34725_RDATAL           0x16  /*!< Red channel data low byte                                              */
#define TCS34725_RDATAH           0x17  /*!< Red channel data high byte                                             */
#define TCS34725_GDATAL           0x18  /*!< Green channel data low byte                                            */
#define TCS34725_GDATAH           0x19  /*!< Green channel data high byte                                           */
#define TCS34725_BDATAL           0x1A  /*!< Blue channel data low byte                                             */
#define TCS34725_BDATAH           0x1B  /*!< Blue channel data high byte                                            */

/**
* Offset and Compensated
**/
#define TCS34725_R_Coef 0.136   /*!< Red                                                                            */  
#define TCS34725_G_Coef 1.000   /*!< Green                                                                          */
#define TCS34725_B_Coef -0.444  /*!< Blue                                                                           */
#define TCS34725_GA 1.0         /*!< ???                                                                            */
#define TCS34725_DF 310.0       /*!< ???                                                                            */
#define TCS34725_CT_Coef 3810.0 /*!< ???                                                                            */
#define TCS34725_CT_Offset 1391.0   /*!< ???                                                                        */

#define TCS34725_SlaveAddr  0x29 << 1   /*!< TCS34725 Device Address                                                */

/**
 * delay x ms
**/
#define DEV_Delay_ms(__xms) Delay(__xms)    /*!< Delay Time                                                         */

/**
 * PWM
**/
#define DEV_Set_PWM(_Value) LED = _Value    /*!< Set Light PWM Time                                                 */
#define DEV_PWM_value       2000            /*!< Light PWM Time                                                     */

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

/* Private macro -------------------------------------------------------------*/
/* Private typedef -----------------------------------------------------------*/
/**
* Integration Time
**/
typedef enum
{
    TCS34725_INTEGRATIONTIME_2_4MS  = 0xFF,   /**<  2.4ms - 1 cycle    - Max Count: 1024  */
    TCS34725_INTEGRATIONTIME_24MS   = 0xF6,   /**<  24ms  - 10 cycles  - Max Count: 10240 */
    TCS34725_INTEGRATIONTIME_50MS   = 0xEB,   /**<  50ms  - 20 cycles  - Max Count: 20480 */
    TCS34725_INTEGRATIONTIME_101MS  = 0xD5,   /**<  101ms - 42 cycles  - Max Count: 43008 */
    TCS34725_INTEGRATIONTIME_154MS  = 0xC0,   /**<  154ms - 64 cycles  - Max Count: 65535 */
    TCS34725_INTEGRATIONTIME_700MS  = 0x00    /**<  700ms - 256 cycles - Max Count: 65535 */
}TCS34725IntegrationTime_t;

/**
 *******************************************************************************
 * Gain
 *******************************************************************************
 */
typedef enum{
    TCS34725_GAIN_1X                = 0x00,   /*!<  No gain  */
    TCS34725_GAIN_4X                = 0x01,   /*!<  4x gain  */
    TCS34725_GAIN_16X               = 0x02,   /*!<  16x gain */
    TCS34725_GAIN_60X               = 0x03    /*!<  60x gain */
}TCS34725Gain_t;

/**
 *******************************************************************************
 * Color struct
 *******************************************************************************
 */
typedef struct{
    uint16_t R;         /*!< Red */
    uint16_t G;         /*!< Green */
    uint16_t B;         /*!< Blue */
    uint16_t C;         /*!< Clear */
}RGB;

/**
 *******************************************************************************
 * 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 ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private user code ---------------------------------------------------------*/



/* Exported variables --------------------------------------------------------*/
/* Exported functions --------------------------------------------------------*/
void Sample_I2C_ColorSeneor_TCS34725(void); // Main function.

//initialization
uint8_t TCS34725_Init(void);
void TCS34725_SetLight(uint16_t value);
void TCS34725_Disable(void);
void TCS34725_Set_Integration_Time(TCS34725IntegrationTime_t time);
void TCS34725_Set_Gain(TCS34725Gain_t gain);
void TCS34725_Interrupt_Enable(void);
void TCS34725_Interrupt_Disable(void);
//void TCS34725_Set_IntegrationTime(TCS34725IntegrationTime_t it);
// void TCS34725_Set_Config(TCS34725Gain_t gain, TCS34725IntegrationTime_t it);

//Read Color
RGB TCS34725_Get_RGBData(void);
uint16_t TCS34725_Get_ColorTemp(RGB rgb);
uint16_t TCS34725_Get_RGB565(RGB rgb);
uint32_t TCS34725_Get_RGB888(RGB rgb);

//Read Light
uint16_t TCS34725_Get_Lux(RGB rgb);
uint8_t TCS34725_GetLux_Interrupt(uint16_t Threshold_H, uint16_t Threshold_L);

void DEV_Set_I2CAddress(uint8_t add_);
void DEV_I2C_WriteByte(uint8_t add_, uint8_t data_);
void DEV_I2C_WriteWord(uint8_t add_, uint16_t data_);
uint8_t DEV_I2C_ReadByte(uint8_t add_);
uint16_t DEV_I2C_ReadWord(uint8_t add_);

void Sample_GPIO_Init(void);
void Sample_URT0_Init(void);
void Sample_I2C0_Init(void);
void Sample_I2C0_Code(void);
Sample_StatusTypeDef I2C_BusStart(I2C_Struct* I2Cx);
Sample_StatusTypeDef I2C_Master_BusStop(I2C_Struct* I2Cx);
Sample_StatusTypeDef I2C_Transmiter(I2C_Struct* I2Cx, uint8_t TxData);
Sample_StatusTypeDef I2C_Receive(I2C_Struct* I2Cx, uint8_t *RxData, uint8_t Acknowledge);

void SysTick_Handler(void);

/*
 ******************************************************************************
 *
 *    Sample_I2C_ColorSeneor_TCS34725  main function
 *
 ******************************************************************************
 */
static TCS34725IntegrationTime_t IntegrationTime_t = TCS34725_INTEGRATIONTIME_700MS;
static TCS34725Gain_t Gain_t = TCS34725_GAIN_60X;

/**
 ******************************************************************************
 * @brief       Sample I2C ColorSeneor TCS34725
 * @details     Color Seneor TCS34725 function entry
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                Sample_I2C_ColorSeneor_TCS34725();
 * @endcode     
 * @par         Modify
 *              Sample_I2C_ColorSeneor_TCS34725(void)
 ******************************************************************************
 */
void Sample_I2C_ColorSeneor_TCS34725(void)
{
    RGB rgb;
    uint32_t RGB888 = 0;
    uint16_t RGB565 = 0;
    uint16_t lLoopCount = 5;

    // ------------------------------------------------------------------------
    // chip initial (User can enable CSC, GPIO, TM, ADC, EXIC ... wizard)
    // ------------------------------------------------------------------------
    // CK_MAIN = CK_APB = CK_AHB = 48MHz

    // Systick Initial
    InitTick(CONF_CK_AHB_FREQ, 0);

    Sample_GPIO_Init();

    Sample_URT0_Init();

    Sample_I2C0_Init();

    TCS34725_Init();

    do{
        rgb = TCS34725_Get_RGBData();
        RGB888 = TCS34725_Get_RGB888(rgb);
        RGB565 = TCS34725_Get_RGB565(rgb);
        printf("RGB888 :R = %d   G = %d  B = %d \r\n", (RGB888 >> 16), (RGB888 >> 8) & 0xff, (RGB888) & 0xff);
        printf("RGB888 = 0X%X  RGB565=0X%X \r\n", RGB888, RGB565);

        if(TCS34725_GetLux_Interrupt(0xff00, 0x0Cff) == 1){
            printf("Lux_Interrupt = 1\r\n");
            __NOP();
        }else{
            printf("Lux_Interrupt = 0\r\n");
            __NOP();
        }

        printf("\r\n");
        DEV_Delay_ms(300);
    }while(lLoopCount != 0);
}

/**
 ******************************************************************************
 * @brief       TCS34725 Write Byte
 * @details     Write a byte to TCS34725
 * @param[in]   add : Register address
 * @param[in]   data : Written data.
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_WriteByte(add, data);
 * @endcode     
 * @par         Modify
 *              TCS34725_WriteByte(uint8_t add, uint8_t data)
 ******************************************************************************
 */
static void TCS34725_WriteByte(uint8_t add, uint8_t data)
{
    //Note: remember to add this when users write their own
    //Responsible for not finding the register, 
    //refer to the data sheet Command Register CMD(Bit 7)
    add = add | TCS34725_CMD_BIT;
    DEV_I2C_WriteByte(add, data);
}

/**
 ******************************************************************************
 * @brief       TCS34725 Read Byte
 * @details     Read a byte to TCS34725
 * @param[in]   add : Register address
 * @return      TCS34725 Register value
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_ReadByte(add);
 * @endcode     
 * @par         Modify
 *              TCS34725_ReadByte(uint8_t add)
 ******************************************************************************
 */
static uint8_t TCS34725_ReadByte(uint8_t add)
{
    add = add | TCS34725_CMD_BIT;
    return DEV_I2C_ReadByte(add);
}

/**
 ******************************************************************************
 * @brief       TCS34725 Read word
 * @details     Read a word to TCS34725
 * @param[in]   add : Register address
 * @return      TCS34725 Register value
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_ReadWord(add);
 * @endcode     
 * @par         Modify
 *              TCS34725_ReadWord(uint8_t add)
 ******************************************************************************
 */
static uint16_t TCS34725_ReadWord(uint8_t add)
{
    add = add | TCS34725_CMD_BIT;
    return DEV_I2C_ReadWord(add);
}

/**
 ******************************************************************************
 * @brief       TCS34725 wake up
 * @details     Touch TCS34725 wake up
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Enable();
 * @endcode     
 * @par         Modify
 *              TCS34725_Enable(void)
 ******************************************************************************
 */
static void TCS34725_Enable(void)
{
    TCS34725_WriteByte(TCS34725_ENABLE, TCS34725_ENABLE_PON);
    DEV_Delay_ms(3);
    TCS34725_WriteByte(TCS34725_ENABLE, TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN);
    DEV_Delay_ms(3);
}

/**
 ******************************************************************************
 * @brief       TCS34725 Disable
 * @details     TCS34725 Sleep
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Disable();
 * @endcode     
 * @par         Modify
 *              void TCS34725_Disable(void)
 ******************************************************************************
 */
void TCS34725_Disable(void)
{
    /* Turn the device off to save power */
    uint8_t reg = 0;
    reg = TCS34725_ReadByte(TCS34725_ENABLE);
    TCS34725_WriteByte(TCS34725_ENABLE, reg & ~(TCS34725_ENABLE_PON | TCS34725_ENABLE_AEN));
}

/**
 ******************************************************************************
 * @brief       TCS34725 Set Integration Time
 * @details     TCS34725 Set Integration Time
 * @param[in]   time : Integration Time Reference "TCS34725.h" Enumeration Type
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Set_Integration_Time(TCS34725_INTEGRATIONTIME_2_4MS);
                TCS34725_Set_Integration_Time(TCS34725_INTEGRATIONTIME_24MS);
                TCS34725_Set_Integration_Time(TCS34725_INTEGRATIONTIME_50MS);
                TCS34725_Set_Integration_Time(TCS34725_INTEGRATIONTIME_101MS);
                TCS34725_Set_Integration_Time(TCS34725_INTEGRATIONTIME_154MS);
                TCS34725_Set_Integration_Time(TCS34725_INTEGRATIONTIME_700MS);
 * @endcode     
 * @par         Modify
 *              void TCS34725_Set_Integration_Time(TCS34725IntegrationTime_t time)
 ******************************************************************************
 */
void TCS34725_Set_Integration_Time(TCS34725IntegrationTime_t time)
{
    /* Update the timing register */
    TCS34725_WriteByte(TCS34725_ATIME, time);
    IntegrationTime_t = time;
}

/**
 ******************************************************************************
 * @brief       TCS34725 Set gain
 * @details     TCS34725 Set gain
 * @param[in]   gain: gain Reference "TCS34725.h" Enumeration Type
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Set_Gain(TCS34725_GAIN_1X);
                TCS34725_Set_Gain(TCS34725_GAIN_4X);
                TCS34725_Set_Gain(TCS34725_GAIN_16X);
                TCS34725_Set_Gain(TCS34725_GAIN_60X);
 * @endcode     
 * @par         Modify
 *              void TCS34725_Set_Gain(TCS34725Gain_t gain)
 ******************************************************************************
 */
void TCS34725_Set_Gain(TCS34725Gain_t gain)
{
    TCS34725_WriteByte(TCS34725_CONTROL, gain); 
    Gain_t = gain;
}

/**
 ******************************************************************************
 * @brief       Interrupt Enable
 * @details     Enable Interrupt
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Interrupt_Enable();
 * @endcode     
 * @par         Modify
 *              TCS34725_Interrupt_Enable()
 ******************************************************************************
 */
void TCS34725_Interrupt_Enable(void)
{
    uint8_t data = 0;
    data = TCS34725_ReadByte(TCS34725_ENABLE);
    TCS34725_WriteByte(TCS34725_ENABLE, data | TCS34725_ENABLE_AIEN);
}

/**
 *****************************************************************************
 * @brief       Interrupt Disable
 * @details     Disable Interrupt
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Interrupt_Disable();
 * @endcode     
 * @par         Modify
 *              TCS34725_Interrupt_Disable()
 ******************************************************************************
 */
void TCS34725_Interrupt_Disable(void)
{
    uint8_t data = 0;
    data = TCS34725_ReadByte(TCS34725_ENABLE);
    TCS34725_WriteByte(TCS34725_ENABLE, data & (~TCS34725_ENABLE_AIEN));
}

/**
 ******************************************************************************
 * @brief       Interrupt Disable
 * @details     Set Interrupt Persistence register, Interrupts need to be maintained for several cycles.
 * @param[in]   TCS34725_PER reference "TCS34725.h"
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_NONE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_1_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_2_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_3_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_5_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_10_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_15_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_20_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_25_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_30_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_35_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_40_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_45_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_50_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_55_CYCLE);
                TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_60_CYCLE);
 * @endcode     
 * @par         Modify
 *              TCS34725_Set_Interrupt_Persistence_Reg(uint8_t TCS34725_PER)
 ******************************************************************************
 */
static void TCS34725_Set_Interrupt_Persistence_Reg(uint8_t TCS34725_PER)
{
    if(TCS34725_PER < 0x10)
        TCS34725_WriteByte(TCS34725_PERS, TCS34725_PER);
    else 
        TCS34725_WriteByte(TCS34725_PERS, TCS34725_PERS_60_CYCLE);
}

/**
 ******************************************************************************
 * @brief       Set Interrupt Threshold
 * @details     Two 16-bit interrupt threshold registers allow the user to set limits 
 *              below and above a desired light level. An interrupt can be generated 
 *              when the Clear data (CDATA) is less than the Clear interrupt low 
 *              threshold (AILTx) or is greater than the Clear interrupt high 
 *              threshold (AIHTx)(Clear is the Clear ADC Channel Data Registers)
 * @param[in]   Threshold_H : (AILTx) RGBC clear channel low threshold.
 * @param[in]   Threshold_L : (AIHTx) RGBC clear channel high threshold.
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Set_Interrupt_Threshold(0xff00, 0x00ff); //Interrupt upper and lower threshold
 * @endcode     
 * @par         Modify
 *              TCS34725_Set_Interrupt_Threshold(uint16_t Threshold_H, uint16_t Threshold_L)
 ******************************************************************************
 */
static void TCS34725_Set_Interrupt_Threshold(uint16_t Threshold_H, uint16_t Threshold_L)
{
    TCS34725_WriteByte(TCS34725_AILTL, Threshold_L & 0xff);
    TCS34725_WriteByte(TCS34725_AILTH, Threshold_L >> 8);
    TCS34725_WriteByte(TCS34725_AIHTL, Threshold_H & 0xff);
    TCS34725_WriteByte(TCS34725_AIHTH, Threshold_H >> 8);
}

/**
 ******************************************************************************
 * @brief       Clear interrupt flag
 * @details     Clear interrupt flag
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Clear_Interrupt_Flag();
 * @endcode     
 * @par         Modify
 *              TCS34725_Clear_Interrupt_Flag(void)
 ******************************************************************************
 */
static void TCS34725_Clear_Interrupt_Flag(void)
{
    TCS34725_WriteByte(TCS34725_CMD_Clear_INT, 0x00);
}

/**
 ******************************************************************************
 * @brief       TCS34725 initialization
 * @details     gain Reference "TCS34725.h" Enumeration Type
 *              Integration Time Reference "TCS34725.h" Enumeration Type
 * @return      0 : Success
 *              1 : Failure
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Init();
 * @endcode     
 * @par         Modify
 *              uint8_t TCS34725_Init(void)
 ******************************************************************************
 */
uint8_t TCS34725_Init(void)
{
    uint8_t ID = 0;
    DEV_Set_I2CAddress(TCS34725_ADDRESS);
    ID = TCS34725_ReadByte(TCS34725_ID);
    if(ID != 0x44 && ID != 0x4D){
        return 1;
    }
    //Set the integration time and gain
    TCS34725_Set_Integration_Time(TCS34725_INTEGRATIONTIME_154MS);
    TCS34725_Set_Gain(TCS34725_GAIN_60X);

    IntegrationTime_t = TCS34725_INTEGRATIONTIME_154MS;
    Gain_t = TCS34725_GAIN_60X;

    //Set Interrupt
    TCS34725_Set_Interrupt_Threshold(0xff00, 0x00ff);       //Interrupt upper and lower threshold
    TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_2_CYCLE);
    TCS34725_Enable();
    TCS34725_Interrupt_Enable();

    //Set the LCD brightness
    TCS34725_SetLight(0);

    return 0;
}

/**
 ******************************************************************************
 * @brief       TCS34725 Read RGBC data
 * @details     Read RGBC data
 * @return      RGBC : Red / Green / Blue / Clear Numerical value,Is a pointer.
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Get_RGBData();
 * @endcode     
 * @par         Modify
 *              TCS34725_Get_RGBData(void)
 ******************************************************************************
 */
RGB TCS34725_Get_RGBData(void)
{
    RGB temp;
    temp.C = TCS34725_ReadWord(TCS34725_CDATAL | TCS34725_CMD_Read_Word);
    temp.R = TCS34725_ReadWord(TCS34725_RDATAL | TCS34725_CMD_Read_Word);
    temp.G = TCS34725_ReadWord(TCS34725_GDATAL | TCS34725_CMD_Read_Word);
    temp.B = TCS34725_ReadWord(TCS34725_BDATAL | TCS34725_CMD_Read_Word);

    switch (IntegrationTime_t){
        case TCS34725_INTEGRATIONTIME_2_4MS:
              DEV_Delay_ms(3);
              break;
        case TCS34725_INTEGRATIONTIME_24MS:
              DEV_Delay_ms(24);
              break;
        case TCS34725_INTEGRATIONTIME_50MS:
              DEV_Delay_ms(50);
              break;
        case TCS34725_INTEGRATIONTIME_101MS:
              DEV_Delay_ms(101);
              break;
        case TCS34725_INTEGRATIONTIME_154MS:
              DEV_Delay_ms(154);
              break;
        case TCS34725_INTEGRATIONTIME_700MS:
              DEV_Delay_ms(700);
              break;
    }
    return temp;
}

/**
 ******************************************************************************
 * @brief       TCS34725 Read RGBC data
 * @details     Converts the raw R/G/B values to color temperature in degrees Kelvin.
 * @param[in]   Threshold_H :
 * @param[in]   Threshold_L : 
 * @return      0 : Success
 *              1 : Failure
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                Temp = TCS34725_GetLux_Interrupt(0xff00, 0x0Cff);
                if(TCS34725_GetLux_Interrupt(0xff00, 0x0Cff) == 1)
 * @endcode     
 * @par         Modify
 *              TCS34725_GetLux_Interrupt(uint16_t Threshold_H, uint16_t Threshold_L)
 ******************************************************************************
 */
uint8_t TCS34725_GetLux_Interrupt(uint16_t Threshold_H, uint16_t Threshold_L)
{
    TCS34725_Set_Interrupt_Threshold(Threshold_H, Threshold_L);
    if(PB7 == 0){
        TCS34725_Clear_Interrupt_Flag();
        TCS34725_Set_Interrupt_Persistence_Reg(TCS34725_PERS_2_CYCLE);
        return 1;
    }
    return 0;
}

/**
 ******************************************************************************
 * @brief       get Color Temp
 * @details     Converts the raw R/G/B values to color temperature in degrees Kelvin.
 * @param[in]   rgb : RGBC Numerical value.
 * @return      Color Temp
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Get_ColorTemp(rgb);
 * @endcode     
 * @par         Modify
 *              TCS34725_Get_ColorTemp(RGB rgb)
 ******************************************************************************
 */
uint16_t TCS34725_Get_ColorTemp(RGB rgb)
{
    float cct;
    uint16_t r_comp, b_comp, ir;

    ir = (rgb.R + rgb.G + rgb.B > rgb.C) ? (rgb.R + rgb.G + rgb.B - rgb.C) / 2 : 0;
    r_comp = rgb.R - ir;
    b_comp = rgb.B - ir;
    cct = ((float)TCS34725_CT_Coef) * ((float)b_comp) / ((float)r_comp) + ((float)TCS34725_CT_Offset);

    return (uint16_t)cct;
}

/**
 ******************************************************************************
 * @brief       get Lux
 * @details     Converts the raw R/G/B values to lux
 * @param[in]   rgb : RGBC Numerical value.
 * @return      brightness(unit Lux)
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Get_Lux(rgb);
 * @endcode     
 * @par         Modify
 *              TCS34725_Get_Lux(RGB rgb)
 ******************************************************************************
 */
uint16_t TCS34725_Get_Lux(RGB rgb)
{
    float lux, cpl, atime_ms, Gain_temp = 1;
    uint16_t ir = 1;
    uint16_t r_comp, g_comp, b_comp;

    atime_ms = (((float)(256 - IntegrationTime_t)) * ((float)2.4));
    ir = (rgb.R + rgb.G + rgb.B > rgb.C) ? (rgb.R + rgb.G + rgb.B - rgb.C) / 2 : 0;
    r_comp = rgb.R - ir;
    g_comp = rgb.G - ir;
    b_comp = rgb.B - ir;

    switch (Gain_t)
    {
        case TCS34725_GAIN_1X:
              Gain_temp = 1;
              break;
        case TCS34725_GAIN_4X:
              Gain_temp = 4;
              break;
        case TCS34725_GAIN_16X:
              Gain_temp = 16;
              break;
        case TCS34725_GAIN_60X:
              Gain_temp = 60;
              break;
    }
    cpl = (atime_ms * Gain_temp) / ((float)(TCS34725_GA * TCS34725_DF));

    lux = (((float)TCS34725_R_Coef) * ((float)r_comp) + ((float)TCS34725_G_Coef) * \
            ((float)g_comp) + ((float)TCS34725_B_Coef) * ((float)b_comp)) / ((float)cpl);
    return (uint16_t)lux;
}

/**
 ******************************************************************************
 * @brief       Get RGB888
 * @details     Convert raw RGB values to RGB888 format
 * @param[in]   rgb : RGBC Numerical value
 * @return      R / G / B Color Value.
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Get_RGB888(rgb);
 * @endcode     
 * @par         Modify
 *              TCS34725_Get_RGB888(RGB rgb)
 ******************************************************************************
 */
uint32_t TCS34725_Get_RGB888(RGB rgb)
{
    float i = 1;
    //Limit data range
    if(rgb.R >= rgb.G && rgb.R >= rgb.B){
        i = rgb.R / 255 + 1;
    }
    else if(rgb.G >= rgb.R && rgb.G >= rgb.B){
        i = rgb.G / 255 + 1;
    }
    else if(rgb.B >=  rgb.G && rgb.B >= rgb.R){
        i = rgb.B / 255 + 1;
    }
    if(i != 0)
    {
        rgb.R = (uint16_t)(((float)rgb.R) / i);
        rgb.G = (uint16_t)(((float)rgb.G) / i);
        rgb.B = (uint16_t)(((float)rgb.B) / i);
    }
    //Amplify data differences
    /*Please don't try to make the data negative,
        unless you don't change the data type*/
    if(rgb.R > 30)
        rgb.R = rgb.R - 30;
    if(rgb.G > 30)
        rgb.G = rgb.G - 30;
    if(rgb.B > 30)
        rgb.B = rgb.B - 30;
    rgb.R = rgb.R * 255 / 225;
    rgb.G = rgb.G * 255 / 225;
    rgb.B = rgb.B * 255 / 225;

    if(rgb.R>255)
           rgb.R = 255;
    if(rgb.G>255)
           rgb.G = 255;
    if(rgb.B>255)
           rgb.B = 255;
    return (((uint32_t)rgb.R) << 16) | (((uint32_t)rgb.G) << 8) | ((uint32_t)rgb.B);
}

/**
 ******************************************************************************
 * @brief       Get RGB565
 * @details     Convert raw RGB values to RGB565 format
 * @param[in]   rgb : RGBC Numerical value
 * @return      R / G / B Color Value for RGB565 format.
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_Get_RGB565(rgb);
 * @endcode     
 * @par         Modify
 *              TCS34725_Get_RGB565(RGB rgb)
 ******************************************************************************
 */
uint16_t TCS34725_Get_RGB565(RGB rgb)
{
    float i = 1;
    //Limit data range
    if(rgb.R >= rgb.G && rgb.R >= rgb.B){ 
        i = rgb.R / 255 + 1;
    }
    else if(rgb.G >= rgb.R && rgb.G >= rgb.B){ 
        i = rgb.G / 255 + 1;
    }
    else if(rgb.B >=  rgb.G && rgb.B >= rgb.R){ 
        i = rgb.B / 255 + 1;  
    }
    if(i != 0){
        rgb.R = (uint16_t)(((float)rgb.R) / i);
        rgb.G = (uint16_t)(((float)rgb.G) / i);
        rgb.B = (uint16_t)(((float)rgb.B) / i);
    }
    if(rgb.R > 30)
        rgb.R = rgb.R - 30;
    if(rgb.G > 30)
        rgb.G = rgb.G - 30;
    if(rgb.B > 30)
        rgb.B = rgb.B - 30;

    rgb.R = rgb.R * 255 / 225;
    rgb.G = rgb.G * 255 / 225;
    rgb.B = rgb.B * 255 / 225;
    
    if(rgb.R>255)
           rgb.R = 255; 
    if(rgb.G>255)
           rgb.G = 255; 
    if(rgb.B>255)
           rgb.B = 255; 
    return (((uint16_t)(rgb.R << 11)) | ((uint16_t)(rgb.G << 5)) | ((uint16_t)(rgb.B)));
}

/**
 ******************************************************************************
 * @brief       Set Light
 * @details     Set the onboard LED brightness
 * @param[in]   value : = 0 : Light Off
 *                      > 0 : Light ON
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                TCS34725_SetLight(0);
                TCS34725_SetLight(1);
 * @endcode     
 * @par         Modify
 *              TCS34725_SetLight(uint16_t value)
 ******************************************************************************
 */
void TCS34725_SetLight(uint16_t value)
{
    PB6 = 0;
    if(value != 0)
    {
        PB6 = 1;
    }

//    if(value <= 100){
//        value = value * DEV_PWM_value / 100;
//        DEV_Set_PWM(value);
//    }
}

/*
 ******************************************************************************
 *
 ******************************************************************************
 */
static uint16_t TargetAddress = TCS34725_SlaveAddr; 

/**
 *******************************************************************************
 * @brief       Set I2C Target Address.
 * @details     I2C Write and Read.
 * @param[in]   TargetAddr : 0 ~ 127
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                DEV_Set_I2CAddress(TCS34725_ADDRESS);
                DEV_Set_I2CAddress((0x29<<1));
 * @endcode     
 * @par         Modify
 *              DEV_Set_I2CAddress(uint8_t TargetAddr)
 *******************************************************************************
 */
void DEV_Set_I2CAddress(uint8_t TargetAddr)
{
    TargetAddress = TargetAddr;
}

/**
 *******************************************************************************
 * @brief       I2C Byte Write .
 * @details     I2C Byte Write Register.
 * @param[in]   RegAddr :
 * @param[in]   Data :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                DEV_I2C_WriteByte(add, data);
                DEV_I2C_WriteByte(0x00, 0x00);
 * @endcode     
 * @par         Modify
 *              void DEV_I2C_WriteByte(uint8_t RegAddr, uint8_t Data)
 *******************************************************************************
 */
void DEV_I2C_WriteByte(uint8_t RegAddr, uint8_t Data)
{
    // HAL_I2C_Mem_Write(&hi2c1, IIC_Addr_t, add_, I2C_MEMADD_SIZE_8BIT, Buf, 1, 0x10);
    I2C_BusStart(I2C0);
    I2C_Transmiter(I2C0, (uint8_t)(TargetAddress & 0xFE));  // TCS34725 Salve Address
    I2C_Transmiter(I2C0, RegAddr);                          // TCS34725 Register Address
    I2C_Transmiter(I2C0, Data);                             // TCS34725 Register Data
    I2C_Master_BusStop(I2C0);
}

/**
 *******************************************************************************
 * @brief       I2C word Write Register.
 * @details     I2C word Write Register.
 * @param[in]   RegAddr :
 * @param[in]   Data : 
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                DEV_I2C_WriteWord(0x00, 0x0000);
 * @endcode     
 * @par         Modify
 *              void DEV_I2C_WriteWord(uint8_t RegAddr, uint16_t Data)
 *******************************************************************************
 */
void DEV_I2C_WriteWord(uint8_t RegAddr, uint16_t Data)
{
    union{
        uint16_t H;
        uint8_t  B[2];
    }lH_B;

    lH_B.H = Data;
    //HAL_I2C_Mem_Write(&hi2c1, IIC_Addr_t, add_, I2C_MEMADD_SIZE_8BIT, Buf, 2, 0x10);
    I2C_BusStart(I2C0);
    I2C_Transmiter(I2C0, (uint8_t)(TargetAddress & 0xFE));  // TCS34725 Salve Address
    I2C_Transmiter(I2C0, RegAddr);                          // TCS34725 Register Address
    I2C_Transmiter(I2C0, lH_B.B[0]);                        // TCS34725 Register Data
    I2C_Transmiter(I2C0, lH_B.B[1]);                        // TCS34725 Register Data
    I2C_Master_BusStop(I2C0);
}

/**
 *******************************************************************************
 * @brief       I2C Read Register.
 * @details     I2C Read Register.
 * @param[in]   RegAddr :
 * @return      Register value.
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                DEV_I2C_ReadByte(add);
                DEV_I2C_ReadByte(0x00);
 * @endcode     
 * @par         Modify
 *              DEV_I2C_ReadByte(uint8_t RegAddr)
 *******************************************************************************
 */
uint8_t DEV_I2C_ReadByte(uint8_t RegAddr)
{
    uint8_t lrData;
    //HAL_I2C_Mem_Read(&hi2c1, IIC_Addr_t, add_, I2C_MEMADD_SIZE_8BIT, Buf, 1, 0x10);
    I2C_BusStart(I2C0);
    I2C_Transmiter(I2C0, (uint8_t)TargetAddress);           // TCS34725 Salve Address
    I2C_Transmiter(I2C0, RegAddr);                          // TCS34725 Register Address
    I2C_BusStart(I2C0);                                     // Repeated Start
    I2C_Transmiter(I2C0, (uint8_t)(TargetAddress | 0x01));  // TCS34725 Salve Address
    I2C_Receive(I2C0, &lrData, I2C_NACK);                   // TCS34725 Read Data
    I2C_Master_BusStop(I2C0);
    return lrData;
}

/**
 *******************************************************************************
 * @brief       I2C Word Read Register.
 * @details     I2C Word Read Register.
 * @param[in]   RegAddr : 0 - 100
 * @return      Register word value.
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                DEV_I2C_ReadWord(0x00);
 * @endcode     
 * @par         Modify
 *              DEV_I2C_ReadWord(uint8_t RegAddr)
 *******************************************************************************
 */
uint16_t DEV_I2C_ReadWord(uint8_t RegAddr)
{
    union{
        uint16_t H;
        uint8_t  B[2];
    }lrH_B;

    // HAL_I2C_Mem_Read(&hi2c1, IIC_Addr_t, add_, I2C_MEMADD_SIZE_8BIT, Buf, 2, 0x10);
    I2C_BusStart(I2C0);
    I2C_Transmiter(I2C0, (uint8_t)TargetAddress);           // TCS34725 Salve Address
    I2C_Transmiter(I2C0, RegAddr);                          // TCS34725 Register Address
    I2C_BusStart(I2C0);                                     // Repeated Start
    I2C_Transmiter(I2C0, (uint8_t)(TargetAddress | 0x01));  // TCS34725 Salve Address
    I2C_Receive(I2C0, &lrH_B.B[0], I2C_ACK);                // TCS34725 Read Data 1
    I2C_Receive(I2C0, &lrH_B.B[1], I2C_NACK);               // TCS34725 Read Data 2
    I2C_Master_BusStop(I2C0);

    return lrH_B.H;
}

/**
 ******************************************************************************
 * @brief       Sample GPIO Initialize
 * @details     GPIO Initialize for TCS34725.
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                Sample_GPIO_Init();
 * @endcode     
 * @par         Modify
 *              Sample_GPIO_Init(void)
 ******************************************************************************
 */
void Sample_GPIO_Init(void)
{
    PIN_InitTypeDef PINX_InitStruct;

  // 1.0 GPIO Pin Config
    PINX_InitStruct.PINX_Pin                = PX_Pin_7;
    PINX_InitStruct.PINX_Mode               = PINX_Mode_Digital_I;
    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_Inverse            = PINX_Inverse_Disable;
    PINX_InitStruct.PINX_Alternate_Function = 0;
    GPIO_PortMode_Config(IOMB, &PINX_InitStruct);

    PINX_InitStruct.PINX_Pin                = PX_Pin_6;
    PINX_InitStruct.PINX_Mode               = PINX_Mode_PushPull_O;
    GPIO_PortMode_Config(IOMB, &PINX_InitStruct);
}

/**
 *******************************************************************************
 * @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_I2C0_Init();
 * @endcode     
 * @par         Modify
 *              Sample_I2C0_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;
    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_2);               // 11.0592MHz
    I2C_SetSCLHighTime(I2C0, 29);                           // High Time Must >= 5CLK, 
    I2C_SetSCLLowTime(I2C0, 28);                            // 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), DISABLE);

  // 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 : I2C0 / 1
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
 *              I2C_BusStart(I2Cx);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef I2C_BusStart(I2C_Struct* I2Cx)
 *******************************************************************************
 */
Sample_StatusTypeDef I2C_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 : I2C0 / 1
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                I2C_Master_BusStop(I2C0);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef I2C_Master_BusStop(I2C_Struct* I2Cx)
 *******************************************************************************
 */
Sample_StatusTypeDef I2C_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 : I2C0 / 1
 * @param[in]   TxData : Value of Output Data
 * @return      Sample_SUCCESS :
 *              Sample_FAILURE :
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                I2C_Transmiter(I2C0, (uint8_t *)&TxBuff)
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef I2C_Transmiter(I2C_Struct* I2Cx, uint8_t TxData)
 *******************************************************************************
 */
Sample_StatusTypeDef I2C_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 : I2C0 / 1
 * @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        
                I2C_Receive(I2C0, (uint8_t *)&RxBuff, I2C_ACK);
                I2C_Receive(I2C0, (uint8_t *)&RxBuff, I2C_NACK);
 * @endcode     
 * @par         Modify
 *              Sample_StatusTypeDef I2C_Receive(I2C_Struct* I2Cx, uint8_t *RxData, uint8_t Acknowledge)
 *******************************************************************************
 */
Sample_StatusTypeDef I2C_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 0x58:
        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;
    }
}

#define URTX    URT0    /*!< UART Connect to PC Module                                          */
/**
 *******************************************************************************
 * @brief       Sample URT0 initial
 * @details     1. Set CSC initial.
 *     \n       2. Set GPIO initial.
 *     \n       3. Set RX/TX Baudrate.
 *     \n       4. Set data character.
 *     \n       5. Set URT0 mode.
 *     \n       6. Set Data line.
 *     \n       7. Set Data buffer control.
 *     \n       8. Enable URT0 interrupt.
 *     \n       9. Enable URT0 
 *     \n      10. Receive data into interrupt function.
 *     \n      11. Send data of receive.
 * @exception   No
 * @note
 * @par         Example
 * @code            Sample_URT0_Init();
 * @endcode
 * @par         Modify
 *                  void Sample_URT0_Init(void)
 *******************************************************************************
 */
void Sample_URT0_Init(void)
{
    PIN_InitTypeDef PINX_InitStruct;
    URT_BRG_TypeDef  URT_BRG;
    URT_Data_TypeDef DataDef;

    //==Set CSC init
    //MG32_CSC_Init.h(Configuration Wizard)
    //Select CK_HS source = CK_IHRCO
    //Select IHRCO = 11.0592M
    //Select CK_MAIN Source = CK_HS
    //Configure PLL->Select APB Prescaler = CK_MAIN/1
    //Configure Peripheral On Mode Clock->Port B/URT0 = Enable
    //Configure Peripheral On Mode Clock->URT0->Select URT0_PR Source = CK_APB(11.0592)
    // 1.0 GPIO IOMB Filter Config

    //==Set GPIO init
    //MG32_GPIO_Init.h(Configuration Wizard)->Use GPIOB->Pin8/9
    //GPIO port initial is 0xFFFF
    //Pin8 mode is PPO/Pin9 mode is ODO
    //Pin8/9 pull-up resister Enable
    //Pin8/9 function URT0_TX/RX

    // 1.1 I2c AFS Pin Config
    PINX_InitStruct.PINX_Pin                = PX_Pin_8;
    PINX_InitStruct.PINX_Mode               = PINX_Mode_PushPull_O;
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Disable;
    PINX_InitStruct.PINX_Speed              = PINX_Speed_High;
    PINX_InitStruct.PINX_OUTDrive           = PINX_OUTDrive_Level0;
    PINX_InitStruct.PINX_Inverse            = PINX_Inverse_Disable;
    PINX_InitStruct.PINX_FilterDivider      = PINX_FilterDivider_Bypass;
    PINX_InitStruct.PINX_Alternate_Function = 3;
    GPIO_PortMode_Config(IOMB, &PINX_InitStruct);

    PINX_InitStruct.PINX_Pin                = PX_Pin_9;
    PINX_InitStruct.PINX_Mode               = PINX_Mode_Digital_I;
    PINX_InitStruct.PINX_PUResistant        = PINX_PUResistant_Enable;
    GPIO_PortMode_Config(IOMB, &PINX_InitStruct);

    //=====Set Clock=====//
    //---Set BaudRate---//
    URT_BRG.URT_InternalClockSource = URT_BDClock_PROC;
    URT_BRG.URT_BaudRateMode = URT_BDMode_Separated;
    URT_BRG.URT_PrescalerCounterReload = 0;                 //Set PSR
    URT_BRG.URT_BaudRateCounterReload = 12;                 //Set RLR
    URT_BaudRateGenerator_Config(URTX, &URT_BRG);           //BR115200 = f(CK_URTx)/(PSR+1)/(RLR+1)/(OS_NUM+1)
    URT_BaudRateGenerator_Cmd(URTX, ENABLE);                //Enable BaudRateGenerator

    //---TX/RX Clock---//
    URT_TXClockSource_Select(URTX, URT_TXClock_Internal);   //URT_TX use BaudRateGenerator
    URT_RXClockSource_Select(URTX, URT_RXClock_Internal);   //URT_RX use BaudRateGenerator
    URT_TXOverSamplingSampleNumber_Select(URTX, 31);        //Set TX OS_NUM
    URT_RXOverSamplingSampleNumber_Select(URTX, 31);        //Set RX OS_NUM
    URT_RXOverSamplingMode_Select(URTX, URT_RXSMP_3TIME);
    URT_TX_Cmd(URTX, ENABLE);                               //Enable TX
    URT_RX_Cmd(URTX, ENABLE);                               //Enable RX

    //=====Set Mode=====//
    //---Set Data character config---//
    DataDef.URT_TX_DataLength  = URT_DataLength_8;
    DataDef.URT_RX_DataLength  = URT_DataLength_8;
    DataDef.URT_TX_DataOrder   = URT_DataTyped_LSB;
    DataDef.URT_RX_DataOrder   = URT_DataTyped_LSB;
    DataDef.URT_TX_Parity      = URT_Parity_No;
    DataDef.URT_RX_Parity      = URT_Parity_No;
    DataDef.URT_TX_StopBits    = URT_StopBits_1_0;
    DataDef.URT_RX_StopBits    = URT_StopBits_1_0;
    DataDef.URT_TX_DataInverse = DISABLE;
    DataDef.URT_RX_DataInverse = DISABLE;
    URT_DataCharacter_Config(URTX, &DataDef);

    //---Set Mode Select---//
    URT_Mode_Select(URTX, URT_URT_mode);

    //---Set DataLine Select---//
    URT_DataLine_Select(URTX, URT_DataLine_2);

    //=====Set Error Control=====//
    // to do...

    //=====Set Bus Status Detect Control=====//
    // to do...

    //=====Set Data Control=====//
    URT_RXShadowBufferThreshold_Select(URTX, URT_RXTH_1BYTE);
    URT_IdlehandleMode_Select(URTX, URT_IDLEMode_No);
    URT_TXGuardTime_Select(URTX, 0);

    //=====Enable URT Interrupt=====//
    URT_IT_Config(URTX, URT_IT_RX, ENABLE);
    URT_ITEA_Cmd(URTX, ENABLE);
    NVIC_EnableIRQ(URT0_IRQn);

    //=====Enable URT=====//
    URT_Cmd(URTX, ENABLE);
}


static volatile uint8_t gURT0_First = 0;    /*!< URT0 First Log                */
/**
 *******************************************************************************
 * @brief       writes the character specified by c (converted to an unsigned char) to
 *              the output stream pointed to by stream, at the position indicated by the
 *              asociated file position indicator (if defined), and advances the
 *              indicator appropriately. If the file position indicator is not defined,
 *              the character is appended to the output stream.
 * @param[in]   ch : This is the character to be written. This is passed as its int promotion.
 * @param[in]   f : This is the pointer to a FILE object that identifies the stream where the character is to be written.
 * @return      the character written. If a write error occurs, the error
 *              indicator is set and fputc returns EOF.
 *******************************************************************************
 */
int fputc(int ch, FILE *f __attribute__((unused)))
{
    if(gURT0_First == 0)
        gURT0_First = 1;
    else
        while((URT0->STA.W & URT_STA_TXF_mask_w) == 0);
    URT0->TDAT.B[0] = (uint8_t)ch;
    return ch;
}

/**
 *******************************************************************************
 * @brief       SysTick Handler
 * @details     SysTick Handler
 * @exception   None
 * @note        
 * @par         Example
 * @code        
                SysTick_Handler();
 * @endcode     
 * @par         Modify
 *              SysTick_Handler(void)
 *******************************************************************************
 */
void SysTick_Handler(void)
{
    IncTick();
}

