/********************************************************************************************************************
 *  COPYRIGHT
 *  -----------------------------------------------------------------------------------------------------------------
 *  \verbatim
 *                 TEXAS INSTRUMENTS INCORPORATED PROPRIETARY INFORMATION
 *
 *                 Property of Texas Instruments, Unauthorized reproduction and/or distribution
 *                 is strictly prohibited.  This product  is  protected  under  copyright  law
 *                 and  trade  secret law as an  unpublished work.
 *                 (C) Copyright Texas Instruments - 2012.  All rights reserved.
 *
 *  \endverbatim
 *  -----------------------------------------------------------------------------------------------------------------
 *  FILE DESCRIPTION
 *  -----------------------------------------------------------------------------------------------------------------
 *         File:  Spi.c
 *      Project:  Tms570_AutosarSpiDriver
 *       Module:  SpiDriver
 *    Generator:  -
 *
 *  Description:  This file implements the Spi Api for the spi communication driver.
 *-------------------------------------------------------------------------------------------------------------------
 * Author:  Prathap Srinivasan
 *-------------------------------------------------------------------------------------------------------------------
 * Revision History
 *-------------------------------------------------------------------------------------------------------------------
 * Version        Date         Author               Change ID        Description
 *-------------------------------------------------------------------------------------------------------------------
 * 02.10.00       24Jan2013    Prathap Srinivasan  0000000000000    Initial Version adapted for TMS570LS1227
 * 02.20.00       08Aug2013    Enrique Lizarraga   SDOCM00103201    -Removed individual DET macros. Only one macro
 *                                                                   enables/disables all DET errors.
 *                                                                  -Corrected inverted CS logic.
 *                                                                  -Corrected line indentation.
 *                                                                  -Removed unnecessary local variables.
 *                                                                  -Removed API multiple exit points.
 *                                                                  -Corrected length check at Spi_SetupEB
 *                                                                  -Added 32 bit support to MiBSPI mode
 *                                                                  -Added Sync mode support
 *                                                                  -Update version info
 *                                                                  -Added traceability tags.
 *                                                                  -Added Loopback mode enable/disable API's
 *                                                                  -Removed function-like macro Spi_DetReportError
 *                                                                   and replaced by direct DET API call.
 *                                                                  -Encapsulated Spi_MainFunction_Handling for
 *                                                                   SPI_LEVEL_2 only
 * 02.21.00       30Sep2014    Enrique Lizarraga   SDOCM00112317    -Update version info
 *                                                                  -Added traceability tags.
 *                                                                  -Removed unused code
 *                                                                  -MISRA fixes
 * 02.21.01       29Feb2016    Enrique Lizarraga   SDOCM00121246    -Update version info
 * 02.22.00       18Jul2016    Prathap Srinivasan  SDOCM00122408    -Update version info
 * 																	-Added Sync Polling Mode Support
 * 02.22.01       10Aug2016    Prathap Srinivasan  SDOCM00122593    -Bug Fix: Spi_IrqTxRxERR function checks for
 *                                                                   wrong error status bit
 * 02.22.02       23Aug2016    Vishwanath Reddy    SDOCM00121246    -Update version info
 * 02.22.03       26Sep2016    Prathap Srinivasan  SDOCM00122695    -Update version info
 * 02.30.00       01Dec2016    Sudhakar Singh         None          -Update version info
 * 05.30.00       15Mar2017    Sudhakar Singh      SDOCM00122834    Version supports TMS570LSxx Family of Devices.
 *
 ********************************************************************************************************************/
#define SPI_SOURCE

/********************************************************************************************************************
 *  INCLUDES
 ********************************************************************************************************************/
#include "Spi.h"
#include "Spi_Hw.h"

/********************************************************************************************************************
 *  VERSION CHECK
 ********************************************************************************************************************/
#define SPI_SW_C_MAJOR_VERSION               (5U)
#define SPI_SW_C_MINOR_VERSION               (30U)
#define SPI_SW_C_PATCH_VERSION               (0U)
 
 /* SourceId : SPI_SourceId_001 */
/* DesignId : SPI_DesignId_018 */
/* Requirements : AR_SPI_SR118 */
/* AUTOSAR version information check has to match definition in header file */
#if (  (SPI_AR_RELEASE_MAJOR_VERSION != (0x04U)) \
    || (SPI_AR_RELEASE_MINOR_VERSION != (0x00U)) \
    || (SPI_AR_RELEASE_REVISION_VERSION != (0x03U)) )
  #error "Spi: AUTOSAR Version Numbers of Spi are different"
#endif

/* SourceId : SPI_SourceId_002 */
/* DesignId : SPI_DesignId_018 */
/* Requirements : AR_SPI_SR117 */
/* AUTOSAR version information check has to match definition in header file */
#if (  (SPI_SW_MAJOR_VERSION != SPI_SW_C_MAJOR_VERSION) \
    || (SPI_SW_MINOR_VERSION != SPI_SW_C_MINOR_VERSION) \
	|| (SPI_SW_PATCH_VERSION != SPI_SW_C_PATCH_VERSION))
