/* Copyright Statement:
 *
 * This software/firmware and related documentation ("AutoChips Software") are
 * protected under relevant copyright laws. The information contained herein is
 * confidential and proprietary to AutoChips Inc. and/or its licensors. Without
 * the prior written permission of AutoChips inc. and/or its licensors, any
 * reproduction, modification, use or disclosure of AutoChips Software, and
 * information contained herein, in whole or in part, shall be strictly
 * prohibited.
 *
 * AutoChips Inc. (C) 2024. All rights reserved.
 *
 * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
 * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("AUTOCHIPS SOFTWARE")
 * RECEIVED FROM AUTOCHIPS AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER
 * ON AN "AS-IS" BASIS ONLY. AUTOCHIPS EXPRESSLY DISCLAIMS ANY AND ALL
 * WARRANTIES, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
 * NONINFRINGEMENT. NEITHER DOES AUTOCHIPS PROVIDE ANY WARRANTY WHATSOEVER WITH
 * RESPECT TO THE SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY,
 * INCORPORATED IN, OR SUPPLIED WITH THE AUTOCHIPS SOFTWARE, AND RECEIVER AGREES
 * TO LOOK ONLY TO SUCH THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO.
 * RECEIVER EXPRESSLY ACKNOWLEDGES THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO
 * OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES CONTAINED IN AUTOCHIPS
 * SOFTWARE. AUTOCHIPS SHALL ALSO NOT BE RESPONSIBLE FOR ANY AUTOCHIPS SOFTWARE
 * RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
 * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND AUTOCHIPS'S
 * ENTIRE AND CUMULATIVE LIABILITY WITH RESPECT TO THE AUTOCHIPS SOFTWARE
 * RELEASED HEREUNDER WILL BE, AT AUTOCHIPS'S OPTION, TO REVISE OR REPLACE THE
 * AUTOCHIPS SOFTWARE AT ISSUE, OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE
 * CHARGE PAID BY RECEIVER TO AUTOCHIPS FOR SUCH AUTOCHIPS SOFTWARE AT ISSUE.
 */
/******************************************************************************
 * @version: V3.1.0  AC7840x  Demo
 ******************************************************************************/

/*!
* @file can_demo.c
*
* @brief This file provides CAN demo test integration functions.
*
*/

/* ===========================================  Includes  =========================================== */
#include "debugout_ac7840x.h"
#include "gpio_drv.h"
#include "can_drv.h"
#include "clock_config.h"
#include "timer_drv.h"
#include "gpio.h"
#include "string.h"
#include "can_hw.h"

/* ============================================  Define  ============================================ */
#define CAN_SOURCE_CLOCK              (60UL)                /* 时钟源选择60M */
#define CAN_MSG_HANDLE_DIRECT         (1UL)                 /* 是否处理消息， 1 是， 0 否 */
#define CAN_TIME_STAMP_ENABLE         (0UL)                 /* 使能/失能CAN时间戳 1 使能， 0 失能 */

#define CAN_BUS_ON_STS                (0U)                  /* 无busoff发生*/
#define CAN_BUS_OFF_STS               (1U)                  /* 当前为busoff*/
#define CAN_BUS_RCVY_STS              (2U)                  /* 3秒内发生过busoff, 当前不是busoff， 3秒后如无busoff出现，则恢复为CAN_BUS_ON_STS状态*/
#define LED_TOGGLE_TIME               (500U)                /* led 闪烁时间，每隔LED_TOGGLE_TIME ms 发送一次 */
#define SEND_FRAME_TIME               (500U)                /* 发送数据帧时间，每隔SEND_FRAME_TIME ms 发送一次 */
/* ===========================================  Typedef  ============================================ */
typedef struct
{
    uint32_t recvCount;                                     /* 接收消息计数 */
    uint32_t sendCount;                                     /* 发送消息计数*/
} can_cur_node_t;


