/*!
 * @file        lin.c
 *
 * @brief       Lin program body
 *
 * @version     V1.0.0
 *
 * @date        2026-02
 *
 * @attention
 *
 *  Copyright (C) 2026 Geehy Semiconductor
 *
 *  You may not use this file except in compliance with the
 *  GEEHY COPYRIGHT NOTICE (Geehy Semiconductor Software License Agreement).
 *
 *  The program is only for reference, which is distributed in the hope
 *  that it will be useful and instructional for customers to develop
 *  their software. Unless required by applicable law or agreed to in
 *  writing, the program is distributed on an "AS IS" BASIS, WITHOUT
 *  ANY WARRANTY OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the Geehy Semiconductor Software License Agreement for the governing permissions
 *  and limitations under the License.
 */

/* Includes */
#include "stdio.h"
#include "lin.h"
#include "g32a10xx_gpio.h"
#include "g32a10xx_usart.h"
#include "g32a10xx_misc.h"
#include "user_usart_config.h"

/** @addtogroup Examples
  @{
*/

/** @addtogroup USART_Examples
  @{
*/

/** @addtogroup USART_LIN_autosync
  @{
*/

/** @defgroup USART_LIN_autosync_INT_Macros INT_Macros
  @{
*/

/** Configuration LIN Classic Diagnostic IDs */
/** Master -> Slaves */
#define LIN_DIAG_ID_MASTER_REQUEST              0x3C
/** Slave  -> Master */
#define LIN_DIAG_ID_SLAVE_RESPONSE              0x3D
/** Configuration Application / Signal Frame IDs */
/** Designate the valid ID number required for Slave response , Slave  Tx (example) */
#define LIN_APP_ID_SLAVE_PUBLISH                0x16
/** Designate the valid ID number required for Master require , Master Tx (example) */
#define LIN_APP_ID_MASTER_PUBLISH               0x15

#define SLAVE_TO_MASTER                         0
#define MASTER_TO_SLAVE                         1

/**@} end of group USART_LIN_autosync_INT_Macros */

/** @defgroup USART_LIN_autosync_INT_Variables INT_Variables
  @{
*/

Lin_MessageType g_MasterSend = {0};
Lin_MessageType g_MasterReceived = {0};

volatile uint8_t g_MasterReceivedProces = 0;
volatile uint8_t g_MasterReceiveDataProces = 0;
volatile uint8_t g_MasterReceivedOverFlag = 0;

Lin_MessageType g_SlaveSend = {0};
Lin_MessageType g_SlaveReceived = {0};

volatile uint8_t g_SlaveReceivedProces = 0;
volatile uint8_t g_SlaveReceivedDataProces = 0;
volatile uint8_t g_SlaveReceivedOverFlag = 0;
uint8_t g_ResponseBuf[9] = {0,0,0,0,0,0,0,0,0 };
uint8_t g_SendBuf[9] = {0,0,0,0,0,0,0,0,0 };
volatile uint8_t g_frameIndex = 0;
uint8_t* g_dataPtr = NULL;
volatile uint8_t g_pid = 0x80;
volatile uint8_t g_currentId = 0;
volatile uint8_t g_checkSum = 0;

/** Lin message configured table for Slave node. */
const Lin_MsgType g_linMsgCfgTable[3] =
{
    {LIN_APP_ID_SLAVE_PUBLISH,PARITY_FIELD(LIN_APP_ID_SLAVE_PUBLISH), 8,SLAVE_TO_MASTER},

    {LIN_APP_ID_MASTER_PUBLISH,PARITY_FIELD(LIN_APP_ID_MASTER_PUBLISH), 8,MASTER_TO_SLAVE},

    {LIN_DIAG_ID_MASTER_REQUEST,PARITY_FIELD(LIN_DIAG_ID_MASTER_REQUEST), 8,MASTER_TO_SLAVE}
};

