

//#include "stdint.h"
//#include <string.h>
#include "IC_Config.h" 
#include "CAN_XHY.h"
#include "DoCAN_ISO15765.h"
#include "Diag_ID_Def.h"



/******************************************************************************

                                波特率设置

===============================================================================
- MSCAN通过其预分频器生成时间量子Tq作为采样CAN信号的时基

- 依据 Bosch CAN 2.0A/B 标准, MSCAN接收/发送每一位的时间被分为如下三段:

  ----------------------------------------------------------------------------
  | Sync_Seg |            Time Segment 1            |     Time Segment 2     |
  ----------------------------------------------------------------------------
  |<- 1 Tq ->|<------------  4 ~ 16 Tq  ----------->|<-----  2 ~ 8 Tq  ----->|
  |                                                                          |
  |<---------------------------  Total 8 ~ 25 Tq  -------------------------->|
  
  Sync_Seg：本段有固定的1Tq时长,CAN总线上信号的上升或下降沿在本段产生(发送时)或
            触发本段(接收时),标志CAN总线一个数据位收发的开始,用于同步收发
  时段 1  ：本段包括CAN标准的PROP_SEG段和PHASE_SEG1段,接收时,数据的采样发生于本
            段的后段靠近下一段处,本段的时长可以设置为 4 ~ 16 Tq
  时段 2  ：本段包括CAN标准的PHASE_SEG2段,本段的时长可以设置为 2 ~ 8 Tq

- 同步跳转宽度SJW：在重同步期间,采样点的位置被移动整数个Tq,该时间份额被允许的最
                   大值称为同步跳转宽度,它可被设置为 1 ~ 4 Tq
                   
- 用户有责任确保位时间设置遵从CAN标准
  --------------------------------------------------
       时段 1     |     时段 2     |  同步跳转宽度
  --------------------------------------------------
       5 ~ 10     |       2        |     1 ~ 2
       4 ~ 11     |       3        |     1 ~ 3
       5 ~ 12     |       4        |     1 ~ 4
       6 ~ 13     |       5        |     1 ~ 4
       7 ~ 14     |       6        |     1 ~ 4
       8 ~ 15     |       7        |     1 ~ 4
       9 ~ 16     |       8        |     1 ~ 4
  --------------------------------------------------
******************************************************************************/
#if (IC_Current == LD01)

#define MSCAN0_BAUD_RATE 250//LD01  250 //波特率,单位kbps	LD02 500 
#define MSCAN0_T_SEG1 13//LD01 13 //时间段1的Tq数	      LD02 12
#define MSCAN0_T_SEG2 2//LD01  2	 //时间段2的Tq数	      LD02 3

#elif(IC_Current == LD02)

#define MSCAN0_BAUD_RATE 500//LD01  250 //波特率,单位kbps	LD02 500 
#define MSCAN0_T_SEG1 12//LD01 13 //时间段1的Tq数	      LD02 12
#define MSCAN0_T_SEG2 3//LD01  2	 //时间段2的Tq数	      LD02 3

#endif

//采样位置计算 （1+MSCAN0_T_SEG1）/（1+MSCAN0_T_SEG1+MSCAN0_T_SEG2）
//计算过程中的1是Sync_Seg  同步段，固定为1。后下面的同步跳转宽度不是一个东西

#define MSCAN0_SAMPLE_POINT MSCAN0_SAMPLE_1POINT
#define MSCAN0_SJW 1//1 //2 //3               //同步跳转宽度

/******************************************************************************
采样点数选择                                                                                                                                    
******************************************************************************/
#define MSCAN0_SAMPLE_1POINT 0x00 //每位采样1个样本(高速CAN推荐)
#define MSCAN0_SAMPLE_3POINT 0x80 //每位采样3个样本

/******************************************************************************
波特率预处理
******************************************************************************/
#define MSCAN0_PRESCALER (8000000 / (1 + MSCAN0_T_SEG1 + MSCAN0_T_SEG2) / MSCAN0_BAUD_RATE / 1000)

