/**************************************************************************//**
*
* @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date            Author       Notes
* 2022-4-27       Wayne        First version
*
******************************************************************************/

#include <rtconfig.h>

#if defined(BSP_USING_CANFD)

#include <rtdevice.h>
#include <rthw.h>
#include "NuMicro.h"
#include "nu_bitutil.h"

#define LOG_TAG    "drv.canfd"
#undef  DBG_ENABLE
#define DBG_SECTION_NAME   LOG_TAG
#define DBG_LEVEL       LOG_LVL_ERROR
#define DBG_COLOR
#include <rtdbg.h>

/* Private Define ---------------------------------------------------------------*/
#define IS_CAN_STDID(STDID)   ((STDID) <= 0x7FFU)
#define IS_CAN_EXTID(EXTID)   ((EXTID) <= 0x1FFFFFFFU)
#define IS_CAN_DLC(DLC)       ((DLC) <= 8U)

/* Default config for serial_configure structure */
#define NU_CANFD_CONFIG_DEFAULT                  \
{                                              \
    CAN1MBaud,           /* 1M bits/s       */ \
    RT_CANMSG_BOX_SZ,    /* message box max size */ \
    RT_CANSND_BOX_NUM,   /* message box number   */ \
    RT_CAN_MODE_NORMAL,  /* Normal mode     */ \
    0,                   /* privmode        */ \
    0,                   /* reserved        */ \
    100,                 /* Timeout Tick    */ \
}

enum
{
    CANFD_START = -1,
#if defined(BSP_USING_CANFD0)
    CANFD0_IDX,
#endif
#if defined(BSP_USING_CANFD1)
    CANFD1_IDX,
#endif
#if defined(BSP_USING_CANFD2)
    CANFD2_IDX,
#endif
#if defined(BSP_USING_CANFD3)
    CANFD3_IDX,
#endif
    CANFD_CNT
};

/* Private Typedef --------------------------------------------------------------*/
struct nu_canfd
{
    struct rt_can_device dev;
    char *name;
    CANFD_T *base;
    uint32_t rstidx;
    IRQn_Type irqn0;
    IRQn_Type irqn1;
    uint32_t int_flag;
    CANFD_FD_T sCANFD_Config;
};
typedef struct nu_canfd *nu_canfd_t;

/* Private functions ------------------------------------------------------------*/
static rt_err_t nu_canfd_configure(struct rt_can_device *can, struct can_configure *cfg);
static rt_err_t nu_canfd_control(struct rt_can_device *can, int cmd, void *arg);
static int nu_canfd_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno);
static int nu_canfd_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno);
static void nu_canfd_isr(nu_canfd_t can);

static struct nu_canfd nu_canfd_arr[] =
{
#if defined(BSP_USING_CANFD0)
    {
        .name = "canfd0",
        .base = CANFD0,
        .rstidx = CANFD0_RST,
        .irqn0 = CANFD00_IRQn,
        .irqn1 = CANFD01_IRQn,
    },
#endif
#if defined(BSP_USING_CANFD1)
    {
        .name = "canfd1",
        .base = CANFD1,
        .rstidx = CANFD1_RST,
        .irqn0 = CANFD10_IRQn,
        .irqn1 = CANFD11_IRQn,
    },
#endif
#if defined(BSP_USING_CANFD2)
    {
        .name = "canfd2",
        .base = CANFD2,
        .rstidx = CANFD2_RST,
        .irqn0 = CANFD20_IRQn,
        .irqn1 = CANFD21_IRQn,
    },
#endif
#if defined(BSP_USING_CANFD3)
    {
        .name = "canfd3",
        .base = CANFD3,
        .rstidx = CANFD3_RST,
        .irqn0 = CANFD30_IRQn,
        .irqn1 = CANFD31_IRQn,
    },
#endif
}; /* struct nu_can */

/* Public functions ------------------------------------------------------------*/

/* Private variables ------------------------------------------------------------*/
static const struct rt_can_ops nu_canfd_ops =
{
    .configure = nu_canfd_configure,
    .control = nu_canfd_control,
    .sendmsg = nu_canfd_sendmsg,
    .recvmsg = nu_canfd_recvmsg,
};

