/**
 * @file    Lin_Lld_Uart.c
 * @version V2.3.0
 *
 * @brief   AUTOSAR Lin Driver Interface
 * @details API implementation for LIN driver
 *
 * @addtogroup LIN_DRIVER
 * @{
 */
/*==================================================================================================
 *   Project              : YTMicro AUTOSAR 4.4.0 MCAL
 *   Platform             : ARM
 *   Peripheral           : Lin
 *   Dependencies         : none
 *
 *   Autosar Version      : V4.4.0
 *   Autosar Revision     : ASR_REL_4_4_REV_0000
 *   Autosar Conf.Variant :
 *   SW Version           : V2.3.0
 *
 *
 *   (c) Copyright 2020-2025 Yuntu Microelectronics co.,ltd.
 *   All Rights Reserved.
==================================================================================================*/
/*==================================================================================================
==================================================================================================*/

#include "ComStack_Types.h"
#include "Lin.h"
#ifdef __cplusplus
extern "C" {
#endif

/*==================================================================================================
 *                                        INCLUDE FILES
==================================================================================================*/
#include "pSIP_Uart.h"
#include "Lin_Lld_Uart.h"
#include "SchM_Lin.h"
#include "Lin_Cfg.h"
#include "EcuM.h"
#include "LinIf.h"
#include "OsIf.h"

/*==================================================================================================
 *                              SOURCE FILE VERSION INFORMATION
==================================================================================================*/
#define LIN_LLD_UART_VENDOR_ID_C                      (180)
#define LIN_LLD_UART_AR_RELEASE_MAJOR_VERSION_C       (4)
#define LIN_LLD_UART_AR_RELEASE_MINOR_VERSION_C       (4)
#define LIN_LLD_UART_AR_RELEASE_REVISION_VERSION_C    (0)
#define LIN_LLD_UART_SW_MAJOR_VERSION_C               (2)
#define LIN_LLD_UART_SW_MINOR_VERSION_C               (3)
#define LIN_LLD_UART_SW_PATCH_VERSION_C               (0)

/*==================================================================================================
 *                                     FILE VERSION CHECKS
==================================================================================================*/
/* Check if source file and LIN header file are of the same vendor */
#if (LIN_LLD_UART_VENDOR_ID_C != LIN_LLD_UART_VENDOR_ID)
#error "Lin_Lld_Uart.c have different vendor ids"
#endif

/* Check if source file and LIN header file are of the same Autosar version */
#if ((LIN_LLD_UART_AR_RELEASE_MAJOR_VERSION_C != LIN_LLD_UART_AR_RELEASE_MAJOR_VERSION) || \
     (LIN_LLD_UART_AR_RELEASE_MINOR_VERSION_C != LIN_LLD_UART_AR_RELEASE_MINOR_VERSION) || \
     (LIN_LLD_UART_AR_RELEASE_REVISION_VERSION_C != LIN_LLD_UART_AR_RELEASE_REVISION_VERSION) \
    )
#error "AutoSar Version Numbers of Lin_Lld_Uart.c are different"
#endif

/* Check if source file and LIN header file are of the same Software version */
#if ((LIN_LLD_UART_SW_MAJOR_VERSION_C != LIN_LLD_UART_SW_MAJOR_VERSION) || \
     (LIN_LLD_UART_SW_MINOR_VERSION_C != LIN_LLD_UART_SW_MINOR_VERSION) || \
     (LIN_LLD_UART_SW_PATCH_VERSION_C != LIN_LLD_UART_SW_PATCH_VERSION) \
    )
#error "Software Version Numbers of Lin_Lld_Uart.c are different"
#endif

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

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

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

/*==================================================================================================
 *                                      GLOBAL VARIABLES
==================================================================================================*/

/*==================================================================================================
 *                                       LOCAL CONSTANTS
==================================================================================================*/
#define LIN_START_SEC_CONST_8
#include "Lin_MemMap.h"

LIN_CONST static const uint8 LinPidTable[64] =
{
    0x80U, 0xC1U, 0x42U, 0x03U, 0xC4U, 0x85U, 0x06U, 0x47U,
    0x08U, 0x49U, 0xCAU, 0x8BU, 0x4CU, 0x0DU, 0x8EU, 0xCFU,
    0x50U, 0x11U, 0x92U, 0xD3U, 0x14U, 0x55U, 0xD6U, 0x97U,
    0xD8U, 0x99U, 0x1AU, 0x5BU, 0x9CU, 0xDDU, 0x5EU, 0x1FU,
    0x20U, 0x61U, 0xE2U, 0xA3U, 0x64U, 0x25U, 0xA6U, 0xE7U,
    0xA8U, 0xE9U, 0x6AU, 0x2BU, 0xECU, 0xADU, 0x2EU, 0x6FU,
    0xF0U, 0xB1U, 0x32U, 0x73U, 0xB4U, 0xF5U, 0x76U, 0x37U,
    0x78U, 0x39U, 0xBAU, 0xFBU, 0x3CU, 0x7DU, 0xFEU, 0xBFU
};

#define LIN_STOP_SEC_CONST_8
#include "Lin_MemMap.h"

/*==================================================================================================
 *                                       LOCAL VARIABLES
==================================================================================================*/
#if defined(UNIT_TEST)
#define LIN_START_SEC_VAR_INIT_UNSPECIFIED
#include "Lin_MemMap.h"
LIN_VAR static volatile UART_Type *Lin_LocBasePtrs[LIN_CHANNEL_MAX_NUM] = UART_BASE_PTRS;
#define LIN_STOP_SEC_VAR_INIT_UNSPECIFIED
#include "Lin_MemMap.h"/*memory map finish*/
#else
#define LIN_START_SEC_CONST_UNSPECIFIED
#include "Lin_MemMap.h"
/* MAX NUM is necessary because of 6 hardware instances */
LIN_CONST static volatile UART_Type *const Lin_LocBasePtrs[LIN_CHANNEL_MAX_NUM] = UART_BASE_PTRS;

#define LIN_STOP_SEC_CONST_UNSPECIFIED
#include "Lin_MemMap.h"/*memory map finish*/
#endif

#define LIN_START_SEC_VAR_CLEARED_UNSPECIFIED
#include "Lin_MemMap.h"
/**
 * @brief          LIN global channels configuration pointer
 */
LIN_VAR static const Lin_ChConfigType *Lin_GlobalChConfigPtrs[LIN_CHANNEL_USED_NUM];

LIN_VAR static const uint8 *Lin_LocUartInstMapPtr;

LIN_VAR static Lin_PduType Lin_LocCurrentPdu[LIN_CHANNEL_USED_NUM];

#define LIN_STOP_SEC_VAR_CLEARED_UNSPECIFIED
#include "Lin_MemMap.h"/*memory map finish*/

#define LIN_START_SEC_VAR_CLEARED_8
#include "Lin_MemMap.h"

LIN_VAR static uint8 Lin_DrvUartFrameSdu[LIN_CHANNEL_USED_NUM][8];

LIN_VAR static Lin_Drv_HwStatusType Lin_LocUartHwStatus[LIN_CHANNEL_USED_NUM];

LIN_VAR static boolean Lin_LocUartLatchRxEmptyStatus[LIN_CHANNEL_USED_NUM];

LIN_VAR static boolean Lin_LocUartWakeupReq[LIN_CHANNEL_USED_NUM];
/**
 * @brief          LIN driver header commands array.
 */
LIN_VAR static Lin_DrvCommandType Lin_LocTxHeaderCommands[LIN_CHANNEL_USED_NUM];

/**
 * @brief          LIN driver frame error states array for all channels.
 */
LIN_VAR static Lin_DrvErrorType Lin_LocChFrameErrorStates[LIN_CHANNEL_USED_NUM];

/**
 * @brief          LIN driver frame states array for all channels.
 */
LIN_VAR static Lin_DrvStateType Lin_LocChFrameStates[LIN_CHANNEL_USED_NUM];

/**
 * @brief           LIN driver channel node mode array for all channels.
 */
