/*!
* @file     Spi.c
*
* @version  1.0.0
*
* @brief    Code file of AUTOSAR Spi driver.This file contains the AUTOSAR API functions of spi driver used.
*
* @attention
*
* Project Name      : AUTOSAR MCAL
*
* Platform          : Arm
*
* Autosar Standard  : Classic Platform 4.4.0
*
* Compiled Version  : G32A10xx_MCAL_1_0_0_01-Otc-25
*
* Copyright (C) 2026 Geehy Semiconductor
*
* You may not use this file except in compliance with the
* GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
*
* The program is only for reference, which is distributed in the hope
* that it will be usefull and instructional for customers to develop
* their software. Unless required by applicable law or agreed to in
* writing, the program is distributed on an "AS IS" BASIS, WITHOUT
* ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
* See the Geehy Semiconductor Software License Agreement for the governing permissions
* and limitations under the License.
*/

/*
* MISRA-C:2012 compliance checks
*
*     Spi_c_MISRA_REF1
*          Breaks the required Rule-11.8 of MISRA 2012 guidelines, 
*          A cast shall not remove any const or volatile qualification from the type pointed to by a pointer.
*
*/

#ifdef __cplusplus
extern "C"
{
#endif

#include "Spi.h"
#include "Spi_Hw.h"

#if (STD_OFF == SPI_DEM_EVENT_ERROR_REPORT_DISABLED)
    #include "Dem.h"
#endif
#include "Det.h"
#include "SchM_Spi.h"
/** @addtogroup G32A10xx_StdPeriphDriver
  @{
*/

/** @defgroup SPI_Driver
  * @brief SPI driver modules
  @{
*/

/** @defgroup SPI_Macros
  @{
*/
/**************************************************************************
                  VENDOR ID & AUTOSAR VERSION INFO
**************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define SPI_VENDOR_ID                         0x00C1U
/** Module ID of this module, as defined in the BSW Module List. */
#define SPI_MODULE_ID                         0x0053U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define SPI_AR_RELEASE_MAJOR_VERSION          0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define SPI_AR_RELEASE_MINOR_VERSION          0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define SPI_AR_RELEASE_REVISION_VERSION       0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define SPI_SW_MAJOR_VERSION                  0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define SPI_SW_MINOR_VERSION                  0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define SPI_SW_PATCH_VERSION                  0x00U

/**************************************************************************
                    VERSION INFOMATION VERIFICATION
**************************************************************************/
#ifdef ENABLE_INTERMODULE_MCAL_CHECK

    /* Make sure the AUTOSAR major version number is the same between Spi.c and SchM_Spi.h */
    #if (SPI_AR_RELEASE_MAJOR_VERSION != SCHM_SPI_H_AR_RELEASE_MAJOR_VERSION)
        #error "AUTOSAR Major Version Number mismatch between Spi.c and SchM_Spi.h"
    #endif
    /* Make sure the AUTOSAR minor version number is the same between Spi.c and SchM_Spi.h */
    #if (SPI_AR_RELEASE_MINOR_VERSION != SCHM_SPI_H_AR_RELEASE_MINOR_VERSION)
        #error "AUTOSAR Minor Version Number mismatch between Spi.c and SchM_Spi.h"
    #endif

    /* Make sure the AUTOSAR major version number is the same between Spi.c and Det.h */
    #if (SPI_AR_RELEASE_MAJOR_VERSION != DET_H_AR_RELEASE_MAJOR_VERSION) 
        #error "AUTOSAR Major Version Number mismatch between Spi.c and Det.h"
    #endif
    /* Make sure the AUTOSAR minor version number is the same between Spi.c and Det.h */
    #if (SPI_AR_RELEASE_MINOR_VERSION != DET_H_AR_RELEASE_MINOR_VERSION)
        #error "AUTOSAR Minor Version Number mismatch between Spi.c and Det.h"
    #endif

    #if (STD_OFF == SPI_DEM_EVENT_ERROR_REPORT_DISABLED)

        /* Make sure the AUTOSAR major version number is the same between Spi.c and Dem.h */
        #if (SPI_AR_RELEASE_MAJOR_VERSION != DEM_H_AR_RELEASE_MAJOR_VERSION) 
            #error "AUTOSAR Major Version Number mismatch between Spi.c and Dem.h"
        #endif
        /* Make sure the AUTOSAR minor version number is the same between Spi.c and Dem.h */
        #if (SPI_AR_RELEASE_MINOR_VERSION != DEM_H_AR_RELEASE_MINOR_VERSION)
            #error "AUTOSAR Minor Version Number mismatch between Spi.c and Dem.h"
        #endif

    #endif
#endif

/* Make sure the vendor id is the same between Spi.c and Spi_Hw.h */
#if (SPI_VENDOR_ID != SPI_HW_H_VENDOR_ID)
    #error "Vendor id mismatch between Spi.c and Spi_Hw.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Spi.c and Spi_Hw.h */
#if (SPI_AR_RELEASE_MAJOR_VERSION != SPI_HW_H_AR_RELEASE_MAJOR_VERSION) 
    #error "AUTOSAR Major Version Number mismatch between Spi.c and Spi_Hw.h "
#endif
/* Make sure the AUTOSAR minor version number is the same between Spi.c and Spi_Hw.h */
#if (SPI_AR_RELEASE_MINOR_VERSION != SPI_HW_H_AR_RELEASE_MINOR_VERSION) 
    #error "AUTOSAR Minor Version Number mismatch between Spi.c and Spi_Hw.h "
#endif
/* Make sure the AUTOSAR revision version number is the same between Spi.c and Spi_Hw.h */
#if (SPI_AR_RELEASE_REVISION_VERSION != SPI_HW_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR Revision Version Number mismatch between Spi.c and Spi_Hw.h "
#endif
/* Make sure the software major version number is the same between Spi.c and Spi_Hw.h */
#if (SPI_SW_MAJOR_VERSION != SPI_HW_H_SW_MAJOR_VERSION) 
    #error "Software Major Version Number mismatch between Spi.c and Spi_Hw.h"
#endif
/* Make sure the software minor version number is the same between Spi.c and Spi_Hw.h */
#if (SPI_SW_MINOR_VERSION != SPI_HW_H_SW_MINOR_VERSION) 
    #error "Software Minor Version Number mismatch between Spi.c and Spi_Hw.h"
#endif
/* Make sure the software patch version number is the same between Spi.c and Spi_Hw.h */
#if (SPI_SW_PATCH_VERSION != SPI_HW_H_SW_PATCH_VERSION)
    #error "Software Patch Version Number mismatch between Spi.c and Spi_Hw.h"
#endif

/* Make sure the vendor id is the same between Spi.c and Spi.h */
#if (SPI_VENDOR_ID != SPI_H_VENDOR_ID)
    #error "Vendor id mismatch between Spi.c and Spi.h"
#endif
/* Make sure the AUTOSAR major version number is the same between Spi.c and Spi.h */
#if (SPI_AR_RELEASE_MAJOR_VERSION != SPI_H_AR_RELEASE_MAJOR_VERSION) 
    #error "AUTOSAR Major Version Number mismatch between Spi.c and Spi.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Spi.c and Spi.h */
#if (SPI_AR_RELEASE_MINOR_VERSION != SPI_H_AR_RELEASE_MINOR_VERSION) 
    #error "AUTOSAR Minor Version Number mismatch between Spi.c and Spi.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Spi.c and Spi.h */
#if (SPI_AR_RELEASE_REVISION_VERSION != SPI_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR Revision Version Number mismatch between Spi.c and Spi.h"
#endif
/* Make sure the software major version number is the same between Spi.c and Spi.h */
#if (SPI_SW_MAJOR_VERSION != SPI_H_SW_MAJOR_VERSION) 
    #error "Software Major Version Number mismatch between Spi.c and Spi.h"
#endif
/* Make sure the software minor version number is the same between Spi.c and Spi.h */
#if (SPI_SW_MINOR_VERSION != SPI_H_SW_MINOR_VERSION) 
    #error "Software Minor Version Number mismatch between Spi.c and Spi.h"
#endif
/* Make sure the software patch version number is the same between Spi.c and Spi.h */
#if (SPI_SW_PATCH_VERSION != SPI_H_SW_PATCH_VERSION)
    #error "Software Patch Version Number mismatch between Spi.c and Spi.h"
#endif

/**************************************************************************
                    LOCAL CONSTANT DEFINITION
**************************************************************************/
#if (LEVEL0 != SPI_LEVEL_DELIVERED)
    /**  Define the flag value of empty job  */
    #if (STD_ON == SPI_EXTSIZE_COLLECTION_ENABLE)
        #define SPI_JOB_EMPTY            ((Spi_JobType)(0xFFFFFFFFU))
    #else
        #define SPI_JOB_EMPTY            ((Spi_JobType)(0xFFFFU))
    #endif 
#endif 
/**@} end of group SPI_Macros */
/**************************************************************************
                    LOCAL VARIABLE
**************************************************************************/
/** @defgroup SPI_Variable
  @{
*/
#define   SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Spi_MemMap.h"
/** the senquence array of hardware units */
static VAR(Spi_HwSequenceInfoType, SPI_VAR) Spi_HwQueueArray[SPI_HWUNITCFG_NUM];

#define   SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

/**************************************************************************
                    GLOBAL VARIABLE
**************************************************************************/
#define   SPI_START_SEC_VAR_INIT_UNSPECIFIED
#include "Spi_MemMap.h"
 
/** Pointer to received configuration structure during init and all functions will use */
P2CONST(Spi_ConfigType, SPI_VAR, SPI_APPL_CONST) g_spiCfgPtr = NULL_PTR;

#define   SPI_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

#define   SPI_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Spi_MemMap.h"

/** Used to store the sequence state */
VAR(Spi_SeqStateType, SPI_VAR) g_spiSequenceState[SPI_SEQCFG_NUM];
/** Used to store the job state */
VAR(Spi_JobStateType, SPI_VAR) g_spiJobState[SPI_JOBCFG_NUM];
/** Used to store the channel state */
VAR(Spi_ChannelStateType, SPI_VAR) g_spiChannelState[SPI_CHANNELCFG_NUM];

#if (SPI_HWUNITCFG_NUM > 32u)
    #error "The config HW Units is more than max 32 allowed"
#endif

#define SPI_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Spi_MemMap.h"
 
#define   SPI_START_SEC_VAR_NO_INIT_32
#include "Spi_MemMap.h"
 
/** Used to store the HW units number of sequence occupies */
#if ( LEVEL1 != SPI_LEVEL_DELIVERED )
    static VAR(uint32, SPI_VAR) s_hwUnitSeqUsed[SPI_SEQCFG_NUM];
#endif

#define SPI_STOP_SEC_VAR_NO_INIT_32
#include "Spi_MemMap.h"
 
#define SPI_START_SEC_VAR_INIT_32
#include "Spi_MemMap.h"
 
/** Used to store the runtime HWUnits Status of sync transmission,1:BUSY,0:IDLE */
static volatile VAR(Spi_HwunitStatusType, SPI_VAR) s_syncTransBusyStatus[SPI_HWUNITCFG_NUM] = {SPI_HW_IDLE};

#define SPI_STOP_SEC_VAR_INIT_32
#include "Spi_MemMap.h"
/**@} end of group SPI_Variable */
/**************************************************************************
                    FUNCTION DECLARATION
**************************************************************************/
/** @defgroup SPI_Fuctions
  @{
*/
#define SPI_START_SEC_CODE
#include "Spi_MemMap.h"

#if (SPI_LEVEL_DELIVERED == LEVEL2)
    /** This function returns the HWunit status of the async transmission */
    LOCAL_INLINE FUNC(Spi_StatusType, SPI_CODE) Spi_GetHwAsyncTransStatus(void);
#endif

#if (LEVEL0 != SPI_LEVEL_DELIVERED)
    /** This function scheduling a job for a given HWunit */
    LOCAL_INLINE FUNC(void, SPI_CODE) Spi_JobScheduleOperate(P2VAR(Spi_HwSequenceInfoType, AUTOMATIC, SPI_APPL_DATA) hwQueuePtr,
        VAR(Spi_JobType, AUTOMATIC) jobId,P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) jobCfgPtr);
    /** This function is called in order to lock the jobs of a sequence as ready to be transmitted */
    LOCAL_INLINE FUNC(Std_ReturnType, SPI_CODE) Spi_JobLockStatus
        (VAR(Spi_SequenceType, AUTOMATIC) seqNum,P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr);
