/******************************************************************************
 * @file     main.c
 * @brief    Main program body
 * @version  V4.0.1
 * @date     30-July-2026
 *
 * @note
 * Copyright (C) 2022 Spintrol Electronic Technology (Shanghai) Co., Ltd.. All rights reserved.
 *
 * @attention
 * THIS SOFTWARE JUST PROVIDES CUSTOMERS WITH CODING INFORMATION REGARDING
 * THEIR PRODUCTS, WHICH AIMS AT SAVING TIME FOR THEM. SPINTROL SHALL NOT BE
 * LIABLE FOR THE USE OF THE SOFTWARE. SPINTROL DOES NOT GUARANTEE THE
 * CORRECTNESS OF THIS SOFTWARE AND RESERVES THE RIGHT TO MODIFY THE SOFTWARE
 * WITHOUT NOTIFICATION.
 *
 ******************************************************************************/

#include<stdio.h>
#include<stdlib.h>

#if defined(SPC1158)
#include "spc1158.h"
#elif defined(SPD1148)
#include "spd1148.h"
#elif defined(SPD1178)
#include "spd1178.h"
#elif defined(SPD1188)
#include "spd1188.h"
#elif defined(SPD1163)
#include "spd1163.h"
#else
#include "spc1168.h"
#endif

/* I2C GPIO Config*/
#if defined(SPD1148)
    #define                 SDA_GPIO                   GPIO_31
    #define                 SCL_GPIO                   GPIO_30
    #define                 SDA_GPIO_FUNC              GPIO31_I2C_SDA
    #define                 SCL_GPIO_FUNC              GPIO30_I2C_SCL
#elif defined(SPD1163)
    #define                 SDA_GPIO                   GPIO_38
    #define                 SCL_GPIO                   GPIO_39
    #define                 SDA_GPIO_FUNC              GPIO38_I2C_SDA
    #define                 SCL_GPIO_FUNC              GPIO39_I2C_SCL
#else
    #define                 SDA_GPIO                   GPIO_13
    #define                 SCL_GPIO                   GPIO_12
    #define                 SDA_GPIO_FUNC              GPIO13_I2C_SDA
    #define                 SCL_GPIO_FUNC              GPIO12_I2C_SCL
#endif


#define                 DEBUG_INFO                 1
#define                 MASTER_TRANSMIT            1                      /* 1: master transmit 0: master receive */
#define                 Rx_FIFO_INT_TH             0xf                    /* Rx threshold as 16 entry */
#define                 Tx_FIFO_INT_TH             0x0                    /* Tx threshold as 1 entry */
#define                 TxRx_DATA_LEN              16                     /* Send receive 16 Byte */


#define                 T_BUFFER_SIZE              128
#define                 I2C_SPEED                  400000
#define                 I2C_Slave_ADDR             0x9                    /* IIC Slave ADDR */

uint32_t                gu32BuffSize                = T_BUFFER_SIZE;
uint8_t                 gau8TxBuf[T_BUFFER_SIZE];
uint8_t                 gau8RxBuf[T_BUFFER_SIZE];
uint32_t                u32IsrCnt = 0;
ErrorStatus             estatus;
uint32_t                num;
uint8_t                 u32DetectStart = 0;

static ErrorStatus Check_Receive_Data(void)
{
    int i;
    uint8_t u8Data = 0;

    /*To check the datum sent and received are the same*/
    for(i = 0; i < gu32BuffSize; i++)
    {
        if (gau8RxBuf[i] != u8Data)
        {
            #if DEBUG_INFO
            printf("[Error]@%4d: TX(0x%02X) != RX(0x%02X)\n", __LINE__, u8Data, gau8RxBuf[i]);
            #endif

            return ERROR;
        }
        else
        {
            #if DEBUG_INFO
            printf("%3d: TX(0x%02X) == RX(0x%02X)\n", i, u8Data, gau8RxBuf[i]);
            #endif
        }

        u8Data++;
    }

    return SUCCESS;
}

void I2C_Master_TxRX_data(I2C_REGS *I2Cx, I2C_AddrModeEnum eAddrMode, uint16_t u16TargetAddr, uint32_t u32Count)
{
    uint32_t i;
    uint8_t u8Data = 0;

    /* Set Address Mode */
    I2C->I2CMASTERADDR.bit.MASTERADDR10B = eAddrMode;

    /* Set Target Slave Address*/
    I2C->I2CMASTERADDR.bit.TARADDR = u16TargetAddr;

    if (MASTER_TRANSMIT)
    {
        /* Generate random datum to transmit */
        for(i = 0; i < gu32BuffSize; i++)
        {
            gau8TxBuf[i] = u8Data++;
            #if DEBUG_INFO
            printf("gau8TxBuf[%d] = 0x%x\n", i, gau8TxBuf[i]);
            #endif
        }

        printf("Master Tx data...\n");

        I2C_SetTxFIFOThreshold(I2C, Tx_FIFO_INT_TH);

        I2C_EnableTxDataRequestInt(I2C);
    }
    else
    {
        for (i = 0; i < TxRx_DATA_LEN; i++)
        {
            I2C_MasterReadCmd(I2C);

            if (u32DetectStart == 0)
            {
                while(I2C_GetStartDetectIntRawFlag(I2C) == 0) {}
                u32DetectStart = 1;
            }
        }

        printf("Master Rx data...\n");

        I2C_SetRxFIFOThreshold(I2C, Rx_FIFO_INT_TH);

        I2C_EnableRxDataAvailableInt(I2C);
    }

}