LIN_VAR static Lin_LinNodeModeType Lin_LocNodeMode[LIN_CHANNEL_USED_NUM];

LIN_VAR static uint8 Lin_LocUartWakeupByte[LIN_CHANNEL_USED_NUM];

LIN_VAR static Lin_DrvTimeoutType Lin_LocUartTimeoutType[LIN_CHANNEL_USED_NUM];

LIN_VAR static boolean Lin_LocUartTickEnable[LIN_CHANNEL_USED_NUM];

LIN_VAR static uint16 Lin_LocUartBitTimeOfMicrosec[LIN_CHANNEL_USED_NUM];

LIN_VAR static uint16 Lin_LocUartTickCounter[LIN_CHANNEL_USED_NUM];

LIN_VAR static uint16 Lin_LocUartTickSetValue[LIN_CHANNEL_USED_NUM];

LIN_VAR static uint8 Lin_DrvUartDataCount[LIN_CHANNEL_USED_NUM];

LIN_VAR static uint8 Lin_DrvUartFrameChecksum[LIN_CHANNEL_USED_NUM];

LIN_VAR static uint8 Lin_DrvUartSentData[LIN_CHANNEL_USED_NUM];

extern LIN_VAR Lin_DrvStateType Lin_ChStates[LIN_CHANNEL_USED_NUM];

#define LIN_STOP_SEC_VAR_CLEARED_8
#include "Lin_MemMap.h"/*memory map finish*/

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

LIN_FUNC static Std_ReturnType Lin_Lld_Uart_LocTransmittionAbort(volatile UART_Type *Base);

LIN_FUNC void Lin_Lld_Uart_LocIntHandler(const uint8 HwChannel);
#ifdef UART_IP_0_LIN_OCCUPY
#ifdef UART0_BASE_ADDR32
LIN_FUNC ISR(UART0_IRQHandler);
#endif
#endif
#ifdef UART_IP_1_LIN_OCCUPY
#ifdef UART1_BASE_ADDR32
LIN_FUNC ISR(UART1_IRQHandler);
#endif
#endif
#ifdef UART_IP_2_LIN_OCCUPY
#ifdef UART2_BASE_ADDR32
LIN_FUNC ISR(UART2_IRQHandler);
#endif
#endif

/*==================================================================================================
 *                                       LOCAL  FUNCTION
==================================================================================================*/
#if (LIN_FRAME_TIMEOUT_DISABLE == STD_OFF)  /* timeout update*/
LIN_FUNC static void Lin_Lld_Uart_LocEnableLbkDtc(volatile UART_Type *Base)
{
    SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_00();
    Base->CTRL1 |= UART_CTRL1_LBKDEN_MASK;
    Base->INTE = UART_INTE_LBKDIE_MASK | LIN_CONST_UART_ERROR_INTE_MASK;
    SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_00();
}
#endif

LIN_FUNC static uint8 Lin_Lld_Uart_LocGetChecksumByte(const Lin_PduType *LinPdu)
{
    uint8 Tmp8 = 0U;
    uint16 CheckSum = 0U;
    uint8 Id = (uint8)(LinPdu->Pid & 0x3FU);
    /* For PID is 0x3C (ID 0x3C) or 0x7D (ID 0x3D) or 0xFE (ID 0x3E) or 0xBF (ID 0x3F)
     * apply classic checksum and apply enhanced checksum for other PID */
    /* For 0x3C, 0x7D, 0xFE and 0xBF: Do not add PID in checksum calculation */
    if ((LIN_ENHANCED_CS == LinPdu->Cs) && (LIN_DRV_MASTER_REQUEST_DIAGNOSTIC_ID > Id))
    {
        /* For 0x3C, 0x7D, 0xFE and 0xBF: Do not add PID in checksum calculation */
        CheckSum = LinPdu->Pid;
    }
    for (uint8 Index = 0U; Index < LinPdu->Dl; ++Index)
    {
        CheckSum += LinPdu->SduPtr[Index];
        /* Deal with the carry */
        if (CheckSum > 0xFFU)
        {
            CheckSum -= 0xFFU;
        }
    }
    Tmp8 = (uint8)(CheckSum & 0xFFU);
    Tmp8 = ~Tmp8;
    /* Return reversed checksum */
    return Tmp8;
}

LIN_FUNC static void Lin_Lld_Uart_LocStartToTicks(const uint8 Channel, const Lin_DrvTimeoutType TicksMode)
{
    uint32 Tmp32;
    if (LIN_DRV_TO_BREAK == TicksMode)
    {
        Tmp32 = (LIN_CONST_TIMEOUT_BREAK_CYCLES * (uint32)Lin_LocUartBitTimeOfMicrosec[Channel]) / LIN_CONST_GPT_TICS_500US;
    }
    else if (LIN_DRV_TO_M_RECEIVE == TicksMode)
    {
        Tmp32 = ((uint32)Lin_LocCurrentPdu[Channel].Dl + (uint32)1U) * (uint32)14U; /*NOSONAR, no memory overruns*/
        Tmp32 = Tmp32 * (uint32)Lin_LocUartBitTimeOfMicrosec[Channel] / LIN_CONST_GPT_TICS_500US;
    }
    else if (LIN_DRV_TO_HEADER == TicksMode)
    {
        Tmp32 = (LIN_CONST_TIMEOUT_HEADER_CYCLES * (uint32)Lin_LocUartBitTimeOfMicrosec[Channel]) / LIN_CONST_GPT_TICS_500US;
    }
    else /*LIN_DRV_TO_S_RECEIVE*/
    {
        Tmp32 = ((uint32)Lin_LocCurrentPdu[Channel].Dl + (uint32)1U) * (uint32)14U; /*NOSONAR, no memory overruns*/
        Tmp32 = Tmp32 * (uint32)Lin_LocUartBitTimeOfMicrosec[Channel] / LIN_CONST_GPT_TICS_500US; /*NOSONAR, no memory overruns*/
    }
    Lin_LocUartTickSetValue[Channel] = (uint16)Tmp32 + LIN_CONST_PARA_NUM_2;
    Lin_LocUartTickCounter[Channel] = 0U;
    Lin_LocUartTickEnable[Channel] = TRUE;
}

LIN_FUNC static void Lin_Lld_Uart_LocStopToTicks(const uint8 Channel)
{
    Lin_LocUartTickEnable[Channel] = FALSE;
    Lin_LocUartTickCounter[Channel] = 0U;
}

LIN_FUNC LOCAL_INLINE Std_ReturnType Lin_Lld_Uart_LocTxIdleState(volatile const UART_Type *Base)
{
    Std_ReturnType RetVal = E_OK;
    if (0U == (UART_INTF_TCIF_MASK & Base->INTF))
    {
        RetVal = E_NOT_OK;
    }
    return RetVal;
}

LIN_FUNC static Std_ReturnType Lin_Lld_Uart_LocTransmittionAbort(volatile UART_Type *Base)
{
    Std_ReturnType RetVal = E_NOT_OK;
    /* Base->CTRL0 = 0x00000000U; */
    Base->INTE = 0x00000000U;
    Base->CTRL1 &= ~UART_CTRL1_LBKDEN_MASK;
    uint32 Index = 0U;
    /* wait frame transmission aborted */
    while ((E_NOT_OK == Lin_Lld_Uart_LocTxIdleState(Base)) && (Index < (uint32)LIN_TIMEOUT_DURATION))
    {
        ++Index;
    }
    if (Index < (uint32)LIN_TIMEOUT_DURATION)
    {
        RetVal = E_OK;
    }
    return RetVal;
}

LIN_FUNC LOCAL_INLINE uint8 Lin_Lld_Uart_LocGetWakeupByte(const uint32 Baudrate)
{
    uint32 Tmp32;
    uint8 Tmp8;
    uint8 RetVal;
    Tmp32 = LIN_CONST_PARA_BYTE_US_TIME_DIVIDEND / Baudrate; /*us per byte*/
    Tmp32 = LIN_CONST_PARA_400US_DIVIDEND / Tmp32; /* Low Level bits number for wakeup by Baudrate, 400us to 1000us */
    Tmp8 = (uint8)Tmp32;
    if (0U < Tmp8)
    {
        RetVal = (uint8)LIN_CONST_CONST_WHOLE_OF_BYTE_ALL_TRUE << Tmp8;
    }
    else
    {
        RetVal = (uint8)LIN_CONST_CONST_WHOLE_OF_BYTE_ALL_TRUE;
    }
    return RetVal;
}

