/******************************************************************************
文 件 名：MSCAN0.h
功能描述：MSCAN0总线收发控制函数库文件
作    者：张暄
版    本：V1.0
日    期：2016.5.5
******************************************************************************/

#include <hidef.h>           /* common defines and macros */
#include "derivative.h"      /* derivative-specific definitions */
#include "mc9s12xhy256.h"
#include "stdint.h" 
#include "comdef.h"
#include "Unit_Conv.h"

//#include "AutoGUI.h"
#include "main.h" 

/* Driver */
#include "CRG.h"
#include "ADC.h"
#include "GPIO.h"
#include "MSCAN0.h"
#include "PWM.h"
#include "SCI0_UART.h"

#include "Sound_List.h"

/* System */ 
#include "PowerManagement.h"
#include "API.h" 
#include "Line_In.h"
#include "Key.h"
#include "CRG.h"

/* Protocol */
#include "CAN_Communication_Matrix.h"
#include "Analog_Signal_Conversion.h"
#include "Communication_Over_CAN.h"
#include "Simulated_IIC_Master.h"
#include "Simulated_SPI_Master.h"
#include "YGV642_SPI.h"

/* Device */
#include "EEPROM_24Cxx.h"
#include "EEPROM_24Cxx_Remap.h"
#include "ISD2360.h"
#include "LED.h"
#include "GUI.h"
#include "YGV642.h"

/* Module */
#include "Flash_synchronizer.h"

#include "Non_volatile_Memorys.h"
#include "Sound_Player.h"
#include "System_Status_Monitor.h"
#include "TFT_LCD.h"

/* Implementation */
#include "Popup_List.h"
#include "IO_Manager.h"
#include "Popup_Scheduler.h"
#include "Sound_Scheduler.h"
#include "Warning_Processor.h"
#include "Data_Processor.h"
#include "IPC.h"

/* Application */

#include "Telltales.h"
//#include "Back_Light.h"
#include "Drive_Info.h"
#include "Gauges.h"
#include "Menus.h"
#include "Popups.h"

#include "Startup_Animation.h"

#include "FuelConfig.h" 
//#include "FuelConfig1.h" 
 
/*Diagnostic*/
#include "Diag_ID_Def.h"
#include "DoCAN_ISO15765_Config.h"
#include "DoCAN_ISO15765.h"
#include "UDS_ISO14229_Services.h"
#include "Diag_ID_Def.h"
#include "UDS_ISO14229_Server.h"
#include "UDS_ISO14229_Server_Config.h"

#include "API_BD8379.h"

extern uint8_t CanFrameExist;
extern INT8U   BUS_OFF_FLAG;
extern uint8_t DiagnosticReceived;
uint32_t                  MSCAN0TxID[3];
MSCAN0BusoffMonitorStruct MSCAN0Busoff;

extern void SetErrState(unsigned char n); 
extern void SetRxState(unsigned char n); 
extern void SetTxState(unsigned char n);

extern void CoCAN_L_Data_Indication ( uint32_t Identifier, uint8_t DLC, uint8_t *Data );
extern void CAN1939_L_Data_Indication ( uint32_t Identifier, uint8_t DLC, uint8_t *Data );
//extern void CoCAN_L_Data_Confirm(uint32_t Identifier, uint8_t TransferStatus);

extern void DoCAN_L_Data_Indication ( uint32_t Identifier, uint8_t dlc, uint8_t *pData );
extern void DoCAN_L_Data_Confirm ( uint32_t Identifier, uint8_t TransferStatus );
extern void NM_Receive_isr_Fun(unsigned int id, unsigned char *pBuf) ;

extern void MSCAN0_L_Data_Request ( uint32_t Identifier, uint8_t DLC, uint8_t *Data, uint8_t Priority ) ;
extern uint8_t  CANNetRxOFF ;
extern uint8_t  CANNetTxOFF ;

extern uint8_t  Time10ms;
extern uint8_t  Time2ms;

