/*
 * Copyright (c) 2016, NXP Semiconductors, Inc.
 * All rights reserved.
 *
 * 
 * SPDX-License-Identifier: BSD-3-Clause
 */

/**
 * This is template for main module created by New Kinetis SDK 2.x Project Wizard. Enjoy!
 **/

#include "board.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "FunctionLib.h"
#include "fsl_lin.h"
#include "fsl_debug_console.h"
#include "fsl_tpm.h"
#include "Flash_Adapter.h"
#include "TimersManager.h" 
#include "led.h"
#include "lin_cfg.h"
#include "gen_fsk_tests.h"

#if OTA_BY_CAN_LIN
#include "EEPROM.h"
#include "OtaSupport.h"
#endif

/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define SIM_LPUART_CLK_SEL_OSCERCLK_CLK                   2U  /*!< LPUART clock select: OSCERCLK clock */
#define SIM_TPM_CLK_SEL_OSCERCLK_CLK                      2U  /*!< TPM clock select: OSCERCLK clock */
#define LIN_CLOCK_NAME kCLOCK_Osc0ErClk
#define TJA_WAKEUP 1
#define TIMER_TPM 1

#define DEMO_TPM_BASEADDR TPM0
#define DEMO_TPM_IRQn TPM0_IRQn
#define DEMO_TPM_IRQHandler TPM0_IRQHandler
#define DEMO_TPM_CH_OUT_NUM 0
#define DEMO_TPM_CH_OUT kTPM_Chnl_0
#define DEMO_TPM_CH_IN kTPM_Chnl_2
#define DEMO_TPM_CH_OUT_FLG kTPM_Chnl0Flag
#define DEMO_TPM_CH_IN_FLG kTPM_Chnl2Flag
#define DEMO_TPM_CH_OUT_IRQ kTPM_Chnl0InterruptEnable
#define DEMO_TPM_CH_IN_IRQ kTPM_Chnl2InterruptEnable
/* timer frequency */
#define TIMER_FREQ CLOCK_GetFreq(kCLOCK_Osc0ErClk)
/* (timer period (us) * (timer clock frequency)(Hz)) - 1 ) */
#define MODULO_VALUE ((500U*(CLOCK_GetFreq(kCLOCK_Osc0ErClk)/1000000U))-1U)
/* nanoseconds / timer clock frequency  */
#define TIMER_1TICK_DURATION_PS (1000000000000U/TIMER_FREQ)

#define DEMO_LIN_IRQn LPUART0_LPUART1_IRQn

#define DEMO_SLPN_GPIO GPIOC
#define DEMO_SLPN_PIN 5
#define LI0_Slave 0x01


#define SLAVE_INSTANCE LI0_Slave
#define HARDWARE_INSTANCE 0U

/* auto-baudrate feature requires use of very high interrupt priority for LPUART and timer */
#define DEMO_LIN_PRIO 1U
#define DEMO_TIMER_PRIO (DEMO_LIN_PRIO+1U)
/*******************************************************************************
 * Prototypes
 ******************************************************************************/
/*!
 * This function prints response content
 * @param instance LIN instance
 * @param id frame ID
 */
#if OTA_BY_CAN_LIN
static void PrintBuffer(uint8_t instance, uint8_t id);
#endif
/*!
 * This timer returns the count of nanoseconds between two consequencing bits.
 * @param ns number of nanoseconds between two bits, return parameter
 */
void timerGetTimeIntervalCallback0(uint32_t *ns);
/*!
 * This function handles messages from low level
 * @param instance LIN instance
 * @param linState pointer to current LIN state
 */
void CallbackHandler(uint32_t instance, void * linState);
/*!
 * This function initializes master node and low level
 * @param linUserConfig pointer to user configuration structure
 * @param linCurrentState pointer to LIN low level state structure
 * @param clockSource LIN clock frequency
 */
lin_status_t SlaveInit(lin_user_config_t *linUserConfig, lin_state_t *linCurrentState, uint32_t clockSource);
/*!
 * This function calculates register values for supported baudrates
 * @param instance LIN instance
 * @param clocksSource LIN clock frequency
 * @param baudRatesVals pointer to baudrate values
 */
void CalculateBaudrates(uint32_t instance, uint32_t clocksSource, lin_baudrate_values_t *baudRatesVals);
/*!
 * This function process a frame id. If node is publisher, response is sent. If node is subscriber, response is awaited.
 * @param instance LIN instance
 * @param id frame ID
 */
void SlaveProcessId(uint8_t instance, uint8_t id);
/*!
 * This function set bus activity timeout
 * @param instance LIN instance
 */
void SlaveTimeoutService(uint8_t instance);
/*!
 * This function handle error raised by low-level
 * @param instance LIN instance
 * @param event_id ID of LIN bus event
 * @param id frame ID
 */
void SlaveHandleError(uint8_t instance, lin_event_id_t event_id, uint8_t id);
/*!
 * Updates signal, status, and flag after response is sent.
 * @param instance LIN instance
 * @param id frame ID
 */
void SlaveUpdateTx(uint8_t instance, uint8_t id);
/*!
 * This function update tx flag array after response is sent.
 * @param instance LIN instance
 * @param id frame ID
 */
void SlaveUpdateTxFlags(uint8_t instance, uint8_t id);
/*!
 * This function update signal, status, and flag after response is received.
 * @param instance LIN instance
 * @param id frame ID
 */
void SlaveUpdateRx(uint8_t instance, uint8_t id);
/*!
 * This function makes or updates unconditional frames.
 * @param instance LIN instance
 * @param id frame ID
 * @param type type of action
 */
void SlaveProcesUncdFrame(uint8_t instance, uint8_t id, uint8_t type);
/*!
 * This function returns index of array ID from RAM table.
 * @param instance LIN instance
 * @param id frame ID
 */
static inline uint8_t SlaveGetFrameIndex(uint8_t instance, uint8_t id);
/*!
 * This function returns index to baudrate values array by given baudrate
 * @param baudrate LIN baudrate
 */
#if OTA_BY_CAN_LIN
static void ResetTimerCallback(void *pParam); 
static void OtaTimeoutTimerCallback(void *pParam);
#endif
static void OtaTimeoutTimerClear(void);
static inline uint32_t CheckIndex(uint32_t baudrate);

void lin_app_process(uint8_t id, uint8_t frame_offset);