#error "Spi :Software Version Numbers are inconsistent!"
#endif

/* versions of all included header files shall be checked */
#if (  (SPI_CFG_MAJOR_VERSION != SPI_SW_C_MAJOR_VERSION) \
    || (SPI_CFG_MINOR_VERSION != SPI_SW_C_MINOR_VERSION) )
  #error "Spi: Source and Generated Header file are inconsistent!"
#endif

#if (  (SPI_HW_MAJOR_VERSION != SPI_SW_C_MAJOR_VERSION) \
    || (SPI_HW_MINOR_VERSION != SPI_SW_C_MINOR_VERSION) )
  #error "Spi_Hw: Source and Header file are inconsistent!"
#endif

/********************************************************************************************************************
 *  GLOBAL DATA
 ********************************************************************************************************************/
/*SAFETYMCUSW 580 S MR:1.1 <APPROVED> "AUTOSAR Memory Mapping approach "*/
#define SPI_START_SEC_VAR_ZERO_INIT_UNSPECIFIED
/*SAFETYMCUSW 338 S MR:19.1 <APPROVED> "Based on Autosar Memory Map strategy" */
#include "MemMap.h"

/*SAFETYMCUSW 440 S MR:11.3 <APPROVED> "Null pointer definition" */
/*SAFETYMCUSW 131 S MR:5.2 <APPROVED> "Variable declaration and definition" */
P2CONST(Spi_ConfigType, SPI_VAR_ZERO_INIT, SPI_PBCFG) Spi_ConfigPtr_pt = NULL_PTR;
/* SourceId : SPI_SourceId_003 */
/* DesignId : SPI_DesignId_026 */
/* Requirements : AR_SPI_SR136 */
/*SAFETYMCUSW 131 S MR:5.2 <APPROVED> "Variable declaration and definition" */
volatile VAR(Spi_StatusType, SPI_VAR_ZERO_INIT) Spi_DrvStatus = SPI_UNINIT;

/*SAFETYMCUSW 580 S MR:1.1 <APPROVED> "AUTOSAR Memory Mapping approach "*/
#define SPI_STOP_SEC_VAR_ZERO_INIT_UNSPECIFIED
/*SAFETYMCUSW 338 S MR:19.1 <APPROVED> "Based on Autosar Memory Map strategy" */
#include "MemMap.h"

/********************************************************************************************************************
 *  GLOBAL FUNCTIONS
 ********************************************************************************************************************/
/*SAFETYMCUSW 580 S MR:1.1 <APPROVED> "AUTOSAR Memory Mapping approach "*/
#undef SPI_START_SEC_CODE
#define SPI_START_SEC_CODE
/*SAFETYMCUSW 338 S MR:19.1 <APPROVED> "Based on Autosar Memory Map strategy" */
#include "MemMap.h"

/********************************************************************************************************************
 *  Spi_Init
 ********************************************************************************************************************/
/*! \brief      This method is Spi_Init Api.
 *  \param[in]  Spi_ConfigType             ConfigPtr
 *  \param[out] none
 *  \return     none
 *  \pre        Input parameter must not be NULL.
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 ********************************************************************************************************************/
/* SourceId : SPI_SourceId_004 */
/* DesignId : SPI_DesignId_001 */
/* Requirements : AR_SPI_SR1, AR_SPI_SR2, AR_SPI_SR96, AR_SPI_SR102, AR_SPI_SR114, AR_SPI_SR169, AR_SPI_SR170,
 * AR_SPI_SR171, AR_SPI_SR172, AR_SPI_SR173, AR_SPI_SR174 */
FUNC(void, SPI_CODE) Spi_Init
(
   P2CONST(Spi_ConfigType, AUTOMATIC, SPI_PBCFG) ConfigPtr
)
{
   uint32 Index_loc;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus != SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_INIT, SPI_E_ALREADY_INITIALIZED);
   }
   /*SAFETYMCUSW 440 S MR:11.3 <APPROVED> "Null pointer definition" */
   else if (NULL_PTR == ConfigPtr)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_INIT, SPI_E_PARAM_POINTER);
   }
   else
#endif
   {
      /* Store configuration pointer */
      Spi_ConfigPtr_pt = ConfigPtr;
      /* Initialize driver status */
      Spi_DrvStatus = SPI_IDLE;

      /* Initialize all DLC's status */
      for (Index_loc = 0U; Index_loc < Spi_ConfigPtr_pt->Spi_MaxDlcs; Index_loc++)
      {
         Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_DlcResult[Index_loc] = SPI_DLC_OK;
      }
      /* Initialize all Jobs status */
      for (Index_loc = 0U; Index_loc < Spi_ConfigPtr_pt->Spi_MaxJobs; Index_loc++)
      {
         Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_JobResult[Index_loc] = SPI_JOB_OK;
      }
      /* Initialize all Sequences status */
      for (Index_loc = 0U; Index_loc < Spi_ConfigPtr_pt->Spi_MaxSequences; Index_loc++)
      {
         Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_SeqResult[Index_loc] = SPI_SEQ_OK;
      }
      Spi_HwInit();
   }
}