/* ==========================================  Variables  =========================================== */
static can_cur_node_t s_canCurNode[CAN_INSTANCE_MAX] = {0}; /* 接收信息*/
uint8_t g_CANBusoffFlag = CAN_BUS_ON_STS;                   /* busoff 标志位，标识当前busoff状态， 有三种状态,CAN_BUS_ON_STS,CAN_BUS_OFF_STS,CAN_BUS_RCVY_STS*/
uint16_t g_RecoverCount = 0;                                /* busoff恢复次数， 用于判断第几次恢*/
uint16_t g_RecoverTimeCount = 0;                            /* busoff恢复时间计算*/
uint16_t g_SendMsgTimeCount = 0;                            /* 发送数据时间计数 */
uint16_t g_LedTrggleCount = 0;                              /* LED 闪烁时间计数 */
/*
 *  波特率和采样点计算公式：
 *  tSeg1 = (S_SEG_1 + 2); tSeg2 = (S_SEG_2 + 1).
 *  BandRate = (SRC_CLK / (S_PRESC + 1) / ((S_SEG_1 + 2) + (S_SEG_2 + 1))), SRC_CLK 是CAN模块源时钟
 *  SamplePoint = (tSeg1 / (tSeg1 + tSeg2)).
 */

#if (CAN_SOURCE_CLOCK == 80UL)                                /* 时钟源为80M */
static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =
{
    {0x1C, 0x09, 0x09, 0x01},                                 /*   1M, 75% */
    {0x26, 0x09, 0x09, 0x01},                                 /* 800K, 80% */
    {0x1C, 0x09, 0x09, 0x03},                                 /* 500K, 75% */
    {0x1C, 0x09, 0x09, 0x07},                                 /* 250K, 75% */
    {0x1C, 0x09, 0x09, 0x0F},                                 /* 125K, 75% */
    {0x1C, 0x09, 0x09, 0x13},                                 /* 100K, 75% */
    {0x1C, 0x09, 0x09, 0x27},                                 /*  50K, 75% */
};

#elif (CAN_SOURCE_CLOCK == 60UL)                              /* 时钟源为60M*/
static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =
{
    {0x0D, 0x04, 0x04, 0x02},                                 /*   1M, 75% */
    {0x12, 0x04, 0x04, 0x02},                                 /* 800K, 80% */
    {0x1C, 0x09, 0x09, 0x02},                                 /* 500K, 75% */
    {0x1C, 0x09, 0x09, 0x05},                                 /* 250K, 75% */
    {0x1C, 0x09, 0x09, 0x0B},                                 /* 125K, 75% */
    {0x1C, 0x09, 0x09, 0x0E},                                 /* 100K, 75% */
    {0x1C, 0x09, 0x09, 0x1D},                                 /*  50K, 75% */
};

#elif (CAN_SOURCE_CLOCK == 48UL)                              /* 时钟源为48M*/
static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =
{
    {0x22, 0x0B, 0x0B, 0x00},                                 /*   1M, 75% */
    {0x16, 0x05, 0x05, 0x01},                                 /* 800K, 80% */
    {0x22, 0x0B, 0x0B, 0x01},                                 /* 500K, 75% */
    {0x22, 0x0B, 0x0B, 0x03},                                 /* 250K, 75% */
    {0x22, 0x0B, 0x0B, 0x07},                                 /* 125K, 75% */
    {0x22, 0x0B, 0x0B, 0x09},                                 /* 100K, 75% */
    {0x22, 0x0B, 0x0B, 0x13},                                 /*  50K, 75% */
};

#elif (CAN_SOURCE_CLOCK == 24UL)                              /* 时钟源为24M*/
static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =
{
    {0x10, 0x05, 0x05, 0x00},                                 /*   1M, 75% */
    {0x16, 0x05, 0x05, 0x00},                                 /* 800K, 80% */
    {0x10, 0x05, 0x05, 0x01},                                 /* 500K, 75% */
    {0x10, 0x05, 0x05, 0x03},                                 /* 250K, 75% */
    {0x10, 0x05, 0x05, 0x07},                                 /* 125K, 75% */
    {0x10, 0x05, 0x05, 0x09},                                 /* 100K, 75% */
    {0x10, 0x05, 0x05, 0x13},                                 /*  50K, 75% */
};