#if (STD_ON == SPI_CANCEL_API)
    /** This function is called to unlock the jobs at the end of an async sequence transmission. */
    LOCAL_INLINE FUNC(void, SPI_CODE) Spi_LeftoverJobsUnlock
        (VAR(Spi_JobType, AUTOMATIC) jobsIndexLeft,P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr);
#endif
/** This function starts the transfer of the first scheduled job for a given HwSequence. */
static FUNC(void, SPI_CODE) Spi_ScheduleJobList(P2VAR(Spi_HwSequenceInfoType, AUTOMATIC, SPI_APPL_DATA) hwQueuePtr);
#endif

/**************************************************************************
                    LOCAL FUNCTION
**************************************************************************/
/*!
* @brief    The function will return the HWUnit status of async transmission.
*
* @param[in] None
* @param[out] None
* @param[in,out] None
*
* @retval hwStatus:SPI_UNINIT,SPI_IDLE,SPI_BUSY
*
*/
#if (SPI_LEVEL_DELIVERED == LEVEL2)
LOCAL_INLINE FUNC(Spi_StatusType, SPI_CODE) Spi_GetHwAsyncTransStatus(void)
{
    VAR(Spi_StatusType, AUTOMATIC) hwStatus = SPI_IDLE;
    VAR(Spi_HWUnitType, AUTOMATIC) unitId = 0u;
    /* Get Hwunit asynchronous transfer status. */
    while ((unitId < (Spi_HWUnitType)SPI_HWUNITCFG_NUM) && (SPI_BUSY != hwStatus))
    {
        switch(g_spiCfgPtr->pcHWUnitCfgPtr[unitId].syncMode)
        {
            case SPI_PHYUNIT_ASYNC_U32:
            {
                if(SPI_BUSY == Spi_HwQueueArray[unitId].Status)
                {
                     hwStatus = SPI_BUSY;
                }
                /* current async HWUnit is not busy */
                else 
                {
                     unitId++;
                }
                break;
            }
            /* SPI_PHYUNIT_SYNC_U32: current HWUnit syncMode is not async */
            default: 
            {
                unitId++;
                break;
            }
        }
    }
    return hwStatus;
}
#endif
#if (LEVEL0 != SPI_LEVEL_DELIVERED)
/*!
* @brief    The function will return the status of one job if it is already linked.
*
* @param[in]     seqNum
* @param[in]     seqCfgPtr
* @param[out]    None
* @param[in,out] None
*
* @retval jobStatus:E_OK,E_NOT_OK
*         E_OK:The jobs locked success,not share with other sequences
*         E_NOT_OK:The jobs locked fail,already share with other sequences
*
*/
LOCAL_INLINE FUNC(Std_ReturnType, SPI_CODE) Spi_JobLockStatus
    (VAR(Spi_SequenceType, AUTOMATIC) seqNum,P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) jobStatus = (Std_ReturnType)E_OK;
    P2CONST(Spi_JobType, AUTOMATIC, SPI_APPL_CONST) jobPtr = seqCfgPtr->pcJobIndexListPtr;
    P2VAR(Spi_JobStateType, AUTOMATIC, SPI_APPL_DATA) jobStatePtr;
    P2VAR(Spi_SeqStateType, AUTOMATIC, SPI_APPL_DATA) seqStatePtr;
    VAR(Spi_JobType, AUTOMATIC) jobNum = seqCfgPtr->numOfJobs;
    Spi_JobType lockedCount = (Spi_JobType)0;
    SchM_Enter_Spi_SPI_CRITICAL_SECTION5();
    /* more than one job sequence optimized implementation */
    if ( jobNum > (Spi_JobType)1 ) 
    {
        seqStatePtr = &g_spiSequenceState[seqNum];
        for( ; jobNum > (Spi_JobType)0; jobNum--)
        {
            jobStatePtr = &g_spiJobState[*jobPtr];
            /* the job is locked already used for a pending sequence */
            if (NULL_PTR != jobStatePtr->asyncSequenceStatePtr) 
            {
                /* recover all the previous locked jobs to unlock */
                while(lockedCount > (Spi_JobType)0) 
                {
                    jobPtr--;
                    /* the job status set unlock */
                    g_spiJobState[*jobPtr].asyncSequenceStatePtr = NULL_PTR; 
                    lockedCount--;
                }
                jobStatus = (Std_ReturnType)E_NOT_OK;
                break;
            }
            else 
            {
                /* the job is not locked */
            }
            /* lock the job to current sequence */
            jobStatePtr->asyncSequenceStatePtr = seqStatePtr; 
            lockedCount++;
            jobPtr++; /* Point to next job */
        }
    }
    /* one job sequence optimized implementation */
    else 
    {
        jobStatePtr = &g_spiJobState[*jobPtr];
        /* the job is locked already used for a pending sequence */
        if (NULL_PTR != jobStatePtr->asyncSequenceStatePtr) 
        {
            jobStatus = (Std_ReturnType)E_NOT_OK;
        }
        else 
        {
            /* the job is not lock ,lock the job to current sequence */
            jobStatePtr->asyncSequenceStatePtr = &g_spiSequenceState[seqNum];
        }
    }
    SchM_Exit_Spi_SPI_CRITICAL_SECTION5();
    return jobStatus;
}
/*!
* @brief    Release the jobs at the end of an async sequence transmission.
*
* @param[in]     RemainingJobs    The starting job
* @param[in]     seqCfgPtr        The sequence configuration
* @param[out]    None
* @param[in,out] None
*
* @retval        None
*
*/
#if ( STD_ON == SPI_CANCEL_API )
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_LeftoverJobsUnlock
    (VAR(Spi_JobType, AUTOMATIC) jobsIndexLeft,P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr)
{
    VAR(Spi_JobType, AUTOMATIC) seqJobsCount = seqCfgPtr->numOfJobs;
    VAR(Spi_JobType, AUTOMATIC) jobIndexNum;
    jobIndexNum = seqJobsCount-jobsIndexLeft;
    SchM_Enter_Spi_SPI_CRITICAL_SECTION6();
    while( jobIndexNum < seqJobsCount )
    {
        /* the job status set unlock */
        g_spiJobState[seqCfgPtr->pcJobIndexListPtr[jobIndexNum]].asyncSequenceStatePtr = NULL_PTR;
        jobIndexNum++;
    }
    SchM_Exit_Spi_SPI_CRITICAL_SECTION6();
}
#endif 

