/*
 ## USB 3.0 Platform source file (cyfxslfifosync.c)
 ## =========================================
 ##
 ##	 Soliton Technologies Private Limited
 ##	 Interface Between J56 and PC
 ##
 ##  Designer :- Gokul Prasath Nallasamy
 ##
 ##
 ## =========================================
*/

/* This file illustrates the I2C Register Write, SPI Flash R/W and Synchronous Slave FIFO mode*/

#include "cyu3system.h"
#include "cyu3i2c.h"
#include "cyu3os.h"
#include "cyu3dma.h"
#include "cyu3error.h"
#include "cyu3usb.h"
#include "cyfxslfifosync.h"
#include "cyfxconfigfpga.h"
#include "cyu3gpif.h"
#include "cyu3pib.h"
#include "pib_regs.h"
#include <cyu3gpio.h>
#include "cyu3uart.h"
#include "cyu3spi.h"

#include "cyfxslfifogpifreconfig.h"

#include "fx3_i2c_reg_mode.h"	//including i2c constants


#define CY_FX_GPIOAPP_GPIO_HIGH_EVENT    (1 << 0)   /* GPIO high event */
#define CY_FX_GPIOAPP_GPIO_LOW_EVENT     (1 << 1)   /* GPIO low event */

#define CY_U3P_LPP_GPIO_INTR (1<<27) /* Do not touch the interrupt bit */
#define OUT_VALUE 0x01 /* The 0th bit is the value that is output on the pins */


CyU3PThread slFifoAppThread;	        /* Slave FIFO application thread structure */
CyU3PDmaChannel glChHandleSlFifoUtoP;   /* DMA Channel handle for U2P transfer. */
CyU3PDmaChannel glChHandleSlFifoPtoU;   /* DMA Channel handle for P2U transfer. */

uint32_t glDMARxCount = 0;               /* Counter to track the number of buffers received from USB. */
uint32_t glDMATxCount = 0;               /* Counter to track the number of buffers sent to USB. */
CyBool_t glIsApplnActive = CyFalse;      /* Whether the loopback application is active or not. */
uint8_t *seqnum_slfifo;					/* Endpoint sequence number. Reference for this addition in Note
										AN84868 - Endpoint Configuration and Restoring the Sequence Number*/

//------------- Fw Mode Variable --------
uint32_t glApplnMode = MODE_NO_CONFIG;	/*Firmware Running Mode*/

/* Firmware ID variable that may be used to verify I2C firmware. */
const uint8_t glFirmwareID[32] __attribute__ ((aligned (32))) = { 'T', 'I', '1', '4', 'J', '5', '6', '\0' };

#ifdef SPI_ENABLE
uint16_t glSpiPageSize = 0x100;  /* SPI Page size to be used for transfers. */
#endif

uint8_t glEp0Buffer[4096] __attribute__ ((aligned (32)));

uint16_t glI2cPageSize = 0x02;	//0x40;   /* I2C Page size to be used for transfers. */



/* Application Error Handler */
void
CyFxAppErrorHandler (
        CyU3PReturnStatus_t apiRetStatus    /* API return status */
        )
{
    /* Application failed with the error code apiRetStatus */

    /* Add custom debug or recovery actions here */

    /* Loop Indefinitely */
    for (;;)
    {
        /* Thread sleep : 100 ms */
        CyU3PThreadSleep (100);
    }
}

/* This function initializes the debug module. The debug prints
 * are routed to the UART and can be seen using a UART console
 * running at 115200 baud rate. */
void
CyFxSlFifoApplnDebugInit (void)
{
#ifdef UART_ENABLE
    CyU3PUartConfig_t uartConfig;
    CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
    /* Initialize the UART for printing debug messages */
    apiRetStatus = CyU3PUartInit();
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        /* Error handling */
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Set UART configuration */
    CyU3PMemSet ((uint8_t *)&uartConfig, 0, sizeof (uartConfig));
    uartConfig.baudRate = CY_U3P_UART_BAUDRATE_115200;
    uartConfig.stopBit = CY_U3P_UART_ONE_STOP_BIT;
    uartConfig.parity = CY_U3P_UART_NO_PARITY;
    uartConfig.txEnable = CyTrue;
    uartConfig.rxEnable = CyFalse;
    uartConfig.flowCtrl = CyFalse;
    uartConfig.isDma = CyTrue;

    apiRetStatus = CyU3PUartSetConfig (&uartConfig, NULL);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Set the UART transfer to a really large value. */
    apiRetStatus = CyU3PUartTxSetBlockXfer (0xFFFFFFFF);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Initialize the debug module. */
    apiRetStatus = CyU3PDebugInit (CY_U3P_LPP_SOCKET_UART_CONS, 8);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        CyFxAppErrorHandler(apiRetStatus);
    }

    CyU3PDebugPrint (6, " UART Initialized successfully");
#endif
}

/* I2C initialization. */
void
CyFxApplnI2CInit (void)
{
    CyU3PI2cConfig_t i2cConfig;;
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    status = CyU3PI2cInit ();
    if (status != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "I2C initialization failed!\n");
		#endif
        CyFxAppErrorHandler (status);
    }

    /* Start the I2C master block. The bit rate is set at 1MHz.*/
    CyU3PMemSet ((uint8_t *)&i2cConfig, 0, sizeof(i2cConfig));
    i2cConfig.bitRate    = 1000000;      /*  1MHz */
    i2cConfig.isDma      = CyFalse;
    i2cConfig.busTimeout = 0xffffffffU;
    i2cConfig.dmaTimeout = 0xffff;

    status = CyU3PI2cSetConfig (&i2cConfig, 0);
    if (status != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "I2C configuration failed!\n");
		#endif
        CyFxAppErrorHandler (status);
    }
    else
    {
    	glI2cPageSize = CY_FX_USBI2C_I2C_PAGE_SIZE;
    }
}

/* DMA callback function to handle the produce events for U to P transfers. */
void
CyFxSlFifoUtoPDmaCallback (
        CyU3PDmaChannel   *chHandle,
        CyU3PDmaCbType_t  type,
        CyU3PDmaCBInput_t *input
        )
{
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if (type == CY_U3P_DMA_CB_PROD_EVENT)
    {
        /* This is a produce event notification to the CPU. This notification is 
         * received upon reception of every buffer. The buffer will not be sent
         * out unless it is explicitly committed. The call shall fail if there
         * is a bus reset / usb disconnect or if there is any application error. */
        status = CyU3PDmaChannelCommitBuffer (chHandle, input->buffer_p.count, 0);
        if (status != CY_U3P_SUCCESS)
        {
			#ifdef UART_ENABLE
            CyU3PDebugPrint (4, "CyU3PDmaChannelCommitBuffer failed, Error code = %d\n", status);
			#endif
        }

        /* Increment the counter. */
        glDMARxCount++;
    }
}

/* DMA callback function to handle the produce events for P to U transfers. */
void
CyFxSlFifoPtoUDmaCallback (
        CyU3PDmaChannel   *chHandle,
        CyU3PDmaCbType_t  type,
        CyU3PDmaCBInput_t *input
        )
{
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if (type == CY_U3P_DMA_CB_PROD_EVENT)
    {
        /* This is a produce event notification to the CPU. This notification is 
         * received upon reception of every buffer. The buffer will not be sent
         * out unless it is explicitly committed. The call shall fail if there
         * is a bus reset / usb disconnect or if there is any application error. */
        status = CyU3PDmaChannelCommitBuffer (chHandle, input->buffer_p.count, 0);
        if (status != CY_U3P_SUCCESS)
        {
			#ifdef UART_ENABLE
            CyU3PDebugPrint (4, "CyU3PDmaChannelCommitBuffer failed, Error code = %d\n", status);
			#endif
        }

        /* Increment the counter. */
        glDMATxCount++;
    }
}

/* This function starts the slave FIFO loop application. This is called
 * when a SET_CONF event is received from the USB host. The endpoints
 * are configured and the DMA pipe is setup in this function. */
void
CyFxSlFifoApplnStart (
        void)
{
    uint16_t size = 0;
    CyU3PEpConfig_t epCfg;
    CyU3PDmaChannelConfig_t dmaCfg;
    CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
    CyU3PUSBSpeed_t usbSpeed = CyU3PUsbGetSpeed();
    uint8_t burstLength =0;

    /* First identify the usb speed. Once that is identified,
     * create a DMA channel and start the transfer on this. */

#ifdef UART_ENABLE
	CyU3PDebugPrint (4, "\n...CyFxSlFifoApplnStart()...\n");
#endif

    /* Based on the Bus Speed configure the endpoint packet size */
    switch (usbSpeed)
    {
        case CY_U3P_FULL_SPEED:
            size = 64;
            break;

        case CY_U3P_HIGH_SPEED:
            size = 512;
            burstLength=1;
            break;

        case  CY_U3P_SUPER_SPEED:
            size = 1024;
            burstLength=16;
            break;

        default:
			#ifdef UART_ENABLE
            CyU3PDebugPrint (4, "Error! Invalid USB speed.\n");
			#endif
            CyFxAppErrorHandler (CY_U3P_ERROR_FAILURE);
            break;
    }

    CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg));
    epCfg.enable = CyTrue;
    epCfg.epType = CY_U3P_USB_EP_BULK;
#ifdef STREAM_IN_OUT
    epCfg.burstLen = burstLength;
#else
    epCfg.burstLen = BURST_LEN;
#endif
    epCfg.streams = 0;
    epCfg.pcktSize = size;

    /* Producer endpoint configuration */
    apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_PRODUCER, &epCfg);

    if (apiRetStatus != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\n", apiRetStatus);
		#endif
        CyFxAppErrorHandler (apiRetStatus);
    }

//    apiRetStatus = CyU3PUsbGetEpSeqNum(CY_FX_EP_PRODUCER, seqnum_slfifo);
//    if (apiRetStatus != CY_U3P_SUCCESS)
//    {
//		#ifdef UART_ENABLE
//        CyU3PDebugPrint (4, "CyU3PUsbGetEpSeqNum failed, Error code = %d\n", apiRetStatus);
//		#endif
//    }

    /* Consumer endpoint configuration */
    apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_CONSUMER, &epCfg);

    if (apiRetStatus != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\n", apiRetStatus);
		#endif
        CyFxAppErrorHandler (apiRetStatus);
    }

