#include "can.h"
#include "stm32f4xx.h"
#include "stm32f4xx_gpio.h"

// CAN初始化
// tsjw:重新同步跳跃时间单元.范围:CAN_SJW_1tq~ CAN_SJW_4tq
// tbs2:时间段2的时间单元.   范围:CAN_BS2_1tq~CAN_BS2_8tq;
// tbs1:时间段1的时间单元.   范围:CAN_BS1_1tq ~CAN_BS1_16tq
// brp :波特率分频器.范围:1~1024; tq=(brp)*tpclk1
// 波特率=Fpclk1/((tbs1+1+tbs2+1+1)*brp);
// mode:CAN_Mode_Normal,普通模式;CAN_Mode_LoopBack,回环模式;
// Fpclk1的时钟在初始化的时候设置为42M,如果设置CAN1_Mode_Init(CAN_SJW_1tq,CAN_BS2_6tq,CAN_BS1_7tq,6,CAN_Mode_LoopBack);
// 则波特率为:42M/((6+7+1)*6)=500Kbps

u8 can1_mode_init(uint8_t tsjw, uint8_t tbs2, uint8_t tbs1, uint16_t brp, uint8_t mode)
{
    GPIO_InitTypeDef      GPIO_InitStructure;
    CAN_InitTypeDef       CAN_InitStructure;
    CAN_FilterInitTypeDef CAN_FilterInitStructure;
    NVIC_InitTypeDef      NVIC_InitStructure;

    CAN_DeInit(CAN1);

    RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); // 使能PORTA时钟
    RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);  // 使能CAN1时钟

    GPIO_InitStructure.GPIO_Mode  = GPIO_Mode_AF;
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;
    GPIO_InitStructure.GPIO_PuPd  = GPIO_PuPd_UP;
    GPIO_InitStructure.GPIO_Pin   = GPIO_Pin_11 | GPIO_Pin_12;
    GPIO_Init(GPIOA, &GPIO_InitStructure); // 初始化IO

    GPIO_PinAFConfig(GPIOA, GPIO_PinSource11, GPIO_AF_CAN1);
    GPIO_PinAFConfig(GPIOA, GPIO_PinSource12, GPIO_AF_CAN1);

    // CAN单元设置
    CAN_InitStructure.CAN_TTCM      = DISABLE; // 非时间触发通信模式
    CAN_InitStructure.CAN_ABOM      = ENABLE;  // 软件自动离线管理
    CAN_InitStructure.CAN_AWUM      = DISABLE; // 睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
    CAN_InitStructure.CAN_NART      = DISABLE; // 禁止报文自动传送
    CAN_InitStructure.CAN_RFLM      = DISABLE; // 报文不锁定,新的覆盖旧的
    CAN_InitStructure.CAN_TXFP      = DISABLE; // 优先级由报文标识符决定
    CAN_InitStructure.CAN_Mode      = mode;    // 模式设置
    CAN_InitStructure.CAN_SJW       = tsjw;    // 重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位 CAN_SJW_1tq~CAN_SJW_4tq
    CAN_InitStructure.CAN_BS1       = tbs1;    // Tbs1范围CAN_BS1_1tq ~CAN_BS1_16tq
    CAN_InitStructure.CAN_BS2       = tbs2;    // Tbs2范围CAN_BS2_1tq ~	CAN_BS2_8tq
    CAN_InitStructure.CAN_Prescaler = brp;     // 分频系数(Fdiv)为brp+1
    CAN_Init(CAN1, &CAN_InitStructure);        // 初始化CAN1

    // 配置过滤器0
    CAN_FilterInitStructure.CAN_FilterNumber = 0; // 过滤器0
    CAN_FilterInitStructure.CAN_FilterMode   = CAN_FilterMode_IdMask;
    CAN_FilterInitStructure.CAN_FilterScale  = CAN_FilterScale_32bit; // 32位

    // 只接收标识符位0x0666报文  注意：RTR  IDE  SRR也参与构成标识符
    CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; //(((u32)0x0666<<3)&0xFFFF0000)>>16;				//要过滤的ID高位
    CAN_FilterInitStructure.CAN_FilterIdLow  = 0x0000; //(((u32)0x0666<<3)|CAN_ID_EXT|CAN_RTR_DATA)&0xFFFF; //要过滤的ID低位

    CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; // 32位MASK
    //    CAN_FilterInitStructure.CAN_FilterMaskIdLow=0xfff8; // 最后3位不管
    CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0000; // 最后3位不管

    CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; // 过滤器0关联到FIFO0
    CAN_FilterInitStructure.CAN_FilterActivation     = ENABLE;           // 激活过滤器0
    CAN_FilterInit(&CAN_FilterInitStructure);                            // 滤波器初始化

    CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE); // FIFO0消息挂号中断允许.
    NVIC_InitStructure.NVIC_IRQChannel                   = CAN1_RX0_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0; // 次优先级为0
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);

    // CAN_ITConfig(CAN1, CAN_IT_TME, ENABLE); // FIFO0消息挂号中断允许.
    NVIC_InitStructure.NVIC_IRQChannel                   = CAN1_TX_IRQn;
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority        = 0; // 次优先级为0
    NVIC_InitStructure.NVIC_IRQChannelCmd                = ENABLE;
    NVIC_Init(&NVIC_InitStructure);
    ////////////////////////////////////////////////

    return 0;
}

/**********************************************************************************************************
 *	函 数 名: CAN1_Init
 *	功能说明: CAN1初始化
 *	形    参: 无
 *	返 回 值: 无
 **********************************************************************************************************/
void can_init(void)
{
#if defined(__CAN_BAUD_500K)
    can1_mode_init(CAN_SJW_1tq, CAN_BS2_6tq, CAN_BS1_7tq, 6, CAN_Mode_Normal); // CAN1初始化环回模式,波特率500Kbps
#elif defined(__CAN_BAUD_250K)
    can1_mode_init(CAN_SJW_1tq, CAN_BS2_6tq, CAN_BS1_7tq, 12, CAN_Mode_Normal); // CAN1初始化环回模式,波特率250Kbps
#else
#error no can baud macro!;
#endif
}