/*!
* @brief    the Hardware Unit schedule Jobs in order to send the highest priority Job first.
*
* @param[in]     hwQueuePtr   the Hardware Unit of job used
* @param[in]     jobId        job ID value
* @param[in]     jobCfgPtr    The job configuration
* @param[out]    None
* @param[in,out] None
*
* @retval        None
*
*/
LOCAL_INLINE FUNC(void, SPI_CODE) Spi_JobScheduleOperate
    (P2VAR(Spi_HwSequenceInfoType, AUTOMATIC, SPI_APPL_DATA) hwQueuePtr,VAR(Spi_JobType, AUTOMATIC) jobId,
     P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) jobCfgPtr)
{
    VAR(sint8, AUTOMATIC) jobPrioCfg;
    P2VAR(Spi_JobType, AUTOMATIC, SPI_APPL_DATA) jobTailPtr;

    SchM_Enter_Spi_SPI_CRITICAL_SECTION3();
    /* add the job to the HWUnit scheduling queue */
    if (SPI_IDLE != hwQueuePtr->Status) 
    {
        jobPrioCfg = jobCfgPtr->s8JobPriority;
        /* Get the tail of the scheduling queue */
        jobTailPtr = &hwQueuePtr->schedulingJobTail[jobPrioCfg]; 
        /* the list is empty */
        if (SPI_JOB_EMPTY == *jobTailPtr) 
        {
            /* Add job to the head of list */
            hwQueuePtr->schedulingJobHead[jobPrioCfg] = jobId; 
        }
        else
        {
             /* the list already have job , add the job to the end of list */
            g_spiJobState[*jobTailPtr].nextAsyncJob = jobId; 
        }
        /* config the new list tail */
        *jobTailPtr = jobId; 
        /* the last element is the new job */
        g_spiJobState[jobId].nextAsyncJob = SPI_JOB_EMPTY; 
        /* the new job Priority is less than the current Max Job Priority in the list */
        if (hwQueuePtr->schedulingMaxJobPriority > jobPrioCfg) 
        {
            /* No Operation */
        } 
        /* Arbitration the Max Job Priority in the list and update */
        else 
        {
            hwQueuePtr->schedulingMaxJobPriority = jobPrioCfg;
        }
        SchM_Exit_Spi_SPI_CRITICAL_SECTION3();
    }
    else 
    {
        /* Set the HWUnit status as SPI_BUSY */
        hwQueuePtr->Status = SPI_BUSY; 
        SchM_Exit_Spi_SPI_CRITICAL_SECTION3();
        /* Set the job Result as pending */
        g_spiJobState[jobId].jobResult = SPI_JOB_PENDING; 
        Spi_Hw_JobTrans(jobCfgPtr);
    }
}
#endif /* {( LEVEL0 != SPI_LEVEL_DELIVERED )} */

/**************************************************************************
                    GLOBAL FUNCTION
**************************************************************************/
#if ( STD_ON == SPI_VERSION_INFO_API )
/*!
* @brief    Get the version information of the SPI driver.
*
* @param[in]     verInfoPtr   pointer to module's version information
* @param[out]    None
* @param[in,out] None
*
* @retval        None
*
* @note          AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_GetVersionInfo (P2VAR(Std_VersionInfoType, AUTOMATIC, SPI_APPL_DATA) verInfoPtr)
{  
#if( STD_OFF == SPI_DEV_ERROR_DETECT )
    verInfoPtr->vendorID = (uint16)SPI_H_VENDOR_ID;
    verInfoPtr->moduleID = (uint16)SPI_H_MODULE_ID;
    verInfoPtr->sw_major_version = (uint8)SPI_H_SW_MAJOR_VERSION;
    verInfoPtr->sw_minor_version = (uint8)SPI_H_SW_MINOR_VERSION;
    verInfoPtr->sw_patch_version = (uint8)SPI_H_SW_PATCH_VERSION;
#else
    /* the verInfoPtr is valid,there will report DET error */
    if(NULL_PTR == verInfoPtr) 
    {
        (void)Det_ReportError((uint16)SPI_H_MODULE_ID,(uint8)0,SPI_GETVERSIONINFO_SERVICE_ID,SPI_E_PARAM_POINTER);
    }
    /* Get the module version information */
    else 
    {
        verInfoPtr->vendorID = (uint16)SPI_H_VENDOR_ID;
        verInfoPtr->moduleID = (uint16)SPI_H_MODULE_ID;
        verInfoPtr->sw_major_version = (uint8)SPI_H_SW_MAJOR_VERSION;
        verInfoPtr->sw_minor_version = (uint8)SPI_H_SW_MINOR_VERSION;
        verInfoPtr->sw_patch_version = (uint8)SPI_H_SW_PATCH_VERSION;
    }
#endif 
}
#endif 

/*!
* @brief    Initializes the SPI driver with pre-configurations.
*
* @param[in]     cfgPtr   pointer to the pre-configuration
* @param[out]    None
* @param[in,out] None
*
* @retval        None
*
* @note          AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Init(P2CONST(Spi_ConfigType, AUTOMATIC, SPI_APPL_CONST) cfgPtr)
{
    VAR(uint32, AUTOMATIC) channelCount;
    VAR(uint32, AUTOMATIC) jobCount;
    VAR(uint32, AUTOMATIC) seqCount;
    VAR(Spi_HWUnitType, AUTOMATIC) hwUnitId;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) pcChannelCfgPtr;
#if (LEVEL0 != SPI_LEVEL_DELIVERED || \
    ((SPI_LEVEL_DELIVERED == LEVEL0) && (STD_ON == SPI_CONCURRENT_SYNCTRANSMIT_ENABLE)))
    P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr;
#endif
#if (LEVEL0 != SPI_LEVEL_DELIVERED)
    VAR(sint8, AUTOMATIC) jobPrioCfg;
#endif
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    /* HWUnit is UNINIT state */
    if (NULL_PTR == g_spiCfgPtr) 
    { 
#endif

    #if (STD_ON == SPI_DEV_ERROR_DETECT)
        /* Check the parameter cfgPtr is valid,otherwise report DET error */
        if (NULL_PTR == cfgPtr) 
        {
            (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_INIT_SERVICE_ID,SPI_E_PARAM_POINTER);
        }
        /* Valid parameter */
        else 
        {
    #endif 
            channelCount = (uint32)(cfgPtr->maxChannel);
            jobCount = (uint32)(cfgPtr->maxJob);
            seqCount = (uint32)(cfgPtr->maxSequence);
            /* Check the parameter cfgPtr is valid with PB-configurations,otherwise report DET error */
            /* Inside the range */
            if((channelCount < SPI_CHANNELCFG_NUM) && (jobCount < SPI_JOBCFG_NUM) && (seqCount < SPI_SEQCFG_NUM)) 
            {
                g_spiCfgPtr = cfgPtr;

                /* initialize channel info buffer and state */
                channelCount = 0u;
                while(channelCount <= (uint32)(g_spiCfgPtr->maxChannel))
                {
                    pcChannelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[channelCount];
                    /* IB buffers */
                    if (IB == pcChannelCfgPtr->bufType) 
                    {
                        /* Setup data Length */
                        g_spiChannelState[channelCount].dataLength = pcChannelCfgPtr->dataLength; 
                    }
                    /* EB buffers */
                    else 
                    {
                        /* Initialize TX buffers */
                        pcChannelCfgPtr->pcBufferDescriptPtr->pBufferTXPtr = NULL_PTR; 
                        /* Initialize RX buffers */
                        pcChannelCfgPtr->pcBufferDescriptPtr->pBufferRXPtr = NULL_PTR; 
                        /* data Length Initial zero */
                        g_spiChannelState[channelCount].dataLength = (Spi_NumberOfDataType) 0; 
                    }
                    /* transmit Flags set as SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG */
                    g_spiChannelState[channelCount].transmitFlags = \
                    (VAR(uint8, AUTOMATIC))SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG;
                    channelCount++;
                }
            
                /* initialize job state */
                jobCount = 0u;
                while(jobCount <= (uint32)( g_spiCfgPtr->maxJob))
                {
                    g_spiJobState[jobCount].jobResult = SPI_JOB_OK;
                    #if (LEVEL0 != SPI_LEVEL_DELIVERED)
                        /* Mark the job as unlocked state */
                        g_spiJobState[jobCount].asyncSequenceStatePtr = NULL_PTR; 
                    #endif
                    jobCount++;
                }
            
                /* initialize Sequence state */
                seqCount = 0u;
                while(seqCount <= (uint32)(g_spiCfgPtr->maxSequence))
                {
                    #if (LEVEL0 != SPI_LEVEL_DELIVERED)
                        seqCfgPtr = &g_spiCfgPtr->seqCfgPtr[seqCount];
                        g_spiSequenceState[seqCount].seqCfgPtr = seqCfgPtr;
                    #endif
                    /* initialize sequence results */
                    g_spiSequenceState[seqCount].seqResult = SPI_SEQ_OK;
            
                    #if ( LEVEL1 != SPI_LEVEL_DELIVERED )
                        #if (STD_OFF == SPI_CONCURRENT_SYNCTRANSMIT_ENABLE)
                            s_hwUnitSeqUsed[seqCount] = 0xFFFFFFFFU; 
                        #else 
                            /* Initialize the HWUnits sequence mapping */
                            s_hwUnitSeqUsed[seqCount] = (uint32)0; 
                        #endif 
                    #endif 
                    seqCount++;
                }

                /* initialize all HWUnits configured values */
                for (hwUnitId = 0u;hwUnitId < (VAR(Spi_HWUnitType, AUTOMATIC)) SPI_HWUNITCFG_NUM;hwUnitId++)
                {
                    /* De-initializes HWUnit configured values first */
                    Spi_Hw_DeInit(hwUnitId); 
                    Spi_Hw_Init(hwUnitId, &Spi_HwQueueArray[hwUnitId].Status);
                    #if (SPI_LEVEL_DELIVERED == LEVEL1)
                        /* Set handler with interrupt mode */
                        Spi_Hw_IrqCfg(hwUnitId, SPI_INTERRUPT_MODE); 
                    #elif (SPI_LEVEL_DELIVERED == LEVEL2)
                        /* Set handler with polling mode */
                        Spi_Hw_IrqCfg(hwUnitId, SPI_POLLING_MODE); 
                    #endif
            
                    #if (LEVEL0 != SPI_LEVEL_DELIVERED)
                        /* initialize the scheduling job lists */
                        jobPrioCfg = 0;
                        while( jobPrioCfg < SPI_JOBPRIORITY_LEVELS_MAX)
                        {
                            Spi_HwQueueArray[hwUnitId].schedulingJobHead[jobPrioCfg] = SPI_JOB_EMPTY;
                            Spi_HwQueueArray[hwUnitId].schedulingJobTail[jobPrioCfg] = SPI_JOB_EMPTY;
                            jobPrioCfg++;
                        }
                        /* initialize scheduling MaxJobPriority as -1(no scheduled job) */
                        Spi_HwQueueArray[hwUnitId].schedulingMaxJobPriority = -1;
                    #endif
                    Spi_HwQueueArray[hwUnitId].Status = SPI_IDLE;
                }
            
                #if ((SPI_LEVEL_DELIVERED != LEVEL1) && (STD_ON == SPI_ONEJOBSEQ_OPTIMIZE))
                    /* Initialize prepare cache information for only one job sequences */
                    Spi_Hw_PreCacheInfo(); 
                #endif
            }
            /* Out of the configured range */
            else 
            {
            #if (STD_ON == SPI_DEV_ERROR_DETECT)
                (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_INIT_SERVICE_ID,SPI_E_CONFIG_OUT_RANGE);
            #endif
            } 
#if (STD_ON == SPI_DEV_ERROR_DETECT) 
        }
    }
    /* Report DET error if HWUnit being already initialized */
    else 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_INIT_SERVICE_ID,SPI_E_ALREADY_INITIALIZED);
    }