#ifdef MANUAL
    /* Create a DMA MANUAL channel for U2P transfer.
     * DMA size is set based on the USB speed. */
    dmaCfg.size  = size;
    dmaCfg.count = CY_FX_SLFIFO_DMA_BUF_COUNT;
    dmaCfg.prodSckId = CY_FX_PRODUCER_USB_SOCKET;
    dmaCfg.consSckId = CY_FX_CONSUMER_PPORT_SOCKET;
    dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
    /* Enabling the callback for produce event. */
    dmaCfg.notification = CY_U3P_DMA_CB_PROD_EVENT;
    dmaCfg.cb = CyFxSlFifoUtoPDmaCallback;
    dmaCfg.prodHeader = 0;
    dmaCfg.prodFooter = 0;
    dmaCfg.consHeader = 0;
    dmaCfg.prodAvailCount = 0;

    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleSlFifoUtoP,
            CY_U3P_DMA_TYPE_MANUAL, &dmaCfg);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
		#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Create a DMA MANUAL channel for P2U transfer. */
    dmaCfg.prodSckId = CY_FX_PRODUCER_PPORT_SOCKET;
    dmaCfg.consSckId = CY_FX_CONSUMER_USB_SOCKET;
    dmaCfg.cb = CyFxSlFifoPtoUDmaCallback;
    apiRetStatus = CyU3PDmaChannelCreate (&glChHandleSlFifoPtoU,
            CY_U3P_DMA_TYPE_MANUAL, &dmaCfg);

#endif


    /* Create a DMA AUTO channel for U2P transfer.
        * DMA size is set based on the USB speed. */

      dmaCfg.size  = DMA_BUF_SIZE* size ;
	  dmaCfg.count = CY_FX_SLFIFO_DMA_BUF_COUNT_U_2_P;
	  dmaCfg.prodSckId = CY_FX_PRODUCER_USB_SOCKET;
       dmaCfg.consSckId = CY_FX_CONSUMER_PPORT_SOCKET;
       dmaCfg.dmaMode = CY_U3P_DMA_MODE_BYTE;
       /* Enabling the callback for produce event. */
       dmaCfg.notification = 0;
       dmaCfg.cb = NULL;
       dmaCfg.prodHeader = 0;
       dmaCfg.prodFooter = 0;
       dmaCfg.consHeader = 0;
       dmaCfg.prodAvailCount = 0;

       apiRetStatus = CyU3PDmaChannelCreate (&glChHandleSlFifoUtoP,
               CY_U3P_DMA_TYPE_AUTO, &dmaCfg);
       if (apiRetStatus != CY_U3P_SUCCESS)
       {
			#ifdef UART_ENABLE
           	CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
			#endif
           CyFxAppErrorHandler(apiRetStatus);
       }
       else
       {
    	   CyU3PDebugPrint (4, " U2P DMA Channel created with %d bytes and there are %d buffers \n",DMA_BUF_SIZE*size ,CY_FX_SLFIFO_DMA_BUF_COUNT_U_2_P);
       }

       /* Create a DMA AUTO channel for P2U transfer. */
       dmaCfg.size  = DMA_BUF_SIZE*size; //increase buffer size for higher performance	+-+-+-+-
       dmaCfg.count = CY_FX_SLFIFO_DMA_BUF_COUNT_P_2_U; // increase buffer count for higher performance
       dmaCfg.prodSckId = CY_FX_PRODUCER_PPORT_SOCKET;
       dmaCfg.consSckId = CY_FX_CONSUMER_USB_SOCKET;
       dmaCfg.cb = NULL;
       apiRetStatus = CyU3PDmaChannelCreate (&glChHandleSlFifoPtoU,
               CY_U3P_DMA_TYPE_AUTO, &dmaCfg);


    if (apiRetStatus != CY_U3P_SUCCESS)
    {
    	#ifdef UART_ENABLE
       	CyU3PDebugPrint (4, "CyU3PDmaChannelCreate failed, Error code = %d\n", apiRetStatus);
		#endif
       	CyFxAppErrorHandler(apiRetStatus);
    }
    else
    {
    	CyU3PDebugPrint (4, " P2U DMA Channel created with %d bytes and there are %d buffers \n",DMA_BUF_SIZE*size ,CY_FX_SLFIFO_DMA_BUF_COUNT_P_2_U);
    }

    /* Flush the Endpoint memory */
    CyU3PUsbFlushEp(CY_FX_EP_PRODUCER);
    CyU3PUsbFlushEp(CY_FX_EP_CONSUMER);

    /* Set DMA channel transfer size. */
    apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleSlFifoUtoP, CY_FX_SLFIFO_DMA_TX_SIZE);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "CyU3PDmaChannelSetXfer Failed, Error code = %d\n", apiRetStatus);
		#endif
        CyFxAppErrorHandler(apiRetStatus);
    }
    apiRetStatus = CyU3PDmaChannelSetXfer (&glChHandleSlFifoPtoU, CY_FX_SLFIFO_DMA_RX_SIZE);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "CyU3PDmaChannelSetXfer Failed, Error code = %d\n", apiRetStatus);
		#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Update the status flag. */
    glIsApplnActive = CyTrue;


    //CyU3PGpioSetValue (59, CyFalse);
}

/* This function stops the slave FIFO loop application. This shall be called
 * whenever a RESET or DISCONNECT event is received from the USB host. The
 * endpoints are disabled and the DMA pipe is destroyed by this function. */
void
CyFxSlFifoApplnStop (
        void)
{
    CyU3PEpConfig_t epCfg;
    CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;

    /* Update the flag. */
    glIsApplnActive = CyFalse;

#ifdef UART_ENABLE
	CyU3PDebugPrint (4, "\n...CyFxSlFifoApplnStop()...\n");
#endif

    /* Abort and clear the channel */
	CyU3PDmaChannelReset(&glChHandleSlFifoUtoP);
	CyU3PDmaChannelReset(&glChHandleSlFifoPtoU);

    /* Flush the endpoint memory */
    CyU3PUsbFlushEp(CY_FX_EP_PRODUCER);
    CyU3PUsbFlushEp(CY_FX_EP_CONSUMER);

    /* Destroy the channel */
    CyU3PDmaChannelDestroy (&glChHandleSlFifoUtoP);
    CyU3PDmaChannelDestroy (&glChHandleSlFifoPtoU);

    /* Disable endpoints. */
    CyU3PMemSet ((uint8_t *)&epCfg, 0, sizeof (epCfg));
    epCfg.enable = CyFalse;

    /* Producer endpoint configuration. */
    apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_PRODUCER, &epCfg);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\n", apiRetStatus);
		#endif
        CyFxAppErrorHandler (apiRetStatus);
    }

    /* Consumer endpoint configuration. */
    apiRetStatus = CyU3PSetEpConfig(CY_FX_EP_CONSUMER, &epCfg);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
		#ifdef UART_ENABLE
		CyU3PDebugPrint (4, "CyU3PSetEpConfig failed, Error code = %d\n", apiRetStatus);
		#endif
		CyFxAppErrorHandler (apiRetStatus);
	}

    //Configure GPIF
//    apiRetStatus = Fx3_Gpif_Configure(GPIF_CONFIG_DISABLED);
//	if (apiRetStatus != CY_U3P_SUCCESS)
//	{
//		#ifdef UART_ENABLE
//				CyU3PDebugPrint (4, "Gpif Configuration Failed, Error Code = %d\n",apiRetStatus);
//		#endif
//				CyFxAppErrorHandler(apiRetStatus);
//	}

    //LPM = true
	//CyFxApplnLPMSuspend(CyTrue);
	//glApplnMode = MODE_NO_CONFIG;
}

//-------------------------- SPI Functions ----------------------------------------
#ifdef SPI_ENABLE

/* This function pulls up/down the SPI Clock line. */
CyU3PReturnStatus_t
CyFxSpiSetClockValue (
        CyBool_t isHigh        /* Cyfalse: Pull down the Clock line,
                                  CyTrue: Pull up the Clock line */
        )
{
    CyU3PReturnStatus_t status;

    status = CyU3PGpioSetValue (FX3_SPI_CLK, isHigh);

    return status;
}

/* This function pulls up/down the slave select line. */
CyU3PReturnStatus_t
CyFxSpiSetSsnLine (
        CyBool_t isHigh        /* Cyfalse: Pull down the SSN line,
                                  CyTrue: Pull up the SSN line */
        )
{
#ifndef FX3_USE_GPIO_REGS
    CyU3PReturnStatus_t status;

    status = CyU3PGpioSetValue (FX3_SPI_SS, isHigh);

    return status;
#else
    uvint32_t *regPtrSS;
    regPtrSS = &GPIO->lpp_gpio_simple[FX3_SPI_SS];
    if(isHigh)
    {
        *regPtrSS |=CYFX_GPIO_HIGH;
    }
    else
    {
        *regPtrSS&=~CYFX_GPIO_HIGH;
    }

    return CY_U3P_SUCCESS;
#endif
}

/* This function transmits the byte to the SPI slave device one bit a time.
   Most Significant Bit is transmitted first.
 */
CyU3PReturnStatus_t
CyFxSpiWriteByte (
        uint8_t data)
{
    uint8_t i = 0;
#ifdef FX3_USE_GPIO_REGS
    CyBool_t value;
    uvint32_t *regPtrMOSI, *regPtrClock;
	regPtrMOSI = &GPIO->lpp_gpio_simple[FX3_SPI_MOSI];
	regPtrClock = &GPIO->lpp_gpio_simple[FX3_SPI_CLK];
#endif
    for (i = 0; i < 8; i++)
    {
#ifndef FX3_USE_GPIO_REGS
        /* Most significant bit is transferred first. */
        CyU3PGpioSetValue (FX3_SPI_MOSI, ((data >> (7 - i)) & 0x01));

        CyFxSpiSetClockValue (CyTrue);
        CyU3PBusyWait (1);
        CyFxSpiSetClockValue (CyFalse);
        CyU3PBusyWait (1);
#else
        /* Most significant bit is transferred first. */
		value =((data >> (7 - i)) & 0x01);
		if(value)
		{
			*regPtrMOSI |=	CYFX_GPIO_HIGH;
		}
		else
		{
			*regPtrMOSI &=~CYFX_GPIO_HIGH;
		}
		*regPtrClock|=CYFX_GPIO_HIGH;
        CyU3PBusyWait (1);
        *regPtrClock&=~CYFX_GPIO_HIGH;
        CyU3PBusyWait (1);
#endif
    }

    return CY_U3P_SUCCESS;
}

/* This function receives the byte from the SPI slave device one bit at a time.
   Most Significant Bit is received first.
 */
