 /*******************************************************************************
 * ON Semiconductor                                                            *
 * NCV7383 Evaluation KIT                                                      *
 *                                                                             *
 * CAN.c                                                                       *
 * CAN interface                                                              *
 *                                                                             *
 * Created by: Filip Brtan                                                     *
 * Date: 30.07.2012                                                            *
 *                                                                             *
 *******************************************************************************/

/* S12X derivative information */   
#include "mc9s12xf512.h" 
/* CAN channel definitions  */
#include "CAN.h"

/* Global variable  */
word CAN_node_ID; /* extern definition */

#pragma DATA_SEG CAN_DATA
#pragma CODE_SEG CAN_CODE


/******************/
/* Flags          */
/******************/

#define CAN_OVERRUN_ERR      1         /* Overrun error flag bit */
#define CAN_COMMON_ERR       2         /* Common error of RX */      
#define CAN_CHAR_IN_RX       4         /* Char is in the RX buffer */
#define CAN_RUNINT_FROM_TX   8         /* Interrupt is in progress */
#define CAN_FULL_RX          16        /* Full receive buffer */     
#define CAN_BREAK_ERR        32        /* Break detect */
#define CAN_RXFRAME          64        /* frame reception in progress */
#define CAN_TXFRAME          128       /* frame transmission in progress */

static byte CAN_Flag;                  /* Flags for serial communication */
                                       /* Bit 0 - Overrun error */
                                       /* Bit 1 - Common error of RX */
                                       /* Bit 2 - Char in the RX buffer */
                                       /* Bit 3 - Interrupt is in progress */
                                       /* Bit 4 - Full RX buffer */
                                       /* Bit 5 - Break detected */
                                       
static byte CAN_ErrFlag = 0;           /* Error flags mirror of SerFlag */


/******************/
/* Buffers        */
/******************/

byte CAN_rxlen;                       /* Length of incoming frame */
byte CAN_txlen;                       /* Length of outgoing frame */

static byte CAN_rxpos;                /* current position in the RX buffer */
static byte CAN_txpos;                /* current position in the TX buffer */


TBUFFER_DATA CAN_rxdata[SIZE_CAN_RXBUF];  /* Reception data buffer */
TBUFFER_DATA CAN_txdata[SIZE_CAN_TXBUF];  /* Transmission data buffer */


/******************/
/* Data Reception */
/******************/

/* Data reception finished. */
byte  CAN_received (void) {
  return (byte)((CAN_Flag & CAN_RXFRAME) && (CAN_rxpos == CAN_rxlen));
}

/* Received data processed, get ready for next frame. */
void CAN_rxprocessed (void) {
  CAN_Flag &= ~(CAN_RXFRAME);     /* RXFRAME = 0 */
}

/*********************/
/* Data Transmission */
/*********************/

/* Request to transmit data in the TX buffer. */
void CAN_transmit (void) {
  // Send the header byte right away.
  byte i;
  byte Length;  
  byte TxData[8];
  
  CAN_txpos = 0;
  TxData[CAN_txpos] = CAN_txlen;
  
  Length = CAN_txlen + 1;
  if (Length > 8) Length = 8;
  
  for (i = 1; i < Length ;i++){
    TxData[i] = CAN_txdata[CAN_txpos++];   
  }
  
  CAN_Flag |= (CAN_TXFRAME);                /* CAN_TXFRAME = 1 */

  /* Store chars to transmitter register */ 
  if (CAN_send_frame(Length, &TxData[0]) == ERR_OK); 
}

/* Transmission in progress. */
byte  CAN_txactive (void) {
  return (CAN_Flag & CAN_TXFRAME);
}

/* Tests the internal input break flag */
byte CAN_get_break(byte *Break)
{
  *Break = (CAN_ErrFlag & CAN_BREAK_ERR) != 0;   /* If was break signal? */
  CAN_ErrFlag &= ~CAN_BREAK_ERR;                 /* Reset break signal flag */
  return ERR_OK;                       /* OK */
}

/* Sends the break sequence to the output line. */
byte CAN_set_break(void)
{
  if (CAN_txpos) {                     /* Is a char in the transmit buffer? */
    return ERR_TXFULL;                 /* If yes then error */
  }
  /* Send break signal */  
  return CAN_send_frame(0, &CAN_txpos); /* OK */
}

/********************************************************************************/
/* Reset CAN buffer registers. Resynchronize frame reception                     */
/********************************************************************************/
void CAN_on_error(void){
  CAN_rxpos = 0;
  CAN_txpos = 0;
  CAN_rxlen = 0;                    /* resyncronize frame reception */
  CAN_txlen = 0;                    
  CAN_Flag &= ~(CAN_RXFRAME);
  CAN_Flag &= ~(CAN_TXFRAME);
  CAN_ErrFlag &= ~(CAN_FULL_RX);
  CAN_ErrFlag &= ~(CAN_BREAK_ERR);
  CAN0TIER_TXEIE0 = 0;             /* Disable Transmitter empty interrupt register */
}

