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

/**
*   @file   Lpuart_Lin_Ip.c
*
*   @addtogroup LPUART_LIN_IP
*   @{
*/

#ifdef __cplusplus
extern "C"    
{
#endif

/*==================================================================================================
*                                        INCLUDE FILES
* 1) system and project includes
* 2) needed interfaces from external units
* 3) internal and external interfaces from this unit
==================================================================================================*/

#include "Lpuart_Lin_Ip.h"

/*==================================================================================================
*                              SOURCE FILE VERSION INFORMATION
==================================================================================================*/

#define LPUART_LIN_IP_VENDOR_ID_C                      43
#define LPUART_LIN_IP_AR_RELEASE_MAJOR_VERSION_C       4
#define LPUART_LIN_IP_AR_RELEASE_MINOR_VERSION_C       4
#define LPUART_LIN_IP_AR_RELEASE_REVISION_VERSION_C    0
#define LPUART_LIN_IP_SW_MAJOR_VERSION_C               0
#define LPUART_LIN_IP_SW_MINOR_VERSION_C               9
#define LPUART_LIN_IP_SW_PATCH_VERSION_C               0
/*==================================================================================================
*                                       FILE VERSION CHECKS
==================================================================================================*/

#if (LPUART_LIN_IP_VENDOR_ID_C != LPUART_LIN_IP_VENDOR_ID)
    #error "Lpuart_Lin_Ip.c and Lpuart_Lin_Ip.h have different vendor ids"
#endif
/* Check if current file and Lpuart_Lin_Ip header file are of the same Autosar version */
#if ((LPUART_LIN_IP_AR_RELEASE_MAJOR_VERSION_C    != LPUART_LIN_IP_AR_RELEASE_MAJOR_VERSION) || \
     (LPUART_LIN_IP_AR_RELEASE_MINOR_VERSION_C    != LPUART_LIN_IP_AR_RELEASE_MINOR_VERSION) || \
     (LPUART_LIN_IP_AR_RELEASE_REVISION_VERSION_C != LPUART_LIN_IP_AR_RELEASE_REVISION_VERSION))
    #error "AutoSar Version Numbers of Lpuart_Lin_Ip.c and Lpuart_Lin_Ip.h are different"
#endif
/* Check if current file and Lpuart_Lin_Ip header file are of the same Software version */
#if ((LPUART_LIN_IP_SW_MAJOR_VERSION_C != LPUART_LIN_IP_SW_MAJOR_VERSION) || \
     (LPUART_LIN_IP_SW_MINOR_VERSION_C != LPUART_LIN_IP_SW_MINOR_VERSION) || \
     (LPUART_LIN_IP_SW_PATCH_VERSION_C != LPUART_LIN_IP_SW_PATCH_VERSION) )
    #error "Software Version Numbers of Lpuart_Lin_Ip.c and Lpuart_Lin_Ip.h are different"
#endif

/*==================================================================================================
*                           LOCAL TYPEDEFS (STRUCTURES, UNIONS, ENUMS)
==================================================================================================*/

/*==================================================================================================
*                                          LOCAL MACROS
==================================================================================================*/

/*==================================================================================================
*                                         LOCAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
*                                         LOCAL VARIABLES
==================================================================================================*/
#define LIN_START_SEC_VAR_NO_INIT_8
#include "Lin_MemMap.h"

static uint8 Lpuart_Lin_Ip_au8WakeupSignal[LPUART_INSTANCE_COUNT];

#define LIN_STOP_SEC_VAR_NO_INIT_8
#include "Lin_MemMap.h"

/*==================================================================================================
*                                        GLOBAL CONSTANTS
==================================================================================================*/

/*==================================================================================================
*                                        GLOBAL VARIABLES
==================================================================================================*/
/* Table of base addresses for LPUART instances. */
#define LIN_START_SEC_CONST_UNSPECIFIED
#include "Lin_MemMap.h"

static LPUART_Type * const Lpuart_Lin_Ip_apxBases[LPUART_INSTANCE_COUNT] = LPUART_BASE_PTRS;

#define LIN_STOP_SEC_CONST_UNSPECIFIED
#include "Lin_MemMap.h"

#define LIN_START_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"

Lpuart_Lin_Ip_StateStructType Lpuart_Lin_Ip_axStateStructure[LPUART_LIN_IP_NUMBER_OF_INSTANCES];

/* Table to save LIN user config structure pointers */
static const Lpuart_Lin_Ip_UserConfigType * Lpuart_Lin_Ip_apxUserConfigs[LPUART_INSTANCE_COUNT];

static Lpuart_Lin_Ip_StateStructType *Lpuart_Lin_Ip_apxStateStructureArray[LPUART_INSTANCE_COUNT];

#define LIN_STOP_SEC_VAR_NO_INIT_UNSPECIFIED
#include "Lin_MemMap.h"

/*==================================================================================================
*                                    LOCAL FUNCTION PROTOTYPES
==================================================================================================*/
#define LIN_START_SEC_CODE
#include "Lin_MemMap.h"

static void  Lpuart_Lin_Ip_ProcessBreakDetect(const uint32 u32Instance);
static void  Lpuart_Lin_Ip_CheckWakeupSignal(const uint32 u32Instance);
static void  Lpuart_Lin_Ip_FrameIrqHandler(const uint32 u32Instance);
static void  Lpuart_Lin_Ip_ProcessFrameHeader(const uint32 u32Instance, const uint8 tmpByte);
static void  Lpuart_Lin_Ip_ProcessReceiveFrameData(const uint32 u32Instance);
static void  Lpuart_Lin_Ip_ProcessSendFrameData(const uint32 u32Instance, const uint8 tmpByte);
static uint8 Lpuart_Lin_Ip_MakeChecksumByte(const uint32 u32Instance, \
                                            const uint8 * buffer, \
                                            const uint8 sizeBuffer, \
                                            const uint8 PID \
                                           );
static void Lpuart_Lin_Ip_AutoBaudCapture(const uint32 u32Instance);
static void Lpuart_Lin_Ip_ProcessWakeupDetect(const uint32 u32Instance);
static void Lpuart_Lin_Ip_FrameErrorIrqHandler(const uint32 u32Instance);
static Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_StatusBeforeTransfer(const uint8 u8Size, const Lpuart_Lin_Ip_StateStructType *linCurrentState);
static Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_GetBytetoBuffer(const uint8 byteCnt, \
                                                              const uint8 u8BuffSize, \
                                                              uint8 * pBuff, \
                                                              const uint32 u32Instance \
                                                             );
static Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_CheckReadbackByte(const uint8 readbackByte, const uint8 sendByte);
/*==================================================================================================
*                                         LOCAL FUNCTIONS
==================================================================================================*/
/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_CheckReadbackByte
 * Description   : This function checks read-back byte and updates status.
 *
 *END**************************************************************************/
static Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_CheckReadbackByte(const uint8 readbackByte, const uint8 sendByte)
{
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;
    if (sendByte != readbackByte)
    {
        retVal = LPUART_LIN_IP_STATUS_ERROR;
    }
    else
    {
        /* Do nothing */
    }

    return retVal;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_GetBytetoBuffer
 * Description   : This function get received byte then stored to up and also update instance state.
 *
 *END**************************************************************************/
static Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_GetBytetoBuffer(const uint8 byteCnt, \
                                                              const uint8 u8BuffSize, \
                                                              uint8 * pBuff, \
                                                              const uint32 u32Instance \
                                                             )
{
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;
    const LPUART_Type *base = Lpuart_Lin_Ip_apxBases[u32Instance];
    Lpuart_Lin_Ip_StateStructType *linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];
    uint8 checkSum;

    if (byteCnt < u8BuffSize)
    {
        /* No error happened, get data bytes */
        Lpuart_Lin_Ip_HwGetchar(base, &pBuff[byteCnt]);
    }
    else
    {
        /* Get checksum byte */
        Lpuart_Lin_Ip_HwGetchar(base, &checkSum);

        if (checkSum != Lpuart_Lin_Ip_MakeChecksumByte(u32Instance, pBuff, u8BuffSize, linCurrentState->currentPid))
        {
            linCurrentState->currentEventId = LPUART_LIN_IP_CHECKSUM_ERROR_EVENT;
            retVal = LPUART_LIN_IP_STATUS_ERROR;
        }
        else
        {
            linCurrentState->currentEventId = LPUART_LIN_IP_RX_COMPLETED;
            linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_RECV_DATA_COMPLETED;
            retVal = LPUART_LIN_IP_STATUS_SUCCESS;
        }
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_StatusBeforeTransfer
 * Description   : This function checks input parameters of transmission/reception operation.
 *
 *END**************************************************************************/
static Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_StatusBeforeTransfer(const uint8 u8Size, const Lpuart_Lin_Ip_StateStructType *linCurrentState)
{
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;
    boolean checkSleepMode = (LPUART_LIN_IP_NODE_STATE_SLEEP_MODE == linCurrentState->currentNodeState);

    if ((8U < u8Size) || (0U == u8Size) || checkSleepMode)
    {
        retVal = LPUART_LIN_IP_STATUS_ERROR;
    }
    else
    {
        /* Check if the LIN Bus is busy */
        if (linCurrentState->isBusBusy)
        {
            retVal = LPUART_LIN_IP_STATUS_BUSY;
        }
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_FrameErrorIrqHandler
 * Description   : This function handles frame error when it occurs
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_FrameErrorIrqHandler(const uint32 u32Instance)
{
    LPUART_Type *base = Lpuart_Lin_Ip_apxBases[u32Instance];
    Lpuart_Lin_Ip_StateStructType *linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
    uint8 tmpByte;

    /* Clear Framing Error Interrupt Flag */
    (void)Lpuart_Lin_Ip_HwClearStatusFlag(base, LPUART_LIN_IP_FRAME_ERR);

    /* Read dummy to clear LPUART_LIN_IP_RX_DATA_REG_FULL flag */
    Lpuart_Lin_Ip_HwGetchar(base, &tmpByte);

    /* Set current event id to LIN_FRAME_ERROR */
    linCurrentState->currentEventId = LPUART_LIN_IP_FRAME_ERROR;

    /* Check if LIN current node state is LPUART_LIN_IP_NODE_STATE_SEND_DATA */
    if (LPUART_LIN_IP_NODE_STATE_SEND_DATA == linCurrentState->currentNodeState)
    {
        /* Callback function to handle Framing Error Event */
        if (NULL_PTR != pUserConfig->Callback)
        {
            pUserConfig->Callback(u32Instance, linCurrentState);
        }
    }
    else
    {
        /* Check if LIN current node state is LPUART_LIN_IP_NODE_STATE_RECV_DATA */
        if (LPUART_LIN_IP_NODE_STATE_RECV_DATA == linCurrentState->currentNodeState)
        {
            /* Callback function to handle Framing Error Event */
            if (NULL_PTR != pUserConfig->Callback)
            {
                pUserConfig->Callback(u32Instance, linCurrentState);
            }
        }
    }
}
/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_MakeChecksumByte
 * Description   : This function calculate checksum for a frame. This function
 * will return classic or enhanced checksum base on data in
 * Lpuart_Lin_Ip_apxUserConfigs[u32Instance] and input parameter.
 *
 *END**************************************************************************/
static uint8 Lpuart_Lin_Ip_MakeChecksumByte(const uint32 u32Instance, const uint8 * buffer, const uint8 sizeBuffer, const uint8 PID)
{
    uint8 checkSum = PID;
    const uint8 *classicPID;
    uint8 retVal = 0U;
    const Lpuart_Lin_Ip_StateStructType *linCurrentState = (const Lpuart_Lin_Ip_StateStructType *)Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];
    const uint8 numOfClassicPID = linCurrentState->numOfClassicPID;

    /* Get list of PIDs use classic checksum. */
    classicPID = linCurrentState->classicPID;

    if (255U == numOfClassicPID)
    {
        /*all frame use enhanced checksum */
        checkSum = 0U;
    }
    else
    {
        if(NULL_PTR != classicPID)
        {
            for (retVal = 0U; retVal < numOfClassicPID; retVal++)
            {
                if(checkSum == classicPID[retVal])
                {
                    checkSum = 0U;
                    break;
                }
            }
        }
    }
    retVal = Lin_Ip_MakeChecksumByte(buffer, sizeBuffer, checkSum);
    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_AutoBaudCapture
 * Description   : This function capture bits time to detect break char, calculate
 * baudrate from sync bits and enable transceiver if autobaud successful.
 * This function should only be used in Slave.
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_AutoBaudCapture(const uint32 u32Instance)
{
    static uint32 currentTick;
    static uint8 fallingEgdeCount;
    uint32 u32ElapsedTicks;
    uint32 tickPerMicros;
    uint32 masterBaudrateDivisor = 0UL;
    uint8 wakeupByte = 0xF8u; /* wakeup byte for baudrate smaller than 10000 bps */
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;
    Lpuart_Lin_Ip_StateStructType *linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];
    LPUART_Type *base = Lpuart_Lin_Ip_apxBases[u32Instance];
    
    pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];

    if (fallingEgdeCount++ > 0u)
    {
        /* Time between two time falling edge */
        u32ElapsedTicks = OsIf_GetElapsed(&currentTick, LPUART_LIN_IP_TIMEOUT_TYPE);
        /* Get number of tick per a micro second */
        tickPerMicros = OsIf_MicrosToTicks(1000000, LPUART_LIN_IP_TIMEOUT_TYPE);

        if ((u32ElapsedTicks >= (tickPerMicros * BIT_DURATION_MIN_19200)) && (u32ElapsedTicks <= (tickPerMicros * BIT_DURATION_MAX_19200)))
        {
            masterBaudrateDivisor = 19200UL;
            wakeupByte = 0x80u;
        }

        if ((u32ElapsedTicks >= (tickPerMicros * BIT_DURATION_MIN_14400)) && (u32ElapsedTicks <= (tickPerMicros * BIT_DURATION_MAX_14400)))
        {
            masterBaudrateDivisor = 14400UL;
            wakeupByte = 0x80u;
        }

        if ((u32ElapsedTicks >= (tickPerMicros * BIT_DURATION_MIN_9600)) && (u32ElapsedTicks <= (tickPerMicros * BIT_DURATION_MAX_9600)))
        {
            masterBaudrateDivisor = 9600UL;
        }

        if ((u32ElapsedTicks >= (tickPerMicros * BIT_DURATION_MIN_4800)) && (u32ElapsedTicks <= (tickPerMicros * BIT_DURATION_MAX_4800)))
        {
            masterBaudrateDivisor = 4800UL;
        }

        if ((u32ElapsedTicks >= (tickPerMicros * BIT_DURATION_MIN_2400)) && (u32ElapsedTicks <= (tickPerMicros * BIT_DURATION_MAX_2400)))
        {
            masterBaudrateDivisor = 2400UL;
        }

        if (0UL != masterBaudrateDivisor)
        {
            masterBaudrateDivisor = pUserConfig->u32ChannelClock / (pUserConfig->u32OverSamplingRatio * masterBaudrateDivisor);
        }

        if ((0UL != masterBaudrateDivisor) && (pUserConfig->u32BaudRateDivisor != masterBaudrateDivisor))
        {
            /* set the new baudrate */
            Lpuart_Lin_Ip_HwSetBaudRateDivisor(base, masterBaudrateDivisor);

            /* configure wakeup byte because it depends on baudrate */
            Lpuart_Lin_Ip_au8WakeupSignal[u32Instance] = wakeupByte;
            linCurrentState->currentEventId = LPUART_LIN_IP_BAUDRATE_ADJUSTED;
            /* Disable baudrate evaluation process */
            linCurrentState->baudrateEvalEnable = (boolean)FALSE;

            if (NULL_PTR != pUserConfig->Callback)
            {
                pUserConfig->Callback(u32Instance, linCurrentState);
            }

            /* disable Rx active edge */
            Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_ACTIVE_EDGE, (boolean)FALSE);
            /* Update current state and current event */
            linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_RECV_PID;
            linCurrentState->currentEventId = LPUART_LIN_IP_SYNC_OK;
        }
    }
    else
    {
        currentTick = OsIf_GetCounter(LPUART_LIN_IP_TIMEOUT_TYPE);
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_ProcessWakeupDetect
 * Description   : This function process wake-up signal detect for LIN communication.
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_ProcessWakeupDetect(const uint32 u32Instance)
{
    const Lpuart_Lin_Ip_StateStructType * linCurrentState = (const Lpuart_Lin_Ip_StateStructType *)Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];
    LPUART_Type * base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Clear LPUART_RX Pin Active Edge Interrupt Flag. */
    (void)Lpuart_Lin_Ip_HwClearStatusFlag(base, LPUART_LIN_IP_RX_ACTIVE_EDGE_DETECT);

    switch(linCurrentState->currentNodeState)
    {
        case LPUART_LIN_IP_NODE_STATE_SLEEP_MODE:
            /* Check if a wakeup signal has been received */
            Lpuart_Lin_Ip_CheckWakeupSignal(u32Instance);
            break;

        case LPUART_LIN_IP_NODE_STATE_RECV_SYNC:
            if (linCurrentState->baudrateEvalEnable)
            {
                /* Count falling edge of sync byte */
                Lpuart_Lin_Ip_AutoBaudCapture(u32Instance);
            }
            break;

        default:
            /* Other case, do nothing */
            break;
    }
}
/*==================================================================================================
*                                        GLOBAL FUNCTIONS
==================================================================================================*/

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_Init
 * Description   : This function initializes a LPUART instance for operation.
 * This function will initialize the run-time state structure to keep track of
 * the on-going transfers, initialize the module to user defined settings and
 * default settings, set break field length to be 13 bit times minimum, enable
 * the break detect interrupt, Rx complete interrupt, frame error detect interrupt,
 * and enable the LPUART module transmitter and receiver.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_Init_Activity
*/
void Lpuart_Lin_Ip_Init(const uint32 u32Instance, const Lpuart_Lin_Ip_UserConfigType * pUserConfig)
{
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *pCrtStateStruct;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != pUserConfig);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];
    /* Check if current instance is already initialized. */

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR == Lpuart_Lin_Ip_apxStateStructureArray[u32Instance]);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the pointer of the state structure  */
    pCrtStateStruct = pUserConfig->pStateStruct;
    /* Save LIN user config structure pointer. */
    Lpuart_Lin_Ip_apxUserConfigs[u32Instance] = pUserConfig;
    /* Init LPUART */
    Lpuart_Lin_Ip_HwInit(base);
    /* if autobaud is enabled */
    if ((pUserConfig->autobaudEnable) && ((boolean)LPUART_LIN_IP_SLAVE == pUserConfig->nodeFunction))
    {
        /* Setting Slave's baudrate to 19200 will help Slave node */
        /* always detect LIN Break from Master */
        pCrtStateStruct->fallingEdgeInterruptCount = 0U;
        pCrtStateStruct->baudrateEvalEnable = (boolean)TRUE;
    }
    /* Check if osr is between 4x and 7x oversampling.
    * If so, then "BOTHEDGE" sampling must be turned on */
    if (pUserConfig->u32OverSamplingRatio < 8U)
    {
        Lpuart_Lin_Ip_HwEnableBothEdgeSamplingCmd(base);
    }
    /* program the osr value (bit value is one less than actual value) */
    Lpuart_Lin_Ip_HwSetOversamplingRatio(base, (pUserConfig->u32OverSamplingRatio - 1U));
    /* write the sbr value to the BAUD registers */
    Lpuart_Lin_Ip_HwSetBaudRateDivisor(base, pUserConfig->u32BaudRateDivisor);

    /* Set 8 bit counts per char */
    Lpuart_Lin_Ip_HwSetBitCountPerChar(base, LPUART_LIN_IP_8_BITS_PER_CHAR, (boolean)FALSE);

    /* Set no parity mode */
    Lpuart_Lin_Ip_HwSetParityMode(base, LPUART_LIN_IP_PARITY_DISABLED);
    /* One stop bit */
    Lpuart_Lin_Ip_HwSetStopBitCount(base, LPUART_LIN_IP_ONE_STOP_BIT);
    /* Check if the current node is MASTER */
    if ((boolean)LPUART_LIN_IP_MASTER == pUserConfig->nodeFunction)
    {
        /* Set Break char length as 13 bits minimum */
        Lpuart_Lin_Ip_HwSetBreakCharTransmitLength(base, pUserConfig->u8BreakLength);
        /* Set Break char detect length as 11 bits minimum */
        Lpuart_Lin_Ip_HwSetBreakCharDetectLength(base, pUserConfig->u8BreakLengthDetect);
    }
    else
    {
        /* Set Break char detect length as 11 bits minimum */
        Lpuart_Lin_Ip_HwSetBreakCharDetectLength(base, pUserConfig->u8BreakLengthDetect);
        /* Enable LIN break detect interrupt */
        Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT, (boolean)TRUE);
    }

    /* Clear interupt lag for guarantee */
    (void)Lpuart_Lin_Ip_HwClearStatusFlag(base, LPUART_LIN_IP_ALL_INT_FLAGS);
    /* Disable RX complete interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL, (boolean)FALSE);
    /* Enable frame error interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_FRAME_ERR_FLAG, (boolean)TRUE);

    /* Change node's current state to IDLE */
    pCrtStateStruct->currentNodeState = LPUART_LIN_IP_NODE_STATE_IDLE;
    /* Clear flags in current LIN state structure */
    pCrtStateStruct->isTxBusy = (boolean)FALSE;
    pCrtStateStruct->isRxBusy = (boolean)FALSE;
    pCrtStateStruct->isBusBusy = (boolean)FALSE;
    pCrtStateStruct->timeoutCounterFlag = (boolean)FALSE;
    pCrtStateStruct->timeoutCounter = 0U;
    pCrtStateStruct->classicPID = pUserConfig->classicPID;
    pCrtStateStruct->numOfClassicPID = pUserConfig->numOfClassicPID;

    /* Assign wakeup signal to satisfy LIN Specifications specifies that
    * wakeup signal shall be in range from 250us to 5 ms.
    */
    Lpuart_Lin_Ip_au8WakeupSignal[u32Instance] = pUserConfig->u8WakeupByte;

    if (!((pUserConfig->autobaudEnable) && ((boolean)LPUART_LIN_IP_SLAVE == pUserConfig->nodeFunction)))
    {
        /* Enable the LPUART transmitter and receiver */
        Lpuart_Lin_Ip_HwSetTransmitterCmd(base, (boolean)TRUE);
        Lpuart_Lin_Ip_HwSetReceiverCmd(base, (boolean)TRUE);
    }

    /* Save runtime structure pointer. */
    Lpuart_Lin_Ip_apxStateStructureArray[u32Instance] = pUserConfig->pStateStruct;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_Deinit
 * Description   : This function shuts down the LPUART by disabling interrupts and
 *                 transmitter/receiver.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_Deinit_Activity
