/*******************************************************************************
* Freescale Semiconductor Inc.
* (c) Copyright 2004-2005 Freescale Semiconductor, Inc.
* ALL RIGHTS RESERVED.
********************************************************************************
Services performed by FREESCALE in this matter are performed AS IS and without 
any warranty. CUSTOMER retains the final decision relative to the total design 
and functionality of the end product. FREESCALE neither guarantees nor will be 
held liable by CUSTOMER for the success of this project.
FREESCALE DISCLAIMS ALL WARRANTIES, EXPRESSED, IMPLIED OR STATUTORY INCLUDING, 
BUT NOT LIMITED TO, IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR 
A PARTICULAR PURPOSE ON ANY HARDWARE, SOFTWARE OR ADVISE SUPPLIED TO THE PROJECT
BY FREESCALE, AND OR NAY PRODUCT RESULTING FROM FREESCALE SERVICES. IN NO EVENT
SHALL FREESCALE BE LIABLE FOR INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF 
THIS AGREEMENT.

CUSTOMER agrees to hold FREESCALE harmless against any and all claims demands or 
actions by anyone on account of any damage, or injury, whether commercial, 
contractual, or tortuous, rising directly or indirectly as a result of an advise
or assistance supplied CUSTOMER in connection with product, services or goods 
supplied under this Agreement.
********************************************************************************
* File      SCI.c
* Owner     b01802
* Version   1.0
* Date      Dec-02-2010
* Classification   General Business Information
* Brief     SCI functions
********************************************************************************
Revision History:
Version   Date          Author    Description of Changes
1.0       Dec-02-2010   b01802    Initial version
*******************************************************************************/
#include <string.h>
#include "Types.h"
#include "Regdef.h"
#include "SCI.h"
#include "Srec.h"

/******************************************************************************/
#define Baud9600 163
#define Baud38400 41
#define Baud57600 27
#define Baud115200 14

#define XOn 0x11
#define XOff 0x13

#define RxBufSize 96
#define TxBufSize 64

#define XOnCount RxBufSize - 8
#define XOffCount (RxBufSize-16)+2

/******************************************************************************/
UINT8 RxBuff[RxBufSize];  //receive queue
UINT8 TxBuff[TxBufSize];  //transmit queue
UINT8 RxIn;               //next available location in the Rx queue
UINT8 RxOut;              //next character to be removed from the Rx queue
UINT8 TxIn;               //next available location in the Tx queue
UINT8 TxOut;              //next character to be sent from the Tx queue
volatile UINT8 RxBAvail;  //number of bytes left in the Rx queue
volatile UINT8 TxBAvail;  //number of bytes left in the Tx queue

UINT8 XOffSent;
  //flag indicating that an XOff character was sent (== 1, XOff was sent)
  
UINT8 XOffRcvd;
  //flag indicating that an XOff character was received (== 1, XOff was received)
  
UINT8 SendXOff;
  //flag indicating that the TxISR should send an XOff the next time it's called
  
UINT8 SendXOn;

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

INT8 getchar(void);
INT8 putchar(INT8 c);
void OutStr(INT8 * Str);

/******************************************************************************/
void OutStr(INT8 * Str)
{
  //output 1 character at a time untill we reach the end of the string
  while (*Str != 0)
    putchar(*Str++);
}

/******************************************************************************/
INT8 putchar(INT8 c)
{
 while (TxBAvail == 0);     //if there's no room in the xmit queue wait here
 
 DisableInterrupts;
 TxBuff[TxIn++] = (UINT8)c; //put the char in the buffer, inc buffer index
 if (TxIn == TxBufSize)     //buffer index go past the end of the buffer?
  TxIn = 0;                 //yes. wrap around to the start
 TxBAvail--;                //one less character available in the buffer
 if (XOffRcvd == 0)         //if an XOff has not been received...
  SCICR2 |= SCICR2_TIE_MASK;//enable SCI transmit interrupts
 EnableInterrupts;
 
 return(c);                 //return the character we sent
}

/******************************************************************************/
INT8 getchar(void)
{
 UINT8 c;                   //holds the character we'll return
 
 //if there's no characters in the Rx buffer wait here
 while (RxBAvail == RxBufSize);
 
 DisableInterrupts;
 
 //get a character from the Rx buffer & advance the Rx index
 c = RxBuff[RxOut++];
 if (RxOut == RxBufSize)    //index go past the physical end of the buffer?
  RxOut = 0;                //yes wrap around to the start
 RxBAvail++;                //1 more byte available in the receive buffer
 
 //if an XOff was previously sent & the Rx buffer
 //has more than XOnCount bytes available
 if ((XOffSent != 0) & (RxBAvail >= XOnCount))
 {
   SendXOn = 1;
   SCICR2 |= SCICR2_TIE_MASK; //enable SCI transmit interrupts
 }
 EnableInterrupts;
 
 return(c);     //return the character retrieved from receive buffer
}

