/* ======================================================================
 *   Copyright (c) 2022 Texas Instruments Incorporated
 *
 *   All rights reserved. Property of Texas Instruments Incorporated.
 *   Restricted rights to use, duplicate or disclose this code are
 *   granted through contract.
 *
 *   The program may not be used without the written permission
 *   of Texas Instruments Incorporated or against the terms and conditions
 *   stipulated in the agreement under which this program has been
 *   supplied.
 * ==================================================================== */

/**
 *  \file     MibspiApp.c
 *
 *  \brief    This file contains the SPI test example for MibSPI
 *
 */

/* ========================================================================== */
/*                             Include Files                                  */
/* ========================================================================== */

/*LDRA_NOANALYSIS*/
#include "string.h"
#include "Std_Types.h"
#include "Det.h"
#include "Dem.h"
/*LDRA_ANALYSIS*/
#include "Spi_Cfg.h"
#include "Spi.h"
#include "Spi_Dbg.h"
#include "SchM_Spi.h"
#include "EcuM_Cbk.h"
#include "Mcu.h"
#include "Mcu_Cfg.h"
#include "Port_Cfg.h"
#include "Port.h"
#include "SchM_Port.h"
#include "hw_types.h"

/* Starterware Includes */
#include "app_utils.h"
#include "trace.h"
#include "sys_vim.h"
#include "McspiApp.h"

#include "hw_mcspi.h"
#include "Spi_Irq.h"
/* ========================================================================== */
/*                           Macros & Typedefs                                */
/* ========================================================================== */

#define ARRAYSIZE(x)                    (sizeof ((x)) / sizeof (x[0U]))

/* UART read timeout in msec */
#define SPI_APP_UART_TIMEOUT_MSEC       (10000U)
#define APP_PERFORMANCE_MODE   STD_OFF

/* ========================================================================== */
/*                         Structures and Enums                               */
/* ========================================================================== */

/* None */

/* ========================================================================== */
/*                 Internal Function Declarations                             */
/* ========================================================================== */



/* ========================================================================== */
/*                            Global Variables                                */
/* ========================================================================== */

uint32                          SpiApp_TestPassed = E_OK;
uint8 gMcspiTxBuffer[SPI_MAX_CHANNELS][RX_TX_BUF_SIZE_WORD];
uint8 gMcspiRxBuffer[SPI_MAX_CHANNELS][RX_TX_BUF_SIZE_WORD];

uint32 Performance_Result[30];
void Stop_Timer(uint8 Api_Id);
void Start_Timer(void);
#if (STD_ON == APP_PERFORMANCE_MODE)
static void MCSPIExample_PerformanceTest();
#endif
volatile uint32                 SpiApp_McspiJobDone[SPI_MAX_JOBS +1],
                                SpiApp_McspiSeqDone[SPI_MAX_SEQ +1];
								
uint32 						frc;//,mask = 0x00000000U;



#if (STD_OFF == MCU_NO_PLL)
extern CONST(Mcu_ConfigType, MCU_PBCFG) McuModuleConfiguration_0;
#endif

/** \brief SPI Channel PC Configuration struct declaration */
extern const struct Spi_ChannelConfigType_PC_s Spi_ChannelConfig_PC[SPI_MAX_CHANNELS];

/** \brief SPI Job PC Configuration struct declaration */
extern const struct Spi_JobConfigType_PC_s Spi_JobConfig_PC[SPI_MAX_JOBS];

/** \brief SPI Sequence PC Configuration struct declaration */
extern const struct Spi_SeqConfigType_PC_s Spi_SeqConfig_PC[SPI_MAX_SEQ];

static void SpiApp_platformInit(void);
static void SpiApp_interruptConfig(void);

static Mcu_RamSectionConfigType gSpiAppMcuRamConfig[] =
{
    [0U] =
    {
    .Mcu_RamSectionBaseAddress = (uint8 *) &gMcspiRxBuffer[0U][0U],
    .Mcu_RamDefaultValue       = 0x00U,
    .Mcu_RamSectionBytes       = sizeof (gMcspiRxBuffer)
    },
	[1U] =
    {
    .Mcu_RamSectionBaseAddress = (uint8 *) &gMcspiTxBuffer[0U][0U],
    .Mcu_RamDefaultValue       = 0x00U,
    .Mcu_RamSectionBytes       = sizeof (gMcspiTxBuffer)
    },
    
};

