#include <stdint.h>
#include "gpio.h"
#include "isr.h"
#include "rte_can.h"


CANMSG_Type* CANMSG;
CanTxRxMsg CAN_RecvMsg;
CANBuffList_t CanBufList = {0};
can_rx_callback can_rx_handler = NULL;

uint8_t Read_RingBuff(CanTxRxMsg *data)
{
    if (CanBufList.length == 0)
    {
        return 0;
    }
    *data = CanBufList.data[CanBufList.Head];
    CanBufList.Head = (CanBufList.Head + 1) % LIST_BUF_MAX_NUM;
    CanBufList.length--;
    return 1;
}

/**
 * @brief CAN就收完成回调
 * 
 * @param msg 
 */
static void can_recv_handler(void *msg)
{
    INTC_ClearPendingIRQ(CAN0REC_IRQn);

    if (CAN_GetFlagStatus(CAN0, CAN_FLAG_REC) != RESET)
    {
        CAN_ClearFlag(CAN0, CAN_FLAG_REC);
        CAN_Receive_IT(CAN0, &CanBufList);
        Read_RingBuff(&CAN_RecvMsg);

        if (can_rx_handler != NULL)
        {
            can_rx_handler(&CAN_RecvMsg);
        }
    }
}

/**
 * @brief CAN初始�?
 * 
 * @param config CAN初始结构体指�?
 * @return uint8_t 0成功 1失败
 */
uint8_t rte_can_init(can_config_st_t *config)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    CAN_InitTypeDef CAN_InitStruct;

    /* GPIO AF set for CAN bus */
    GPIO_PinAFConfig(GPIO_PORT5, GPIO_Pin_1, GPIO_P51, GROUP_AF_CTXD);
    GPIO_PinAFConfig(GPIO_PORT5, GPIO_Pin_0, GPIO_P50, GROUP_AF_CRXD);

    /****** GPIO for CAN bus init ******/
    /* CTXD pin init */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_1;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Level = GPIO_Level_HIGH;
    GPIO_InitStruct.GPIO_Ctrl = GPIO_Control_DIG;
    GPIO_Init(GPIO_PORT5, &GPIO_InitStruct);

    /* CRXD pin init */
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_0;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IN;
    GPIO_InitStruct.GPIO_Ctrl = GPIO_Control_DIG;
    GPIO_Init(GPIO_PORT5, &GPIO_InitStruct);

    /****** GPIO for STB init ******/
    GPIO_InitStruct.GPIO_Pin = GPIO_Pin_2;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_OUT;
    GPIO_InitStruct.GPIO_Ctrl = GPIO_Control_DIG;
    GPIO_InitStruct.GPIO_PuPd = GPIO_PuPd_DOWN;
    GPIO_InitStruct.GPIO_Level = GPIO_Level_LOW;
    GPIO_Init(GPIO_PORT5, &GPIO_InitStruct);

    /****** CAN bus periphal init ******/
    CAN_InitStruct.CAN_Prescaler = config->freq;
    CAN_InitStruct.CAN_BitRatePrescaler = 2;
    CAN_InitStruct.CAN_SJW = CAN_SJW_1tq;
    CAN_InitStruct.CAN_BS1 = CAN_BS1_12tq;
    CAN_InitStruct.CAN_BS2 = CAN_BS2_3tq;
    CAN_InitStruct.CAN_OperateMode = CAN_OpMode_Initial;
    CAN_InitStruct.MASK1 = config->MASK[0]; // 0x001fffffU;//进行滤波屏蔽
    CAN_InitStruct.MASK2 = config->MASK[1];
    CAN_InitStruct.MASK3 = config->MASK[2];
    CAN_InitStruct.MASK4 = config->MASK[3];
    CAN_Init(CAN0, &CAN_InitStruct);

    can_rx_handler = config->rx_callback;

    CAN_OperatingModeRequest(CAN0, CAN_OpMode_Normal);

    CAN_ITConfig(CAN0, CAN_IT_REC, ENABLE);

    ISR_Register(CAN0REC_IRQn, can_recv_handler);

    INTC_EnableIRQ(CAN0REC_IRQn);

//    ISR_DisRegister(CAN0REC_IRQn, can_recv_handler);

    return 0;
    
}

/**
 * @brief can反初始化
 * @param CANx CAN0 �? CAN1
 * 
 * @return uint8_t 0成功 1失败
 */
uint8_t rte_can_deinit(CAN_CH ch)
{
    CAN_Type* CANx;

    if (ch == CAN_CH_0)
    {
        CANx = CAN0;
        can_rx_handler = NULL;
    }
    else
    {
        return 1;
    }
        
    CAN_DeInit(CANx);

    return 0;
}


/**
 * @brief 获取CAN是否BusOff
 * @param CANx CAN0 �? CAN1
 * 
 * @return uint8_t 0 没有busoff 
 *                 1 错误的操�? 2 busoff
 */