const uint8_t g_linMsgTblLen = sizeof(g_linMsgCfgTable)/sizeof(g_linMsgCfgTable[0]);

/**@} end of group USART_LIN_autosync_INT_Variables */

/** @defgroup USART_LIN_autosync_INT_Functions INT_Functions
  @{
*/

#ifdef LIN_AUTO_BAUDRATE_ENABLE
extern uint32_t SysTick_Init(uint32_t Ticks);
extern void SysTick_Stop(void);
#endif

/*!
 * @brief       Lin Init functions
 *
 * @param       None
 *
 * @retval      None
 *
 * @note
 */
void Lin_Init(void)
{
    Gpio_ConfigType gpioConfig = {0};

    /* Enable GPIO clock */
    Rcm_EnableAhbPeriphClock(USASRT2_TX_GPIO_CLK);
    Rcm_EnableAhbPeriphClock(USASRT2_RX_GPIO_CLK);

    /* Enable USART2 clock */
    Rcm_EnableApb1PeriphClock(RCM_APB1_PERIPH_USART2);

    /* Connect PXx to USART2_Tx */
    Gpio_ConfigPinAF(USASRT2_TX_GPIO_PORT, USASRT2_TX_PIN_SOURCE, USASRT2_TX_AF);

    /* Connect PXx to USART2_Rx */
    Gpio_ConfigPinAF(USASRT2_RX_GPIO_PORT, USASRT2_RX_PIN_SOURCE, USASRT2_RX_AF);

    /* Configure USART2 Tx as alternate function push-pull */
    gpioConfig.mode = GPIO_MODE_AF;
    gpioConfig.pin = (uint16_t)USASRT2_TX_PIN;
    gpioConfig.speed = GPIO_SPEED_50MHz;
    gpioConfig.outtype = GPIO_OUT_TYPE_PP;
    gpioConfig.pupd = GPIO_PUPD_PU;
    Gpio_Config(USASRT2_TX_GPIO_PORT, &gpioConfig);

    /* Configure USART2 Rx as input floating */
    gpioConfig.pin = (uint16_t)USASRT2_RX_PIN;
    Gpio_Config(USASRT2_RX_GPIO_PORT, &gpioConfig);

    /* USART2 configured as follow: */
    Usart_Config(USART2, &g_usart2Config);

    /* Enable USART2_Interrupt_RXBNEIE */
    Usart_EnableInterrupt(USART2, USART_INT_LBDIE);

    Nvic_EnableIrqRequest(USART2_IRQn, 3);

    Usart_ConfigLinBreakDetectLenCfg(USART2, USART_LBDLC_11B);

    /* Enable the USARTx LIN mode */
    Usart_EnableLin(USART2);

    /* Enable USART2 */
    Usart_Enable(USART2);

    /* Clear USARTx TXC Flag */
    Usart_ClearStatusFlag(USART2, USART_FLAG_TXC);
    Usart_ClearStatusFlag(USART2, USART_FLAG_TXBE);
}

/*!
 * @brief       The master send data to the slave function
 *
 * @param       None
 *
 * @retval      None
 *
 */
void Lin_MasterSendSlave(void)
{
    uint8_t i = 0;
    g_MasterSend.ID = LIN_DIAG_ID_MASTER_REQUEST;

    /* The following data is the data sent from the master to the slave. */
    g_MasterSend.data[0] = 0x11;
    g_MasterSend.data[1] = 0x22;
    g_MasterSend.data[2] = 0x33;
    g_MasterSend.data[3] = 0x44;
    g_MasterSend.data[4] = 0x55;
    g_MasterSend.data[5] = 0x66;
    g_MasterSend.data[6] = 0x77;
    g_MasterSend.data[7] = 0x88;

    Lin_SendHead(USART2, g_MasterSend, TIMEOUT_VALUE);
    Lin_SendAnswer(USART2, g_MasterSend, TIMEOUT_VALUE);

    printf("\r\nThe master sends data to the slave.\r\n");
    printf("Master Send ID : 0x%X ,\r\n", g_MasterSend.ID);

    printf("Master Send Data : ");

    for (i = 0; i < 8u; i++)
    {
        printf("0x%X ,", g_MasterSend.data[i]);
    }

    printf(" CheckSum : 0x%X \r\n",  Lin_Hw_CheckSum(g_MasterSend.ID, g_MasterSend.data));
}

