/***********************************************************************
 * Copyright (c)  2017 - 2022, Unicmicro Co.,Ltd .
 * All rights reserved.
 * Filename    : can.c
 * Description : can driver source file
 * Author(s)   : Mason
 * version     : V1.0
 * Modify date : 2022-08-04
 ***********************************************************************/
#include "can.h"

void (*can_callback)(void) = NULL;
/************************************************************************
 * Function     : CAN_IRQHandler
 * Description  : CAN IRQHandler
 * Input        : none
 * Output		: none
 * Return       : none
 ************************************************************************/
void CAN_IRQHandler(void)
{
	uint32_t temp;
	temp = REG_CAN_ISR;

	if(temp & CAN_IMR_RIM)	                                            //接收完成标志
	{
		if(can_callback != NULL)
		{
			(*can_callback)();
		}
		REG_CAN_ISR = CAN_IMR_RIM;                                      //清除中断状态
	}
	else
	{
		REG_CAN_ISR = 0x7F;			                                    //清除中断状态
	}
		
}

/************************************************************************
 * Function     : can_init
 * Description  : can init
 * Input        : baudrate 速率可以选择为1M/500k/250k/125k bps
 *                APB时钟=PCLK=48Mhz,
 *                CAN波特率 BitRate = Fpclk/2*((BRP+1)*(TS1+TS2+3)), 有个约定:TS1>=TS2
 *
 *                设波特率为1M的参数：
 *                设置BRP=2(6分频), BitRate = 1M = 48M/2((2+1)*(TS1+TS2+3)),所以可以设置TS1=3,TS2=2
 *                
 *                设波特率为500K的参数：
 *                设置BRP=5(12分频), BitRate = 0.5M = 48M/2((5+1)*(TS1+TS2+3)),所以可以设置TS1=3,TS2=2
 *                
 *                设波特率为250K的参数：
 *                设置BRP=11(24分频), BitRate = 0.25M = 48M/2((11+1)*(TS1+TS2+3)),所以可以设置TS1=3,TS2=2
 *                
 *                设波特率为125K的参数：
 *                设置BRP=23(48分频), BitRate = 0.125M = 48M/2((23+1)*(TS1+TS2+3)),所以可以设置TS1=3,TS2=2
 * Return       : none
 ************************************************************************/