/*******************************************************************************************************************
 *  Spi_DeInit
 *******************************************************************************************************************/
/*! \brief      This method is Spi_DeInit Api.
 *  \param[in]  none
 *  \param[out] none
 *  \return     E_OK
 *  \return     E_NOT_OK
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_005 */
/* DesignId : SPI_DesignId_002 */
/* Requirements : AR_SPI_SR176, AR_SPI_SR177, AR_SPI_SR178, AR_SPI_SR179, AR_SPI_SR180, AR_SPI_SR181, AR_SPI_SR182,
 * AR_SPI_SR183, AR_SPI_SR184, AR_SPI_SR93, AR_SPI_SR102, AR_SPI_SR112, AR_SPI_SR113 */
FUNC(Std_ReturnType, SPI_CODE) Spi_DeInit(void)
{
   Std_ReturnType deinit_return = E_NOT_OK;
   uint32 Index_loc;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus  == SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_DEINIT, SPI_E_UNINIT);
   }
   else
#endif
   {
      if (Spi_DrvStatus  == SPI_BUSY)
      {
         /* Do nothing */
      }
      else
      {
         Spi_DrvStatus  = SPI_UNINIT;
         /*SAFETYMCUSW 45 D <APPROVED> "Pointer checked during initialization routine" */
         for (Index_loc = 0U; Index_loc < Spi_ConfigPtr_pt->Spi_MaxDlcs; Index_loc++)
         {
            Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_DlcResult[Index_loc] = SPI_DLC_OK ;
         }
         for (Index_loc = 0U; Index_loc < Spi_ConfigPtr_pt->Spi_MaxJobs; Index_loc++)
         {
            Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_JobResult[Index_loc] = SPI_JOB_OK;
         }
         for (Index_loc = 0U; Index_loc < Spi_ConfigPtr_pt->Spi_MaxSequences; Index_loc++)
         {
            Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_SeqResult[Index_loc] = SPI_SEQ_OK;
         }
         Spi_HwDeInit();

         deinit_return = E_OK;
      }
   }
   return(deinit_return);
}

/*******************************************************************************************************************
 *  Spi_GetStatus
 *******************************************************************************************************************/
/*! \brief      This method is Spi_GetStatus Api.
 *  \param[in]  none
 *  \param[out] none
 *  \return     SPI_UNINIT, SPI_BUSY, SPI_IDLE
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_006 */
/* DesignId : SPI_DesignId_005 */
/* Requirements : AR_SPI_SR134, AR_SPI_SR137, AR_SPI_SR138, AR_SPI_SR139, AR_SPI_SR230, AR_SPI_SR232, AR_SPI_SR233 */
FUNC(Spi_StatusType, SPI_CODE) Spi_GetStatus(void)
{
   VAR(Spi_StatusType, SPI_VAR_ZERO_INIT) DrvStatusLoc = SPI_UNINIT;
   DrvStatusLoc = Spi_DrvStatus;
   return(DrvStatusLoc);
}

/*******************************************************************************************************************
 *  Spi_GetJobResult
 *******************************************************************************************************************/
/*! \brief      This method is Spi_GetJobResult Api.
 *  \param[in]  Spi_JobType               Job
 *  \param[out] none
 *  \return     SPI_JOB_OK, SPI_JOB_PENDING, SPI_JOB_FAILED
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_007 */
/* DesignId : SPI_DesignId_006 */
/* Requirements : AR_SPI_SR143, AR_SPI_SR145, AR_SPI_SR234, AR_SPI_SR236, AR_SPI_SR237, AR_SPI_SR89,
 * AR_SPI_SR93, AR_SPI_SR102, AR_SPI_SR106, AR_SPI_SR107, AR_SPI_SR112, AR_SPI_SR113 */
FUNC(Spi_JobResultType, SPI_CODE) Spi_GetJobResult
(
   Spi_JobType Job
)
{
   Spi_JobResultType get_job_result_return = SPI_JOB_FAILED;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus  == SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_GET_JOB_RESULT, SPI_E_UNINIT);
   }
   else if (Job >= Spi_ConfigPtr_pt->Spi_MaxJobs)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_GET_JOB_RESULT, SPI_E_PARAM_JOB);
   }
   else
#endif
   {
      get_job_result_return = Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_JobResult[Job];
   }
   return(get_job_result_return);
}

#if (SPI_HW_STATUS_API == STD_ON)
/*******************************************************************************************************************
 *  Spi_GetHWUnitStatus
 *******************************************************************************************************************/
