/*!
* @file     Lin.c
*
* @version  1.0.0
*
* @brief    AUTOSAR Lin - High level part of LIN driver.
*           This file contains the functions defined by AutoSAR.
* @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
*
*     Lin_c_MISRA_REF2
*          Breaks the required Rule-8.13 of MISRA 2012 guidelines,
*          A pointer should point to a const-qualified type whenever possible.
*
*     Lin_c_MISRA_REF3
*          Breaks the required Rule-13.5 of MISRA 2012 guidelines,
*          The right hand operand of a logical && or || operator shall not contain persistent side effects.
*/

#ifdef __cplusplus
extern "C"
{
#endif

#include "Lin.h"
#include "Lin_Hw.h"
#if (LIN_DEV_ERR_DETECT == STD_ON)
  #include "Det.h"
#endif
#include "LinIf_Cbk.h"

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

/** @defgroup LIN_Driver
  * @brief LIN driver modules
  @{
*/

/** @defgroup LIN_Macros
  @{
*/
/*******************************************************************************
                     VENDOR ID & AUTOSAR VERSION INFO
*******************************************************************************/
/** Vendor ID (vendorId) of the dedicated implementation of this module according to the AUTOSAR vendor list. */
#define LIN_VENDOR_ID                         0x00C1U
/** Major version number of AUTOSAR release on which the appropriate implementation is based on. */
#define LIN_AR_RELEASE_MAJOR_VERSION          0x04U
/** Minor version number of AUTOSAR release on which the appropriate implementation is based on. */
#define LIN_AR_RELEASE_MINOR_VERSION          0x04U
/** Revision version number of AUTOSAR release on which the appropriate implementation is based on. */
#define LIN_AR_RELEASE_REVISION_VERSION       0x00U
/** Major version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define LIN_SW_MAJOR_VERSION                  0x01U
/** Minor version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define LIN_SW_MINOR_VERSION                  0x00U
/** Patch level version number of the vendor specific implementation of the module. The numbering is vendor specific. */
#define LIN_SW_PATCH_VERSION                  0x00U
/**@} end of group LIN_Macros */
/*******************************************************************************
                             VERSION CHECK
*******************************************************************************/
/* Make sure the vendor ids are the same between Lin.c and Lin.h */
#if (LIN_VENDOR_ID != LIN_H_VENDOR_ID)
    #error "Vendor ids mismatch between Lin.c and Lin.h"
#endif /* LIN_VENDOR_ID != LIN_H_VENDOR_ID */

/* Make sure the AUTOSAR major version number is the same between Lin.c and Lin.h */
#if (LIN_AR_RELEASE_MAJOR_VERSION != LIN_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR major Version Numbers mismatch between Lin.c and Lin.h"
#endif /* {(LIN_AR_RELEASE_MAJOR_VERSION != LIN_H_AR_RELEASE_MAJOR_VERSION)} */
/* Make sure the AUTOSAR minor version number is the same between Lin.c and Lin.h */
#if (LIN_AR_RELEASE_MINOR_VERSION != LIN_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR minor Version Numbers mismatch between Lin.c and Lin.h"
#endif /* {(LIN_AR_RELEASE_MINOR_VERSION != LIN_H_AR_RELEASE_MINOR_VERSION)} */
/* Make sure the AUTOSAR revision version number is the same between Lin.c and Lin.h */
#if (LIN_AR_RELEASE_REVISION_VERSION != LIN_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR revision Version Numbers mismatch between Lin.c and Lin.h"
#endif /* {(LIN_AR_RELEASE_REVISION_VERSION != LIN_H_AR_RELEASE_REVISION_VERSION)} */

/* Make sure the software major version number is the same between Lin.c and Lin.h */
#if (LIN_SW_MAJOR_VERSION != LIN_H_SW_MAJOR_VERSION)
    #error "Software major Version Numbers mismatch between Lin.c and Lin.h"
#endif /* {(LIN_SW_MAJOR_VERSION != LIN_H_SW_MAJOR_VERSION)} */
/* Make sure the software minor version number is the same between Lin.c and Lin.h */
#if (LIN_SW_MINOR_VERSION != LIN_H_SW_MINOR_VERSION)
    #error "Software minor Version Numbers mismatch between Lin.c and Lin.h"
#endif /* {(LIN_SW_MINOR_VERSION != LIN_H_SW_MINOR_VERSION)} */
/* Make sure the software patch version number is the same between Lin.c and Lin.h */
#if (LIN_SW_PATCH_VERSION != LIN_H_SW_PATCH_VERSION)
    #error "Software patch Version Numbers mismatch between Lin.c and Lin.h"
#endif /* {(LIN_SW_PATCH_VERSION != LIN_H_SW_PATCH_VERSION)} */

/* Make sure the vendor ids are the same between Lin.c and Lin_Hw.h */
#if (LIN_VENDOR_ID != LIN_HW_H_VENDOR_ID)
    #error "Vendor ids mismatch between Lin.c and Lin_Hw.h"
#endif

/* Make sure the AUTOSAR major version number is the same between Lin.c and Lin_Hw.h */
#if (LIN_AR_RELEASE_MAJOR_VERSION != LIN_HW_H_AR_RELEASE_MAJOR_VERSION)
    #error "AUTOSAR major Version Numbers mismatch between Lin.c and Lin_Hw.h"
#endif
/* Make sure the AUTOSAR minor version number is the same between Lin.c and Lin_Hw.h */
#if (LIN_AR_RELEASE_MINOR_VERSION != LIN_HW_H_AR_RELEASE_MINOR_VERSION)
    #error "AUTOSAR minor Version Numbers mismatch between Lin.c and Lin_Hw.h"
#endif
/* Make sure the AUTOSAR revision version number is the same between Lin.c and Lin_Hw.h */
#if (LIN_AR_RELEASE_REVISION_VERSION != LIN_HW_H_AR_RELEASE_REVISION_VERSION)
    #error "AUTOSAR revision Version Numbers mismatch between Lin.c and Lin_Hw.h"
#endif

/* Make sure the software major version number is the same between Lin.c and Lin_Hw.h */
#if (LIN_SW_MAJOR_VERSION != LIN_HW_H_SW_MAJOR_VERSION)
    #error "Software major Version Numbers mismatch between Lin.c and Lin_Hw.h"
#endif
/* Make sure the software minor version number is the same between Lin.c and Lin_Hw.h */
#if (LIN_SW_MINOR_VERSION != LIN_HW_H_SW_MINOR_VERSION)
    #error "Software minor Version Numbers mismatch between Lin.c and Lin_Hw.h"
#endif
/* Make sure the software revision version number is the same between Lin.c and Lin_Hw.h */
#if (LIN_SW_PATCH_VERSION != LIN_HW_H_SW_PATCH_VERSION)
    #error "Software revision Version Numbers mismatch between Lin.c and Lin_Hw.h"
#endif 

#ifdef ENABLE_INTERMODULE_MCAL_CHECK
    #if (LIN_DEM_REP_ERR_DIS == STD_OFF)
        /* Make sure the AUTOSAR major version number is the same between Lin.c and Dem.h */
        #if (LIN_AR_RELEASE_MAJOR_VERSION != DEM_H_AR_RELEASE_MAJOR_VERSION)
            #error "AUTOSAR major Version Numbers mismatch between Lin.c and Dem.h"
        #endif /* {(LIN_AR_RELEASE_MAJOR_VERSION != DEM_H_AR_RELEASE_MAJOR_VERSION)} */
        /* Make sure the AUTOSAR minor version number is the same between Lin.c and Dem.h */
        #if (LIN_AR_RELEASE_MINOR_VERSION != DEM_H_AR_RELEASE_MINOR_VERSION)
            #error "AUTOSAR minor Version Numbers mismatch between Lin.c and Dem.h"
        #endif /* {(LIN_AR_RELEASE_MINOR_VERSION != DEM_H_AR_RELEASE_MINOR_VERSION)} */
    #endif /* LIN_DEM_REP_ERR_DIS == STD_OFF */

    #if (LIN_DEV_ERR_DETECT == STD_ON)
        /* Make sure the AUTOSAR major version number is the same between Lin.c and Det.h */
        #if (LIN_AR_RELEASE_MAJOR_VERSION != DET_H_AR_RELEASE_MAJOR_VERSION)
            #error "AUTOSAR major Version Numbers mismatch between Lin.c and Det.h"
        #endif /* {(LIN_AR_RELEASE_MAJOR_VERSION != DET_H_AR_RELEASE_MAJOR_VERSION)} */
        /* Make sure the AUTOSAR minor version number is the same between Lin.c and Det.h */
        #if (LIN_AR_RELEASE_MINOR_VERSION != DET_H_AR_RELEASE_MINOR_VERSION)
            #error "AUTOSAR minor Version Numbers mismatch between Lin.c and Det.h"
        #endif /* {(LIN_AR_RELEASE_MINOR_VERSION != DET_H_AR_RELEASE_MINOR_VERSION)} */
    #endif /* LIN_DEV_ERR_DETECT == STD_ON */

    /* Make sure the AUTOSAR major version number is the same between Lin.c and LinIf_Cbk.h */
    #if (LIN_AR_RELEASE_MAJOR_VERSION != LINIF_CBK_H_RELEASE_AUTOSAR_MAJOR_VER)
        #error "AUTOSAR major Version Numbers mismatch between Lin.c and LinIf_Cbk.h"
    #endif /* {(LIN_AR_RELEASE_MAJOR_VERSION != LINIF_CBK_H_RELEASE_AUTOSAR_MAJOR_VER)} */
    /* Make sure the AUTOSAR minor version number is the same between Lin.c and LinIf_Cbk.h */
    #if (LIN_AR_RELEASE_MINOR_VERSION != LINIF_CBK_H_RELEASE_AUTOSAR_MINOR_VER)
        #error "AUTOSAR minor Version Numbers mismatch between Lin.c and LinIf_Cbk.h"
    #endif /* {(LIN_AR_RELEASE_MINOR_VERSION != LINIF_CBK_H_RELEASE_AUTOSAR_MINOR_VER)} */
#endif

/*******************************************************************************
                              GLOBAL VARIABLE
*******************************************************************************/
/** @defgroup LIN_Variable
  @{
*/
/** put all LIN variables into the section defined */
#define LIN_START_SEC_VAR_INIT_UNSPECIFIED
#include "Lin_MemMap.h"

/** Global configuration pointer */
P2CONST(Lin_ConfigType,LIN_VAR,LIN_APPL_CONST) g_LinPCCfgPointer = NULL_PTR;

#define LIN_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Lin_MemMap.h"

#define LIN_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"

/** Global configuration arrayArray */
P2CONST(Lin_ChConfigType,LIN_VAR,LIN_APPL_CONST) g_LinChCfgPtr[LIN_MAX_HW_CH_COUNT];

#define LIN_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"

#define LIN_START_SEC_VAR_INIT_8
#include "Lin_MemMap.h"

/** LIN driver status variable */
VAR(uint8,LIN_VAR)g_LinDriverStatus = (uint8)LIN_UNINIT;

#define LIN_STOP_SEC_VAR_INIT_8
#include "Lin_MemMap.h"

#define LIN_START_SEC_VAR_NO_INIT_8
#include "Lin_MemMap.h"

/** LIN channel state variable */
volatile VAR(uint8,LIN_VAR)g_LinChannelStatus[LIN_MAX_HW_CH_COUNT];
/** LIN frame state variable */
volatile VAR(uint8,LIN_VAR)g_LinChannelFrameStatus[LIN_MAX_HW_CH_COUNT];
/** LIN Frame header state variable */
static volatile VAR(uint8,LIN_VAR)g_LinChannelHeaderStatus[LIN_MAX_HW_CH_COUNT];
/** LIN Frame error status variable */
volatile VAR(uint8,LIN_VAR)g_LinChannelFrameErrorStatus[LIN_MAX_HW_CH_COUNT];
/** LIN channel hardware map variable */
VAR(sint8,LIN_VAR)g_ChannelHWMap[LIN_MAX_HW_AVAILABLE_CH_COUNT];
/** LIN header command type variable */
VAR(uint8, LIN_VAR)g_LinTXHeaderCommand[LIN_MAX_HW_CH_COUNT];
/** LIN SDU buffer variable */
static VAR(uint8, LIN_VAR) g_LinSduBufferAddress[LIN_MAX_HW_CH_COUNT][LIN_SDU_MAX_LEN];

#define LIN_STOP_SEC_VAR_NO_INIT_8
#include "Lin_MemMap.h"

/**@} end of group LIN_Variable */
/*******************************************************************************
                         LOCAL FUNCTION PROTOTYPES
*******************************************************************************/
/** @defgroup LIN_Fuctions
  @{
*/
LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckStateTransitionError(
    VAR(uint8, AUTOMATIC) ChanState,
    VAR(uint8, AUTOMATIC) LinChan,
    VAR(boolean, AUTOMATIC) Condition,
    VAR(uint8, AUTOMATIC) ApiId);

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckInvalidPointerError(
    P2CONST(Lin_ConfigType, AUTOMATIC, LIN_APPL_CONST) LinCfg,
    VAR(uint8, AUTOMATIC) ApiId);

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckUninitError(
    VAR(uint8, AUTOMATIC) ApiId);

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckInvalidChannelError(
    VAR(uint8, AUTOMATIC) LinChan,
    VAR(uint8, AUTOMATIC) ApiId);

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckParamPointerError(
    P2CONST(Lin_PduType, AUTOMATIC, LIN_APPL_CONST) pduInfoPtr,
    VAR(uint8, AUTOMATIC) ApiId);

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckTimeoutError(
    FUNC(Std_ReturnType, LIN_CODE) Api,
    VAR(uint8, AUTOMATIC) ApiId);

/*******************************************************************************
                              GLOBAL FUNCTION
*******************************************************************************/
#define LIN_START_SEC_CODE
#include "Lin_MemMap.h"

/*!
* @brief         Initializes the LIN drive
*
* @param[in]     LinConfig: A Pointer to the LIN driver configuration set
*
* @retval        void
*
* @note          None
*/
FUNC(void, LIN_CODE) Lin_Init(P2CONST(Lin_ConfigType, AUTOMATIC, LIN_APPL_CONST) LinConfig)
{
    VAR(uint8,AUTOMATIC) linChannelLoop;
    VAR(uint8,AUTOMATIC) linHwChannelLoop;
    VAR(uint8,AUTOMATIC) linDataLength;

    /* Check that the LIN driver is in LIN_UNINIT state */
    (void) Lin_CheckStateTransitionError((uint8)LIN_UNINIT,g_LinDriverStatus,FALSE,(uint8)LIN_API_INIT_ID);
    if(E_OK == Lin_CheckInvalidPointerError(LinConfig, (uint8)LIN_API_INIT_ID))
    {
        g_LinPCCfgPointer = LinConfig;

        for(linHwChannelLoop=(uint8)0U; linHwChannelLoop < LIN_MAX_HW_AVAILABLE_CH_COUNT; linHwChannelLoop++)
        {
            g_ChannelHWMap[linHwChannelLoop]= -1;
        }
        for(linChannelLoop=(uint8)0U; linChannelLoop < LIN_MAX_HW_CH_COUNT; linChannelLoop++)
        {
            for(linDataLength=(uint8)0U; linDataLength < LIN_SDU_MAX_LEN; linDataLength++)
            {
                g_LinSduBufferAddress[linChannelLoop][linDataLength]= (uint8)0;
            }
            g_LinChCfgPtr[linChannelLoop] = g_LinPCCfgPointer->linChannelConfigArr[linChannelLoop];
           
            /* Map the configured hardware channel to the logical channel */
            g_ChannelHWMap[g_LinChCfgPtr[linChannelLoop]->channelConfigPCPtr->linChId] =
              (sint8)g_LinChCfgPtr[linChannelLoop]->channelConfigPCPtr->linHwCh;
            /* Reset the error status global flag */
            g_LinChannelFrameErrorStatus[linChannelLoop] = (uint8)LIN_NO_INT_ERROR;
            /* Reset the type of the header command */
            g_LinTXHeaderCommand[linChannelLoop] = (uint8)LIN_TX_NO_COMMAND_ID;
            /* The header status flag */
            g_LinChannelHeaderStatus[linChannelLoop] = (uint8)FALSE;
            /* Set the LIN channel frame operation status to LIN_CHANNEL_NOT_READY_STATE */
            g_LinChannelFrameStatus[linChannelLoop] = (uint8)LIN_CHANNEL_NOT_READY_STATE;
            /* Set the LIN channel state machine to LIN_CH_SLEEP_STATE */
            g_LinChannelStatus[linChannelLoop] = (uint8)LIN_CH_SLEEP_STATE;
            Lin_Hw_InitLinChannel(linChannelLoop);
        }
        /* Update the LIN driver status to LIN_INIT */
        g_LinDriverStatus = (uint8)LIN_INIT;
    }
    else
    {
        /* nothing */
    }
    return;
}


/*!
* @brief         Validates for upper layers the wake up of LIN channel.
*
* @param[in]     LinChannel: Lin channel ID
*
* @retval        E_NOT_OK:  The reasons are:(1)Invalid LIN channel
*                                           (2)The LIN driver is not initialized
*                                           (3)The LIN channel is not dormant
*                                           (4)Wake was not detected
*                E_OK:      No error
*
* @note          None
*/
FUNC(Std_ReturnType, LIN_CODE) Lin_CheckWakeup(VAR(uint8, AUTOMATIC) LinChannel)
{
    VAR(Std_ReturnType, AUTOMATIC) tempReturnValue = (uint8)E_NOT_OK;
    VAR(uint8,AUTOMATIC) linChannelStatus;

    /* Check that the LIN driver is in LIN_INIT state */
    if((E_OK == Lin_CheckUninitError((uint8)LIN_API_CHECKWAKEUP_ID)) &&
       (E_OK == Lin_CheckInvalidChannelError(LinChannel,(uint8)LIN_API_CHECKWAKEUP_ID)))
    {
        linChannelStatus = g_LinChannelStatus[LinChannel];
        /* Check whether the channel is LIN_CH_SLEEP_STATE state or LIN_CH_SLEEP_PENDING state */
        if ((((uint8)LIN_CH_SLEEP_STATE == linChannelStatus) || ((uint8)LIN_CH_SLEEP_PENDING == linChannelStatus))
            && ((uint8)STD_ON == g_LinChCfgPtr[LinChannel]->channelConfigPCPtr->linChWakeupEn))
        {
            if((uint8)TRUE == Lin_Hw_CheckChannelWakeup(LinChannel))
            {
                tempReturnValue = (uint8)E_OK;
            }
            else
            {
                tempReturnValue = (uint8)E_NOT_OK;
            }
        }
        else
        {
            tempReturnValue = (uint8)E_NOT_OK;
        }
        if(E_OK == tempReturnValue)
        {
            /* Indicates a valid timer wake up event to the ECU State Manager */
            EcuM_SetWakeupEvent(g_LinChCfgPtr[LinChannel]->channelConfigPCPtr->linChEcuMWakeupSrc);
            /* Report the wakeup source after a successful wakeup to LinInterface */
            LinIf_WakeupConfirmation(g_LinChCfgPtr[LinChannel]->channelConfigPCPtr->linChEcuMWakeupSrc);
            tempReturnValue = (uint8)E_OK;
        }
        else
        {
            /* Do nothing */
        }
    }
    else
    {
        /* Do nothing */
    }
    return tempReturnValue;
}

/*!
* @brief         When running,view the current LIN driver status
*
* @param[in]     LinChannel:    LIN channel ID
*
* @param[out]    LinSduPtr:    Pointer to the buffer where the current SDU is stored
*
* @retval        LIN_NOT_OK          : Development or production error
*                LIN_TX_OK           : LIN transmission completed
*                LIN_TX_BUSY         : Ongoing transmission of header or response
*                LIN_TX_HEADER_ERROR : Error occurred during header transmission
*                LIN_TX_ERROR        : Error occurred during response transmission
*                LIN_RX_OK           : Reception of correct response
*                LIN_RX_BUSY         : Reception in progress
*                LIN_RX_ERROR        : Error generated during reception
*                LIN_RX_NO_REPONSE   : No data byte was received
*                LIN_OPERATIONAL     : The channel is ready for the next header transfer,and no data is available
*                LIN_CH_SLEEP        : Channel is in sleep mode
*
* @note          None
*/
FUNC(Lin_StatusType, LIN_CODE) Lin_GetStatus(VAR(uint8, AUTOMATIC) LinChannel, P2P2VAR(uint8, AUTOMATIC, LIN_APPL_DATA) LinSduPtr)
{
    VAR(Lin_StatusType, AUTOMATIC) tempReturnValue = LIN_NOT_OK;
    VAR(uint8, AUTOMATIC) linChannelStatus;

    /* Check that the LIN driver is in LIN_INIT state */
    if(E_OK == Lin_CheckUninitError((uint8)LIN_API_GETSTATUS_ID))
    {
        if(E_OK == Lin_CheckInvalidChannelError(LinChannel,(uint8)LIN_API_GETSTATUS_ID))
        {
            /* Check that the pduInfoPtr is not a null pointer */
            if(NULL_PTR == LinSduPtr)
            {
            #if (LIN_DEV_ERR_DETECT == STD_ON)
                /* The input pointer is invalid */
                (void)Det_ReportError((uint16)LIN_H_MODULE_ID, (uint8)0, (uint8)LIN_API_GETSTATUS_ID, (uint8)LIN_E_PARAM_POINTER);
            #endif /* LIN_DEV_ERR_DETECT == STD_ON */
                tempReturnValue = LIN_NOT_OK;
            }
            else
            {
                tempReturnValue = LIN_OK;
            }
        }
        else
        {
            tempReturnValue = LIN_NOT_OK;
        }
    }
    else
    {
        tempReturnValue = LIN_NOT_OK;
    }
    if(LIN_OK == tempReturnValue)
    {
        linChannelStatus = g_LinChannelStatus[LinChannel];
        /* LIN channel status */
        if(linChannelStatus == (uint8)LIN_CH_SLEEP_STATE)
        {
            tempReturnValue = LIN_CH_SLEEP;
        }
        else if(linChannelStatus == (uint8)LIN_CH_SLEEP_PENDING)
        {
            g_LinChannelStatus[LinChannel] = (uint8)LIN_CH_SLEEP_STATE;
            tempReturnValue = LIN_CH_SLEEP;
        }
        else if(linChannelStatus == (uint8)LIN_CH_OPERATIONAL)
        {
            /* Initialize a pointer to return */
            *LinSduPtr = g_LinSduBufferAddress[LinChannel];
            tempReturnValue = Lin_Hw_GetStatus(LinChannel, g_LinSduBufferAddress[LinChannel]);
        }
        else
        {
            /* nothing */
        }
    }
    else
    {
        /* Do nothing */
    }
    return tempReturnValue;
}

/*!
* @brief         Prepares and send a go-to-sleep-command frame on Channel
*
* @param[in]     LinChannel:   LIN channel ID
*
* @retval        E_NOT_OK:  The reasons are:(1)Invalid LIN channel
*                                           (2)The LIN driver is not initialized
*                                           (3)The LIN channel is not dormant
*                                           (4)Wake was not detected
*                E_OK:      No error
*
* @note          None
*/
FUNC(Std_ReturnType, LIN_CODE) Lin_GoToSleep(VAR(uint8, AUTOMATIC) LinChannel)
{
    VAR(Std_ReturnType, AUTOMATIC) tempReturnValue = (uint8)E_NOT_OK;

    /* Check that the LIN driver is in LIN_INIT state */
    if((E_OK == Lin_CheckUninitError((uint8)LIN_API_GOTOSLEEP_ID)) &&
       (E_OK == Lin_CheckInvalidChannelError(LinChannel,(uint8)LIN_API_GOTOSLEEP_ID)))
    {
        /* Check whether the channel is LIN_CH_SLEEP_STATE state */
        if((uint8)LIN_CH_SLEEP_STATE == g_LinChannelStatus[LinChannel])
        {
            tempReturnValue = (uint8)E_OK;
        }
        else
        {
            if(E_OK == Lin_CheckTimeoutError(Lin_Hw_SendGoToSleepFrame(LinChannel),(uint8)LIN_API_GOTOSLEEP_ID))
            {
                tempReturnValue = (uint8)E_OK;
            }
            else
            {
                /* Do nothing */
            }
            /* Set the lin channel state to LIN_CH_SLEEP_PENDING state */
            g_LinChannelStatus[LinChannel] = (uint8)LIN_CH_SLEEP_PENDING;
        }
    }
    else
    {
        /* Do nothing */
    }
    return tempReturnValue;
}

/*!
* @brief         Set the channel status to sleep,but no go-to-sleep-command occurs
*
* @param[in]     ChannelID:   LIN channel ID
*
* @retval        E_NOT_OK:  The reasons are:(1)Invalid LIN channel
*                                           (2)The LIN driver is not initialized
*                                           (3)The LIN channel is not dormant
*                                           (4)Wake was not detected
*                E_OK:      No error
*
* @note          None
*/
FUNC(Std_ReturnType, LIN_CODE) Lin_GoToSleepInternal(VAR(uint8, AUTOMATIC) ChannelID)
{
    VAR(Std_ReturnType, AUTOMATIC) tempReturnValue = (uint8)E_NOT_OK;

    /* Check that the LIN driver is in LIN_INIT state */
    if((E_OK == Lin_CheckUninitError((uint8)LIN_API_GOTOSLEEPINTERNAL_ID)) &&
       (E_OK == Lin_CheckInvalidChannelError(ChannelID,(uint8)LIN_API_GOTOSLEEPINTERNAL_ID)))
    {
        /* Check whether the channel is LIN_CH_SLEEP_STATE state */
        if ((uint8)LIN_CH_SLEEP_STATE == g_LinChannelStatus[ChannelID])
        {
            tempReturnValue = (uint8)E_OK;
        }
        else
        {
            if(E_OK == Lin_CheckTimeoutError(Lin_Hw_GoToSleepStatus(ChannelID),(uint8)LIN_API_GOTOSLEEPINTERNAL_ID))
            {
                tempReturnValue = (uint8)E_OK;
                /* Update the LIN channel frame operation status to LIN_CHANNEL_NOT_READY_STATE */
                g_LinChannelFrameStatus[ChannelID] = (uint8)LIN_CHANNEL_NOT_READY_STATE;
                /* Update the LIN channel status to LIN_CH_SLEEP_STATE */
                g_LinChannelStatus[ChannelID] = (uint8)LIN_CH_SLEEP_STATE;
            }
            else
            {
                /* Do nothing */
            }
        }
    }
    else
    {
        /* Do nothing */
    }
    return tempReturnValue;
}

/*!
* @brief         Sends a LIN frame
*
* @param[in]     ChannelID :    LIN channel ID
* @param[in]     pduInfoPtr:    pointer to PDU that contains the PID, Checksum model,
*                               Response type, Dl and SDU data pointers
*
* @retval        E_NOT_OK:  The reasons are:(1)Invalid LIN channel
*                                           (2)The LIN driver is not initialized
*                                           (3)The LIN channel is not dormant
*                                           (4)Wake was not detected
*                E_OK:      No error
*
* @note          None
*/
FUNC(Std_ReturnType, LIN_CODE) Lin_SendFrame(VAR(uint8, AUTOMATIC) ChannelID, P2CONST(Lin_PduType, AUTOMATIC, LIN_APPL_CONST) pduInfoPtr)
{
    VAR(Std_ReturnType, AUTOMATIC) tempReturnValue = (uint8)E_NOT_OK;

    /* Check that the LIN driver is in LIN_INIT state */
    if((E_OK == Lin_CheckUninitError((uint8)LIN_API_SENDFRAME_ID)) &&
       (E_OK == Lin_CheckInvalidChannelError(ChannelID,(uint8)LIN_API_SENDFRAME_ID)) &&
       (E_OK == Lin_CheckParamPointerError(pduInfoPtr,(uint8)LIN_API_SENDFRAME_ID)) &&
       (E_OK == Lin_CheckStateTransitionError((uint8)LIN_CH_SLEEP_STATE,
                                               g_LinChannelStatus[ChannelID],
                                               TRUE,
                                               (uint8)LIN_API_SENDFRAME_ID)) &&
       (E_OK == Lin_CheckTimeoutError(Lin_Hw_SendFrameHeader(ChannelID,pduInfoPtr),(uint8)LIN_API_SENDFRAME_ID)))
    {
        /* If the host wants to send a response frame,set the header status to TRUE */
        if (LIN_MASTER_RESPONSE == pduInfoPtr->Drc)
        {
            g_LinChannelHeaderStatus[ChannelID]= (uint8)TRUE;
        }
        else
        {
            /* nothing */
        }
        /* The Lin_SendHeader function should be called first */
        if ((uint8)FALSE != g_LinChannelHeaderStatus[ChannelID])
        {
            g_LinChannelHeaderStatus[ChannelID] = (uint8)FALSE;
            Lin_Hw_SendFrameResponse(ChannelID,pduInfoPtr);
            tempReturnValue = (uint8)E_OK;
        }
        else
        {
            tempReturnValue = (uint8)E_OK;
        }
    }
    else
    {
        /* Do nothing */
    }
    return tempReturnValue;
}

/*!
* @brief         Sends a wake up signal to the LIN bus
*
* @param[in]     ChannelID:   LIN channel ID
*
* @retval        E_NOT_OK:  The reasons are:(1)Invalid LIN channel
*                                           (2)The LIN driver is not initialized
*                                           (3)The LIN channel is not dormant
*                                           (4)Wake was not detected
*                E_OK:      No error
*
* @note          None
*/
FUNC(Std_ReturnType, LIN_CODE) Lin_Wakeup(VAR(uint8, AUTOMATIC) ChannelID)
{
    VAR(Std_ReturnType, AUTOMATIC) tempReturnValue = (uint8)E_NOT_OK;

    /* Check that the LIN driver is in LIN_INIT state */
    if((E_OK == Lin_CheckUninitError((uint8)LIN_API_WAKEUP_ID)) && \
       (E_OK == Lin_CheckInvalidChannelError(ChannelID,(uint8)LIN_API_WAKEUP_ID)) && \
       (E_OK == Lin_CheckStateTransitionError((uint8)LIN_CH_SLEEP_STATE,
                                               g_LinChannelStatus[ChannelID],
                                               FALSE,
                                               (uint8)LIN_API_WAKEUP_ID)))
    {
        /* Call Lin_Hw_SendWakeUpFrame function */
        Lin_Hw_SendWakeUpFrame(ChannelID);
        tempReturnValue = (uint8)E_OK;
        /* Reset the error status global flag */
        g_LinChannelFrameErrorStatus[ChannelID] = (uint8)LIN_NO_INT_ERROR;
        /* Update the LIN channel frame operation status to LIN_CHANNEL_READY_STATE */
        g_LinChannelFrameStatus[ChannelID] = (uint8)LIN_CHANNEL_READY_STATE;
        /* Update the LIN channel status to LIN_CH_OPERATIONAL */
        g_LinChannelStatus[ChannelID] = (uint8)LIN_CH_OPERATIONAL;
    }
    else
    {
        /* Do nothing */
    }
    return tempReturnValue;
}

/*!
* @brief         Wake up the LIN channel
*
* @param[in]     ChannelID:   LIN channel ID
*
* @retval        E_NOT_OK:  The reasons are:(1)Invalid LIN channel
*                                           (2)The LIN driver is not initialized
*                                           (3)The LIN channel is not dormant
*                                           (4)Wake was not detected
*                E_OK:      No error
*
* @note          None
*/
FUNC(Std_ReturnType, LIN_CODE) Lin_WakeupInternal(VAR(uint8, AUTOMATIC) ChannelID)
{
    VAR(Std_ReturnType, AUTOMATIC) tempReturnValue = (uint8)E_NOT_OK;

    /* Check that the LIN driver is in LIN_INIT state */
    if((E_OK == Lin_CheckUninitError((uint8)LIN_API_WAKEUPINTERNAL_ID)) &&
       (E_OK == Lin_CheckInvalidChannelError(ChannelID,(uint8)LIN_API_WAKEUPINTERNAL_ID)) &&
       (E_OK == Lin_CheckStateTransitionError((uint8)LIN_CH_SLEEP_STATE,
                                               g_LinChannelStatus[ChannelID],
                                               FALSE,
                                               (uint8)LIN_API_WAKEUPINTERNAL_ID)))
    {
        /* Call Lin_Hw_WakeupChannel function */
        Lin_Hw_WakeupChannel(ChannelID);
        tempReturnValue = (uint8)E_OK;
        /* Reset the error status global flag */
        g_LinChannelFrameErrorStatus[ChannelID] = (uint8)LIN_NO_INT_ERROR;
        /* Update the LIN channel frame operation status to LIN_CHANNEL_READY_STATE */
        g_LinChannelFrameStatus[ChannelID] = (uint8)LIN_CHANNEL_READY_STATE;
        /* Update the LIN channel status to LIN_CH_OPERATIONAL */
        g_LinChannelStatus[ChannelID] = (uint8)LIN_CH_OPERATIONAL;
    }
    else
    {
        /* Do nothing */
    }
    return tempReturnValue;
}

#if (LIN_VERSION_INFO_API == STD_ON)
/*!
* @brief         Returns the versioninfo of this module
*
* @param[in]     versioninfo:   A Pointer to store version information for this module
*
* @retval        void
*
* @note          None
*/
FUNC(void, LIN_CODE) Lin_GetVersionInfo (P2VAR(Std_VersionInfoType, AUTOMATIC,LIN_APPL_DATA) linVersioninfo)
{
#if( LIN_DEV_ERR_DETECT == STD_ON )
    if(NULL_PTR != linVersioninfo)
    {
#endif /* STD_ON == LIN_DEV_ERR_DETECT */
        (linVersioninfo)->sw_major_version = (uint8) LIN_H_SW_MAJOR_VERSION;
        (linVersioninfo)->moduleID = (uint8) LIN_H_MODULE_ID;
        (linVersioninfo)->sw_minor_version = (uint8) LIN_H_SW_MINOR_VERSION;
        (linVersioninfo)->vendorID = (uint16) LIN_H_VENDOR_ID;
        (linVersioninfo)->sw_patch_version = (uint8) LIN_H_SW_PATCH_VERSION;
#if( LIN_DEV_ERR_DETECT == STD_ON )
    }
    else
    {
        (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                              (uint8)0, \
                              (uint8)LIN_API_GETVERSIONINFO_ID, \
                              (uint8) LIN_E_PARAM_POINTER);
    }
#endif /* STD_ON == LIN_DEV_ERR_DETECT */
}
#endif /* STD_ON == LIN_VERSION_INFO_API */

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckStateTransitionError(
    VAR(uint8, AUTOMATIC) ChanState,
    VAR(uint8, AUTOMATIC) LinChan,
    VAR(boolean, AUTOMATIC) Condition,
    VAR(uint8, AUTOMATIC) ApiId)
{
    Std_ReturnType returnValue = E_NOT_OK;
    if (Condition == (boolean)TRUE)
    {
        if (ChanState == LinChan)
        {
    #if (LIN_DEV_ERR_DETECT == STD_ON)
            /* The LIN driver is initialized */
            (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                                  (uint8)0, \
                                  (uint8)ApiId, \
                                  (uint8)LIN_E_STATE_TRANSITION);
    #else
            (void)ApiId;
    #endif /* LIN_DEV_ERR_DETECT == STD_ON */
        }
        else
        {
            returnValue = E_OK;
        }
    }
    else
    {
        if (ChanState != LinChan)
        {
    #if (LIN_DEV_ERR_DETECT == STD_ON)
            /* The LIN driver is initialized */
            (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                                  (uint8)0, \
                                  (uint8)ApiId, \
                                  (uint8)LIN_E_STATE_TRANSITION);
    #else
            (void)ApiId;
    #endif /* LIN_DEV_ERR_DETECT == STD_ON */
        }
        else
        {
            returnValue = E_OK;
        }
    }
    return returnValue;
}

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckInvalidPointerError(
    P2CONST(Lin_ConfigType, AUTOMATIC, LIN_APPL_CONST) LinCfg,
    VAR(uint8, AUTOMATIC) ApiId)
{
    Std_ReturnType returnValue = E_NOT_OK;

    if (NULL_PTR == LinCfg)
    {
    #if (LIN_DEV_ERR_DETECT == STD_ON)
        /* The input pointer is invalid */
        (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                              (uint8)0, \
                              (uint8)ApiId, \
                              (uint8)LIN_E_INVALID_POINTER);
    #else
        (void)ApiId;
    #endif /* LIN_DEV_ERR_DETECT == STD_ON */
    }
    else
    {
        returnValue = E_OK;
    }
    return returnValue;
}

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckUninitError(
    VAR(uint8, AUTOMATIC) ApiId)
{
    Std_ReturnType returnValue = E_NOT_OK;
    /* Checking channel validity */
    if((uint8)LIN_INIT != g_LinDriverStatus)
    {
    #if (LIN_DEV_ERR_DETECT == STD_ON)
        /* LIN driver has not been initialized */
        (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                              (uint8)0, \
                              (uint8)ApiId, \
                              (uint8)LIN_E_UNINIT);
    #else
        (void)ApiId;
    #endif /* LIN_DEV_ERR_DETECT == STD_ON */
    }
    else
    {
        returnValue = E_OK;
    }
    return returnValue;
}

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckInvalidChannelError(
    VAR(uint8, AUTOMATIC) LinChan,
    VAR(uint8, AUTOMATIC) ApiId)
{
    Std_ReturnType returnValue = E_NOT_OK;
    /* Checking channel validity */
    if(LinChan >= LIN_MAX_HW_CH_COUNT)
    {
    #if (LIN_DEV_ERR_DETECT == STD_ON)
        /* LIN driver has not been initialized */
        (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                              (uint8)0, \
                              (uint8)ApiId, \
                              (uint8)LIN_E_INVALID_CHANNEL);
    #else
        (void)ApiId;
    #endif /* LIN_DEV_ERR_DETECT == STD_ON */
    }
    else
    {
        returnValue = E_OK;
    }
    return returnValue;
}

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckParamPointerError(
    P2CONST(Lin_PduType, AUTOMATIC, LIN_APPL_CONST) pduInfoPtr,
    VAR(uint8, AUTOMATIC) ApiId)
{
    Std_ReturnType returnValue = E_NOT_OK;
    /* Check that the pduInfoPtr is not a null pointer */
    if(NULL_PTR == pduInfoPtr)
    {
    #if (LIN_DEV_ERR_DETECT == STD_ON)
        /* The input pointer is invalid */
        (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                              (uint8)0, \
                              (uint8)ApiId, \
                              (uint8)LIN_E_PARAM_POINTER);
    #else
        (void)ApiId;
    #endif /* LIN_DEV_ERR_DETECT == STD_ON */
    }
    else
    {
        returnValue = E_OK;
    }
    return returnValue;
}

LOCAL_INLINE FUNC(Std_ReturnType, LIN_CODE) Lin_CheckTimeoutError(
    FUNC(Std_ReturnType, LIN_CODE) Api,
    VAR(uint8, AUTOMATIC) ApiId)
{
    Std_ReturnType returnValue = E_NOT_OK;
    /* Check that the SduPtr is not a null pointer */
    if((uint8)E_NOT_OK == Api)
    {
        /* Report production error */
        #if (LIN_DEM_REP_ERR_DIS == STD_OFF)
        if ((uint32)STD_ON == g_linErrTimeoutConfig.state)
        {
            (void)Dem_SetEventStatus((Dem_EventIdType)g_linErrTimeoutConfig.id,
                                     DEM_EVENT_STATUS_FAILED);
        }
        else
        {
            #if (LIN_DEV_ERR_DETECT == STD_ON)
            (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                                  (uint8)0, \
                                  (uint8)ApiId, \
                                  (uint8)LIN_E_TIMEOUT);
            #endif  /* LIN_DEV_ERR_DETECT == STD_ON */
        }
        #else
            #if (LIN_DEV_ERR_DETECT == STD_ON)
            (void)Det_ReportError((uint16)LIN_H_MODULE_ID, \
                                  (uint8)0, \
                                  (uint8)ApiId, \
                                  (uint8)LIN_E_TIMEOUT);
            #else
            (void)ApiId;
            #endif  /* LIN_DEV_ERR_DETECT == STD_ON */
        #endif  /* LIN_DEM_REP_ERR_DIS == STD_OFF */
    }
    else
    {
        /* Report production error */
        #if (LIN_DEM_REP_ERR_DIS == STD_OFF)
        if ((uint32)STD_ON == g_linErrTimeoutConfig.state)
        {
            (void)Dem_SetEventStatus((Dem_EventIdType)g_linErrTimeoutConfig.id,
                                     DEM_EVENT_STATUS_PASSED);
        }
        else
        {
             /* nothing */
        }
        #endif
        returnValue = E_OK;
    }
    return returnValue;
}

#define LIN_STOP_SEC_CODE
#include "Lin_MemMap.h"

/**@} end of group LIN_Fuctions */
#ifdef __cplusplus
}
#endif 
/**@} end of group LIN_Driver */
/**@} end of group G32A10xx_StdPeriphDriver */