/*!
 * @brief       Transmits break characters
 *
 * @param       UsartPtr: Select the USART or the UART peripheral
 *
 * @retval      None
 *
 */
void Lin_SendBreak(USART_T* UsartPtr)
{
    UsartPtr->REQUEST_R.REQUEST_B.TXBFQ = BIT_SET;
}

/*!
 * @brief       Transmits Sync Segment
 *
 * @param       UsartPtr: Select the USART or the UART peripheral
 *
 * @param       Timeout: Timeout value
 *
 * @retval      status
 *
 */
uint32_t Lin_SendSyncSegment(USART_T* UsartPtr, uint32_t Timeout)
{
    uint32_t status = ERROR_TIMEOUT;
    uint32_t timeout_cnt = Timeout;

    Usart_TxData(UsartPtr, 0x55);

    while(timeout_cnt > 0u)
    {
        /* wait for the data to be send */
        if (Usart_ReadStatusFlag(UsartPtr, USART_FLAG_TXBE) == (uint8_t)RESET)
        {
            status = ERROR_TIMEOUT;
        }
        else
        {
            status = ERROR_NONE;
            break;
        }
        timeout_cnt = timeout_cnt - 1u;
    }
    return status;
}

/*!
 * @brief       ID check
 *
 * @param       Id: frame ID
 *
 * @retval      checked id
 *
 */
uint8_t Lin_CheckPid(uint8_t Id)
{
    uint8_t returnpid ;
    uint8_t P0 ;
    uint8_t P1 ;

    P0 = (((Id) ^ (Id >> 1u) ^ (Id >> 2u) ^ (Id >> 4u)) & 0x01u) << 6u ;
    P1 = ((~((Id >> 1u) ^ (Id >> 3u) ^ (Id >> 4u) ^ (Id >> 5u))) & 0x01u) << 7u ;

    returnpid = Id | P0 | P1 ;

    return returnpid ;
}

/*!
* @brief         PID Check and return current id
*
* @param[in]     Pid: protect id
*
* @retval        current id
*
* @note          None
*/
uint8_t Lin_ProcessParity(uint8_t Pid)
{
    uint8_t parity;
    uint8_t ret;

    parity =((uint8_t)((BITT(Pid, 0u)^BITT(Pid, 1u)^BITT(Pid, 2u)^BITT(Pid, 4u)) << 6u) |
            ((uint8_t)(~(BITT(Pid, 1u)^BITT(Pid, 3u)^BITT(Pid, 4u)^BITT(Pid, 5u))) << 7u));

    if((Pid & 0xC0u) != parity)
    {
        ret = 0xFFu;
    }
    else
    {
        ret = (uint8_t)(Pid & 0x3Fu);
    }
    return (ret);
}

/*!
* @brief         Check whether the received frame is a configured frame by verifying it against the configuration message table.
*
* @param[in]     Id: frame id
*
* @retval        current frame id
*
* @note          None
*/
 static uint8_t Lin_Hw_CheckUsedId(uint8_t Id)
{
    uint8_t i;
    uint8_t retId = 0xFF;
    for(i = 0; i < g_linMsgTblLen; i++)
    {
        if(g_linMsgCfgTable[i].id == Id)
        {
            retId = i;
            break;
        }
        else
        {
            /* do nothiing */
        }
    }
    return (retId);
}

