/*==================================================================================================
*   Project              : RTD AUTOSAR 4.4
*   Platform             : CORTEXM
*   Peripheral           : 
*   Dependencies         : 
*
*   Autosar Version      : 4.4.0
*   Autosar Revision     : ASR_REL_4_4_REV_0000
*   Autosar Conf.Variant :
*   SW Version           : 1.0.0
*   Build Version        : S32K3_RTD_1_0_0_D2209_ASR_REL_4_4_REV_0000_20220916
*
*   (c) Copyright 2020 - 2022 NXP Semiconductors
*   All Rights Reserved.
*
*   NXP Confidential. This software is owned or controlled by NXP and may only be
*   used strictly in accordance with the applicable license terms. By expressly
*   accepting such terms or by downloading, installing, activating and/or otherwise
*   using the software, you are agreeing that you have read, and that you agree to
*   comply with and are bound by, such license terms. If you do not agree to be
*   bound by the applicable license terms, then you may not retain, install,
*   activate or otherwise use the software.
==================================================================================================*/

/**
*   @file
*
*   @addtogroup switch_spi_external_access
*   @{
*/

#if defined (__cplusplus)
extern "C" {
#endif

/*==================================================================================================
*                                        INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/
#include "sbc_spi_external_access.h"

/*==================================================================================================
*                              SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define SPI_EXTERNAL_ACCESS_VENDOR_ID_C                      43
#define SPI_EXTERNAL_ACCESS_AR_RELEASE_MAJOR_VERSION_C       4
#define SPI_EXTERNAL_ACCESS_AR_RELEASE_MINOR_VERSION_C       4
#define SPI_EXTERNAL_ACCESS_AR_RELEASE_REVISION_VERSION_C    0
#define SPI_EXTERNAL_ACCESS_SW_MAJOR_VERSION_C               1
#define SPI_EXTERNAL_ACCESS_SW_MINOR_VERSION_C               0
#define SPI_EXTERNAL_ACCESS_SW_PATCH_VERSION_C               0

/*==================================================================================================
*                                     FILE VERSION CHECKS
==================================================================================================*/
/* Checks against Spi External Access header file */
#if ( SPI_EXTERNAL_ACCESS_VENDOR_ID_C != SPI_EXTERNAL_ACCESS_VENDOR_ID)
    #error "Spi External Access source file and Spi External Access header file have different vendor ids"
#endif
#if (( SPI_EXTERNAL_ACCESS_AR_RELEASE_MAJOR_VERSION_C    != SPI_EXTERNAL_ACCESS_AR_RELEASE_MAJOR_VERSION    ) || \
     ( SPI_EXTERNAL_ACCESS_AR_RELEASE_MINOR_VERSION_C    != SPI_EXTERNAL_ACCESS_AR_RELEASE_MINOR_VERSION    ) || \
     ( SPI_EXTERNAL_ACCESS_AR_RELEASE_REVISION_VERSION_C != SPI_EXTERNAL_ACCESS_AR_RELEASE_REVISION_VERSION ))
     #error "AUTOSAR Version Numbers of Spi External Access source file and Spi External Access header file are different"
#endif
#if (( SPI_EXTERNAL_ACCESS_SW_MAJOR_VERSION_C != SPI_EXTERNAL_ACCESS_SW_MAJOR_VERSION) || \
     ( SPI_EXTERNAL_ACCESS_SW_MINOR_VERSION_C != SPI_EXTERNAL_ACCESS_SW_MINOR_VERSION) || \
     ( SPI_EXTERNAL_ACCESS_SW_PATCH_VERSION_C != SPI_EXTERNAL_ACCESS_SW_PATCH_VERSION))
    #error "Software Version Numbers of Spi External Access source file and Spi External Access header file are different"
#endif

/*==================================================================================================
*                                        LOCAL VARIABLES
==================================================================================================*/
#define SBC_FS26_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "Sbc_fs26_MemMap.h"

/*! @brief Pointer to an array of pointers towards the driver structures */
static Std_ReturnType s_transferStatus;

#define SBC_FS26_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "Sbc_fs26_MemMap.h"

/*==================================================================================================
*                                    LOCAL FUNCTION PROTOTYPES
==================================================================================================*/
#define SBC_FS26_START_SEC_CODE
#include "Sbc_fs26_MemMap.h"

