#include "user_can.h"
#include "user_config.h"
#include "dip_sw.h"

tmosTaskID user_can_task_id = INVALID_TASK_ID;
static uint16_t user_can_task_process_event(uint8_t task_id, uint16_t events);

static vUser_can_recv_data_func xRecv_data = NULL;
static uint8_t can_node_id = 0x00;
static user_can_work_s user_can_work = {
    .sendData = {0},
    .sendSize = 0,
    .RxMessage = {0},
};

/*******************************************************************************
  * @函数名称   prvUser_can_gpio_Init
  * @函数说明   GPIO初始化
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_can_gpio_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure = {0};
    CAN_InitTypeDef CAN_InitSturcture = {0};
    NVIC_InitTypeDef NVIC_InitStructure;

    USER_CAN_GPIO_RCC_ENABLE;
    USER_CAN_RCC_ENABLE;

#ifdef USER_CAN_REMAPCONFIG_ENABLE
    USER_CAN_REMAPCONFIG_ENABLE;
#endif

    GPIO_InitStructure.GPIO_Pin = CAN_TX_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(CAN_TX_GPIO, &GPIO_InitStructure);

    GPIO_InitStructure.GPIO_Pin = CAN_RX_PIN;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(CAN_RX_GPIO, &GPIO_InitStructure);

    CAN_InitSturcture.CAN_TTCM = DISABLE;
    CAN_InitSturcture.CAN_ABOM = ENABLE; // 自动离线管理
    CAN_InitSturcture.CAN_AWUM = ENABLE; // 自动唤醒
    CAN_InitSturcture.CAN_NART = ENABLE; // 自动重传
    CAN_InitSturcture.CAN_RFLM = DISABLE; // 不锁定接收FIFO
    CAN_InitSturcture.CAN_TXFP = ENABLE; // 优先级由标识符决定
    CAN_InitSturcture.CAN_Mode = CAN_Mode_Normal; // 正常模式
    CAN_InitSturcture.CAN_SJW = CAN_SJW_1tq;

    switch(user_config_param.can_baud)
    {
        case CAN_BAUD_100:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 60;
        }break;
        case CAN_BAUD_150:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 40;
        }break;
        case CAN_BAUD_200:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 30;
        }break;
        case CAN_BAUD_250:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 24;
        }break;
        case CAN_BAUD_300:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 =CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 20;
        }break;
        case CAN_BAUD_400:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 15;
        }break;
        case CAN_BAUD_500:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 12;
        }break;
        case CAN_BAUD_666:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 9;
        }break;
        case CAN_BAUD_800:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_7tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 6;
        }break;
        case CAN_BAUD_1000:
        default:{
            CAN_InitSturcture.CAN_BS1 = CAN_BS1_5tq;
            CAN_InitSturcture.CAN_BS2 = CAN_BS2_2tq;
            CAN_InitSturcture.CAN_Prescaler = 6;
        }break;
    }

    CAN_Init(CAN_TYPE, &CAN_InitSturcture);

    // 配置CAN接收中断
    NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
}



/*******************************************************************************
  * @函数名称   prvUser_can_filter
  * @函数说明   设置过滤
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void prvUser_can_filter(void)
{
    CAN_FilterInitTypeDef CAN_FilterInitstructure = {0};

    CAN_FilterInitstructure.CAN_FilterNumber = 0;
    CAN_FilterInitstructure.CAN_FilterMode = CAN_FilterMode_IdMask;
    CAN_FilterInitstructure.CAN_FilterScale = CAN_FilterScale_32bit;
    CAN_FilterInitstructure.CAN_FilterIdHigh = ((CAN_SDO_RX + can_node_id) << 5);
    CAN_FilterInitstructure.CAN_FilterIdLow = 0x0000;
    CAN_FilterInitstructure.CAN_FilterMaskIdHigh = 0x7FF << 5;
    CAN_FilterInitstructure.CAN_FilterMaskIdLow = 0x0000;
    CAN_FilterInitstructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0;
    CAN_FilterInitstructure.CAN_FilterActivation = ENABLE;

    CAN_FilterInit(&CAN_FilterInitstructure);
    
}


/*********************************************************************
 * @fn      CAN_Send_Msg
 *
 * @brief   CAN Transmit function.
 *
 * @param   msg - Transmit data buffer.
 *          len - Data length.
 *
 * @return  0 - Send successful.
 *          1 - Send failed.
 */
uint8_t ucCAN_Send_Msg(uint8_t *msg, uint8_t len)
{
    uint8_t  mbox;
    
    if(len > 8)
    {
        return 0;
    }

    CanTxMsg CanTxStructure;

    CanTxStructure.StdId = CAN_SDO_TX + can_node_id;
    CanTxStructure.IDE = CAN_Id_Standard;

    CanTxStructure.RTR = CAN_RTR_Data;
    CanTxStructure.DLC = len;

    for(uint8_t i = 0; i < len; i++) {
        CanTxStructure.Data[i] = msg[i];
    }

    mbox = CAN_Transmit(CAN1, &CanTxStructure);
    
    uint16_t timeout = 0;

    while((CAN_TransmitStatus(CAN_TYPE, mbox) != CAN_TxStatus_Ok) && (timeout < 0xFFF))
    {
        timeout++;
    }

    if(timeout == 0xFFF)
    {
        return 0;
    }
    else
    {
        return len;
    }
}