#define MSCAN0_BTR0_VALUE ((INT8U)((MSCAN0_SJW - 1) << 6) | (INT8U)(MSCAN0_PRESCALER - 1))
#define MSCAN0_BTR1_VALUE (MSCAN0_SAMPLE_POINT | (INT8U)((MSCAN0_T_SEG2 - 1) << 4) | (INT8U)(MSCAN0_T_SEG1 - 1))
/////////////////////////////////////////////////////////////////////////////////////////////////////

#define Standard_Frame 1 //标准帧
#define Extended_Frame 0 //扩展帧
//CAN0  FIFO深度
#define TX0_BUF_LEN 15 // 10

#define CAN0_Frame_Type Extended_Frame //Standard_Frame

#define Sampling_Rate_Select

#if (CAN0_Frame_Type == Standard_Frame)
#elif (CAN0_Frame_Type == Extended_Frame)
#else
#error CAN0 Frame Type select error
#endif
////////////////////变量类型及定义//////////////////////////////////////////////////////////////////////////////////////////////
volatile _CAN_TX_BUF_TYPE CAN0_TX_BUF[TX0_BUF_LEN];
volatile INT8U CAN0_TX_Count;  //将要发送BUF的序号
volatile INT8U CAN0_TX_Seting; //正在设置数据内容

static INT8U CanFrameExist = 0;