typedef struct 
{
  uint32_t Identifier;
  uint8_t  DLC;
  uint8_t  Data[8];
  uint8_t  Priority;  
} MSCAN0TxID_t;

typedef struct 
{
  MSCAN0TxID_t TxBuf[32];
  uint8_t      TxHead;
  uint8_t      TxTail;  
} MSCAN0TxBuf_t;

//static MSCAN0TxID_t  BackUpTxBuf[5];
static MSCAN0TxBuf_t MSCAN0TxBuf;

/******************************************************************************
函数名：MSCAN0_L_Data_Request
功  能：该函数由上层调用,用于请求向总线上发送一组报文
参  数：Identifier：报文ID
        DLC       ：报文长度
        Data      ：报文数据
        Priority  ：发送优先级 0 - 2 数字越小优先级越高
返回值：无
******************************************************************************/
void MSCAN0_L_Data_Service(void)
{                                     
  uint8_t  BufSel;
  //uint16_t cnt = 0;
  uint8_t  Priority = 0;
  
  static uint16_t temp = 0;
  
  if ((MSCAN0TxBuf.TxHead != MSCAN0TxBuf.TxTail) && (TpTimingCtrl.Cnt - temp >= 20)) 
  {    
    BufSel   = 0x01;
    BufSel <<= MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Priority;

    //当前优先级的发送缓冲区为空时,上报发送失败并退出发送
    if ((CAN0TFLG & 0x07) == 0)
    {
      temp = TpTimingCtrl.Cnt;
      return;
    }
    
    DisableInterrupts;
    
    //CAN0TBSEL = BufSel;   		                //选择指向指定的发送缓冲区
    if ((CAN0TFLG & 0x01) == 0x01) 
    {
      Priority = 0;
      CAN0TBSEL = 1;
    }//选择指向指定的发送缓冲区
    else if ((CAN0TFLG & 0x02) == 0x02) 
    {
      Priority = 1;
      CAN0TBSEL = 2;  
    } 
    else if ((CAN0TFLG & 0x04) == 0x04) 
    {
      Priority = 2; 
      CAN0TBSEL = 4;
    }
    
    BufSel = CAN0TBSEL;
    
    // CAN0TXIDR0 = (uint8_t)(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier >> 3);  //写入标识符ID
    // CAN0TXIDR1 = (uint8_t)(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier << 5);
    
    // 写入标识符ID
    CAN0TXIDR0 = (uint8_t)(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier >> 21);
    CAN0TXIDR1 = ((uint8_t)(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier >> 13) & 0xE0) | ((uint8_t)(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier >> 15) & 0x07);
    CAN0TXIDR2 = (uint8_t)(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier >> 7);
    CAN0TXIDR3 = (uint8_t)(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier << 1) & 0xFE;
    
    CAN0TXIDR1_SRR = 1;
    CAN0TXIDR1_IDE = 1;
    if(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier == 0x7DA)
    {
      CAN0TXIDR0 = (uint8_t)((MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier & 0x07F8) >> 3);
      CAN0TXIDR1 = (uint8_t)((MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier & 0x0007) << 5);
      CAN0TXIDR1_SRR = 0;
      CAN0TXIDR1_IDE = 0;
    }
    
    CAN0TXDLR = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].DLC;
    
    CAN0TXDSR0 = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[0];
    CAN0TXDSR1 = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[1];
    CAN0TXDSR2 = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[2];
    CAN0TXDSR3 = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[3];
    CAN0TXDSR4 = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[4];
    CAN0TXDSR5 = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[5];
    CAN0TXDSR6 = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[6];
    CAN0TXDSR7 = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[7];
    
    /*                                                      
    BackUpTxBuf[BufSel].Identifier = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier; 
    BackUpTxBuf[BufSel].DLC = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].DLC;
    BackUpTxBuf[BufSel].Priority =  MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Priority;
    BackUpTxBuf[BufSel].Data[0] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[0];
    BackUpTxBuf[BufSel].Data[1] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[1];
    BackUpTxBuf[BufSel].Data[2] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[2];
    BackUpTxBuf[BufSel].Data[3] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[3];
    BackUpTxBuf[BufSel].Data[4] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[4];
    BackUpTxBuf[BufSel].Data[5] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[5];
    BackUpTxBuf[BufSel].Data[6] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[6];
    BackUpTxBuf[BufSel].Data[7] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Data[7];
    */
    
    EnableInterrupts;
               
    //if (MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier == 0x729)
    //  CAN0TXTBPR = 1; //MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Priority;                    //设置优先级,各Buffer优先级相同,则BufferID越小,优先级越高
    //else

    CAN0TXTBPR = BufSel; //MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Priority;                   //设置优先级,各Buffer优先级相同,则BufferID越小,优先级越高
    CAN0TFLG   = BufSel; //启动发送
    CAN0TIER  |= BufSel; //启动相应CAN发送中断
    
    MSCAN0TxID[Priority] = MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier;    
    
    //MSCAN0_L_Data_Confirm(MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxHead].Identifier, COMPLETE);
    MSCAN0TxBuf.TxHead++;            
    if (MSCAN0TxBuf.TxHead >= 32)
      MSCAN0TxBuf.TxHead = 0; 
          
    /*cnt = 0;
    while ((CAN0TFLG & BufSel) != BufSel) 
    {
      cnt++;
      if(cnt >= 1800)  
        break;
    }*/
  }
}