LIN_FUNC static void Lin_Lld_Uart_LocGoToSleep(const uint8 Channel)
{
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];
    Lin_Lld_Uart_LocStopToTicks(Channel);
    Base->INTF = Base->INTF;
    /* Release message buffer */
    SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_05();
    /* Enter sleep mode */
    Base->RXFIFO = UART_RXFIFO_RESET_MASK | UART_RXFIFO_EN_MASK;
    Base->CTRL0 = UART_CTRL0_RXEN_MASK;
    Base->INTE = UART_INTE_RXEDGEIE_MASK;
    SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_05();
    /* Clear wakeup detection flag */
    /* Update LIN channel frame operation state */
    Lin_LocChFrameStates[Channel] = LIN_DRV_CH_SLEEP;
    Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_SLEEP_MODE;
    Lin_LocTxHeaderCommands[Channel] = LIN_DRV_TX_NO_CMD;
    Lin_LocUartWakeupReq[Channel] = FALSE;
    Lin_ChStates[Channel] = LIN_DRV_CH_SLEEP;
}

LIN_FUNC void Lin_Lld_Uart_LocWakeup(const uint8 Channel)
{
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];
    Base->TXFIFO = UART_TXFIFO_RESET_MASK;
    Base->INTF = Base->INTF;
    Base->RXFIFO = UART_RXFIFO_RESET_MASK;
    if (LIN_SLAVE_MODE == Lin_LocNodeMode[Channel])
    {
        Lin_Lld_Uart_LocEnableLbkDtc(Base);
    }
    else
    {
        /* Enable RXEN */
        Base->INTE = 0x00000000U;
    }
    /* Uart Timer Command Init as no cmd*/
    Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
}

/*==================================================================================================
 *                                       GLOBAL FUNCTIONS
==================================================================================================*/
#if (LIN_FRAME_TIMEOUT_DISABLE == STD_OFF)  /* timeout update*/
LIN_FUNC void Lin_Lld_Uart_TimerTickCbk(void)
{
    /* Get LINFlexD Base address */
    volatile UART_Type *Base;
    for (uint8 Index = 0U; Index < (uint8)LIN_CHANNEL_USED_NUM; ++Index)
    {
        if (TRUE == Lin_LocUartTickEnable[Index])
        {
            ++Lin_LocUartTickCounter[Index];
            if (Lin_LocUartTickCounter[Index] >= Lin_LocUartTickSetValue[Index])
            {
                /* Get LINFlexD Base address */
                Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Index]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];
                Lin_LocUartTickEnable[Index] = FALSE;
                Lin_LocUartTickCounter[Index] = 0U;
                if (LIN_DRV_TO_BREAK == Lin_LocUartTimeoutType[Index])
                {
                    Lin_LocChFrameErrorStates[Index] = LIN_DRV_BREAK_FIELD_ERROR;
                    Base->INTF = Base->INTF;
                    Base->INTE = LIN_CONST_UART_ERROR_INTE_MASK;
                }
                else if (LIN_DRV_TO_HEADER == Lin_LocUartTimeoutType[Index])
                {
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
                    LinIf_LinErrorIndication(Index, LIN_ERR_HEADER);
#endif
                    Lin_Lld_Uart_LocEnableLbkDtc(Base);
                }
                else if (LIN_DRV_TO_M_RECEIVE == Lin_LocUartTimeoutType[Index])
                {
                    Lin_LocChFrameErrorStates[Index] = LIN_DRV_TIMEOUT_ERROR;
                    if (0U != (Base->RXFIFO & UART_RXFIFO_COUNT_MASK))
                    {
                        Lin_LocUartLatchRxEmptyStatus[Index] = FALSE;
                    }
                    Base->INTF = Base->INTF;
                    Base->INTE = LIN_CONST_UART_ERROR_INTE_MASK;
                }
                else /*LIN_DRV_TO_S_RECEIVE*/
                {
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
                    if (0U == Lin_DrvUartDataCount[Index])
                    {
                        LinIf_LinErrorIndication(Index, LIN_ERR_NO_RESP);
                    }
                    else
                    {
                        LinIf_LinErrorIndication(Index, LIN_ERR_INC_RESP);
                    }
#endif
                    Lin_Lld_Uart_LocEnableLbkDtc(Base);
                }
                Lin_LocUartHwStatus[Index] = LIN_DRV_HW_IDLE_MODE;
                if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Index])
                {
                    Lin_Lld_Uart_LocGoToSleep(0U);
                }
            }
        }
    }
}
#endif

LIN_FUNC void Lin_Lld_Uart_SetInstMap(const uint8 *LinInstMapPtr)
{
    Lin_LocUartInstMapPtr = LinInstMapPtr;
}

LIN_FUNC void Lin_Lld_Uart_InitChannel(const uint8 Channel, const Lin_ConfigType *LinCfgPtr)
{
    uint32 Tmp32;
    uint32 TmpIbr;
    Lin_GlobalChConfigPtrs[Channel] = &(LinCfgPtr->LinChConfigPtrs[Channel]);
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];
    Lin_LocUartLatchRxEmptyStatus[Channel] = TRUE;
    Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_SLEEP_MODE;
    Lin_LocNodeMode[Channel] = Lin_GlobalChConfigPtrs[Channel]->LinNodeMode;
    Lin_LocCurrentPdu[Channel].SduPtr = Lin_DrvUartFrameSdu[Channel];
    /* Baudrate configuration */
    Tmp32 = Lin_GlobalChConfigPtrs[Channel]->LinBaudrateRegValue * (uint32)LIN_CONST_BAUDRATE_OSRVAL_16;
    TmpIbr = (Lin_GlobalChConfigPtrs[Channel]->LinClockRef) / Tmp32;
    if (((Lin_GlobalChConfigPtrs[Channel]->LinClockRef) % Tmp32) > (Tmp32 / LIN_CONST_PARA_NUM_2))
    {
        TmpIbr += LIN_CONST_PARA_NUM_1;
    }
    Base->BAUD = TmpIbr;
    Lin_LocUartWakeupByte[Channel] = Lin_Lld_Uart_LocGetWakeupByte((uint32)Lin_GlobalChConfigPtrs[Channel]->LinBaudrateRegValue);
    Lin_LocUartBitTimeOfMicrosec[Channel] =
        (uint16)(LIN_CONST_PARA_US_OF_SECOND / Lin_GlobalChConfigPtrs[Channel]->LinBaudrateRegValue) + LIN_CONST_PARA_NUM_1;
    /* Write init value */
    Base->CTRL0 = 0x00000000U;
    Base->CTRL1 = 0x00000000U;
    Base->TXFIFO = 0x00000000U;
    Base->RXFIFO = UART_RXFIFO_RESET_MASK;
    Base->MATCH = 0x00000000U;
    Base->INTF = Base->INTF;
    SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_01();
    /* LIN loop back mode */
    Base->CTRL1 = UART_CTRL1_LBKSZ_MASK | UART_CTRL1_FRAMESZ(LIN_CONST_UART_8_BIT_DATA_MODE);
    Base->CTRL0 = UART_CTRL0_RXEN_MASK;
    /*  wakeup function */
    Base->INTE = UART_INTE_RXEDGEIE_MASK;
    /* Reset header command type */
    Lin_LocTxHeaderCommands[Channel] = LIN_DRV_TX_NO_CMD;
    /* Reset error status flag */
    Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
    /* Set LIN channel frame state to default not ready */
    Lin_LocChFrameStates[Channel] = LIN_DRV_CH_SLEEP;
    Lin_LocUartWakeupReq[Channel] = FALSE;
    SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_01();
}