/////////////////////////函数////////////////////////////////////////////////////////////////////
//CAN0初始化
void MSCAN0_Init(void)
{

	CAN0CTL0 = 0x01; //请求 MSCAN进入初始化模式
	while (!(CAN0CTL1_INITAK))
		; //等待进入初始化模式

	CAN0IDAC = 0; //配置屏蔽验收寄存器的工作方式  two 32-bit filter

	CAN0IDAR0 = 0x00; //设置验收寄存器
	CAN0IDAR1 = 0x00;
	CAN0IDAR2 = 0x00;
	CAN0IDAR3 = 0x00;

	CAN0IDMR0 = 0xFF; //设置屏蔽寄存器 (这里设置为所有报文ID都接收)
	CAN0IDMR1 = 0xFF;
	CAN0IDMR2 = 0xFF;
	CAN0IDMR3 = 0xFF;

	CAN0IDAR4 = 0x00; //设置验收寄存器
	CAN0IDAR5 = 0x00;
	CAN0IDAR6 = 0x00;
	CAN0IDAR7 = 0x00;

	CAN0IDMR4 = 0xFF; //设置屏蔽寄存器 (这里设置为所有报文ID都接收)
	CAN0IDMR5 = 0xFF;
	CAN0IDMR6 = 0xFF;
	CAN0IDMR7 = 0xFF;

	CAN0CTL1_CANE = 1;	 //使能MSCAN模块
	CAN0CTL1_CLKSRC = 0; //选择OSCCLK(8MHz)为MSCAN的时钟源
	CAN0CTL1_LISTEN = 0; //正常运行模式(非监听模式)

	// CAN0CTL1_BORM = 0; //自动总线BUS_OFF恢复
	CAN0CTL1_BORM = 1; //总线BUS_OFF由用户控制恢复

	CAN0CTL1_WUPM = 1; //给唤醒加滤波

	CAN0BTR0 = MSCAN0_BTR0_VALUE; //波特率设置 现在这个配置是81.25%的采样点
	CAN0BTR1 = MSCAN0_BTR1_VALUE;

	CAN0CTL0 = 0x00; //退出初始化模式
	while (CAN0CTL1_INITAK)
		; //等待退出初始化模式
	while (!CAN0CTL0_SYNCH)
		; //等待MSCAN与CAN总线同步

	CAN0TIER = 0x00;	//禁止CAN发送中断
	CAN0RIER_RXFIE = 1; //使能CAN接收中断
	CAN0RIER_WUPIE = 1;

	//CAN0_STB = 0; //使能CAN收发器
	MSCAN0_TJA1042_STB_SET(0); //使能CAN收发器
}
//真实的发送函数
void MSCAN0_SendMsg(_CAN_TX_BUF_TYPE *sendMsgBuf)
{
	INT8U txEmptyBuf = 0;
	INT8U i = 0;

	if ((CAN0CTL0_SLPRQ) || (MSCAN0_TJA1042_STB_GET()))
		return; //MACAN 不在睡眠模式 ?,NO
	/*if ((CAN0RFLG_TSTAT == 0x03) || (CAN0RFLG_RSTAT == 0x03))
	{
		return;
	}*/
	//	if (CAN0CTL0_SYNCH == 0)
	//	return; //MSCAN与CAN BUS 不同步
	if (!(CAN0TFLG & 0x01))
		return; //3个发送缓冲区都没有空闲

	txEmptyBuf = CAN0TBSEL = CAN0TFLG; //选择指向空闲的发送缓冲区(多个空闲选择最低的)

#if (CAN0_Frame_Type == Standard_Frame)
	CAN0TXIDR0 = (INT8U)(sendMsgBuf->SendID >> 3);
	CAN0TXIDR1 = (INT8U)(sendMsgBuf->SendID << 5);
	CAN0TXIDR1_SRR = 0; //sendMsgBuf->RTR;
	CAN0TXIDR1_IDE = 0;
#elif (CAN0_Frame_Type == Extended_Frame)
	CAN0TXIDR0 = (INT8U)((sendMsgBuf->SendID & 0x1fe00000) >> 21);
	CAN0TXIDR1 = (INT8U)((sendMsgBuf->SendID & 0x001c0000) >> 13);
	CAN0TXIDR1 |= (INT8U)((sendMsgBuf->SendID & 0x00038000) >> 15);
	CAN0TXIDR1 |= 0x18;
	CAN0TXIDR2 = (INT8U)((sendMsgBuf->SendID & 0x00007f80) >> 7);
	CAN0TXIDR3 = (INT8U)((sendMsgBuf->SendID & 0x0000007f) << 1);

#endif

	for (i = 0; i < sendMsgBuf->Len; i++)
	{
		*((&CAN0TXDSR0) + i) = sendMsgBuf->BUFF[i]; //写入数据
	}
	CAN0TXDLR = sendMsgBuf->Len;

	//  CAN0TXTBPR  =   2;//sendMsgBuf->priority;               	         //写入优先级
	CAN0TFLG = txEmptyBuf; //清TXx缓冲区空闲标志后,对应的发送缓冲区准备发送,发送成功后TXx置位表示又空闲
}
//==================================================
//服务器CAN0发送,中断中调用
//==================================================
void CAN0_TX_DATA_BUF(void)
{
   
	if (CAN0_TX_Seting)
	{
		CAN0TIER_TXEIE = 0X00;
		return;
	}
	
	 BusoffRecover(); 
	if (CAN0_TX_BUF[CAN0_TX_Count].Len != 0)
	{
		MSCAN0_SendMsg(&CAN0_TX_BUF[CAN0_TX_Count]);
		CAN0_TX_BUF[CAN0_TX_Count].Len = 0;
		
		CanNm_Data_Confirm ( CAN0_TX_BUF[CAN0_TX_Count].SendID, 1 );
	
	  	DoCAN_L_Data_Confirm(CAN0_TX_BUF[CAN0_TX_Count].SendID, DIAG_COMPLETE);
			
		CAN0_TX_BUF[CAN0_TX_Count].SendID = 0;
		CAN0_TX_Count++;
		if (CAN0_TX_Count >= TX0_BUF_LEN)
		{
			CAN0_TX_Count = 0;
		}
		
		return;
	}
	CAN0TIER_TXEIE = 0X00; //关闭中断
}
//CAN0  buf 中待发送的数据清零
void CAN0_TX_BUF_Clear(void)
{
	INT8U i = 0;

	CAN0_TX_Count = 0;
	for (i = 0; i < TX0_BUF_LEN; i++)
	{
		CAN0_TX_BUF[i].SendID = 0;
		CAN0_TX_BUF[i].Len = 0;
	}
}
//设置发送数据
_CAN_SetState CAN0_TX_BUF_Set(INT8U *pdata, INT32U ID, INT8U Len)
{
	INT8U i = 0;
	INT8U j = 0;
	INT8U Count = 0;
	if ((CAN0RFLG_TSTAT == 0x03) || (CAN0RFLG_RSTAT == 0x03))
	{
		return CAN_Set_ERROR_BUSOFF;
	}
	if (Len > 8)
	{
		return CAN_Set_ERROR_OverMaxLen;
	}
	__asm SEI;
	Count = CAN0_TX_Count;
	CAN0_TX_Seting = 1;

	for (j = 0; j < TX0_BUF_LEN; j++)
	{
		if (CAN0_TX_BUF[Count].Len == 0) //
		{
			CAN0_TX_BUF[Count].Len = Len;
			CAN0_TX_BUF[Count].SendID = ID;
			for (i = 0; i < Len; i++)
			{
				CAN0_TX_BUF[Count].BUFF[i] = *(pdata + i);
			}
			CAN0_TX_Seting = 0;

			CAN0TIER_TXEIE = 0x01;
			__asm CLI;
			return CAN_Set_Complete;
		}
		else
		{
			Count++;
			if (Count >= TX0_BUF_LEN)
			{
				Count = 0;
			}
		}
	}

	CAN0_TX_Seting = 0;
	CAN0TIER_TXEIE = 0x01;
	__asm CLI;
	return CAN_Set_ERROR_OverFlow;
}
unsigned char GetBusOffState(void)
{
	if ((CAN0RFLG_TSTAT == 0x03) || (CAN0RFLG_RSTAT == 0x03))
	{
		return 1;
	}
	return 0;
}
void AbortAllCan0Tx(void)
{
	CAN0TARQ = 0x07;
}
/******************************************************************************
函数名：MSCAN0_Enter_Low_Power_Mode
功  能：令MSCAN0进入低功耗模式
参  数：无
返回值：无
******************************************************************************/
void MSCAN0_Enter_Low_Power_Mode(void)
{
	MSCAN0_Init(); //透过初始化终止CAN收发

	//CAN0_STB = 1; //失能CAN收发器
	MSCAN0_TJA1042_STB_SET(1); ////失能CAN收发器

	if (CAN0RFLG_WUPIF) //唤醒中断请求标志 = 1 则写1清0
		CAN0RFLG_WUPIF = 1;
	CAN0CTL0_WUPE = 1; //唤醒使能

	//置1后,当MSCAN所有发送完成(发送队列空),接受也完成(CAN总线空闲)后,
	//MSCAN 进入SLEEP模式,并且置 CAN0CTL1_SLPAK=1表示确认
	//在置此位前 CAN0RFLG_WUPIF 必须清除

	//当CAN0CTL0_SLPRQ=1,且CAN0CTL1_SLPAK=1 ,表示MSCAN已经进入睡眠模式
	CAN0CTL0_SLPRQ = 1; //请求置MSCAN进入睡眠模式

	//当MSCAN进入睡眠模式后,如果 CAN0CTL0_WUPE = 1 且收到CAN报文后,MSCAN退出睡眠,且CAN0RFLG_WUPIF置1
	//同时 CAN0CTL0_SLPRQ,CAN0CTL1_SLPAK 也将自动清0.

	//在MSCAN进入睡眠模式后,软件也可以主动置CAN0CTL0_SLPRQ = 0,使得MSCAN退出睡眠,CAN0CTL1_SLPAK 也将自动清0.
	//当 CAN0CTL0_SLPRQ = 1后,如果MSCAN还没有进入睡眠模式,那么不能主动清CAN0CTL0_SLPRQ = 0.

	CAN0TARQ = 0x07; //请求终止所有报文发送.

	CAN0RIER_RXFIE = 0; //禁止CAN接收中断
}