#endif
}

/*!
* @brief    De-initializes the SPI driver.
*
* @param[in]     None
* @param[out]    None
* @param[in,out] None
*
* @retval        deInitStatus:E_OK,E_NOT_OK
*
* @note          AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_DeInit(void)
{
    VAR(Std_ReturnType, AUTOMATIC) deInitStatus = (Std_ReturnType)E_OK;
    VAR(Spi_HWUnitType, AUTOMATIC) hwUnitId;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
     /* Check not Initialized will report DET error */
    if (NULL_PTR == g_spiCfgPtr)
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_DEINIT_SERVICE_ID,SPI_E_UNINIT);
        deInitStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* module Initialized already */
    else 
    {
        /* No Operation */
    }
    if(E_OK == deInitStatus)
    {
#endif
        /* the Spi Status: not Busy */
        if (SPI_BUSY != Spi_GetStatus()) 
        {
            /* de-initialize all physical HWUnits */
            hwUnitId = 0u;
            while(hwUnitId < (VAR(Spi_HWUnitType, AUTOMATIC)) SPI_HWUNITCFG_NUM)
            {
                Spi_Hw_DeInit(hwUnitId);
                Spi_HwQueueArray[hwUnitId].Status = SPI_UNINIT;
                hwUnitId++;
            }
            /* reset configuration pointer as NULL_PTR */
            g_spiCfgPtr = NULL_PTR; 
        }
        /* the Spi Status:Busy */
        else 
        {
            deInitStatus = (VAR(Std_ReturnType, AUTOMATIC)) E_NOT_OK;
            (void)Det_ReportRuntimeError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_DEINIT_SERVICE_ID,SPI_E_SEQ_PENDING);
        }
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    }
    else
    {
        /* No Operation */
    }
#endif
    return deInitStatus;
}
#if ( (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE0) || (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE2) )
/*!
* @brief    Service for writing one or more data to an IB SPI Handler/Driver Channel specified by parameter.
*
* @param[in]     Channel             Channel ID value
* @param[in]     DataBufferPtr       Pointer to source data buffer to be transmitted
* @param[out]    None
* @param[in,out] None
*
* @retval        writeStatus:E_OK,E_NOT_OK
*
* @note          AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_WriteIB
    (VAR(Spi_ChannelType, AUTOMATIC) Channel,P2CONST(Spi_DataBufferType, AUTOMATIC, SPI_APPL_CONST) DataBufferPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) writeStatus = (Std_ReturnType)E_OK;
    VAR(uint16, AUTOMATIC) index;
    P2VAR(Spi_ChannelStateType, AUTOMATIC, SPI_APPL_DATA) channelStatePtr;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) pcChannelCfgPtr;
    P2VAR(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) txDataBufferPtr;
    P2CONST(Spi_DataBufferType, AUTOMATIC, SPI_APPL_CONST) srcDataBufPtr=NULL_PTR;
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    if ((NULL_PTR != g_spiCfgPtr) && (Channel <= (g_spiCfgPtr->maxChannel)) && (IB == g_spiCfgPtr->pcChannelCfgPtr[Channel].bufType)) /* Check valid parameter */
    {
#endif
        /* Get the channel State */
        channelStatePtr = &g_spiChannelState[Channel]; 
        /* Get the channel configuration */
        pcChannelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[Channel]; 
        /* valid DataBufferPtr, copy data to IB channels */
        if (NULL_PTR != DataBufferPtr) 
        {
            txDataBufferPtr = pcChannelCfgPtr->pcBufferDescriptPtr->pBufferTXPtr;
            srcDataBufPtr = DataBufferPtr;
            index = 0u;
            while( index < pcChannelCfgPtr->dataLength )
            {
                *txDataBufferPtr=*srcDataBufPtr;
                txDataBufferPtr++;
                srcDataBufPtr++;
                index++;
            }
            channelStatePtr->transmitFlags = (uint8)(channelStatePtr->transmitFlags & \
                                                    ((uint8)(~SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG)));
        }
        /* Transmit default value if DataBufferPtr is NULL_PTR */
        else 
        {
            channelStatePtr->transmitFlags |= SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG;
        }
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    }
    /* Check not initialized will report DET error */
    else if (NULL_PTR == g_spiCfgPtr) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_WRITEIB_SERVICE_ID,SPI_E_UNINIT);
        writeStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* invalid channel will report DET error */
    else if (Channel > (g_spiCfgPtr->maxChannel)) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_WRITEIB_SERVICE_ID,SPI_E_PARAM_CHANNEL);
        writeStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* pcChannelCfgPtr->bufType = EB , EB channels will report DET error */
    else 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_WRITEIB_SERVICE_ID,SPI_E_PARAM_CHANNEL);
        writeStatus = (Std_ReturnType)E_NOT_OK;
    }
#endif
    return writeStatus;
}
#endif

#if ( (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE0) || (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE2) )
/*!
* @brief    Service for reading the channel data buffer and storing memory .
*
* @param[in]     Channel            Channel ID value
* @param[out]    None
* @param[in,out] DataBufferPointer  Pointer to destination data buffer in RAM
*
* @retval        readStatus:E_OK,E_NOT_OK
*
* @note          AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_ReadIB
    (VAR(Spi_ChannelType, AUTOMATIC) Channel,P2VAR(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) DataBufferPointer)
{
    VAR(Std_ReturnType, AUTOMATIC) readStatus = (Std_ReturnType)E_OK;
    VAR(Spi_NumberOfDataType, AUTOMATIC) indexNum;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) pcChannelCfgPtr;
    P2CONST(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) srcDataBufPtr;
    P2VAR(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) desDataBufPtr;
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    /* Check valid parameter */
    if ((NULL_PTR != g_spiCfgPtr) && (Channel <= (g_spiCfgPtr->maxChannel)) && (NULL_PTR != DataBufferPointer) && (IB == g_spiCfgPtr->pcChannelCfgPtr[Channel].bufType))
    {
#endif
        /* Get channel configuration */
        pcChannelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[Channel]; 
        /* Copy Rx buffer srcDataBufPtr to IB buffer desDataBufPtr */
        srcDataBufPtr = pcChannelCfgPtr->pcBufferDescriptPtr->pBufferRXPtr;
        desDataBufPtr = DataBufferPointer;
        indexNum = 0u;
        while( indexNum < pcChannelCfgPtr->dataLength )
        {
            *desDataBufPtr=*srcDataBufPtr;
            desDataBufPtr++;
            srcDataBufPtr++;
            indexNum++;
        }
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    }
    /* Module not initialized will report DET error */
    else if (NULL_PTR == g_spiCfgPtr) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_READIB_SERVICE_ID,SPI_E_UNINIT);
        readStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* invalid channel will report DET error */
    else if (Channel > (g_spiCfgPtr->maxChannel)) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_READIB_SERVICE_ID,SPI_E_PARAM_CHANNEL);
        readStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* Invalid Data Buffer Pointer will report DET error */
    else if (NULL_PTR == DataBufferPointer) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_READIB_SERVICE_ID,SPI_E_PARAM_CHANNEL);
        readStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* pcChannelCfgPtr->bufType = EB , EB buffer type will report DET error */
    else 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_READIB_SERVICE_ID,SPI_E_PARAM_CHANNEL);
        readStatus = (Std_ReturnType)E_NOT_OK;
    }
#endif
    return readStatus;
}
#endif

