/******************************************************************************
�� �� ����MSCAN0.h
����������MSCAN0�����շ����ƺ������ļ�
��    �ߣ�����
��    ����V1.0
��    �ڣ�2016.5.5
******************************************************************************/

#include "MSCAN0.h"
uint8_t    WakeUpFlag;
uint8_t    WakeUpID;
uint16_t                      MSCAN0TxID[3];
MSCAN0BusoffMonitorStruct     MSCAN0Busoff;
extern uint8_t NM_RECEIVE;

extern void CoCAN_L_Data_Indication(uint16_t Identifier, uint8_t DLC, uint8_t *Data);
extern void CoCAN_L_Data_Confirm(uint16_t Identifier, uint8_t TransferStatus);

extern void DoCAN_L_Data_Indication(uint16_t Identifier, uint8_t dlc, uint8_t *pData);
extern void DoCAN_L_Data_Confirm(uint16_t Identifier, uint8_t TransferStatus);

extern FUNC(void, CANNM_CODE) CanNm_RxIndication
(
  PduIdType RxPudId,
  const uint16 RxId,
  P2CONST(PduInfoType, AUTOMATIC, CANNM_APPL_DATA)PduInfoPtr
);

extern FUNC(void, CANNM_CODE) CanNm_TxConfirmation
(
  PduIdType TxPudId
);

/******************************************************************************
��������MSCAN0_L_Data_Request
��  �ܣ��ú������ϲ����,���������������Ϸ���һ�鱨��
��  ����Identifier������ID
        DLC       �����ij���
        Data      ����������
����ֵ����
******************************************************************************/
void MSCAN0_L_Data_Request(uint16_t Identifier, uint8_t DLC, uint8_t *Data)
{
  uint8_t  i;
  uint8_t  BufDetect;
  uint8_t  BufSel;

  //�������ݳ��ȴ���8��MSCAN��CAN BUS��ͬ����3�����ͻ�������û�п���ʱ��ID��Ч,�ϱ�����ʧ�ܲ��˳�����
  if ((DLC > 8) ||	(CAN0CTL0_SYNCH == 0) || (CAN0TFLG & 0x07 == 0) || (Identifier > 0x07FF))
  {
    MSCAN0_L_Data_Confirm(Identifier, NOT_COMPLETE);
    return;
  }

  CAN0TBSEL = CAN0TFLG;   		              //ѡ��ָ����еķ��ͻ�����(�������ѡ����͵�)
  BufSel    = CAN0TBSEL;

  BufDetect = 0x01;
  for (i = 0; i < 3; i++)
  {
    if (BufDetect == BufSel)
    {
      if (MSCAN0TxID[i] != 0xFFFF)           //ǰһ�α��ķ���δ�õ��������Buffer���������
      {
        MSCAN0_L_Data_Confirm(MSCAN0TxID[i], NOT_COMPLETE);
        MSCAN0TxID[i] = 0xFFFF;
      }

      MSCAN0TxID[i] = Identifier;            //����ID
    }

    BufDetect <<= 1;
  }

  CAN0TXIDR0 = (uint8_t)(Identifier >> 3);  //д���ʶ��ID
  CAN0TXIDR1 = (uint8_t)(Identifier << 5);
  CAN0TXIDR1_SRR = 0;
  CAN0TXIDR1_IDE = 0;

  for (i = 0; i < DLC; i++)                 //�����
    *((&CAN0TXDSR0) + i) = Data[i];

  CAN0TXDLR = DLC;

  //CAN0TXTBPR = 0;                         //�������ȼ�,��Buffer���ȼ���ͬ,��BufferIDԽС,���ȼ�Խ��
  CAN0TFLG  = BufSel;                       //��������
  CAN0TIER |= BufSel;                       //������ӦCAN�����ж�
}