/******************************************************************************/
void InitSCI(void)
{
  SCICR2 = 0;               //reset the SCI if it was previously enabled
  
  RxIn = RxOut = TxIn = TxOut = 0;  //set the Rx & Tx queue indexes to zero
  RxBAvail = RxBufSize;     //the receive buffer is empty
  TxBAvail = TxBufSize;     //the transmit buffer is empty
  XOffSent = 0;             //XOff character has not been sent
  XOffRcvd = 0;             //XOff character has not been received
  SendXOff = 0;             //Don't send an XOff
  SCIBD = Baud9600;         //initialize the Baud register
  //enable both the transmitter & receiver
  SCICR2 = SCICR2_TE_MASK + SCICR2_RE_MASK + SCICR2_RIE_MASK;
}
 
/******************************************************************************/
void SetBaud(void)
{
  INT8 c;
  
  OutStr("\r\n1.) 9600\r\n"); //display baud rate selection menu
  OutStr("2.) 38400\r\n");
  OutStr("3.) 57600\r\n");
  OutStr("4.) 115200\r\n");
  OutStr("? ");
  c = getchar();              //get choice
  (void)putchar(c);           //echo choice
  
  //display message at old baudrate
  OutStr("\r\nChange Terminal Baud Rate and Press Return");
  
  //now wait until the last character has been shifted out
  while ((SCISR1 & SCISR1_TC_MASK) == 0);
  
  switch (c) {
  
  case '1':
    SCIBD = Baud9600;
    break;
  
  case '2':
    SCIBD = Baud38400;
    break;
   
  case '3':
    SCIBD = Baud57600;
    break;
   
  case '4':
    SCIBD = Baud115200;
    break;
    
  default:                  //invalid choice returns to main menu
    break;
  
  }
  
  (void)getchar();          //and wait for the user to change the baud rate
  
  OutStr("\r\n");
  OutStr("Passed\r\n");
}

/******************************************************************************/
#pragma CODE_SEG RAM_CODE
static void RxISR(void)
{ 
  UINT8 c;
  
  c = SCIDRL;
  
  if (c == XOff)                //host want us to stop sending data?
  {
    SCICR2 &= ~SCICR2_TIE_MASK; //yes. disable transmit interrupts
    XOffRcvd = 1; //let putchar know that it may continue to place characters
                  //in the buffer but not enable Xmit interrupts
    return;
  }
  else if (c == XOn)            //host want us to start sending data?
  {
    if (TxBAvail != TxBufSize)  //anything left in the Tx buffer?
    SCICR2 |= SCICR2_TIE_MASK;  //yes. enable transmit interrupts
    XOffRcvd = 0;
    return;
  }
  
  //if the number of bytes available in the Rx buff
  //is < XOffCount & an XOff hasn't been sent 
  if ((RxBAvail <= XOffCount) && (XOffSent == 0))
  {
    SendXOff = 1; //set flag to send an XOff, stoping the host from sending data
    XOffSent = 1; //set the flag showing that we've queued up to send an XOff
    
    //enable transmit interrupts,
    //so the TxISR will be called next time the TDRE bit is set
    SCICR2 |= SCICR2_TIE_MASK;
  }
  
  if (RxBAvail != 0)            //if there are bytes available in the Rx buffer
  {
    RxBAvail--;                 //reduce the count by 1
    RxBuff[RxIn++] = c;         //place the received byte in the buffer
    if (RxIn == RxBufSize)      //reached the physical end of the buffer?
    RxIn = 0;                   //yes. wrap around to the start
  }
}
#pragma CODE_SEG DEFAULT

/******************************************************************************/
#pragma CODE_SEG RAM_CODE
static void TxISR(void)
{
  if (SendXOn != 0)             //request to send an XOn to the host?
  {
    SendXOn = 0;
    XOffSent = 0;               //reset the XOff flag
    SCIDRL = XOn;               //send the character
    if (TxBAvail == TxBufSize)  //anything in the Tx buffer?
    SCICR2 &= ~SCICR2_TIE_MASK; //no. disable transmit interrupts
  }
  else if (SendXOff != 0)       //request to send an XOff to the host?
  {
    SendXOff = 0;               //yes, clear the request
    SCIDRL = XOff;              //send the character
    if (TxBAvail == TxBufSize)  //anything in the Tx buffer?
    SCICR2 &= ~SCICR2_TIE_MASK; //no. disable transmit interrupts
  }
  else
  {
    SCIDRL = TxBuff[TxOut++];   //remove a character from the buffer & send it
    
    if (TxOut == TxBufSize)     //reached the physical end of the buffer?
      TxOut = 0;                //yes. wrap around to the start
      
    if (++TxBAvail == TxBufSize)  //anything left in the Tx buffer?
      SCICR2 &= ~SCICR2_TIE_MASK; //no. disable transmit interrupts
   }
}
#pragma CODE_SEG DEFAULT

/******************************************************************************/
#pragma CODE_SEG RAM_CODE
interrupt void SCIISR(void)
{
  // if the RDRF OR the OR flag is set
  if (SCISR1 & (SCISR1_RDRF_MASK + SCISR1_OR_MASK))
    RxISR();              //go get a character & place it in the buffer
    
  //if transmit interrupts are enable AND the TDRE flag is set
  if ((SCICR2 & SCICR2_TIE_MASK) && (SCISR1 & SCISR1_TDRE_MASK))
    TxISR();              //go send a character to the host
}
#pragma CODE_SEG DEFAULT

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