CyU3PReturnStatus_t
CyFxSpiReadByte (
        uint8_t *data)
{
    uint8_t i = 0;
    CyBool_t temp = CyFalse;

#ifdef FX3_USE_GPIO_REGS
    uvint32_t *regPtrClock;
	regPtrClock = &GPIO->lpp_gpio_simple[FX3_SPI_CLK];
#endif
    *data = 0;

    for (i = 0; i < 8; i++)
    {
#ifndef FX3_USE_GPIO_REGS
        CyFxSpiSetClockValue (CyTrue);

        CyU3PGpioGetValue (FX3_SPI_MISO, &temp);
        *data |= (temp << (7 - i));

        CyU3PBusyWait (1);

        CyFxSpiSetClockValue (CyFalse);
        CyU3PBusyWait (1);
#else
        *regPtrClock|=CYFX_GPIO_HIGH;
		temp = (GPIO->lpp_gpio_simple[FX3_SPI_MISO] & CY_U3P_LPP_GPIO_IN_VALUE)>>1;
        *data |= (temp << (7 - i));
        CyU3PBusyWait (1);
        *regPtrClock&=~CYFX_GPIO_HIGH;
        CyU3PBusyWait (1);
#endif
    }

    return CY_U3P_SUCCESS;
}

/* This function is used to transmit data to the SPI slave device. The function internally
   calls the CyFxSpiWriteByte function to write to the slave device.
 */
CyU3PReturnStatus_t
CyFxSpiTransmitWords (
        uint8_t *data,
        uint32_t byteCount)
{
    uint32_t i = 0;
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if ((!byteCount) || (!data))
    {
        return CY_U3P_ERROR_BAD_ARGUMENT;
    }

    for (i = 0; i < byteCount; i++)
    {
        status = CyFxSpiWriteByte (data[i]);

        if (status != CY_U3P_SUCCESS)
        {
            break;
        }
    }

    return status;
}

/* This function is used receive data from the SPI slave device. The function internally
   calls the CyFxSpiReadByte function to read data from the slave device.
 */
CyU3PReturnStatus_t
CyFxSpiReceiveWords (
        uint8_t *data,
        uint32_t byteCount)
{
    uint32_t i = 0;
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if ((!byteCount) || (!data))
    {
        return CY_U3P_ERROR_BAD_ARGUMENT;
    }

    for (i = 0; i < byteCount; i++)
    {
        status = CyFxSpiReadByte (&data[i]);

        if (status != CY_U3P_SUCCESS)
        {
            break;
        }
    }

    return status;
}

/* Wait for the status response from the SPI flash. */
CyU3PReturnStatus_t
CyFxSpiWaitForStatus (
        void)
{
    uint8_t buf[2], rd_buf[2];
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    /* Wait for status response from SPI flash device. */
    do
    {
        buf[0] = 0x06;  /* Write enable command. */

        CyFxSpiSetSsnLine (CyFalse);
        status = CyFxSpiTransmitWords (buf, 1);
        CyFxSpiSetSsnLine (CyTrue);
        if (status != CY_U3P_SUCCESS)
        {
        	//CyU3PDebugPrint (2, "SPI WR_ENABLE command failed\n\r");
            return status;
        }
        buf[0] = 0x05;  /* Read status command */

        CyFxSpiSetSsnLine (CyFalse);
        status = CyFxSpiTransmitWords (buf, 1);
        if (status != CY_U3P_SUCCESS)
        {
            //CyU3PDebugPrint (2, "SPI READ_STATUS command failed\n\r");
            CyFxSpiSetSsnLine (CyTrue);
            return status;
        }

        status = CyFxSpiReceiveWords (rd_buf, 2);
        CyFxSpiSetSsnLine (CyTrue);
        if(status != CY_U3P_SUCCESS)
        {
            //CyU3PDebugPrint (2, "SPI status read failed\n\r");
            return status;
        }

    } while ((rd_buf[0] & 1)|| (!(rd_buf[0] & 0x2)));

    return CY_U3P_SUCCESS;
}

/* SPI read / write for programmer application. */
CyU3PReturnStatus_t
CyFxSpiTransfer (
        uint16_t  pageAddress,
        uint16_t  byteCount,
        uint8_t  *buffer,
        CyBool_t  isRead)
{
    uint8_t location[4];
    uint32_t byteAddress = 0;
    uint16_t pageCount = (byteCount / glSpiPageSize);
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if (byteCount == 0)
    {
        return CY_U3P_SUCCESS;
    }
    if ((byteCount % glSpiPageSize) != 0)
    {
        pageCount ++;
    }

    byteAddress  = pageAddress * glSpiPageSize;
    //CyU3PDebugPrint (2, "SPI access - addr: 0x%x, size: 0x%x, pages: 0x%x.\r\n",
           // byteAddress, byteCount, pageCount);

    while (pageCount != 0)
    {
        location[1] = (byteAddress >> 16) & 0xFF;       /* MS byte */
        location[2] = (byteAddress >> 8) & 0xFF;
        location[3] = byteAddress & 0xFF;               /* LS byte */

        if (isRead)
        {
            location[0] = 0x03; /* Read command. */

            status = CyFxSpiWaitForStatus ();
            if (status != CY_U3P_SUCCESS)
                return status;

            CyFxSpiSetSsnLine (CyFalse);
            status = CyFxSpiTransmitWords (location, 4);
            if (status != CY_U3P_SUCCESS)
            {
                //CyU3PDebugPrint (2, "SPI READ command failed\r\n");
                CyFxSpiSetSsnLine (CyTrue);
                return status;
            }

            status = CyFxSpiReceiveWords (buffer, glSpiPageSize);
            if (status != CY_U3P_SUCCESS)
            {
                CyFxSpiSetSsnLine (CyTrue);
                return status;
            }

            CyFxSpiSetSsnLine (CyTrue);
        }
        else /* Write */
        {
            location[0] = 0x02; /* Write command */

            status = CyFxSpiWaitForStatus ();
            if (status != CY_U3P_SUCCESS)
                return status;

            CyFxSpiSetSsnLine (CyFalse);
            status = CyFxSpiTransmitWords (location, 4);
            if (status != CY_U3P_SUCCESS)
            {
                //CyU3PDebugPrint (2, "SPI WRITE command failed\r\n");
                CyFxSpiSetSsnLine (CyTrue);
                return status;
            }

            status = CyFxSpiTransmitWords (buffer, glSpiPageSize);
            if (status != CY_U3P_SUCCESS)
            {
                CyFxSpiSetSsnLine (CyTrue);
                return status;
            }

            CyFxSpiSetSsnLine (CyTrue);
        }

        /* Update the parameters */
        byteAddress  += glSpiPageSize;
        buffer += glSpiPageSize;
        pageCount --;

        CyU3PThreadSleep (10);
    }
    return CY_U3P_SUCCESS;
}

/* Function to erase SPI flash sectors. */
static CyU3PReturnStatus_t
CyFxSpiEraseSector (
     CyBool_t  isErase,
     uint8_t   sector,
     uint8_t  *wip)
{
    uint32_t temp = 0;
    uint8_t  location[4], rdBuf[2];
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    if ((!isErase) && (wip == NULL))
    {
        return CY_U3P_ERROR_BAD_ARGUMENT;
    }

    location[0] = 0x06;  /* Write enable. */

    CyFxSpiSetSsnLine (CyFalse);
    status = CyFxSpiTransmitWords (location, 1);
    CyFxSpiSetSsnLine (CyTrue);
    if (status != CY_U3P_SUCCESS)
        return status;

    if (isErase)
    {
        location[0] = 0xD8; /* Sector erase. */
        temp        = sector * 0x10000;
        location[1] = (temp >> 16) & 0xFF;
        location[2] = (temp >> 8) & 0xFF;
        location[3] = temp & 0xFF;

        CyFxSpiSetSsnLine (CyFalse);
        status = CyFxSpiTransmitWords (location, 4);
        CyFxSpiSetSsnLine (CyTrue);
    }
    else
    {
        location[0] = 0x05; /* Read status */

        CyFxSpiSetSsnLine (CyFalse);
        status = CyFxSpiTransmitWords (location, 1);
        if (status != CY_U3P_SUCCESS)
        {
            CyFxSpiSetSsnLine (CyTrue);
            return status;
        }

        status = CyFxSpiReceiveWords (rdBuf, 2);
        CyFxSpiSetSsnLine (CyTrue);
        *wip = rdBuf[0] & 0x1;	//returning WIP bit of Status Register
    }

    return status;
}

/* Function to Bulk erase all sectors of SPI flash. */
static CyU3PReturnStatus_t   CyFxSpiBulkErase(CyBool_t  isErase, uint8_t  *wip)
{
	uint8_t  location[4], rdBuf[2];
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    location[0] = 0x06;  /* Write enable. */

    CyFxSpiSetSsnLine (CyFalse);
    status = CyFxSpiTransmitWords (location, 1);
    CyFxSpiSetSsnLine (CyTrue);
    if (status != CY_U3P_SUCCESS)
        return status;

    if (isErase)
    {
        location[0] = 0xC7; /* Bulk erase. */

        CyFxSpiSetSsnLine (CyFalse);
        status = CyFxSpiTransmitWords (location, 1);
        CyFxSpiSetSsnLine (CyTrue);
    }
    else
    {
        location[0] = 0x05; /* Read status */

        CyFxSpiSetSsnLine (CyFalse);
        status = CyFxSpiTransmitWords (location, 1);
        if (status != CY_U3P_SUCCESS)
        {
            CyFxSpiSetSsnLine (CyTrue);
            return status;
        }

        status = CyFxSpiReceiveWords (rdBuf, 2);
        CyFxSpiSetSsnLine (CyTrue);
        wip = rdBuf;			//returning the entire status register
/*		*wip = rdBuf[0] & 0x1;	//returning WIP bit of Status Register		*/
    }
    return status;
}
/************************* For TI User Only *********************************/

/* Function to disable SPI write protected sector 7 for changing the Serial Number. */
static CyU3PReturnStatus_t disable_spi_protection (CyBool_t  isUnprotect)
{
	uint8_t  location[4];
	CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
	if (isUnprotect)
	{
		location[0] = 0x06;  /* Write enable. */

		CyFxSpiSetSsnLine (CyFalse);
		status = CyFxSpiTransmitWords (location, 1);
		CyFxSpiSetSsnLine (CyTrue);

		location[0] = 0x01; /* Write Status Register*/
		location[1] = 0x00; /* Clear BP0 bit of status register to Unprotect Sector 7.*/

		CyFxSpiSetSsnLine (CyFalse);
		status = CyFxSpiTransmitWords (location, 2);
		CyFxSpiSetSsnLine (CyTrue);

	}
	return status;
}