#elif (CAN_SOURCE_CLOCK == 8UL)                               /*时钟源为8M*/
static const can_time_segment_t s_canBitrate[CAN_BITRATE_NUM] =
{
    {0x04, 0x01, 0x01, 0x00},                                 /*   1M，75% */
    {0x06, 0x01, 0x01, 0x00},                                 /* 800K, 80% */
    {0x0A, 0x03, 0x03, 0x00},                                 /* 500K，75% */
    {0x0A, 0x03, 0x03, 0x01},                                 /* 250K，75% */
    {0x0A, 0x03, 0x03, 0x03},                                 /* 125K，75% */
    {0x0D, 0x04, 0x03, 0x03},                                 /* 100K，75% */
    {0x0D, 0x04, 0x03, 0x07},                                 /*  50K，75% */
};
#endif

static const can_filter_config_t s_canFilterList[16] =        /* 过滤器配置*/
{
    {0x00000001, 0x00000000, CAN_MSG_ID_BOTH},                /* 只接收ID 0x0000_0001和0x001的数据 */
    {0x00000002, 0x00000000, CAN_MSG_ID_STD},                 /* 只接收ID 0x002的标准帧数据 */
    {0x00000013, 0x00000000, CAN_MSG_ID_EXT},                 /* 只接收ID 0x0000_0013的扩展帧数据 */
    {0x00000124, 0x00000000, CAN_MSG_ID_BOTH},                /* 只接收ID 0x0000_0124和0x124的数据 */
    {0x00000050, 0x1FFFFF0F, CAN_MSG_ID_BOTH},                /* 可接收ID 0xXXXX_XX5X 或 0xX5X的数据，X为任意值 */
    {0x00000060, 0x1FFFFF0F, CAN_MSG_ID_BOTH},                /* 可接收ID 0xXXXX_XX6X 或 0xX6X的数据，X为任意值 */
    {0x00000007, 0x1FFFFFF0, CAN_MSG_ID_BOTH},                /* 可接收ID 0xXXXX_XXX7 或 0xXX7的数据，X为任意值 */
    {0x00000008, 0x1FFFFFF0, CAN_MSG_ID_BOTH},                /* 可接收ID 0xXXXX_XXX8 或 0xXX8的数据，X为任意值 */

    {0x00000009, 0x1FFFFFF0, CAN_MSG_ID_STD},                 /* 可接收ID 0xXX9的标准帧数据，X为任意值 */
    {0x0000000a, 0x1FFFFFF0, CAN_MSG_ID_EXT},                 /* 可接收ID 0xXXXX_XXXa的扩展帧数据，X为任意值 */
    {0x00000700, 0x1FFFF0FF, CAN_MSG_ID_BOTH},                /* 可接收ID 0xXXXX_X7XX 或 0x7XX的数据，X为任意值 */
    {0x0000c000, 0x1FFF0FFF, CAN_MSG_ID_EXT},                 /* 可接收ID 0xXXXX_CXXX 的扩展帧数据，X为任意值 */
    {0x000d0000, 0x1FF0FFFF, CAN_MSG_ID_EXT},                 /* 可接收ID 0xXXXX_DXXX 的扩展帧数据，X为任意值 */
    {0x00e00000, 0x1F0FFFFF, CAN_MSG_ID_EXT},                 /* 可接收ID 0xXXEX_XXXX 的扩展帧数据，X为任意值 */
    {0x0f000000, 0x10FFFFFF, CAN_MSG_ID_EXT},                 /* 可接收ID 0xXXXX_XXXX 的扩展帧数据，X为任意值 */
    {0x10000000, 0x0FFFFFFF, CAN_MSG_ID_EXT},                 /* 可接收ID 0xXXXX_XXXX 的扩展帧数据，X为任意值 */
};