#if ( (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE1) || (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE2) )
/*!
* @brief    Service for setupping an external cahnnel buffer .
*
* @param[in]     Channel             Channel ID value
* @param[in]     SrcDataBufferPtr    Pointer to source data buffer.
* @param[in]     Length              Length (number of data elements) of the data to be transmitted
* @param[out]    DesDataBufferPtr    Pointer to source data buffer.
* @param[in,out] None  
*
* @retval        setupStatus:E_OK,E_NOT_OK
*
* @note          AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_SetupEB
    (VAR(Spi_ChannelType, AUTOMATIC) Channel,P2CONST(Spi_DataBufferType, AUTOMATIC, SPI_APPL_CONST) SrcDataBufferPtr,
     P2VAR(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA) DesDataBufferPtr,VAR(Spi_NumberOfDataType, AUTOMATIC) Length)
{
    VAR(Std_ReturnType, AUTOMATIC) setupStatus = (Std_ReturnType)E_OK;
    P2VAR(Spi_ChannelStateType, AUTOMATIC, SPI_APPL_DATA) channelStatePtr;
    P2CONST(Spi_ChannelConfigType, AUTOMATIC, SPI_APPL_CONST) pcChannelCfgPtr;
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    if((NULL_PTR != g_spiCfgPtr) && (Channel <= g_spiCfgPtr->maxChannel) && \
       (Length <= g_spiCfgPtr->pcChannelCfgPtr[Channel].dataLength) && ((Spi_NumberOfDataType)0 != Length) && 
       (EB == g_spiCfgPtr->pcChannelCfgPtr[Channel].bufType))
    {
#endif
        /* get channel state */
        channelStatePtr = &g_spiChannelState[Channel]; 
        /* get channel configuration */
        pcChannelCfgPtr = &g_spiCfgPtr->pcChannelCfgPtr[Channel]; 
        /*** @warning Spi_c_MISRA_REF1 Dangerous pointer cast results in loss of const qualification. */
        pcChannelCfgPtr->pcBufferDescriptPtr->pBufferTXPtr = \
            (P2VAR(Spi_DataBufferType, AUTOMATIC, SPI_APPL_DATA)) SrcDataBufferPtr;
        pcChannelCfgPtr->pcBufferDescriptPtr->pBufferRXPtr = DesDataBufferPtr;
        channelStatePtr->dataLength = Length;
        /* Transmit default value if source data pointer to NULL_PTR */
        if (NULL_PTR == SrcDataBufferPtr) 
        { 
            channelStatePtr->transmitFlags |= SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG;
        }
        /* Clear transmit default value falg */
        else 
        {
            channelStatePtr->transmitFlags &= (uint8) (~SPI_CHANNEL_TX_DEFAULT_VALUE_FLAG);
        }
        /* Discard receiving data if destination data pointer to NULL_PTR */
        if (NULL_PTR == DesDataBufferPtr) 
        {
            channelStatePtr->transmitFlags |= SPI_CHANNEL_RX_IGNORE_FLAG;
        }
        /* Clear transmit RX ignore falg */
        else 
        {
            channelStatePtr->transmitFlags &= (uint8) (~SPI_CHANNEL_RX_IGNORE_FLAG);
        }
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    }
    /* Module not initialized will report DET error */
    else if (NULL_PTR == g_spiCfgPtr) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETUPEB_SERVICE_ID,SPI_E_UNINIT);
        setupStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* Channel ID out of valid range will report DET error */
    else if (Channel > g_spiCfgPtr->maxChannel) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETUPEB_SERVICE_ID,SPI_E_PARAM_CHANNEL);
        setupStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* Channel data length out of valid range will report DET error */
    else if ((Length > g_spiCfgPtr->pcChannelCfgPtr[Channel].dataLength) || (0u == Length)) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETUPEB_SERVICE_ID,SPI_E_PARAM_LENGTH);
        setupStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* pcChannelCfgPtr->bufType = IB , IB buffer type will report DET error */
    else 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETUPEB_SERVICE_ID,SPI_E_PARAM_CHANNEL);
        setupStatus = (Std_ReturnType)E_NOT_OK;
    }
#endif
    return setupStatus;
}
#endif

/*!
* @brief    Service for getting the HWUnits module status .
*
* @param[in]     None
* @param[out]    None
* @param[in,out] None
*
* @retval        returnStatus:SPI_UNINIT,SPI_IDLE,SPI_BUSY
*
* @note          AUTOSAR support function
*/
FUNC(Spi_StatusType, SPI_CODE) Spi_GetStatus(void)
{
    VAR(Spi_StatusType, AUTOMATIC) returnStatus = SPI_IDLE;
    VAR(Spi_HWUnitType, AUTOMATIC) hwUnitId;
    /* Module initialized already */
    if (NULL_PTR != g_spiCfgPtr) 
    {
        /* check for HWUnit status in sync transmissions */
        hwUnitId = 0u;
        while(hwUnitId < (Spi_HWUnitType)SPI_HWUNITCFG_NUM)
        {
            if (SPI_HW_BUSY == s_syncTransBusyStatus[hwUnitId])
            {
                returnStatus = SPI_BUSY;
                break;
            }
            /* HWUnit status not SPI_BUSY */
            else 
            {
                /* No Operation */
            }
            hwUnitId++;
        }
        /* HWUnit status in sync transmissions is SPI_BUSY */
        if (SPI_BUSY == returnStatus) 
        {
            /* No Operation */
        }
        /* check HWUnit queue array status */
        else 
        {
            hwUnitId = 0u;
            while(hwUnitId < (Spi_HWUnitType)SPI_HWUNITCFG_NUM)
            {
                /* HWUnit queue array status not SPI_BUSY , continue */
                if (SPI_BUSY != Spi_HwQueueArray[hwUnitId].Status) 
                {
                    /* No Operation */
                }
                /* HWUnit status is SPI_BUSY */
                else 
                {
                    returnStatus = SPI_BUSY;
                    break;
                }
                hwUnitId++;
            }
        }
    }
    /* Module not initialized will report DET error */
    else 
    {
    #if (STD_ON == SPI_DEV_ERROR_DETECT)
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_GETSTATUS_SERVICE_ID,SPI_E_UNINIT);
    #endif
        returnStatus = SPI_UNINIT;
    }
    return returnStatus;
}

/*!
* @brief    Service for getting a specific job status .
*
* @param[in]     Job      Job ID value
* @param[out]    None
* @param[in,out] None
*
* @retval        jobStatus:SPI_JOB_OK,SPI_JOB_PENDING,SPI_JOB_FAILED,SPI_JOB_QUEUED
*
* @note          AUTOSAR support function
*/
FUNC(Spi_JobResultType, SPI_CODE) Spi_GetJobResult(VAR(Spi_JobType, AUTOMATIC) Job)
{
    VAR(Spi_JobResultType, AUTOMATIC) jobStatus = SPI_JOB_OK;
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    /* Module not initialized */
    if (NULL_PTR == g_spiCfgPtr) 
    {
        jobStatus = SPI_JOB_FAILED;
        /* Module not initialized will report DET error */
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_GETJOBRESULT_SERVICE_ID,SPI_E_UNINIT);
    }
    /* Job ID out of range */
    else if (Job > g_spiCfgPtr->maxJob) 
    {
        jobStatus = SPI_JOB_FAILED;
        /* Job ID out of range will report DET error */
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_GETJOBRESULT_SERVICE_ID,SPI_E_PARAM_JOB);
    }
    else
    {
        /* No Operation */
    }
    if(SPI_JOB_OK == jobStatus)
    {
        jobStatus = g_spiJobState[Job].jobResult;
    }
    /* Have DET error , jobStatus = SPI_JOB_FAILED */
    else 
    {
        /* No Operation */
    }
#else
    jobStatus = g_spiJobState[Job].jobResult;
#endif
    return jobStatus;
}

/*!
* @brief    Service for getting a specific sequence status .
*
* @param[in]     Sequence      Sequence ID value
* @param[out]    None
* @param[in,out] None
*
* @retval        seqResult:SPI_SEQ_OK,SPI_SEQ_PENDING,SPI_SEQ_FAILED,SPI_SEQ_CANCELLED
*
* @note          AUTOSAR support function
*/
FUNC(Spi_SeqResultType, SPI_CODE) Spi_GetSequenceResult(VAR(Spi_SequenceType, AUTOMATIC) Sequence)
{
    VAR(Spi_SeqResultType, AUTOMATIC) seqResult = SPI_SEQ_OK;
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    /* Module not initialized */
    if (NULL_PTR == g_spiCfgPtr) 
    {
        seqResult = SPI_SEQ_FAILED;
        /* Module not initialized will report DET error */
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_GETSEQUENCERESULT_SERVICE_ID,SPI_E_UNINIT);
    }
    /* Sequence ID out of range */
    else if (Sequence > g_spiCfgPtr->maxSequence) 
    {
        seqResult = SPI_SEQ_FAILED;
        /* Sequence ID out of range will report DET error */
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_GETSEQUENCERESULT_SERVICE_ID,SPI_E_PARAM_SEQ);
    }
    else
    {
        /* No Operation */
    }

    if(SPI_SEQ_OK == seqResult)
    {
        seqResult = g_spiSequenceState[Sequence].seqResult;
    }
    /* Have DET error , seqResult = SPI_SEQ_FAILED */
    else 
    {
        /* No Operation */
    }
#else
    seqResult = g_spiSequenceState[Sequence].seqResult;
#endif
    return seqResult;
}