extern void ResetMCU(void); 

#if LIN_NUM_OF_MASTER_IFCS
#define LinOtaStartCallback  lin_ota_start
#else
#define LinOtaStartCallback  NULL
#endif

/************************************************************************************
*************************************************************************************
* Private type definitions and macros
*************************************************************************************
************************************************************************************/
/* Size of each ota block */
#define LIN_OTA_BLOCK_SIZE       1024U

/* lin frames of each ota block */
#define LIN_OTA_FRAMES_OF_BLOCK  (LIN_OTA_BLOCK_SIZE / 8)

typedef enum 
{
    LIN_APP_STATUS_IDLE = 0x00,
    LIN_APP_STATUS_OTA_READY,
    LIN_APP_STATUS_OTA_RUNNING,
    LIN_APP_STATUS_OTA_FINISH,
    LIN_APP_STATUS_OTA_ABORT,
        
    LIN_APP_STATUS_LM_READY,        //5
    LIN_APP_STATUS_LM_RUNNING,
    LIN_APP_STATUS_LM_FINISH,
    LIN_APP_STATUS_LM_ABORT
} lin_app_status_t;

typedef enum
{
    LIN_APP_CMD_NONE = 0x00,
    LIN_APP_CMD_OTA_START,
    LIN_APP_CMD_OTA_CONTINUE,
    LIN_APP_CMD_OTA_END,
    
    LIN_APP_CMD_LM_START,       //4  link monitor
    LIN_APP_CMD_LM_CONTINUE,
    LIN_APP_CMD_LM_END,
} lin_app_cmd_c;

/*******************************************************************************
 * Variables
 ******************************************************************************/
/* storage for timer counter */
uint16_t timerCounterValue[2] = {0u};
/* number of timer overflow */
volatile uint32_t timerOverflowInterruptCount = 0u;
/* buffer handling messages between lower and higher level communication */
static uint8_t g_linResponseBuffer[LIN_NUM_OF_IFCS][10];
/* supported baudrate for autobaudrate feature */
uint32_t baudRateArray[LIN_NUM_OF_SUPP_BAUDRATES] = {2400,4800,9600,14400,19200};
lin_baudrate_values_t g_baudRatesValues[LIN_NUM_OF_SUPP_BAUDRATES];
/* maximal header duration time */
static volatile  uint16_t linMaxHeaderTimeoutVal[LIN_NUM_OF_IFCS];
/* maximal response duration time */
static uint16_t linMaxResTimeoutVal[LIN_NUM_OF_IFCS];
#if OTA_BY_CAN_LIN
/* single shot timer to reset MCU */
static tmrTimerID_t mResetTimerId = gTmrInvalidTimerID_c;
/* interval timer to check the ota status */
static tmrTimerID_t mOtaTimeoutTimerId = gTmrInvalidTimerID_c;
#endif
lin_user_config_t linUserConfigSlave;
lin_state_t linCurrentState;
#if OTA_BY_CAN_LIN

static uint8_t eeprom_write_buffer[LIN_OTA_BLOCK_SIZE] = {0};
static uint16_t lin_ota_rx_frame_offset = 0;
static uint32_t lin_ota_image_offset = 0;

static uint8_t lin_ota_total_block_numbers = 0;
static uint8_t lin_ota_previous_block_cnt = 0xFF;
static uint8_t lin_ota_timeout_cnt = 0;
#endif

static uint8_t lin_ota_block_cnt = 0;
static lin_app_status_t g_lin_app_status = LIN_APP_STATUS_IDLE;
////link monitor
uint8_t gLMConnectionParaBlockNum = 0; 


extern uint32_t g_lin_ota_image_length;
extern uint32_t g_lin_write_flash_offset;
extern bool_t mNewImageReady;


/*******************************************************************************
 * Code
 ******************************************************************************/
static inline uint32_t CheckIndex(uint32_t baudrate)
{
    uint32_t retval;
    switch(baudrate)
    {
        case 2400:
            retval = (uint32_t)kLIN_BAUD_2400;
        break;
        case 4800:
            retval = (uint32_t)kLIN_BAUD_4800;
        break;
        case 9600:
            retval = (uint32_t)kLIN_BAUD_9600;
        break;
        case 14400:
            retval = (uint32_t)kLIN_BAUD_14400;
        break;
        case 19200:
            retval = (uint32_t)kLIN_BAUD_19200;
        break;
        default:
            retval = 0xFF;
        break;
    }
    return retval;
}


static inline uint8_t SlaveGetFrameIndex(uint8_t instance, uint8_t id)
{
    uint8_t retVal = 0xFF;
    uint8_t i;

    const lin_protocol_user_config_t *prot_user_config_ptr = &g_lin_protocol_user_cfg_array[HARDWARE_INSTANCE];

    for (i = prot_user_config_ptr->number_of_configurable_frames; i > 0U; i--)
    {
        if (prot_user_config_ptr->list_identifiers_RAM_ptr[i] == id)
        {
            retVal = i + prot_user_config_ptr->frame_start - 1U;
            break;
        }
    }
    return retVal;
} 
#if OTA_BY_CAN_LIN
static void PrintBuffer(uint8_t instance, uint8_t id)
{
    uint8_t i = 0;
    uint8_t frame_index;
    uint8_t frame_len;
    uint8_t print_byte;

    const lin_protocol_user_config_t *prot_user_config_ptr = &g_lin_protocol_user_cfg_array[HARDWARE_INSTANCE];
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];

    /* get index of frame in RAM table */
    frame_index = SlaveGetFrameIndex(instance, id);
    /* get length of frame in RAM table */
    frame_len = prot_user_config_ptr->frame_tbl_ptr[frame_index].frm_len;
    /* print whole response from buffer */

    while (i < frame_len)
    {
        print_byte = prot_state_ptr->response_buffer_ptr[i++];
        PRINTF("%02X ", print_byte);
    }
    PRINTF("\r\n");
}
#endif

#if (defined(TIMER_TPM) && TIMER_TPM)
/*!
 * This interrupt checks for communication timeout and falling edge detection.
 * This interrupt is also invoked every 500us on timer overflow.
 */