static Mcu_ClockConfigType gMcspiAppMcuClockConfig[] =
{
[0] =
{
.Mcu_InitCfg = TRUE,
.Mcu_ClockModuleId = MCU_CLKSRC_MODULE_ID_MCSPI0,
.Mcu_ClockSourceId = MCU_CLKSRC_4,
.Mcu_ClockDiv = 7U /* mcu clock div for 80 MhZ, with 400 MHz clock */
},
[1] = 
   { .Mcu_InitCfg       = TRUE,
    .Mcu_ClockModuleId = MCU_CLKSRC_MODULE_ID_RTI0,   
    .Mcu_ClockSourceId = MCU_CLKSRC_2,    
    .Mcu_ClockDiv = 0U // Source = Sysclk ie 200MHz, so (200/(0+1) = 200MHz with 200MHz clk)
   }
};


static Mcu_ConfigType            gSpiAppMcuConfig =
{
    .Mcu_ResetMode           = MCU_PERFORM_RESET_MODE_WARM,
    .Mcu_ConfigRamSection    = &gSpiAppMcuRamConfig[0U],
    .Mcu_NumberOfRamSectors  = ARRAYSIZE(gSpiAppMcuRamConfig),
    .Mcu_ClockConfig         = (Mcu_ClockConfigPtrType) gMcspiAppMcuClockConfig,
    .Mcu_NumberOfClockConfig = 1U
};

#define SPI_APP_NUM_CLK_LIST            (sizeof (gClkDividerTestList) / \
                                         sizeof (gClkDividerTestList[0U]))
/* ========================================================================== */
/*                          Function Definitions                              */
/* ========================================================================== */