static const struct can_configure nu_canfd_default_config = NU_CANFD_CONFIG_DEFAULT;

/* Interrupt Handle Function  ----------------------------------------------------*/
#if defined(BSP_USING_CANFD0)
/* CAN0 interrupt entry */
void CANFD00_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    nu_canfd_isr(&nu_canfd_arr[CANFD0_IDX]);

    /* leave interrupt */
    rt_interrupt_leave();
}

void CANFD01_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    nu_canfd_isr(&nu_canfd_arr[CANFD0_IDX]);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

#if defined(BSP_USING_CANFD1)
void CANFD10_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    nu_canfd_isr(&nu_canfd_arr[CANFD1_IDX]);

    /* leave interrupt */
    rt_interrupt_leave();
}

void CANFD11_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    nu_canfd_isr(&nu_canfd_arr[CANFD1_IDX]);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

#if defined(BSP_USING_CANFD2)
void CANFD20_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    nu_canfd_isr(&nu_canfd_arr[CANFD2_IDX]);

    /* leave interrupt */
    rt_interrupt_leave();
}

void CANFD21_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    nu_canfd_isr(&nu_canfd_arr[CANFD2_IDX]);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

#if defined(BSP_USING_CANFD3)
void CANFD30_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    nu_canfd_isr(&nu_canfd_arr[CANFD3_IDX]);

    /* leave interrupt */
    rt_interrupt_leave();
}

void CANFD31_IRQHandler(void)
{
    /* enter interrupt */
    rt_interrupt_enter();

    nu_canfd_isr(&nu_canfd_arr[CANFD3_IDX]);

    /* leave interrupt */
    rt_interrupt_leave();
}
#endif

/* Private Variables ------------------------------------------------------------*/
const char *szIR[] =
{
    "CANFD_IR_RF0N - Rx FIFO 0 New Message",
    "CANFD_IR_RF0W - Rx FIFO 0 Watermark Reached",
    "CANFD_IR_RF0F - Rx FIFO 0 Full",
    "CANFD_IR_RF0L - Rx FIFO 0 Message Lost",
    "CANFD_IR_RF1N - Rx FIFO 1 New Message",
    "CANFD_IR_RF1W - Rx FIFO 1 Watermark Reached",
    "CANFD_IR_RF1F - Rx FIFO 1 Full",
    "CANFD_IR_RF1L - Rx FIFO 1 Message Lost",
    "CANFD_IR_HPM - High Priority Message",
    "CANFD_IR_TC - Transmission Completed",
    "CANFD_IR_TCF - Transmission Cancellation Finished",
    "CANFD_IR_TFE - Tx FIFO Empty",
    "CANFD_IR_TEFN - Tx Event FIFO New Entry",
    "CANFD_IR_TEFW - Tx Event FIFO Watermark Reached",
    "CANFD_IR_TEFF - Tx Event FIFO Full",
    "CANFD_IR_TEFL - Tx Event FIFO Event Lost",
    "CANFD_IR_TSW - Timestamp Wraparound",
    "CANFD_IR_MRAF - Message RAM Access Failure",
    "CANFD_IR_TOO - Timeout Occurred",
    "CANFD_IR_DRX - Message stored to Dedicated Rx Buffer",
    "BIT20",
    "BIT21",
    "CANFD_IR_ELO - Error Logging Overflow",
    "CANFD_IR_EP - Error Passive",
    "CANFD_IR_EW - Warning Status",
    "CANFD_IR_BO - Bus_Off Status",
    "CANFD_IR_WDI - Watchdog",
    "CANFD_IR_PEA - Protocol Error in Arbitration Phase",
    "CANFD_IR_PED - Protocol Error in Data Phase",
    "CANFD_IR_ARA - Access to Reserved Address",
    "BIT30",
    "BIT31"
};

static void dump_interrupt_event(uint32_t u32Status)
{
    uint32_t idx;
    while ((idx = nu_ctz(u32Status)) < 32) // Count Trailing Zeros ==> Find First One
    {
        LOG_D("[%s]", szIR[idx]);
        u32Status &= ~(1 << idx);
    }
}

