/*********************************************************/
/* ON Semiconductor                                      */
/* MCV7383 Evaluation KIT                                */
/*                                                       */
/* SCI0.C                                                */
/* Serial communication interface SCI0                   */
/*                                                       */
/* Created by: Filip Brtan                               */
/* Date: 30.07.2012                                      */
/*********************************************************/

// PROTOCOL:
// This module implements the transmission level of the host communication protocol. See documentation for details.

// NOTES:
// - Receive buffer overrun is not checked. If this happens, new data is discarded until space in the buffer is available.

/** S12X derivative information */ 
#include <mc9s12xf512.h> 
/** Variable types and common definitions */
#include "typedefs.h"  
/** ADC header file */
#include "SCI0.h"

#pragma DATA_SEG SCI0_DATA
#pragma CODE_SEG SCI0_CODE

/*** Flags ***/

#define OVERRUN_ERR      1             /* Overrun error flag bit */
#define COMMON_ERR       2             /* Common error of RX */      
#define CHAR_IN_RX       4             /* Char is in the RX buffer */
#define RUNINT_FROM_TX   8             /* Interrupt is in progress */
#define FULL_RX          16            /* Full receive buffer */     
#define BREAK_ERR        32            /* Break detect */
#define RXFRAME          64            /* frame reception in progress */
#define TXFRAME          128           /* frame transmission in progress */

static byte SerFlag;                   /* 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 ErrFlag = 0;               /* Error flags mirror of SerFlag */

/* Buffers */
byte SCI0_rxlen;                       /* Length of incoming frame */
byte SCI0_txlen;                       /* Length of outgoing frame */

static byte rxpos;                     /* current position in the RX buffer */
static byte txpos;                     /* current position in the TX buffer */


TBUFFER_DATA SCI0_rxdata[SIZE_RXBUF];  /* Reception data buffer */
TBUFFER_DATA SCI0_txdata[SIZE_TXBUF];  /* Transmission data buffer */


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

/*******************************************************************************/
/* Data reception finished                                                     */
/*******************************************************************************/
byte  SCI0_received (void) {
  return (byte)((SerFlag & RXFRAME) && (rxpos == SCI0_rxlen));
}

/*******************************************************************************/
/* Received data processed, get ready for next frame                           */
/*******************************************************************************/
void SCI0_rxprocessed (void) {
  SerFlag &= ~(RXFRAME);     /* RXFRAME = 0 */
}

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

/*******************************************************************************/
/* Request to transmit data in the TX buffer                                   */
/*******************************************************************************/
void SCI0_transmit (void) {
  // Send the header byte right away.
  SCI0DRL = (byte)SCI0_txlen;
  txpos = 0;
  SerFlag |= (TXFRAME);                /* TXFRAME = 1 */
  SCI0CR2_TIE = 1;                     /* Enable transmit interrupt */
}

/*******************************************************************************/
/* Transmission in progress                                                    */
/*******************************************************************************/
byte  SCI0_txactive (void) {
  return (SerFlag & TXFRAME);
}


/*******************************************************************************/
/* Tests the internal input break flag                                         */
/*******************************************************************************/
byte SCI0_GetBreak(byte *Brk)
{
  EnterCritical();                     /* Save the PS register */
  *Brk = (ErrFlag & BREAK_ERR) !=0;    /* If was break signal? */
  ErrFlag &= ~BREAK_ERR;               /* Reset break signal flag */
  ExitCritical();                      /* Restore the PS register */
  return ERR_OK;                       /* OK */
}


/*******************************************************************************/
/* Sends the break sequence to the output line                                 */
/*******************************************************************************/
byte SCI0_SetBreak(void)
{
  if (txpos) {                         /* Is a char in the transmit buffer? */
    return ERR_TXFULL;                 /* If yes then error */
  }
  EnterCritical();                     /* Save the PS register */
  SCI0CR2_SBK = 1;                     /* Send break signal */
  SCI0CR2_SBK = 0;                     /* Send break signal */
  ExitCritical();                      /* Restore the PS register */
  return ERR_OK;                       /* OK */
}

/*******************************************************************************/
/* Reset SCI0 buffer registers. Resyncronize frame reception                   */
/*******************************************************************************/
void SCI0_OnError(void){
  rxpos = 0;
  txpos = 0;
  SCI0_rxlen = 0;                    /* resyncronize frame reception */
  SCI0_txlen = 0;                    
  SerFlag &= ~(RXFRAME);
  SerFlag &= ~(TXFRAME);
  SCI0CR2_TIE = 0;                     /* Send break signal */
}