/********************************************************************************/
/* CAN frame transmission                                                       */
/********************************************************************************/
byte CAN_send_frame(byte Length, byte *TxData)
{   
    /* Transmission buffer */
    byte TxBuffer = {0};
    
    /* Index to data within the transmission buffer */ 
    byte Index;
    
    if (!CAN0TFLG)              /* Retrun if Transmit Buffer is full */
        return ERR_BUFFER_FULL;

    CAN0TBSEL = CAN0TFLG;     /* Select lowest empty buffer */
    TxBuffer = CAN0TBSEL;		/* Backup selected buffer */
    
    /* Load Id to IDR Registers */
    CAN0TXIDR1_ID_18 = (0x07 & CAN_node_ID);
    CAN0TXIDR0 = (byte)(CAN_node_ID >> 3);
    CAN0TXIDR1_IDE = 0; /* Standart format */             
    CAN0TXIDR1_SRR = 0; /* RTR = 0 => Data frame */
    
    if (Length > 8) Length = 8;    
    /* Load data to Data Segment Registers */
    for (Index=0;Index<Length;Index++) {
        *(&CAN0TXDSR0 + Index) = TxData[Index];  
    }

    CAN0TXDLR = Length;   /* Set Data Length Code */
    CAN0TXTBPR = 1;         /* Set Priority */

    CAN0TFLG = TxBuffer;  /* Start transmission */
    CAN0TIER_TXEIE0 = 1;    /* Enable transmit interrupt */
    
    /* Wait for Transmission completion */            
    Index = 0;
    while ( (CAN0TFLG & TxBuffer) != TxBuffer)
      if (Index++ >= 254) break;  
            
    return ERR_OK;
 }

/********************************************************************************/
/* Read CAN reception buffer                                                    */
/********************************************************************************/
byte CAN_received_frame(word *pID, byte *pLength, byte *pRxData)
{
    /* Node ID */
    word ID;
    
    /* Length of received frame */
    byte Length;
    
    /* Index for extracting/storing received data */
    byte i;
    
    ID = ((word)CAN0RXIDR0 << 8);
    ID |= CAN0RXIDR1;
    ID >>= 5;
    *pID = ID;
    
    Length = (CAN0RXDLR & 0x0F);  /* Extract received frame data length */
    *pLength = Length;
    
	  if (Length <= 8){ 
	    /* Read and store each of the received data */
	    for (i = 0; i < Length; i++)
	      *pRxData++ =  *(&CAN0RXDSR0 + i);    
  	  return ERR_OK;   
	  } else return ERR_RANGE;      
}