uint8_t get_can_busoff(CAN_CH ch)
{
    CAN_Type* CANx;

    if (ch == CAN_CH_0)
    {
        CANx = CAN0;
    }
    else
    {
        return 1;
    }

    if(CAN_ErrorStat_BusOff == CAN_GetErrorStatus(CANx))
    {
        return 2;
    }

    return 0;
}

/**
 * @brief 从busoff状态恢�?
 * 
 * @param CANx CAN0 �? CAN1
 * @return uint8_t 0成功 1失败
 */
uint8_t reset_busoff(CAN_CH ch)
{
    uint16_t data;
    CAN_Type* CANx;
    
    if (ch == CAN_CH_0)
    {
       CANx = CAN0;
    }
    else
    {
        return 1;
    }
    

    data = CANx->CCTRL;
    data &= 0xf8f8;
    data |= 0x0007;
    CANx->CCTRL = data;

    data = CANMSG->CMCTRL;
    data &= 0xfCfC;
    data |= 0x0002;
    CANMSG->CMCTRL = data;

    data = CANx->CCTRL;
    data &= 0xf8f8;
    data |= 0x0100;
    CANx->CCTRL = data;
    
    return 0;
}

/*  下面是一些例�? 自己�? 
	CAN_SendMsg.Id = 0x00aa0432;
	CAN_SendMsg.IDE = CAN_Id_Extended;
	CAN_SendMsg.CacheType = CAN_CacheType_Tx;
	CAN_SendMsg.RTR = CAN_RTR_Data;
	CAN_RecvMsg.Interrupt = DISABLE;
	CAN_SendMsg.DLC = 8;
	CAN_SendMsg.Data[7] = 0x9F;
	CAN_MessageCache_DeInit(CAN0MSG01);
	CAN_MessageCache_Init(CAN0MSG01, &CAN_SendMsg);

	CAN2_RecvMsg.Id = 0x00bb0432;
	CAN2_RecvMsg.IDE = CAN_Id_Extended;
	CAN2_RecvMsg.CacheType = CAN_CacheType_Rx_3Mask;
	CAN2_RecvMsg.RTR = CAN_RTR_Data;
	CAN2_RecvMsg.Interrupt = ENABLE;
	CAN_MessageCache_DeInit(CAN0MSG08);
	CAN_MessageCache_Init(CAN0MSG08, &CAN2_RecvMsg);
	CAN_MessageCache_OverWriteConfig(CAN0MSG08, ENABLE);

	CAN_RecvMsg.Id = 0x231;
	CAN_RecvMsg.IDE = CAN_Id_Standard;
	CAN_RecvMsg.CacheType = CAN_CacheType_Rx_1Mask;
	CAN_RecvMsg.RTR = CAN_RTR_Data;
	CAN_RecvMsg.Interrupt = ENABLE;
	CAN_MessageCache_DeInit(CAN0MSG07);
	CAN_MessageCache_Init(CAN0MSG07, &CAN_RecvMsg);
	CAN_MessageCache_OverWriteConfig(CAN0MSG07, ENABLE);

	CAN1_RecvMsg.Id = 0x032;
	CAN1_RecvMsg.IDE = CAN_Id_Standard;
	CAN1_RecvMsg.CacheType = CAN_CacheType_Rx_1Mask;
	CAN1_RecvMsg.RTR = CAN_RTR_Data;
	CAN1_RecvMsg.Interrupt = ENABLE;
	CAN_MessageCache_DeInit(CAN0MSG06);
	CAN_MessageCache_Init(CAN0MSG06, &CAN1_RecvMsg);
	CAN_MessageCache_OverWriteConfig(CAN0MSG06, ENABLE);

	CAN_Type* CANx = CAN0;
	uint16_t data;
	while(1)
	{
		CAN_SendMsg.Data[0] += 3;
		CAN_Transmit(CAN0MSG01, &CAN_SendMsg);
		
		m0_delay_us(100);
		if(Read_RingBuff(&Can_Msg))
		{
//			printf("id=%x ,%x-%x-%x-%x-%x-%x-%x \r\n",Can_Msg.Id,Can_Msg.Data[0],Can_Msg.Data[1],Can_Msg.Data[2],Can_Msg.Data[3],Can_Msg.Data[4],\
//			Can_Msg.Data[5],Can_Msg.Data[6]);
			printf("count =%d,id=%x \r\n",count++,Can_Msg.Id);
		}
		if(CAN_ErrorStat_BusOff == CAN_GetErrorStatus(CAN0))
		{
				data = CANx->CCTRL;
				data &= 0xf8f8;
				data |= 0x0007;
				CANx->CCTRL = data;

				data = CANMSG->CMCTRL;
				data &= 0xfCfC;
				data |= 0x0002;
				CANMSG->CMCTRL = data;
			
				data = CANx->CCTRL;
				data &= 0xf8f8;
				data |= 0x0100;
				CANx->CCTRL = data;
		}
	}
*/