static void nu_canfd_isr(nu_canfd_t psNuCANFD)
{
    /* Get base address of CAN register */
    CANFD_T *base = psNuCANFD->base;

    /* Get interrupt status */
    uint32_t u32Status = base->IR;
    CANFD_ClearStatusFlag(base, u32Status);

    /* Dump IR event */
    dump_interrupt_event(u32Status);

    /* Check Status Interrupt Flag (Error status Int and Status change Int) */
    /**************************/
    /* Status Change interrupt*/
    /**************************/

    if (u32Status & CANFD_IR_TC_Msk)
    {
        if (psNuCANFD->int_flag & RT_DEVICE_FLAG_INT_TX)
        {
            rt_hw_can_isr(&psNuCANFD->dev, RT_CAN_EVENT_TX_DONE);
        }
    }

    if (u32Status & (CANFD_IR_RF0N_Msk | CANFD_IR_RF1N_Msk))
    {
        if (psNuCANFD->int_flag & RT_DEVICE_FLAG_INT_RX)
        {
            rt_hw_can_isr(&psNuCANFD->dev, RT_CAN_EVENT_RX_IND);
        }
    }

    if (u32Status & (CANFD_IR_RF0L_Msk | CANFD_IR_RF1L_Msk))
    {
        rt_hw_can_isr(&psNuCANFD->dev, RT_CAN_EVENT_RXOF_IND);
    }

    if (u32Status & (CANFD_IR_TEFF_Msk | CANFD_IR_TOO_Msk))
    {
        rt_hw_can_isr(&psNuCANFD->dev, RT_CAN_EVENT_TX_FAIL);
    }

    /**************************/
    /* Error Status interrupt */
    /**************************/
    if (u32Status & CANFD_IR_EW_Msk)
    {
        LOG_E("[%s]EWARN", psNuCANFD->name) ;
    }

    if (u32Status & CANFD_IR_BO_Msk)
    {
        LOG_E("[%s]BUSOFF", psNuCANFD->name) ;

        /* To release busoff pin */
    }

    if (u32Status & CANFD_IR_PED_Msk)
    {
        LOG_E("[%s] LEC: %03x\n", psNuCANFD->name, base->PSR & CANFD_PSR_LEC_Msk) ;
    }
}

static void nu_canfd_ie(nu_canfd_t psNuCANFD)
{
    uint32_t u32CanFDIE = CANFD_IE_BOE_Msk;

    if (psNuCANFD->int_flag & (RT_DEVICE_FLAG_INT_RX))
    {
        /* Rx FIFO 0 New Message Interrupt */
        u32CanFDIE |= (CANFD_IE_RF0NE_Msk | CANFD_IE_RF1NE_Msk);
    }

    if (psNuCANFD->int_flag & (RT_DEVICE_FLAG_INT_TX))
    {
        /* Transmission Completed Interrupt */
        /* Timeout Occurred Interrupt */
        u32CanFDIE |= (CANFD_IE_TCE_Msk | CANFD_IE_TEFNE_Msk);
    }

    if (psNuCANFD->int_flag & RT_DEVICE_CAN_INT_ERR)
    {
        /* Bus_Off Status Interrupt */
        /* Warning Status Interrupt */
        /* Error Passive Interrupt */
        /* Error Logging Overflow Interrupt */
        /* Protocol Error in Data Phase interrupt Indicator */
        u32CanFDIE |= (CANFD_IE_EPE_Msk | CANFD_IE_EWE_Msk | CANFD_IE_ELOE_Msk | CANFD_IE_TOOE_Msk | CANFD_IR_PED_Msk);
    }

    //u32CanFDIE = 0xffffffff;

    CANFD_EnableInt(psNuCANFD->base, u32CanFDIE, 0,
                    (psNuCANFD->int_flag & (RT_DEVICE_FLAG_INT_TX)) ? CANFD_TXBTIE_TIEn_Msk : 0,
                    (psNuCANFD->int_flag & (RT_DEVICE_FLAG_INT_TX)) ? CANFD_TXBCIE_CFIEn_Msk : 0);
}