*/
void Lpuart_Lin_Ip_Deinit(const uint32 u32Instance)
{
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
    uint32 startTime;
    uint32 timeoutTicks;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Check if current instance is already de-initialized or is gated.*/
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    Lpuart_Lin_Ip_StartTimeout(&startTime, &timeoutTicks, LPUART_LIN_IP_TIMEOUT_VALUE_US, LPUART_LIN_IP_TIMEOUT_TYPE);
    do
    {
        /* Wait until the data is completely shifted out of shift register */
        if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_TX_COMPLETE))
        {
            break;
        }
    }
    while (!Lpuart_Lin_Ip_TimeoutExpired(startTime, timeoutTicks, LPUART_LIN_IP_TIMEOUT_TYPE));

    /* Disable the LPUART transmitter and receiver */
    Lpuart_Lin_Ip_HwSetTransmitterCmd(base, (boolean)FALSE);
    Lpuart_Lin_Ip_HwSetReceiverCmd(base, (boolean)FALSE);

    /* Change node's current state to UNINIT */
    linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_UNINIT;

    /* Clear our saved pointer to the LIN state structure */
    Lpuart_Lin_Ip_apxStateStructureArray[u32Instance] = NULL_PTR;

}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_AsyncSendFrameData
 * Description   : This function sends data out through the LPUART module using
 * non-blocking method. This function will calculate the checksum byte and send
 * it with the frame data. The function will return immediately after calling
 * this function. If txSize is equal to 0 or greater than 8  or node's current
 * state is in SLEEP mode then the function will return LPUART_LIN_IP_STATUS_ERROR. If
 * isBusBusy is currently TRUE then the function will return LPUART_LIN_IP_STATUS_BUSY.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_AsyncSendFrameData_Activity
*/
Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_AsyncSendFrameData(const uint32 u32Instance, const uint8 * pTxBuff, const uint8 u8TxSize)
{
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
#if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;
#endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != pTxBuff);
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Check if txSize > 8 or equal to 0 or node's current state
     * is in SLEEP mode then return LPUART_LIN_IP_STATUS_ERROR. Or
     * return LPUART_LIN_IP_STATUS_BUSY if bus is busy */
    retVal = Lpuart_Lin_Ip_StatusBeforeTransfer(u8TxSize, linCurrentState);
    
    if (LPUART_LIN_IP_STATUS_SUCCESS != retVal)
    {
        /* Do nothing */
    }
    else
    {
        /* Make the checksum byte. */
        linCurrentState->checkSum = Lpuart_Lin_Ip_MakeChecksumByte(u32Instance, pTxBuff, u8TxSize, linCurrentState->currentPid);

        SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_00();
        {
            /* Update the LIN state structure. */
            linCurrentState->txBuff = pTxBuff;
            /* Add a place for checksum byte */
            linCurrentState->txSize = (uint8)(u8TxSize + 1U);
            linCurrentState->cntByte = 0U;
            linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_SEND_DATA;
            linCurrentState->currentEventId = LPUART_LIN_IP_NO_EVENT;
            linCurrentState->isBusBusy = (boolean)TRUE;
            linCurrentState->isTxBusy = (boolean)TRUE;
        }
        SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_00();

        /* Set Break char detect length as 10 bits minimum */
        Lpuart_Lin_Ip_HwSetBreakCharDetectLength(base, LPUART_LIN_IP_BREAK_CHAR_10_BIT_MINIMUM_U8);

    #if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
        pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
        /* Set timeout counter for processing in TimeoutService funtion */
        /* 
         * The TimeoutService function is call each 500 microsecond regularly,
         * so timeout counter equal to timeout each data byte multi length of data frame plus checksum byte and div 500.
         * At the end, plus 1 for surplus.
         */
        Lpuart_Lin_Ip_SetTimeoutCounter(u32Instance, pUserConfig->u32ResponseTimeoutValue * ((uint32)u8TxSize + 1UL) / 500UL + 1UL);

        #ifdef LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION
        /* Call notification to start timer */
        LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION(u32Instance);
        #endif
    #endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

        /* Start sending data */
        Lpuart_Lin_Ip_HwPutchar(base, *linCurrentState->txBuff);
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_SyncSendFrameData
 * Description   : This function shall send frame data out through 
 *                 the LIN Hardware Interface module using a blocking method.
 *                 The function does not return until the transmission is completed.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_SyncSendFrameData_Activity
*/
Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_SyncSendFrameData(const uint32 u32Instance, const uint8 * pTxBuff, const uint8 u8TxSize)
{
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_ERROR;
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
    uint8 byteCnt = 0;
    uint8 sendByte;
    uint8 readbackByte;
    uint32 startTime;
    uint32 timeoutTicks;
#if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;
#endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != pTxBuff);
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];
    /* Check if rxSize > 8, equal to 0 or node's current state
     * is in SLEEP mode then return LPUART_LIN_IP_STATUS_ERROR. Or instance is Busy */
    retVal = Lpuart_Lin_Ip_StatusBeforeTransfer(u8TxSize, linCurrentState);

    if (LPUART_LIN_IP_STATUS_SUCCESS != retVal)
    {
        /* Do nothing */
    }
    else
    {
        /* Disable interrupt Rx data full */
        Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL, (boolean)FALSE);
        /* Disable LIN break detect interrupt */
        Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT, (boolean)FALSE);
        linCurrentState->currentEventId = LPUART_LIN_IP_NO_EVENT;
        /* Make the checksum byte. */
        linCurrentState->checkSum = Lpuart_Lin_Ip_MakeChecksumByte(u32Instance, pTxBuff, u8TxSize, linCurrentState->currentPid);

    #if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
        pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
        /* Set timeout counter for processing in TimeoutService funtion */
        /* 
         * The TimeoutService function is call each 500 microsecond regularly,
         * so timeout counter equal to timeout each data byte multi length of data frame plus checksum byte and div 500.
         * At the end, plus 1 for surplus.
         */
        Lpuart_Lin_Ip_SetTimeoutCounter(u32Instance, pUserConfig->u32ResponseTimeoutValue * ((uint32)u8TxSize + 1UL) / 500UL + 1UL);

        #ifdef LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION
        /* Call notification to start timer */
        LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION(u32Instance);
        #endif
    #endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

        do
        {
            /* Check no error occurred or not */
            if ( (LPUART_LIN_IP_NO_EVENT != linCurrentState->currentEventId) || (byteCnt > u8TxSize) )
            {
                /* At least an error occurred */
                retVal = LPUART_LIN_IP_STATUS_ERROR;
                break;
            }
            else
            {
                if (byteCnt < u8TxSize)
                {
                    sendByte = pTxBuff[byteCnt];
                }
                else
                {
                    sendByte = linCurrentState->checkSum;
                }

                /* Push data to buffer */
                Lpuart_Lin_Ip_HwPutchar(base, sendByte);
                /* Prepare state to fit code flow */
                retVal = LPUART_LIN_IP_STATUS_TIMEOUT;
            }

            /* Set time for waiting loop */
            Lpuart_Lin_Ip_StartTimeout(&startTime, &timeoutTicks, LPUART_LIN_IP_TIMEOUT_VALUE_US, LPUART_LIN_IP_TIMEOUT_TYPE);

            /* Check status of byte transmission and read back value */
            do
            {
                /* Check read back status of buffer */
                if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_RX_DATA_REG_FULL))
                {
                    Lpuart_Lin_Ip_HwGetchar(base, &readbackByte);

                    retVal = Lpuart_Lin_Ip_CheckReadbackByte(readbackByte, sendByte);

                    break;
                }
            }
            while (!Lpuart_Lin_Ip_TimeoutExpired(startTime, timeoutTicks, LPUART_LIN_IP_TIMEOUT_TYPE));
        }
        /* Check the last of data frame and move to next byte */
        while ((byteCnt++ < u8TxSize) && (LPUART_LIN_IP_STATUS_SUCCESS == retVal));

        /* Change node's current state to IDLE */
        Lpuart_Lin_Ip_GotoIdleState(u32Instance);
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_GetTransmitStatus
 * Description   : This function returns whether the previous LPUART transmit has
 * finished. When performing non-blocking transmit, the user can call this
 * function to ascertain the state of the current transmission:
 * in progress (or busy that is LPUART_LIN_IP_STATUS_BUSY) or timeout (if timeout has occurred that is
 * LPUART_LIN_IP_STATUS_TIMEOUT) or complete (success that is LPUART_LIN_IP_STATUS_SUCCESS).
 * In addition, if the transmission is still in progress, the user can obtain the number
 * of bytes that still needed to transmit.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_GetTransmitStatus_Activity