void DEMO_TPM_IRQHandler(void)
{    
    uint32_t counterVal;
    if(TPM_GetStatusFlags(DEMO_TPM_BASEADDR) & DEMO_TPM_CH_IN_FLG)
    {
        TPM_ClearStatusFlags(DEMO_TPM_BASEADDR, DEMO_TPM_CH_IN_FLG);
        if(LIN_AutoBaudCapture(SLAVE_INSTANCE) == LIN_SUCCESS)
        {
          TPM_DisableInterrupts(DEMO_TPM_BASEADDR, DEMO_TPM_CH_IN_FLG);
        }      
    }
    
    if(TPM_GetStatusFlags(DEMO_TPM_BASEADDR) & DEMO_TPM_CH_OUT_FLG)
    {
        TPM_ClearStatusFlags(DEMO_TPM_BASEADDR, DEMO_TPM_CH_OUT_FLG);
        counterVal = (uint16_t)(DEMO_TPM_BASEADDR->CNT);
        (DEMO_TPM_BASEADDR->CONTROLS[DEMO_TPM_CH_OUT_NUM].CnV) = counterVal + MODULO_VALUE;
        SlaveTimeoutService(SLAVE_INSTANCE);
    }

    if(TPM_GetStatusFlags(DEMO_TPM_BASEADDR) & kTPM_TimeOverflowFlag)
    {
        /* Clear interrupt flag.*/
        TPM_ClearStatusFlags(DEMO_TPM_BASEADDR, kTPM_TimeOverflowFlag);
        /* increase number of overflow count */
        timerOverflowInterruptCount++;      
    }    
}
#endif

#if defined(TIMER_TPM) && TIMER_TPM
void timerGetTimeIntervalCallback0(uint32_t *ns)
{
    uint16_t counterMaxValue = 0xFFFFU;
    uint32_t currentOverflowCount = timerOverflowInterruptCount;

    /* check current CNT value */
    timerCounterValue[1] = (uint16_t)(DEMO_TPM_BASEADDR->CNT);
    /* calculate number of ns from current and previous count value */
    if(timerCounterValue[1]>=timerCounterValue[0])
    {
        /* Correction: Timer overflow interrupt should be delayed by other processes
         * if TOF is set, timer overflow occured so increase the number of interrupt and clear a flag
         * */
        if(TPM_GetStatusFlags(DEMO_TPM_BASEADDR) & kTPM_TimeOverflowFlag)
        {
            TPM_ClearStatusFlags(DEMO_TPM_BASEADDR, kTPM_TimeOverflowFlag);
            currentOverflowCount++;
        }
        *ns = (uint32_t)(((uint32_t)((timerCounterValue[1] - timerCounterValue[0])*TIMER_1TICK_DURATION_PS)/1000U) + (currentOverflowCount*counterMaxValue));
    }
    else /* (timerCounterValue[1]<timerCounterValue[0]) */
    {
        *ns = ((uint32_t)(((counterMaxValue - timerCounterValue[0] + timerCounterValue[1]))*TIMER_1TICK_DURATION_PS)/1000U);
        if(TPM_GetStatusFlags(DEMO_TPM_BASEADDR) & kTPM_TimeOverflowFlag)
        {
            TPM_ClearStatusFlags(DEMO_TPM_BASEADDR, kTPM_TimeOverflowFlag);
            currentOverflowCount++;
        }
        if(currentOverflowCount > 0U)
        {
            *ns += (uint32_t)((currentOverflowCount-1U)*counterMaxValue);
        }
    }

    /* set current count value to previous count value */
    timerCounterValue[0] = timerCounterValue[1];
    /* clear timerOverflowInterruptCount mark */
    timerOverflowInterruptCount = 0u;
}
#endif

void CallbackHandler(uint32_t instance, void * linState)
{ 
    lin_state_t * linCurrentState = (lin_state_t *) linState;
    lin_user_config_t *linUserConfig = g_linUserconfigPtr[instance];
    uint8_t bytesRemaining;

    const lin_protocol_user_config_t *prot_user_config_ptr = &g_lin_protocol_user_cfg_array[HARDWARE_INSTANCE];
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];
    uint32_t index; 

    /* check timeout flag */
    if(linCurrentState->timeoutCounterFlag == (bool)1U)
    {
        /* set timeout error event id */
        linCurrentState->currentEventId = LIN_TIMEOUT_ERROR;
    }
    
    /* check event id */
    switch (linCurrentState->currentEventId)
    {
        case LIN_PID_OK:
            /* process PID of frame */
            SlaveProcessId(instance, linCurrentState->currentId);
            break;
        case LIN_RECV_BREAK_FIELD_OK:
            /* reload frame timeout */
            prot_state_ptr->frame_timeout_cnt = linMaxResTimeoutVal[HARDWARE_INSTANCE] + linMaxHeaderTimeoutVal[HARDWARE_INSTANCE];
            break;
        case LIN_TX_COMPLETED:
            /* update protocol state */
            SlaveUpdateTx(instance, linCurrentState->currentId);
            break;
        case LIN_RX_COMPLETED:
            /* update protocol state */
            SlaveUpdateRx(instance, linCurrentState->currentId);             
         
            break;
        case LIN_BUS_ACTIVITY_TIMEOUT:
        case LIN_TIMEOUT_ERROR:
            /* check for remaining bytes */
            (void)LIN_GetReceiveStatus(instance, &bytesRemaining);
            if (linCurrentState->rxSize > bytesRemaining)
            {
                /* report timeout to higher level */
                SlaveHandleError(instance, LIN_NO_DATA_TIMEOUT, linCurrentState->currentId);
            }
            break;
        case LIN_PID_ERROR:
        case LIN_FRAME_ERROR:
        case LIN_CHECKSUM_ERROR:
        case LIN_READBACK_ERROR:
        case LIN_RECV_SYNC_ERROR:
            /* report error to higher level */
            SlaveHandleError(instance, linCurrentState->currentEventId, linCurrentState->currentId);
            break;
        case LIN_BAUDRATE_ADJUSTED:
            index = CheckIndex(linUserConfig->baudRate);
            if(index != 0xFF)
            {
                LIN_SetBaudrate(SLAVE_INSTANCE, g_baudRatesValues[index].osrValue, g_baudRatesValues[index].sbrValue);
            }
            /* change protocol baudrate */
            prot_state_ptr->baud_rate = linUserConfig->baudRate;
            /* update protocol timeout values */
            prot_state_ptr->frame_timeout_cnt = LIN_CalcMaxResTimeoutCnt(prot_state_ptr->baud_rate, 8U);
            break;
        case LIN_WAKEUP_SIGNAL:
        case LIN_NO_EVENT:
        case LIN_RECV_SYNC_OK:
        case LIN_NO_DATA_TIMEOUT:
        default:
            /* do nothing */
        break;
    }
    prot_state_ptr->idle_timeout_cnt = prot_user_config_ptr->max_idle_timeout_cnt;
}