/* Function to write Serial Number and protect the sector 7 from future modifications,
 * when firmware is updated in the SPI Flash or User tries to modify the location
 */
static CyU3PReturnStatus_t write_serial_number_and_protect (
        uint16_t  pageAddress,
        uint16_t  byteCount,
        uint8_t  *buffer)
{
	uint8_t  location[4];
	CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

	/*Writing the serial number into the Flash Memory*/
	status = CyFxSpiTransfer(pageAddress, byteCount, buffer, CyFalse);
	if (status == CY_U3P_SUCCESS)
	{
		/*Protect the sector 7 in which the serial number is stored*/

		location[0] = 0x06;  /* Write enable. */

		CyFxSpiSetSsnLine (CyFalse);
		status = CyFxSpiTransmitWords (location, 1);
		CyFxSpiSetSsnLine (CyTrue);

		location[0] = 0x01; /* Write Status Register*/
		location[1] = 0x04; /* Set BP0 to protect Sector 7.*/

		CyFxSpiSetSsnLine (CyFalse);
		status = CyFxSpiTransmitWords (location, 2);
		CyFxSpiSetSsnLine (CyTrue);
	}

	return status;
}

/****************************************************************************/

#endif
//------------------ SPI Functoins Ends ------------------------------

/* I2C read / write for programmer application. */
CyU3PReturnStatus_t
CyFxUsbI2cTransfer (
        uint16_t  byteAddress,
        uint16_t   devAddr,
        uint16_t  byteCount,
        uint8_t  *buffer,
        CyBool_t  isRead)
{
	CyU3PI2cPreamble_t preamble;
    uint16_t pageCount = (byteCount / glI2cPageSize);
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
    uint16_t resCount = glI2cPageSize;

    if (byteCount == 0)
    {
        return CY_U3P_SUCCESS;
    }

    //checking for the odd values present
    if ((byteCount % glI2cPageSize) != 0)
    {
        pageCount ++;
        resCount = byteCount % glI2cPageSize;
    }

    /*CyU3PDebugPrint (2, "I2C access - dev: 0x%x, register address: 0x%x, size: 0x%x, pages: 0x%x.\r\n",
            devAddr, byteAddress, byteCount, pageCount);*/

    while (pageCount != 0)
    {
        if (isRead)/* Rear */
        {
        	//CyU3PDebugPrint (2, "I2C Read Sequence\n");
            /* Update the preamble information. */
            preamble.length    = 2;	//5;
            preamble.buffer[0] = (devAddr);
//          preamble.buffer[1] = (uint8_t)(devAddr >> 8);	//higher order 8 bit device address
//          preamble.buffer[2] = (uint8_t)(byteAddress >> 8);	//higher order 8 bit reg addr
            preamble.buffer[1] = (uint8_t)(byteAddress & 0xFF);	//lower order 8 bit reg addr
//          preamble.buffer[4] = (devAddr | 0x01);
            preamble.ctrlMask  = 0x0000;	//0x0004;

            status = CyU3PI2cReceiveBytes (&preamble, buffer,2 /*(pageCount == 1) ? resCount : glI2cPageSize*/, 0);
//          CyU3PDebugPrint (4, "Received: = %d   %d\n", buffer[0],buffer[1]);
            if (status != CY_U3P_SUCCESS)
            {
                return status;
            }
        }
        else /* Write */
        {
            /* Update the preamble information. */
        	//CyU3PDebugPrint (2, "I2C Write Sequence\n");
        	preamble.length    = 2;	//5;
			preamble.buffer[0] = devAddr;
//			preamble.buffer[1] = (uint8_t)(devAddr >> 8);	//higher order 8 bit device address
//			preamble.buffer[2] = (uint8_t)(byteAddress >> 8);	//higher order 8 bit reg addr
			preamble.buffer[1] = (uint8_t)(byteAddress & 0xFF);	//lower order 8 bit reg addr
//			preamble.buffer[4] = (devAddr | 0x01);
			preamble.ctrlMask  = 0x0000;	//0x0004;


            status = CyU3PI2cTransmitBytes (&preamble, buffer , (pageCount == 1) ? resCount : glI2cPageSize, 0);
            if (status != CY_U3P_SUCCESS)
            {
                return status;
            }


            /* Wait for the write to complete. */
           /* preamble.length = 1;
            status = CyU3PI2cWaitForAck(&preamble, 200);
            if (status != CY_U3P_SUCCESS)
            {
                return status;
            }*/
        }

        /* An additional delay seems to be required after receiving an ACK. */
        CyU3PThreadSleep (1);

        /*	This part is for continuous register write
        // Update the parameters
        //byteAddress  += glI2cPageSize;
        //buffer += glI2cPageSize;
        //pageCount --;
         */
        pageCount = 0;	//comment this line for continuous register write
    }

    return CY_U3P_SUCCESS;
}

/* Callback to handle the USB setup requests. */
CyBool_t
CyFxSlFifoApplnUSBSetupCB (
        uint32_t setupdat0,
        uint32_t setupdat1
    )
{
    CyBool_t Fpga_Confg_Done_Status = CyFalse;

    /* Fast enumeration is used. Only requests addressed to the interface, class,
     * vendor and unknown control requests are received by this function.*/

	/**********************FX3 Unique ID Declarations****************/
	uvint32_t *Unique_ID_Addr = (uvint32_t*) (0xE0055010);
	uint64_t Unique_ID_64b = *Unique_ID_Addr;
	uint8_t Unique_ID[8];
	int i=0;
	/****************************************************************/

	/********************	Used For BitBanged JTAG Purpose *******************************/
	/*
	uvint32_t *gpio_addr_50 = (uvint32_t*) (0xe0001100 + ((50)*(0x0004)));	//gpio register address direct access
	uvint32_t *gpio_addr_51 = (uvint32_t*) (0xe0001100 + ((51)*(0x0004)));
	uvint32_t *gpio_addr_52 = (uvint32_t*) (0xe0001100 + ((52)*(0x0004)));
	uint16_t  k=0;
	*/
	/****************************************************************/

	uint16_t  i2cAddr;
	uint8_t  bRequest, bReqType;
    uint8_t  bType, bTarget;
    uint16_t wValue, wIndex, wLength;
    CyBool_t isHandled = CyFalse;
//	uvint32_t *I2C_Error_Bit = (uvint32_t*) (0xE0000404);
//  uint8_t h = 0, i = 0, j = 0;
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;

    /* Decode the fields from the setup request. */
    bReqType = (setupdat0 & CY_U3P_USB_REQUEST_TYPE_MASK);
    bType    = (bReqType & CY_U3P_USB_TYPE_MASK);
    bTarget  = (bReqType & CY_U3P_USB_TARGET_MASK);
    bRequest = ((setupdat0 & CY_U3P_USB_REQUEST_MASK) >> CY_U3P_USB_REQUEST_POS);
    wValue   = ((setupdat0 & CY_U3P_USB_VALUE_MASK)   >> CY_U3P_USB_VALUE_POS);
    wIndex   = ((setupdat1 & CY_U3P_USB_INDEX_MASK)   >> CY_U3P_USB_INDEX_POS);
    wLength   = ((setupdat1 & CY_U3P_USB_LENGTH_MASK)   >> CY_U3P_USB_LENGTH_POS);

    if (bType == CY_U3P_USB_STANDARD_RQT)
    {
        /* Handle SET_FEATURE(FUNCTION_SUSPEND) and CLEAR_FEATURE(FUNCTION_SUSPEND)
         * requests here. It should be allowed to pass if the device is in configured
         * state and failed otherwise. */
        if ((bTarget == CY_U3P_USB_TARGET_INTF) && ((bRequest == CY_U3P_USB_SC_SET_FEATURE)
                    || (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)) && (wValue == 0))
        {
            if (glIsApplnActive)
                CyU3PUsbAckSetup ();
            else
                CyU3PUsbStall (0, CyTrue, CyFalse);

            isHandled = CyTrue;
        }
    }

    /* Handle supported vendor requests. */
	if (bType == CY_U3P_USB_VENDOR_RQT)
	{
		isHandled = CyTrue;

		switch (bRequest)
				{
					case CY_FX_RQT_ID_CHECK:

						CyU3PUsbSendEP0Data (8, (uint8_t *)glFirmwareID);
					break;

					case CY_FX_UNIQUE_ID:

						for(i=0;i<8;i++)
						{
							Unique_ID[i] = ( Unique_ID_64b >> (i*8) ) & 0xFF;
						}
						CyU3PUsbSendEP0Data (8, (uint8_t *) Unique_ID);

						#ifdef UART_ENABLE
						CyU3PDebugPrint (4, "Device ID is %d\n", Unique_ID_64b);
						#endif

					break;

					case CY_FX_RQT_I2C_WRITE:

						i2cAddr = wValue ; /*0xA0 | ((wValue & 0x0007) << 1);		*/
						status  = CyU3PUsbGetEP0Data(((wLength + 15) & 0xFFF0), glEp0Buffer, NULL);
						if (status == CY_U3P_SUCCESS)
						{
							CyFxUsbI2cTransfer (wIndex, i2cAddr, wLength,
									glEp0Buffer, CyFalse);
						}
					break;

					case CY_FX_RQT_I2C_READ:

						i2cAddr = wValue ; /*0xA0 | ((wValue & 0x0007) << 1);		*/
						CyU3PMemSet (glEp0Buffer, 0, sizeof (glEp0Buffer));
						status = CyFxUsbI2cTransfer (wIndex, i2cAddr, wLength,
								glEp0Buffer, CyTrue);
						if (status == CY_U3P_SUCCESS)
						{
							status = CyU3PUsbSendEP0Data(wLength, glEp0Buffer);
						}
					break;

					//-------------------FPGA FPP Firmware Loading-----------------------
					case FPGA_FW_LOAD:

						if ((bReqType & 0x80) == 0)
						{
							CyU3PUsbGetEP0Data (wLength, glEp0Buffer, NULL);

							/*TODO: Check file size operation;where to send; when to send; gokul*/
							filelen = (uint32_t)(glEp0Buffer[3]<<24)|(glEp0Buffer[2]<<16)|(glEp0Buffer[1]<<8)|glEp0Buffer[0];
							glConfigDone = CyTrue;
							/* Set CONFIGFPGAAPP_START_EVENT to start configuring FPGA */
							CyU3PEventSet(&glFxConfigFpgaAppEvent, CY_FX_CONFIGFPGAAPP_START_EVENT,
									CYU3P_EVENT_OR);
							isHandled = CyTrue;
						}
					break;
					case FPGA_FW_STATUS:

						if ((bReqType & 0x80) == 0x80)
						{
							status = CyU3PGpioGetValue(GPIO_CONFDONE, &Fpga_Confg_Done_Status);
							glEp0Buffer [0]= Fpga_Confg_Done_Status;	//glEp0Buffer [0]= glConfigDone;
							CyU3PUsbSendEP0Data (wLength, glEp0Buffer);
							/* Switch to slaveFIFO interface when FPGA is configured successfully*/
							if (Fpga_Confg_Done_Status)	//glConfigDone
							CyU3PEventSet(&glFxConfigFpgaAppEvent, CY_FX_CONFIGFPGAAPP_SW_TO_SLFIFO_EVENT,
														CYU3P_EVENT_OR);
							isHandled = CyTrue;
						}
					break;
					//-------------------------------------------------------------------

					//-------------------- SPI Requests --------------------------
					#ifdef SPI_ENABLE

					/*********************For TI User Only************************/
					case DISABLE_SERIAL_NUMBER_PROTECTION:
						status = disable_spi_protection((wValue) ? CyTrue : CyFalse);

						//To make the transmission out happy. <dummy read>
						status  = CyU3PUsbGetEP0Data(((wLength + 15) & 0xFFF0), glEp0Buffer, NULL);

					break;

					case WRITE_FPGA_BOARD_NAME:
						status = CyU3PUsbGetEP0Data (fpga_board_name_byte_count,
														glEp0Buffer, NULL);
						if (status == CY_U3P_SUCCESS)
						{
							status = CyFxSpiTransfer(fpga_board_name_addr,
									fpga_board_name_byte_count, glEp0Buffer, CyFalse);
						}
					break;

					case WRITE_SERIAL_NUMBER_AND_PROTECT:
						status = CyU3PUsbGetEP0Data (fpga_serial_number_byte_count,
								glEp0Buffer, NULL);
						if (status == CY_U3P_SUCCESS)
						{
							write_serial_number_and_protect(fpga_serial_number_addr,
									fpga_serial_number_byte_count, glEp0Buffer);
						}
					break;
					/**************************************************************/

					case READ_FPGA_BOARD_NAME:
						CyU3PMemSet (glEp0Buffer, 0, sizeof (glEp0Buffer));
						status = CyFxSpiTransfer(fpga_board_name_addr,
													16, glEp0Buffer, CyTrue);
						if (status == CY_U3P_SUCCESS)
						{
							status = CyU3PUsbSendEP0Data (fpga_board_name_byte_count, glEp0Buffer);
						}
					break;

					case READ_FPGA_SERIAL_NUMBER:
						CyU3PMemSet (glEp0Buffer, 0, sizeof (glEp0Buffer));
						status = CyFxSpiTransfer (fpga_serial_number_addr,
									16, glEp0Buffer, CyTrue);
						if (status == CY_U3P_SUCCESS)
						{
							status = CyU3PUsbSendEP0Data (fpga_serial_number_byte_count, glEp0Buffer);
						}
					break;

					case CY_FX_RQT_SPI_FLASH_WRITE:
						status = CyU3PUsbGetEP0Data (wLength, glEp0Buffer, NULL);
						if (status == CY_U3P_SUCCESS)
						{
							status = CyFxSpiTransfer (wIndex, wLength,
									glEp0Buffer, CyFalse);
						}
					break;

					case CY_FX_RQT_SPI_FLASH_READ:
						CyU3PMemSet (glEp0Buffer, 0, sizeof (glEp0Buffer));
						status = CyFxSpiTransfer (wIndex, wLength,
								glEp0Buffer, CyTrue);
						if (status == CY_U3P_SUCCESS)
						{
							status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);
						}
					break;

					case CY_FX_RQT_SPI_FLASH_ERASE_POLL:
						status = CyFxSpiEraseSector ((wValue) ? CyTrue : CyFalse,
								(wIndex & 0xFF), glEp0Buffer);
						if (status == CY_U3P_SUCCESS)
						{
							CyFxSpiWaitForStatus ();
							if (wValue == CyTrue)
							{
								status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);
							}
							else
							{
								CyU3PUsbAckSetup ();
							}
						}
					break;

					case CY_FX_RQT_SPI_FLASH_BULK_ERASE:
						status = CyFxSpiBulkErase ((wValue) ? CyTrue : CyFalse, glEp0Buffer);

						//Sending the status of the Bulk Erase
						status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);

						if (status == CY_U3P_SUCCESS)
						{
							CyFxSpiWaitForStatus ();
							if (wValue == CyTrue)
							{
								//status = CyU3PUsbSendEP0Data (wLength, glEp0Buffer);
							}
							else
							{
								CyU3PUsbAckSetup ();
							}
						}
					break;

					#endif
					//-------------------------------------------------------------------