int main(void)
{
	uint32              index, chIndex, isPending;
    uint32              testPassed = E_OK, matching;
    uint8              *tempTxPtr, *tempRxPtr;
    uint32              byteLength[SPI_MAX_CHANNELS] = {0U};
    uint32              xferLength[SPI_MAX_CHANNELS] = {0U};
    Std_ReturnType      retVal;
    Spi_StatusType      status;
    Spi_SeqResultType   seqResult;
    Spi_JobResultType   jobResult;
    Spi_ChannelType     chId;
    Spi_SequenceType    seqId;
    Spi_JobType         jobId;
	const Spi_ConfigType *cfgPtr = &SpiDriver;
	Std_VersionInfoType versioninfo;

#ifdef DIAB
    AppUtils_defaultInitDiab();
#else     
    AppUtils_defaultInit();
#endif

    SpiApp_platformInit();

    AppUtils_printf(APP_NAME ": Sample Application - STARTS !!!\n\r");

#if (SPI_VERSION_INFO_API == STD_ON)
    /* Get and print version */
    Spi_GetVersionInfo(&versioninfo);
    AppUtils_printf(" \n");
    AppUtils_printf("SPI MCAL Version Info\n\r");
    AppUtils_printf("---------------------\n\r");
    AppUtils_printf("Vendor ID           : %d\n\r", versioninfo.vendorID);
    AppUtils_printf("Module ID           : %d\n\r", versioninfo.moduleID);
    AppUtils_printf("SW Major Version    : %d\n\r", versioninfo.sw_major_version);
    AppUtils_printf("SW Minor Version    : %d\n\r", versioninfo.sw_minor_version);
    AppUtils_printf("SW Patch Version    : %d\n\r", versioninfo.sw_patch_version);
    AppUtils_printf(" \n");
#endif  /* #if (SPI_VERSION_INFO_API == STD_ON) */

#if (STD_ON == APP_PERFORMANCE_MODE)
MCSPIExample_PerformanceTest();
#endif
/* Print test case information */
    AppUtils_printf(APP_NAME ": CH %d: JOBS %d: SEQ %d: HWUNIT %d: NUM OF WORDS %d:!!!\n\r",
        cfgPtr->maxChannels,
        cfgPtr->maxJobs,
        cfgPtr->maxSeq,
        cfgPtr->maxHwUnit,
        SPI_APP_RX_TX_LENGTH);
		/* Init */
    Spi_Init(cfgPtr);
    SpiApp_interruptConfig();
		
		/* SPI driver should be free now - check */

    status = Spi_GetStatus();
    if (status != SPI_IDLE)
    {
        testPassed = E_NOT_OK;
        AppUtils_printf(
        APP_NAME ": SPI driver is not IDLE!!\n");
    }
	#if (SPI_HW_STATUS_API == STD_ON)
    /* SPI HW unit should be free now - check */
    for (index = 0U; index < cfgPtr->maxHwUnit; index++)
    {
        status =
            Spi_GetHWUnitStatus(cfgPtr->hwUnitCfg[index].hwUnitId);
        if (status != SPI_IDLE)
        {
            testPassed = E_NOT_OK;
            AppUtils_printf(
                APP_NAME ": SPI HW %d is not IDLE!!\n",
                            cfgPtr->hwUnitCfg[index].hwUnitId);
        }
    }
#endif  /* #if (SPI_HW_STATUS_API == STD_ON) */

#if (STD_OFF == SPI_DMA_ENABLE)
#if (SPI_SCALEABILITY == SPI_LEVEL_2)
    /* Set Async mode */
    /** \brief Default ASYNC/SYNC Transmit flag - TRUE: Async, FALSE: Sync */
    retVal = Spi_SetAsyncMode(SPI_APP_DEFAULT_ASYNC_MODE);
    if (retVal != E_OK)
    {
        testPassed = E_NOT_OK;
        AppUtils_printf(
            APP_NAME ": SPI Set Async Mode Failed!!\n");
    }
#endif  /* #if (SPI_SCALEABILITY == SPI_LEVEL_2) */
#endif  /* #if (STD_OFF == SPI_DMA_ENABLE) */

    /* Init test params */
    for (chIndex = 0U; chIndex < cfgPtr->maxChannels; chIndex++)
    {
        /* Init TX buffer with known data and memset RX buffer */
        tempTxPtr = (Spi_DataBufferType *) &gMcspiTxBuffer[chIndex][0U];
        tempRxPtr = (Spi_DataBufferType *) &gMcspiRxBuffer[chIndex][0U];
        for (index = 0U; index < (RX_TX_BUF_SIZE_WORD); index++)
        {
            *tempTxPtr++ = (Spi_DataBufferType) (index + 1U);
            *tempRxPtr++ = 0U;
        }
		if (cfgPtr->channelCfg[chIndex].dataWidth <= 8U)
        {
            xferLength[chIndex] = SPI_APP_RX_TX_LENGTH;
        }
        else if (cfgPtr->channelCfg[chIndex].dataWidth <= 16U)
        {
            xferLength[chIndex] = SPI_APP_RX_TX_LENGTH / 2;
        }
        else
        {
            xferLength[chIndex] = SPI_APP_RX_TX_LENGTH / 4;
        }
    }

    for (chIndex = 0U; chIndex < cfgPtr->maxChannels; chIndex++)
    {
        /* Memset RX buffer for every run */
        if (cfgPtr->channelCfg[chIndex].dataWidth <= 8U)
        {
            byteLength[chIndex] = xferLength[chIndex];
        }
        else if (cfgPtr->channelCfg[chIndex].dataWidth <= 16U)
        {
            byteLength[chIndex] = xferLength[chIndex] * 2U;
        }
        else
        {
            byteLength[chIndex] = xferLength[chIndex] * 4U;
        }
        tempRxPtr = (uint8 *) &gMcspiRxBuffer[chIndex][0U];
        for (index = 0U; index < byteLength[chIndex]; index++)
        {
            *tempRxPtr++ = 0U;
        }
		       /* SetUp Buffers */
#if ((SPI_CHANNELBUFFERS == SPI_IB_EB) || (SPI_CHANNELBUFFERS == SPI_EB))
        if (SPI_EB == cfgPtr->channelCfg[chIndex].channelBufType)
        {
            Spi_DataBufferType *srcDataBuf, *destDataBuf;

            /* Setup EB for TX/RX */
            srcDataBuf  = (Spi_DataBufferType *) &gMcspiTxBuffer[chIndex][0U];
            destDataBuf = (Spi_DataBufferType *) &gMcspiRxBuffer[chIndex][0U];
            chId        = Spi_ChannelConfig_PC[chIndex].channelId;
            retVal      = Spi_SetupEB(
                chId,
                srcDataBuf,
                destDataBuf,
                xferLength[chIndex]);
            if (retVal != E_OK)
            {
                testPassed = E_NOT_OK;
                AppUtils_printf(
                    APP_NAME ": SPI Setup EB Failed!!\n\r");
            }
        }
#endif
#if ((SPI_CHANNELBUFFERS == SPI_IB_EB) || (SPI_CHANNELBUFFERS == SPI_IB))
        if (SPI_IB == cfgPtr->channelCfg[chIndex].channelBufType)
        {
            Spi_DataBufferType *srcDataBuf;

            /* Write TX data to IB */
            srcDataBuf = (Spi_DataBufferType *) &gMcspiTxBuffer[chIndex][0U];
            chId = Spi_ChannelConfig_PC[chIndex].channelId;
            retVal = Spi_WriteIB(chId, srcDataBuf);
            if (retVal != E_OK)
            {
                testPassed = E_NOT_OK;
                AppUtils_printf(
                    APP_NAME ": SPI Write IB Failed!!\n\r");
            }
        }
#endif
    }

    /* Reset flags */
    for (index = 0U; index < SPI_MAX_JOBS; index++)
    {
        SpiApp_McspiJobDone[index] = FALSE;
    }

    for (index = 0U; index < SPI_MAX_SEQ; index++)
    {
        SpiApp_McspiSeqDone[index] = FALSE;
    }

#if (STD_ON == SPI_DMA_ENABLE)
    for (chIndex = 0U;
         chIndex < cfgPtr->maxChannels;
         chIndex++)
    {
        SpiApp_wbCache((Spi_DataBufferType *)&gMcspiTxBuffer[chIndex][0U], RX_TX_BUF_SIZE_WORD * sizeof(gMcspiTxBuffer[chIndex][0U]));
        SpiApp_wbCache((Spi_DataBufferType *)&gMcspiRxBuffer[chIndex][0U], RX_TX_BUF_SIZE_WORD * sizeof(gMcspiRxBuffer[chIndex][0U]));
    }
#endif
#if ((SPI_SCALEABILITY == SPI_LEVEL_1) || \
(SPI_SCALEABILITY == SPI_LEVEL_2))
    AppUtils_printf(
        APP_NAME ": SPI Async transmit in progress!!\n\r");
    for (index = 0U; index < cfgPtr->maxSeq; index++)
    {
        /* Start the TX/RX */
        seqId  = Spi_SeqConfig_PC[index].seqId;
        retVal = Spi_AsyncTransmit(seqId);
        if (retVal != E_OK)
        {
            testPassed = E_NOT_OK;
            AppUtils_printf(
                APP_NAME ": SPI Async transmit Failed!!\n\r");
        }
    }

    if (SPI_INTERRUPT_MODE == SPI_APP_DEFAULT_ASYNC_MODE)
    {
        /* Wait for TX/RX to get over */
        while (1U)
        {
            isPending = FALSE;
            for (index = 0U; index < cfgPtr->maxSeq;
                 index++)
            {
                if (SpiApp_McspiSeqDone[index] == FALSE)
                {
                    isPending = TRUE;
                    break;
                }
            }
            for (index = 0U; index < cfgPtr->maxJobs;
                 index++)
            {
                if (SpiApp_McspiJobDone[index] == FALSE)
                {
                    isPending = TRUE;
                    break;
                }
            }
            if (FALSE == isPending)
            {
                break;
            }
        }
    }
    else
    {
        while (1U)
        {
            Spi_MainFunction_Handling();

            isPending = FALSE;
            for (index = 0U; index < cfgPtr->maxSeq;
                 index++)
            {
                seqResult = Spi_GetSequenceResult(index);
                if (seqResult != SPI_SEQ_OK)
                {
                    isPending = TRUE;
                    break;
                }
            }
            for (index = 0U; index < cfgPtr->maxJobs;
                 index++)
            {
                jobResult = Spi_GetJobResult(index);
                if (jobResult != SPI_JOB_OK)
                {
                    isPending = TRUE;
                    break;
                }
            }

            /* All jobs/sequences completed */
            if (FALSE == isPending)
            {
                break;
            }
        }
    }