/******************************************************************************
函数名：MSCAN0_Exit_Low_Power_Mode
功  能：令MSCAN0退出低功耗模式
参  数：无
返回值：无
******************************************************************************/
void MSCAN0_Exit_Low_Power_Mode(void)
{
	CAN0CTL0_SLPRQ = 0; //使得MSCAN退出睡眠

	if (CAN0RFLG_WUPIF) //唤醒中断请求标志 = 1 则写1清0
		CAN0RFLG_WUPIF = 1;
	CAN0CTL0_WUPE = 0; //禁用唤醒功能

	//CAN0_STB = 0; //使能CAN收发器
	MSCAN0_TJA1042_STB_SET(0); //使能CAN收发器
	CAN0RIER_RXFIE = 1;		   //使能CAN接收中断
}

/******************************************************************************
函蔵名：MSCAN0_Get_Wake_Up_Flag
功  能：获取MSCAN0的唤G炎刺?
参  蔵：蜸
返回值：0 - 未被唤G? 1 - 已被唤G?
******************************************************************************/
INT8U MSCAN0_Get_Wake_Up_Flag(void)
{
	if ((CAN0CTL0_SLPRQ == 0))
	{
		return 1;
	}
	else
	{
		return 0;
	}
}

INT8U MSCAN0_Set_Exist_Frame(void)
{ 
  CanFrameExist = 1;
}