/********************	Used For BitBanged JTAG Purpose *******************************/
/*					case Bit_Banged_Write:
						status  = CyU3PUsbGetEP0Data(((wLength + 15) & 0xFFF0), glEp0Buffer, NULL);
						if(status != CY_U3P_SUCCESS)
						{
							#ifdef UART_ENABLE
							CyU3PDebugPrint(4,"GetEP0Data Error in switch case\n");
							#endif
						}

						for(k=0; k<wLength ;k++)
						{

		//					status = CyU3PGpioSimpleSetValue (50,j&0x01 );
		//					status = CyU3PGpioSimpleSetValue (51, j&0x2);
		//					status = CyU3PGpioSimpleSetValue (52, j&0x4);
		//					status = CyU3PGpioSimpleSetValue (57, j&0x8);

		//					* gpio_addr_50 = 2147483697;	//configuration value for setting the gpio pin
		//					* gpio_addr_51 = 2147483697;
		//					* gpio_addr_52 = 2147483697;


		//					* (gpio_addr+0x04) = ( *(gpio_addr+0x04) & ~CY_U3P_LPP_GPIO_INTR) ^ ( j & 0x01 );
		//					* (gpio_addr+0x08) = ( *(gpio_addr+0x08) & ~CY_U3P_LPP_GPIO_INTR) ^ ( j & 0x01 );
		//					* (gpio_addr+0x1C) = ( *(gpio_addr+0x1C) & ~CY_U3P_LPP_GPIO_INTR) ^ ( j & 0x01 );

							* gpio_addr_50 = 2147483696 + ( (glEp0Buffer[k] )&0x01 );
							* gpio_addr_51 = 2147483696 + ( (glEp0Buffer[k]>>1 )&0x01 );
							* gpio_addr_52 = 2147483696 + ( (glEp0Buffer[k]>>3 )&0x01 );

						}

		//				CyU3PDebugPrint(4,"gpio 50 value is :- %u \n",(k&0x01));
		//				CyU3PDebugPrint(4,"gpio 51 value is :- %u \n",(k&0x02));
		//				CyU3PDebugPrint(4,"gpio 52 value is :- %u \n",(k&0x04));

						if(status != CY_U3P_SUCCESS)
						{
							//CyU3PDebugPrint(4,"gpio writing error in switch case\n");
						}
					break;
*/
					default:
					/* This is unknown request. */
					isHandled = CyFalse;
					break;
				}

		/* If there was any error, return not handled so that the library will
		 * stall the request. Alternatively EP0 can be stalled here and return
		 * CyTrue. */
		if (status != CY_U3P_SUCCESS)
		{
			isHandled = CyFalse;
		}
	}

        /* CLEAR_FEATURE request for endpoint is always passed to the setup callback
         * regardless of the enumeration model used. When a clear feature is received,
         * the previous transfer has to be flushed and cleaned up. This is done at the
         * protocol level. Since this is just a loopback operation, there is no higher
         * level protocol. So flush the EP memory and reset the DMA channel associated
         * with it. If there are more than one EP associated with the channel reset both
         * the EPs. The endpoint stall and toggle / sequence number is also expected to be
         * reset. Return CyFalse to make the library clear the stall and reset the endpoint
         * toggle. Or invoke the CyU3PUsbStall (ep, CyFalse, CyTrue) and return CyTrue.
         * Here we are clearing the stall. */
        if ((bTarget == CY_U3P_USB_TARGET_ENDPT) && (bRequest == CY_U3P_USB_SC_CLEAR_FEATURE)
                && (wValue == CY_U3P_USBX_FS_EP_HALT))
        {
            if (glIsApplnActive)
            {
                if (wIndex == CY_FX_EP_PRODUCER)
                {
                    CyU3PDmaChannelReset (&glChHandleSlFifoUtoP);
                    CyU3PUsbFlushEp(CY_FX_EP_PRODUCER);
                    CyU3PUsbResetEp (CY_FX_EP_PRODUCER);
                    CyU3PDmaChannelSetXfer (&glChHandleSlFifoUtoP, CY_FX_SLFIFO_DMA_TX_SIZE);
                }

                if (wIndex == CY_FX_EP_CONSUMER)
                {
                    CyU3PDmaChannelReset (&glChHandleSlFifoPtoU);
                    CyU3PUsbFlushEp(CY_FX_EP_CONSUMER);
                    CyU3PUsbResetEp (CY_FX_EP_CONSUMER);
                    CyU3PDmaChannelSetXfer (&glChHandleSlFifoPtoU, CY_FX_SLFIFO_DMA_RX_SIZE);
                }

                CyU3PUsbStall (wIndex, CyFalse, CyTrue);
                isHandled = CyTrue;
            }
        }

    return isHandled;
}

/* This is the callback function to handle the USB events. */
void
CyFxSlFifoApplnUSBEventCB (
    CyU3PUsbEventType_t evtype,
    uint16_t            evdata
    )
{

//#ifdef UART_ENABLE
//		 CyU3PDebugPrint(4,"\nCyFxApplnUSBEventCB evtype = %d ",evtype);
//#endif

    switch (evtype)
    {
        case CY_U3P_USB_EVENT_SETCONF:
            /* Stop the application before re-starting. */
//            if (glIsApplnActive)
//            {
            	if(glApplnMode == MODE_SLFIFO_CONFIG)
            	{
            		if (glIsApplnActive)
            		{
            			CyFxSlFifoApplnStop();
            		}
                	CyU3PUsbLPMDisable();
                	CyFxSlFifoApplnStart ();	//Start the loop back function
            	}
            	else if(glApplnMode == MODE_FPGA_CONFIG)
            	{
            		if (glIsApplnActive)
            		{
            			CyFxConfigFpgaApplnStop ();
            		}
                	CyU3PUsbLPMDisable();
            		CyFxConfigFpgaApplnStart();	//Start the loop back function
            	}
//            }

            /* Start the loop back function. */
//            if(glApplnMode == MODE_SLFIFO_CONFIG)
//            	CyFxSlFifoApplnStart ();
//        	else if(glApplnMode == MODE_FPGA_CONFIG)
//        		CyFxConfigFpgaApplnStart();
		break;

        case CY_U3P_USB_EVENT_RESET:
        case CY_U3P_USB_EVENT_DISCONNECT:
            /* Stop the loop back function. */
            if (glIsApplnActive)
            {
            	if(glApplnMode == MODE_SLFIFO_CONFIG)
            			CyFxSlFifoApplnStop ();
            	else if(glApplnMode == MODE_FPGA_CONFIG)
            		CyFxConfigFpgaApplnStop ();
            }
		break;

        default:
		break;
    }
}