void can_init(uint8_t baudrate)
{
	REG_SCU_PERICLKEN |= (1<<24);									    //开CAN时钟使能	
	REG_SCU_PERIRESET |= (1<<24);									    //CAN正常工作

	REG_SCU_IOCTRLPROTECT = 0xA5A55A5A; 							    //清除IO写保护
    
	REG_SCU_PBSEL = (REG_SCU_PBSEL&(~(0xf<<16)))|(6<<16);			    //PB4复用为CAN_TX
    REG_SCU_PDSEL = (REG_SCU_PDSEL&(~(0xf<<20)))|(6<<20);		        //PD5复用为CAN_RX
	REG_SCU_PADIE0 |= (1<<29);		                                    //使能RX管脚  
        
	REG_SCU_IOCTRLPROTECT = 0xffffffff; 							    //开启IO写保护
        
	REG_CAN_MR |= (1<<2); 											    //CAN工作复位模式
        
	switch(baudrate)    
    {   
         case CAN_RATE_1M:                                			    //1M bps
				REG_CAN_BTR0 = (REG_CAN_BTR0&(~(3<<6)))|(1<<6);		    //SJW同步跳跃宽度 2个时间单元
				REG_CAN_BTR0 = (REG_CAN_BTR0&(~(0x3f<<0)))|(2<<0);	    //BRP 6分频
				REG_CAN_BTR1 = (REG_CAN_BTR1&(~(0x07<<0)))|(3<<0);	    //TS1 4个时间单元
				REG_CAN_BTR1 = (REG_CAN_BTR1&(~(0x0f<<4)))|(2<<4);	    //TS2 3个时间单元
            
				break;  
            
		 case CAN_RATE_500K:                                		    //500k bps
				REG_CAN_BTR0 = (REG_CAN_BTR0&(~(3<<6)))|(1<<6);		    //SJW同步跳跃宽度 2个时间单元
				REG_CAN_BTR0 = (REG_CAN_BTR0&(~(0x3f<<0)))|(5<<0);	    //BRP 12分频
				REG_CAN_BTR1 = (REG_CAN_BTR1&(~(0x07<<0)))|(3<<0);	    //TS1 4个时间单元
				REG_CAN_BTR1 = (REG_CAN_BTR1&(~(0x0f<<4)))|(2<<4);	    //TS2 3个时间单元
				break;  
            
		 case CAN_RATE_250K:                                	        //250k bps		 
				REG_CAN_BTR0 = (REG_CAN_BTR0&(~(3<<6)))|(1<<6);		    //SJW同步跳跃宽度 2个时间单元
				REG_CAN_BTR0 = (REG_CAN_BTR0&(~(0x3f<<0)))|(11<<0);	    //BRP 24分频
				REG_CAN_BTR1 = (REG_CAN_BTR1&(~(0x07<<0)))|(3<<0);	    //TS1 4个时间单元
				REG_CAN_BTR1 = (REG_CAN_BTR1&(~(0x0f<<4)))|(2<<4);	    //TS2 3个时间单元
				break;  
            
		 case CAN_RATE_125K:                                		    //125k bps 
				REG_CAN_BTR0 = (REG_CAN_BTR0&(~(3<<6)))|(1<<6);		    //SJW同步跳跃宽度 2个时间单元
				REG_CAN_BTR0 = (REG_CAN_BTR0&(~(0x3f<<0)))|(23<<0);	    //BRP 48分频
				REG_CAN_BTR1 = (REG_CAN_BTR1&(~(0x0f<<0)))|(3<<0);	    //TS1 4个时间单元
				REG_CAN_BTR1 = (REG_CAN_BTR1&(~(0x0f<<4)))|(2<<4);	    //TS2 3个时间单元
				break;
		 
		 default:
			 
				break;
	}
	
	REG_CAN_MR |= (1<<7);									            //reset rx fifo pointer
	REG_CAN_ISR = 0x7F;										            //清除中断标志
                
	REG_CAN_AMR = 0xFFFFFFFF;           
	REG_CAN_RXADDR = CAN_RX_ADDR;							            //设置接收缓存基地址
                
	REG_CAN_MR &= ~(1<<1);									            //CAN进入正常模式
            
	REG_CAN_MR &= ~(1<<2); 									            //CAN退出复位模式
}

/************************************************************************
 * Function     : can_filter_config
 * Description  : can filter config
 * Input        : uint32_t filter_value：filter value 
 *                uint8_t filter_mode：single filter or double filter
 *                uint8_t data_mode: standard frame or extended frame
 *                uint8_t filter_en ：enable/disable
 * Return       : none
 ************************************************************************/
void can_filter_config(uint32_t filter_value, uint8_t filter_mode, uint8_t data_mode, uint8_t filter_en)
{
	REG_CAN_MR |= (1<<2); 					                            //CAN工作复位模式
	
	REG_CAN_ACR = 0;
	REG_CAN_AMR = 0;
	
	if(filter_en)                                                       //can过滤器使能
	{
		if(filter_mode)
		{
			REG_CAN_MR |= (1<<0);				                        //使用单过滤器
			if(data_mode == 0)					                        //标准格式
			{
				REG_CAN_ACR = filter_value;
				REG_CAN_AMR = 0xFFFF0000;		                        //不比对data
			}
			else								                        //扩展格式
			{
				REG_CAN_ACR = filter_value;
				REG_CAN_AMR = 0x0;
			}
		}
		else
		{
			REG_CAN_MR &= ~(1<<0);				                        //使用双过滤器
			if(data_mode == 0)					                        //标准格式
			{
				REG_CAN_ACR = filter_value;
				REG_CAN_AMR = 0xF000F00;		                        //比对ID1和ID2，不比对DATA
				
			}
			else								                        //扩展格式
			{
				REG_CAN_ACR = filter_value;
				REG_CAN_AMR = 0x0;				                        //比对ID1和ID2
			
			}
		}
	}
	else                                                                //can 过滤器不使能
	{
		REG_CAN_AMR = 0xFFFFFFFF;				                        //不比对
	}
	
	REG_CAN_MR &= ~(1<<1);					                            //CAN进入正常模式
	REG_CAN_MR &= ~(1<<2); 					                            //CAN退出复位模式
}

