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

#include "fsl_debug_console.h"
#include "fsl_flexcan.h"
#include "board.h"

#include "fsl_device_registers.h"
#include "fsl_common.h"
#include "pin_mux.h"
#include "clock_config.h"
#include "TimersManager.h"
#include "FunctionLib.h"
#include "SecLib.h"

#if OTA_BY_CAN_LIN
#include "Eeprom.h"
#include "OtaSupport.h"
#endif
#include "flexcan_cfg.h"
#include "can_lin_common.h"
   
/*******************************************************************************
 * Definitions
 ******************************************************************************/
#define EXAMPLE_CAN CAN0
#define EXAMPLE_CAN_CLKSRC kCLOCK_BusClk
#define EXAMPLE_CAN_CLK_FREQ CLOCK_GetFreq(kCLOCK_BusClk)
#define USE_CANFD (1)
/* 
 *    DWORD_IN_MB    DLC    BYTES_IN_MB             Maximum MBs
 *    2              8      kFLEXCAN_8BperMB        32
 *    4              10     kFLEXCAN_16BperMB       21
 *    8              13     kFLEXCAN_32BperMB       12
 *    16             15     kFLEXCAN_64BperMB       7
 *
 * Dword in each message buffer, Length of data in bytes, Payload size must align,
 * and the Message Buffers are limited corresponding to each payload configuration:
 */
#define DWORD_IN_MB (4)
#define DLC (10)
#define BYTES_IN_MB kFLEXCAN_16BperMB
#define RX_MESSAGE_BUFFER_NUM (9)
#define TX_MESSAGE_BUFFER_NUM (8)

/*******************************************************************************
 * Prototypes
 ******************************************************************************/
#if OTA_BY_CAN_LIN
static void OtaTimeoutTimerCallback(void *pParam);
static void CanGetIdTimeoutTimerCallback(void *pParam);
#endif
static void OtaTimeoutTimerClear(void);

/*******************************************************************************
 * Variables
 ******************************************************************************/
flexcan_handle_t flexcanHandle;
volatile bool txComplete = false;
volatile bool rxComplete = false;
flexcan_mb_transfer_t txXfer, rxXfer;
#if (defined(USE_CANFD) && USE_CANFD)
flexcan_fd_frame_t canFrame;
#else
flexcan_frame_t canFrame;
#endif
static uint32_t txIdentifier = CAN_TX_IDENTIFIER;
static uint32_t rxIdentifier = CAN_RX_IDENTIFIER;

can_ota_status_t g_can_ota_status = CAN_OTA_STATUS_IDLE;
can_ota_stage_t g_can_ota_stage = CAN_OTA_STAGE_IDLE;

static tmrTimerID_t mOtaTimeoutTimerId = gTmrInvalidTimerID_c; 
#if OTA_BY_CAN_LIN
static tmrTimerID_t mCanGetIdTimeoutTimerId = gTmrInvalidTimerID_c;
static uint8_t can_ota_block_num = 0;
static uint32_t can_ota_image_offset = 0;
static uint16_t can_ota_tx_frame_offset = 0;
static uint8_t eeprom_read_buffer[CAN_OTA_BLOCK_SIZE] = {0};
static uint8_t can_ota_timeout_cnt = 0;
#endif
static uint8_t can_ota_tx_sequence = 0;
static uint16_t can_device_id_list[16] = {0};
static uint8_t can_device_id_cnt = 0;

#if OTA_BY_CAN_LIN
uint32_t g_can_ota_image_length = 0;
uint32_t g_can_read_flash_offset = gBootData_ImageLength_Offset_c;

uint8_t key128[128/8] = { 0x55, 0x6c, 0x74, 0x72,  
                          0x61, 0x53, 0x65, 0x63, 
	                      0x61, 0x73, 0x73, 0x77, 
                          0x6f, 0x72, 0x64, 0x31 };     /*AES128 key*/
extern bool_t g_ota_image_ready_for_lin_or_can;
extern bool_t g_device_reset_for_ota;
#endif
/*******************************************************************************
 * Code
 ******************************************************************************/
/*!
 * @brief FlexCAN Call Back function
 */