static rt_err_t nu_canfd_configure(struct rt_can_device *can, struct can_configure *cfg)
{
    nu_canfd_t psNuCANFD  = (nu_canfd_t)can;
    CANFD_FD_T *psCANFDConf;

    RT_ASSERT(can);
    RT_ASSERT(cfg);

    psCANFDConf = &psNuCANFD->sCANFD_Config;

    /* Get base address of CAN register */
    CANFD_T *base = psNuCANFD->base;

    CANFD_GetDefaultConfig(psCANFDConf, CANFD_OP_CAN_MODE);

    LOG_I("Message Ram Size: %d @%08x ~ %08x",    psCANFDConf->u32MRamSize, CANFD_SRAM_BASE_ADDR(base), psCANFDConf->u32MRamSize + CANFD_SRAM_BASE_ADDR(base));
    LOG_I("SIDFC: %d @%08x Size:%d",       psCANFDConf->sElemSize.u32SIDFC, CANFD_SRAM_BASE_ADDR(base) + psCANFDConf->sMRamStartAddr.u32SIDFC_FLSSA, psCANFDConf->sElemSize.u32SIDFC * sizeof(CANFD_STD_FILTER_T));
    LOG_I("XIDFC: %d @%08x Size:%d",       psCANFDConf->sElemSize.u32XIDFC, CANFD_SRAM_BASE_ADDR(base) + psCANFDConf->sMRamStartAddr.u32XIDFC_FLESA, psCANFDConf->sElemSize.u32XIDFC * sizeof(CANFD_EXT_FILTER_T));
    LOG_I("RxFifo0: %d @%08x Size:%d",     psCANFDConf->sElemSize.u32RxFifo0, CANFD_SRAM_BASE_ADDR(base) + psCANFDConf->sMRamStartAddr.u32RXF0C_F0SA, psCANFDConf->sElemSize.u32RxFifo0 * sizeof(CANFD_BUF_T));
    LOG_I("RxFifo1: %d @%08x Size:%d",     psCANFDConf->sElemSize.u32RxFifo1, CANFD_SRAM_BASE_ADDR(base) + psCANFDConf->sMRamStartAddr.u32RXF1C_F1SA, psCANFDConf->sElemSize.u32RxFifo1 * sizeof(CANFD_BUF_T));
    LOG_I("RxBuf: %d @%08x Size:%d",       psCANFDConf->sElemSize.u32RxBuf, CANFD_SRAM_BASE_ADDR(base) + psCANFDConf->sMRamStartAddr.u32RXBC_RBSA, psCANFDConf->sElemSize.u32RxBuf * sizeof(CANFD_BUF_T));
    LOG_I("TxEventFifo: %d @%08x Size:%d", psCANFDConf->sElemSize.u32TxEventFifo, CANFD_SRAM_BASE_ADDR(base) + psCANFDConf->sMRamStartAddr.u32TXEFC_EFSA, psCANFDConf->sElemSize.u32TxEventFifo * sizeof(CANFD_EXT_FILTER_T));
    LOG_I("TxBuf: %d @%08x Size:%d",       psCANFDConf->sElemSize.u32TxBuf, CANFD_SRAM_BASE_ADDR(base) + psCANFDConf->sMRamStartAddr.u32TXBC_TBSA, psCANFDConf->sElemSize.u32TxBuf * sizeof(CANFD_BUF_T));

    psCANFDConf->sBtConfig.sNormBitRate.u32BitRate = cfg->baud_rate;
    psCANFDConf->sBtConfig.sDataBitRate.u32BitRate = 0;

    LOG_I("CAN Baud rate: %d bps",  cfg->baud_rate);

    switch (cfg->mode)
    {
    case RT_CAN_MODE_NORMAL:    // Normal
        psCANFDConf->sBtConfig.evTestMode = eCANFD_NORMAL;
        break;

    case RT_CAN_MODE_LISTEN:     // Bus monitor Mode, can't start a transmission
        psCANFDConf->sBtConfig.evTestMode = eCANFD_BUS_MONITOR;
        break;

    case RT_CAN_MODE_LOOPBACK:  // Test - Internal loopback
        psCANFDConf->sBtConfig.evTestMode = eCANFD_LOOPBACK_INTERNAL;
        break;

    case RT_CAN_MODE_LOOPBACKANLISTEN:
    default:
        rt_kprintf("Unsupported Operating mode\n");
        goto exit_nu_canfd_configure;
    }

    /*Set the CAN Bit Rate and Operating mode*/
    CANFD_Open(base, psCANFDConf);

    /* Set FIFO policy */
#if defined(RT_CAN_USING_HDR)
    /* Whitelist filtering */
    CANFD_SetGFC(base, eCANFD_REJ_NON_MATCH_FRM, eCANFD_REJ_NON_MATCH_FRM, 0, 0);
#else
    /* Blacklist filtering. */
    CANFD_SetGFC(base, eCANFD_ACC_NON_MATCH_FRM_RX_FIFO0, eCANFD_ACC_NON_MATCH_FRM_RX_FIFO0, 0, 0);
#endif

    /* Enable interrupt */
    nu_canfd_ie(psNuCANFD);

    //LOG_HEX("canfd", 16, (void *)base, sizeof(CANFD_T));

    /* Lock protected registers & Run */
    CANFD_RunToNormal(base, TRUE);

    return RT_EOK;

exit_nu_canfd_configure:

    CANFD_Close(base);

    return -(RT_ERROR);
}