/************************************************************************
 * Function     : can_irq_init
 * Description  : can irq init
 * Input        : uint8_t irq_enable: interrupt enable/disable
 *                void (*can_int)(): interrupt callback function 
 * Return       : none
 ************************************************************************/
void can_irq_init(uint8_t irq_enable, void (*can_int)())
{
	if(irq_enable == CAN_IRQ_ENABLE)
	{
		NVIC_ClearPendingIRQ(CAN_IRQn);
		NVIC_EnableIRQ(CAN_IRQn);
		
		REG_CAN_IMR |= CAN_IMR_RIM;	                                    //使能接收完成中断
		
		can_callback = can_int;		                                    //中断回调函数
	}
	else
	{
		REG_CAN_IMR &= ~CAN_IMR_RIM;                                    //禁止接收完成中断
		
		can_callback = NULL;
	}
	
}

/************************************************************************
 * Function     : can_send_data
 * Description  : can send data
 * Input        : uint32_t *data： can_tx_msg
 * Return       : none
 ************************************************************************/
void can_send_data(uint32_t *data)
{
	uint32_t i = 0;
	
	for(i=0; i<4; i++)
	{
		REG_CAN_TXBUF = *data++;
	}
	
	REG_CAN_CMR |= (1<<2);	                                            //启动发送
	
	while(!(REG_CAN_SR & (1<<5)));	                                    //等待发送完成

}

/************************************************************************
 * Function     : can_read_data
 * Description  : can read data；获取can数据
 * Input        : uint32_t *buff： data buff 
 *                uint8_t *ide：standard frame or extended frame 
 *                uint8_t *rtr：data frame or remote frame
 *                uint8_t *len：data length
 * Return       : none
 ************************************************************************/
void can_read_data(uint32_t *buff, uint8_t *ide, uint8_t *rtr, uint8_t *len)
{
	buff[0] = REG_CAN_RXBUF;						                    //读第一次RX FIFO，用于判断ID格式
	
	*ide = (uint8_t)((buff[0] & 0x80)>>7);			                    //获取IDE
	*rtr = (uint8_t)((buff[0] & 0x40)>>6);			                    //获取RTR
	*len = (uint8_t)((buff[0] & 0xF));				                    //获取数据len
                        
	if(*ide)										                    //扩展格式
	{
		if(*len >= 8)
		{
			buff[1] = REG_CAN_RXBUF;
			buff[2] = REG_CAN_RXBUF;
			buff[3] = REG_CAN_RXBUF;
		}
		else if(*len >= 4)
		{
			buff[1] = REG_CAN_RXBUF;
			buff[2] = REG_CAN_RXBUF;
		}
		else 
		{
			buff[1] = REG_CAN_RXBUF;
		}
	}
	else											                    //标准格式
	{
		if(*len >= 6)
		{
			buff[1] = REG_CAN_RXBUF;
			buff[2] = REG_CAN_RXBUF;
		}
		else 
		{
			buff[1] = REG_CAN_RXBUF;

		}
	}
	
	REG_CAN_ISR = 0x08;
}

/************************************************************************
 * Function     : can_get_sr_reg
 * Description  : can get sr reg
 * Input        : none
 * Return       : sr register value
 ************************************************************************/
uint32_t can_get_sr_reg(void)
{
	uint32_t temp;
	
	temp = REG_CAN_SR;
	
	return temp;
}

/************************************************************************
 * Function     : can_get_rmc_reg
 * Description  : can get rmc reg, can rx fifo data 
 * Input        : none
 * Return       : rmc register value
 ************************************************************************/
uint8_t can_get_rmc_reg(void)
{
	uint8_t temp;
	
	temp = REG_CAN_RMC;
	
	return temp;
}