#ifndef SYNC_TRANSMIT
static Std_ReturnType Sbc_Ip_WaitForAsyncTransmitEnd(uint32 timeout);
#endif
/*==================================================================================================
*                                         LOCAL FUNCTIONS
==================================================================================================*/

/*FUNCTION**********************************************************************
 *
 * Function Name : Sbc_Ip_WaitForAsyncTransmitEnd
 * Description   : Checks if the SPI transfer has ended
 *
 *END**************************************************************************/
#ifndef SYNC_TRANSMIT
static Std_ReturnType Sbc_Ip_WaitForAsyncTransmitEnd(uint32 timeout)
{
    Std_ReturnType    tempRet = (Std_ReturnType)E_NOT_OK;
    uint32            loops   = 0U;

    /* Read the sequence result until the timeout expire or it is SPI_SEQ_OK or SPI_SEQ_FAILED */
    do
    {
        if (s_transferStatus == (Std_ReturnType)E_OK)
        {
            tempRet = (Std_ReturnType)E_OK;
            break;
        }
        else
        {
            loops++;
        }
    } while (loops < timeout);

    return tempRet;
}
#endif
/*==================================================================================================
*                                        GLOBAL FUNCTIONS
==================================================================================================*/

/*FUNCTION**********************************************************************
 *
 * Function Name : Sbc_Ip_SpiTransferExternal
 * Description   : SPI access for external devices
 *
 *END**************************************************************************/