/*******************************************************************************
  * @函数名称   user_charge_task_process_event
  * @函数说明   task的event处理回调函数,需要在注册task时候,传进去
  * @输入参数  	task_id：任务ID
               events：事件
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static uint16_t user_can_task_process_event(uint8_t task_id, uint16_t events)
{
    //event 处理
    if(events & (1 << CAN_QUEUE_SEND))
    {
        ucCAN_Send_Msg(user_can_work.sendData, user_can_work.sendSize);
        return (events ^ (1 << CAN_QUEUE_SEND)); //异或的方式清除该事件运行标志，并返回未运行的事件标志
    }

    if(events & (1 << CAN_QUEUE_RECIEVE))
    {
        // 从FIFO0读取消息
        // PRINT("STDID=0x%X,DLC=%d\n",user_can_work.RxMessage.StdId, user_can_work.RxMessage.DLC);
        // PRINT("DATA=%02X %02X %02X %02X %02X %02X %02X %02X\n", user_can_work.RxMessage.Data[0], user_can_work.RxMessage.Data[1],
        //                                                         user_can_work.RxMessage.Data[2], user_can_work.RxMessage.Data[3],
        //                                                         user_can_work.RxMessage.Data[4], user_can_work.RxMessage.Data[5],
        //                                                         user_can_work.RxMessage.Data[6], user_can_work.RxMessage.Data[6]);

        if(xRecv_data != NULL)
        {
            xRecv_data(user_can_work.RxMessage.Data, user_can_work.RxMessage.DLC);
        }
        return (events ^ (1 << CAN_QUEUE_RECIEVE)); //异或的方式清除该事件运行标志，并返回未运行的事件标志
    }

    if(events & (1 << CAN_QUEUE_TIME))
    {
        ucCAN_Send_Msg(user_can_work.sendData, user_can_work.sendSize);
        return (events ^ (1 << CAN_QUEUE_TIME)); //异或的方式清除该事件运行标志，并返回未运行的事件标志
    }

    dipsw_task_process_event(task_id, events);

    return 0;
}

/*******************************************************************************
  * @函数名称   set_user_can_Queue
  * @函数说明   开始can任务event
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
static void set_user_can_Queue(USER_CAN_QUEUE_TYPE type)
{
    if(can_node_id > 0)
    {
        bStatus_t stat = tmos_start_task(user_can_task_id, (1 << type), MS1_TO_SYSTEM_TIME(1));
    }
}

/*******************************************************************************
  * @函数名称   vUser_can_send_data
  * @函数说明   惨数据发送
  * @输入参数  	data：数据
  *            size：长度
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_can_send_data(uint8_t *data, uint8_t size)
{
    if(size <= 8)
    {
        memcpy(user_can_work.sendData, data, size);
        user_can_work.sendSize = size;
        set_user_can_Queue(CAN_QUEUE_SEND);
    }
}

/*******************************************************************************
  * @函数名称   vUser_can_recv_data
  * @函数说明   can数据接收
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_can_recv_data(CanRxMsg *RxMessage)
{
    memcpy((void *)&(user_can_work.RxMessage), (void *)RxMessage, sizeof(CanRxMsg));
    set_user_can_Queue(CAN_QUEUE_RECIEVE);
}

/*******************************************************************************
  * @函数名称   vUser_can_set_recv_data_func
  * @函数说明   设置CAN接收数据上报回调函数
  * @输入参数  	func：函数指针
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_can_set_recv_data_func(vUser_can_recv_data_func func)
{
    xRecv_data = func;
}

/*******************************************************************************
  * @函数名称   vUser_can_set_addr
  * @函数说明   设置CAN Node id
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_can_set_addr(uint8_t addr)
{
    if(addr != can_node_id)
    {
        can_node_id = addr;
        PRINT("Node ID=%d\n", can_node_id);
        if(addr == 0)
        {
            CAN_ITConfig(CAN_TYPE, CAN_IT_FMP0, DISABLE);
        }
        else{
            prvUser_can_filter();
            CAN_ITConfig(CAN_TYPE, CAN_IT_FMP0, ENABLE);
            // 启用CAN接收
            // bStatus_t stat = tmos_start_reload_task(user_can_task_id, (1 << CAN_QUEUE_TIME), MS1_TO_SYSTEM_TIME(3000));
        }
    }
}

/*******************************************************************************
  * @函数名称   user_charge_init
  * @函数说明   Charge初始化
  * @输入参数  	无
  * @输出参数   无
  * @返回参数   无
*******************************************************************************/
void vUser_can_init(void)
{
    prvUser_can_gpio_Init();

    user_can_task_id  = TMOS_ProcessEventRegister(user_can_task_process_event);
    PRINT("user_can_task_id=%d\n", user_can_task_id);
}
 