/*!
* @brief         Write slave response data
*
* @param[in]     Ch: Send data
* @param[in]     UsartId: Usart index
*
* @retval        void
*
* @note          None
*/
static void Lin_Hw_PutChar(uint8_t Ch, USART_T* Usart)
{
    uint16_t cnt = 300;
    while(cnt > 0U)
    {
        cnt--;

        if (Usart_ReadStatusFlag(Usart, USART_FLAG_TXBE) == (uint8_t)SET)
        {
            Usart_TxData(Usart,Ch);
            break;
        }
        else
        {
            /* nothing */
        }
    }
}

/*!
* @brief         Process received pid event from master
*
* @param[in]     Pid: Received pid from master
* @param[in]     UsartIdx: Usart index
*
* @retval        void
*
* @note          None
*/
void Lin_Hw_ProcessPid(uint8_t Pid, USART_T* UsartPtr)
{
    Lin_ResponseType action = LIN_IDLE;
    /* get frame g_frameIndex */
    g_frameIndex = Lin_Hw_CheckUsedId(Pid);
    if (0xFFu == g_frameIndex)
    {
        action = LIN_IDLE;
    }
    else
    {
        /* allowing the application layer to perform special logic processing based on the PID */
        Lin_PidReceivedNotification(Pid, g_frameIndex);

        /* Determine the data transmission direction */
        if ((uint8_t)SLAVE_TO_MASTER == g_linMsgCfgTable[g_frameIndex].data_dir)
        {
            action = LIN_SET;
        }
        else if ((uint8_t)MASTER_TO_SLAVE == g_linMsgCfgTable[g_frameIndex].data_dir)
        {
            action = LIN_RECEIVE;
        }
        else
        {
            /* nothing */
        }
    }
    switch (action)
    {
        case LIN_RECEIVE:
             /* Receive response (Slave as Receiver) */
             g_SlaveReceivedDataProces = 0;
             g_dataPtr = g_ResponseBuf;
             g_SlaveReceivedProces = (uint8_t)RECV_DATA;
             break;
        case LIN_SET:
            /* Set response(Slave as Publisher) */
            g_SlaveReceivedDataProces = 1;

            /* Parse configuration or application layer data into the transmission buffer */
            Lin_GetTxDataNotification(g_frameIndex, g_SendBuf);

            /* Send First byte */
            Lin_Hw_PutChar(g_SendBuf[0], UsartPtr);
            /* Set LIN Status */
            g_SlaveReceivedProces = (uint8_t)SEND_DATA;
            break;
        default:
            g_SlaveReceivedProces = (uint8_t)IDLE;
            /* Clear the status and re-enable Break detection interrupt */
            Usart_DisableInterrupt(USART2, USART_INT_RXBNEIE);
            Usart_ClearStatusFlag(USART2, USART_FLAG_LBD);
            Usart_EnableInterrupt(USART2, USART_INT_LBDIE);
            break;
    }
}

/*!
 * @brief       The master header frame sending function.
 *
 * @param       UsartPtr: Select the USART or the UART peripheral
 *
 * @param       LINMessage: LIN Message structure @Lin_MessageType
 *
 * @param       Timeout: Timeout value
 *
 * @retval      status
 *
 */
uint32_t Lin_SendHead(USART_T* UsartPtr, Lin_MessageType LinMessage, uint32_t Timeout)
{
    uint32_t status = ERROR_TIMEOUT;
    uint32_t timeout_cnt = Timeout;

    Lin_SendBreak(UsartPtr);
    Lin_SendSyncSegment(UsartPtr, timeout_cnt);
    Usart_TxData(UsartPtr, Lin_CheckPid(LinMessage.ID));

    while(timeout_cnt > 0u)
    {
        /* wait for the data to be send  */
        if (Usart_ReadStatusFlag(UsartPtr, USART_FLAG_TXBE) == (uint8_t)RESET)
        {
            status = ERROR_TIMEOUT;
        }
        else
        {
            status = ERROR_NONE;
            break;
        }
        timeout_cnt = timeout_cnt - 1u;
    }
    return status;
}