/*!
 * @brief 初始化CAN模块的GPIO引脚
 *
 * @param[in] instance: CAN模块通道
 * @return none
 */
void CAN_InitGPIO(uint8_t instance)
{
    if (0U == instance)
    {
        GPIO_DRV_SetMuxModeSel(PORTE, 4U, PORT_MUX_ALT5);     /* CAN0_RX */
        GPIO_DRV_SetMuxModeSel(PORTE, 5U, PORT_MUX_ALT5);     /* CAN0_TX */
        GPIO_DRV_SetMuxModeSel(PORTE, 10U, PORT_MUX_ALT5);    /* 配置收发器standby功能*/
    }
    else if (1U == instance)
    {
        GPIO_DRV_SetMuxModeSel(PORTC, 6U, PORT_MUX_ALT3);     /* CAN1_RX */
        GPIO_DRV_SetMuxModeSel(PORTC, 7U, PORT_MUX_ALT3);     /* CAN1_TX */
        GPIO_DRV_SetMuxModeSel(PORTE, 6U, PORT_MUX_ALT5);     /* 配置收发器standby功能*/
    }
    else if (2U == instance)
    {
        GPIO_DRV_SetMuxModeSel(PORTC, 16U, PORT_MUX_ALT3);    /* CAN2_RX */
        GPIO_DRV_SetMuxModeSel(PORTC, 17U, PORT_MUX_ALT3);    /* CAN2_TX */
        GPIO_DRV_SetMuxModeSel(PORTC, 15U, PORT_MUX_ALT5);    /* 配置收发器standby功能*/
    }
    else if (3U == instance)
    {
        GPIO_DRV_SetMuxModeSel(PORTC, 12U, PORT_MUX_ALT5);    /* CAN3_RX */
        GPIO_DRV_SetMuxModeSel(PORTC, 13U, PORT_MUX_ALT5);    /* CAN3_TX */
        GPIO_DRV_SetMuxModeSel(PORTC, 11U, PORT_MUX_ALT5);    /* 配置收发器standby功能*/
    }
}

/*!
 * @brief 获取波特率设置
 *
 * @param[in] index: 波特率配置索引
 * @return 波特率配置
 */
static can_time_segment_t CAN_GetNormalBitrate(can_bitrate_t index)
{
    can_time_segment_t bitrate = {0};

    if (index < CAN_BITRATE_NUM)
    {
        bitrate = s_canBitrate[index];
    }

    return bitrate;
}

/*!
 * @brief CAN接收信息处理中断函数
 *
 * @param[in] instance: CAN 模块通道
 * @param[in] msgInfo: 接收到的信息
 * @return none
 */
static void CAN_HandleMsg(uint8_t instance, const can_msg_info_t *msgInfo)
{
    uint8_t i = 0;

    s_canCurNode[instance].recvCount++;
#if CAN_MSG_HANDLE_DIRECT /* 处理数据*/
    if (msgInfo->IDE)
    {
        printf("CAN[%d] RecvCount:%06d ID:%08x DLC:%d", instance, s_canCurNode[instance].recvCount, msgInfo->ID, msgInfo->DLC);
    }
    else
    {
        printf("CAN[%d] RecvCount:%06d  ID:%03x DLC:%d", instance, s_canCurNode[instance].recvCount, msgInfo->ID, msgInfo->DLC);
    }
    if ((0 == msgInfo->RTR) && msgInfo->DLC)
    {
        printf("\r\tData: ");
        for (i = 0; (i < msgInfo->DLC) && (i < 8); i++)
        {
            printf(" %02x", msgInfo->DATA[i]);
        }
    }
    printf("\r\n");
#endif
}

/*!
 * @brief CAN 中断回调函数
 *
 * @param[in] instance: CAN 模块通道
 * @param[in] event: CAN 中断事件
 * @param[in] koer: 错误类型，会一直保留，直到下一个错误出现刷新此位
 * @return 0: none
 */