static void flexcan_callback(CAN_Type *base, flexcan_handle_t *handle, status_t status, uint32_t result, void *userData)
{
    switch (status)
    {
        case kStatus_FLEXCAN_RxIdle:
            if (RX_MESSAGE_BUFFER_NUM == result)
            {
                rxComplete = true;
                //PRINTF("rx finish\r\n");
                can_rx_process();
                //can_tx_process();
            }
            break;

        case kStatus_FLEXCAN_TxIdle:
            if (TX_MESSAGE_BUFFER_NUM == result)
            {
                txComplete = true;
                //PRINTF("tx finish\r\n");
                can_set_to_rx_mode();
            }
            break;

        default:
            break;
    }
}

/*!
 * @brief CAN Initialization function
 */
void can_demo_init(void)
{
    flexcan_config_t flexcanConfig;
    flexcan_rx_mb_config_t mbConfig;
   
    /* Initialize board hardware. */
    BOARD_InitCAN();

    /* Get FlexCAN module default Configuration. */
    /*
     * flexcanConfig.clkSrc = kFLEXCAN_ClkSrcOsc;
     * flexcanConfig.baudRate = 1000000U;
     * flexcanConfig.maxMbNum = 16;
     * flexcanConfig.enableLoopBack = false;
     * flexcanConfig.enableSelfWakeup = false;
     * flexcanConfig.enableIndividMask = false;
     * flexcanConfig.enableDoze = false;
     * flexcanConfig.timingConfig = timingConfig;
     */
    FLEXCAN_GetDefaultConfig(&flexcanConfig);

    /* Init FlexCAN module. */
#if (!defined(FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE)) || !FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE
    flexcanConfig.clkSrc = kFLEXCAN_ClkSrcPeri;
#endif /* FSL_FEATURE_FLEXCAN_SUPPORT_ENGINE_CLK_SEL_REMOVE */
    /* If special quantum setting is needed, set the timing parameters. */
#if (defined(SET_CAN_QUANTUM) && SET_CAN_QUANTUM)
    flexcanConfig.timingConfig.phaseSeg1 = PSEG1;
    flexcanConfig.timingConfig.phaseSeg2 = PSEG2;
    flexcanConfig.timingConfig.propSeg = PROPSEG;
#if (defined(FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE) && FSL_FEATURE_FLEXCAN_HAS_FLEXIBLE_DATA_RATE)
    flexcanConfig.timingConfig.fphaseSeg1 = FPSEG1;
    flexcanConfig.timingConfig.fphaseSeg2 = FPSEG2;
    flexcanConfig.timingConfig.fpropSeg = FPROPSEG;
#endif
#endif

#if (defined(USE_CANFD) && USE_CANFD)
    FLEXCAN_FDInit(EXAMPLE_CAN, &flexcanConfig, EXAMPLE_CAN_CLK_FREQ, BYTES_IN_MB, false);
#else
    FLEXCAN_Init(EXAMPLE_CAN, &flexcanConfig, EXAMPLE_CAN_CLK_FREQ);
#endif

    /* Create FlexCAN handle structure and set call back function. */
    FLEXCAN_TransferCreateHandle(EXAMPLE_CAN, &flexcanHandle, flexcan_callback, NULL);

    /* Set Rx Masking mechanism. */
    FLEXCAN_SetRxMbGlobalMask(EXAMPLE_CAN, FLEXCAN_RX_MB_STD_MASK(rxIdentifier, 0, 0));

    /* Setup Rx Message Buffer. */
    mbConfig.format = kFLEXCAN_FrameFormatStandard;
    mbConfig.type = kFLEXCAN_FrameTypeData;
    mbConfig.id = FLEXCAN_ID_STD(rxIdentifier);
#if (defined(USE_CANFD) && USE_CANFD)
    FLEXCAN_SetFDRxMbConfig(EXAMPLE_CAN, RX_MESSAGE_BUFFER_NUM, &mbConfig, true);
#else
    FLEXCAN_SetRxMbConfig(EXAMPLE_CAN, RX_MESSAGE_BUFFER_NUM, &mbConfig, true);
#endif

    /* Setup Tx Message Buffer. */
#if (defined(USE_CANFD) && USE_CANFD)
    FLEXCAN_SetFDTxMbConfig(EXAMPLE_CAN, TX_MESSAGE_BUFFER_NUM, true);
#else
    FLEXCAN_SetTxMbConfig(EXAMPLE_CAN, TX_MESSAGE_BUFFER_NUM, true);
#endif

    can_set_to_rx_mode();
    mOtaTimeoutTimerId = TMR_AllocateTimer();
#if OTA_BY_CAN_LIN
    mCanGetIdTimeoutTimerId = TMR_AllocateTimer();
#endif
}

/*!
 * @brief Set CAN to rx mode
 */