//extern uint16_t StartCanOutTime0;
//extern uint16_t StartCanOutTime1;

void MSCAN0_L_Data_Request(uint32_t Identifier, uint8_t DLC, uint8_t *Data, uint8_t Priority)
{
  uint8_t i = 0;
  uint8_t tmp = MSCAN0TxBuf.TxHead;
  //uint16_t temp0, temp1;
  //uint8_t cnt = 0;
  
  DisableInterrupts;
  
  //cnt = (tmp > MSCAN0TxBuf.TxTail) ? (MSCAN0TxBuf.TxHead - MSCAN0TxBuf.TxTail - 1) : (32 - MSCAN0TxBuf.TxTail + MSCAN0TxBuf.TxHead - 1); 
  
  if ((DLC > 8) || (Priority > 2)) 
  { 
    EnableInterrupts;
    return;  
  }
  
  if (Identifier == 0x18FEF717 ) 
  {
    //temp0 = StartCanOutTime0;
    //temp1 = StartCanOutTime1;
    //CANMsg18FEF717.Msg[4] = temp0;
    //CANMsg18FEF717.Msg[5] = temp0 >> 8;
    //CANMsg18FEF717.Msg[6] = temp1;
    //CANMsg18FEF717.Msg[7] = temp1 >> 8;
       
    if (1 == CANNetTxOFF)
    {
      EnableInterrupts;
      return;
    }
  }
    
  /*if (Identifier != 0x729 ) 
  {
    if (Identifier == 0x402) 
    {
      ;
    } 
    else 
    {
      if(DIAG_TST_BIT_SET(m_28SerComCtrlState ,DIAG_COM_NOR_TX,uint8_t)) 
      {          
        EnableInterrupts;
        return;  
      }
    }
  }
  */  
  MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxTail].Identifier = Identifier;
  MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxTail].DLC = DLC;
  
  for (i = 0; i < 8; i++) 
    MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxTail].Data[i] = 0;
        
  for (i = 0; i < DLC; i++) 
    MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxTail].Data[i] = Data[i];
  
    
  MSCAN0TxBuf.TxBuf[MSCAN0TxBuf.TxTail].Priority = Priority;
      
  MSCAN0TxBuf.TxTail++;
  if (MSCAN0TxBuf.TxTail >= 32)
    MSCAN0TxBuf.TxTail = 0;
 
  EnableInterrupts;
  
  return;
}