#if ( LEVEL1 != SPI_LEVEL_DELIVERED )
/*!
* @brief    Service for triggerring the given sequence synchronous transmission. 
*
* @param[in]     Sequence      Sequence ID value
* @param[out]    None
* @param[in,out] None
*
* @retval        transStatus:E_OK,E_NOT_OK
*
* @note          AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_SyncTransmit(VAR(Spi_SequenceType, AUTOMATIC) Sequence)
{
    VAR(Std_ReturnType, AUTOMATIC) transStatus = (Std_ReturnType)E_OK;
    P2VAR(Spi_SeqStateType, AUTOMATIC, SPI_APPL_DATA) seqStatePtr;
    VAR(uint32, AUTOMATIC) seqHWUnitUsed; 
    VAR(Spi_HWUnitType, AUTOMATIC) hwUnitId;
    VAR(Spi_JobType, AUTOMATIC) jobNum;
    P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr;
    VAR(Spi_JobType, AUTOMATIC) seqJobsCount;
    VAR(Spi_JobType, AUTOMATIC) jobId;
    P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) pcJobCfgPtr; 

#if (STD_ON == SPI_DEV_ERROR_DETECT)
    VAR(uint32, AUTOMATIC) unitIsSync;
    #if ( (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE1) || (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE2) )
        VAR(Spi_ChannelType, AUTOMATIC)ChannelID;
        VAR(Spi_ChannelType, AUTOMATIC) NumChannelsInJob;
        VAR(Spi_ChannelType, AUTOMATIC)ChannelIndex;
    #endif
    if ((NULL_PTR != g_spiCfgPtr) && (Sequence <= g_spiCfgPtr->maxSequence))
    {
        /* Get the sequence configuration */
        seqCfgPtr = &g_spiCfgPtr->seqCfgPtr[Sequence]; 
        /* Get the jobs number of sequence */
        seqJobsCount = seqCfgPtr->numOfJobs; 
        for (jobNum = 0u; jobNum < seqJobsCount; jobNum++)
        {
            /* Get the job id */
            jobId = seqCfgPtr->pcJobIndexListPtr[jobNum]; 
            /* Get the job configuration */
            pcJobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId]; 
            /* Get the Logical Spi HWUnit ID */
            hwUnitId = pcJobCfgPtr->jobHWUnit; 
            unitIsSync = g_spiCfgPtr->pcHWUnitCfgPtr[hwUnitId].syncMode;
            /* Async mode will report DET error */
            if ((uint32)(SPI_PHYUNIT_ASYNC_U32) == (unitIsSync)) 
            {
                (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SYNCTRANSMIT_SERVICE_ID,SPI_E_PARAM_UNIT);
                transStatus = (Std_ReturnType)E_NOT_OK;
            }
            /* No DET error ,transStatus = (Std_ReturnType)E_OK */
            else 
            {
            #if ( (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE1) || (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE2) )
                /* Check EB channels setup */
                NumChannelsInJob = pcJobCfgPtr->numOfChannels;
                ChannelIndex = (Spi_ChannelType)0;
                while(ChannelIndex < NumChannelsInJob)
                {
                    ChannelID = pcJobCfgPtr->pcChannelIndexListPtr[ChannelIndex];
                    if ((EB == g_spiCfgPtr->pcChannelCfgPtr[ChannelID].bufType) && (0U == g_spiChannelState[ChannelID].dataLength))
                    {
                        /* Used EB channel not initialized will report DET error */
                        (void)Det_ReportError
                        ((uint16) SPI_H_MODULE_ID, (uint8) 0,SPI_SYNCTRANSMIT_SERVICE_ID,SPI_E_PARAM_EXT_BUF_UNIT);
                        transStatus = (Std_ReturnType)E_NOT_OK;
                        break;
                    }
                    /* IB channel No Operation */
                    else 
                    {
                        /* No Operation */
                    }
                    ChannelIndex++;
                }
            #endif
            }
            if ((Std_ReturnType)E_OK == transStatus)
            {
                /* No Operation */
            }
            else 
            {
                break;
            }
        }        
        if ((Std_ReturnType)E_OK == transStatus)
        {
#endif 
            seqHWUnitUsed = s_hwUnitSeqUsed[Sequence];
            seqCfgPtr = &g_spiCfgPtr->seqCfgPtr[Sequence];
            /* Get the jobs number of sequence */
            seqJobsCount = seqCfgPtr->numOfJobs; 

            SchM_Enter_Spi_SPI_CRITICAL_SECTION1();
            /* if there are HWunits already used,status will be E_NOT_OK */
            for (hwUnitId = 0u; hwUnitId < (Spi_HWUnitType)SPI_HWUNITCFG_NUM; hwUnitId++)
            {
                if(0u == (((uint32)s_syncTransBusyStatus[hwUnitId] << g_spiCfgPtr->pcHWUnitCfgPtr[hwUnitId].hwOffset) \
                & seqHWUnitUsed))
                {
                    /* HWunits is not used , No Operation */
                }
                /* HWunits is used */
                else 
                {
                    transStatus = (Std_ReturnType)E_NOT_OK;
                    break;
                }
            }
            if ((Std_ReturnType)E_NOT_OK == transStatus)
            {
                /* if HWunits already used , will report ReportRuntimeError */
                SchM_Exit_Spi_SPI_CRITICAL_SECTION1();
                (void)Det_ReportRuntimeError
                ((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SYNCTRANSMIT_SERVICE_ID,SPI_E_SEQ_IN_PROCESS);
            }
            else
            {
                seqStatePtr = &g_spiSequenceState[Sequence];
                /* Set the sequence state to SPI_SEQ_PENDING */
                seqStatePtr->seqResult = SPI_SEQ_PENDING; 
                jobNum = 0u;
                while(jobNum < seqJobsCount)
                {
                    /* Get the job id */
                    jobId = seqCfgPtr->pcJobIndexListPtr[jobNum]; 
                    pcJobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId];
                    hwUnitId = pcJobCfgPtr->jobHWUnit;
                    /* set used HWunits status flag to busy */
                    s_syncTransBusyStatus[hwUnitId] = SPI_HW_BUSY; 
                    jobNum++;
                }
                SchM_Exit_Spi_SPI_CRITICAL_SECTION1();
                
                transStatus = Spi_Hw_SeqSyncTrans(Sequence);
                SchM_Enter_Spi_SPI_CRITICAL_SECTION2();
                /* Set the sequence state to SPI_SEQ_FAILED */
                if ((Std_ReturnType)E_NOT_OK == transStatus) 
                {
                    seqStatePtr->seqResult = SPI_SEQ_FAILED; 
                }
                /* Set the sequence state to SPI_SEQ_OK */
                else 
                {
                    seqStatePtr->seqResult = SPI_SEQ_OK; 
                }
                jobNum = 0u;
                while(jobNum < seqJobsCount)
                {
                    /* Get the job id */
                    jobId = seqCfgPtr->pcJobIndexListPtr[jobNum]; 
                    pcJobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId];
                    hwUnitId = pcJobCfgPtr->jobHWUnit;
                    /* set used HWunits status flag to idle */
                    s_syncTransBusyStatus[hwUnitId] = SPI_HW_IDLE; 
                    jobNum++;
                }
                SchM_Exit_Spi_SPI_CRITICAL_SECTION2();
            }
#if (STD_ON == SPI_DEV_ERROR_DETECT)
        }
        /* transStatus E_NOT_OK, No Operation */
        else 
        {
            /* No Operation */
        }
    }
    /* Module not initialized will report DET error */
    else if (NULL_PTR == g_spiCfgPtr) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SYNCTRANSMIT_SERVICE_ID,SPI_E_UNINIT);
        transStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* Sequence > g_spiCfgPtr->maxSequence , Sequence ID out of range will report DET error */
    else 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SYNCTRANSMIT_SERVICE_ID,SPI_E_PARAM_SEQ);
        transStatus = (Std_ReturnType)E_NOT_OK;
    }
#endif
    return transStatus;
}
#endif 

#if (SPI_HW_STATUS_API == STD_ON)

/*!
* @brief    Service for getting the specific HWUnit status. 
*
* @param[in]     HWUnit      SPI Hardware microcontroller peripheral (unit) ID.
* @param[out]    None
* @param[in,out] None
*
* @retval        hwUnitStatus:SPI_UNINIT,SPI_IDLE,SPI_BUSY
*
* @note          AUTOSAR support function
*/
FUNC(Spi_StatusType, SPI_CODE) Spi_GetHWUnitStatus(VAR(Spi_HWUnitType, AUTOMATIC) HWUnit)
{
    VAR(Spi_StatusType, AUTOMATIC) hwUnitStatus = SPI_IDLE;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
    /* Module not initialized will report DET error */
    if (NULL_PTR == g_spiCfgPtr) 
    {
        hwUnitStatus = SPI_UNINIT;
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_GETHWUNITSTATUS_SERVICE_ID,SPI_E_UNINIT);
    }
    /* HWUnit ID out of range will report DET error */
    else if (HWUnit >= SPI_HWUNITCFG_NUM) 
    {
        hwUnitStatus = SPI_UNINIT;
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_GETHWUNITSTATUS_SERVICE_ID,SPI_E_PARAM_UNIT);
    }
    /* No DET Error */
    else 
    {
        /* No Operation */
    }
    if(SPI_IDLE == hwUnitStatus)
    {
        hwUnitStatus = Spi_HwQueueArray[HWUnit].Status;
    }
    /* DET Error */
    else 
    {
        /* No Operation */
    }
#else
    hwUnitStatus = Spi_HwQueueArray[HWUnit].Status;
#endif
    return hwUnitStatus;
}
#endif 
 
#if (STD_ON == SPI_CANCEL_API)

/*!
* @brief    Service for cancelation the given sequence transmission. 
*
* @param[in]     Sequence      Sequence ID value.
* @param[out]    None
* @param[in,out] None
*
* @retval        None
*
* @note          AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_Cancel(VAR(Spi_SequenceType, AUTOMATIC) Sequence)
{
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    if ((NULL_PTR != g_spiCfgPtr) && (Sequence <= g_spiCfgPtr->maxSequence))
    {
#endif
        /* Config sequence state to SPI_SEQ_CANCELLED */
        g_spiSequenceState[Sequence].seqResult = SPI_SEQ_CANCELLED; 
        #if (STD_ON == SPI_SLAVE_SUPPORT)
            /* In Slave mode: Stop sequence immediately */
            Spi_Hw_SlaveTransCancel(Sequence); 
        #endif
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    }
    /* Module not initialized will report DET error */
    else if (NULL_PTR == g_spiCfgPtr) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_CANCEL_SERVICE_ID,SPI_E_UNINIT);
    }
    /* Sequence > g_spiCfgPtr->maxSequence , Sequence ID out of range will report DET error */
    else 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_CANCEL_SERVICE_ID,SPI_E_PARAM_SEQ);
    }
#endif
}
#endif
 
#if (SPI_LEVEL_DELIVERED == LEVEL2)

/*!
* @brief    Service for setting spi module async transmission mode. 
*
* @param[in]     Mode      New mode required..
* @param[out]    None
* @param[in,out] None
*
* @retval        setStatus:E_OK,E_NOT_OK
*
* @note          AUTOSAR support function , only support for level2
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_SetAsyncMode(VAR(Spi_AsyncModeType, AUTOMATIC) Mode)
{
    VAR(Spi_HWUnitType, AUTOMATIC) HWUnit = 0;
    VAR(Std_ReturnType, AUTOMATIC) setStatus = (Std_ReturnType)E_OK;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
    /* Module not initialized will report DET error */
    if (NULL_PTR == g_spiCfgPtr) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETASYNCMODE_SERVICE_ID,SPI_E_UNINIT);
        setStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* No DET Error */
    else 
    {
        /* No Operation */
    }

    if(E_OK == setStatus)
    {
#endif
        if (SPI_BUSY != Spi_GetHwAsyncTransStatus()) 
        {
            HWUnit = 0u;
            while( HWUnit < (Spi_HWUnitType) SPI_HWUNITCFG_NUM)
            {
                /* set the async mode for each HW Unit */
                Spi_Hw_IrqCfg(HWUnit, Mode); 
                HWUnit++;
            }
        }
        /* Busy status will report Runtime Error */
        else 
        {
            (void)Det_ReportRuntimeError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETASYNCMODE_SERVICE_ID,SPI_E_SEQ_PENDING);
            setStatus = (Std_ReturnType)E_NOT_OK;
        }
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    }
    /* DET Error */
    else 
    {
        /* No Operation */
    }