/*! \brief      This method is Spi_GetHWUnitStatus Api.
 *  \param[in]  Spi_HWUnitType            HWUnit
 *  \param[out] none
 *  \return     SPI_UNINIT, SPI_IDLE, SPI_BUSY
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_008 */
/* DesignId : SPI_DesignId_009 */
/* Requirements : AR_SPI_SR135, AR_SPI_SR140, AR_SPI_SR141, AR_SPI_SR92, AR_SPI_SR93, AR_SPI_SR102, AR_SPI_SR110,
 * AR_SPI_SR111, AR_SPI_SR112, AR_SPI_SR262, AR_SPI_SR263, AR_SPI_SR264, AR_SPI_SR265, AR_SPI_SR267 */
FUNC(Spi_StatusType, SPI_CODE) Spi_GetHWUnitStatus
(
   Spi_HWUnitType HWUnit
)
{
   Spi_StatusType get_hw_unit_status_return = SPI_UNINIT;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus  == SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_GET_UNIT_STATUS, SPI_E_UNINIT);
   }
   else if (HWUnit >= Spi_ConfigPtr_pt->Spi_MaxDlcs)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_GET_UNIT_STATUS, SPI_E_PARAM_UNIT);
   }
   else
#endif
   {
      switch(Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_DlcResult[HWUnit])
      {
         case SPI_DLC_PENDING:
            /* need to fall through here, both results are mapped to SPI_BUSY  */
         case SPI_DLC_FAILED:
            get_hw_unit_status_return = SPI_BUSY;
            break;
         case SPI_DLC_OK:
            get_hw_unit_status_return = SPI_IDLE;
            break;
         default:
            break;
      }
   }
   return(get_hw_unit_status_return);
}
#endif /* SPI_HW_STATUS_API == STD_ON */

/*******************************************************************************************************************
 *  Spi_GetSequenceResult
 *******************************************************************************************************************/
/*! \brief      This method is Spi_GetSequenceResult Api.
 *  \param[in]  Spi_SeqResultType         Seq
 *  \param[out] none
 *  \return     SPI_SEQ_OK
 *  \return     SPI_SEQ_PENDING
 *  \return     SPI_SEQ_CANCELLED
 *  \return     SPI_SEQ_FAILED
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_009 */
/* DesignId : SPI_DesignId_007 */
/* Requirements : AR_SPI_SR146, AR_SPI_SR148, AR_SPI_SR150, AR_SPI_SR151, AR_SPI_SR152, AR_SPI_SR239, AR_SPI_SR90,
 * AR_SPI_SR93, AR_SPI_SR102, AR_SPI_SR106, AR_SPI_SR107, AR_SPI_SR112, AR_SPI_SR113, AR_SPI_SR240, AR_SPI_SR241,
 * AR_SPI_SR242 */
FUNC(Spi_SeqResultType, SPI_CODE) Spi_GetSequenceResult
(
   Spi_SequenceType Seq
)
{
   Spi_SeqResultType get_sequence_result_return = SPI_SEQ_FAILED;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus  == SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_GET_SEQ_RESULT, SPI_E_UNINIT);
   }
   else if (Seq >= Spi_ConfigPtr_pt->Spi_MaxSequences)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_GET_SEQ_RESULT, SPI_E_PARAM_SEQ);
   }
   else
#endif
   {
      get_sequence_result_return = Spi_ConfigPtr_pt->Spi_GlobalStatus_pt->Spi_SeqResult[Seq];
   }

   return(get_sequence_result_return);
}

#if (SPI_VERSION_INFO_API == STD_ON)
/*******************************************************************************************************************
 *  Spi_GetVersionInfo
 *******************************************************************************************************************/
/*! \brief      This method is Spi_GetVersionInfo Api.
 *  \param[in]  Std_VersionInfoType       VersioninfoPtr
 *  \param[out] none
 *  \return     E_OK
 *  \return     E_NOT_OK
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_010 */
/* DesignId : SPI_DesignId_008 */
/* Requirements : AR_SPI_SR102, AR_SPI_SR244, AR_SPI_SR245, AR_SPI_SR246, AR_SPI_SR247, AR_SPI_SR249, AR_SPI_SR250,
 * AR_SPI_SR251 */
FUNC(void, SPI_CODE) Spi_GetVersionInfo
(
    P2VAR(Std_VersionInfoType, AUTOMATIC, SPI_APPL_DATA) VersioninfoPtr
)
{

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   /*SAFETYMCUSW 440 S MR:11.3 <APPROVED> "Null pointer definition" */
   if (VersioninfoPtr == NULL_PTR)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_GETVERSION_INFO, SPI_E_PARAM_POINTER);
   }
   else
#endif
   {
      VersioninfoPtr->vendorID         = (uint16)( SPI_VENDOR_ID);
      VersioninfoPtr->moduleID         = (uint16)( SPI_MODULE_ID );
      VersioninfoPtr->sw_major_version = (uint8)( SPI_SW_MAJOR_VERSION);
      VersioninfoPtr->sw_minor_version = (uint8)( SPI_SW_MINOR_VERSION);
      VersioninfoPtr->sw_patch_version = (uint8)( SPI_SW_PATCH_VERSION);
   }
}
#endif /* SPI_VERSION_INFO_API == STD_ON */