#endif

#if ((SPI_SCALEABILITY == SPI_LEVEL_0) || \
(SPI_SCALEABILITY == SPI_LEVEL_2))
    for (index = 0U; index < cfgPtr->maxSeq; index++)
    {
        /* Start the TX/RX */
        seqId  = Spi_SeqConfig_PC[index].seqId;
        retVal = Spi_SyncTransmit(seqId);
        if (retVal != E_OK)
        {
            testPassed = E_NOT_OK;
            AppUtils_printf(
                APP_NAME ": SPI Sync transmit Failed!!\n\r");
        }
    }
#endif

    /* SPI driver should be free now - check */
    status = Spi_GetStatus();
    if (status != SPI_IDLE)
    {
        testPassed = E_NOT_OK;
        AppUtils_printf(
            APP_NAME ": SPI driver is not IDLE!!\n\r");
    }
    for (index = 0U; index < cfgPtr->maxSeq; index++)
    {
        seqId     = Spi_SeqConfig_PC[index].seqId;
        seqResult = Spi_GetSequenceResult(seqId);
        if (seqResult != SPI_SEQ_OK)
        {
            if (seqResult == SPI_SEQ_CANCELLED)
            {
                AppUtils_printf(
                    APP_NAME ": SPI Sequence was cancelled!!\n\r");
            }
            else
            {
                testPassed = E_NOT_OK;
                AppUtils_printf(
                    APP_NAME ": SPI Sequence is not OK!!\n\r");
            }
        }
    }

    for (index = 0U; index < cfgPtr->maxJobs; index++)
    {
        jobId     = Spi_JobConfig_PC[index].jobId;
        jobResult = Spi_GetJobResult(jobId);
        if (jobResult != SPI_JOB_OK)
        {
            testPassed = E_NOT_OK;
            AppUtils_printf(
                APP_NAME ": SPI Job is not OK!!\n\r");
        }
    }