void can_set_to_rx_mode(void)
{
    rxComplete = false;

    /* Start receive data through Rx Message Buffer. */
    rxXfer.mbIdx = RX_MESSAGE_BUFFER_NUM;
#if (defined(USE_CANFD) && USE_CANFD)
    rxXfer.framefd = &canFrame;
    FLEXCAN_TransferFDReceiveNonBlocking(EXAMPLE_CAN, &flexcanHandle, &rxXfer);
#else
    rxXfer.frame = &canFrame;
    FLEXCAN_TransferReceiveNonBlocking(EXAMPLE_CAN, &flexcanHandle, &rxXfer);
#endif
}

/*!
 * @brief To process the received data of CAN
 */
void can_rx_process(void)
{
    uint8_t rx_data[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    uint8_t rx_length = canFrame.length;
    if ((rx_length > 15) || (rx_length == 0))
    {
        PRINTF("invalid receive length\r\n");
        return;
    }
    //PRINTF("rx length: %d\r\n", rx_length);
    
    rx_data[0] = canFrame.dataByte0;    
    if (rx_length > 1)
        rx_data[1] = canFrame.dataByte1;
    if (rx_length > 2)
        rx_data[2] = canFrame.dataByte2;
    if (rx_length > 3)
        rx_data[3] = canFrame.dataByte3;
    if (rx_length > 4)
        rx_data[4] = canFrame.dataByte4;    
    if (rx_length > 5)
        rx_data[5] = canFrame.dataByte5;
    if (rx_length > 6)
        rx_data[6] = canFrame.dataByte6;
    if (rx_length > 7)
        rx_data[7] = canFrame.dataByte7;
    if (rx_length > 8)
        rx_data[8] = canFrame.dataByte8;
    if (rx_length > 9)
        rx_data[9] = canFrame.dataByte9;
    if (rx_length > 10)
        rx_data[10] = canFrame.dataByte10;
    if (rx_length > 11)
        rx_data[11] = canFrame.dataByte11;
    if (rx_length > 12)
        rx_data[12] = canFrame.dataByte12;    
    if (rx_length > 13)
        rx_data[13] = canFrame.dataByte13;
    if (rx_length > 14)
        rx_data[14] = canFrame.dataByte14;

    /*for (uint8_t i = 0; i < rx_length; i ++)
        PRINTF("%02X ", rx_data[i]);
    PRINTF("\r\n");*/    

    switch (rxIdentifier)
    {
        case CAN_RX_IDENTIFIER:
        {
            if (CAN_OTA_STAGE_IDLE == g_can_ota_stage)
            {
                if (CAN_GEN_CMD_OTA_STATUS == rx_data[0])
                {
                    switch (rx_data[1])
                    {
                        case CAN_OTA_STATUS_READY:
                            g_can_ota_stage = CAN_OTA_STAGE_TX_DATA;
                            break;
                        case CAN_OTA_STATUS_RUNNING:
                            break;
                        case CAN_OTA_STATUS_FINISH:
                        {
                            PRINTF("dev 0x%04X can ota finish\r\n", can_device_id_list[can_device_id_cnt - 1]);
                            g_can_ota_stage = CAN_OTA_STAGE_IDLE;
                            TMR_StopTimer(mOtaTimeoutTimerId);
                            can_device_id_list[can_device_id_cnt - 1] = 0;
                            can_device_id_cnt --;
                            if (can_device_id_cnt > 0)
                            {
                                can_tx_process();
                                return;
                            }
                            else
                            {
                                can_set_to_rx_mode();
#if OTA_BY_CAN_LIN
                                g_ota_image_ready_for_lin_or_can = FALSE;
#endif
                            }
                        }
                            break;
                        case CAN_OTA_STATUS_ABORT:
                        {
                            PRINTF("can ota abort\r\n");
                            g_can_ota_stage = CAN_OTA_STAGE_IDLE;
                            TMR_StopTimer(mOtaTimeoutTimerId);
                            can_device_id_list[can_device_id_cnt - 1] = 0;
                            can_device_id_cnt --;
                            if (can_device_id_cnt > 0)
                            {
                                can_tx_process();
                                return;
                            }
                            else
                            {
                                can_set_to_rx_mode();
#if OTA_BY_CAN_LIN
                                g_ota_image_ready_for_lin_or_can = FALSE;
#endif
                            }
                        }
                            break;
                        default:
                            break;
                    }
                    can_tx_process();
                }
                else if (CAN_GEN_CMD_GET_DEV_ID == rx_data[0])
                {
                    can_device_id_list[can_device_id_cnt] = rx_data[1] + (rx_data[2] << 8);
                    PRINTF("Got dev id %d: 0x%04X\r\n", can_device_id_cnt, can_device_id_list[can_device_id_cnt]);
                    can_device_id_cnt ++;
                    can_set_to_rx_mode();
                }
                OtaTimeoutTimerClear();
            }
            else if (CAN_OTA_STAGE_TX_DATA == g_can_ota_stage)
            {
                if (CAN_GEN_CMD_OTA_DATA == rx_data[0])
                {
                    switch (rx_data[1])
                    {
                        case CAN_OTA_RX_ACK_SUCCESS:
                            if (can_ota_tx_sequence == rx_data[2])
                            {
                                can_ota_tx_sequence ++;
                            }
                            break;
                        case CAN_OTA_RX_ACK_ERROR:
                            break;
                        default:
                            break;
                    }
                }
                can_tx_process();
                OtaTimeoutTimerClear();
            }
            else if (CAN_OTA_STAGE_END == g_can_ota_stage)
            {
                OtaTimeoutTimerClear();           
                can_tx_process();
            }
        }
            break;
        default:
            break;
    }  
}

/*!
 * @brief Send one frame data of CAN to the bus, maximum length is limited to 15 
 */
void can_tx_data(uint8_t data[], uint8_t length)
{
    if ((length > 15) || (length == 0))
    {
        PRINTF("invalid input length!\r\n");
        return;
    }
    //PRINTF("tx length = %d\r\n", length);

    txComplete = false;
    
    canFrame.dataByte0 = data[0];    
    if (length > 1)
        canFrame.dataByte1 = data[1];   
    if (length > 2)
        canFrame.dataByte2 = data[2];
    if (length > 3)
        canFrame.dataByte3 = data[3];
    if (length > 4)
        canFrame.dataByte4 = data[4];
    if (length > 5)
        canFrame.dataByte5 = data[5];
    if (length > 6)
        canFrame.dataByte6 = data[6];
    if (length > 7)
        canFrame.dataByte7 = data[7];
    if (length > 8)
        canFrame.dataByte8 = data[8];
    if (length > 9)
        canFrame.dataByte9 = data[9];   
    if (length > 10)
        canFrame.dataByte10 = data[10];
    if (length > 11)
        canFrame.dataByte11 = data[11];
    if (length > 12)
        canFrame.dataByte12 = data[12];
    if (length > 13)
        canFrame.dataByte13 = data[13];
    if (length > 14)
        canFrame.dataByte14 = data[14];
    
    /*for (uint8_t i = 0; i < length; i ++)
        PRINTF("%02X ", data[i]);
    PRINTF("\r\n");*/
    
    canFrame.id = FLEXCAN_ID_STD(txIdentifier);
    canFrame.format = kFLEXCAN_FrameFormatStandard;
    canFrame.type = kFLEXCAN_FrameTypeData;
    canFrame.length = length;
    txXfer.mbIdx = TX_MESSAGE_BUFFER_NUM;
    
#if (defined(USE_CANFD) && USE_CANFD)
    txXfer.framefd = &canFrame;
    FLEXCAN_TransferFDSendNonBlocking(EXAMPLE_CAN, &flexcanHandle, &txXfer);
#else
    txXfer.frame = &canFrame;
    FLEXCAN_TransferSendNonBlocking(EXAMPLE_CAN, &flexcanHandle, &txXfer);
#endif    

}

/*!
 * @brief To prepare a frame data that will be sent to the bus
 */
void can_tx_process(void)
{
    uint8_t tx_data[15] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
    
    switch (txIdentifier)
    {
        case CAN_TX_IDENTIFIER:
        {
            if (CAN_OTA_STAGE_IDLE == g_can_ota_stage)
            {
#if OTA_BY_CAN_LIN
                if(g_ota_image_ready_for_lin_or_can)
                {
                    if (can_device_id_cnt == 0)
                    {
                        tx_data[0] = CAN_GEN_CMD_GET_DEV_ID;
                        TMR_StartSingleShotTimer(mCanGetIdTimeoutTimerId, 1200, CanGetIdTimeoutTimerCallback, NULL);
                        can_tx_data(tx_data, 1);
                    }                    
                    else if(can_device_id_cnt > 0)
                    {
                        tx_data[0] = CAN_GEN_CMD_OTA_CMD;
                        tx_data[1] = CAN_OTA_CMD_START;
                        tx_data[2] = (uint8_t)can_device_id_list[can_device_id_cnt - 1];  //test
                        tx_data[3] = (uint8_t)(can_device_id_list[can_device_id_cnt - 1] >> 8);  //test
                        g_can_read_flash_offset = gBootData_ImageLength_Offset_c;
                        can_ota_image_offset = g_can_read_flash_offset;
                        can_ota_tx_frame_offset = 0;
                        can_ota_block_num = 0;
                        can_ota_tx_sequence = 0;
                        TMR_StartLowPowerTimer(mOtaTimeoutTimerId, gTmrLowPowerIntervalMillisTimer_c, 200, OtaTimeoutTimerCallback, NULL);
                        can_tx_data(tx_data, 4);
                    }
                }
#endif
                if(gLMConnectionReady)
                {
                    gLMConnectionReady = FALSE;                     
                    tx_data[0] = CAN_GEN_CMD_TX_LM_PARA;
                    
                    tx_data[1] = gLMPara.peerDeviceId;
                    tx_data[2] = gLMPara.connOrDisconn;
                    tx_data[3] = gLMPara.CI >> 8;
                    tx_data[4] = gLMPara.CI & 0xFF;
                    tx_data[5] = gLMPara.hopIncrement;                  
                    tx_data[6] = (gLMPara.crcSeed>>24) & 0xFF;
                    tx_data[7] = (gLMPara.crcSeed>>16) & 0xFF;
                    tx_data[8] = (gLMPara.crcSeed>>8) & 0xFF;
                    tx_data[9] = (gLMPara.crcSeed>>0) & 0xFF;
                    tx_data[10] = (gLMPara.syncAddress>>24) & 0xFF;
                    tx_data[11] = (gLMPara.syncAddress>>16) & 0xFF;
                    tx_data[12] = (gLMPara.syncAddress>>8) & 0xFF;
                    tx_data[13] = (gLMPara.syncAddress>>0) & 0xFF;
                    
//                    TMR_StartLowPowerTimer(mOtaTimeoutTimerId, gTmrLowPowerIntervalMillisTimer_c, 500, OtaTimeoutTimerCallback, NULL);                    
                    can_tx_data(tx_data, 14);
                }        
                else
                {
                    can_set_to_rx_mode();
                }
            } 
#if OTA_BY_CAN_LIN
            else if (CAN_OTA_STAGE_TX_DATA == g_can_ota_stage)
            {

                if ((g_can_read_flash_offset == g_can_ota_image_length)
                    || (CAN_OTA_STATUS_ABORT == g_can_ota_status))
                {
                    tx_data[0] = CAN_GEN_CMD_OTA_CMD;
                    tx_data[1] = CAN_OTA_CMD_END;
                    g_can_ota_stage = CAN_OTA_STAGE_END;
                    g_can_read_flash_offset = gBootData_ImageLength_Offset_c;
                    can_ota_image_offset = g_can_read_flash_offset;
                    can_ota_tx_frame_offset = 0;
                    can_tx_data(tx_data, 2);
                }
                else
                {
                    tx_data[0] = CAN_GEN_CMD_OTA_DATA;
                    tx_data[1] = can_ota_tx_sequence;

                    if (can_ota_tx_frame_offset == 0)
                    {
                        g_can_read_flash_offset = gBootData_ImageLength_Offset_c + can_ota_block_num * CAN_OTA_BLOCK_SIZE;
                        if ((g_can_read_flash_offset + CAN_OTA_BLOCK_SIZE) <= g_can_ota_image_length)
                        {
                            EEPROM_ReadData(CAN_OTA_BLOCK_SIZE, g_can_read_flash_offset, eeprom_read_buffer);                    
                            can_ota_image_offset = g_can_read_flash_offset;
                            can_ota_block_num ++;
                        }
                        else if (g_can_read_flash_offset < g_can_ota_image_length)
                        {
                            uint16_t length;
                            length = g_can_ota_image_length - g_can_read_flash_offset;
                            EEPROM_ReadData(length, g_can_read_flash_offset, eeprom_read_buffer);
                            FLib_MemSet(&(eeprom_read_buffer[length]), 0xFF, CAN_OTA_BLOCK_SIZE - length);
                            can_ota_image_offset = g_can_read_flash_offset;
                            can_ota_block_num ++;
                        }
                        else
                        {
                            can_ota_image_offset = g_can_ota_image_length;                    
                        }
                    }
                    
                    if (can_ota_tx_frame_offset < CAN_OTA_BLOCK_SIZE)
                    {
                        //PRINTF("offset:%d\r\n", can_ota_image_offset);
                        if ((can_ota_image_offset + 8) <= g_can_ota_image_length)
                        {                    
                            FLib_MemCpy(&(tx_data[2]), &(eeprom_read_buffer[can_ota_tx_frame_offset]), 8);
                            can_ota_image_offset += 8;
                            can_ota_tx_frame_offset += 8;
                            if (can_ota_image_offset == g_can_ota_image_length)
                            {
                                g_can_ota_stage = CAN_OTA_STAGE_END;
                            }
                            if (CAN_OTA_BLOCK_SIZE == can_ota_tx_frame_offset)
                            {
                                can_ota_tx_sequence = 0;
                                can_ota_tx_frame_offset = 0;
                            }                            
                        }
                        else if (can_ota_image_offset < g_can_ota_image_length)
                        {
                            uint8_t len = g_can_ota_image_length - can_ota_image_offset;
                            FLib_MemCpy(&(tx_data[2]), &(eeprom_read_buffer[can_ota_tx_frame_offset]), len);
                            FLib_MemSet(&(tx_data[2 + len]), 0xFF, (8 - len));
                            can_ota_image_offset = g_can_ota_image_length;
                            g_can_read_flash_offset = g_can_ota_image_length;
                            g_can_ota_stage = CAN_OTA_STAGE_END;                  
                        }                        
                        can_tx_data(tx_data, 10);
                    }
                }
            }
            else if (CAN_OTA_STAGE_END == g_can_ota_stage)
            {
                tx_data[0] = CAN_GEN_CMD_OTA_CMD;
                tx_data[1] = CAN_OTA_CMD_END;
                tx_data[2] = (uint8_t)can_device_id_list[can_device_id_cnt - 1];
                tx_data[3] = (uint8_t)(can_device_id_list[can_device_id_cnt - 1] >> 8);                                    
                g_can_ota_stage = CAN_OTA_STAGE_IDLE;
                g_can_read_flash_offset = gBootData_ImageLength_Offset_c;
                can_ota_image_offset = g_can_read_flash_offset;
                can_ota_tx_frame_offset = 0;
                can_ota_block_num = 0;
                can_tx_data(tx_data, 4);
                OtaTimeoutTimerClear();
            } 
#endif
        }
            break;
        default:
            break;
    }
}

/*!
 * @brief Start point of CAN OTA
 */
void can_ota_start(void)
{
#if OTA_BY_CAN_LIN
    PRINTF("can ota start\r\n");
    if(OTA_InitExternalMemory() != gOtaSucess_c)
    {
        PRINTF("eeprom init fail\r\n");
        return;
    }

    g_ota_image_ready_for_lin_or_can = TRUE;
    
    uint8_t length[gBootData_ImageLength_Size_c];
    EEPROM_ReadData(gBootData_ImageLength_Size_c, gBootData_ImageLength_Offset_c, length);
    /* the length of image data */
    g_can_ota_image_length = (length[2] << 16) + (length[1] << 8) + length[0]; 
    /* add the length of image header */
    g_can_ota_image_length += gBootData_Image_Offset_c; 
    PRINTF("image len: %d\r\n", g_can_ota_image_length);
#endif
    can_tx_process();
}

/*!
 * @brief Callback of OTA Timeout 
 */
#if OTA_BY_CAN_LIN
static void OtaTimeoutTimerCallback(void *pParam)
{
    can_ota_timeout_cnt ++;
    if (can_ota_timeout_cnt >= 5)
    {
        PRINTF("can ota timeout, reset related variables\r\n");
        can_ota_timeout_cnt = 0;
        g_can_ota_status = CAN_OTA_STATUS_IDLE;
        g_can_ota_stage = CAN_OTA_STAGE_IDLE;
        can_ota_block_num = 0;
        can_ota_image_offset = 0;
        can_ota_tx_frame_offset = 0;        
        g_can_ota_image_length = 0;
        g_can_read_flash_offset = gBootData_ImageLength_Offset_c;
        FLib_MemSet(eeprom_read_buffer, 0x00, CAN_OTA_BLOCK_SIZE);
        TMR_StopTimer(mOtaTimeoutTimerId);
    }
}

static void CanGetIdTimeoutTimerCallback(void *pParam)
{
    PRINTF("device id collection finished\r\n");
    can_tx_process();
}
#endif

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