/*******************************************************************************/
/* SCI0 module Interrupt service routine                                       */
/*******************************************************************************/
#pragma CODE_SEG __NEAR_SEG NON_BANKED
void interrupt SCI0_Isr(void)
{
  byte StatReg = SCI0SR1;
  byte OnFlags = 0;                    /* Temporary variable for flags */
  byte AltStatReg;
  byte Data;                           /* Temporary variable for data */   

  SCI0SR2_AMAP = 1;                    /* Switch to the alternative register set */
  AltStatReg = SCI0ASR1;               /* Read alternative status flag */
  SCI0ASR1 = SCI0ASR1_BKDIF_MASK;      /* Clear alternative status flags */
  SCI0SR2_AMAP = 0;                    /* Switch to the normal register set */

  if(AltStatReg & SCI0ASR1_BKDIF_MASK) { /* Is break signal detected? */
    OnFlags |= BREAK_ERR;              /* If yes then set an internal flag */
  }
  if (StatReg & (SCI0SR1_OR_MASK | SCI0SR1_FE_MASK | SCI0SR1_NF_MASK)) { /* Is any error flag set? */
    OnFlags |= COMMON_ERR;             /* If yes then set an internal flag */
    (void) SCI0DRL;                    /* Dummy read of data register - clear error bits */
    StatReg &= ~SCI0SR1_RDRF_MASK;     /* Clear the receive data flag to discard the errorneous data */
  }
  SerFlag |= OnFlags;                  /* Copy flags status to SerFlag status variable */
  ErrFlag |= OnFlags;                  /* Copy flags status to ErrFlag status variable */
  if (OnFlags & BREAK_ERR) {           /* Was the break signal detected? */
    SCI0_OnError();             
  } else if(OnFlags & (COMMON_ERR)) {  /* Was any error set? */
    SCI0_OnError();
  }
  
  /* --- received data interrupt --- */
  if (StatReg & SCI0SR1_RDRF_MASK) {   /* Is the receiver interrupt flag set? */
    Data = SCI0DRL;
    if (!(SerFlag & RXFRAME)) {        /* new frame? */
      SCI0_rxlen = Data;               /* frame header */
      rxpos = 0;
      SerFlag |= (RXFRAME);            /* rxframe = 1 */
    } 
    else {
      if (rxpos < SCI0_rxlen)          /* buffer overload */
        SCI0_rxdata[rxpos++] = Data;   /* frame data */
    }                
  }
  
  /* --- transmitted data interrupt --- */
  if (SCI0CR2_TIE) {                   /* Is the transmitter interrupt enabled? */
    if (StatReg & SCI0SR1_TDRE_MASK) { /* Is the transmitter interrupt flag set? */
      if (SerFlag & TXFRAME) {                   /* frame transmission in progress */      
        if (txpos < SCI0_txlen){       /* data in buffer */
          (void) SCI0SR1;              /* Reset interrupt request flag */
          SCI0DRL = (byte) SCI0_txdata[txpos++];/* Store char to transmitter register */
        } 
        else {
          SerFlag &= ~(TXFRAME);       /* end of frame */
          SCI0CR2_TIE = 0;             /* Disable transmit interrupt */
        }
      }
    }
  }
}

#pragma CODE_SEG SCI0_CODE

/*******************************************************************************/
/* SCI module Initialization.                                                  */
/*******************************************************************************/
void SCI0_init (void)
{
  byte dummy;
      
  rxpos = 0;
  txpos = 0;
  SCI0_rxlen = 0;
  SCI0_txlen = 0;
  
  /* --- SCI0 --- */
  /* SCI0CR2: TIE=0,TCIE=0,RIE=0,ILIE=0,TE=0,RE=0,RWU=0,SBK=0 */
  SCI0CR2 = 0;                /* Disable the SCI0 module */ 
  dummy = SCI0SR1;            /* Dummy read of the SCI0SR1 registr to clear flags */
  dummy = SCI0DRL;            /* Dummy read of the SCI0DRL registr to clear flags */
  /* SCI0SR2: AMAP=0,??=0,??=0,TXPOL=0,RXPOL=0,BRK13=1,TXDIR=0,RAF=0 */
  SCI0SR2 = 4;                  
  /* SCI0BD: IREN=0,TNP1=0,TNP0=0,SBR12=0,SBR11=0,SBR10=0,SBR9=0,SBR8=0,SBR7=1,SBR6=0,SBR5=0,SBR4=0,SBR3=0,SBR2=0,SBR1=1,SBR0=0 */
  SCI0BD = 130;                
  /* SCI0CR1: LOOPS=0,SCISWAI=0,RSRC=0,M=0,WAKE=0,ILT=0,PE=0,PT=0 */
  SCI0CR1 = 0;                  
  /* SCI0SR2: AMAP=1 */
  SCI0SR2_AMAP = 1;           /* Switch to the alternative register set */ 
  /* SCI0ASR1: RXEDGIF=1,??=0,??=0,??=0,??=0,BERRV=0,BERRIF=1,BKDIF=1 */
  SCI0ASR1 = 131;             /* Clear interrupt flags */ 
  /* SCI0ACR1: RXEDGIE=0,??=0,??=0,??=0,??=0,??=0,BERRIE=0,BKDIE=1 */
  SCI0ACR1 = 1;                 
  /* SCI0ACR2: ??=0,??=0,??=0,??=0,??=0,BERRM1=0,BERRM0=0,BKDFE=1 */
  SCI0ACR2 = 1;                 
  /* SCI0SR2: AMAP=0 */
  SCI0SR2_AMAP = 0;           /* Switch to the normal register set */ 
  /* SCI0CR2: TIE=0,TCIE=0,RIE=1,ILIE=0,TE=1,RE=1,RWU=0,SBK=0 */
  SCI0CR2 = 0x2C;                  
}

#pragma CODE_SEG DEFAULT

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