*/
Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_GetTransmitStatus(const uint32 u32Instance, uint8 * const pBytesRemaining)
{
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;
    const Lpuart_Lin_Ip_StateStructType *linCurrentState;
    boolean bBytesCountReturn = (NULL_PTR == pBytesRemaining) ? (boolean)FALSE : (boolean)TRUE;
    uint8 u8LocalBytesRemaining = 0u;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = (const Lpuart_Lin_Ip_StateStructType *)Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the number of bytes that is still needed to transmit */
    u8LocalBytesRemaining = (uint8)(linCurrentState->txSize - linCurrentState->cntByte);

    /* Return status of the on-going transmission */
    if ( (LPUART_LIN_IP_NO_EVENT == linCurrentState->currentEventId) && (0U != u8LocalBytesRemaining) )
    {
        
        if ((boolean)TRUE != linCurrentState->timeoutCounterFlag)
        {
            retVal = LPUART_LIN_IP_STATUS_BUSY;
        }
        else
        {
            retVal = LPUART_LIN_IP_STATUS_TIMEOUT;
        }
        
    }

    if (bBytesCountReturn)
    {
        *pBytesRemaining = u8LocalBytesRemaining;
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_AsyncReceiveFrameData
 * Description   : This function receives data from LPUART module using
 * non-blocking method. This function returns immediately after initiating the
 * receive function. The application has to get the receive status to see when
 * the receive is complete. In other words, after calling non-blocking get
 * function, the application must get the receive status to check if receive
 * is completed or not. The interrupt handler function will check
 * the checksum byte. If the checksum is correct, it will receive the frame data.
 * If the checksum is incorrect, this function will return LPUART_LIN_IP_STATUS_TIMEOUT and data in
 * rxBuff might be wrong. This function also check if rxSize is in range from 1 to 8.
 * If not, it will return LPUART_LIN_IP_STATUS_ERROR. This function also returns LPUART_LIN_IP_STATUS_ERROR if
 * node's current state is in SLEEP mode. This function checks if the
 * isBusBusy is (boolean)FALSE, if not it will return LPUART_LIN_IP_STATUS_BUSY.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_AsyncReceiveFrameData_Activity
*/
Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_AsyncReceiveFrameData(const uint32 u32Instance, uint8 * pRxBuff, const uint8 u8RxSize)
{
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
#if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;
#endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != pRxBuff);
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Check if txSize > 8 or equal to 0 or node's current state
     * is in SLEEP mode then return LPUART_LIN_IP_STATUS_ERROR. Or
     * return LPUART_LIN_IP_STATUS_BUSY if bus is busy */
    retVal = Lpuart_Lin_Ip_StatusBeforeTransfer(u8RxSize, linCurrentState);

    if (LPUART_LIN_IP_STATUS_SUCCESS != retVal)
    {
        /* Do nothing */
    }
    else
    {
        SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_01();
        {
            /* Update the LIN state structure. */
            linCurrentState->rxBuff = pRxBuff;
            /* Add a place for checksum byte */
            linCurrentState->rxSize = (uint8)(u8RxSize + 1U);
            linCurrentState->cntByte = 0U;

            /* Start receiving data */
            linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_RECV_DATA;
            linCurrentState->currentEventId = LPUART_LIN_IP_NO_EVENT;
            linCurrentState->isBusBusy = (boolean)TRUE;
            linCurrentState->isRxBusy = (boolean)TRUE;
        }
        SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_01();

    #if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
        pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
        /* Set timeout counter for processing in TimeoutService funtion */
        /* 
         * The TimeoutService function is call each 500 microsecond regularly,
         * so timeout counter equal to timeout each data byte multi length of data frame plus checksum byte and div 500.
         * At the end, plus 1 for surplus.
         */
        Lpuart_Lin_Ip_SetTimeoutCounter(u32Instance, pUserConfig->u32ResponseTimeoutValue * ((uint32)u8RxSize + 1UL) / 500UL + 1UL);

        #ifdef LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION
        /* Call notification to start timer */
        LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION(u32Instance);
        #endif
    #endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

        /* Set Break char detect length as 10 bits minimum */
        Lpuart_Lin_Ip_HwSetBreakCharDetectLength(base, LPUART_LIN_IP_BREAK_CHAR_10_BIT_MINIMUM_U8);
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_SyncReceiveFrameData
 * Description   : This function receives data from LPUART module using
 * non-blocking method. This function returns immediately after initiating the
 * receive function. The application has to get the receive status to see when
 * the receive is complete. In other words, after calling non-blocking get
 * function, the application must get the receive status to check if receive
 * is completed or not. The interrupt handler function will check
 * the checksum byte. If the checksum is correct, it will receive the frame data.
 * If the checksum is incorrect, this function will return LPUART_LIN_IP_STATUS_TIMEOUT and data in
 * rxBuff might be wrong. This function also check if rxSize is in range from 1 to 8.
 * If not, it will return LPUART_LIN_IP_STATUS_ERROR. This function also returns LPUART_LIN_IP_STATUS_ERROR if
 * node's current state is in SLEEP mode. This function checks if the
 * isBusBusy is (boolean)FALSE, if not it will return LPUART_LIN_IP_STATUS_BUSY.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_SyncReceiveFrameData_Activity
*/
Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_SyncReceiveFrameData(const uint32 u32Instance, uint8 * pRxBuff, const uint8 u8RxSize)
{
    volatile Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
    uint8 byteCnt = 0;
    uint32 timeoutTicks;
    uint32 startTime;
#if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;
#endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != pRxBuff);
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Check if rxSize > 8 or equal to 0 or node's current state
     * is in SLEEP mode then return LPUART_LIN_IP_STATUS_ERROR */
    retVal = Lpuart_Lin_Ip_StatusBeforeTransfer(u8RxSize, linCurrentState);

    if (LPUART_LIN_IP_STATUS_SUCCESS != retVal)
    {
        /* Do nothing */
    }
    else
    {
        /* Disable interrupt Rx data full */
        Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL, (boolean)FALSE);
        /* Disable LIN break detect interrupt */
        Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT, (boolean)FALSE);
        /* Start receiving data */
        linCurrentState->currentEventId = LPUART_LIN_IP_NO_EVENT;

        do
        {
            #if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
                pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
                /* Set timeout counter for processing in TimeoutService funtion */
                /* 
                 * The TimeoutService function is call each 500 microsecond regularly,
                 * so timeout counter equal to timeout each data byte multi length of data frame plus checksum byte and div 500.
                 * At the end, plus 1 for surplus.
                 */
                Lpuart_Lin_Ip_SetTimeoutCounter(u32Instance, pUserConfig->u32ResponseTimeoutValue * ((uint32)u8RxSize + 1UL) / 500UL + 1UL);

                #ifdef LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION
                /* Call notification to start timer */
                LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION(u32Instance);
                #endif
            #endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

            retVal = LPUART_LIN_IP_STATUS_TIMEOUT;
            /* Set time for waiting loop */
            Lpuart_Lin_Ip_StartTimeout(&startTime, &timeoutTicks, LPUART_LIN_IP_TIMEOUT_VALUE_US, LPUART_LIN_IP_TIMEOUT_TYPE);

            while (!Lpuart_Lin_Ip_TimeoutExpired(startTime, timeoutTicks, LPUART_LIN_IP_TIMEOUT_TYPE))
            {
                if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_RX_DATA_REG_FULL))
                {
                    retVal = LPUART_LIN_IP_STATUS_SUCCESS;
                    break;
                }
            }

            if (LPUART_LIN_IP_NO_EVENT != linCurrentState->currentEventId)
            {
                /* An error occurred in reception */
                retVal = LPUART_LIN_IP_STATUS_ERROR;
            }
            else if (LPUART_LIN_IP_STATUS_SUCCESS == retVal)
            {
                /* Get char to Rx buffer, check check sum byte to update event id */
                retVal = Lpuart_Lin_Ip_GetBytetoBuffer(byteCnt, u8RxSize, pRxBuff, u32Instance);
            }
            else
            {
                retVal = LPUART_LIN_IP_STATUS_TIMEOUT;
            }

            if (LPUART_LIN_IP_STATUS_SUCCESS != retVal)
            {
                /* Error in receiving previous byte */
                break;
            }
        }
        while (u8RxSize > byteCnt++);

        /* Change node's current state to IDLE */
        Lpuart_Lin_Ip_GotoIdleState(u32Instance);
    }

    return retVal;
}
/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_AbortTransferData
 * Description   : Aborts an on-going non-blocking transmission/reception.
 * While performing a non-blocking transferring data, users can call this
 * function to terminate immediately the transferring.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_AbortTransferData_Activity