/*************************************************************************************************************************
 *
 * @brief      In this case, the IIC controller is used as master and sent datum to the slave and read these datum back to
 *             compare, if there is a item not equal with each other, the test FAIL.
 *
 * @note
 *             The slave device runs first, the master device runs later
 *
 *************************************************************************************************************************/


int main()
{
    FLASH_WALLOW();

#if defined(SPC1158)
    FLASH_SetTiming(100000000);
    /* Disable flash write access after flash operation had done */
    FLASH_WDIS();

    CLOCK_InitWithRCO(100000000UL);
#else
    FLASH_SetTiming(200000000);
    /* Disable flash write access after flash operation had done */
    FLASH_WDIS();

    CLOCK_InitWithRCO(200000000UL);
#endif

    Delay_Init();

    /*
     * Init the UART
     *
     * 1.Set the GPIO34/35 as UART FUNC
     *
     * 2.Enable the UART CLK
     *
     * 3.Set the rest para
     */
    GPIO_SetPinChannel(GPIO_34, GPIO34_UART_TXD);
    GPIO_SetPinChannel(GPIO_35, GPIO35_UART_RXD);
    CLOCK_EnableModule(UART_MODULE);
    UART_Init(UART, 38400);

    /* Config GPIO as I2C function */
    GPIO_SetPinChannel(SDA_GPIO, SDA_GPIO_FUNC);
    GPIO_SetPinChannel(SCL_GPIO, SCL_GPIO_FUNC);

    /*
     * Set Output Strength as 20mA, in case of many more
     * slaves are linking to the master.
     */
    GPIO_SetOutStrength(SDA_GPIO, GPIO_OUT_STRENGTH_20MA);
    GPIO_SetOutStrength(SCL_GPIO, GPIO_OUT_STRENGTH_20MA);

    /* Disable All INT */
    I2C_DisableAllInt(I2C);

    /* Clear All INT */
    I2C_ClearInt(I2C, I2C_INT_ALL);

    /* Init I2C as Master */
    estatus = I2C_MasterInit(I2C, I2C_SPEED, I2C_SPEED_FAST);
    if (estatus == ERROR)
    {
        #if DEBUG_INFO
        printf("[IIC master init FAIL] I2C clock is not fast enough to support the speed\n");
        #endif

        return 0;
    }

    /* Enable CM4 INT request */
    NVIC_EnableIRQ(I2C_IRQn);

    /* Master start to transmit and receive data */
    I2C_Master_TxRX_data(I2C, I2C_ADDR_7BIT, I2C_Slave_ADDR, gu32BuffSize);

    while (1)
    {

    }
}

void I2C_IRQHandler(void)
{
    int i;

    if (MASTER_TRANSMIT && (u32IsrCnt < T_BUFFER_SIZE))
    {
        /* Wait I2C Bus Idle */
        while (I2C_IsActivity(I2C)) { }

        if (I2C_IsTxEmpty(I2C))
        {
            for (i = 0; i < TxRx_DATA_LEN; i++)
            {
                I2C_WriteByte(I2C, gau8TxBuf[u32IsrCnt++]);

                if (u32DetectStart == 0)
                {
                    while(I2C_GetStartDetectIntRawFlag(I2C) == 0) {}
                    u32DetectStart = 1;
                }
            }
        }
    }
    else if (!MASTER_TRANSMIT && (u32IsrCnt < T_BUFFER_SIZE))
    {
        /* Read RxFIFO, Read Data */
        while(I2C_IsRxNotEmpty(I2C))
        {
            gau8RxBuf[u32IsrCnt++] = I2C_ReadByte(I2C);
        }

        for (i = 0; i < TxRx_DATA_LEN; i++)
        {
            I2C_MasterReadCmd(I2C);
        }
    }

    if (u32IsrCnt == T_BUFFER_SIZE)
    {
        if (MASTER_TRANSMIT)
        {
            I2C_DisableTxDataRequestInt(I2C);
        }
        else
        {
            I2C_DisableRxDataAvailableInt(I2C);
            estatus = Check_Receive_Data();
            if (estatus == ERROR)
            {
                return;
            }
        }

        printf("Success\n");
    }
    I2C_ClearInt(I2C, I2C_INT_ALL);
}