#if ((SPI_CHANNELBUFFERS == SPI_EB) || (SPI_CHANNELBUFFERS == SPI_IB_EB))
/********************************************************************************************************************
 *  Spi_SetupEB
 ********************************************************************************************************************/
/*! \brief      This method is Spi_SetupEB Api.
 *  \param[in]  Spi_ChannelType           Channel
 *  \param[in]  Spi_DataType              SrcDataBufferPtr
 *  \param[in]  Spi_DataType              DesDataBufferPtr
 *  \param[in]  Spi_NumberOfDataType      Length
 *  \param[out] none
 *  \return     E_OK
 *  \return     E_NOT_OK
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 ********************************************************************************************************************/
/* SourceId : SPI_SourceId_011 */
/* DesignId : SPI_DesignId_004 */
/* Requirements : AR_SPI_SR42, AR_SPI_SR43, AR_SPI_SR220, AR_SPI_SR222, AR_SPI_SR223, AR_SPI_SR224, AR_SPI_SR225,
 * AR_SPI_SR226, AR_SPI_SR227, AR_SPI_SR229, AR_SPI_SR88, AR_SPI_SR91, AR_SPI_SR93, AR_SPI_SR102, AR_SPI_SR105,
 * AR_SPI_SR108, AR_SPI_SR109, AR_SPI_SR112, AR_SPI_SR113 */
FUNC(Std_ReturnType, SPI_CODE) Spi_SetupEB
(
    Spi_ChannelType Channel,
    P2CONST(Spi_DataType, AUTOMATIC, SPI_APPL_DATA) SrcDataBufferPtr,
    P2VAR(Spi_DataType, AUTOMATIC, SPI_APPL_DATA) DesDataBufferPtr,
    Spi_NumberOfDataType Length
)
{
   Std_ReturnType setup_eb_return = E_NOT_OK;
   /*SAFETYMCUSW 7 C MR:14.7 <APPROVED> "Reason - Development error check. To reduce complexity. "*/
   Spi_NumberOfDataType LengthEB_t;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus  == SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SETUP_EB, SPI_E_UNINIT);
   }
   else if (  (Channel >= Spi_ConfigPtr_pt->Spi_MaxChannels)
        || (Spi_ConfigPtr_pt->Spi_ChannelCfg[Channel].Spi_ChannelBuf != SPI_EB))
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SETUP_EB, SPI_E_PARAM_CHANNEL);
   }
   else
#endif
   {
      /* check for frame mode if the length is aligned */
      if(Spi_ConfigPtr_pt->Spi_ChannelCfg[Channel].Spi_DataWidth == 8U)
      {
         LengthEB_t = Length;
      }
      else
      {
#if (STD_ON == SPI_DEV_ERROR_DETECT)
         /* length must be even aligned in 16 or 32 bit mode */
         if(((Spi_ConfigPtr_pt->Spi_ChannelCfg[Channel].Spi_DataWidth == 32U) && ((Length % 4U) != 0U)) ||
            ((Spi_ConfigPtr_pt->Spi_ChannelCfg[Channel].Spi_DataWidth == 16U) && ((Length & 1U) == 1U)))
         {
            (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SETUP_EB, SPI_E_PARAM_LENGTH);
            /*SAFETYMCUSW 7 C MR:14.7 <APPROVED> "Reason - Development error check "*/
            return (setup_eb_return);
         }
         else
#endif
         {
            LengthEB_t = (Length >> 1U);
            /* buffers must be even aligned in 16 bit mode */
#if (STD_ON == SPI_DEV_ERROR_DETECT)
            {
               /*SAFETYMCUSW 439 S MR:11.3 <APPROVED> "Check buffer alignment*/
               /*SAFETYMCUSW 203 S MR:11.5 <APPROVED> "Check buffer alignment*/
               /*SAFETYMCUSW 439 S MR:11.3 <APPROVED> "Check buffer alignment*/
               if(  (((uint32)SrcDataBufferPtr  & 1U) == 1U)
                 || (((uint32)DesDataBufferPtr & 1U) == 1U)  )
               {
                  (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SETUP_EB, SPI_E_PARAM_POINTER);
                  /*SAFETYMCUSW 7 C MR:14.7 <APPROVED> "Reason - Development error check "*/
                  return (setup_eb_return);
               }
            }
#endif
         }
      }
      /* now check length */
#if (STD_ON == SPI_DEV_ERROR_DETECT)
      if ((Length == 0U) || (Length > Spi_ConfigPtr_pt->Spi_ChannelCfg[Channel].Spi_BufLength))
      {
         (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SETUP_EB, SPI_E_PARAM_LENGTH);
         setup_eb_return = E_NOT_OK;
      }
      else
#endif
      {
         /*SAFETYMCUSW 203 S MR:11.5 <APPROVED> "Cast to store in Channel Configuration structure" */
         Spi_ConfigPtr_pt->Spi_ChannelCfg[Channel].Spi_Descriptor->Spi_Tx_pt =
             (P2VAR(Spi_DataType, AUTOMATIC, SPI_APPL_DATA))SrcDataBufferPtr;
         Spi_ConfigPtr_pt->Spi_ChannelCfg[Channel].Spi_Descriptor->Spi_Rx_pt = DesDataBufferPtr;
         Spi_ConfigPtr_pt->Spi_ChannelCfg[Channel].Spi_Descriptor->Spi_TxRxLength = LengthEB_t;

         setup_eb_return = E_OK;
      }
   }
   return(setup_eb_return);
}
#endif /* (SPI_CHANNELBUFFERS == SPI_EB) || (SPI_CHANNELBUFFERS == SPI_IB_EB) */