*/
void Lpuart_Lin_Ip_AbortTransferData(const uint32 u32Instance)
{
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
    LPUART_Type * base;
    uint32 startTime;
    uint32 timeoutTicks;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];
    /* Disable RX complete interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL, (boolean)FALSE);

    /* Disable frame error interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_FRAME_ERR_FLAG, (boolean)FALSE);

    /* Disable LIN break detect interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT, (boolean)FALSE);

    MCAL_FAULT_INJECTION_POINT(LPUART_FIP_1_T_TIME_OUT_1);

    /* Wait until the data is completely shifted out of shift register */
    Lpuart_Lin_Ip_StartTimeout(&startTime, &timeoutTicks, LPUART_LIN_IP_TIMEOUT_VALUE_US, LPUART_LIN_IP_TIMEOUT_TYPE);
    do
    {
        if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_TX_COMPLETE))
        {
            break;
        }
    }
    while (!Lpuart_Lin_Ip_TimeoutExpired(startTime, timeoutTicks, LPUART_LIN_IP_TIMEOUT_TYPE));

    /* Change node's current state to IDLE */
    Lpuart_Lin_Ip_GotoIdleState(u32Instance);

    /* Clear LIN Tx and Rx Busy flag */
    linCurrentState->isTxBusy = (boolean)FALSE;
    linCurrentState->isRxBusy = (boolean)FALSE;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_GetReceiveStatus
 * Description   : This function returns whether the previous LPUART reception is
 * complete. When performing a non-blocking receive, the user can call this
 * function to ascertain the state of the current receive progress: in progress
 * or complete. In addition, if the reception is still in progress, the user can
 * obtain the number of words that is still needed to receive.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_GetReceiveStatus_Activity