/*!
 * @brief       Check data sum
 *
 * @param       id: frame ID
 *
 * @param       DataPtr: frame data
 *
 * @retval      checked sum
 *
 */
uint8_t Lin_CheckSum(uint8_t id, const uint8_t* DataPtr)
{
    uint8_t t = 0;
    uint16_t sum = 0;

    sum = DataPtr[0];

    for (t = 1; t < 8u; t++)
    {
        sum += DataPtr[t];

        if (0u != (sum & 0xff00u))
        {
            sum = sum & 0x00ffu;
            sum = sum + 1u;
        }
        else
        {
            /* do nothing */
        }
    }

    /* In the case of diagnostic frames, the classic checksum is used. */
    if (id != (uint8_t)0x3C)
    {
        sum += Lin_CheckPid(id);

        if (0u != (sum & 0xff00u))
        {
            sum = sum & 0x00ffu;
            sum = sum + 1u;
        }
        else
        {
            /* do nothing */
        }
    }
    else
    {
        /* nothing */
    }

    sum = ~sum;
    return (uint8_t)sum ;
}

/*!
 * @brief       Transmits data
 *
 * @param       UsartPtr: Select the USART or the UART peripheral
 *
 * @param       DataPtr: frame data
 *
 * @param       Timeout: Timeout value
 *
 * @retval      status
 *
 */
uint32_t Lin_TxData(USART_T* UsartPtr, const uint8_t* DataPtr, uint32_t Timeout)
{
    uint8_t t, txdata ;
    uint32_t status = ERROR_TIMEOUT;
    uint32_t timeout_cnt = Timeout;

    for (t = 0; t < 8u; t++)
    {
        txdata = DataPtr[t];

        Usart_TxData(UsartPtr, txdata);

        while(timeout_cnt > 0u)
        {
            /* wait for the DataPtr to be send */
            if (Usart_ReadStatusFlag(UsartPtr, USART_FLAG_TXBE) == (uint8_t)RESET)
            {
                status = ERROR_TIMEOUT;
            }
            else
            {
                status = ERROR_NONE;
                break;
            }
            timeout_cnt = timeout_cnt - 1u;
        }
        if (status == ERROR_TIMEOUT)
        {
            break;
        }
        else
        {
            /* do nothing */
        }
    }
    return status;
}

/*!
 * @brief       Transmits Answer
 *
 * @param       UsartPtr: Select the USART or the UART peripheral
 *
 * @param       LINMessage: LIN Message strucstruct @Lin_MessageType
 *
 * @param       Timeout: Timeout value
 *
 * @retval      status
 *
 */
uint32_t Lin_SendAnswer(USART_T* UsartPtr, Lin_MessageType LinMessage, uint32_t Timeout)
{
    uint32_t status = ERROR_TIMEOUT;
    uint32_t timeout_cnt = Timeout;

    Lin_TxData(UsartPtr, LinMessage.data, timeout_cnt);
    Usart_TxData(UsartPtr, Lin_Hw_CheckSum(LinMessage.ID, LinMessage.data));

    while(timeout_cnt > 0u)
    {
        /* wait for the data to be send */
        if (Usart_ReadStatusFlag(UsartPtr, USART_FLAG_TXBE) == (uint8_t)RESET)
        {
            status = ERROR_TIMEOUT;
        }
        else
        {
            status = ERROR_NONE;
            break;
        }
        timeout_cnt = timeout_cnt - 1u;
    }
    return status;
}


/*!
 * @brief       Slave received data flame process
 *
 * @param       None
 *
 * @retval      ERROR/SUCCESS: data verify is failed/successful.
 *
 */