#if (LIN_DEINIT_API_SUPPORT == STD_ON)
LIN_FUNC void Lin_Lld_Uart_DeInitChannel(const uint8 Channel)
{
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];
    Base->INTE = 0x00000000U;
    Base->INTF = Base->INTF;
    Base->CTRL0 = 0x00000000U;
    Base->CTRL1 = 0x00000000U;
    Lin_GlobalChConfigPtrs[Channel] = NULL_PTR;
}
#endif /* LIN_DEINIT_API_SUPPORT == STD_ON */

LIN_FUNC Std_ReturnType Lin_Lld_Uart_SendGoToSleep(const uint8 Channel)
{
    Std_ReturnType RetVal = E_NOT_OK;
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];
    Lin_Lld_Uart_LocStopToTicks(Channel);
    /* Release message buffer */
    Base->RXFIFO = UART_RXFIFO_RESET_MASK;
    Base->INTF = Base->INTF;
    if (E_OK == Lin_Lld_Uart_LocTransmittionAbort(Base))
    {
        Base->CTRL0 = UART_CTRL0_RXEN_MASK | UART_CTRL0_TXEN_MASK;
        Lin_Lld_Uart_LocEnableLbkDtc(Base);
        SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_06();
        Base->DATA = UART_DATA_LINBRK_MASK;
        Lin_Lld_Uart_LocStartToTicks(Channel, LIN_DRV_TO_BREAK);
        Lin_LocUartTimeoutType[Channel] = LIN_DRV_TO_BREAK;
        /* update set lin frame */
        Lin_LocCurrentPdu[Channel].Drc = LIN_FRAMERESPONSE_TX;
        Lin_LocCurrentPdu[Channel].Pid = LinPidTable[LIN_DRV_SLEEP_COMMAND_ID];
        Lin_LocCurrentPdu[Channel].Cs = LIN_CLASSIC_CS;
        Lin_LocCurrentPdu[Channel].Dl = LIN_DRV_SLEEP_COMMAND_DATA_LENGTH;
        Lin_DrvUartFrameSdu[Channel][0] = 0x00U;
        /* Reset error status */
        for (uint8 Index = 1U; Index < LIN_DRV_SLEEP_COMMAND_DATA_LENGTH; ++Index)
        {
            Lin_DrvUartFrameSdu[Channel][Index] = LIN_CONST_CONST_WHOLE_OF_BYTE_ALL_TRUE;/*NOSONAR, no memory overruns*/
        }
        Lin_DrvUartFrameChecksum[Channel] = Lin_Lld_Uart_LocGetChecksumByte(&Lin_LocCurrentPdu[Channel]);
        Lin_LocTxHeaderCommands[Channel] = LIN_DRV_TX_SLEEP_CMD;
        Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
        Lin_LocUartLatchRxEmptyStatus[Channel] = TRUE;
        Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_BREAK;
        Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
        SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_06();
        RetVal = E_OK;
    }
    else
    {
        Lin_Lld_Uart_LocWakeup(Channel);
    }
    return RetVal;
}

LIN_FUNC Std_ReturnType Lin_Lld_Uart_GoToSleepInternal(const uint8 Channel)
{
    Std_ReturnType RetVal = E_NOT_OK;
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];  /*NOSONAR*/
    Lin_Lld_Uart_LocStopToTicks(Channel);
    Base->INTF = Base->INTF;
    if (E_OK == Lin_Lld_Uart_LocTransmittionAbort(Base))
    {
        Lin_Lld_Uart_LocGoToSleep(Channel);
        RetVal = E_OK;
    }
    else
    {
        Lin_Lld_Uart_LocWakeup(Channel);
    }
    return RetVal;
}

LIN_FUNC void Lin_Lld_Uart_Wakeup(const uint8 Channel)
{
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];  /*NOSONAR*/
    Lin_Lld_Uart_LocStopToTicks(Channel);
    Base->INTF = Base->INTF;
    if (E_OK == Lin_Lld_Uart_LocTransmittionAbort(Base))
    {
        /* Send out wakeup request */
        SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_03();
        Base->CTRL0 = UART_CTRL0_RXEN_MASK | UART_CTRL0_TXEN_MASK;
        Base->RXFIFO = UART_RXFIFO_RESET_MASK | UART_RXFIFO_EN_MASK;
        Base->DATA = Lin_LocUartWakeupByte[Channel];
        Lin_DrvUartSentData[Channel] = Lin_LocUartWakeupByte[Channel];
        Base->INTE = UART_INTE_RXIE_MASK | LIN_CONST_UART_ERROR_INTE_MASK;
        Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_WAKEUP_FIELD;
        SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_03();
        uint32 Timeout = 0U;
        while (Timeout <= 0xFFFF)
        {
            Timeout++;
            if (Lin_LocUartHwStatus[Channel] != LIN_DRV_HW_WAKEUP_FIELD)
            {
                Lin_ChStates[Channel] = LIN_DRV_CH_OPERATIONAL;
                break;
            }
        }
    }
    else
    {
        Lin_Lld_Uart_LocWakeup(Channel);
        /* Update LIN channel frame operation status */
        Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
        /* Reset frame error status */
        Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
        Lin_ChStates[Channel] = LIN_DRV_CH_OPERATIONAL;
    }
}

LIN_FUNC void Lin_Lld_Uart_WakeupInternal(const uint8 Channel)
{
    Lin_Lld_Uart_LocWakeup(Channel);
    /* Update LIN channel frame operation status */
    Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
    /* Reset frame error status */
    Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
    Lin_ChStates[Channel] = LIN_DRV_CH_OPERATIONAL;
}

LIN_FUNC boolean Lin_Lld_Uart_CheckWakeup(const uint8 Channel)
{
    boolean RetVal = FALSE;
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];  /*NOSONAR*/
    if (TRUE == Lin_LocUartWakeupReq[Channel]) /*NOSONAR, no memory overruns*/
    {
        if (LIN_MASTER_MODE == Lin_LocNodeMode[Channel])
        {
            Base->INTE = 0x00000000U;
            /* Reset header command type */
            Lin_LocTxHeaderCommands[Channel] = LIN_DRV_TX_NO_CMD;
            /* Reset error status flag */
            Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
            /* Set LIN channel frame state to default not ready */
            Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
            Lin_LocUartLatchRxEmptyStatus[Channel] = TRUE;
        }
        else
        {
            Base->CTRL0 = UART_CTRL0_RXEN_MASK;
            Lin_Lld_Uart_LocEnableLbkDtc(Base);
        }
        Lin_LocUartWakeupReq[Channel] = FALSE;/*NOSONAR, no memory overruns*/
        EcuM_CheckWakeup(Lin_GlobalChConfigPtrs[Channel]->LinChEcuMWakeupSource);
        Lin_ChStates[Channel] = LIN_DRV_CH_OPERATIONAL;
        RetVal = TRUE;
    }
    return RetVal;
}