/********************************************************************************/
/*\CAN initialization, baud rate = 500kbps, 16 bit acceptance filters */
/********************************************************************************/
void CAN_init(word node_ID) 
{
    /* Node ID definition */
    CAN_node_ID = 0x07FF & node_ID;
    
    CAN0CTL0 = 0x01;    /* MSCAN in initialization mode */
        while (!(CAN0CTL1_INITAK))
            ;	        /* Wait for initialization mode acknowledge */
            
    CAN0CTL1_CANE = 1;      /* Enable MSCAN module */
    CAN0CTL1_CLKSRC = 1;    /* Clock source is BUSCLK, CANCLK = 40MHz */    
    CAN0CTL1_LOOPB = 0;     /* Set to 1 for LoopBack Mode, 0 otherwise */
    CAN0CTL1_LISTEN = 0;    /* Not listen only mode */            
           
    /* Baud rate = CANCLK/(Prescaler * time quantas) */                                                                           
    CAN0BTR1_TSEG_10 = 0x04;    /* Time Segment 1 = 5 */
    CAN0BTR1_TSEG_20 = 0x01;    /* Time Segment 2 = 2 */
                                /* TSEG1 + TSEG2 + SYNCH_SEG = 8 time quantas */                              
                                    
    /* Prescaler = CANCLK/(Baud rate * time quantas) = 40MHz/(500kHz * 8) = 10 */    
    CAN0BTR0_BRP = 0x09;    /* Baud rate prescaler = 1 */  
    CAN0BTR0_SJW = 0x01;    /* Synchronization jump width = 2 clock cycles */
                                  
    CAN0BTR1_SAMP = 1;      /* Three samples per bit */	      
         
    
    CAN0IDAC_IDAM = 0x01;               /* Four 16-bit acceptance filters */                                                          
    
    /* 16 bit Filter 0 */
    CAN0IDAR0 = 0x00;
    CAN0IDAR1 = 0x20;
    if (CAN_node_ID == 1){
      CAN0IDMR0 = 0x1F;  // Node 1 receives all frames         
      CAN0IDMR1 = 0xE0;
    }
    else{       
      CAN0IDMR0 = 0x00;  // Node 2..255 receive only frame from node 1
      CAN0IDMR1 = 0x00;
    }
          
    CAN0IDAR2 = 0x00;                   /* 16 bit Filter 1 */
    CAN0IDMR2 = 0x00;   
    CAN0IDAR3 = 0x00;                   
    CAN0IDMR3 = 0x00;    
    
    CAN0IDAR4 = 0x00;                   /* 16 bit Filter 2 */
    CAN0IDMR4 = 0x00;   
    CAN0IDAR5 = 0x00;                   
    CAN0IDMR5 = 0x00;    
    
    CAN0IDAR6 = 0x00;                   /* 16 bit Filter 3 */
    CAN0IDMR6 = 0x00;   
    CAN0IDAR7 = 0x00;                   
    CAN0IDMR7 = 0x00;    
    
    
    CAN0CTL0 = 0x00;            /* Exit initialization mode request */
        while (CAN0CTL1_INITAK)
            ;               	/* Wait for normal mode */
                   
        while(!(CAN0CTL0_SYNCH))
            ;                   /* Wait for CAN synchronization */
   
    CAN0RFLG_RXF = 1;       /* Clear receiver flags */                                   
    CAN0RIER_RXFIE = 1;     /* Enable Full Receive Buffer interrupt */
    //CAN0RIER_CSCIE = 1;     /* Status change interrupt enable */
    //CAN0RIER_TSTATE = 2;    /* Generate CSCIF interrupt only if the transmitter enters or leaves TxErr or bus-off state */
    
    CAN0TIER_TXEIE0 = 0;    /* Disable Transmitter empty interrupt register */                                
}

#pragma CODE_SEG CAN_CODE


/********************************************************************************/
/* CAN TX Interrupt Service routine                                             */
/********************************************************************************/
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt CAN0_TX_Isr(void)
{      
  /* Call CAN driver interrupt service routine */
  byte i = 0; 
  byte Length; 
   
  if (CAN_Flag & CAN_TXFRAME) {       /* frame transmission in progress */      
    if (CAN_txpos < CAN_txlen){      
      Length = CAN_txlen - CAN_txpos;
      if (Length > 8) Length = 8;
      /* Store chars to transmitter register */
      if (CAN_send_frame(Length, &CAN_txdata[CAN_txpos]) == ERR_OK);
      CAN_txpos += Length;
    }
    if (CAN_txpos >= CAN_txlen){       /* no data in buffer? */
      CAN_Flag &= ~(CAN_TXFRAME);      /* end of frame */
      CAN0TIER_TXEIE0 = 0;             /* Disable Transmitter empty interrupt register */
    }  
  } 
}
#pragma CODE_SEG CAN_TX_ISR_CODE


/********************************************************************************/
/* CAN RX Interrupt Service routine                                             */
/********************************************************************************/
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt CAN0_RX_Isr(void)
{      
  /* Call CAN driver interrupt service routine */
  byte RxData[8];
  byte Length;
  UINT16 ID;
  byte i = 0;
  
  if (CAN_received_frame(&ID, &Length, &RxData[0]) == ERR_OK){
    if(Length > 0) {
      if (!(CAN_Flag & CAN_RXFRAME)){ /* new frame? */              
        CAN_rxlen = RxData[0];      /* frame header */
        CAN_rxpos = 0;
        CAN_Flag |= (CAN_RXFRAME);  /* rxframe = 1 */
        i = 1;
      }
      for (i = i; i < Length; i++){
        if (CAN_rxpos < CAN_rxlen)          /* buffer overload */
          CAN_rxdata[CAN_rxpos++] = RxData[i];
        else CAN_ErrFlag |= CAN_FULL_RX;
      }   
    }else CAN_on_error();  /* Reset all buffers counters */ 
  }
   
  CAN0RFLG_RXF = 1;   /* Clear reception flag */   
}
#pragma CODE_SEG CAN_RX_ISR_CODE


/********************************************************************************/
/* CAN Error Interrupt Service Routine                                          */
/********************************************************************************/
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt CAN0_ERR_Isr(void)
{      
    CAN0RFLG_CSCIF = 1;
}
#pragma CODE_SEG CAN_ERR_ISR_CODE


#pragma CODE_SEG DEFAULT

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