lin_status_t SlaveInit(lin_user_config_t *linUserConfig, lin_state_t *linCurrentState, uint32_t clockSource)
{
    lin_status_t status = LIN_SUCCESS;
    const lin_protocol_user_config_t  *prot_user_config_ptr = &g_lin_protocol_user_cfg_array[HARDWARE_INSTANCE];
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];
    /* initialize protocol variables */

    if(clockSource == 0)
    {
        /* with no clock report error */
        status = LIN_ERROR;
    }
    else
    {
        /* initialize LIN low lovel */
        status = LIN_Init(SLAVE_INSTANCE,  linUserConfig, linCurrentState,  clockSource);

        /* make hardware instance visible to lower level */
        linUserConfig->hardware_instance = HARDWARE_INSTANCE;
        /* register time interval callback */
        linUserConfig->timerGetTimeIntervalCallback = &timerGetTimeIntervalCallback0;
        /* install callback service */
        LIN_InstallCallback(SLAVE_INSTANCE, CallbackHandler);

        prot_state_ptr->baud_rate = linUserConfig->baudRate;
        prot_state_ptr->response_buffer_ptr = g_linResponseBuffer[HARDWARE_INSTANCE];
        prot_state_ptr->idle_timeout_cnt = prot_user_config_ptr->max_idle_timeout_cnt;

        if(linUserConfig->autobaudEnable == true)
        {
            /* in case of auto-baudrate feature */
            linMaxResTimeoutVal[HARDWARE_INSTANCE] = LIN_CalcMaxResTimeoutCnt(2400U, 8U);
            prot_state_ptr->frame_timeout_cnt = linMaxResTimeoutVal[HARDWARE_INSTANCE];
            linMaxHeaderTimeoutVal[HARDWARE_INSTANCE] = LIN_CalcMaxHeaderTimeoutCnt(2400U);
            /* Set the highest priority */
            NVIC_SetPriority(DEMO_LIN_IRQn, DEMO_LIN_PRIO);
        }
        else
        {
            /* if auto-baudrate feature is used, enhance timeout for sync field */
            linMaxResTimeoutVal[HARDWARE_INSTANCE] = LIN_CalcMaxResTimeoutCnt(prot_state_ptr->baud_rate, 8U);
            prot_state_ptr->frame_timeout_cnt = linMaxResTimeoutVal[HARDWARE_INSTANCE];
            linMaxHeaderTimeoutVal[HARDWARE_INSTANCE] = LIN_CalcMaxHeaderTimeoutCnt(prot_state_ptr->baud_rate);
        }
    }
    return status;
}

void CalculateBaudrates(uint32_t instance, uint32_t clocksSource, lin_baudrate_values_t *baudRatesVals)
{
    uint8_t sbrt;
    uint32_t tempBaudrate;
    uint32_t *osr;
    uint16_t *sbr;

    /* calculate OSR and SBR register valus for all supported baudrates for autobaudrate feature */
    for(sbrt = 0; sbrt<LIN_NUM_OF_SUPP_BAUDRATES; sbrt++)
    {
        tempBaudrate = baudRatesVals[sbrt].baudRate = baudRateArray[sbrt];
        sbr = &baudRatesVals[sbrt].sbrValue;
        osr = &baudRatesVals[sbrt].osrValue;
        LIN_CalculateBaudrate(instance, tempBaudrate, clocksSource, osr, sbr);
    }
} 

void SlaveProcessId(uint8_t instance, uint8_t id)
{
    uint8_t frame_index;
    uint32_t response_length;
    uint32_t lin_max_frame_res_timeout_val;
    const lin_frame_struct *lin_frame_ptr;

    const lin_protocol_user_config_t *prot_user_config_ptr = &g_lin_protocol_user_cfg_array[HARDWARE_INSTANCE];
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];

    /* get index of current frame from RAM table */
    frame_index = SlaveGetFrameIndex(instance, id);

    if(frame_index != 0xFF)
    {
        prot_state_ptr->go_to_sleep_flg = (bool)0U;
        /* get frame buffer pointer */
        lin_frame_ptr = &(prot_user_config_ptr->frame_tbl_ptr[frame_index]);
        /* check if id represents a supported frame */
        if ((id > 0) && (id < 0x3B))
        {
            response_length = lin_frame_ptr->frm_len;
            lin_max_frame_res_timeout_val = LIN_CalcMaxResTimeoutCnt(prot_state_ptr->baud_rate, response_length);

            /* check response type */
            if (LIN_RES_PUB == lin_frame_ptr->frm_response)
            {
                /* make unconditional frame */
                SlaveProcesUncdFrame(instance, id, LIN_MAKE_UNCONDITIONAL_FRAME);

                if ((response_length <= 8U) && (response_length > 0U))
                {
                    /* Set response */
                    LIN_SetResponse(instance, &(prot_state_ptr->response_buffer_ptr[0]), response_length, lin_max_frame_res_timeout_val);
                }
            }
            else
            {
                if ((response_length <= 8U) && (response_length != 0U))
                {
                    /* wait for response */
                    LIN_RxResponse(instance, &(prot_state_ptr->response_buffer_ptr[0]), response_length, lin_max_frame_res_timeout_val);
                }
            }
        }
        /* frame is not supported */
        else
        {
            /* ignore frame */
            LIN_IgnoreResponse(instance);
        }
    }
    /* unknown id */
    else
    {
        /* ignore frame */
        LIN_IgnoreResponse(instance);
    }
}