void CAN_EventCallback(uint8_t instance, uint32_t event, uint32_t koer)
{
    can_msg_info_t recvMsg = {0};
    uint8_t recvData[8] = {0};
    CAN_Type *base = CAN_DRV_GetBase(instance);

    if (event & (uint32_t)CAN_EVENT_ERROR)
    {
        if(base->CTRL0 & CAN_CTRL0_BUSOFF_Msk)
        {
            g_CANBusoffFlag = CAN_BUS_OFF_STS;
            CAN_DRV_SetReset(instance, ENABLE);    /* 发生busoff， reset 置1*/
        }
    }

    if (event & (uint32_t)CAN_EVENT_BUS_ERROR)     /* 发生错误*/
    {
        printf("CAN[%d]e: EVEN: %x  KOER: %x\r\n", instance, event, koer);  /* 打印错误信息*/
    }

    if (event & (uint32_t)CAN_EVENT_RECEIVE_DONE)   /* 接收数据*/
    {
        while (CAN_DRV_GetRbufStatus(instance))
        {
            recvMsg.DATA = recvData;                /* 为接收数据索引中的数据域分配空间， 如果未给接收数据索引的数据域分配空间，直操作会触发Haltfault */
            if (STATUS_SUCCESS == CAN_DRV_Receive(instance, &recvMsg))
            {
                CAN_HandleMsg(instance, &recvMsg);
            }
        }
    }
}

/*!
 * @brief CAN模块发送数据测试
 *
 * @param[in] instance: CAN 模块通道数
 * @param[in] type: CAN 模块缓冲区选择
 *              - CAN_TRANSMIT_PRIMARY
 *              - CAN_TRANSMIT_SECONDARY
 * @return STATUS_SUCCESS: 发送成功   其他值： 发送失败
 */
status_t CAN_SendTest(uint8_t instance, can_transmit_buff_t type)
{
    status_t ret;
    volatile uint32_t timeout;
    static can_msg_info_t s_sendMsg = {0};
    static uint8_t sendData[8] = {0};

    s_sendMsg.ID = 0x220;          /* CAN ID*/
    s_sendMsg.IDE = 0;             /* 标准帧*/
    s_sendMsg.RTR = 0;             /* 非远程帧*/
    s_sendMsg.DLC = 8;             /* 数据长度*/
    s_sendMsg.DATA = sendData;     /* 分配空间*/
    s_sendMsg.DATA[0] = 0x11;      /* 填充数据*/
    s_sendMsg.DATA[1] = 0x22;
    s_sendMsg.DATA[2] = 0x33;
    s_sendMsg.DATA[3] = 0x44;
    s_sendMsg.DATA[4] = 0x55;
    s_sendMsg.DATA[5] = 0x66;
    s_sendMsg.DATA[6] = 0x77;
    s_sendMsg.DATA[7] = 0x88;

    do
    {
        ret = CAN_DRV_Send(instance, &s_sendMsg, type);
        timeout++;
    } while ((STATUS_BUSY == ret) && (timeout < 0xFFF));

    if (STATUS_SUCCESS == ret)
    {
        s_canCurNode[instance].sendCount++;     /* 节点信息更新 */
    }

    return ret;
}



/*!
* @brief TIMER中断回调函数，用于g_RecoverCount 计数变量自加
*
* @param[in] device:  TIMER 索引
* @param[in] wpara: 终端标志
* @param[in] lpara:  NULL
* @return none
*/
void TIMER_Callback(void *device, uint32_t wpara, uint32_t lpara)
{
    if( (wpara & TIMER_CTRL_SR_TIF0_Msk) != 0 )
    {
        if(g_CANBusoffFlag)       /*发生busoff后，计数值开始累加， 计算恢复时间*/
        {
           g_RecoverTimeCount++;
        }
        g_SendMsgTimeCount ++;   /* 发送时间计数 */
        g_LedTrggleCount ++;
    }
}