uint8_t Lin_SlaveReceivedProces(void)
{
    uint8_t i = 0;
    uint8_t status = SUCCESS;

    if (g_MasterSend.ID != (g_SlaveReceived.ID & 0x3fu))
    {
        status = ERROR;
    }
    else
    {
        for (i = 0; i < 8u; i++)
        {
            if (g_MasterSend.data[i] != g_SlaveReceived.data[i])
            {
                status = ERROR;
                break;
            }
            else
            {
                /* do nothing */
            }
        }
        if (status != (uint8_t)ERROR)
        {

            if (Lin_Hw_CheckSum(g_MasterSend.ID, g_MasterSend.data) != g_SlaveReceived.CheckSum)
            {
                status = ERROR;
            }
            else
            {
                /* do nothing */
            }
        }
        else
        {
            /* do nothing */
        }
    }
    return status;
}

/*!
* @brief         Frame Check
*
* @param[in]     Id: protect id
*
* @param[in]     BufferPtr: data for check
*
* @retval        uint8
*
* @note          None
*/
uint8_t Lin_Hw_CheckSum(uint8_t Pid, const uint8_t* BufferPtr)
{
    uint8_t length = 0;
    uint16_t checkSum = 0;

    for(length = 0; length < 8U; length++)
    {
        checkSum += BufferPtr[length];
        if(checkSum > 0xFFu)
        {
            checkSum -= 0xFFu;
        }
        else
        {
            /* do nothing */
        }
    }

    if((Pid != 0x3Cu)&&(Pid != 0x7Du))
    {
        checkSum += Pid;
    }
    else
    {
        /* do nothing, the diagnostic frame adopts a classical checksum. */
    }
    if(checkSum > 0xFFu)
    {
        checkSum -= 0xFFu;
    }
    else
    {
        /* do nothing */
    }

    return (uint8_t)((~checkSum) & 0xFFu);
}

/*!
 * @brief       Slave interrupt server functions
 *
 * @param       UsartPtr: Select the USART or the UART peripheral
 *
 * @retval      None
 *
 */
void Lin_SlaveIsr(USART_T* UsartPtr)
{
    uint8_t ReceiveData;
    uint8_t idx = g_SlaveReceivedDataProces;
    uint8_t sendData;

    uint8_t isRxNotEmpty;
    uint8_t isTxEmpty;

    if (Usart_ReadIntFlag(UsartPtr, USART_INT_FLAG_LBD) == (uint8_t)SET)
    {
        /* Clear LIN Break Detection Flag */
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_LBD);
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_TXC);
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_OVRE);
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_NEF);
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_FEF);
        Usart_EnableInterrupt(UsartPtr, USART_INT_RXBNEIE);
        g_SlaveReceivedProces = (uint8_t)RECV_SYN;
        Usart_RxData(UsartPtr);
#ifdef LIN_AUTO_BAUDRATE_ENABLE
        Usart_ConfigAutoBaudRate(UsartPtr, USART_AUTO_BAUD_RATE_0X55);
        Usart_EnableAutoBaudRate(UsartPtr);
        /* Configure the SysTick to generate a time base equal to 1 ms */
        g_sysTick = 0;
        SysTick_Init(SystemCoreClock / 1000);