#endif
    return setStatus;
}
#endif

#if ((SPI_LEVEL_DELIVERED == LEVEL2) && (SPI_ASYNC_MODE_ENABLE == STD_ON))
/*!
* @brief    Service for setting a given HWUnit async transmission mode. 
*
* @param[in]     HWUnit         HWUnit ID 
* @param[in]     AsyncMode      New mode required
* @param[out]    None
* @param[in,out] None
*
* @retval        setStatus:E_OK,E_NOT_OK
*
* @note          non-AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_SetHWUnitAsyncMode
    (VAR(Spi_HWUnitType, AUTOMATIC) HWUnit,VAR(Spi_AsyncModeType, AUTOMATIC) AsyncMode)
{
    VAR(Std_ReturnType, AUTOMATIC) setStatus = (Std_ReturnType)E_OK;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
    /* valid configured parameter */
    if ((NULL_PTR != g_spiCfgPtr) && (HWUnit < SPI_HWUNITCFG_NUM)) 
    {
#endif
        /* Sync Mode will report DET error */
        if (SPI_PHYUNIT_ASYNC_U32 != g_spiCfgPtr->pcHWUnitCfgPtr[HWUnit].syncMode) 
        {
        #if (STD_ON == SPI_DEV_ERROR_DETECT)
            (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETHWUNITASYNCMODE_SERVICE_ID,SPI_E_PARAM_UNIT);
        #endif
            setStatus = (Std_ReturnType)E_NOT_OK;
        }
        /* Busy status will report Runtime Error */
        else if (SPI_BUSY == Spi_HwQueueArray[HWUnit].Status) 
        {
            (void)Det_ReportRuntimeError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETHWUNITASYNCMODE_SERVICE_ID,SPI_E_SEQ_PENDING);
            setStatus = (Std_ReturnType)E_NOT_OK;
        }
        /* No error,set async mode */
        else 
        {
            /* set the given HWUnit async transmission mode */
            Spi_Hw_IrqCfg(HWUnit, AsyncMode); 
        }
#if (STD_ON == SPI_DEV_ERROR_DETECT)
    }
    /* Module not initialized will report DET error */
    else if (NULL_PTR == g_spiCfgPtr) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETHWUNITASYNCMODE_SERVICE_ID,SPI_E_UNINIT);
        setStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* HWUnit >= SPI_HWUNITCFG_NUM , HWUnit ID out of range will report DET error */
    else 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_SETHWUNITASYNCMODE_SERVICE_ID,SPI_E_PARAM_UNIT);
        setStatus = (Std_ReturnType)E_NOT_OK;
    }
#endif
    return setStatus;
}
#endif 

#if (LEVEL0 != SPI_LEVEL_DELIVERED)
/*!
* @brief    Service for triggerring the given sequence asynchronous transmission.
*
* @param[in]     Sequence            Sequence ID value
* @param[out]    None
* @param[in,out] None
*
* @retval        seqStatus:E_OK,E_NOT_OK
*
* @note          AUTOSAR support function
*/
FUNC(Std_ReturnType, SPI_CODE) Spi_AsyncTransmit( VAR(Spi_SequenceType, AUTOMATIC) Sequence )
{
    VAR(Std_ReturnType, AUTOMATIC) seqStatus = (Std_ReturnType)E_OK;
    VAR(Spi_JobType, AUTOMATIC) seqJobsCount;
    VAR(Spi_JobType, AUTOMATIC) jobNum;
    P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr;
    P2VAR(Spi_SeqStateType, AUTOMATIC, SPI_APPL_DATA) seqStatePtr;
    P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) pcJobCfgPtr;
    P2CONST(Spi_JobType, AUTOMATIC, SPI_APPL_CONST) JobPtr;
    P2CONST(Spi_JobType, AUTOMATIC, SPI_APPL_CONST) JobIndexPtr;

#if (STD_ON == SPI_DEV_ERROR_DETECT)
    VAR(Spi_JobType, AUTOMATIC) jobId;
    VAR(Spi_HWUnitType, AUTOMATIC) hwUnitId;
    #if ( (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE1) || (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE2) )
        VAR(Spi_ChannelType, AUTOMATIC) ChannelID;
        VAR(Spi_ChannelType, AUTOMATIC) NumChannelsInJob;
        VAR(Spi_ChannelType, AUTOMATIC) ChannelIndex;
    #endif
    /* Check configured parameter */
    if ((NULL_PTR != g_spiCfgPtr) && (Sequence <= (g_spiCfgPtr->maxSequence))) 
    {
#endif 
        /* Get the sequence configuration of the sequence */
        seqCfgPtr = &g_spiCfgPtr->seqCfgPtr[Sequence]; 
        /* Get the job counts of the sequence */
        seqJobsCount = seqCfgPtr->numOfJobs; 
#if (STD_ON == SPI_DEV_ERROR_DETECT)
        /* seqJobsCount = 0 , Empty sequence will report DET error */
        if (0u == seqJobsCount) 
        {
            (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_ASYNCTRANSMIT_SERVICE_ID,SPI_E_SEQUENCE_EMPTY);
            seqStatus = (Std_ReturnType)E_NOT_OK;
        }
        else
        {
            /* No Operation */
        }
        for (jobNum = 0u; jobNum < seqJobsCount; jobNum++)
        {
            /* Get the job id value */
            jobId = seqCfgPtr->pcJobIndexListPtr[jobNum]; 
            /* Get the job configuration */
            pcJobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId]; 
            /* Get the HWUnit ID value */
            hwUnitId = pcJobCfgPtr->jobHWUnit; 
            /* Empty job will report DET error */
            if (0u == pcJobCfgPtr->numOfChannels) 
            {
                (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_ASYNCTRANSMIT_SERVICE_ID,SPI_E_JOB_EMPTY);
                seqStatus = (Std_ReturnType)E_NOT_OK;
            }
            else if (SPI_PHYUNIT_ASYNC_U32 != g_spiCfgPtr->pcHWUnitCfgPtr[hwUnitId].syncMode) 
            {
                (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_ASYNCTRANSMIT_SERVICE_ID,SPI_E_PARAM_UNIT);
                seqStatus = (Std_ReturnType)E_NOT_OK;
            }
            else
            {
                /* No Operation */
            }
        #if ( (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE1) || (SPI_CHANNEL_BUFFERS_ALLOWED == USAGE2) )
            if ((Std_ReturnType)E_NOT_OK != seqStatus)
            {
                /* Check all EB channels setup already */
                NumChannelsInJob = pcJobCfgPtr->numOfChannels;
                ChannelIndex = (Spi_ChannelType)0;
                while(ChannelIndex < NumChannelsInJob)
                {
                    /* Get the channel ID */
                    ChannelID = pcJobCfgPtr->pcChannelIndexListPtr[ChannelIndex]; 
                    if ((EB == g_spiCfgPtr->pcChannelCfgPtr[ChannelID].bufType) && (0U == g_spiChannelState[ChannelID].dataLength))
                    {
                        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_ASYNCTRANSMIT_SERVICE_ID,SPI_E_PARAM_EXT_BUF_UNIT);
                        seqStatus = (Std_ReturnType)E_NOT_OK;
                        break;
                    }
                    /* Buff Type : IB */
                    else 
                    {
                        /* No Operation */
                    }
                    ChannelIndex++;
                }
            }
            /* Sequence status E_NOT_OK */
            else 
            {
                /* No Operation */
            }
        #endif  
            if ((Std_ReturnType)E_OK == seqStatus)
            {
                /* No Operation */
            }
            else
            {
                /* Sequence status E_NOT_OK break loop */
                break; 
            }
        }
        if ((Std_ReturnType)E_NOT_OK != seqStatus)
        {
#endif  
            seqStatus = Spi_JobLockStatus(Sequence, seqCfgPtr);
            /* Report Det_ReportRuntimeError */
            if ((Std_ReturnType)E_NOT_OK == seqStatus) 
            {
                (void)Det_ReportRuntimeError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_ASYNCTRANSMIT_SERVICE_ID,SPI_E_SEQ_PENDING);
            }
            else 
            {
                seqStatePtr = &g_spiSequenceState[Sequence];
                /* Sequence state set SPI_SEQ_PENDING */
                seqStatePtr->seqResult = SPI_SEQ_PENDING; 
                /* job related info Initial */
                seqStatePtr->currentRemainingJobs = seqCfgPtr->numOfJobs - 1u; 
                JobPtr = &seqCfgPtr->pcJobIndexListPtr[0];
                seqStatePtr->pcCurrentJobIndexPtr = JobPtr;
                jobNum = 0u;
                while(jobNum < seqJobsCount)
                {
                    JobIndexPtr = &seqCfgPtr->pcJobIndexListPtr[jobNum];
                    g_spiJobState[*JobIndexPtr].jobResult = SPI_JOB_QUEUED;
                    jobNum++;
                }
                /* Schedule first job transmission */
                pcJobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[*JobPtr];
                Spi_JobScheduleOperate(&Spi_HwQueueArray[pcJobCfgPtr->jobHWUnit],*JobPtr, pcJobCfgPtr);
            }
#if (STD_ON == SPI_DEV_ERROR_DETECT)
        }
        /* seqStatus = E_NOT_OK */
        else 
        {
            /* No Operation */
        }
    }
    /* Module not initialized will report DET error */
    else if (NULL_PTR == g_spiCfgPtr) 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_ASYNCTRANSMIT_SERVICE_ID,SPI_E_UNINIT);
        seqStatus = (Std_ReturnType)E_NOT_OK;
    }
    /* (Sequence > (g_spiCfgPtr->maxSequence)) Sequence ID invalid out of Range will report DET error */
    else 
    {
        (void)Det_ReportError((uint16) SPI_H_MODULE_ID,(uint8) 0,SPI_ASYNCTRANSMIT_SERVICE_ID,SPI_E_PARAM_SEQ);
        seqStatus = (Std_ReturnType)E_NOT_OK;
    }