/*!
* @brief TIMER初始化函数
*
* @param[in] none
* @return none
*/
void TIMER_Init(void)
{
    timer_user_channel_config_t timerConfig;
    memset(&timerConfig, 0, sizeof(timerConfig));

    timerConfig.timerMode = TIMER_PERIODIC_COUNTER;               /* 32bit计数 */
    timerConfig.periodUnits = TIMER_PERIOD_UNITS_MICROSECONDS;    /* 以us为单位计数 */
    timerConfig.period = 1000U;                                   /* 1ms为周期 */
    timerConfig.triggerSource = TIMER_TRIGGER_SOURCE_INTERNAL;    /* 触发输入选择*/
    timerConfig.triggerSelect = 0x00U;                            /* 内部触发源选择 */
    timerConfig.enableReloadOnTrigger = DISABLE;                  /* 触发源来时不重新加载计数值 */
    timerConfig.enableStopOnInterrupt = DISABLE;                  /* 发生一次中断后不停止Timer的计数 */
    timerConfig.enableStartOnTrigger = DISABLE;                   /* 配置ENRx=1即会使Timer开始计数,该位决定触发源是否奏效 */
    timerConfig.chainChannel = DISABLE;                           /* 禁能链接 */
    timerConfig.isInterruptEnabled = ENABLE;                      /* 使能中断 */

    TIMER_DRV_Init (0, ENABLE);                                   /* Timer 时钟和调试模式控制*/
    TIMER_DRV_InitChannel(0, TIMER_CHANNEL_0,&timerConfig);       /* Timer 通道模式配置*/
    TIMER_DRV_StartChannels(0, 1<<TIMER_CHANNEL_0);               /* Timer 通道使能控制*/
    TIMER_DRV_InstallCallback(TIMER_CHANNEL_0, &TIMER_Callback);
}

/*!
 * @brief   CAN模块Busoff快慢恢复
 *          发生busoff后，先以50ms的速度进行10次快恢复，再以1S的时间进行慢恢复，3S无异常则说明通信正常
 * @param   instance: CAN模块通道
 * @return  void
 */
void CAN_Busoff_Handle(uint8_t instance)
{
    if((CAN_BUS_RCVY_STS == g_CANBusoffFlag) && (g_RecoverTimeCount > 3000))  /* recover状态下，3S后无异常后，状态恢复正常*/
    {
        g_RecoverTimeCount = 0;                              /* 时间计数清零*/
        g_RecoverCount = 0;                                  /* 恢复次数清零*/
        g_CANBusoffFlag = CAN_BUS_ON_STS;                    /* 设置为正常状态*/
    }
    else if((CAN_BUS_OFF_STS == g_CANBusoffFlag) && (g_RecoverTimeCount > 50) && (g_RecoverCount < 10))                     /* 50ms恢复一次， 恢复10次 */
    {
        g_RecoverTimeCount = 0;                              /* 时间计数清零*/
        g_RecoverCount++;                                    /* 恢复次数加1*/
        g_CANBusoffFlag = CAN_BUS_RCVY_STS;                  /* 状态设置为busoff恢复状态*/
        CAN_ExitBusOff(CAN0);                                /* 清楚busoff标志位*/
        CAN_DRV_SetReset(instance, DISABLE);                 /* busoff恢复，reset 清0*/
    }
    else if((CAN_BUS_OFF_STS == g_CANBusoffFlag) && (g_RecoverTimeCount > 999) && (g_RecoverCount >= 10))             /* 超过10次，以1S的时间进行恢复*/
    {
        g_RecoverTimeCount = 0;                              /* 时间计数清零*/
        g_RecoverCount ++;                                   /* 恢复次数清零*/
        g_CANBusoffFlag = CAN_BUS_RCVY_STS;                  /* 状态设置为busoff恢复状态*/
        CAN_ExitBusOff(CAN0);                                /* 清楚busoff标志位*/
        CAN_DRV_SetReset(instance, DISABLE);                 /* busoff恢复，reset 清0*/
    }
    else
    {

    }
}

/*!
 * @brief  busoff测试函数
 *
 * @param[in] none
 * @return none
 */