#if (STD_ON == SPI_DMA_ENABLE)
    for (chIndex = 0U;
         chIndex < cfgPtr->maxChannels;
         chIndex++)
    {
        SpiApp_invCache((uint8 *)&gMcspiRxBuffer[chIndex][0U], RX_TX_BUF_SIZE_WORD * sizeof(gMcspiRxBuffer[chIndex][0U]));
    }
#endif

#if (STD_ON == SPI_REGISTER_READBACK_API)
    for (index = 0U; index < cfgPtr->maxHwUnit; index++)
    {
        Spi_RegisterReadbackType  RegReadback, *RegRbPtr;
        RegRbPtr = &RegReadback;
        retVal = Spi_RegisterReadback(cfgPtr->hwUnitCfg[index].hwUnitId, RegRbPtr);
        if (retVal != E_OK)
        {
            AppUtils_printf(
                APP_NAME ": SPI configuration Register Readback Failed!!\n\r");
        }
        else
        {
            /* AppUtils_printf( APP_NAME
                ": SPI Hwunit %d configuration Register Readback values  \n",
                (cfgPtr->hwUnitCfg[index].hwUnitId) );
            AppUtils_printf(  APP_NAME
                ": MCSPI_HL_REV 			: 0x%x\n", RegRbPtr->mcspiHlRev);
            AppUtils_printf(  APP_NAME
                ": MCSPI_HL_HWINFO 		: 0x%x\n", RegRbPtr->mcspiHlHwInfo);
            AppUtils_printf(  APP_NAME
                ": MCSPI_HL_SYSCONFIG 		: 0x%x\n", RegRbPtr->mcspiHlSysConfig);
            AppUtils_printf(  APP_NAME
                ": MCSPI_REVISION 			: 0x%x\n", RegRbPtr->mcspiRev);
            AppUtils_printf(  APP_NAME
                ": MCSPI_SYSSTATUS 		: 0x%x\n", RegRbPtr->mcspiSysStatus);
            AppUtils_printf(  APP_NAME
                ": MCSPI_SYST 			: 0x%x\n", RegRbPtr->mcspiSyst);
            AppUtils_printf(  APP_NAME
                ": MCSPI_MODULCTRL 		: 0x%x\n", RegRbPtr->mcspiModulctrl);
            AppUtils_printf(  APP_NAME
                ": MCSPI_SYSCONFIG 		: 0x%x\n", RegRbPtr->mcspiSysConfig);
            AppUtils_printf(  APP_NAME
                ": MCSPI_CH0CONF 			: 0x%x\n", RegRbPtr->mcspiCh0config);
            AppUtils_printf(  APP_NAME
                ": MCSPI_CH1CONF 			: 0x%x\n", RegRbPtr->mcspiCh1config);
            AppUtils_printf(  APP_NAME
                ": MCSPI_CH2CONF 			: 0x%x\n", RegRbPtr->mcspiCh2config);
            AppUtils_printf(  APP_NAME
                ": MCSPI_CH3CONF 			: 0x%x\n", RegRbPtr->mcspiCh3config);
            AppUtils_printf(  APP_NAME
                ": MCSPI_IRQENABLE 		: 0x%x\n", RegRbPtr->mcspiIrqenable); */
        }
    }