/* Callback function to handle LPM requests from the USB 3.0 host. This function is invoked by the API
   whenever a state change from U0 -> U1 or U0 -> U2 happens. If we return CyTrue from this function, the
   FX3 device is retained in the low power state. If we return CyFalse, the FX3 device immediately tries
   to trigger an exit back to U0.

   This application does not have any state in which we should not allow U1/U2 transitions; and therefore
   the function always return CyTrue.
 */

static CyBool_t allow_suspend = CyTrue;

void CyFxApplnLPMSuspend(CyBool_t set_allow_suspend) {
    allow_suspend = set_allow_suspend;
}

CyBool_t
CyFxApplnLPMRqtCB (
        CyU3PUsbLinkPowerMode link_mode)
{
    return allow_suspend;
}

void
gpif_error_cb(CyU3PPibIntrType cbType, uint16_t cbArg)
{
#ifdef UART_ENABLE
if(cbType==CYU3P_PIB_INTR_ERROR)
{
    switch (CYU3P_GET_PIB_ERROR_TYPE(cbArg))
    {
        case CYU3P_PIB_ERR_THR0_WR_OVERRUN:
        CyU3PDebugPrint (4, "CYU3P_PIB_ERR_THR0_WR_OVERRUN");
        break;
        case CYU3P_PIB_ERR_THR1_WR_OVERRUN:
        CyU3PDebugPrint (4, "CYU3P_PIB_ERR_THR1_WR_OVERRUN");
        break;
        case CYU3P_PIB_ERR_THR2_WR_OVERRUN:
        CyU3PDebugPrint (4, "CYU3P_PIB_ERR_THR2_WR_OVERRUN");
        break;
        case CYU3P_PIB_ERR_THR3_WR_OVERRUN:
        CyU3PDebugPrint (4, "CYU3P_PIB_ERR_THR3_WR_OVERRUN");
        break;

        case CYU3P_PIB_ERR_THR0_RD_UNDERRUN:
        CyU3PDebugPrint (4, "CYU3P_PIB_ERR_THR0_RD_UNDERRUN");
        break;
        case CYU3P_PIB_ERR_THR1_RD_UNDERRUN:
        CyU3PDebugPrint (4, "CYU3P_PIB_ERR_THR1_RD_UNDERRUN");
        break;
        case CYU3P_PIB_ERR_THR2_RD_UNDERRUN:
        CyU3PDebugPrint (4, "CYU3P_PIB_ERR_THR2_RD_UNDERRUN");
        break;
        case CYU3P_PIB_ERR_THR3_RD_UNDERRUN:
        CyU3PDebugPrint (4, "CYU3P_PIB_ERR_THR3_RD_UNDERRUN");
        break;

        default:
        CyU3PDebugPrint (4, "No Error :%d\n ",CYU3P_GET_PIB_ERROR_TYPE(cbArg));
            break;
    }
}
#endif

}

/*This function initialises GPIO clock*/
CyU3PReturnStatus_t
CyFxGpioInitialization (void)
{
    CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
	CyU3PGpioClock_t gpioClock;

	/* Initialize the GPIO module. */
	gpioClock.fastClkDiv = 2;
	gpioClock.slowClkDiv = 0;
	gpioClock.simpleDiv  = CY_U3P_GPIO_SIMPLE_DIV_BY_2;
	gpioClock.clkSrc     = CY_U3P_SYS_CLK;
	gpioClock.halfDiv    = 0;

	apiRetStatus = CyU3PGpioInit(&gpioClock, NULL);
	if (apiRetStatus != 0)
	{
		/* Error Handling */
		CyFxAppErrorHandler(apiRetStatus);
	}

	apiRetStatus = CyFxSlFifoGpioReConfig();
	if (apiRetStatus != 0)
	{
		/* Error Handling */
		CyFxAppErrorHandler(apiRetStatus);
	}

	return apiRetStatus;
}

/* This function defines the GPIO module and IO Matrix. GPIO Ids 53-56 are used for communicating
   with the SPI slave device.  GPIO 52,51,50 - for FPGA FW Loading*/
CyU3PReturnStatus_t
CyFxSlFifoGpioReConfig (void)
{
    CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;
    CyU3PIoMatrixConfig_t io_cfg;
    CyU3PGpioSimpleConfig_t gpioConfig;

    /* Configure the IO matrix for the device. On the FX3 DVK board, the COM port
	 * is connected to the IO(53:56). This means that either DQ32 mode should be
	 * selected or lppMode should be set to UART_ONLY. Here we are choosing
	 * UART_ONLY configuration for 16 bit slave FIFO configuration and setting
	 * isDQ32Bit for 32-bit slave FIFO configuration. */

	CyU3PMemSet ((uint8_t *)&io_cfg, 0, sizeof(io_cfg));
	io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE;
	io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE;


#ifdef UART_ENABLE
	io_cfg.useUart   = CyTrue;
#endif

#ifdef SPI_ENABLE
	io_cfg.useUart   = CyFalse;
#endif

	io_cfg.useI2C    = CyTrue;
	io_cfg.useI2S    = CyFalse;
	io_cfg.useSpi   = CyFalse;
	io_cfg.isDQ32Bit = CyTrue;
	io_cfg.lppMode   = CY_U3P_IO_MATRIX_LPP_DEFAULT;
	/* GPIO's are enabled. */
	io_cfg.gpioSimpleEn[0]  = 0;
#ifndef UART_ENABLE
	io_cfg.gpioSimpleEn[1]  = 0x01FC0000; /*GPIO 53,54,55,56 - SPI; GPIO 52,51,50 - For FPGA Configuration;
							(BitBanged JTAG -GPIO 57,52,51,50 = 0x021C0000;) - Not Added*/
#else
	io_cfg.gpioSimpleEn[1] = 0x001C0000; /* GPIO 52,51,50 - For FPGA Configuration Only*/;
#endif
	io_cfg.gpioComplexEn[0] = 0;
	io_cfg.gpioComplexEn[1] = 0;
	apiRetStatus = CyU3PDeviceConfigureIOMatrix (&io_cfg);
	if (apiRetStatus != CY_U3P_SUCCESS)
	{
		#ifdef UART_ENABLE
			CyU3PDebugPrint (4, "Fatal Error During IOMatrix Configuration");
		#endif
	}

	//I2C Initialisation Function
	CyFxApplnI2CInit();

    /* Configure GPIO_nSTATUS as input */
	gpioConfig.outValue = CyTrue;
	gpioConfig.inputEn = CyTrue;
	gpioConfig.driveLowEn = CyFalse;
	gpioConfig.driveHighEn = CyFalse;
	gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
	apiRetStatus = CyU3PGpioSetSimpleConfig(GPIO_nSTATUS, &gpioConfig);
	if (apiRetStatus != CY_U3P_SUCCESS)
	{
	  /* Error handling */
		#ifdef UART_ENABLE
			CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig for GPIO Id %d failed, error code = %d\n",
					GPIO_nSTATUS, apiRetStatus);
		#endif
	  CyFxAppErrorHandler(apiRetStatus);
	}

	/* Configure GPIO_CONFDONE as input */
	gpioConfig.outValue = CyTrue;
	gpioConfig.inputEn = CyTrue;
	gpioConfig.driveLowEn = CyFalse;
	gpioConfig.driveHighEn = CyFalse;
	gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
	apiRetStatus = CyU3PGpioSetSimpleConfig(GPIO_CONFDONE, &gpioConfig);
	if (apiRetStatus != CY_U3P_SUCCESS)
	{
	  /* Error handling */
	  /*CyU3PDebugPrint (4,
	   "CyU3PGpioSetSimpleConfig failed, error code = %d\n",apiRetStatus);*/
	  CyFxAppErrorHandler(apiRetStatus);
	}

	/* Configure GPIO_nCONFIG as output */
	gpioConfig.outValue = CyFalse;
	gpioConfig.inputEn = CyFalse;
	gpioConfig.driveLowEn = CyTrue;
	gpioConfig.driveHighEn = CyTrue;
	gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
	apiRetStatus = CyU3PGpioSetSimpleConfig(GPIO_nCONFIG, &gpioConfig);
	if (apiRetStatus != CY_U3P_SUCCESS)
	{
	  /* Error handling */
	  /* CyU3PDebugPrint (4,
		"CyU3PGpioSetSimpleConfig failed, error code = %d\n",apiRetStatus);*/
	  CyFxAppErrorHandler(apiRetStatus);
	}