#if 0
void MSCAN0_L_Data_Request ( uint32_t Identifier, uint8_t DLC, uint8_t *Data, uint8_t Priority )
{
  uint8_t  i;
  //uint8_t  BufDetect;
  uint8_t  BufSel;
  

  /*if((Identifier >= 0x400) && (Identifier <= 0x4ff) ) 
  {
    if (1 == CANNetTxOFF)
       return;
  }*/
  if (Identifier == 0x18FEF717 ) 
  {
    if (1 == CANNetTxOFF)
       return;
  }
  //MSCAN与CAN BUS不同步,或ID无效,或发送数据长度大于8,或优先级设置错误时,上报发送失败并退出发送
  if ( ( CAN0CTL0_SYNCH == 0 ) || ( DLC > 8 ) || ( Priority > 2 ) ) //|| (Identifier > 0x07FF)
  {
    MSCAN0_L_Data_Confirm ( Identifier, NOT_COMPLETE );
    return;
  }

  BufSel   = 0x01;
  BufSel <<= Priority;

  //当前优先级的发送缓冲区为空时,上报发送失败并退出发送
  if ( CAN0TFLG & BufSel == 0 )
  {
    MSCAN0_L_Data_Confirm ( Identifier, NOT_COMPLETE );
    return;
  }

  if ( MSCAN0TxID[Priority] != 0xFFFF )     //前一次报文发送未得到结果但是Buffer被意外清空
    MSCAN0_L_Data_Confirm ( MSCAN0TxID[Priority], NOT_COMPLETE );

  MSCAN0TxID[Priority] = Identifier;        //保存ID
  CAN0TBSEL = BufSel;   		                //选择指向指定的发送缓冲区
  /* CAN0TXIDR0 = ( uint8_t ) ( Identifier >> 3 ); //写入标识符ID
  CAN0TXIDR1 = ( uint8_t ) ( Identifier << 5 );
  CAN0TXIDR1_SRR = 0;
  CAN0TXIDR1_IDE = 0;*/

  //写入标识符ID
  CAN0TXIDR0 = (uint8_t)(Identifier >> 21);
  CAN0TXIDR1 = ((uint8_t)(Identifier >> 13) & 0xE0) | ((uint8_t)(Identifier >> 15) & 0x07);
  CAN0TXIDR2 = (uint8_t)(Identifier >> 7);
  CAN0TXIDR3 = (uint8_t)(Identifier << 1) & 0xFE;

  //发送（扩展帧）
  CAN0TXIDR1_SRR = 1;
  CAN0TXIDR1_IDE = 1;

  for ( i = 0; i < DLC; i++ )               //写入数据
    * ( ( &CAN0TXDSR0 ) + i ) = Data[i];

  CAN0TXDLR = DLC;
  //CAN0TXTBPR = 0;                         //设置优先级,各Buffer优先级相同,则BufferID越小,优先级越高
  CAN0TFLG  = BufSel;                       //启动发送
  CAN0TIER |= BufSel;                       //启动相应CAN发送中断
}
#endif 
/******************************************************************************
函数名：MSCAN0_L_Data_Indication
功  能：该函数用于向上层指示一帧报文的到来,并同时将报文数据传递至上层
        注意：1.使用时应将上层的报文传递函数包含于本函数之中,报文到来时则会调用
                相应的函数传递报文数据
              2.本函数与中断相关,被调用的上层的报文传递函数应尽可能简短
参  数：Identifier：报文ID
        DLC       ：报文长度
        Data      ：报文数据
返回值：无
******************************************************************************/
void MSCAN0_L_Data_Indication ( uint32_t Identifier, uint8_t DLC, uint8_t *Data )
{
   /*PduInfoType NW_MessageBuffer; 
   
   if( ( Identifier >= 0x18FFFA00 ) && ( Identifier <= 0x18FFFAFF ) ) {//网络管理报文
        NW_MessageBuffer.SduDataPtr = Data;
        NW_MessageBuffer.SduLength = DLC;
        CanNm_RxIndication(0, 0,&NW_MessageBuffer);   
        NM_RECEIVE=1; 
        sleepFlg=1;   
    
   } */
    ReceivedMsg(Identifier,DLC);
   //????1939-21 ?????????????
    //if( ( Identifier == DIAG_ID_Rx_PHY ) || ( Identifier == DIAG_ID_Rx_FUN ) )
   //{ 
       // DoCAN_L_Data_Indication ( Identifier, DLC, Data );
   //}
   //else
   //{
        //??????
        CoCAN_L_Data_Indication ( Identifier, DLC, Data );
   //}

  //if ((Identifier == 0x7E3) || (Identifier == 0x7EB))
  //  DoCAN_L_Data_Indication(Identifier, DLC, Data);
  //else
  //  CoCAN_L_Data_Indication(Identifier, DLC, Data);
}