#endif
#if ((SPI_CHANNELBUFFERS == SPI_IB_EB) || (SPI_CHANNELBUFFERS == SPI_IB))
    for (chIndex = 0U; chIndex < cfgPtr->maxChannels; chIndex++)
    {
        if (SPI_IB == cfgPtr->channelCfg[chIndex].channelBufType)
        {
            Spi_DataBufferType *destDataBuf;

            /* Read RX data from IB to app buffer */
            destDataBuf = (Spi_DataBufferType *) &gMcspiRxBuffer[chIndex][0U];
            chId = Spi_ChannelConfig_PC[chIndex].channelId;
            retVal = Spi_ReadIB(chId, destDataBuf);
            if (retVal != E_OK)
            {
                testPassed = E_NOT_OK;
                AppUtils_printf(
                    APP_NAME ": SPI Read IB Failed!!\n\r");
            }
        }
    }
#endif
 /* Check RX buffer against TX buffer */
    matching = TRUE;
    for (chIndex = 0U;
         chIndex < cfgPtr->maxChannels;
         chIndex++)
    {
        tempTxPtr = (Spi_DataBufferType *) &gMcspiTxBuffer[chIndex][0U];
        tempRxPtr = (Spi_DataBufferType *) &gMcspiRxBuffer[chIndex][0U];
        for (index = 0U; index < byteLength[chIndex]; index++)
        {
            if (*tempTxPtr++ != *tempRxPtr++)
            {
                matching = FALSE;
            }
        }
    }
    if (TRUE != matching)
    {
        testPassed = E_NOT_OK;
        AppUtils_printf(
            APP_NAME ": McSPI data mismatch error!!\n\r");
    }

    if (testPassed == E_OK)
    {
        for (chIndex = 0U; chIndex < cfgPtr->maxChannels; chIndex++)
        {

            xferLength[chIndex] = SPI_APP_RX_TX_LENGTH;
        }
    }

    /* DeInit */
    if (testPassed == E_OK)
    {
        retVal = Spi_DeInit();
        if (retVal != E_OK)
        {
            testPassed = E_NOT_OK;
            AppUtils_printf(
                APP_NAME ": SPI Deinit Failed!!\n\r");
        }
    }

    if (testPassed == E_OK)
    {
        /* SPI driver should be uninit now - check */
        status = Spi_GetStatus();
        if (status != SPI_UNINIT)
        {
            testPassed = E_NOT_OK;
            AppUtils_printf(
                APP_NAME ": SPI driver is not in uninit state!!\n\r");
        }
    }

   /*  if (testPassed == E_OK)
    {
        AppUtils_printf(
            APP_NAME ": SPI Stack Usage: %d bytes\n", AppUtils_getStackUsage());
        if (AppUtils_checkStackAndSectionCorruption() != E_OK)
        {
            testPassed = E_NOT_OK;
            AppUtils_printf(
                APP_NAME ": SPI Stack/section corruption!!!\n\r");
        }
    } */

    if (E_OK == testPassed)
    {
        SpiApp_TestPassed = testPassed;
        AppUtils_printf(
            APP_NAME ": SPI Loopback Test Passed!!!\n\r");
        
    }
    else
    {
        SpiApp_TestPassed = testPassed;
        AppUtils_printf(
            APP_NAME ": SPI Loopback Test Failed!!!\n\r");
    }

    return (SpiApp_TestPassed);
}

#if (STD_ON == APP_PERFORMANCE_MODE)
static void MCSPIExample_PerformanceTest()
{
    char           option;
    boolean quit_opt = 0;
    uint32 cntr_cnt;//,mask = 0x00000000U;
    const Spi_ConfigType *Spi_ConfigPtr;
	Std_VersionInfoType Spi_Version;
	Spi_DataBufferType *srcDataBuf;
	Spi_DataBufferType *destDataBuf;
    Spi_ConfigPtr = &SpiDriver;
	
	Start_Timer();
	Spi_GetVersionInfo(&Spi_Version);
	Stop_Timer(0);
	
	Start_Timer();
	Spi_Init(Spi_ConfigPtr);
	Stop_Timer(1);
	
	Start_Timer();
	Spi_GetJobResult(0U);
	Stop_Timer(2);
	
	Start_Timer();
	Spi_GetSequenceResult(0U);
	Stop_Timer(3);
	
	Start_Timer();
	Spi_GetHWUnitStatus(0U);
	Stop_Timer(4);
	
	srcDataBuf = (Spi_DataBufferType *) &gMcspiTxBuffer[0][0U];
	destDataBuf = (Spi_DataBufferType *) &gMcspiRxBuffer[0][0U];
	
	Start_Timer();
	Spi_SetupEB(0, srcDataBuf, destDataBuf, 25);
	Stop_Timer(5);
	
    
	Start_Timer();
	Spi_WriteIB(3, srcDataBuf);
	Stop_Timer(6);

	Start_Timer();
	Spi_AsyncTransmit(0);
	Stop_Timer(7);
	
	
	Start_Timer();
	Spi_ReadIB(3, destDataBuf);
	Stop_Timer(8);
	
	Start_Timer();
	Spi_Cancel(0);
	Stop_Timer(10);
	
	Start_Timer();
	Spi_SetAsyncMode(SPI_INTERRUPT_MODE);
	Stop_Timer(11);
	
	Start_Timer();
	Spi_MainFunction_Handling();
	Stop_Timer(12);
	
	Start_Timer();
	Spi_DeInit();
	Stop_Timer(13);
}