void CAN_BUSOFF_Test(void)
{
    uint8_t instance = 0U;
    can_user_config_t canCfg = {0};
    can_bitrate_t bitrateIndex = CAN_BITRATE_500K;          /* 低速波特率， 500K， 75% */
    can_transmit_buff_t type = CAN_TRANSMIT_SECONDARY;      /* 缓冲区选择次缓冲 */

    canCfg.filterNum = 0U;                                  /* 过滤器数量 */
    canCfg.canMode = CAN_NORMAL_MODE;                       /* 正常模式 */
    canCfg.interruptEn = true;                              /* 使能中断 */
    canCfg.tsMode = CAN_TSMODE_FIFO;                        /* 选择FIFO*/
    canCfg.tsAmount = CAN_TRANSMIT_SEC_ALL;                 /* TSALL*/
    canCfg.tpss = false;                                    /* 失能PTB单次发送 */
    canCfg.tsss = false;                                    /* 失能STB单次发送 */
    canCfg.rom = CAN_ROM_OVER_WRITE;                        /* FIFO溢出后， 新数据会覆盖旧数据*/
    canCfg.errorWarningLimit = 0x0BU;                       /* 错误警告限制，TECNT|RECNT超过这个值后会触发EIF中断*/
#if CAN_TIME_STAMP_ENABLE
    canCfg.timeStampEn = true;                              /* 使能时间戳 */
    canCfg.timeStampClkSrc = CAN_TIME_STAMP_CLK_SRC_EXT;    /* 时间戳时钟源选择 */
    canCfg.timeStampClkDiv = CAN_TIME_STAMP_CLK_DIV_8;      /* 时间戳时钟分频 */
    canCfg.timeStampPos = CAN_TIME_STAMP_SOF;               /* 采样位置 */
#endif
    canCfg.dmaRecvEn = false;                               /* 不使用DMA */
    canCfg.memEccEn = false;                                /* 失能ECC */
    canCfg.wakeupIntEn = false;                             /* 失能CAN唤醒 */
    canCfg.busOffRecDisable = false;                        /* 失能自动总线关闭恢复， busoff产生后， 会遵循ISO 11898-规范*/
    canCfg.interruptMask = CAN_IRQ_ALL_ENABLE_MSK;          /* 使能所有中断 */
    canCfg.bitrate = CAN_GetNormalBitrate(bitrateIndex);        /* 低速波特率配置 */
    canCfg.filterList = (can_filter_config_t *)s_canFilterList; /* 过滤器配置*/
    canCfg.callback = (can_callback_t)CAN_EventCallback;

    CAN_InitGPIO(instance);                                 /* CAN模块IO口初始化 */
    (void)CAN_DRV_Init(instance, &canCfg);                  /* CAN模块初始化*/
    TIMER_Init();                                           /* 定时器 初始化 */
    GPIO_LedInit();                                         /* LED IO初始化 */
    while (1)
    {
        CAN_Busoff_Handle(instance);                        /* busoff 快慢恢复 */

        if( CAN_BUS_OFF_STS == g_CANBusoffFlag )
        {
             LED3_ON;
             LED4_ON;
             printf("CAN BUSOFF NOW...\r\n");
        }
        else
        {
            if( g_SendMsgTimeCount > SEND_FRAME_TIME )
            {
                CAN_SendTest(instance, type);                  /* 发送数据 */
                g_SendMsgTimeCount = 0;                        /* 发送计数清零 */
            }
            if(CAN_BUS_RCVY_STS == g_CANBusoffFlag)
            {
                printf("CAN RECOVERY NOW...\r\n");
            }
            else
            {
                if( g_LedTrggleCount > LED_TOGGLE_TIME )       /* LED闪烁*/
                {
                    LED3_TOGGLE;                               /* CAN BUS ON , LED3 翻转 */
                    LED4_TOGGLE;                               /* CAN BUS ON, LED4 翻转*/
                    g_LedTrggleCount = 0;                      /* LED 闪烁计数清零 */
                }
            }
        }
    }
}