/******************************************************************************
��������MSCAN0_L_Data_Indication
��  �ܣ��ú����������ϲ�ָʾһ֡���ĵĵ���,��ͬʱ���������ݴ������ϲ�
        ע�⣺1.ʹ��ʱӦ���ϲ�ı��Ĵ��ݺ��������ڱ�����֮��,���ĵ���ʱ������
                ��Ӧ�ĺ������ݱ�������
              2.���������ж����,�����õ��ϲ�ı��Ĵ��ݺ���Ӧ�����ܼ��
��  ����Identifier������ID
        DLC       �����ij���
        Data      ����������
����ֵ����
******************************************************************************/
void MSCAN0_L_Data_Indication(uint16_t Identifier, uint8_t DLC, uint8_t *Data)
{
  PduInfoType NW_MessageBuffer;

  if( ( Identifier >= 0x400 ) && ( Identifier <= 0x47F ) )  //�����������
  {
    NW_MessageBuffer.SduDataPtr = Data;
    NW_MessageBuffer.SduLength = DLC;
    CanNm_RxIndication(0, 0, &NW_MessageBuffer);
    NM_RECEIVE = 1;

  }
  else    if ((Identifier == 0x7E3) || (Identifier == 0x7EB))
  {
    DoCAN_L_Data_Indication(Identifier, DLC, Data);
  }
  else
  {
    //Ӧ�ñ���
    if( sleepFlg == NET_WORK_STATE )
    {
      CoCAN_L_Data_Indication(Identifier, DLC, Data);

    }
    else if( sleepFlg == PREPARE_BUS_SLEEP_STATE )
    {


    }
    else if( sleepFlg == BUS_SLEEP_STATE )
    {

    }
    else if( sleepFlg == START_INDICATION_STATE )
    {
      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(uint16_t Identifier, uint8_t TransferStatus)
{
  if( ( Identifier >= 0x400 ) && ( Identifier <= 0x47F ) )  //�����������
  {
    CanNm_TxConfirmation(0);
  }
  else if (Identifier == 0x7E3)
    DoCAN_L_Data_Confirm(Identifier, TransferStatus);
  else
  {
    CoCAN_L_Data_Confirm(Identifier, TransferStatus);
  }

  //if (Identifier == 0x7E3)
  //   DoCAN_L_Data_Confirm(Identifier, TransferStatus);
  // else
  //   CoCAN_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.Timer >= MSCAN0_BUS_OFF_RECOVERY_TIME / 20)
    {
      MSCAN0Busoff.Timer = 0;

      MSCAN0Busoff.Status = MSCAN0_BUS_OFF;     //��¼Bus-off״̬

      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;
        CAN0MISC_BOHOLD = 1;                      //д1����,����ָ�Bus-off
        MSCAN0Busoff.Status = MSCAN0_BUS_LIMP;  //����CAN��������ģʽ
        CAN0_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����
  {
    MSCAN0Busoff.Status = MSCAN0_BUS_STABLE;
    MSCAN0Busoff.Timer = 0;

#if MSCAN0_BUS_LIMP_MODE_ENABLE
    MSCAN0Busoff.Cnt   = 0;
#endif
  }
#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 = MSCAN0_BTR0_VALUE;   //����������
  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�շ���

  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
}

/******************************************************************************
��������MSCAN0_Low_Power_Mode
��  �ܣ���MSCAN0����͹���ģʽ
��  ������
����ֵ����
******************************************************************************/
void MSCAN0_Low_Power_Mode(void)
{
  //MSCAN����͹���ģʽ
  MSCAN0_Init();               //͸����ʼ����ֹCAN�շ�
  //	CAN0_STB = 1;   	          //ʹ��CAN�շ���
  CAN0RIER_RXFIE = 0;   			//��ֹ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;            //������ֹ���б��ķ���.
}

#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)
{
  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));

  MSCAN0_L_Data_Indication(CANMsgID, CAN0RXDLR & 0x0F, &CAN0RXDSR0);

  CAN0RFLG_RXF = 1;                        //������жϱ�־
  CAN0RIER_RXFIE = 1;                      //��������MSCAN�����ж�
}

/******************************************************************************
��������MSCAN0_WAKEUP_ISR
��  �ܣ�MSCAN0�����ж�
��  ������
����ֵ����
******************************************************************************/
void interrupt MSCAN0_WAKEUP_ISR(void)
{
  CAN0RFLG_WUPIF = 1;
  WakeUpFlag = 1;
}

uint8_t GetWakeUPFLAG(void)
{
  return    WakeUpFlag;
}

#pragma CODE_SEG DEFAULT

Std_ReturnType CanIf_Transmit(PduIdType CanTxPduId, PduInfoType *PduInfoPtr)
{
  MSCAN0_L_Data_Request( 0x402, (uint8_t)PduInfoPtr->SduLength, (uint8_t *)PduInfoPtr->SduDataPtr );
  return E_OK;
}