#endif

static void SpiApp_platformInit(void)
{
   uint16 mss_uart_tx_pin, mss_uart_rx_pin;
#if (STD_OFF == MCU_NO_PLL)
    uint32 sys_clk_freq_vclk_const;

    /* MCU PLL Config */
    gSpiAppMcuConfig.Mcu_PllConfig = McuModuleConfiguration_0.Mcu_PllConfig;
    gSpiAppMcuConfig.Mcu_PllSourceId = McuModuleConfiguration_0.Mcu_PllSourceId;
#endif

	Mcu_Init(&McuModuleConfiguration);
	Port_Init(PortConfigSet_0_pt);

	 mss_uart_tx_pin = 13;
    mss_uart_rx_pin = 14;
	
	// Set up the pinmux for UART tx
    Port_SetPinMode(mss_uart_tx_pin, PORT_PIN_MODE_LIN0);
    /* Set up the pinmux for UART rx */
    Port_SetPinMode(mss_uart_rx_pin, PORT_PIN_MODE_LIN0);
	Port_SetPinDirection(mss_uart_rx_pin, PORT_PIN_IN);

	#if (STD_OFF == MCU_NO_PLL)
    if(McuModuleConfiguration_0.Mcu_PllSourceId == MCU_CLKSRC_DPLL)
    {
        sys_clk_freq_vclk_const = (McuModuleConfiguration_0.
		Mcu_PllConfig[MCU_CLKSRC_DPLL].Mcu_PllClk1.MCU_PLL_HSDIV2 / (2e6)) * 30;
    }
    else
    {
        sys_clk_freq_vclk_const = (McuModuleConfiguration_0.
		Mcu_PllConfig[MCU_CLKSRC_APLL].Mcu_PllClk1.MCU_PLL_HSDIV0 / (2e6)) * 30;
    }
    Enable_Uart();
    #else
    Enable_Uart();
    #endif
    return;
}
static void SpiApp_interruptConfig(void)
{
    Vim_IntCfg intCfg;
    intCfg.map = VIM_INTTYPE_IRQ;
    intCfg.type = VIM_INTTRIGTYPE_LEVEL;

    vimInit();
    intCfg.priority = VIM_PRIORITY_6;
    intCfg.intNum = 78;
    intCfg.handler = Spi_IrqUnitMcspi0TxRx;
    vimRegisterInterrupt(&intCfg);

    intCfg.priority = VIM_PRIORITY_7;
    intCfg.intNum = 79;
    intCfg.handler = Spi_IrqUnitMcspi1TxRx;
    vimRegisterInterrupt(&intCfg);
	
	intCfg.priority = VIM_PRIORITY_8;
    intCfg.intNum = 80;
    intCfg.handler = Spi_IrqUnitMcspi2TxRx;
    vimRegisterInterrupt(&intCfg);

    intCfg.priority = VIM_PRIORITY_9;
    intCfg.intNum = 81;
    intCfg.handler = Spi_IrqUnitMcspi3TxRx;
	
    vimRegisterInterrupt(&intCfg);
	intCfg.priority = VIM_PRIORITY_10;
    intCfg.intNum = 82;
    intCfg.handler = Spi_IrqUnitMcspi4TxRx;
    vimRegisterInterrupt(&intCfg);
    
	return;
}