static rt_err_t nu_canfd_control(struct rt_can_device *can, int cmd, void *arg)
{
    rt_uint32_t argval = (rt_uint32_t)arg;
    nu_canfd_t psNuCANFD = (nu_canfd_t)can;

    RT_ASSERT(can);

    switch (cmd)
    {
    case RT_DEVICE_CTRL_SET_INT:
        psNuCANFD->int_flag |= argval;
        return nu_canfd_configure(can, &can->config);

    case RT_DEVICE_CTRL_CLR_INT:
        psNuCANFD->int_flag &= ~argval;
        return nu_canfd_configure(can, &can->config);

#if defined(RT_CAN_USING_HDR)
    case RT_CAN_CMD_SET_FILTER:
    {
        struct rt_can_filter_config *filter_cfg = (struct rt_can_filter_config *)arg;

        RT_ASSERT(filter_cfg);

        for (int i = 0; i < filter_cfg->count; i++)
        {
            uint32_t u32FEC = (filter_cfg->items[i].mode == RT_CAN_MODE_PRIV) ?  eCANFD_FLTR_ELEM_SET_PRI_STO_FIFO0 : eCANFD_FLTR_ELEM_STO_FIFO0;

            /* Set the filter rule */
            if (filter_cfg->items[i].ide == RT_CAN_STDID)
            {
                /* for 11-bit */
                CANFD_STD_FILTER_T sStdFilter;

                if (i >= CANFD_MAX_11_BIT_FTR_ELEMS)  // Check filter entry limitation
                    return -(RT_ERROR);

                sStdFilter.SFID2 = filter_cfg->items[i].mask;    /*!<Standard Filter ID 2. */ //mask
                sStdFilter.SFID1 = filter_cfg->items[i].id;      /*!<Standard Filter ID 1. */ //filter
                sStdFilter.SFEC  = u32FEC;                       /*!<Standard Filter Element Configuration */ //001b: Store in Rx FIFO 0 if filter matches
                sStdFilter.SFT   = eCANFD_SID_FLTR_TYPE_CLASSIC; /*!<Standard Filter Type */ //10b: Classic filter: SFID1 = filter, SFID2 = mask

                CANFD_SetSIDFltr(psNuCANFD->base, i, sStdFilter.VALUE);
            }
            else
            {
                /* for 29-bit */
                CANFD_EXT_FILTER_T sXidFilter;

                if (i >= CANFD_MAX_29_BIT_FTR_ELEMS) // Check filter entry limitation
                    return -(RT_ERROR);

                sXidFilter.EFID1 = filter_cfg->items[i].mask;     /*!<Extended Filter ID 2. */ //mask
                sXidFilter.EFID2 = filter_cfg->items[i].id;       /*!<Extended Filter ID 1. */ //filter
                sXidFilter.EFEC  = u32FEC;                        /*!<Extended Filter Element Configuration */ //001b: Store in Rx FIFO 0 if filter matches
                sXidFilter.EFT   = eCANFD_XID_FLTR_TYPE_CLASSIC;  /*!<Extended Filter Type */ //10b: Classic filter: SFID1 = filter, SFID2 = mask

                CANFD_SetXIDFltr(psNuCANFD->base, i, sXidFilter.LOWVALUE, sXidFilter.HIGHVALUE);
            }

        } //for (int i = 0; i < filter_cfg->count; i++)
    }
    break;
#endif

    case RT_CAN_CMD_SET_MODE:
        if ((argval == RT_CAN_MODE_NORMAL) ||
                (argval == RT_CAN_MODE_LISTEN) ||
                (argval == RT_CAN_MODE_LOOPBACK) ||
                (argval == RT_CAN_MODE_LOOPBACKANLISTEN))
        {
            if (argval != can->config.mode)
            {
                can->config.mode = argval;
                return nu_canfd_configure(can, &can->config);
            }
        }
        else
        {
            return -(RT_ERROR);
        }
        break;

    case RT_CAN_CMD_SET_BAUD:
    {
        if ((argval == CAN1MBaud) ||
                (argval == CAN800kBaud) ||
                (argval == CAN500kBaud) ||
                (argval == CAN250kBaud) ||
                (argval == CAN125kBaud) ||
                (argval == CAN100kBaud) ||
                (argval == CAN50kBaud) ||
                (argval == CAN20kBaud) ||
                (argval == CAN10kBaud))
        {
            if (argval != can->config.baud_rate)
            {
                can->config.baud_rate = argval;
                return nu_canfd_configure(can, &can->config);
            }
        }
        else
        {
            return -(RT_ERROR);
        }
    }
    break;

    case RT_CAN_CMD_SET_PRIV:
        if (argval != RT_CAN_MODE_PRIV &&
                argval != RT_CAN_MODE_NOPRIV)
        {
            return -(RT_ERROR);
        }
        if (argval != can->config.privmode)
        {
            can->config.privmode = argval;
            return nu_canfd_configure(can, &can->config);
        }
        break;

    case RT_CAN_CMD_GET_STATUS:
    {
        rt_uint32_t u32ErrCounter = psNuCANFD->base->ECR;
        rt_uint32_t u32ProtocolStatus = psNuCANFD->base->PSR;

        RT_ASSERT(arg);

        /*Receive Error Counter, return value is with Receive Error Passive.*/
        can->status.rcverrcnt = ((u32ErrCounter & CANFD_ECR_REC_Msk) >> CANFD_ECR_REC_Pos);

        /*Transmit Error Counter*/
        can->status.snderrcnt = ((u32ErrCounter & CANFD_ECR_TEC_Msk) >> CANFD_ECR_TEC_Pos);

        /*Last Error Type*/
        can->status.lasterrtype = ((u32ProtocolStatus & CANFD_PSR_LEC_Msk) >> CANFD_PSR_LEC_Pos);

        /*Status error code*/
        can->status.errcode = (u32ProtocolStatus & CANFD_PSR_EW_Msk) ? 1 :
                              (u32ProtocolStatus & CANFD_PSR_EP_Msk) ? 2 :
                              (u32ProtocolStatus & CANFD_PSR_BO_Msk) ? 3 :
                              0;

        rt_memcpy(arg, &can->status, sizeof(struct rt_can_status));
    }
    break;

    default:
        return -(RT_EINVAL);

    }

    return RT_EOK;
}