void SlaveProcesUncdFrame(uint8_t instance, uint8_t id, uint8_t type)
{
    uint8_t frame_index;
    uint8_t *response_buffer_ptr;
    uint8_t i;
    uint8_t frame_byte_offset;
    const lin_node_attribute *node_attr_ptr;

    const lin_protocol_user_config_t *prot_user_config_ptr = &g_lin_protocol_user_cfg_array[HARDWARE_INSTANCE];
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];

    /* get index of current frame from RAM table */
    frame_index = SlaveGetFrameIndex(instance, id);

    /* get protocol response buffer */
    if(frame_index != 0xFF)
    {
        response_buffer_ptr = prot_state_ptr->response_buffer_ptr;
        /* get protocol response buffer length */
        prot_state_ptr->response_length = prot_user_config_ptr->frame_tbl_ptr[frame_index].frm_len;
        /* get protocol response buffer offset */
        frame_byte_offset = prot_user_config_ptr->frame_tbl_ptr[frame_index].frm_offset;

        /* check for frame type */
        if (LIN_MAKE_UNCONDITIONAL_FRAME == type)
        {
            node_attr_ptr = &g_lin_node_attribute_array[HARDWARE_INSTANCE];

            for(i = 0U;i < node_attr_ptr->num_frame_have_esignal;i++)
            {
              /* Check if frame contains error signal */
              if(id == node_attr_ptr->resp_err_frm_id_ptr[i])
              {
                  prot_state_ptr->transmit_error_resp_sig_flg = (bool)1U;
                  break;
              }
            }

            lin_app_process(id, frame_byte_offset);
            
             /* Get data from configuration buffer */
            for (i = 0U; i < prot_state_ptr->response_length; i++)
            {
                response_buffer_ptr[i] = g_lin_frame_data_buffer[frame_byte_offset + i];
            }
        }
        /* update unconditional frame */
        else
        {
            for (i = 0U; i < prot_state_ptr->response_length; i++)
            {
                /* Set data of configuration buffer */
                g_lin_frame_data_buffer[frame_byte_offset + i] = response_buffer_ptr[i];
            }
            lin_app_process(id, frame_byte_offset);    
        }
    }
}
void SlaveUpdateTx(uint8_t instance, uint8_t id)
{
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];

    /* Set successful transfer */
    prot_state_ptr->successful_transfer = 1U;

    if (prot_state_ptr->num_of_processed_frame < 0xFFU)
    {
        /* increase a number of processed frames */
        prot_state_ptr->num_of_processed_frame++;
    }
    /* check whether error signal was transmitted */
    if ((bool)1U == prot_state_ptr->transmit_error_resp_sig_flg)
    {
        /* Set error in response */
        prot_state_ptr->error_in_response = 0U;
        /* clear error flag */
        prot_state_ptr->transmit_error_resp_sig_flg = (bool)0U;
    }
    /* check for valid id of unconditional frame */
    if ((id > 0U) && (id < 0x3BU))
    {
        /* increase a number of succesfull frames */
        prot_state_ptr->num_of_successfull_frame++;
        //PrintBuffer(instance, id);
    }
}

void SlaveUpdateRx(uint8_t instance, uint8_t id)
{
    uint8_t frame_index, flag_offset, flag_size, i;
    const lin_protocol_user_config_t *prot_user_config_ptr = &g_lin_protocol_user_cfg_array[HARDWARE_INSTANCE];
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];

    /* Set successful transfer */
    prot_state_ptr->successful_transfer = 1U;

    if (prot_state_ptr->num_of_processed_frame < 0xFFU)
    {
        /* increase a number of processed frames */
        prot_state_ptr->num_of_processed_frame++;
    }

    frame_index = SlaveGetFrameIndex(instance, id);
    if ((id > 0U) && (id < 0x3BU))
    {
        /* increase a number of succesfull frames */
        prot_state_ptr->num_of_successfull_frame++;
        /* make unconditional frame */
        SlaveProcesUncdFrame(instance, id, LIN_UPDATE_UNCONDITIONAL_FRAME);

        /* Update rx frame flags */
        flag_offset = prot_user_config_ptr->frame_tbl_ptr[frame_index].flag_offset;
        flag_size = prot_user_config_ptr->frame_tbl_ptr[frame_index].flag_size;
        for (i = 0U; i < flag_size; i++)
        {
            g_lin_flag_handle_tbl[flag_offset] = 0xFFU;
            flag_offset++;
        }
        /* print received response */
        //PrintBuffer(instance, id);
    }
    else
    {
        ; /* misra compliance */
    }
}

void SlaveTimeoutService(uint8_t instance)
{

    lin_state_t *linState = g_linStatePtr[SLAVE_INSTANCE];
    const lin_protocol_user_config_t  *prot_user_config_ptr = &g_lin_protocol_user_cfg_array[HARDWARE_INSTANCE];
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];

    /* check if timeout occurs during communication */
    LIN_TimeoutService(instance);

    /* check for current node state */
    switch (linState->currentNodeState)
    {
        case LIN_NODE_STATE_IDLE:
            /* check if idle timeout runs out */
            if (!(prot_state_ptr->idle_timeout_cnt-- > 0U))
            {
                /* Set go to sleep flag */
                prot_state_ptr->go_to_sleep_flg = (bool)1U;

                /* Put current node to Idle state, reset idle timeout count */
                prot_state_ptr->idle_timeout_cnt = prot_user_config_ptr->max_idle_timeout_cnt;

                /* Put current node to sleep mode */
                (void)LIN_GoToSleepMode(instance);
            }
            break;
        case LIN_NODE_STATE_RECV_PID:
        case LIN_NODE_STATE_SEND_PID:
        case LIN_NODE_STATE_RECV_SYNC:
            /* timeout send has occurred - change state of the node and inform core */
            if (!(prot_state_ptr->frame_timeout_cnt -- > 0U))
            {
                /* Go to idle state */
                (void)LIN_GotoIdleState(instance);

                /* Reset frame count timeout */
                prot_state_ptr->frame_timeout_cnt = linMaxResTimeoutVal[HARDWARE_INSTANCE];
            }
            break;
        case LIN_NODE_STATE_SEND_DATA:
        case LIN_NODE_STATE_SEND_DATA_COMPLETED:
            /* timeout send has occurred - change state of the node and inform core */
            if (!(prot_state_ptr->frame_timeout_cnt-- >0U ))
            {
                /* Abort frame data transferring */
                (void)LIN_AbortTransferData(instance);

                /* Reset frame count timeout */
                prot_state_ptr->frame_timeout_cnt = linMaxResTimeoutVal[HARDWARE_INSTANCE];
            }
            break;
        case LIN_NODE_STATE_UNINIT:
        case LIN_NODE_STATE_SLEEP_MODE:
        case LIN_NODE_STATE_SEND_BREAK_FIELD:
        case LIN_NODE_STATE_RECV_DATA:
        case LIN_NODE_STATE_RECV_DATA_COMPLETED:
        default:
            /* do nothing */
            break;
    }
}