void Start_Timer(void)
{
	
      HW_WR_REG32(0x52180000, 0x00000000);//GCTRL
	  HW_WR_REG32(0x52180008, 0x00000000);//Capture Control
	  HW_WR_REG32(0x5218000C, 0x00000000);//COMP CTRL
	  HW_WR_REG32(0x52180010, 0x00000000);//FRC0
	  HW_WR_REG32(0x52180014, 0x00000000);//UP Counter
	  HW_WR_REG32(0x52180018, 0x00000001);//Compare Up Counter
	  HW_WR_REG32(0x52180084, 0x00070F0F);//Clear Interrupt
	  HW_WR_REG32(0x52180000, 0x00000001);//GCTRL Start Timer
	  
}

void Stop_Timer(uint8 Api_Id)
{
		  HW_WR_REG32(0x52180000, 0x00000000);//GCTRL Stop Timer
          frc = HW_RD_REG32(0x52180010);
		  Performance_Result[Api_Id] = frc;
}

void SpiApp_McspiJob0EndNotification(void)
{
    SpiApp_McspiJobDone[0U] = TRUE;

    return;
}

void SpiApp_McspiSeq0EndNotification(void)
{
    SpiApp_McspiSeqDone[0U] = TRUE;

    return;
}

void SpiApp_McspiJob1EndNotification(void)
{
    SpiApp_McspiJobDone[1U] = TRUE;

    return;
}

void SpiApp_McspiJob2EndNotification(void)
{
    SpiApp_McspiJobDone[2U] = TRUE;

    return;
}

void SpiApp_McspiJob3EndNotification(void)
{
    SpiApp_McspiJobDone[3U] = TRUE;

    return;
}

void SpiApp_McspiSeq1EndNotification(void)
{
    SpiApp_McspiSeqDone[1U] = TRUE;

    return;
}

void SpiApp_McspiSeq2EndNotification(void)
{
    SpiApp_McspiSeqDone[2U] = TRUE;

    return;
}

void SchM_Enter_Spi_SPI_EXCLUSIVE_AREA_0(void)
{
	AppUtils_SchM_Enter_EXCLUSIVE_AREA_0();
	
}
void SchM_Exit_Spi_SPI_EXCLUSIVE_AREA_0(void)
{
	AppUtils_SchM_Exit_EXCLUSIVE_AREA_0();
	
}

void CacheP_wbInv(const void * addr, int32_t size)
{
    uintptr_t i, firstAddr, lastAddr;
    uint32_t cacheLineSize =0; //CacheP_getCacheSize();
    
    /* Calculate the last address */
    lastAddr = (uintptr_t) addr + (uint32_t)size;
    
    /* find the first address for cache Wb */
    firstAddr = (uintptr_t ) addr & ~(cacheLineSize -1U);
    
    for (i = firstAddr; i < lastAddr; i+=cacheLineSize)
    {
        /* clean and invalidate single entry in DCache to PoC */
       // CSL_a53v8CleanInvalidateDcacheMvaPoC(i);
    }
    
    return;

}

void CacheP_wb(const void * addr, int32_t size)
{
   uintptr_t i, firstAddr, lastAddr;
   uint32_t cacheLineSize = 0u; //CacheP_getCacheSize();

   /* Calculate the last address */
   lastAddr = (uintptr_t) addr + (uint32_t)size;

   /* find the first address for cache Wb */
   firstAddr = (uintptr_t ) addr & ~(cacheLineSize -1U);

   for (i = firstAddr; i < lastAddr; i+=cacheLineSize)
   {
      /* clean single entry in DCache to PoC */
       //CSL_a53v8CleanDcacheMvaPoC(i);
   }

   return;
}

void SpiApp_wbInvCache(uint8 *buf, uint16 len)
{
CacheP_wbInv(buf, len);
}



void SpiApp_wbCache(uint8 *buf, uint16 len)
{
  CacheP_wb(buf, len);
}



void SpiApp_invCache(uint8 *buf, uint16 len)
{
//CacheP_Inv(buf, len);
}

#if (defined CLANG) || (defined DIAB)
void  SchM_Enter_Mcu_MCU_EXCLUSIVE_AREA_0()
{
    AppUtils_SchM_Enter_EXCLUSIVE_AREA_0();
}

void   SchM_Exit_Mcu_MCU_EXCLUSIVE_AREA_0()
{
     AppUtils_SchM_Exit_EXCLUSIVE_AREA_0();
}
#endif

void  SchM_Enter_Port_PORT_EXCLUSIVE_AREA_0()
{
    AppUtils_SchM_Enter_EXCLUSIVE_AREA_0();

}

void   SchM_Exit_Port_PORT_EXCLUSIVE_AREA_0()
{

  AppUtils_SchM_Exit_EXCLUSIVE_AREA_0();

}