/******************************************************************************
函数名：MSCAN0_L_Data_Confirm
功  能：该函数用于向上层指示请求发送的报文的发送结果
        注意：1.使用时应将上层的报文发送结果传递函数包含于本函数之中,报文发送事
                件产生时则会调用相应的函数传递报文发送结果
              2.本函数与中断相关,被调用的上层的报文发送结果传递函数应尽可能简短
参  数：Identifier    ：报文ID
        TransferStatus：报文发送结果：COMPLETE     发送完成
                                      NOT_COMPLETE 报文未能发送完成
返回值：无
******************************************************************************/
void MSCAN0_L_Data_Confirm ( uint32_t Identifier, uint8_t TransferStatus )
{
  if (Identifier == DIAG_ID_Tx)
  {
    DoCAN_L_Data_Confirm ( Identifier, TransferStatus );
  }
}

/******************************************************************************
函数名：MSCAN0_Bus_Off_Monitoring_Service
功  能：MSCAN0 Bus-off状态监控服务,监控Bus-off状态并尝试恢复
参  数：无
返回值：无
*******************************************************************************
注  意：该服务函数必须每20ms被调用一次
******************************************************************************/
void MSCAN0_Bus_Off_Monitoring_Service ( void )
{
#if !MSCAN0_BUS_OFF_AUTO_RECOVERY
  #if MSCAN0_BUS_LIMP_MODE_ENABLE

  if ( MSCAN0Busoff.Status == MSCAN0_BUS_LIMP )
    return;	                                    //CAN总线已经在跛行模式(多次恢复失败),则不再恢复

  #endif

  if ( CAN0MISC_BOHOLD )                        //如果Bus-off发生
  {
    MSCAN0Busoff.Timer++;

    if ( MSCAN0Busoff.Status == MSCAN0_BUS_STABLE )
      MSCAN0Busoff.Status = MSCAN0_BUS_OFF_LV1;

    if ( MSCAN0Busoff.Status == MSCAN0_BUS_OFF_LV1 )
    {
      if ( MSCAN0Busoff.Timer >= MSCAN0_BUS_OFF_LV1_RECOVERY_TIME / 20 )
      {
        MSCAN0Busoff.Timer = 0;
        CAN0MISC_BOHOLD = 1;                    //写1清零,请求恢复Bus-off
        MSCAN0Busoff.Cnt++;

        if ( MSCAN0Busoff.Cnt >= 10 )
        {
          BUS_OFF_FLAG = 1;
          MSCAN0Busoff.Cnt = 0;
          MSCAN0Busoff.Status = MSCAN0_BUS_OFF_LV2;
        }
      }
    }
    else if ( MSCAN0Busoff.Status == MSCAN0_BUS_OFF_LV2 )
    {
      if ( MSCAN0Busoff.Timer >= MSCAN0_BUS_OFF_LV2_RECOVERY_TIME / 20 )
      {
        MSCAN0Busoff.Timer = 0;
        CAN0MISC_BOHOLD = 1;                    //写1清零,请求恢复Bus-off
      }

    #if MSCAN0_BUS_LIMP_MODE_ENABLE
      MSCAN0Busoff.Cnt++;

      if ( MSCAN0Busoff.Cnt > MSCAN0_BUS_LIMP_MODE_THRESHOLD )
      {
        MSCAN0Busoff.Cnt = 0;
        MSCAN0Busoff.Status = MSCAN0_BUS_LIMP;  //进入CAN总线跛行模式
        CAN0_PHY_STB = 1;                       //进入省电模式
        MSCAN0_Init();				                  //通过初始化终止所有CAN收发
        CAN0RIER_RXFIE = 0;   		              //禁止CAN接收中断
        CAN0RIER_WUPIE = 0;                     //关闭唤醒中断
        CAN0CTL0_WUPE  = 0;                     //禁止唤醒使能

        if ( CAN0RFLG_WUPIF )
          CAN0RFLG_WUPIF = 1;                   //如果有唤醒中断请求标志也一并清除(写1清零)
      }
    #endif
    }
  }
  else                                          //总线正常,没有Bus-off发生
  {
    BUS_OFF_FLAG = 0;
    MSCAN0Busoff.Status = MSCAN0_BUS_STABLE;
    MSCAN0Busoff.Timer = 0;
    MSCAN0Busoff.Cnt   = 0;
  }
#endif
}