*/
Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_GetReceiveStatus(const uint32 u32Instance, uint8 * const pBytesRemaining)
{
    const Lpuart_Lin_Ip_StateStructType *linCurrentState;
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = (const Lpuart_Lin_Ip_StateStructType *)Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the number of bytes that is still needed to receive */
    *pBytesRemaining = (uint8)(linCurrentState->rxSize - linCurrentState->cntByte);

    /* Return status of the on-going reception */
    if ((LPUART_LIN_IP_NO_EVENT == linCurrentState->currentEventId) && (0U != *pBytesRemaining))
    {
        if ((boolean)TRUE != linCurrentState->timeoutCounterFlag)
        {
            retVal = LPUART_LIN_IP_STATUS_BUSY;
        }
        else
        {
            retVal = LPUART_LIN_IP_STATUS_TIMEOUT;
        }
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_GoToSleepMode
 * Description   : This function puts current LIN node to sleep mode.
 * This function changes current node state to LPUART_LIN_IP_NODE_STATE_SLEEP_MODE.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_GoToSleepMode_Activity
*/
void Lpuart_Lin_Ip_GoToSleepMode(const uint32 u32Instance)
{
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];
    /* Update node's current state to SLEEP_MODE. */
    linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_SLEEP_MODE;

    /* Clear txBusy, rxBusy, busBusy flags */
    linCurrentState->isTxBusy  = (boolean)FALSE;
    linCurrentState->isRxBusy  = (boolean)FALSE;
    linCurrentState->isBusBusy = (boolean)FALSE;

    /* Clear LPUART_RX Pin Active Edge Interrupt Flag. */
    (void)Lpuart_Lin_Ip_HwClearStatusFlag(base, LPUART_LIN_IP_RX_ACTIVE_EDGE_DETECT);

    /* Set Receive data not inverted */
    Lpuart_Lin_Ip_HwSetRxDataPolarity(base, (boolean)FALSE);

    /* Disable RX complete interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL, (boolean)FALSE);

    /* Enable RX Input Active Edge interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_ACTIVE_EDGE, (boolean)TRUE);

    /* Disable frame error interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_FRAME_ERR_FLAG, (boolean)FALSE);

    /* Disable LIN break detect interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT, (boolean)FALSE);

}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_SendWakeupSignal
 * Description   : This function sends a wakeup signal through the LPUART interface.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_SendWakeupSignal_Activity
*/
Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_SendWakeupSignal(const uint32 u32Instance)
{
    LPUART_Type *base;
    const Lpuart_Lin_Ip_StateStructType *linCurrentState;
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = (const Lpuart_Lin_Ip_StateStructType *)Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Check if bus is not busy */
    if ((boolean)TRUE != linCurrentState->isBusBusy)
    {
        /* Send a wakeup signal */
        Lpuart_Lin_Ip_HwPutchar(base, Lpuart_Lin_Ip_au8WakeupSignal[u32Instance]);
    }
    else
    {
        retVal = LPUART_LIN_IP_STATUS_BUSY;
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_GetCurrentNodeState
 * Description   : This function gets the current LIN node state.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_GetCurrentNodeState_Activity
*/
Lpuart_Lin_Ip_NodeStateType Lpuart_Lin_Ip_GetCurrentNodeState(const uint32 u32Instance)
{
    Lpuart_Lin_Ip_NodeStateType retVal = LPUART_LIN_IP_NODE_STATE_UNINIT;
    const Lpuart_Lin_Ip_StateStructType *linCurrentState;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = (const Lpuart_Lin_Ip_StateStructType *)Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    if (NULL_PTR != linCurrentState)
    {
        retVal = linCurrentState->currentNodeState;
    }

    /* Return LIN node's current state */
    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_TimeoutService
 * Description   : This is callback function for Timer Interrupt Handler.
 * Users shall initialize a timer (for example FTM) in Output compare mode
 * with period of about 500 micro seconds. In timer IRQ handler, call this function.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_TimeoutService_Activity
*/
void Lpuart_Lin_Ip_TimeoutService(const uint32 u32Instance)
{
#if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
    Lpuart_Lin_Ip_NodeStateType state;

    #if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
    #endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    #if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
    #endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
    /* Get LIN node's current state */
    state = linCurrentState->currentNodeState;

    switch(state)
    {
        /* If the node is SENDING DATA */
        case LPUART_LIN_IP_NODE_STATE_SEND_DATA:
        /* If the node is RECEIVING DATA */
        case LPUART_LIN_IP_NODE_STATE_RECV_DATA:
         /* If the node is RECEIVING HEADER */
        case LPUART_LIN_IP_NODE_STATE_RECV_SYNC:
        case LPUART_LIN_IP_NODE_STATE_RECV_PID:
        /* Timeout error in sending header */
        case LPUART_LIN_IP_NODE_STATE_SEND_PID:
            /* Check if timeout Counter is 0 */
            if (0U == linCurrentState->timeoutCounter)
            {
                /* Set timeout Counter flag */
                linCurrentState->timeoutCounterFlag = (boolean)TRUE;
                /* Clear Tx busy flag */
                linCurrentState->isTxBusy = (boolean)FALSE;
                /* Set current event to timeout error */
                linCurrentState->currentEventId = LPUART_LIN_IP_TIMEOUT_ERROR;

            #ifdef LPUART_LIN_IP_END_TIMEOUT_NOTIFICATION
                /* Call the notification to stop timer */
                LPUART_LIN_IP_END_TIMEOUT_NOTIFICATION(u32Instance);
            #endif

                /* Callback to handle timeout Counter flag to further processing */
                if (NULL_PTR != pUserConfig->Callback)
                {
                    pUserConfig->Callback(u32Instance, linCurrentState);
                }
            }
            else /* If timeout Counter is not 0, then decrease timeout Counter by one */
            {
                linCurrentState->timeoutCounter--;
            }

            break;

        default:
            /* The node state is not SENDING nor RECEIVING data */
            break;
    }

    if ((boolean)FALSE != linCurrentState->timeoutCounterFlag)
    {
        
    }
#else
    /* Casting to void to avoid compiler warning */
    (void)u32Instance;
#endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_SetTimeoutCounter
 * Description   : This function sets value for timeout counter that is used in
 * Lpuart_Lin_Ip_TimeoutService
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_SetTimeoutCounter_Activity
*/
void Lpuart_Lin_Ip_SetTimeoutCounter(const uint32 u32Instance, const uint32 u32TimeoutValue)
{
#if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
    Lpuart_Lin_Ip_StateStructType *linCurrentState;

    #if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
        /* Assert parameters. */
        LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
    #endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    #if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
        /* Assert parameters. */
        LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
    #endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Clear Timeout Counter Flag */
    linCurrentState->timeoutCounterFlag = (boolean)FALSE;

    /* Set new value for Timeout Counter */
    linCurrentState->timeoutCounter = u32TimeoutValue;
#else
    /* Casting to void to avoid compiler warning */
    (void)u32Instance;
    (void)u32TimeoutValue;
#endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_MasterSendHeader
 * Description   : This function sends frame header out through the LPUART module
 * using a non-blocking method. Non-blocking  means that the function returns
 * immediately. This function sends LIN Break field, sync field then the ID with
 * correct parity. This function checks if the interface is Master, if not, it will
 * return LPUART_LIN_IP_STATUS_ERROR.This function checks if id is in range from 0 to 0x3F, if not
 * it will return LPUART_LIN_IP_STATUS_ERROR. This function also check node's current state is in
 * SLEEP mode then the function will return LPUART_LIN_IP_STATUS_ERROR. And check if isBusBusy is
 * currently TRUE then the function will return LPUART_LIN_IP_STATUS_BUSY.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_MasterSendHeader_Activity
*/
Lpuart_Lin_Ip_StatusType Lpuart_Lin_Ip_MasterSendHeader(const uint32 u32Instance, const uint8 u8Id)
{
    Lpuart_Lin_Ip_StatusType retVal = LPUART_LIN_IP_STATUS_SUCCESS;
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
    boolean checkSleepMode;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN user config structure of this LPUART instance. */
    pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    /* Check whether current mode is sleep mode */
    checkSleepMode = (LPUART_LIN_IP_NODE_STATE_SLEEP_MODE == linCurrentState->currentNodeState);

    /* Check if the current node is slave or id is invalid or node's current
     * state is in SLEEP state */
    if (((boolean)LPUART_LIN_IP_MASTER != pUserConfig->nodeFunction) || (0x3FU < u8Id) || checkSleepMode)
    {
        retVal = LPUART_LIN_IP_STATUS_ERROR;
    }
    else
    {
        /* Check if the LIN bus is busy */
        if (linCurrentState->isBusBusy)
        {
            retVal = LPUART_LIN_IP_STATUS_BUSY;
        }
        else
        {
            linCurrentState->currentId = u8Id;

            /* Make parity for the current ID */
            linCurrentState->currentPid = Lin_Ip_ProcessParity(u8Id, LIN_MAKE_PARITY);

            /* Set LIN current state to sending Break field */
            linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_SEND_BREAK_FIELD;
            linCurrentState->currentEventId = LPUART_LIN_IP_NO_EVENT;
            linCurrentState->isBusBusy = (boolean)TRUE;

            /* Set Break char detect length as 13 bits minimum */
            Lpuart_Lin_Ip_HwSetBreakCharDetectLength(base, LPUART_LIN_IP_BREAK_CHAR_13_BIT_MINIMUM_U8);
            Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT, (boolean)TRUE);

            /* Send break char by using queue mode */
            Lpuart_Lin_Ip_HwQueueBreakField(base);
        }
    }

    return retVal;
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_GotoIdleState
 * Description   : This function puts current node to Idle state.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_GotoIdleState_Activity
*/
void Lpuart_Lin_Ip_GotoIdleState(const uint32 u32Instance)
{
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(NULL_PTR != linCurrentState);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];
    /* Get user configuration */
    pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];

    linCurrentState->currentEventId = LPUART_LIN_IP_NO_EVENT;

    /* Set Receive data not inverted */
    Lpuart_Lin_Ip_HwSetRxDataPolarity(base, (boolean)FALSE);

    /* Disable RXEDG interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_ACTIVE_EDGE, (boolean)FALSE);

    /* Enable frame error interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_FRAME_ERR_FLAG, (boolean)TRUE);

    /* Disable Rx buffer full interurpt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL, (boolean)FALSE);

    if ((boolean)LPUART_LIN_IP_MASTER != pUserConfig->nodeFunction)
    {
        /* Set Break char detect length as configuration */
        Lpuart_Lin_Ip_HwSetBreakCharDetectLength(base, pUserConfig->u8BreakLengthDetect);
        /* Only in slave mode, break detection interrupt should be enabled to know new frame. Be side that, the interrupt of master is enable when start transmit a new frame */
        /* Enable LIN break detect interrupt */
        Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT, (boolean)TRUE);
    }

    SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_02();
    {
        /* Change node's current state to IDLE */
        linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_IDLE;
        /* Clear Bus busy Flag */
        linCurrentState->isBusBusy = (boolean)FALSE;
        linCurrentState->isTxBusy = (boolean)FALSE;
        linCurrentState->isRxBusy = (boolean)FALSE;
    #if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
        /* Clear timeout flag */
        linCurrentState->timeoutCounterFlag = (boolean)FALSE;
    #endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */
    }
    SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_02();
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_IRQHandler
 * Description   : Interrupt handler for LPUART.
 * This handler uses the buffers stored in the Lpuart_Lin_Ip_StateStructType struct to transfer
 * data. This is not a public API as it is called by IRQ whenever an interrupt
 * occurs.
 *
 *END**************************************************************************/
/**
* @implements Lpuart_Lin_Ip_IRQHandler_Activity
*/
void Lpuart_Lin_Ip_IRQHandler(const uint32 u32Instance)
{
    const Lpuart_Lin_Ip_UserConfigType *pUserConfig;
    LPUART_Type *base;
    Lpuart_Lin_Ip_StateStructType *linCurrentState;
    boolean activeEdgeIntState;
    boolean bSpuriousIntAvailable = (boolean)FALSE;

#if (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON)
    /* Assert parameters. */
    LPUART_LIN_IP_DEV_ASSERT(LPUART_INSTANCE_COUNT > u32Instance);
#endif /* (LPUART_LIN_IP_DEV_ERROR_DETECT == STD_ON) */

    pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
    /* Get base address of the LPUART instance. */
    base = Lpuart_Lin_Ip_apxBases[u32Instance];
    /* Get the current LIN state of this LPUART instance. */
    linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    /* Check RX Input Active Edge interrupt enable */
    activeEdgeIntState = Lpuart_Lin_Ip_HwGetIntMode(base, LPUART_LIN_IP_INT_RX_ACTIVE_EDGE);

    /* Check instance was initialized or not */
    if (NULL_PTR == linCurrentState)
    {
        /* Clear all interrupt flag */
        (void)Lpuart_Lin_Ip_HwClearStatusFlag(base, LPUART_LIN_IP_ALL_INT_FLAGS);
    }
    else
    {
        /* If LIN break character has been detected. */
        if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_BREAK_DETECT) && Lpuart_Lin_Ip_HwGetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT))
        {
            Lpuart_Lin_Ip_ProcessBreakDetect(u32Instance);
        }
        else
        {
            /* If LPUART_RX Pin Active Edge has been detected. */
            if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_RX_ACTIVE_EDGE_DETECT) && activeEdgeIntState)
            {
                Lpuart_Lin_Ip_ProcessWakeupDetect(u32Instance);
            }
            else
            {
                /* If Framing Error has been detected */
                if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_FRAME_ERR) && Lpuart_Lin_Ip_HwGetIntMode(base, LPUART_LIN_IP_INT_FRAME_ERR_FLAG))
                {
                    Lpuart_Lin_Ip_FrameErrorIrqHandler(u32Instance);

                    /* Change node's state to IDLE */
                    Lpuart_Lin_Ip_GotoIdleState(u32Instance);
                }
                else
                {
                    bSpuriousIntAvailable = (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_RX_DATA_REG_FULL) && Lpuart_Lin_Ip_HwGetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL));
                    /* Check full received register flag and handler */
                    Lpuart_Lin_Ip_FrameIrqHandler(u32Instance);
                } /* End else: if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_FRAME_ERR) == 0) */
            } /* End else: if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_RX_ACTIVE_EDGE_DETECT) == 0) */
        } /* End else: if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_BREAK_DETECT) == 0) */

        /* Get status RX overrun flag */
        if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_RX_OVERRUN) && Lpuart_Lin_Ip_HwGetIntMode(base, LPUART_LIN_IP_INT_RX_OVERRUN))
        {
            /* Clear overrun flag */
            (void)Lpuart_Lin_Ip_HwClearStatusFlag(base, LPUART_LIN_IP_RX_OVERRUN);

            /* Set current event id to LIN_RX_OVERRUN */
            linCurrentState->currentEventId = LPUART_LIN_IP_RX_OVERRUN_ERROR;

            /* Callback function to handle RX Overrun Event */
            if (NULL_PTR != pUserConfig->Callback)
            {
                pUserConfig->Callback(u32Instance, linCurrentState);
            }
        }
        else
        {
            if ((boolean)FALSE != bSpuriousIntAvailable)
            {
                /* Clear all interrupt flag */
                (void)Lpuart_Lin_Ip_HwClearStatusFlag(base, LPUART_LIN_IP_ALL_INT_FLAGS);
            }
        }
    }
} /* End void Lpuart_Lin_Ip_IRQHandler(uint32 u32Instance) */

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_ProcessBreakDetect
 * Description   : This function process break detect for LIN communication.
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_ProcessBreakDetect(const uint32 u32Instance)
{
    /* Get the current LIN user configure structure of this LPUART instance. */
    const Lpuart_Lin_Ip_UserConfigType * pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
    uint8 discardData;

    /* Get base address of the LPUART instance. */
    LPUART_Type * base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Get the current LIN state of this LPUART instance. */
    Lpuart_Lin_Ip_StateStructType * linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    /* Clear LIN Break Detect Interrupt Flag */
    (void)Lpuart_Lin_Ip_HwClearStatusFlag(base, LPUART_LIN_IP_BREAK_DETECT);

    /* Set Break char detect length as 10 bits minimum */
    Lpuart_Lin_Ip_HwSetBreakCharDetectLength(base, LPUART_LIN_IP_BREAK_CHAR_10_BIT_MINIMUM_U8);
    /* Disable LIN Break Detect Interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_BREAK_DETECT, (boolean)FALSE);
    /* Clear Rx complete interrupt flag */
    Lpuart_Lin_Ip_HwGetchar(base, &discardData);
    (void)discardData;
    /* Enable RX complete interrupt */
    Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL, (boolean)TRUE);

    /* Check if the current node is MASTER */
    if ((boolean)LPUART_LIN_IP_SLAVE != pUserConfig->nodeFunction)
    {
        /* Check if LIN current node state is LPUART_LIN_IP_NODE_STATE_SEND_BREAK_FIELD */
        if (LPUART_LIN_IP_NODE_STATE_SEND_BREAK_FIELD == linCurrentState->currentNodeState)
        {
            #if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
                /* 
                 * The TimeoutService function is call each 500 microsecond regularly,
                 * so timeout counter equal to header timeout div 500.
                 * At the end, plus 1 for surplus.
                 */
                Lpuart_Lin_Ip_SetTimeoutCounter(u32Instance, pUserConfig->u32HeaderTimeoutValue / 500UL + 1UL);

                #ifdef LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION
                /* Call notification to start timer */
                LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION(u32Instance);
                #endif
            #endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */

            /* Change the node's current state to SENDING PID to send PID after send SYNC */
            linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_SEND_PID;
            /* Send Sync Field 0x55 */
            Lpuart_Lin_Ip_HwPutchar(base, 0x55);
        }
    }
    /* If the current node is SLAVE */
    else
    {
        /* Set flag LIN bus busy */
        linCurrentState->isBusBusy = (boolean)TRUE;
        /* Change the node's current state to RECEIVED BREAK FIELD */
        linCurrentState->currentEventId = LPUART_LIN_IP_RECV_BREAK_FIELD_OK;
        /* Change the node's current state to RECEIVING SYNC FIELD */
        linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_RECV_SYNC;

        /* If auto baudrate detection is enabled, the driver will count falling edge in sync byte */
        if ((boolean)FALSE != linCurrentState->baudrateEvalEnable)
        {
            Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_ACTIVE_EDGE, (boolean)TRUE);
            linCurrentState->fallingEdgeInterruptCount = 0u;
            /* Enable the LPUART transmitter and receiver */
            Lpuart_Lin_Ip_HwSetTransmitterCmd(base, (boolean)TRUE);
            Lpuart_Lin_Ip_HwSetReceiverCmd(base, (boolean)TRUE);
        }

    #if (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF)
        /* 
         * The TimeoutService function is call each 500 microsecond regularly,
         * so timeout counter equal to header timeout div 500.
         * At the end, plus 1 for surplus.
         */
        Lpuart_Lin_Ip_SetTimeoutCounter(u32Instance, pUserConfig->u32HeaderTimeoutValue / 500UL + 1UL);

        #ifdef LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION
        /* Call notification to start timer */
        LPUART_LIN_IP_START_TIMEOUT_NOTIFICATION(u32Instance);
        #endif
    #endif /* (LPUART_LIN_IP_FRAME_TIMEOUT_DISABLE == STD_OFF) */
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_CheckWakeupSignal
 * Description   : This function check if a dominant signal received is a wakeup
 *                signal.
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_CheckWakeupSignal(const uint32 u32Instance)
{
    uint32 wakeupSignalLength = 0U;

    /* Get the current LIN user config structure of this LPUART instance. */
    const Lpuart_Lin_Ip_UserConfigType * pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];

    /* Get base address of the LPUART instance. */
    LPUART_Type * base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Get the current LIN state of this LPUART instance. */
    Lpuart_Lin_Ip_StateStructType * linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    /* if Lpuart_Lin_Ip_HwGetRxDataPolarity is 0: Receive Data is not inverted */
    if ((boolean)TRUE != Lpuart_Lin_Ip_HwGetRxDataPolarity(base))
    {
        /* Start measure time */
        (void)pUserConfig->timerGetTimeIntervalCallback(u32Instance, &wakeupSignalLength);

        /* Set Receive Data Inverted */
        Lpuart_Lin_Ip_HwSetRxDataPolarity(base, (boolean)TRUE);
    }
    else
    {
        /* Set Receive Data is Not Inverted */
        Lpuart_Lin_Ip_HwSetRxDataPolarity(base, (boolean)FALSE);

        /* Calculate time interval between the falling and rising edge */
        (void)pUserConfig->timerGetTimeIntervalCallback(u32Instance, &wakeupSignalLength);

        /* If length of the dominant signal is longer than 150us, it is a wakeup signal */
        if (wakeupSignalLength >= 150000U)
        {
            linCurrentState->currentEventId = LPUART_LIN_IP_WAKEUP_SIGNAL;

            /* Callback to handle event: Received a wakeup signal */
            if (NULL_PTR != pUserConfig->Callback)
            {
                pUserConfig->Callback(u32Instance, linCurrentState);
            }

            /* Change node's state to IDLE */
            Lpuart_Lin_Ip_GotoIdleState(u32Instance);
        }
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_ProcessFrame
 * Description   : Part of Interrupt handler for receiving and sending data.
 * Receive Header, Data and Send Data.
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_FrameIrqHandler(const uint32 u32Instance)
{
    uint8 tmpByte;
    const LPUART_Type *base = Lpuart_Lin_Ip_apxBases[u32Instance];
    /* Get the current LIN state of this LPUART instance. */
    const Lpuart_Lin_Ip_StateStructType * linCurrentState = (const Lpuart_Lin_Ip_StateStructType *)Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    if (Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_RX_DATA_REG_FULL) && Lpuart_Lin_Ip_HwGetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL))
    {
        /* Check node's current state */
        switch (linCurrentState->currentNodeState)
        {
            /* if current state is RECEIVE SYNC FIELD */
            case LPUART_LIN_IP_NODE_STATE_RECV_SYNC:

            /* if current state is MASTER SENDING PID */
            case LPUART_LIN_IP_NODE_STATE_SEND_PID:

            /* if current state is RECEIVE PID */
            case LPUART_LIN_IP_NODE_STATE_RECV_PID:
                /* Get data from Data Register & Clear LPUART_LIN_IP_RX_DATA_REG_FULL flag */
                Lpuart_Lin_Ip_HwGetchar(base, &tmpByte);
                Lpuart_Lin_Ip_ProcessFrameHeader(u32Instance, tmpByte);
                break;
            /* if current state is RECEIVE DATA */
            case LPUART_LIN_IP_NODE_STATE_RECV_DATA:
                Lpuart_Lin_Ip_ProcessReceiveFrameData(u32Instance);
                break;
            /* if current state is SENDING DATA */
            case LPUART_LIN_IP_NODE_STATE_SEND_DATA:
                /* Get data from Data Register & Clear LPUART_LIN_IP_RX_DATA_REG_FULL flag */
                Lpuart_Lin_Ip_HwGetchar(base, &tmpByte);
                Lpuart_Lin_Ip_ProcessSendFrameData(u32Instance, tmpByte);
                break;

            default:
                /* Other node state */
                /* Get data from Data Register to Clear LPUART_LIN_IP_RX_DATA_REG_FULL flag */
                Lpuart_Lin_Ip_HwGetchar(base, &tmpByte);
                break;
        }
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_ProcessFrameHeader
 * Description   : Part of Interrupt handler for receiving and sending data.
 * Receive Sync byte, PID and Send PID.
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_ProcessFrameHeader(const uint32 u32Instance, const uint8 tmpByte)
{
    /* Get base address of the LPUART instance. */
    LPUART_Type * base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Get the current LIN user config structure of this LPUART instance. */
    const Lpuart_Lin_Ip_UserConfigType * pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];

    /* Get the current LIN state of this LPUART instance. */
    Lpuart_Lin_Ip_StateStructType * linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    /* Check node's current state */
    switch (linCurrentState->currentNodeState)
    {
        /* If current state is RECEIVE SYNC FIELD */
        case LPUART_LIN_IP_NODE_STATE_RECV_SYNC:
            if (0x55U == tmpByte)
            {
                /* Set current event ID to Sync byte is correct */
                linCurrentState->currentEventId = LPUART_LIN_IP_SYNC_OK;
                /* Change node's current state to RECEIVE PID */
                linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_RECV_PID;
            }
            else
            {
                /* Set current event ID to Sync byte is incorrect */
                linCurrentState->currentEventId = LPUART_LIN_IP_SYNC_ERROR;
                /* Callback function to handle event RECEIVED SYNC FIELD ERROR */
                if (NULL_PTR != pUserConfig->Callback)
                {
                    pUserConfig->Callback(u32Instance, linCurrentState);
                }

                /* Change node's current state to IDLE */
                Lpuart_Lin_Ip_GotoIdleState(u32Instance);
            }

            break;
        /* If current state is MASTER SENDING PID */
        case LPUART_LIN_IP_NODE_STATE_SEND_PID:
            /* Check if master node sent SYNC byte correctly before send PID */
            if (0x55U == tmpByte)
            {
                /* Change node's current state to RECEIVING PID */
                linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_RECV_PID;
                /* Send the current PID byte */
                Lpuart_Lin_Ip_HwPutchar(base, linCurrentState->currentPid);
            }
            /* In case of errors during header transmission, it is up to the implementer
             * how to handle these errors (stop/continue transmission) and to decide if the
             * corresponding response is valid or not.
             * By default, LIN Driver set isBusBusy to (boolean)FALSE, and change node's state to IDLE.
             */
            else
            {
                /* Set current event ID to read-back error */
                linCurrentState->currentEventId = LPUART_LIN_IP_READBACK_ERROR;
                /* Clear Bus bus flag */
                linCurrentState->isBusBusy = (boolean)FALSE;

                /* Callback function to handle event SENT SYNC BYTE ERROR */
                if (NULL_PTR != pUserConfig->Callback)
                {
                    pUserConfig->Callback(u32Instance, linCurrentState);
                }
            }

            break;
        /* If current state is RECEIVE PID */
        case LPUART_LIN_IP_NODE_STATE_RECV_PID:
            /* If the node is MASTER */
            if ((boolean)LPUART_LIN_IP_SLAVE != pUserConfig->nodeFunction)
            {
                /* Check if master node sent PID correctly */
                if (tmpByte == linCurrentState->currentPid)
                {
                    /* Set current event ID to PID correct */
                    linCurrentState->currentEventId = LPUART_LIN_IP_PID_OK;

                    /* Clear Bus bus flag */
                    linCurrentState->isBusBusy = (boolean)FALSE;

                    /* Callback function to handle correct PID */
                    if (NULL_PTR != pUserConfig->Callback)
                    {
                        pUserConfig->Callback(u32Instance, linCurrentState);
                    }
                    
                }
                /* In case of errors during header transmission, it is up to the implementer
                 * how to handle these errors (stop/continue transmission) and to decide if the
                 * corresponding response is valid or not.
                 * By default, LIN Driver set isBusBusy to (boolean)FALSE, and change node's state to IDLE.
                 */
                else
                {
                    /* Set current event ID to read-back incorrect */
                    linCurrentState->currentEventId = LPUART_LIN_IP_READBACK_ERROR;
                    /* Clear bus busy flag */
                    linCurrentState->isBusBusy = (boolean)FALSE;

                    /* Callback function to handle event MASTER SENT PID ERROR */
                    if (NULL_PTR != pUserConfig->Callback)
                    {
                        pUserConfig->Callback(u32Instance, linCurrentState);
                    }
                }
            }
            /* If the node is SLAVE */
            else
            {
                /* Check the received PID */
                linCurrentState->currentId = Lin_Ip_ProcessParity(tmpByte, LIN_CHECK_PARITY);
                linCurrentState->currentPid = tmpByte;

                if (0xFFU != linCurrentState->currentId)
                {
                    /* Set current event ID to PID correct */
                    linCurrentState->currentEventId = LPUART_LIN_IP_PID_OK;

                    /* Clear Bus bus flag */
                    linCurrentState->isBusBusy = (boolean)FALSE;

                    /* Callback function to handle event PID correct */
                    if (NULL_PTR != pUserConfig->Callback)
                    {
                        pUserConfig->Callback(u32Instance, linCurrentState);
                    }
                
                }
                else
                {
                    /* Set current event ID to PID ERROR */
                    linCurrentState->currentEventId = LPUART_LIN_IP_PID_ERROR;

                    /* Callback function to handle event PID incorrect */
                    if (NULL_PTR != pUserConfig->Callback)
                    {
                        pUserConfig->Callback(u32Instance, linCurrentState);
                    }

                    /* Change node's current state to IDLE */
                    Lpuart_Lin_Ip_GotoIdleState(u32Instance);
                }
            }

            break;
        default:
            /* Other node state */
            break;
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_ProcessReceiveFrameData
 * Description   : Part of Interrupt handler for receiving.
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_ProcessReceiveFrameData(const uint32 u32Instance)
{
    /* Get the current LIN state of this LPUART instance. */
    Lpuart_Lin_Ip_StateStructType * linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];
    Lpuart_Lin_Ip_StatusType retVal;

    /* Get the current LIN user config structure of this LPUART instance. */
    const Lpuart_Lin_Ip_UserConfigType * pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];

    /* RxSize plused checksum byte to it, so must to decrease 1 in if condition */
    retVal = Lpuart_Lin_Ip_GetBytetoBuffer(linCurrentState->cntByte, \
                                           linCurrentState->rxSize - 1U, \
                                           linCurrentState->rxBuff, \
                                           u32Instance \
                                          );
    /* Increase index to receive next byte */
    if(linCurrentState->cntByte < linCurrentState->rxSize)
    {
       linCurrentState->cntByte++; 
    }
    
    if (LPUART_LIN_IP_STATUS_SUCCESS == retVal)
    {
        if (linCurrentState->rxSize == linCurrentState->cntByte)
        {
            /* Received checksum byte is correct */
            /* callback function to handle RX COMPLETED */
            if (NULL_PTR != pUserConfig->Callback)
            {
                pUserConfig->Callback(u32Instance, linCurrentState);
            }
        }
        else
        {
            /* Nothing to do */
        }
    }
    /* Checksum error occurred */
    else
    {
        /* callback function to handle checksum error */
        if (NULL_PTR != pUserConfig->Callback)
        {
            pUserConfig->Callback(u32Instance, linCurrentState);
        }

        /* Clear Rx busy flag */
        linCurrentState->isRxBusy = (boolean)FALSE;

        /* Change node's current state to IDLE */
        Lpuart_Lin_Ip_GotoIdleState(u32Instance);
    }
}