Std_ReturnType Sbc_Ip_SpiTransferExternal(const Sbc_Ip_SpiSetupType *spiSetup,
                                             uint32 *txBuffer,
                                             uint32 *rxBuffer)
{
    Std_ReturnType status = E_OK;

#ifdef USE_IPV_DSPI
    const Spi_Ip_ExternalDeviceType *externalDevice = (const Spi_Ip_ExternalDeviceType *)spiSetup->extension;
    (void)spiSetup->spi; /* Unused parameter. */
#elif defined(USE_IPV_LPSPI)
    const Lpspi_Ip_ExternalDeviceType *externalDevice = (const Lpspi_Ip_ExternalDeviceType *)spiSetup->extension;
    (void)spiSetup->spi; /* Unused parameter. */
#else
    Spi_DataBufferType *spiDataToSend = (Spi_DataBufferType *)txBuffer;
    Spi_DataBufferType       *spiReceivedData = (Spi_DataBufferType *)rxBuffer;
    const Spi_SequenceType         *SpiSequence = (const Spi_SequenceType *)spiSetup->extension;
#if (2U != SBC_FS26_SPI_LEVEL_DELIVERED)
    (void)spiSetup->syncTransmit;  /* Unused parameter. */
    (void)spiSetup->timeout;  /* Unused parameter. */
#endif /* (2U != SBC_FS26_SPI_LEVEL_DELIVERED) */
#endif

    /* Start SPI transfer */
#ifdef USE_IPV_DSPI
    if (FALSE == spiSetup->syncTransmit)
    {
        s_transferStatus = E_NOT_OK;
        status = (Std_ReturnType)Spi_Ip_AsyncTransmit(externalDevice,
                                                      (uint8 *)txBuffer,
                                                      (uint8 *)rxBuffer,
                                                      (uint16)spiSetup->numberOfBytes,
                                                      (Spi_Ip_CallbackType)Sbc_Ip_SpiNotifyTransferEnd);
        status |= (Std_ReturnType)Sbc_Ip_WaitForAsyncTransmitEnd(spiSetup->timeout);
    }
    else
    {
        status = (Std_ReturnType)Spi_Ip_SyncTransmit(externalDevice,
                                                     (uint8 *)txBuffer,
                                                     (uint8 *)rxBuffer,
                                                     (uint16)spiSetup->numberOfBytes,
                                                     spiSetup->timeout);
    }
#elif defined(USE_IPV_LPSPI)
    if (FALSE == spiSetup->syncTransmit)
    {
        s_transferStatus = E_NOT_OK;
        status = (Std_ReturnType)Lpspi_Ip_AsyncTransmit(externalDevice,
                                                        (uint8 *)txBuffer,
                                                        (uint8 *)rxBuffer,
                                                        (uint16)spiSetup->numberOfBytes,
                                                        (Lpspi_Ip_CallbackType)Sbc_Ip_SpiNotifyTransferEnd);
        status |= (Std_ReturnType)Sbc_Ip_WaitForAsyncTransmitEnd(spiSetup->timeout);
    }
    else
    {
        status = (Std_ReturnType)Lpspi_Ip_SyncTransmit(externalDevice,
                                                       (uint8 *)txBuffer,
                                                       (uint8 *)rxBuffer,
                                                       (uint16)spiSetup->numberOfBytes,
                                                       spiSetup->timeout);
    }
#else
    status = (Std_ReturnType)Spi_SetupEB((Spi_ChannelType) spiSetup->spi, spiDataToSend, spiReceivedData, (Spi_NumberOfDataType)spiSetup->numberOfBytes);

    if ((Std_ReturnType)E_OK == status)
    {
#if (2U == SBC_FS26_SPI_LEVEL_DELIVERED)
        if (FALSE == spiSetup->syncTransmit)
        {
#endif /* (2U == SBC_FS26_SPI_LEVEL_DELIVERED) */
            s_transferStatus = E_NOT_OK;
#if ((2U == SBC_FS26_SPI_LEVEL_DELIVERED) || (1U == SBC_FS26_SPI_LEVEL_DELIVERED))
            status |= (Std_ReturnType)Spi_AsyncTransmit(*SpiSequence);
            status |= (Std_ReturnType)Sbc_Ip_WaitForAsyncTransmitEnd(spiSetup->timeout);
#endif /* ((2U == SBC_FS26_SPI_LEVEL_DELIVERED) || (1U == SBC_FS26_SPI_LEVEL_DELIVERED)) */
#if (2U == SBC_FS26_SPI_LEVEL_DELIVERED)
        }
        else
        {
#endif /* (2U == SBC_FS26_SPI_LEVEL_DELIVERED) */
#if ((2U == SBC_FS26_SPI_LEVEL_DELIVERED) || (0U == SBC_FS26_SPI_LEVEL_DELIVERED))
            status |= (Std_ReturnType)Spi_SyncTransmit(*SpiSequence);
#endif /* ((2U == SBC_FS26_SPI_LEVEL_DELIVERED) || (0U == SBC_FS26_SPI_LEVEL_DELIVERED)) */
#if (2U == SBC_FS26_SPI_LEVEL_DELIVERED)
        }
#endif /* (2U == SBC_FS26_SPI_LEVEL_DELIVERED) */
    }
#endif
    (void)s_transferStatus;

    return status;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Sbc_Ip_SpiSetAsyncMode
 * Description   : Sets the SPI asynchronous mode
 *
 *END**************************************************************************/
Std_ReturnType Sbc_Ip_SpiSetAsyncMode(void)
{
#ifdef USE_IPV_DSPI
    return E_OK;
#elif defined(USE_IPV_LPSPI)
    return E_OK;
#else
    #if (2U == SBC_FS26_SPI_LEVEL_DELIVERED)
        return Spi_SetAsyncMode(SPI_INTERRUPT_MODE);
    #else
        return E_NOT_OK;
    #endif /* (2U == SBC_FS26_SPI_LEVEL_DELIVERED) */
#endif
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Sbc_Ip_SpiNotifyTransferEnd
 * Description   : Notifies the SPI transfer end
 *
 *END**************************************************************************/
#ifdef USE_IPV_DSPI
void Sbc_Ip_SpiNotifyTransferEnd(uint8 instance, Spi_Ip_EventType event)
{
    s_transferStatus = (Std_ReturnType)event;
    (void)instance;

    return;
}
#elif defined(USE_IPV_LPSPI)
void Sbc_Ip_SpiNotifyTransferEnd(uint8 instance, Lpspi_Ip_EventType event)
{
    s_transferStatus = (Std_ReturnType)event;
    (void)instance;

    return;
}	
#else
void Sbc_Ip_SpiNotifyTransferEnd(void)
{
    s_transferStatus = E_OK;

    return;
}
#endif

#define SBC_FS26_STOP_SEC_CODE
#include "Sbc_fs26_MemMap.h"

#if defined(__cplusplus)
}
#endif

/** @}*/