static int nu_canfd_sendmsg(struct rt_can_device *can, const void *buf, rt_uint32_t boxno)
{
    CANFD_FD_MSG_T sTxMsg;
    struct rt_can_msg *pmsg;
    nu_canfd_t psNuCANFD = (nu_canfd_t)can;

    RT_ASSERT(can);
    RT_ASSERT(buf);

    pmsg = (struct rt_can_msg *) buf;

    if (pmsg->ide == RT_CAN_STDID && IS_CAN_STDID(pmsg->id))
    {
        /* Standard ID (11 bits)*/
        sTxMsg.u32Id = pmsg->id;
        sTxMsg.eIdType = eCANFD_SID;
    }
    else if (pmsg->ide == RT_CAN_EXTID && IS_CAN_EXTID(pmsg->id))
    {
        /* Extended ID (29 bits)*/
        sTxMsg.u32Id = pmsg->id;
        sTxMsg.eIdType = eCANFD_XID;
    }
    else
    {
        goto exit_nu_canfd_sendmsg;
    }

    sTxMsg.bBitRateSwitch = 0;

    if (pmsg->rtr == RT_CAN_DTR)
    {
        /* Data frame */
        sTxMsg.eFrmType = eCANFD_DATA_FRM;
    }
    else if (pmsg->rtr == RT_CAN_RTR)
    {
        /* Remote frame */
        sTxMsg.eFrmType = eCANFD_REMOTE_FRM;
    }
    else
    {
        goto exit_nu_canfd_sendmsg;
    }

    /* Check the parameters */
    if (IS_CAN_DLC(pmsg->len))
    {
        sTxMsg.u32DLC = pmsg->len;
    }
    else
    {
        goto exit_nu_canfd_sendmsg;
    }

    if (pmsg->len > 0)
    {
        rt_memcpy(&sTxMsg.au8Data[0], pmsg->data, pmsg->len);
    }

    if (!CANFD_TransmitTxMsg(psNuCANFD->base, 0, &sTxMsg))
    {
        goto exit_nu_canfd_sendmsg;
    }

    return RT_EOK;

exit_nu_canfd_sendmsg:

    return -(RT_ERROR);
}