/******************************************************************************
函数名：MSCAN0_Get_Bus_Status
功  能：获取MSCAN0总线状态
参  数：无
返回值：MSCAN0_BUS_STABLE：总线正常,稳定工作
        MSCAN0_BUS_OFF   ：总线处于Bus-off状态
        MSCAN0_BUS_LIMP  ：总线处于跛行状态(Bus-off后多次恢复均失败而关闭总线)
******************************************************************************/
uint8_t MSCAN0_Get_Bus_Status ( void )
{
  return MSCAN0Busoff.Status;
}

/******************************************************************************
函数名：MSCAN0_Init
功  能：MSCAN0初始化程序
参  数：无
返回值：无
******************************************************************************/
void MSCAN0_Init ( void )
{
  //uint8_t i;
  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;        //正常运行模式(非监听模式)
#if MSCAN0_BUS_OFF_AUTO_RECOVERY
  CAN0CTL1_BORM = 0;	        //自动总线BUS_OFF恢复
#else
  CAN0CTL1_BORM = 1;	        //总线BUS_OFF由用户控制恢复
#endif
  CAN0CTL1_WUPM = 1;		      //给唤醒加滤波
  CAN0BTR0 = 0x40; //0X41;    //2tq, Prescaler value=4,波特率 8M/(1 * (1+3+12)=500k
  CAN0BTR1 = 0x2B; //0X14;    //波特率设置 现在这个配置是1+12/1+12+3 = 81.25%的采样点
  /*
  myBRP    = 5;            p = (myBRP - 1);
  mySJW    = 3;           sj = (mySJW - 1) << 6; //同步跳转段=2       2015-3-12
  myTSEG1  = 11;      t_seg1 = myTSEG1 - 1;
  myTSEG2  = 4;       t_seg2 = (myTSEG2 - 1) << 4;
  CAN0BTR0 = sj | p;
  CAN0BTR1 = t_seg1 | t_seg2;		//设为1次采样 */
  //---------------------------------
  //CAN0CTL0 = 0x00;
  CAN0CTL0 = 0x00;            //退出初始化模式

  while ( CAN0CTL1_INITAK );  //等待退出初始化模式

  while ( !CAN0CTL0_SYNCH );  //等待MSCAN与CAN总线同步

  CAN0TIER = 0x00;            //禁止CAN发送中断
  CAN0RIER_RXFIE = 1;   		  //使能CAN接收中断
  CAN0RIER_WUPIE = 1;
  CAN0_STB = 0;   	          //使能CAN收发器
  MSCAN0Busoff.Status = MSCAN0_BUS_STABLE;
  MSCAN0Busoff.Timer = 0;
#if MSCAN0_BUS_LIMP_MODE_ENABLE
  MSCAN0Busoff.Cnt   = 0;
#endif

  // for ( i = 0; i < 3; i++ )
  //   MSCAN0TxID[i] = 0xFFFF;   //0xFFFF表示无效ID
  MSCAN0TxBuf.TxHead = 0;
  MSCAN0TxBuf.TxTail = 0;   
}