#ifdef SPI_ENABLE
    /* Configure GPIO 53 as output(SPI_CLOCK). */
    gpioConfig.outValue    = CyFalse;
    gpioConfig.inputEn     = CyFalse;
    gpioConfig.driveLowEn  = CyTrue;
    gpioConfig.driveHighEn = CyTrue;
    gpioConfig.intrMode    = CY_U3P_GPIO_NO_INTR;

    apiRetStatus = CyU3PGpioSetSimpleConfig(FX3_SPI_CLK, &gpioConfig);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        /* Error handling */
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Configure GPIO 54 as output(SPI_SSN) */
    gpioConfig.outValue    = CyTrue;
    gpioConfig.inputEn     = CyFalse;
    gpioConfig.driveLowEn  = CyTrue;
    gpioConfig.driveHighEn = CyTrue;
    gpioConfig.intrMode    = CY_U3P_GPIO_NO_INTR;

    apiRetStatus = CyU3PGpioSetSimpleConfig(FX3_SPI_SS, &gpioConfig);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        /* Error handling */
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Configure GPIO 55 as input(MISO) */
    gpioConfig.outValue    = CyFalse;
    gpioConfig.inputEn     = CyTrue;
    gpioConfig.driveLowEn  = CyFalse;
    gpioConfig.driveHighEn = CyFalse;
    gpioConfig.intrMode    = CY_U3P_GPIO_NO_INTR;

    apiRetStatus = CyU3PGpioSetSimpleConfig(FX3_SPI_MISO, &gpioConfig);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        /* Error handling */
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Configure GPIO 56 as output(MOSI) */
    gpioConfig.outValue    = CyFalse;
    gpioConfig.inputEn     = CyFalse;
    gpioConfig.driveLowEn  = CyTrue;
    gpioConfig.driveHighEn = CyTrue;
    gpioConfig.intrMode    = CY_U3P_GPIO_NO_INTR;

    apiRetStatus = CyU3PGpioSetSimpleConfig(FX3_SPI_MOSI, &gpioConfig);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
        /* Error handling */
        CyFxAppErrorHandler(apiRetStatus);
    }

    /********************	Used For BitBanged JTAG Purpose *******************************/
	/* // Configure GPIO 50 as output
		gpioConfig.outValue = CyFalse;
		gpioConfig.driveLowEn = CyTrue;
		gpioConfig.driveHighEn = CyTrue;
		gpioConfig.inputEn = CyFalse;
		gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
		apiRetStatus = CyU3PGpioSetSimpleConfig(50, &gpioConfig);
		if (apiRetStatus != CY_U3P_SUCCESS)
		{
			// Error handling
#ifdef UART_ENABLE
			CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig failed, error code = %d\n", apiRetStatus);
#endif
			CyFxAppErrorHandler(apiRetStatus);
		}
	 // Configure GPIO 51 as output
		gpioConfig.outValue = CyFalse;
		gpioConfig.driveLowEn = CyTrue;
		gpioConfig.driveHighEn = CyTrue;
		gpioConfig.inputEn = CyFalse;
		gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
		apiRetStatus = CyU3PGpioSetSimpleConfig(51, &gpioConfig);
		if (apiRetStatus != CY_U3P_SUCCESS)
		{
			// Error handling
#ifdef UART_ENABLE
			CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig failed, error code = %d\n", apiRetStatus);
#endif
			CyFxAppErrorHandler(apiRetStatus);
		}
		 // Configure GPIO 52 as output
		gpioConfig.outValue = CyFalse;
		gpioConfig.driveLowEn = CyTrue;
		gpioConfig.driveHighEn = CyTrue;
		gpioConfig.inputEn = CyFalse;
		gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
		apiRetStatus = CyU3PGpioSetSimpleConfig(52, &gpioConfig);
		if (apiRetStatus != CY_U3P_SUCCESS)
		{
			// Error handling
#ifdef UART_ENABLE
			CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig failed, error code = %d\n", apiRetStatus);
#endif
			CyFxAppErrorHandler(apiRetStatus);
		}
		 // Configure GPIO 57 as output
		gpioConfig.outValue = CyFalse;
		gpioConfig.driveLowEn = CyTrue;
		gpioConfig.driveHighEn = CyTrue;
		gpioConfig.inputEn = CyFalse;
		gpioConfig.intrMode = CY_U3P_GPIO_NO_INTR;
		apiRetStatus = CyU3PGpioSetSimpleConfig(57, &gpioConfig);
		if (apiRetStatus != CY_U3P_SUCCESS)
		{
			// Error handling
#ifdef UART_ENABLE
			CyU3PDebugPrint (4, "CyU3PGpioSetSimpleConfig failed, error code = %d\n", apiRetStatus);
#endif
			CyFxAppErrorHandler(apiRetStatus);
		}
	*/
#endif

    return apiRetStatus;
}
#if 0
/* This function initializes the GPIF interface and initializes
 * the USB interface. */
void
CyFxSlFifoApplnInit (void)
{
    CyU3PReturnStatus_t apiRetStatus = CY_U3P_SUCCESS;

//    apiRetStatus = Fx3_Gpif_Configure(GPIF_CONFIG_SlFIFO);
//    if (apiRetStatus != CY_U3P_SUCCESS)
//	{
//#ifdef UART_ENABLE
//		CyU3PDebugPrint (4, "Gpif Configuration Failed, Error Code = %d\n",apiRetStatus);
//#endif
//		CyFxAppErrorHandler(apiRetStatus);
//	}

//    /*Initializes GPIO for SPI and Bit Banged JTAG(If Uncommented) */
//    apiRetStatus = CyFxSlFifoGpioReConfig();
//    if (apiRetStatus != CY_U3P_SUCCESS)
//	{
//#ifdef UART_ENABLE
//		CyU3PDebugPrint (4, "GIO Set Failed, Error Code = %d\n",apiRetStatus);
//#endif
//		CyFxAppErrorHandler(apiRetStatus);
//	}

#if 0
    /* Start the USB functionality. */
    apiRetStatus = CyU3PUsbStart();
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "CyU3PUsbStart failed to Start, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* callback to see if there is any overflow of data on the GPIF II side*/
    CyU3PPibRegisterCallback(gpif_error_cb,0xffff);

    /* The fast enumeration is the easiest way to setup a USB connection,
     * where all enumeration phase is handled by the library. Only the
     * class / vendor requests need to be handled by the application. */
    CyU3PUsbRegisterSetupCallback(CyFxSlFifoApplnUSBSetupCB, CyTrue);

    /* Setup the callback to handle the USB events. */
    CyU3PUsbRegisterEventCallback(CyFxSlFifoApplnUSBEventCB);

    /* Register a callback to handle LPM requests from the USB 3.0 host. */
    CyU3PUsbRegisterLPMRequestCallback(CyFxApplnLPMRqtCB);    

    /* Set the USB Enumeration descriptors */

    /* Super speed device descriptor. */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_DEVICE_DESCR, NULL, (uint8_t *)CyFxUSB30DeviceDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB set device descriptor failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* High speed device descriptor. */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_DEVICE_DESCR, NULL, (uint8_t *)CyFxUSB20DeviceDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB set device descriptor failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* BOS descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_BOS_DESCR, NULL, (uint8_t *)CyFxUSBBOSDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB set configuration descriptor failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Device qualifier descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_DEVQUAL_DESCR, NULL, (uint8_t *)CyFxUSBDeviceQualDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB set device qualifier descriptor failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Super speed configuration descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_SS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBSSConfigDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB set configuration descriptor failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* High speed configuration descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_HS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBHSConfigDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB Set Other Speed Descriptor failed, Error Code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* Full speed configuration descriptor */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_FS_CONFIG_DESCR, NULL, (uint8_t *)CyFxUSBFSConfigDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB Set Configuration Descriptor failed, Error Code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* String descriptor 0 */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 0, (uint8_t *)CyFxUSBStringLangIDDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB set string descriptor failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* String descriptor 1 */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 1, (uint8_t *)CyFxUSBManufactureDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB set string descriptor failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* String descriptor 2 */
    apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 2, (uint8_t *)CyFxUSBProductDscr);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB set string descriptor failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    /* String descriptor 3 */
	apiRetStatus = CyU3PUsbSetDesc(CY_U3P_USB_SET_STRING_DESCR, 3, (uint8_t *)CyFxUSBSerialNumDesc);
	if (apiRetStatus != CY_U3P_SUCCESS)
	{
#ifdef UART_ENABLE
		CyU3PDebugPrint (4, "USB set string descriptor failed, Error code = %d\n", apiRetStatus);
#endif
		CyFxAppErrorHandler(apiRetStatus);
	}

    /* Connect the USB Pins with super speed operation enabled. */
    apiRetStatus = CyU3PConnectState(CyTrue, CyTrue);
    if (apiRetStatus != CY_U3P_SUCCESS)
    {
#ifdef UART_ENABLE
        CyU3PDebugPrint (4, "USB Connect failed, Error code = %d\n", apiRetStatus);
#endif
        CyFxAppErrorHandler(apiRetStatus);
    }

    CyU3PUsbLPMDisable();
#endif

}
#endif