void SlaveHandleError(uint8_t instance, lin_event_id_t event_id, uint8_t id)
{  
    lin_protocol_state_t *prot_state_ptr = &g_lin_protocol_state_array[HARDWARE_INSTANCE];

    /* increase a number of processed frames */
    if (prot_state_ptr->num_of_processed_frame < 0xFFU)
    {
        prot_state_ptr->num_of_processed_frame++;
    }

    switch (event_id)
    {
        /* PID error */
        case LIN_PID_ERROR:
        case LIN_FRAME_ERROR:
        case LIN_CHECKSUM_ERROR:
        case LIN_READBACK_ERROR:
        case LIN_RECV_SYNC_ERROR:
            /* Set response error */
            prot_state_ptr->error_in_response += 1U;
            break;
        case LIN_NO_DATA_TIMEOUT:
            /* Set timeout error */
            prot_state_ptr->timeout_in_response += 1U;
            break;
        default:
            /* do nothing */
            break;
    }  
} 

void lin_app_process(uint8_t id, uint8_t frame_offset)
{
    uint8_t *frame_data = g_lin_frame_data_buffer;
    
    switch (id)
    {
        case gID_Cmd_c:
        {
#if OTA_BY_CAN_LIN
            if (LIN_APP_CMD_OTA_START == frame_data[frame_offset])
            {
                if (LIN_APP_STATUS_IDLE == g_lin_app_status){
                    g_lin_app_status = LIN_APP_STATUS_OTA_READY;
                }
                if(OTA_InitExternalMemory() != gOtaSucess_c){
                    PRINTF("eeprom init error\r\n");
                }
#if (gEepromType_d == gEepromDevice_InternalFlash_c)
                uint8_t start_marker[gBootData_Marker_Size_c] = {gBootData_StartMarker_Value_c};                   
                /* Write the Start marker at the beginning of the internal storage. */
                EEPROM_WriteData(gBootData_Marker_Size_c, gBootData_StartMarker_Offset_c, start_marker);
                PRINTF("eeprom start marker written\r\n");
#endif
                lin_ota_image_offset = g_lin_write_flash_offset;
                lin_ota_rx_frame_offset = 0;                
                TMR_StartLowPowerTimer(mOtaTimeoutTimerId, gTmrLowPowerIntervalMillisTimer_c, 200, OtaTimeoutTimerCallback, NULL);
            }
            else if (LIN_APP_CMD_OTA_END == frame_data[frame_offset])
            {
                if (LIN_APP_STATUS_OTA_FINISH == g_lin_app_status)
                {                    
                    if (lin_ota_block_cnt == (lin_ota_total_block_numbers - 1))
                    {
                        PRINTF("write the last block\r\n");
                        g_lin_write_flash_offset = gBootData_ImageLength_Offset_c + lin_ota_block_cnt * LIN_OTA_BLOCK_SIZE;
                        if (lin_ota_rx_frame_offset == LIN_OTA_BLOCK_SIZE)
                        {
                            //PRINTF("length: %d\r\n", LIN_OTA_BLOCK_SIZE);
                            EEPROM_WriteData(LIN_OTA_BLOCK_SIZE, g_lin_write_flash_offset, eeprom_write_buffer);
                        }
                        else if (lin_ota_rx_frame_offset < LIN_OTA_BLOCK_SIZE)
                        {
                            //PRINTF("length: %d\r\n", lin_ota_rx_frame_offset);
                            EEPROM_WriteData(lin_ota_rx_frame_offset, g_lin_write_flash_offset, eeprom_write_buffer);
                            FLib_MemSet(&(eeprom_write_buffer[lin_ota_rx_frame_offset]), 0xFF, LIN_OTA_BLOCK_SIZE - lin_ota_rx_frame_offset);
                            /*EEPROM_ReadData(lin_ota_rx_frame_offset, g_lin_write_flash_offset, read_buf);
                            for (i = 0; i < lin_ota_rx_frame_offset; i++)
                                PRINTF("%02X ", read_buf[i]);
                            PRINTF("\r\n");*/
                        }
                        else
                        {
                            PRINTF("invalid offset!!\r\n");
                            lin_ota_rx_frame_offset = 0;
                            g_lin_app_status = LIN_APP_STATUS_OTA_ABORT;
                        }                                                  
                    }                           
                }
                else
                {
                    g_lin_app_status = LIN_APP_STATUS_OTA_ABORT;
                }

                if (LIN_APP_STATUS_OTA_FINISH == g_lin_app_status)
                {
                    PRINTF("\r\nready to reset and switch\r\n");
                    TMR_StartSingleShotTimer(mResetTimerId, 20, ResetTimerCallback, NULL);
                }
            }
            else if (LIN_APP_CMD_OTA_CONTINUE == frame_data[frame_offset])
            {
                if (((lin_ota_previous_block_cnt == 0xFF) && (lin_ota_block_cnt == 0))
                    || (lin_ota_previous_block_cnt < lin_ota_block_cnt))
                {
                    if (lin_ota_block_cnt < (lin_ota_total_block_numbers - 1))
                    {
                        if (lin_ota_rx_frame_offset == LIN_OTA_BLOCK_SIZE)
                        {
                            g_lin_write_flash_offset = gBootData_ImageLength_Offset_c + lin_ota_block_cnt * LIN_OTA_BLOCK_SIZE;
                            //PRINTF("write offset: %d\r\n", g_lin_write_flash_offset);
                            ee_err_t ec = EEPROM_WriteData(LIN_OTA_BLOCK_SIZE, g_lin_write_flash_offset, eeprom_write_buffer);
                            /*PRINTF("write result: %d\r\n", ec);
                            EEPROM_ReadData(LIN_OTA_BLOCK_SIZE, g_lin_write_flash_offset, read_buf);
                            for (i = 0; i < LIN_OTA_BLOCK_SIZE; i ++)
                                PRINTF("%02X ", read_buf[i]);*/
                            PRINTF("block %d written finished\r\n", lin_ota_block_cnt);
                            lin_ota_previous_block_cnt = lin_ota_block_cnt;
                            lin_ota_block_cnt ++;
                        }
                    }
                    else
                    {
                        g_lin_app_status = LIN_APP_STATUS_OTA_ABORT;
                    }
                }

                lin_ota_image_offset = gBootData_ImageLength_Offset_c + lin_ota_block_cnt * LIN_OTA_BLOCK_SIZE;
                lin_ota_rx_frame_offset = 0;
            }
#endif
            if (LIN_APP_CMD_LM_START == frame_data[frame_offset])
            {
                if (LIN_APP_STATUS_IDLE == g_lin_app_status)
                {
                    g_lin_app_status = LIN_APP_STATUS_LM_READY;
                    gLMConnectionParaBlockNum = 0;
                    PRINTF("LIN_APP_CMD_LM_START\r\n");
                }
                else
                {
                    PRINTF("g_lin_app_status error\r\n");
                }
            }
            else if (LIN_APP_CMD_LM_CONTINUE == frame_data[frame_offset])
            {
                gLMConnectionParaBlockNum++;
                PRINTF("LIN_APP_CMD_LM_CONTINUE\r\n");
            }
            else if (LIN_APP_CMD_LM_END == frame_data[frame_offset])
            {
                PRINTF("LIN_APP_CMD_LM_END\r\n");
                g_lin_app_status = LIN_APP_STATUS_LM_FINISH;

                GfskApp_StartLM();   
            }
            
            OtaTimeoutTimerClear();
        }
            break;

        case gID_GetStatus_c:
        {
//            PRINTF("gID_GetStatus_c\r\n");
            frame_data[frame_offset] = g_lin_app_status;
            if (LIN_APP_STATUS_LM_READY > g_lin_app_status){
                frame_data[frame_offset + 1] = lin_ota_block_cnt;
            }else{
                frame_data[frame_offset + 1] = gLMConnectionParaBlockNum;  
            }
        }
            break;

        case gID_Data_c:
        {
#if OTA_BY_CAN_LIN
            if (LIN_APP_STATUS_OTA_READY == g_lin_app_status)
            {
                g_lin_app_status = LIN_APP_STATUS_OTA_RUNNING;
                g_lin_write_flash_offset = gBootData_ImageLength_Offset_c;
            }
#endif
            if (LIN_APP_STATUS_LM_READY == g_lin_app_status)
            {
                g_lin_app_status = LIN_APP_STATUS_LM_RUNNING;
            }
#if OTA_BY_CAN_LIN            
            if (LIN_APP_STATUS_OTA_RUNNING == g_lin_app_status)
            {
                if (lin_ota_image_offset == gBootData_ImageLength_Offset_c)
                {
                    g_lin_ota_image_length = frame_data[frame_offset]
                        + (frame_data[frame_offset + 1] << 8)
                        + (frame_data[frame_offset + 2] << 16)
                        + gBootData_Image_Offset_c;
                    PRINTF("receive image length: %d\r\n", g_lin_ota_image_length);
                    if (g_lin_ota_image_length % LIN_OTA_BLOCK_SIZE)
                    {
                        lin_ota_total_block_numbers = (g_lin_ota_image_length / LIN_OTA_BLOCK_SIZE) + 1;
                    }
                    else
                    {
                        lin_ota_total_block_numbers = g_lin_ota_image_length / LIN_OTA_BLOCK_SIZE;
                    }
                    PRINTF("total block numbers: %d\r\n", lin_ota_total_block_numbers);                    
                }

                //PRINTF("i:%d ", lin_ota_image_offset);
                //PRINTF("f:%d ", lin_ota_rx_frame_offset);
                if ((lin_ota_image_offset + 8) <= g_lin_ota_image_length)
                {
                    if ((lin_ota_rx_frame_offset + 8) <= LIN_OTA_BLOCK_SIZE)
                    {
                        FLib_MemCpy(&(eeprom_write_buffer[lin_ota_rx_frame_offset]), &(frame_data[frame_offset]), 8);
                        lin_ota_rx_frame_offset += 8;
                        lin_ota_image_offset += 8;
                        if (lin_ota_image_offset == g_lin_ota_image_length)
                        {
                            g_lin_app_status = LIN_APP_STATUS_OTA_FINISH;
                        }
                    }
                    else
                    {
                        PRINTF("invalid frame offest!!\r\n");
                        g_lin_app_status = LIN_APP_STATUS_OTA_ABORT;
                    }
                }
                else if (lin_ota_image_offset < g_lin_ota_image_length)
                {
                    if ((lin_ota_rx_frame_offset + 8) <= LIN_OTA_BLOCK_SIZE)
                    {
                        uint8_t len = g_lin_ota_image_length - lin_ota_image_offset;
                        uint8_t last_frame[8] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
                        FLib_MemCpy(last_frame, &(frame_data[frame_offset]), len);
                        FLib_MemCpy(&(eeprom_write_buffer[lin_ota_rx_frame_offset]), last_frame, 8);
                        lin_ota_rx_frame_offset += 8;
                        lin_ota_image_offset = g_lin_ota_image_length;
                        g_lin_app_status = LIN_APP_STATUS_OTA_FINISH;
                    }
                    else
                    {
                        PRINTF("invalid frame offest!!\r\n");
                        g_lin_app_status = LIN_APP_STATUS_OTA_ABORT;                        
                    }
                }
                else
                {
                    PRINTF("invalid image offest!!\r\n");
                    g_lin_app_status = LIN_APP_STATUS_OTA_ABORT;
                }
            }
#endif    
            PRINTF("gID_Data_c\r\n");
            if (LIN_APP_STATUS_LM_RUNNING == g_lin_app_status)
            {
//                PRINTF("gID_Data_c, BlockNum:%d\r\n", gLMConnectionParaBlockNum);
                switch(gLMConnectionParaBlockNum)
                {
                    case 0:
                    {
                        mLMTrackConnStatus.id = frame_data[frame_offset];
                        mLMTrackConnStatus.status = frame_data[frame_offset+1];

                        gLMPara.CI = (uint16_t)frame_data[frame_offset+2] << 8;
                        gLMPara.CI += frame_data[frame_offset+3];
                        gLMPara.hopIncrement = frame_data[frame_offset+4];                        
                    }
                    break;
                    case 1:
                    {      
                        gLMPara.crcSeed = frame_data[frame_offset] << 24;
                        gLMPara.crcSeed |= frame_data[frame_offset+1] << 16;
                        gLMPara.crcSeed |= frame_data[frame_offset+2] << 8;
                        gLMPara.crcSeed |= frame_data[frame_offset+3] << 0;
                        gLMPara.syncAddress = frame_data[frame_offset+4] << 24;
                        gLMPara.syncAddress |= frame_data[frame_offset+5] << 16;
                        gLMPara.syncAddress |= frame_data[frame_offset+6] << 8;
                        gLMPara.syncAddress |= frame_data[frame_offset+7] << 0;
                    }
                    break;          
                    default:
                    break;
                } 
            }
            else if (LIN_APP_STATUS_LM_FINISH == g_lin_app_status)
            {
                g_lin_app_status = LIN_APP_STATUS_IDLE;                    
            }
            
            OtaTimeoutTimerClear();
        }
            break;
            
        default:
            break;
    }
}
#if OTA_BY_CAN_LIN
static void ResetTimerCallback(void *pParam)
{
    mNewImageReady = TRUE;
    OTA_SetNewImageFlag();
    ResetMCU();     
}