#endif
    }
    else if (Usart_ReadIntFlag(UsartPtr, USART_INT_FLAG_FE) == (uint8_t)SET)
    {
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_FEF);

        g_SlaveReceivedProces = (uint8_t)IDLE;

        Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
        Usart_EnableInterrupt(UsartPtr, USART_INT_LBDIE);
    }
    else
    {
        isRxNotEmpty = Usart_ReadIntFlag(UsartPtr, USART_INT_FLAG_RXBNE);
        isTxEmpty    = Usart_ReadIntFlag(UsartPtr, USART_INT_FLAG_TXBE);

        if ((isRxNotEmpty == (uint8_t)SET) || (isTxEmpty == (uint8_t)SET))
        {
            ReceiveData = (uint8_t)Usart_RxData(UsartPtr);

            switch(g_SlaveReceivedProces)
            {
                case (uint8_t)IDLE:
                    Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
                    Usart_ClearStatusFlag(UsartPtr, USART_FLAG_LBD);
                    Usart_EnableInterrupt(UsartPtr, USART_INT_LBDIE);
                    break;
                case (uint8_t)RECV_SYN:
    #ifdef LIN_AUTO_BAUDRATE_ENABLE
                    Usart_DisableAutoBaudRate(UsartPtr);
                    SysTick_Stop();
                    g_sysTick = 0;
    #endif
                    if (0x55u == ReceiveData)
                    {
                        g_SlaveReceivedProces = (uint8_t)RECV_PID;
                    }
                    else
                    {
                        g_SlaveReceivedProces = (uint8_t)IDLE;
                        Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
                        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_LBD);
                        Usart_EnableInterrupt(UsartPtr, USART_INT_LBDIE);
                    }
                    break;
                case (uint8_t)RECV_PID:
                    g_pid = ReceiveData;
                    g_currentId = Lin_ProcessParity(ReceiveData);
                    if(g_currentId != 0xFFu)
                    {
                        /* ID received correctly - parity OK */
                        Lin_Hw_ProcessPid(g_currentId,UsartPtr);
                    }
                    else
                    {
                        /* ID Parity Error */
                        g_SlaveReceivedProces = (uint8_t)IDLE;
                        Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
                        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_PEF);
                        Usart_EnableInterrupt(UsartPtr, USART_INT_LBDIE);
                    }
                    break;
                case (uint8_t)RECV_DATA:
                    *(g_dataPtr) = ReceiveData;
                    g_dataPtr++;
                    if(g_SlaveReceivedDataProces == 8U)
                    {
                        if(Lin_Hw_CheckSum(g_pid, g_ResponseBuf) == ReceiveData)
                        {
                            g_SlaveReceivedProces = (uint8_t)IDLE;
                            g_SlaveReceivedOverFlag = 1;

                            Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
                            Usart_ClearStatusFlag(UsartPtr, USART_FLAG_LBD);
                            Usart_EnableInterrupt(UsartPtr, USART_INT_LBDIE);
                        }
                        else
                        {
                            g_SlaveReceivedProces = (uint8_t)IDLE;
                        }
                    }
                    else
                    {
                        /* nothing */
                    }
                    g_SlaveReceivedDataProces = idx + 1U;
                    break;
                case (uint8_t)SEND_DATA:
                    /* TX Buffer Empty - Checksum Sent */
                    if(Usart_ReadStatusFlag(UsartPtr, USART_FLAG_TXBE) == (uint8_t)RESET)
                    {
                        /* Set max idle timeout */
                        g_SlaveReceivedProces = (uint8_t)IDLE;
                        Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
                        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_LBD);
                        Usart_EnableInterrupt(UsartPtr, USART_INT_LBDIE);
                        break;
                    }
                    else
                    {
                        /* nothing */
                    }
                    /* Send checksum byte */
                    if(g_SlaveReceivedDataProces == 8U)
                    {
                        sendData = Lin_Hw_CheckSum(g_linMsgCfgTable[g_frameIndex].protected_id, g_SendBuf);
                        g_checkSum = sendData;
                        g_SlaveReceivedProces = (uint8_t)SEND_DATA_COMPLETED;
                        Lin_Hw_PutChar (sendData, UsartPtr);
                    }
                    else
                    {
                        if(g_SendBuf[g_SlaveReceivedDataProces-1U] == ReceiveData)
                        {
                            /* Send byte next */
                            sendData = g_SendBuf[g_SlaveReceivedDataProces];
                            Lin_Hw_PutChar (sendData, UsartPtr);
                            g_SlaveReceivedDataProces = idx + 1U;
                        }
                        else
                        {
                            g_SlaveReceivedProces = (uint8_t)IDLE;
                            Usart_ClearStatusFlag(UsartPtr, USART_FLAG_LBD);
                            Usart_EnableInterrupt(UsartPtr, USART_INT_LBDIE);
                            break;
                        }
                    }
                    break;

                case (uint8_t)SEND_DATA_COMPLETED:
                    /* set lin status: successful_transfer */
                    g_SlaveReceivedProces = (uint8_t)IDLE;
                    Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
                    Usart_ClearStatusFlag(UsartPtr, USART_FLAG_LBD);
                    Usart_EnableInterrupt(UsartPtr, USART_INT_LBDIE);
                    break;
                default :
                    /* nothing */
                    break;
            }
        }
        else
        {
            /* nothing */
        }
    }
}