#if ((SPI_SCALEABILITY == SPI_LEVEL_1) || (SPI_SCALEABILITY == SPI_LEVEL_2))
/********************************************************************************************************************
 *  Spi_AsyncTransmit
 *******************************************************************************************************************/
/*! \brief      This method is Spi_AsyncTransmit Api.
 *  \param[in]  Spi_SequenceType          Sequence
 *  \param[out] none
 *  \return     E_OK
 *  \return     E_NOT_OK
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_012 */
/* DesignId : SPI_DesignId_003 */
/* Requirements : AR_SPI_SR22, AR_SPI_SR50, AR_SPI_SR51, AR_SPI_SR56, AR_SPI_SR194, AR_SPI_SR195, AR_SPI_SR196
 * AR_SPI_SR197, AR_SPI_SR198, AR_SPI_SR199, AR_SPI_SR200, AR_SPI_SR201, AR_SPI_SR202, AR_SPI_SR203, AR_SPI_SR204,
 * AR_SPI_SR205, AR_SPI_SR206, AR_SPI_SR207, AR_SPI_SR208, AR_SPI_SR209, AR_SPI_SR210, AR_SPI_SR90, AR_SPI_SR93,
 * AR_SPI_SR94, AR_SPI_SR102, AR_SPI_SR106, AR_SPI_SR112, AR_SPI_SR113, AR_SPI_SR312, AR_SPI_SR313, AR_SPI_SR317,
 * AR_SPI_SR321, AR_SPI_SR3, AR_SPI_SR46, AR_SPI_SR74, AR_SPI_SR78 */
FUNC(Std_ReturnType, SPI_CODE) Spi_AsyncTransmit
(
    Spi_SequenceType Sequence
)
{
   Spi_HwEventType HwEv_loc;
   Std_ReturnType  Ret_loc = E_NOT_OK;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus  == SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_ASYNC_TRANSMIT, SPI_E_UNINIT);
   }
   else if(Sequence >= Spi_ConfigPtr_pt->Spi_MaxSequences)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_ASYNC_TRANSMIT, SPI_E_PARAM_SEQ);
   }
   else if(Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_ASYNC_TRANSMIT, SPI_E_SEQ_PENDING);
   }
   else
#endif
   {

      /* check jobs of this sequence, if they are in service */
      HwEv_loc.Event_u8   = SPI_HW_EV_SEQ_START;
      HwEv_loc.Guard_u8   = SPI_HW_ASYNC;
      HwEv_loc.TaskID_u8  = Sequence;
      HwEv_loc.NrOfJobs_u8 = 0U;

      Ret_loc = Spi_HwSetEvent(&HwEv_loc);

#if (STD_ON == SPI_DEV_ERROR_DETECT)
      if(Ret_loc == E_NOT_OK)
      {
         (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_ASYNC_TRANSMIT, SPI_E_SEQ_PENDING);
      }
#endif
   }
   return(Ret_loc);
}
#endif /* (SPI_SCALEABILITY == SPI_LEVEL_1) || (SPI_SCALEABILITY == SPI_LEVEL_2) */


#if ((SPI_SCALEABILITY == SPI_LEVEL_0) || (SPI_SCALEABILITY == SPI_LEVEL_2))
/********************************************************************************************************************
 *  Spi_SyncTransmit
 *******************************************************************************************************************/