#if (LIN_MASTER_API_SUPPORT == STD_ON)
LIN_FUNC Std_ReturnType Lin_Lld_Uart_SendHeader(const uint8 Channel, const Lin_PduType *PduInfoPtr)
{
    Std_ReturnType RetVal = E_NOT_OK;
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];  /*NOSONAR*/
    Lin_Lld_Uart_LocStopToTicks(Channel);
    /* Release message buffer */
    Base->RXFIFO = UART_RXFIFO_RESET_MASK;
    /* Clear previous noise flag */
    Base->INTF =  Base->INTF;
    if (E_OK == Lin_Lld_Uart_LocTransmittionAbort(Base))
    {
        Base->CTRL0 = UART_CTRL0_RXEN_MASK | UART_CTRL0_TXEN_MASK;
        Lin_Lld_Uart_LocEnableLbkDtc(Base);
        SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_04();
        Base->DATA = UART_DATA_LINBRK_MASK;
        Lin_Lld_Uart_LocStartToTicks(Channel, LIN_DRV_TO_BREAK);
        Lin_LocUartTimeoutType[Channel] = LIN_DRV_TO_BREAK;
        Lin_LocCurrentPdu[Channel].Pid = PduInfoPtr->Pid;
        Lin_LocCurrentPdu[Channel].Dl = PduInfoPtr->Dl;
        Lin_LocCurrentPdu[Channel].Drc = PduInfoPtr->Drc;
        Lin_LocCurrentPdu[Channel].Cs = PduInfoPtr->Cs;
        /* Reset error status */
        Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
        Lin_LocUartLatchRxEmptyStatus[Channel] = TRUE;
        Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_BREAK;
        if (LIN_FRAMERESPONSE_TX == PduInfoPtr->Drc)
        {
            /* Master response */
            Lin_LocTxHeaderCommands[Channel] = LIN_DRV_TX_MASTER_RES_CMD;
            /* Setup ID, Data length and direction of the frame */
            Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
            for (uint8 Index = 0U; Index < Lin_LocCurrentPdu[Channel].Dl; ++Index)
            {
                Lin_DrvUartFrameSdu[Channel][Index] = PduInfoPtr->SduPtr[Index];
            }
            /* Setup ID checksum type based on Pid */
            Lin_DrvUartFrameChecksum[Channel] = Lin_Lld_Uart_LocGetChecksumByte(&Lin_LocCurrentPdu[Channel]);
        }
        else if (LIN_FRAMERESPONSE_RX == PduInfoPtr->Drc)
        {
            Lin_LocTxHeaderCommands[Channel] = LIN_DRV_TX_SLAVE_RES_CMD;
            Lin_LocChFrameStates[Channel] = LIN_DRV_CH_HEADER_SENT;
        }
        else
        {
            /* Slave send data to slave */
            Lin_LocTxHeaderCommands[Channel] = LIN_DRV_SLAVE_TO_SLAVE_CMD;
            Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
        }
        SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_04();
        RetVal = E_OK;
    }
    else
    {
        Lin_Lld_Uart_LocWakeup(Channel);
    }
    return RetVal;
}

LIN_FUNC void Lin_Lld_Uart_SendResponse(const uint8 Channel, const Lin_PduType *PduInfoPtr)
{
    /* fill data to LINFlexD data register */
    for (uint8 Index = 0U; Index < Lin_LocCurrentPdu[Channel].Dl; ++Index) /*NOSONAR, no memory overruns*/
    {
        Lin_DrvUartFrameSdu[Channel][Index] = PduInfoPtr->SduPtr[Index];/*NOSONAR, no memory overruns*/
    }
}

LIN_FUNC Lin_Drv_HwStatusType Lin_Lld_Uart_GetLinState(const uint8 Channel)
{
    return Lin_LocUartHwStatus[Channel];
}

LIN_FUNC void Lin_Lld_Uart_CopyData(const uint8 Channel, uint8 *LinSduPtr)
{
    for (uint8 Index = 0U; Index < Lin_LocCurrentPdu[Channel].Dl; ++Index)
    {
        LinSduPtr[Index] = Lin_DrvUartFrameSdu[Channel][Index];
    }
}
#endif /* LIN_MASTER_API_SUPPORT == STD_ON */

LIN_FUNC Lin_DrvCommandType Lin_Lld_Uart_GetTxHeaderComands(const uint8 Channel)
{
    return Lin_LocTxHeaderCommands[Channel];
}

LIN_FUNC Lin_DrvErrorType Lin_Lld_Uart_GetFrameErrStates(const uint8 Channel)
{
    return Lin_LocChFrameErrorStates[Channel];
}

LIN_FUNC Lin_DrvStateType Lin_Lld_Uart_GetFrameStates(const uint8 Channel)
{
    return Lin_LocChFrameStates[Channel];
}

LIN_FUNC boolean Lin_Lld_Uart_GetRxEmptyState(const uint8 Channel)
{
    boolean RetVal = FALSE;
    if (FALSE == Lin_LocUartLatchRxEmptyStatus[Channel])
    {
        RetVal = TRUE;
    }
    return RetVal;
}

/*==================================================================================================
 *                                      INTERRUPT FUNCTIONS
==================================================================================================*/
LIN_FUNC boolean Lin_Lld_Uart_LocGetRxFlag(volatile UART_Type *Base)
{
    boolean RetVal = FALSE;
    if (0U != (UART_INTF_RXIF_MASK & Base->INTF))
    {
        RetVal = TRUE;
    }
    return RetVal;
}

LIN_FUNC Std_ReturnType Lin_Lld_Uart_LocReadSentData(volatile UART_Type *Base, uint8 *Data)
{
    Std_ReturnType RetVal = E_NOT_OK;
    uint32 Index = 0U;
    while ((FALSE == Lin_Lld_Uart_LocGetRxFlag(Base)) && (Index < (uint32)LIN_TIMEOUT_DURATION))
    {
        ++Index;
    }
    if ((uint32)LIN_TIMEOUT_DURATION > Index)
    {
        *Data = (uint8)(Base->DATA & 0xFFU);
        RetVal = E_OK;
    }
#if (LIN_DEM_DISABLE == STD_OFF)
    else
    {
        (void) Dem_SetEventStatus(LIN_DEM_EVENT_ID, DEM_EVENT_STATUS_FAILED);
    }
#endif
    return RetVal;
}