/*FUNCTION**********************************************************************
 *
 * Function Name : Lpuart_Lin_Ip_ProcessSendFrameData
 * Description   : Part of Interrupt handler for sending data.
 *
 *END**************************************************************************/
static void Lpuart_Lin_Ip_ProcessSendFrameData(const uint32 u32Instance, const uint8 tmpByte)
{
    boolean sendFlag = (boolean)TRUE;
    uint8 tmpSize;
    boolean tmpCheckSumAndSize;
    boolean tmpBuffAndSize;

    /* Get base address of the LPUART instance. */
    LPUART_Type * base = Lpuart_Lin_Ip_apxBases[u32Instance];

    /* Get the current LIN user config structure of this LPUART instance. */
    const Lpuart_Lin_Ip_UserConfigType * pUserConfig = Lpuart_Lin_Ip_apxUserConfigs[u32Instance];
    
    /* Get the current LIN state of this LPUART instance. */
    Lpuart_Lin_Ip_StateStructType * linCurrentState = Lpuart_Lin_Ip_apxStateStructureArray[u32Instance];

    /* Check if Tx data register empty flag is (boolean)FALSE */
    if ((boolean)TRUE != Lpuart_Lin_Ip_HwGetStatusFlag(base, LPUART_LIN_IP_TX_DATA_REG_EMPTY))
    {
        linCurrentState->currentEventId = LPUART_LIN_IP_READBACK_ERROR;
        /* callback function to handle Readback error */
        if (NULL_PTR != pUserConfig->Callback)
        {
            pUserConfig->Callback(u32Instance, linCurrentState);
        }

    
        /* Clear Tx busy flag */
        linCurrentState->isTxBusy = (boolean)FALSE;

        /* Change node's current state to IDLE */
        Lpuart_Lin_Ip_GotoIdleState(u32Instance);
    

        sendFlag = (boolean)FALSE;
    }
    else
    {
        tmpSize = (uint8)(linCurrentState->txSize - linCurrentState->cntByte);
        tmpCheckSumAndSize = (1U  == tmpSize) && (linCurrentState->checkSum != tmpByte);
        tmpBuffAndSize = (tmpByte != *linCurrentState->txBuff) && (1U != tmpSize);

        if (tmpBuffAndSize || tmpCheckSumAndSize)
        {
            linCurrentState->currentEventId = LPUART_LIN_IP_READBACK_ERROR;

            /* callback function to handle Readback error */
            if (NULL_PTR != pUserConfig->Callback)
            {
                pUserConfig->Callback(u32Instance, linCurrentState);
            }

         
            /* Clear Tx busy flag */
            linCurrentState->isTxBusy = (boolean)FALSE;

            /* Change node's current state to IDLE */
            Lpuart_Lin_Ip_GotoIdleState(u32Instance);
            

            sendFlag = (boolean)FALSE;
        }
        else
        {
            linCurrentState->txBuff++;
            linCurrentState->cntByte++;
        }
    }

    if (sendFlag)
    {
        if (linCurrentState->cntByte < linCurrentState->txSize)
        {
            /* Send checksum byte */
            if (1U == (linCurrentState->txSize - linCurrentState->cntByte))
            {
                Lpuart_Lin_Ip_HwPutchar(base, linCurrentState->checkSum);
            }
            /* Send data bytes */
            else
            {
                Lpuart_Lin_Ip_HwPutchar(base, *linCurrentState->txBuff);
            }
        }
        else
        {
            linCurrentState->currentEventId = LPUART_LIN_IP_TX_COMPLETED;
            linCurrentState->currentNodeState = LPUART_LIN_IP_NODE_STATE_SEND_DATA_COMPLETED;

            Lpuart_Lin_Ip_HwSetIntMode(base, LPUART_LIN_IP_INT_RX_DATA_REG_FULL, (boolean)FALSE);
            /* callback function to handle event TX COMPLETED */
            if (NULL_PTR != pUserConfig->Callback)
            {
                pUserConfig->Callback(u32Instance, linCurrentState);
            }

            /* Clear Tx busy flag */
            linCurrentState->isTxBusy = (boolean)FALSE;

            /* In this case, node is in SLEEP MODE state */
            if (linCurrentState->currentNodeState != LPUART_LIN_IP_NODE_STATE_SLEEP_MODE)
            {
                /* Change node's current state to IDLE */
                Lpuart_Lin_Ip_GotoIdleState(u32Instance);
            }
            
        }
    }
}

#define LIN_STOP_SEC_CODE
#include "Lin_MemMap.h"

#ifdef __cplusplus
}
#endif

/** @} */