/*! \brief      This method is Spi_SyncTransmit Api.
 *  \param[in]  Spi_SequenceType          Sequence
 *  \param[out] none
 *  \return     E_OK
 *  \return     E_NOT_OK
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_058 */
/* DesignId : SPI_DesignId_018 */
/* Requirements : AR_SPI_SR3, AR_SPI_SR22, AR_SPI_SR24, AR_SPI_SR25, AR_SPI_SR31, AR_SPI_SR32,
 * AR_SPI_SR34, AR_SPI_SR56, AR_SPI_SR90, AR_SPI_SR93, AR_SPI_SR94, AR_SPI_SR102, AR_SPI_SR106,
 * AR_SPI_SR112, AR_SPI_SR113, AR_SPI_SR312, AR_SPI_SR313, AR_SPI_SR317, AR_SPI_SR321, AR_SPI_SR44,
 * AR_SPI_SR45, AR_SPI_SR46, AR_SPI_SR47, AR_SPI_SR48, AR_SPI_SR74, AR_SPI_SR75, AR_SPI_SR76,
 * AR_SPI_SR77, AR_SPI_SR78, AR_SPI_SR252, AR_SPI_SR253, AR_SPI_SR254, AR_SPI_SR255, AR_SPI_SR256,
 * AR_SPI_SR257, AR_SPI_SR258, AR_SPI_SR259, AR_SPI_SR260, AR_SPI_SR261, AR_SPI_SR315, AR_SPI_SR319 */
FUNC(Std_ReturnType, SPI_CODE) Spi_SyncTransmit
(
    Spi_SequenceType Sequence
)
{
   Spi_HwEventType HwEv_loc;
   Std_ReturnType  Ret_loc = E_NOT_OK;
   uint32 HW_Inst_Nr_u32;   /* Instance of the SPI Hw */

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus  == SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SYNC_TRANSMIT, SPI_E_UNINIT);
   }
   else if(Sequence >= Spi_ConfigPtr_pt->Spi_MaxSequences)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SYNC_TRANSMIT, SPI_E_PARAM_SEQ);
   }
   else if(Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SYNC_TRANSMIT, SPI_E_SEQ_IN_PROCESS);
   }
   else
#endif
   {
	  /* get the SPI Hardware Instance */
      HW_Inst_Nr_u32 =  Spi_ConfigPtr_pt->Spi_SeqCfg[Sequence].Spi_JobList[0U];

      /* check jobs of this sequence, if they are in service */
      HwEv_loc.Event_u8   = SPI_HW_EV_SEQ_START;
      HwEv_loc.Guard_u8   = SPI_HW_SYNC;
      HwEv_loc.TaskID_u8  = Sequence;
      HwEv_loc.NrOfJobs_u8 = 0U;

      Ret_loc = Spi_HwSetEvent(&HwEv_loc);

#if (STD_ON == SPI_DEV_ERROR_DETECT)
      if(Ret_loc == E_NOT_OK)
      {
         (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_SYNC_TRANSMIT, SPI_E_SEQ_IN_PROCESS);
      }
#endif

      /*Wait Until Sequence is Completed or returned Fail */
      while(Spi_GetSequenceResult(Sequence) == SPI_SEQ_PENDING)
      {
    	  /* Drive the SPI communication through Sync Mode */
    	  Spi_DlcDrive(HW_Inst_Nr_u32);
      }

   }
   return(Ret_loc);
}
#endif /* (SPI_SCALEABILITY == SPI_LEVEL_0) || (SPI_SCALEABILITY == SPI_LEVEL_2) */


#if (SPI_CANCEL_API == STD_ON)
/********************************************************************************************************************
 *  Spi_Cancel
 *******************************************************************************************************************/
/*! \brief      This method is Spi_Cancel Api.
 *  \param[in]  Spi_SequenceType          Sequence
 *  \param[out] none
 *  \return     E_OK
 *  \return     E_NOT_OK
 *  \context    Function could be called from from task level
 *  \note       Spi AUTOSAR API.
 ********************************************************************************************************************/
/* SourceId : SPI_SourceId_013 */
/* DesignId : SPI_DesignId_010 */
/* Requirements : AR_SPI_SR90, AR_SPI_SR93, AR_SPI_SR102, AR_SPI_SR106, AR_SPI_SR112, AR_SPI_SR268, AR_SPI_SR269,
 * AR_SPI_SR270, AR_SPI_SR271, AR_SPI_SR272, AR_SPI_SR273 */
FUNC(void, SPI_CODE) Spi_Cancel
(
   Spi_SequenceType Sequence
)
{
   Spi_HwEventType HwEv_loc;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
   if (Spi_DrvStatus  == SPI_UNINIT)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_CANCEL, SPI_E_UNINIT);
   }
   else if(Sequence >= Spi_ConfigPtr_pt->Spi_MaxSequences)
   {
      (void)Det_ReportError(SPI_MODULE_ID, SPI_INSTANCE_ID, SPI_SID_CANCEL, SPI_E_PARAM_SEQ);
   }
   else
#endif
   {
      HwEv_loc.Guard_u8 = SPI_HW_UNDEF;
      HwEv_loc.NrOfJobs_u8 = 0U;
      HwEv_loc.Event_u8 = SPI_HW_EV_CANCEL;
      HwEv_loc.TaskID_u8 = Sequence;
      (void)Spi_HwSetEvent(&HwEv_loc);
   }
}
#endif /* SPI_CANCEL_API == STD_ON */

#if (SPI_LOOPBACK_MODE_API == STD_ON)
/*******************************************************************************************************************
 *  Spi_EnableLoopbackMode
 *******************************************************************************************************************/