LIN_FUNC void Lin_Lld_Uart_LocMasterRxOk(const uint8 Channel, volatile UART_Type *Base, uint8 ResData)
{
    /* Sync Byte */
    if (LIN_DRV_HW_SYNC_FIELD == Lin_LocUartHwStatus[Channel])
    {
        /* check whether 0x55 */
        if (LIN_CONST_SYNC_FIELD_DATA == ResData)
        {
            /* Sync Byte success, start pid */
            Base->DATA = Lin_LocCurrentPdu[Channel].Pid;
            Lin_DrvUartSentData[Channel] = Lin_LocCurrentPdu[Channel].Pid;
            /* change machine state to pid */
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_ID_FIELD;
        }
        else
        {
            /* Sync Byte failed, change frame error state */
            Lin_LocChFrameErrorStates[Channel] = LIN_DRV_SYNCH_FIELD_ERROR;
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
            Base->INTF = Base->INTF;
            Base->INTE = 0x00000000U;
            if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Channel])
            {
                Lin_Lld_Uart_LocGoToSleep(Channel);
            }
        }
    }
    else if (LIN_DRV_HW_ID_FIELD == Lin_LocUartHwStatus[Channel])
    {
        /* stop pid timeout tick */
        Lin_Lld_Uart_LocStopToTicks(Channel);
        /* check pid whether correct */
        if (ResData == Lin_LocCurrentPdu[Channel].Pid)
        {
            /* Pid success, start send data */
            if (LIN_FRAMERESPONSE_TX == Lin_LocCurrentPdu[Channel].Drc)
            {
                Base->DATA = Lin_DrvUartFrameSdu[Channel][0];
                Lin_DrvUartSentData[Channel] = Lin_DrvUartFrameSdu[Channel][0];
                Lin_DrvUartDataCount[Channel] = 1U;
                /* start data field*/
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_DATA_FIELD;
            }
            else if (LIN_FRAMERESPONSE_RX == Lin_LocCurrentPdu[Channel].Drc)
            {
                /* start master receive timer tick */
                Lin_Lld_Uart_LocStartToTicks(Channel, LIN_DRV_TO_M_RECEIVE);
                Lin_LocUartTimeoutType[Channel] = LIN_DRV_TO_M_RECEIVE;
                Base->INTF = Base->INTF;
                Base->RXFIFO = UART_RXFIFO_RESET_MASK | UART_RXFIFO_EN_MASK;
                Lin_DrvUartDataCount[Channel] = 0U;
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_DATA_FIELD;
            }
            else/* LIN_SLAVE_TO_SLAVE */
            {
                /* disable all interrupt */
                Base->INTE = 0x00000000U;
                /* frame state tx complete */
                Lin_LocChFrameStates[Channel] = LIN_DRV_CH_TX_COMPLETE;
                /* idle */
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
                Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
                Base->INTF = Base->INTF;
            }
        }
        else
        {
            /* Pid failed, change frame error state */
            Lin_LocChFrameErrorStates[Channel] = LIN_DRV_ID_PARITY_ERROR;
            Base->INTF = Base->INTF;
            Base->INTE = 0x00000000U;
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
            if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Channel])
            {
                Lin_Lld_Uart_LocGoToSleep(Channel);
            }
        }
    }
    else if (LIN_DRV_HW_DATA_FIELD == Lin_LocUartHwStatus[Channel])
    {
        if (LIN_FRAMERESPONSE_TX == Lin_LocCurrentPdu[Channel].Drc)
        {
            /* check data whether correct */
            if (ResData == Lin_DrvUartSentData[Channel])
            {
                /* last byte send success */
                if (Lin_DrvUartDataCount[Channel] < Lin_LocCurrentPdu[Channel].Dl)
                {
                    /* data not finished, start send next data */
                    Base->DATA = Lin_DrvUartFrameSdu[Channel][Lin_DrvUartDataCount[Channel]];
                    Lin_DrvUartSentData[Channel] = Lin_DrvUartFrameSdu[Channel][Lin_DrvUartDataCount[Channel]];
                    ++Lin_DrvUartDataCount[Channel];
                }
                else /* data finished, send checksum */
                {
                    Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_CHECKSUM_FIELD;
                    Base->DATA = Lin_DrvUartFrameChecksum[Channel];
                    Lin_DrvUartSentData[Channel] = Lin_DrvUartFrameChecksum[Channel];
                    if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Channel])
                    {
                        Lin_Lld_Uart_LocGoToSleep(Channel);
                    }
                }
            }
            else
            {
                /* last byte send fail */
                Lin_LocChFrameErrorStates[Channel] = LIN_DRV_BIT_ERROR;
                Base->INTF = Base->INTF;
                Base->INTE = 0x00000000U;
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
            }
        }
        else if (LIN_FRAMERESPONSE_RX == Lin_LocCurrentPdu[Channel].Drc)
        {
            Lin_DrvUartFrameSdu[Channel][Lin_DrvUartDataCount[Channel]] = ResData;
            ++Lin_DrvUartDataCount[Channel];
            if (Lin_DrvUartDataCount[Channel] >= Lin_LocCurrentPdu[Channel].Dl)
            {
                /* receive done */
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_CHECKSUM_FIELD;
            }
        }
        else /* LIN_SLAVE_TO_SLAVE */
        {
            /* can not be here */
        }
        if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Channel])
        {
            Base->INTF = Base->INTF;
        }
    }
    else if (LIN_DRV_HW_CHECKSUM_FIELD == Lin_LocUartHwStatus[Channel])
    {
        if (LIN_FRAMERESPONSE_TX == Lin_LocCurrentPdu[Channel].Drc)
        {
            if (ResData == Lin_DrvUartFrameChecksum[Channel])
            {
                /* checksum send success */
                Lin_LocChFrameStates[Channel] = LIN_DRV_CH_TX_COMPLETE;
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
                if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Channel])
                {
                    Lin_Lld_Uart_LocGoToSleep(Channel);
                }
            }
            else
            {
                /* checksum send fail */
                Lin_LocChFrameErrorStates[Channel] = LIN_DRV_BIT_ERROR;
                Base->INTF = Base->INTF;
                Base->INTE = 0x00000000U;
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
                if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Channel])
                {
                    Lin_Lld_Uart_LocGoToSleep(Channel);
                }
            }
        }
        else if (LIN_FRAMERESPONSE_RX == Lin_LocCurrentPdu[Channel].Drc)
        {
            uint8 Tmp = Lin_Lld_Uart_LocGetChecksumByte(&Lin_LocCurrentPdu[Channel]);
            if (ResData == Tmp)
            {
                /* checksum correct */
                Lin_LocChFrameStates[Channel] = LIN_DRV_CH_RX_COMPLETE;
            }
            else
            {
                /* checksum check fail */
                Lin_LocChFrameErrorStates[Channel] = LIN_DRV_CHECKSUM_ERROR;
            }
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
            /* stop master res timeout tick */
            Lin_Lld_Uart_LocStopToTicks(Channel);
        }
        else
        {
            /* can not be here */
        }
    }
    else if (LIN_DRV_HW_WAKEUP_FIELD == Lin_LocUartHwStatus[Channel])
    {
        /* check wakeup signal */
        if (ResData == Lin_LocUartWakeupByte[Channel])
        {
            /* Update LIN channel frame operation status */
            Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
            /* Reset frame error status */
            Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
            Lin_ChStates[Channel] = LIN_DRV_CH_OPERATIONAL;
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
        }
        Base->INTF = Base->INTF;
    }
    else
    {
        /* nothing */
    }
}