#endif 
    return seqStatus;
}

/*!
* @brief    This function shall polls the SPI interrupts linked to HW Units allocated to the transmission 
*           of SPI sequences to enable the evolution of transmission state machine.
*
* @param[in]     None
* @param[out]    None
* @param[in,out] None
*
* @retval        None
*
* @note          AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_MainFunction_Handling(void)
{
    VAR(Spi_HWUnitType, AUTOMATIC) hwUnitId = 0;
    /* Check Module is initialized */
    if (NULL_PTR != g_spiCfgPtr) 
    {
        while(hwUnitId < (Spi_HWUnitType) SPI_HWUNITCFG_NUM)
        {
            if (SPI_BUSY != Spi_HwQueueArray[hwUnitId].Status)
            {
                /* HWUnit is not used , No Operation */
            }
            /* HWUnit is used */
            else 
            {
                /* polls the Used_HWUnits SPI interrupts */
                Spi_Hw_PollingIrq(hwUnitId); 
            }
            hwUnitId++;
        }
    }
    else
    {
        /* No Operation */
    }
}

/*!
* @brief    Service for starting a given HWUnit first scheduled transfer. 
*
* @param[in]     hwQueuePtr     The HWUnit used for scheduling
* @param[out]    None
* @param[in,out] None
*
* @retval        None
*
* @note          Non-AUTOSAR support function
*/
static FUNC(void, SPI_CODE) Spi_ScheduleJobList(P2VAR(Spi_HwSequenceInfoType, AUTOMATIC, SPI_APPL_DATA) hwQueuePtr)
{
    VAR(Spi_JobType, AUTOMATIC) jobId;
    P2VAR(Spi_JobType, AUTOMATIC, SPI_APPL_DATA) jobListHeadPtr;
    VAR(sint8, AUTOMATIC) jobPrioCfg;
    /* Get the max scheduling job Priority */
    VAR(sint8, AUTOMATIC) jobMaxPrio = hwQueuePtr->schedulingMaxJobPriority; 

    SchM_Enter_Spi_SPI_CRITICAL_SECTION4();
    /* a job is waiting,Schedule Next Job */
    if (jobMaxPrio >= 0)  
    {
        jobListHeadPtr = &hwQueuePtr->schedulingJobHead[jobMaxPrio];
        /* get the job ID from the highest priority queue */
        jobId = *jobListHeadPtr; 
        /* set the new list head */
        *jobListHeadPtr = g_spiJobState[jobId].nextAsyncJob; 
        /* the new list head is valid */
        if(SPI_JOB_EMPTY != *jobListHeadPtr) 
        {
            /* No Operation */
        }
        /* jobListHeadPtr =  SPI_JOB_EMPTY, reset the tail and adjust the scheduled priority level */
        else 
        {
            /* reset the tail */
            hwQueuePtr->schedulingJobTail[jobMaxPrio] = SPI_JOB_EMPTY; 
            /* check the first not SPI_JOB_EMPTY of scheduling queue */
            jobPrioCfg = jobMaxPrio - 1;
            while(jobPrioCfg >= 0)
            {
                /* No finding */
                if (SPI_JOB_EMPTY == hwQueuePtr->schedulingJobHead[jobPrioCfg]) 
                {
                    /* No Operation */
                }
                /* find a scheduled Job for current priority level */
                else 
                {
                    break;
                }
                jobPrioCfg--;
            }
            /* set the finded scheduled Job as highest priority */
            hwQueuePtr->schedulingMaxJobPriority = jobPrioCfg; 
        }
        SchM_Exit_Spi_SPI_CRITICAL_SECTION4();
        /* Set the job state to SPI_JOB_PENDING */
        g_spiJobState[jobId].jobResult = SPI_JOB_PENDING; 
        Spi_Hw_JobTrans(&g_spiCfgPtr->pcJobCfgPtr[jobId]);
    }
    /* Mark the HWUnit status to SPI_IDLE */
    else 
    {
        hwQueuePtr->Status = SPI_IDLE;
        SchM_Exit_Spi_SPI_CRITICAL_SECTION4();
    }
}

/*!
* @brief    After a Job has been executed,this function schedules the next sequence job or liberates HWUnit.
*
* @param[in]     pcJobCfgPtr     The pointer of the transmited job
* @param[out]    None
* @param[in,out] None
*
* @retval        None
*
* @note          Non-AUTOSAR support function
*/
FUNC(void, SPI_CODE) Spi_JobTransEnd(P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) pcJobCfgPtr)
{
    VAR(Spi_HWUnitType, AUTOMATIC) hwUnitId = pcJobCfgPtr->jobHWUnit;
    P2VAR(Spi_JobStateType, AUTOMATIC, SPI_APPL_DATA) pJobStatePtr = pcJobCfgPtr->pJobStatePtr;
    P2CONST(Spi_JobType, AUTOMATIC, SPI_APPL_CONST) JobPtr;
    VAR(Spi_JobType, AUTOMATIC) jobId;
    P2VAR(Spi_HwSequenceInfoType, AUTOMATIC, SPI_APPL_DATA) hwQueuePtr = &Spi_HwQueueArray[hwUnitId];
    P2VAR(Spi_SeqStateType, AUTOMATIC, SPI_APPL_DATA) seqStatePtr;
    P2CONST(Spi_SeqCfgType, AUTOMATIC, SPI_APPL_CONST) seqCfgPtr;
    P2CONST(Spi_JobConfigType, AUTOMATIC, SPI_APPL_CONST) jobCfgPtr;
      
    SchM_Enter_Spi_SPI_CRITICAL_SECTION7();
    if(SPI_JOB_OK == pJobStatePtr->jobResult) 
    {
        SchM_Exit_Spi_SPI_CRITICAL_SECTION7();
    }
    /* SPI_JOB_OK != pJobStatePtr->jobResult , check job state = SPI_JOB_OK */
    else 
    {
        pJobStatePtr->jobResult = SPI_JOB_OK;
        SchM_Exit_Spi_SPI_CRITICAL_SECTION7();
        /* check the job EndNotification */
        if (NULL_PTR != pcJobCfgPtr->pfEndNotificationPtr) 
        {
            pcJobCfgPtr->pfEndNotificationPtr();
        }
        /* No job EndNotification */
        else 
        {
            /* No Operation */
        }
        seqStatePtr = pJobStatePtr->asyncSequenceStatePtr;
        seqCfgPtr = seqStatePtr->seqCfgPtr;
        /* liberate the job from the sequence */
        pJobStatePtr->asyncSequenceStatePtr = NULL_PTR; 

    #if (STD_ON == SPI_CANCEL_API)
        /* Check current sequence state */
        /* current sequence state is not SPI_SEQ_CANCELLED */
        if (SPI_SEQ_CANCELLED != seqStatePtr->seqResult)  
        {
    #endif
            /* Check the last one job */
            if (0u != seqStatePtr->currentRemainingJobs) 
            {
                seqStatePtr->pcCurrentJobIndexPtr++;
                JobPtr = seqStatePtr->pcCurrentJobIndexPtr;
                jobId = *JobPtr;
                seqStatePtr->currentRemainingJobs--;
                jobCfgPtr = &g_spiCfgPtr->pcJobCfgPtr[jobId];
                /* transmit the next scheduled job */
                if (hwUnitId == jobCfgPtr->jobHWUnit) 
                {
                #if (STD_ON == SPI_INTERRUPTIBLE_SEQ_ALLOWED)
                    /* if the sequence configuration interruptible,Schedule Operate next job */
                    if ((uint8)FALSE != seqCfgPtr->useInterruptible)
                    {
                        Spi_JobScheduleOperate(hwQueuePtr, jobId, jobCfgPtr);
                        Spi_ScheduleJobList(hwQueuePtr);
                    }
                    /* if the sequence configuration non-interruptible,start transmission without scheduling */
                    else
                    {
                #endif
                        /* mark the job state to SPI_JOB_PENDING */
                        g_spiJobState[jobId].jobResult = SPI_JOB_PENDING; 
                        Spi_Hw_JobTrans(jobCfgPtr);
                #if (STD_ON == SPI_INTERRUPTIBLE_SEQ_ALLOWED)
                    }
                #endif
                }
                /* the next job uses the different HWUnits */
                else 
                {
                    Spi_JobScheduleOperate(&Spi_HwQueueArray[jobCfgPtr->jobHWUnit], jobId, jobCfgPtr);
                    Spi_ScheduleJobList(hwQueuePtr);
                }
            }
            else 
            {
                /* Reset sequence state SPI_SEQ_OK */
                seqStatePtr->seqResult = SPI_SEQ_OK; 
                /* check the sequence EndNotification */
                if (NULL_PTR == seqCfgPtr->pfEndNotificationPtr)
                {
                    /* No sequence EndNotification , No Operation */
                }
                else 
                {
                    seqCfgPtr->pfEndNotificationPtr();
                }
                Spi_ScheduleJobList(hwQueuePtr);
            }
    #if (STD_ON == SPI_CANCEL_API)
        }
        else
        {
            /* unlock jobs */
            Spi_LeftoverJobsUnlock(seqStatePtr->currentRemainingJobs, seqCfgPtr); 
            /* check the sequence EndNotification */
            if (NULL_PTR != seqCfgPtr->pfEndNotificationPtr) 
            {
                seqCfgPtr->pfEndNotificationPtr();
            }
            else
            {
                /* No sequence EndNotification , No Operation */
            }
            Spi_ScheduleJobList(hwQueuePtr);
        }
    #endif
    }
}
#endif /* LEVEL0 != SPI_LEVEL_DELIVERED */

#define SPI_STOP_SEC_CODE
#include "Spi_MemMap.h"

/**@} end of group SPI_Fuctions */
#ifdef __cplusplus
}
#endif
/**@} end of group SPI_Driver */
/**@} end of group G32A10xx_StdPeriphDriver */