/******************************************************************************
函数名：MSCAN0_Enter_Low_Power_Mode
功  能：令MSCAN0进入低功耗模式
参  数：无
返回值：无
******************************************************************************/

void MSCAN0_Enter_Low_Power_Mode ( void )
{
  //MSCAN0_Init();            //透过初始化终止CAN收发
  CAN0_STB = 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接收中断         20200618
}

/******************************************************************************
函数名：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收发器
  CAN0RIER_RXFIE = 1;   			//使能CAN接收中断
}

/******************************************************************************
函数名：MSCAN0_Get_Wake_Up_Flag
功  能：获取MSCAN0的唤醒状态
参  数：无
返回值：0 - 未被唤醒 1 - 已被唤醒
******************************************************************************/
uint8_t MSCAN0_Get_Wake_Up_Flag ( void )
{
  if ((CAN0CTL0_SLPRQ == 0) || (CanFrameExist == 1))
    return 1;
 
  return 0;
}

#pragma CODE_SEG __NEAR_SEG NON_BANKED   	//置所有中断函数放在FLASH的非分页区

/******************************************************************************
函数名：MSCAN0_TX_ISR
功  能：MSCAN0发送中断服务函数。
        当有CAN报文发送完毕或被中止发送时，执行此函数
参  数：无
返回值：无
******************************************************************************/
void interrupt MSCAN0_TX_ISR ( void )
{
  uint8_t i;
  uint8_t TxFlag;
  uint8_t TxBuf;
  uint8_t BufDetect;
  
  do
  {
    TxFlag = CAN0TFLG;
    TxBuf = CAN0TIER & TxFlag;              //获取发送完毕或被中止发送的报文Buffer
    CAN0TIER &= ~TxBuf;                     //关闭发送完毕或被中止发送的报文Buffer对应的中断
    BufDetect = 1;

    for ( i = 0; i < 3; i++ )
    {
      if ( BufDetect & TxBuf )
      {
        if ( BufDetect & CAN0TAAK )         //报文被成功中止发送
          MSCAN0_L_Data_Confirm ( MSCAN0TxID[i], NOT_COMPLETE );
        else                                //报文发送成功
          MSCAN0_L_Data_Confirm ( MSCAN0TxID[i], COMPLETE );

        MSCAN0TxID[i] = 0xFFFF;             //清除报文记录
      }

      BufDetect <<= 1;
    }
  }
  while ( TxFlag != CAN0TFLG );             //避免中断处理期间有新的报文发送完毕
}