LIN_FUNC void Lin_Lld_Uart_LocSlaveRxOk(const uint8 Channel, volatile UART_Type *Base, uint8 ResData)
{
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
    Lin_PduType TmpPduInfo;
#endif
    if (LIN_DRV_HW_SYNC_FIELD == Lin_LocUartHwStatus[Channel])
    {
        /* check whether 0x55 */
        if (LIN_CONST_SYNC_FIELD_DATA == ResData)
        {
            /* start receive pid */
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_ID_FIELD;
        }
        else
        {
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
            LinIf_LinErrorIndication(Channel, LIN_ERR_HEADER);
#endif
            /* enable break detect */
            Lin_Lld_Uart_LocEnableLbkDtc(Base);
            /* state idle */
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
        }
    }
    else if (LIN_DRV_HW_ID_FIELD == Lin_LocUartHwStatus[Channel])
    {
        /* stop header res timeout tick */
        Lin_Lld_Uart_LocStopToTicks(Channel);
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
        TmpPduInfo.Pid = ResData;
        TmpPduInfo.SduPtr = &Lin_DrvUartFrameSdu[Channel][0];
        TmpPduInfo.Dl = LIN_CONST_MAX_FRAME_BYTES_NUM;
        TmpPduInfo.Drc = LIN_FRAMERESPONSE_IGNORE;
        TmpPduInfo.Cs  = LIN_ENHANCED_CS;
        /*  On LIN header reception, the LIN driver shall call the header indication callback
            function LinIf_HeaderIndication with PduPtr->Pid set to the received PID value and
            PduPtr->SduPtr set to the (hardware or shadow) buffer of the LIN driver, to which
            the slave response shall be written by the upper layer.
            Trace: SWS_Lin_00280 */
        /*  If the LIN hardware unit cannot detect invalid PIDs, the LIN driver shall not
            evaluate the PID value (i.e. it shall not verify parity bits in software). The LIN
            driver shall provide the PID as-received to the LIN interface module
            Trace: SWS_Lin_00271 */
        if (E_OK == LinIf_HeaderIndication(Channel, &TmpPduInfo))
        {
            Lin_LocCurrentPdu[Channel].Pid = TmpPduInfo.Pid;
            Lin_LocCurrentPdu[Channel].Drc = TmpPduInfo.Drc;
            Lin_LocCurrentPdu[Channel].Cs = TmpPduInfo.Cs;
            Lin_LocCurrentPdu[Channel].Dl = TmpPduInfo.Dl;
            if ((0U == TmpPduInfo.Dl) || (8U < TmpPduInfo.Dl))
            {
                Base->INTF = Base->INTF;
                Lin_Lld_Uart_LocEnableLbkDtc(Base);
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
                return;
            }
            if (LIN_FRAMERESPONSE_RX == TmpPduInfo.Drc)
            {
                /* start slave res timeout tick */
                Lin_Lld_Uart_LocStartToTicks(Channel, LIN_DRV_TO_S_RECEIVE);
                Lin_LocUartTimeoutType[Channel] = LIN_DRV_TO_S_RECEIVE;
                Lin_DrvUartDataCount[Channel] = 0U;
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_DATA_FIELD;
            }
            else if (LIN_FRAMERESPONSE_TX == TmpPduInfo.Drc)
            {
                Base->CTRL0 = UART_CTRL0_RXEN_MASK | UART_CTRL0_TXEN_MASK;
                Base->RXFIFO = UART_RXFIFO_RESET_MASK | UART_RXFIFO_EN_MASK;
                Base->DATA = TmpPduInfo.SduPtr[0];
                Lin_DrvUartSentData[Channel] = TmpPduInfo.SduPtr[0];
                Lin_DrvUartDataCount[Channel] = 1U;
                for (uint8 Index = 0u; Index < TmpPduInfo.Dl; ++Index)
                {
                    Lin_DrvUartFrameSdu[Channel][Index] = TmpPduInfo.SduPtr[Index];
                }
                Lin_DrvUartFrameChecksum[Channel] = Lin_Lld_Uart_LocGetChecksumByte(&Lin_LocCurrentPdu[Channel]);
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_DATA_FIELD;
            }
            else /* slave to slave */
            {
                Base->INTF = Base->INTF;
                Lin_Lld_Uart_LocEnableLbkDtc(Base);
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
            }
        }
        else
#endif
        {
            Base->INTF = Base->INTF;
            Lin_Lld_Uart_LocEnableLbkDtc(Base);
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
        }
    }
    else if (LIN_DRV_HW_DATA_FIELD == Lin_LocUartHwStatus[Channel])
    {
        if (LIN_FRAMERESPONSE_RX == Lin_LocCurrentPdu[Channel].Drc)
        {
            Lin_DrvUartFrameSdu[Channel][Lin_DrvUartDataCount[Channel]] = ResData;
            ++Lin_DrvUartDataCount[Channel];
            if (Lin_DrvUartDataCount[Channel] >= Lin_LocCurrentPdu[Channel].Dl)
            {
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_CHECKSUM_FIELD;
            }
        }
        else if (LIN_FRAMERESPONSE_TX == Lin_LocCurrentPdu[Channel].Drc)
        {
            if (ResData == Lin_DrvUartSentData[Channel])
            {
                /* last data send success, start next*/
                if (Lin_DrvUartDataCount[Channel] < Lin_LocCurrentPdu[Channel].Dl)
                {
                    /* response not finish */
                    Base->DATA = Lin_DrvUartFrameSdu[Channel][Lin_DrvUartDataCount[Channel]];
                    Lin_DrvUartSentData[Channel] = Lin_DrvUartFrameSdu[Channel][Lin_DrvUartDataCount[Channel]];
                    ++Lin_DrvUartDataCount[Channel];
                }
                else /* response finish */
                {
                    Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_CHECKSUM_FIELD;
                    Base->DATA = Lin_DrvUartFrameChecksum[Channel];
                    Lin_DrvUartSentData[Channel] = Lin_DrvUartFrameChecksum[Channel];
                }
            }
            else /* last data send fail*/
            {
                Lin_LocChFrameErrorStates[Channel] = LIN_DRV_BIT_ERROR;
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
                LinIf_LinErrorIndication(Channel, LIN_ERR_RESP_DATABIT);
#endif
                Base->INTF = Base->INTF;
                /* enable break detect */
                Lin_Lld_Uart_LocEnableLbkDtc(Base);
            }
        }
        else
        {
            /* can not be here */
        }
    }
    else if (LIN_DRV_HW_CHECKSUM_FIELD == Lin_LocUartHwStatus[Channel])
    {
        if (LIN_FRAMERESPONSE_RX == Lin_LocCurrentPdu[Channel].Drc)
        {
            if (ResData == Lin_Lld_Uart_LocGetChecksumByte(&Lin_LocCurrentPdu[Channel]))
            {
                /* checksum check success */
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
                LinIf_RxIndication(Channel, &Lin_DrvUartFrameSdu[Channel][0]);
#endif
            }
            else
            {
                /* checksum check fail */
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
                LinIf_LinErrorIndication(Channel, LIN_ERR_RESP_CHKSUM);
#endif
            }
        }
        else if (LIN_FRAMERESPONSE_TX == Lin_LocCurrentPdu[Channel].Drc)
        {
            if (ResData == Lin_DrvUartFrameChecksum[Channel])
            {
                /* send checksum success */
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
                LinIf_TxConfirmation(Channel);
            }
            else
            {
                /* send checksum fail */
                Lin_LocChFrameErrorStates[Channel] = LIN_DRV_BIT_ERROR;
                Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
                LinIf_LinErrorIndication(Channel, LIN_ERR_RESP_DATABIT);
#endif
                Base->INTF = Base->INTF;
                Lin_Lld_Uart_LocEnableLbkDtc(Base);
            }
        }
        else
        {
            /* can not be here */
        }
        /* stop slave res timeout tick */
        Lin_Lld_Uart_LocStopToTicks(Channel);
        /* enable break detect */
        Lin_Lld_Uart_LocEnableLbkDtc(Base);
    }
    else if (LIN_DRV_HW_WAKEUP_FIELD == Lin_LocUartHwStatus[Channel])
    {
        /* check wakeup signal */
        if (ResData == Lin_LocUartWakeupByte[Channel])
        {
            /* Update LIN channel frame operation status */
            Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
            /* Reset frame error status */
            Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
            Lin_ChStates[Channel] = LIN_DRV_CH_OPERATIONAL;
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
        }
        else
        {
            /* wakeup signal send fail */
            Lin_LocChFrameErrorStates[Channel] = LIN_DRV_BIT_ERROR;
            Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
            LinIf_LinErrorIndication(Channel, LIN_ERR_RESP_DATABIT);
#endif
            Base->INTF = Base->INTF;
            Lin_Lld_Uart_LocEnableLbkDtc(Base);
        }
    }
    else
    {
        /* nothing */
    }
}

LIN_FUNC void Lin_Lld_Uart_LocIntWuRsp(const uint8 Channel, volatile UART_Type *Base)
{
    if (TRUE == Lin_GlobalChConfigPtrs[Channel]->LinChWakeSupport)
    {
        if (LIN_MASTER_MODE == Lin_LocNodeMode[Channel])
        {
            Base->INTE = 0x00000000U;
            /* Reset header command type */
            Lin_LocTxHeaderCommands[Channel] = LIN_DRV_TX_NO_CMD;
            /* Reset error status flag */
            Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NO_ERROR;
            /* Set LIN channel frame state to default not ready */
            Lin_LocChFrameStates[Channel] = LIN_DRV_CH_READY;
            Lin_LocUartLatchRxEmptyStatus[Channel] = TRUE;
        }
        else
        {
            Base->CTRL0 = UART_CTRL0_RXEN_MASK;
            Lin_Lld_Uart_LocEnableLbkDtc(Base);
        }
        EcuM_CheckWakeup(Lin_GlobalChConfigPtrs[Channel]->LinChEcuMWakeupSource);
        Lin_ChStates[Channel] = LIN_DRV_CH_OPERATIONAL;
    }
    else
    {
        Lin_LocUartWakeupReq[Channel] = TRUE;
    }
    Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
    Base->INTF = Base->INTF;
}

LIN_FUNC void Lin_Lld_Uart_LocIntLbkRsp(const uint8 Channel, volatile UART_Type *Base)
{
    SchM_Enter_Lin_LIN_EXCLUSIVE_AREA_02();
    Base->CTRL1 &= ~UART_CTRL1_LBKDEN_MASK;
    SchM_Exit_Lin_LIN_EXCLUSIVE_AREA_02();
    Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_SYNC_FIELD;
    Base->INTF = Base->INTF;
    Base->RXFIFO = UART_RXFIFO_RESET_MASK | UART_RXFIFO_EN_MASK;
    if (LIN_MASTER_MODE == Lin_LocNodeMode[Channel])
    {
        Lin_Lld_Uart_LocStopToTicks(Channel);
        Base->DATA = LIN_CONST_SYNC_FIELD_DATA;
        Lin_DrvUartSentData[Channel] = LIN_CONST_SYNC_FIELD_DATA;
    }
    else
    {
        /* start header timeout tick */
        Lin_Lld_Uart_LocStartToTicks(Channel, LIN_DRV_TO_HEADER);
        Lin_LocUartTimeoutType[Channel] = LIN_DRV_TO_HEADER;
    }
    /* enable rx interrupt, frame error interrupt, overrun interrupt*/
    Base->INTE = UART_INTE_RXIE_MASK | UART_INTE_FEIE_MASK | UART_INTE_OVRIE_MASK;
}