static int nu_canfd_recvmsg(struct rt_can_device *can, void *buf, rt_uint32_t boxno)
{
    CANFD_FD_MSG_T sRxMsg;
    struct rt_can_msg *pmsg;
    nu_canfd_t psNuCANFD = (nu_canfd_t)can;

    RT_ASSERT(can);
    RT_ASSERT(buf);

    pmsg = (struct rt_can_msg *) buf;

    /* get data */
    if (CANFD_ReadRxFifoMsg(psNuCANFD->base, 0, &sRxMsg) == FALSE)
    {
        rt_kprintf("No available RX Msg.\n");
        return -(RT_ERROR);
    }

#ifdef RT_CAN_USING_HDR
    /* Hardware filter messages are valid */
    pmsg->hdr = boxno;
    can->hdr[pmsg->hdr].connected = 1;
#endif

    pmsg->ide = (sRxMsg.eIdType == eCANFD_SID) ? RT_CAN_STDID : RT_CAN_EXTID;
    pmsg->rtr = (sRxMsg.eFrmType == eCANFD_DATA_FRM) ? RT_CAN_DTR : RT_CAN_RTR;
    pmsg->id  = sRxMsg.u32Id;
    pmsg->len = sRxMsg.u32DLC;

    if (pmsg->len > 0)
        rt_memcpy(&pmsg->data[0], &sRxMsg.au8Data[0], pmsg->len);

    return RT_EOK;
}

/**
 * Hardware CAN Initialization
 */
static int rt_hw_canfd_init(void)
{
    int i;
    rt_err_t ret = RT_EOK;

    for (i = (CANFD_START + 1); i < CANFD_CNT; i++)
    {
        nu_canfd_arr[i].dev.config = nu_canfd_default_config;

#ifdef RT_CAN_USING_HDR
        nu_canfd_arr[i].dev.config.maxhdr = RT_CANMSG_BOX_SZ;
#endif
        /* Register can device */
        ret = rt_hw_can_register(&nu_canfd_arr[i].dev, nu_canfd_arr[i].name, &nu_canfd_ops, NULL);
        RT_ASSERT(ret == RT_EOK);

        /* Unmask interrupt. */
        NVIC_EnableIRQ(nu_canfd_arr[i].irqn0);
        NVIC_EnableIRQ(nu_canfd_arr[i].irqn1);
    }

    return (int)ret;
}
INIT_DEVICE_EXPORT(rt_hw_canfd_init);
#endif  //#if defined(BSP_USING_CANFD)