/*!
 * @brief       Lin Error Interrupt Processing Code functions
 *
 * @param       UsartPtr: Select the USART or the UART peripheral
 *
 * @retval      None
 *
 */
void Lin_ErrorInterrupt_ProcessingCode(USART_T* UsartPtr)
{
    /* Receiver Overrun Flag */
    if(Usart_ReadStatusFlag(UsartPtr, USART_FLAG_OVRE) == (uint8_t)SET)
    {
        /* Clear Receiver Overrun Flag */
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_OVRE);
        /* Disable Transmit Interrupt */
        Usart_DisableInterrupt(UsartPtr, USART_INT_TXBEIE);
        /* Disable Receiver Interrupt */
        Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
    }
    /* Noise Flag */
    else if(Usart_ReadStatusFlag(UsartPtr, USART_FLAG_NEF) == (uint8_t)SET)
    {
        /* Clear Receiver Overrun Flag */
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_NEF);
        /* Disable Transmit Interrupt */
        Usart_DisableInterrupt(UsartPtr, USART_INT_TXBEIE);
        /* Disable Receiver Interrupt */
        Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
    }
    /* Framing Error Flag */
    else if(Usart_ReadStatusFlag(UsartPtr, USART_FLAG_FEF) == (uint8_t)SET)
    {
        /* Clear Receiver Overrun Flag */
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_FEF);
        /* Disable Transmit Interrupt */
        Usart_DisableInterrupt(UsartPtr, USART_INT_TXBEIE);
        /* Disable Receiver Interrupt */
        Usart_DisableInterrupt(UsartPtr, USART_INT_RXBNEIE);
    }
    /* Unknown Error Interrupts */
    else
    {
        /* nothing */
    }

}

/*!
 * @brief       Master interrupt server functions
 *
 * @param       UsartPtr: Select the USART or the UART peripheral
 *
 * @retval      None
 *
 */
void Lin_MasterIsr(USART_T* UsartPtr)
{
    uint8_t ReceiveData;

    if (Usart_ReadIntFlag(UsartPtr, USART_INT_FLAG_RXBNE) == (uint8_t)SET)
    {
        ReceiveData = (uint8_t)Usart_RxData(UsartPtr);

        g_MasterReceivedOverFlag = 0 ;

        if (g_MasterReceivedProces == (uint8_t)0)
        {
            if (g_MasterReceiveDataProces < 8u)
            {
                g_MasterReceived.data[g_MasterReceiveDataProces] = ReceiveData ;
                g_MasterReceiveDataProces = g_MasterReceiveDataProces + 1u ;

                if (g_MasterReceiveDataProces == (uint8_t)8)
                {
                    g_MasterReceiveDataProces = 0 ;
                    g_MasterReceivedProces = 1 ;
                }
                else
                {
                    /* do nothing */
                }
            }
            else
            {
                /* do nothing */
            }
        }
        else
        {
            g_MasterReceived.CheckSum = ReceiveData;
            g_MasterReceivedProces = 0 ;
            g_MasterReceivedOverFlag = 1 ;
        }
    }
    else if (Usart_ReadIntFlag(UsartPtr, USART_INT_FLAG_LBD) == (uint8_t)SET)
    {
        Usart_ClearStatusFlag(UsartPtr, USART_FLAG_LBD);
    }
    else
    {
        /* do nothing */
    }
}

/**@} end of group USART_LIN_autosync_INT_Functions */
/**@} end of group USART_LIN_autosync */
/**@} end of group USART_Examples */
/**@} end of group Examples */