INT8U MSCAN0_Is_Exist_Frame(void)
{ 
  INT8U ExistFrame = 0;
  
  ExistFrame = CanFrameExist;
  CanFrameExist = 0;
  
  return ExistFrame;
}

//获取CAN0 接收到的数据长度   //标准帧，扩展帧都用这一个
//extern INT8U MSCAN0_GET_Data_Len(void);
//获取CAN0 接收到的数据长度   //标准帧，扩展帧都用这一个
INT8U MSCAN0_GET_Data_Len(void)
{
	return CAN0RXDLR_DLC;
}
typedef union
{
	INT16U DATA16;
	struct
	{
		INT8U DATA0; //高字节
		INT8U DATA1; //低字节
	} BIT;

} _TEMP_DATA16;

//获取CAN0 标准帧ID
INT16U MSCAN0_GET_Stand_ID(void)
{
	_TEMP_DATA16 CANMsgID;
	CANMsgID.BIT.DATA1 = CAN0RXIDR1;
	CANMsgID.BIT.DATA0 = CAN0RXIDR0;
	CANMsgID.DATA16 >>= 5;
	//CANMsgID = (CAN0RXIDR0<<3);
	//CANMsgID |= (CAN0RXIDR1>>5);

	//CANMsgID = ((INT16U)(CAN0RXIDR0 << 3)) | ((INT16U)(CAN0RXIDR1 >> 5));
	//return CANMsgID;
	return CANMsgID.DATA16;
}
typedef union
{
	INT32U DATA32;
	struct
	{
		INT8U DATA0;
		INT8U DATA1;
		INT8U DATA2;
		INT8U DATA3;
	} BIT;

} _TEMP_DATA32;

//获取CAN0 扩展帧ID
INT32U MSCAN0_GET_Extended_ID(void)
{

	_TEMP_DATA32 CANMsgID;

	CANMsgID.BIT.DATA0 = CAN0RXIDR0;
	CANMsgID.BIT.DATA1 = CAN0RXIDR1;
	CANMsgID.BIT.DATA2 = CAN0RXIDR2;
	CANMsgID.BIT.DATA3 = CAN0RXIDR3;

	CANMsgID.DATA32 = (((CANMsgID.DATA32 & 0X7FFFF) >> 1) | (CANMsgID.DATA32 & 0XFFE00000) >> 3);

	return CANMsgID.DATA32;
}

//#define GET_EXTPGN(id) (((((((INT32U)id & 0xFF0000) >> 16) >= 0xF0) ? ((INT32U)id & 0x00FF00) : 0) | ((INT32U)id & 0x2FF0000)) >> 8)

//获取CAN0 扩展帧PNG
INT32U MSCAN0_GET_Extended_PNG(INT32U ID)
{
	INT32U CAN_PGN;
	if ((ID & 0XFF0000) >= 0XF00000)
	{
		CAN_PGN = ((ID & 0x2FFFF00) >> 8);
	}
	else
	{
		CAN_PGN = ((ID & 0x2FF0000) >> 8);
	}

	return CAN_PGN;
}
//获取CAN0 扩展帧SA
INT8U MSCAN0_GET_Extended_SA(INT32U ID)
{
	return ((INT8U)(ID & 0Xff));
}
//获取CAN0 扩展帧PS
INT8U MSCAN0_GET_Extended_PS(INT32U ID)
{
	return ((INT8U)((ID & 0Xff00) >> 8));
}
//获取CAN0 扩展帧PF
INT8U MSCAN0_GET_Extended_PF(INT32U ID)
{
	return ((INT8U)((ID & 0Xff0000) >> 16));
}