/******************************************************************************
函数名：MSCAN0_RX_ISR
功  能：MSCAN0接收中断服务函数。
        当有CAN报文送达时，接收CAN报文
参  数：无
返回值：无
******************************************************************************/
void interrupt MSCAN0_RX_ISR ( void )
{
    uint32_t tmp;
    uint32_t CANMsgID;
    uint32_t DiagMsgID;

    // uint8_t m8;
    CAN0RIER_RXFIE = 0;                     //先禁止MSCAN接收中断
    
    /*  
    if ( CAN0RXIDR1_IDE || CAN0RXIDR1_SRR ) //如果收到的数据为扩展帧,或为远程帧
    {
      CAN0RFLG_RXF = 1;                     //清接收中断标志
      CAN0RIER_RXFIE = 1;                   //重新启动MSCAN接收中断
      
      return;
    } 
    */

    //数据接收
    tmp = (uint32_t)(CAN0RXIDR0) << 21;
    tmp &= 0x1FE00000; 
    CANMsgID =  tmp | ((uint32_t)(CAN0RXIDR1 & 0xE0) <<13) |  ((uint32_t)(CAN0RXIDR1 & 0x07) <<15)
                    | ((uint32_t)(CAN0RXIDR2) << 7)
                    | ((uint32_t)(CAN0RXIDR3) >> 1); //ID
    		  
    DiagMsgID = ( ( uint16_t ) ( CAN0RXIDR0 << 3 ) ) | ( ( uint16_t ) ( CAN0RXIDR1 >> 5 ) );
    /*if((CANMsgID >= 0x400) && (CANMsgID <= 0x4ff) ) 
    {
      if ( 1 == CANNetRxOFF )
    	         return;
    	NM_Receive_isr_Fun(CANMsgID, &CAN0RXDSR0); 
    }*/
    if (CANMsgID == 0x18FFA021)
    {
      if ( 1 == CANNetRxOFF )
         return;
    }
    if( ( DiagMsgID == DIAG_ID_Rx_PHY ) || ( DiagMsgID == DIAG_ID_Rx_FUN ) )
    { 
      DoCAN_L_Data_Indication ( DiagMsgID, CAN0RXDLR & 0x0F, &CAN0RXDSR0 );
    }
    MSCAN0_L_Data_Indication ( CANMsgID, CAN0RXDLR & 0x0F, &CAN0RXDSR0 );
    CanFrameExist = 1;
    CAN0RFLG_RXF = 1;                       //清接收中断标志
    CAN0RIER_RXFIE = 1;                     //重新启动MSCAN接收中断
}
/*
void interrupt MSCAN0_RX_ISR(void)
{
  uint16_t CANMsgID;

	CAN0RIER_RXFIE = 0;                       //先禁止MSCAN接收中断

	if (CAN0RXIDR1_IDE || CAN0RXIDR1_SRR)     //如果收到的数据为扩展帧,或为远程帧
	{
    CAN0RFLG_RXF=1;                         //清接收中断标志
		CAN0RIER_RXFIE=1;                       //重新启动MSCAN接收中断

    return;
	}

	CANMsgID = ((uint16_t)(CAN0RXIDR0 << 3)) | ((uint16_t)(CAN0RXIDR1 >> 5));

  if((CANMsgID >= 0x400) && (CANMsgID <= 0x47F))
    MSCAN0_L_Data_Indication(CANMsgID, CAN0RXDLR & 0x0F, &CAN0RXDSR0);
  else
  {
  	switch(CANMsgID)
  	{
    	case  0x068 :
    	case  0x268 :
    	case  0x2D7 :
      case  0x4D4 :
      case  0x1C8 :
      case  0x370 :
      case  0x1C9 :
      case  0x0F2 :
      case  0x0E2 :
      case  0x082 :
      case  0x094 :
      case  0x288 :
      case  0x088 :
      case  0x120 :
      case  0x293 :
      case  0x115 :
      case  0x160 :
      case  0x07A :
      case  0x30F :
      case  0x2F1 :
      case  0x10D :
      case  0x7E3 :
      case  DIAG_ID_Rx_FUN :
      case  0x279 : MSCAN0_L_Data_Indication(CANMsgID, CAN0RXDLR & 0x0F, &CAN0RXDSR0);
                    break;
      default     : break;
  	}
	}

  CAN0RFLG_RXF = 1;                         //清接收中断标志
	CAN0RIER_RXFIE = 1;                       //重新启动MSCAN接收中断
}*/

/******************************************************************************
函数名：MSCAN0_WAKEUP_ISR
功  能：MSCAN0唤醒中断
参  数：无
返回值：无
******************************************************************************/

void interrupt MSCAN0_WAKEUP_ISR ( void )
{
  CAN0RFLG_WUPIF = 1;
  CAN0_STB = 0;
  Time2ms  = 0;
  Time10ms = 0;
  API_Start();
  CanFrameExist = 1;
}

#pragma CODE_SEG DEFAULT