static void OtaTimeoutTimerCallback(void *pParam)
{
    lin_ota_timeout_cnt ++;
    if (lin_ota_timeout_cnt >= 10)
    {
        PRINTF("lin ota timeout, reset related variables\r\n");
        lin_ota_timeout_cnt = 0;
        g_lin_app_status = LIN_APP_STATUS_IDLE;

        lin_ota_block_cnt = 0;
        lin_ota_image_offset = 0;
        lin_ota_rx_frame_offset = 0;        
        g_lin_ota_image_length = 0;
        g_lin_write_flash_offset = gBootData_ImageLength_Offset_c;
        FLib_MemSet(eeprom_write_buffer, 0x00, LIN_OTA_BLOCK_SIZE);

        TMR_StopTimer(mOtaTimeoutTimerId);
    }
}
#endif

static void OtaTimeoutTimerClear(void)
{
#if OTA_BY_CAN_LIN
    can_ota_timeout_cnt = 0;
#endif
}

/*!
 * @brief Application entry point.
 */
void lin_demo_init_slave(void) {

    tpm_config_t tpmInfo;

    lin_status_t status;
    uint32_t linfreq;
    gpio_pin_config_t slpn_config = {
        kGPIO_DigitalOutput, 1,
    };
    /* Init board hardware. */
    BOARD_InitLinLpuart();

    /* Set LIN LPUART clock */
    CLOCK_SetLpuart1Clock(SIM_LPUART_CLK_SEL_OSCERCLK_CLK);
#if defined(TIMER_TPM) && TIMER_TPM
    /* Set Timer LPUART clock */
    CLOCK_SetTpmClock(SIM_TPM_CLK_SEL_OSCERCLK_CLK);
#endif

#if defined(TJA_WAKEUP) && TJA_WAKEUP
    /* Wakeup TJA transceiver */
    GPIO_PinInit(DEMO_SLPN_GPIO, DEMO_SLPN_PIN, &slpn_config);
#endif

    /*
     * .linUserConfigSlave.autobaudEnable = false;
     * .linUserConfigSlave.baudRate = 19200;
     * .linUserConfigSlave.nodeFunction = SLAVE;
     * .linUserConfigSlave.timerGetTimeIntervalCallback = NULL;
     */
    LIN_GetSlaveDefaultConfig(&linUserConfigSlave);
    /* get LIN clock frequency */
    linfreq  = CLOCK_GetFreq(LIN_CLOCK_NAME);

#if defined(TIMER_TPM) && TIMER_TPM
    TPM_GetDefaultConfig(&tpmInfo);
    tpmInfo.prescale = kTPM_Prescale_Divide_1;
    /* Initialize TPM module */
    TPM_Init(DEMO_TPM_BASEADDR, &tpmInfo);
    /* Set module value */
    DEMO_TPM_BASEADDR->MOD = 0xFFFF;
    /* Setup TPM output compare mode */
    TPM_SetupOutputCompare(DEMO_TPM_BASEADDR, DEMO_TPM_CH_OUT, kTPM_NoOutputSignal, MODULO_VALUE);
    /* Setup TPM input capture mode - capture LPUART-RX falling edge */
    TPM_SetupInputCapture(DEMO_TPM_BASEADDR, DEMO_TPM_CH_IN, kTPM_RiseAndFallEdge);
    /* Enable interrupt on overflow */
    TPM_EnableInterrupts(DEMO_TPM_BASEADDR, kTPM_TimeOverflowInterruptEnable |  DEMO_TPM_CH_OUT_IRQ | DEMO_TPM_CH_IN_IRQ);
    /* Set the second highest priority */
    NVIC_SetPriority(DEMO_TPM_IRQn, DEMO_TIMER_PRIO);
    /* Enable at the NVIC */
    EnableIRQ(DEMO_TPM_IRQn);  
#endif

    if(TIMER_FREQ == 0U)
    {
      PRINTF("\r\n Timer initialization failed!");

    }
    /* Initialize slave node */
    status = SlaveInit( &linUserConfigSlave, &linCurrentState,  linfreq);


    if(status != LIN_INITIALIZED)
    {
        PRINTF("\r\nLIN initialization failed!");
    }
    else
    {
        PRINTF("\r\nLIN slave initialized");
    }

    if(linUserConfigSlave.autobaudEnable == true)
    {
        /* Prepare baudrate array for autobadrate mode */
        CalculateBaudrates(SLAVE_INSTANCE, linfreq, g_baudRatesValues);
    }
    
    /* Go to sleep until master starts communication */
    LIN_GoToSleepMode(SLAVE_INSTANCE);
    if(linCurrentState.currentNodeState != LIN_NODE_STATE_SLEEP_MODE)
    {
         PRINTF("\r\nLIN sleep command failed!");
    }
    PRINTF("\r\nAwaiting data from Master\r\n");
#if defined(TIMER_TPM) && TIMER_TPM
    TPM_StartTimer(DEMO_TPM_BASEADDR, kTPM_SystemClock);
#endif
#if OTA_BY_CAN_LIN
    mResetTimerId = TMR_AllocateTimer();
    mOtaTimeoutTimerId = TMR_AllocateTimer();
#endif
}