/*! \brief      This method enables Loopback mode for the specified HW Unit.
 *  \param[in]  Spi_HWUnitType            HWUnit
 *  \param[in]  Spi_LoopbackModeType      LBMode
 *  \param[out] none
 *  \return     E_OK, E_NOT_OK
 *  \context    Function could be called from from task level
 *  \note       SafeTI API
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_030 */
/* DesignId : SPI_DesignId_011 */
/* Requirements : AR_SPI_SR322 */
FUNC(Std_ReturnType, SPI_CODE)  Spi_EnableLoopbackMode
(
   Spi_HWUnitType HWUnit,
   Spi_LoopbackModeType LBMode
)
{
   Std_ReturnType enable_loopback_mode_return = E_NOT_OK;

   /* Check if Spi driver already initialized*/
   if (Spi_DrvStatus != SPI_UNINIT)
   {
      /* Check requested HW Unit validity */
      if (HWUnit < Spi_ConfigPtr_pt->Spi_MaxDlcs)
      {
         Spi_DlcEnableLpbk(HWUnit, LBMode);

         enable_loopback_mode_return = E_OK;
      }
   }

   return(enable_loopback_mode_return);
}

/*******************************************************************************************************************
 *  Spi_DisableLoopbackMode
 *******************************************************************************************************************/
/*! \brief      This method disables Loopback mode for the specified HW Unit.
 *  \param[in]  Spi_HWUnitType            HWUnit
 *  \param[out] none
 *  \return     E_OK, E_NOT_OK
 *  \context    Function could be called from from task level
 *  \note       SafeTI API
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_031 */
/* DesignId : SPI_DesignId_012 */
/* Requirements : AR_SPI_SR322 */
FUNC(Std_ReturnType, SPI_CODE)  Spi_DisableLoopbackMode
(
   Spi_HWUnitType HWUnit
)
{
   Std_ReturnType disable_loopback_mode_return = E_NOT_OK;

   if (HWUnit < Spi_ConfigPtr_pt->Spi_MaxDlcs)
   {
      Spi_DlcDisableLpbk(HWUnit);

      disable_loopback_mode_return = E_OK;
   }

   return(disable_loopback_mode_return);
}
#endif /* SPI_LOOPBACK_MODE_API == STD_ON */

#if (SPI_REGISTER_READBACK_API == STD_ON)
/*******************************************************************************************************************
 *  Spi_RegisterReadback
 *******************************************************************************************************************/
/*! \brief      This method is Spi_RegisterReadback Api.
 *  \param[in]  Spi_RegisterReadbackType       RegisterReadbackPtr
 *  \param[in]  Spi_HWUnitType                 HWUnit
 *  \param[out] none
 *  \return     none
 *  \context    Function could be called from from task level
 *  \note       SafeTI API
 *******************************************************************************************************************/
/* SourceId : SPI_SourceId_032 */
/* DesignId : SPI_DesignId_013 */
/* Requirements : AR_SPI_SR327 */
FUNC(Std_ReturnType, SPI_CODE) Spi_RegisterReadback
(
    P2VAR(Spi_RegisterReadbackType, AUTOMATIC, SPI_APPL_DATA) RegisterReadbackPtr,
    Spi_HWUnitType HWUnit
)
{
   Std_ReturnType register_readback_return = E_NOT_OK;

   /*SAFETYMCUSW 440 S MR:11.3 <APPROVED> "Null pointer definition" */
   if(NULL_PTR == RegisterReadbackPtr)
   {
      /* Do nothing. Incorrect pointer. */
   }
   else if(HWUnit >= Spi_ConfigPtr_pt->Spi_MaxDlcs)
   {
      /* Do nothing. Incorrect HW Unit. */
   }
   else
   {
      RegisterReadbackPtr->Spi_GCR0 = Spi_DlcRegisterRdbk(SPI_GCR0_RB, HWUnit);
      RegisterReadbackPtr->Spi_GCR1 = Spi_DlcRegisterRdbk(SPI_GCR1_RB, HWUnit);
      RegisterReadbackPtr->Spi_DEF  = Spi_DlcRegisterRdbk(SPI_DEF_RB, HWUnit);
      RegisterReadbackPtr->Spi_EN   = Spi_DlcRegisterRdbk(SPI_EN_RB, HWUnit);

      register_readback_return = E_OK;
   }

   return(register_readback_return);
}
#endif /* SPI_REGISTER_READBACK_API == STD_ON */

/*SAFETYMCUSW 580 S MR:1.1 <APPROVED> "AUTOSAR Memory Mapping approach "*/
#undef SPI_STOP_SEC_CODE
#define SPI_STOP_SEC_CODE
/*SAFETYMCUSW 338 S MR:19.1 <APPROVED> "Based on Autosar Memory Map strategy" */
#include "MemMap.h"

/*****************************************************************************************************************
 *  END OF FILE: Spi.c
 *****************************************************************************************************************/