LIN_FUNC void Lin_Lld_Uart_LocIntRxRsp(const uint8 Channel, volatile UART_Type *Base)
{
    uint32 Tmp32 = Base->DATA;
    uint8 ResData = (uint8)(Tmp32 & 0xFFU);
    boolean RxNoiseErrFlag = FALSE;
    boolean RxFeErrFlag = FALSE;
    if (0U != (Tmp32 & UART_DATA_NOISE_MASK))
    {
        RxNoiseErrFlag = TRUE;
    }
    if ((0U != (Base->INTF & UART_INTF_FEIF_MASK)) || (0U != (Tmp32 & UART_DATA_FERR_MASK)))
    {
        RxFeErrFlag = TRUE;
    }
    if (TRUE == RxNoiseErrFlag)
    {
        if (LIN_MASTER_MODE == Lin_LocNodeMode[Channel])
        {
            Lin_LocChFrameErrorStates[Channel] = LIN_DRV_NOISE_ERROR;
            Base->INTE = 0x00000000U;
            /* Base->CTRL0 = 0x00000000U; */
            /* Base->RXFIFO = UART_RXFIFO_RESET_MASK;*/
        }
        else
        {
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
            if ((LIN_DRV_HW_SYNC_FIELD == Lin_LocUartHwStatus[Channel]) || (LIN_DRV_HW_ID_FIELD == Lin_LocUartHwStatus[Channel]))
            {
                LinIf_LinErrorIndication(Channel, LIN_ERR_HEADER);
            }
            else
            {
                LinIf_LinErrorIndication(Channel, LIN_ERR_INC_RESP);
            }
#endif
            Base->INTF = Base->INTF;
            Lin_Lld_Uart_LocEnableLbkDtc(Base);
            if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Channel])
            {
                Lin_Lld_Uart_LocGoToSleep(0U);
            }
        }
        Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
    }
    else if (TRUE == RxFeErrFlag)
    {
        if (LIN_MASTER_MODE == Lin_LocNodeMode[Channel])
        {
            if ((LIN_DRV_HW_BREAK == Lin_LocUartHwStatus[Channel]) ||
                    (LIN_DRV_HW_SYNC_FIELD == Lin_LocUartHwStatus[Channel]) || (LIN_DRV_HW_ID_FIELD == Lin_LocUartHwStatus[Channel]))
            {
                Lin_LocChFrameErrorStates[Channel] = LIN_DRV_HEADER_FRAMING_ERROR;
            }
            else
            {
                Lin_LocChFrameErrorStates[Channel] = LIN_DRV_FRAMING_ERROR;
            }
            Base->INTE = 0x00000000U;
            /* Base->CTRL0 = 0x00000000U; */
            /* Base->RXFIFO = UART_RXFIFO_RESET_MASK;*/
        }
        else
        {
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
            if ((LIN_DRV_HW_SYNC_FIELD == Lin_LocUartHwStatus[Channel]) || (LIN_DRV_HW_ID_FIELD == Lin_LocUartHwStatus[Channel]))
            {
                LinIf_LinErrorIndication(Channel, LIN_ERR_HEADER);
            }
            else
            {
                LinIf_LinErrorIndication(Channel, LIN_ERR_RESP_STOPBIT);
            }
#endif
            Lin_Lld_Uart_LocEnableLbkDtc(Base);
            if (LIN_DRV_TX_SLEEP_CMD == Lin_LocTxHeaderCommands[Channel])
            {
                Lin_Lld_Uart_LocGoToSleep(0U);
            }
        }
        Base->INTF = Base->INTF;
        Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
    }
    else
    {
        if (LIN_MASTER_MODE == Lin_LocNodeMode[Channel])
        {
            Lin_Lld_Uart_LocMasterRxOk(Channel, Base, ResData);
        }
        else
        {
            Lin_Lld_Uart_LocSlaveRxOk(Channel, Base, ResData);
        }
    }
}

LIN_FUNC void Lin_Lld_Uart_LocIntOvrRsp(const uint8 Channel, volatile UART_Type *Base)
{
    if (LIN_MASTER_MODE == Lin_LocNodeMode[Channel])
    {
        Lin_LocChFrameErrorStates[Channel] = LIN_DRV_OVERRUN_ERROR;
        Base->INTE = 0x00000000U;
        /* Base->CTRL0 = 0x00000000U; */
        Base->RXFIFO = UART_RXFIFO_RESET_MASK;
    }
    else
    {
#if (LIN_SLAVE_API_SUPPORT == STD_ON)
        LinIf_LinErrorIndication(Channel, LIN_ERR_INC_RESP);
#endif
        Lin_Lld_Uart_LocEnableLbkDtc(Base);
    }
    Base->INTF = Base->INTF;
    Lin_LocUartHwStatus[Channel] = LIN_DRV_HW_IDLE_MODE;
    /* No receive overflow happen because TX_SLEEP_CMD(Lin_GotoSleep) is transmitting command */
}

LIN_FUNC void Lin_Lld_Uart_LocIntHandler(const uint8 HwChannel)
{
    uint8 Channel;
    uint32 UartStatus;
    uint32 UartIe;
    /* convert hardware channel to logic channel */
    Channel = Lin_LocUartInstMapPtr[HwChannel];
    /* Get LINFlexD Base address */
    volatile UART_Type *Base = Lin_LocBasePtrs[(uint8)Lin_GlobalChConfigPtrs[Channel]->LinHwChannel - LIN_CONST_UART_ID_START_NUMBER];
    UartStatus = Base->INTF;
    UartIe = Base->INTE;
    /*GCOVR_EXCL_START UART_INTE_OVRIE_MASK always true, But it is not allowed to be deleted */
    if ((0UL != (UartStatus & UART_INTF_OVRIF_MASK)) && (0UL != (UartIe & UART_INTE_OVRIE_MASK)))
        /*GCOVR_EXCL_STOP*/
    {
        Lin_Lld_Uart_LocIntOvrRsp(Channel, Base);
    }
    if ((0UL != (UartStatus & UART_INTF_RXEDGEIF_MASK)) && (0UL != (UartIe & UART_INTE_RXEDGEIE_MASK)))
    {
        Lin_Lld_Uart_LocIntWuRsp(Channel, Base);
    }
    /*GCOVR_EXCL_START UART_INTE_LBKDIE_MASK always true, But it is not allowed to be deleted */
    if ((0UL != (UartStatus & UART_INTF_LBKDIF_MASK)) && (0UL != (UartIe & UART_INTE_LBKDIE_MASK)))
        /*GCOVR_EXCL_STOP*/
    {
        Lin_Lld_Uart_LocIntLbkRsp(Channel, Base);
    }
    if (((0UL != (UartStatus & UART_INTF_RXIF_MASK)) && (0UL != (UartIe & UART_INTE_RXIE_MASK)))
            || ((0UL != (UartStatus & UART_INTF_FEIF_MASK)) && (0UL != (UartIe & UART_INTE_FEIE_MASK))))
    {
        Lin_Lld_Uart_LocIntRxRsp(Channel, Base);
    }
}

#ifdef UART_IP_0_LIN_OCCUPY
#ifdef UART0_BASE_ADDR32
LIN_FUNC ISR(UART0_IRQHandler)
{
    Lin_Lld_Uart_LocIntHandler(LIN_INSTANCE_ID_0);
}
#endif
#endif
#ifdef UART_IP_1_LIN_OCCUPY
#ifdef UART1_BASE_ADDR32
LIN_FUNC ISR(UART1_IRQHandler)
{
    Lin_Lld_Uart_LocIntHandler(LIN_INSTANCE_ID_1);
}
#endif
#endif
#ifdef UART_IP_2_LIN_OCCUPY
#ifdef UART2_BASE_ADDR32
LIN_FUNC ISR(UART2_IRQHandler)
{
    Lin_Lld_Uart_LocIntHandler(LIN_INSTANCE_ID_2);
}
#endif
#endif

#define LIN_STOP_SEC_CODE
#include "Lin_MemMap.h"


/** @} */