/* Switch to SlaveFIFO interface */
void
CyFxSwitchtoslFifo (
		void)
{
	CyU3PReturnStatus_t ApiRetStatus = CY_U3P_SUCCESS;
	static int first_call = 1;

	//Stop fpga config
	if(glApplnMode == MODE_FPGA_CONFIG)
		CyFxConfigFpgaApplnStop();

	//LPM = false
	//CyFxApplnLPMSuspend(CyFalse);

	//Configure GPIO
//	ApiRetStatus = CyFxSlFifoGpioReConfig();
//	if(ApiRetStatus != CY_U3P_SUCCESS )
//	{
//		#ifdef UART_ENABLE
//			CyU3PDebugPrint(4,
//			"GPIO Configuration Failed with Error Code : %d\n",ApiRetStatus);
//		#endif
//	}

	//CyFxSlFifoApplnInit();

	//Configure GPIF
	ApiRetStatus = Fx3_Gpif_Configure(GPIF_CONFIG_SlFIFO);
	if (ApiRetStatus != CY_U3P_SUCCESS)
	{
		#ifdef UART_ENABLE
				CyU3PDebugPrint (4, "Gpif Configuration Failed, Error Code = %d\n",ApiRetStatus);
		#endif
				CyFxAppErrorHandler(ApiRetStatus);
	}

	first_call = 0;//comment it gokul

	//Start slfifo - configure EP and DMA
	//if(first_call == 0)
	//{
		CyFxSlFifoApplnStart();

		//Update the status variable
		glApplnMode = MODE_SLFIFO_CONFIG;
	//}
	first_call = 0;

	return;
}
#if 0
/*		Switch to FPAG Config Mode	*/
void
CyFxSwitchtoFpgaConfig(
			void)
{

	CyU3PReturnStatus_t ApiRetStatus = CY_U3P_SUCCESS;
	static int first_call = 1;

	if(glApplnMode == MODE_SLFIFO_CONFIG)
		CyFxSlFifoApplnStop ();

	//LPM = false
	//CyFxApplnLPMSuspend(CyFalse);		//changed from false to true

	//Configure GPIO
//	ApiRetStatus = CyFxSlFifoGpioReConfig();
//	if(ApiRetStatus != CY_U3P_SUCCESS )
//	{
//		#ifdef UART_ENABLE
//			CyU3PDebugPrint(4,
//			"GPIO Configuration Failed with Error Code : %d\n",ApiRetStatus);
//		#endif
//	}

	//Configure GPIF
	ApiRetStatus = Fx3_Gpif_Configure(GPIF_CONFIG_FPGA_FW_LOAD);
	if (ApiRetStatus != CY_U3P_SUCCESS)
	{
		#ifdef UART_ENABLE
				CyU3PDebugPrint (4, "Gpif Configuration Failed, Error Code = %d\n",ApiRetStatus);
		#endif
				CyFxAppErrorHandler(ApiRetStatus);
	}

	//Configure DMA and EP
	if(first_call == 0)
		CyFxConfigFpgaApplnStart();	//Uncomment it after verifying how to handle;

	 first_call = 0;

	/* Start configuring FPGA */
	ApiRetStatus = CyFxConfigFpgaStart(filelen);
	if(ApiRetStatus != CY_U3P_SUCCESS )
	{
		#ifdef UART_ENABLE
			CyU3PDebugPrint(4,
			"Configuration start of FPGA Failed with Error Code : %d\n",ApiRetStatus);
		#endif
	}

	glApplnMode = MODE_FPGA_CONFIG;

	return;
}
#endif
/* Entry function for the slFifoAppThread. */
void
SlFifoAppThread_Entry (
        uint32_t input)
{
	uint32_t eventFlag;
	CyU3PReturnStatus_t txApiRetStatus = CY_U3P_SUCCESS;
	static int first_call = 1;

	/* Initialize the debug module */
    CyFxSlFifoApplnDebugInit();

    /* Initialise GPIOs*/
    CyFxGpioInitialization();

    /* Initialize the FPGA configuration application */
    CyFxUsbInit();		//Also setting glapplnmode as slfifo in this function as intial value

    //Trial - configuring the gpif of the current mode
    if(glApplnMode == MODE_SLFIFO_CONFIG)
        txApiRetStatus = Fx3_Gpif_Configure(GPIF_CONFIG_SlFIFO);
	else if(glApplnMode == MODE_FPGA_CONFIG)
	    txApiRetStatus = Fx3_Gpif_Configure(GPIF_CONFIG_FPGA_FW_LOAD);
	if (txApiRetStatus != CY_U3P_SUCCESS)
	{
		#ifdef UART_ENABLE
				CyU3PDebugPrint (4, "Gpif Configuration Failed, Error Code = %d\n",txApiRetStatus);
		#endif
				CyFxAppErrorHandler(txApiRetStatus);
	}

    for (;;)
    {
        //CyU3PThreadSleep (1000);

        if (glIsApplnActive)
        {

        	/* Wait for events to configure FPGA */
			txApiRetStatus = CyU3PEventGet (&glFxConfigFpgaAppEvent,
			   (CY_FX_CONFIGFPGAAPP_START_EVENT | CY_FX_CONFIGFPGAAPP_SW_TO_SLFIFO_EVENT),
			   CYU3P_EVENT_OR_CLEAR, &eventFlag, CYU3P_WAIT_FOREVER);
			if (txApiRetStatus == CY_U3P_SUCCESS)
			{
				if (eventFlag & CY_FX_CONFIGFPGAAPP_START_EVENT)
				{
//					#ifdef UART_ENABLE
//						CyU3PDebugPrint(4,
//						"\nSwitching to Fpga Config Mode, previous =  %d\n", glApplnMode);
//					#endif

					if(glApplnMode == MODE_SLFIFO_CONFIG)
					{
						#ifdef UART_ENABLE
							CyU3PDebugPrint(4,
							"\nStopping SLFIFO, Switching to Fpga Config Mode, previous =  %d\n", glApplnMode);
						#endif

						CyFxSlFifoApplnStop ();
					}

					first_call = 0;//comment it gokul

					//Switch to slave FPGA Config
					if(glApplnMode != MODE_FPGA_CONFIG)
					{
						//Configure DMA and EP
						if(first_call == 0)
						{
							#ifdef UART_ENABLE
								CyU3PDebugPrint (4,
										"Entering second time\n");
							#endif

							CyFxConfigFpgaApplnInit();

							CyFxConfigFpgaApplnStart();

							//Configure GPIF
	//						txApiRetStatus = Fx3_Gpif_Configure(GPIF_CONFIG_FPGA_FW_LOAD);
	//						if (txApiRetStatus != CY_U3P_SUCCESS)
	//						{
	//							#ifdef UART_ENABLE
	//									CyU3PDebugPrint (4,
	//											"Gpif Configuration Failed, Error Code = %d\n",txApiRetStatus);
	//							#endif
	//									CyFxAppErrorHandler(txApiRetStatus);
	//						}
						}
					}
					first_call = 0;

					txApiRetStatus = CyFxConfigFpgaStart(filelen);
					if(txApiRetStatus != CY_U3P_SUCCESS )
					{
						#ifdef UART_ENABLE
							CyU3PDebugPrint(4,
							"Configuration start of FPGA Failed with Error Code : %d\n",txApiRetStatus);
						#endif
					}

					glApplnMode = MODE_FPGA_CONFIG;

					//CyFxSwitchtoFpgaConfig();
				}
				else if ((eventFlag & CY_FX_CONFIGFPGAAPP_SW_TO_SLFIFO_EVENT))
				{
					#ifdef UART_ENABLE
						CyU3PDebugPrint(4,
						"\nSwitching to SlaveFIFO Interface, previous = %d \n", glApplnMode);
					#endif

					//Switch to slave FIFO
					if(glApplnMode != MODE_SLFIFO_CONFIG)
						CyFxSwitchtoslFifo();
				}
			}

            /* Print the number of buffers received so far from the USB host. */
            /*CyU3PDebugPrint (6, "Data tracker: buffers received: %d, buffers sent: %d.\r\n",
                    glDMARxCount, glDMATxCount);*/
        }
    }
}

/* Application define function which creates the threads. */
void
CyFxApplicationDefine (
        void)
{
    void *ptr = NULL;
    uint32_t retThrdCreate = CY_U3P_SUCCESS;

    /* Allocate the memory for the thread */
    ptr = CyU3PMemAlloc (CY_FX_SLFIFO_THREAD_STACK);

    /* Create the thread for the application */
    retThrdCreate = CyU3PThreadCreate (&slFifoAppThread,           /* Slave FIFO app thread structure */
                          "21:Slave_FIFO_sync",                    /* Thread ID and thread name */
                          SlFifoAppThread_Entry,                   /* Slave FIFO app thread entry function */
                          0,                                       /* No input parameter to thread */
                          ptr,                                     /* Pointer to the allocated thread stack */
                          CY_FX_SLFIFO_THREAD_STACK,               /* App Thread stack size */
                          CY_FX_SLFIFO_THREAD_PRIORITY,            /* App Thread priority */
                          CY_FX_SLFIFO_THREAD_PRIORITY,            /* App Thread pre-emption threshold */
                          CYU3P_NO_TIME_SLICE,                     /* No time slice for the application thread */
                          CYU3P_AUTO_START                         /* Start the thread immediately */
                          );

    /* Check the return code */
    if (retThrdCreate != 0)
    {
        /* Thread Creation failed with the error code retThrdCreate */

        /* Add custom recovery or debug actions here */

        /* Application cannot continue */
        /* Loop indefinitely */
        while(1);
    }
}

#if 0
/*
 * Main function
 */
int
main (void)
{
    CyU3PIoMatrixConfig_t io_cfg;
    CyU3PReturnStatus_t status = CY_U3P_SUCCESS;
    CyU3PSysClockConfig_t clkCfg;

        /* setSysClk400 clock configurations */
        clkCfg.setSysClk400 = CyTrue;   /* FX3 device's master clock is set to a frequency > 400 MHz */
        clkCfg.cpuClkDiv = 2;           /* CPU clock divider */
        clkCfg.dmaClkDiv = 2;           /* DMA clock divider */
        clkCfg.mmioClkDiv = 2;          /* MMIO clock divider */
        clkCfg.useStandbyClk = CyFalse; /* device has no 32KHz clock supplied */
        clkCfg.clkSrc = CY_U3P_SYS_CLK; /* Clock source for a peripheral block  */

    /* Initialize the device */
    status = CyU3PDeviceInit (&clkCfg);
    if (status != CY_U3P_SUCCESS)
    {
        goto handle_fatal_error;
    }

    /* Initialize the caches. Enable instruction cache and keep data cache disabled.
     * The data cache is useful only when there is a large amount of CPU based memory
     * accesses. When used in simple cases, it can decrease performance due to large 
     * number of cache flushes and cleans and also it adds to the complexity of the
     * code. */
    status = CyU3PDeviceCacheControl (CyTrue, CyFalse, CyFalse);
    if (status != CY_U3P_SUCCESS)
    {
        goto handle_fatal_error;
    }

    /* Configure the IO matrix for the device. On the FX3 DVK board, the COM port 
     * is connected to the IO(53:56). This means that either DQ32 mode should be
     * selected or lppMode should be set to UART_ONLY. Here we are choosing
     * UART_ONLY configuration for 16 bit slave FIFO configuration and setting
     * isDQ32Bit for 32-bit slave FIFO configuration. */

    CyU3PMemSet ((uint8_t *)&io_cfg, 0, sizeof(io_cfg));
    io_cfg.s0Mode = CY_U3P_SPORT_INACTIVE;
    io_cfg.s1Mode = CY_U3P_SPORT_INACTIVE;


#ifdef UART_ENABLE
    io_cfg.useUart   = CyTrue;
#endif

#ifdef SPI_ENABLE
    io_cfg.useUart   = CyFalse;
#endif

    io_cfg.useI2C    = CyTrue;
    io_cfg.useI2S    = CyFalse;
    io_cfg.useSpi   = CyFalse;
    io_cfg.isDQ32Bit = CyTrue;
    io_cfg.lppMode   = CY_U3P_IO_MATRIX_LPP_DEFAULT;
    /* GPIO's are enabled. */
    io_cfg.gpioSimpleEn[0]  = 0;
    io_cfg.gpioSimpleEn[1]  = 0x01E00000; /* SPI - GPIO 53,54,55,56; (BitBanged JTAG -GPIO 57,52,51,50 = 0x021C0000;) - Not Added*/
    io_cfg.gpioComplexEn[0] = 0;
    io_cfg.gpioComplexEn[1] = 0;
    status = CyU3PDeviceConfigureIOMatrix (&io_cfg);
    if (status != CY_U3P_SUCCESS)
    {
        goto handle_fatal_error;
    }

    /* This is a non returnable call for initializing the RTOS kernel */
    CyU3PKernelEntry ();

    /* Dummy return to make the compiler happy */
    return 0;

handle_fatal_error:

    /* Cannot recover from this error. */
    while (1);
}
#endif

/* [ ] */

