// serial.c

#include "serial.h"
#include "delay_timer.h"

void InitSci (void)
{
	volatile unsigned long bit_delay;
	
	// serial port initialisation
	//
	// disable Tx and Rx
	SCI_SCR.BIT.TE = 0;
	SCI_SCR.BIT.RE = 0;
	// internal baud rate generator with SCK pin used as general IO
	SCI_SCR.BIT.CKE = 0;
	
	// async mode
//	SCI_SMR.BIT.CA = 0;
	// 8-N-1
//	SCI_SMR.BIT.CHR = 0;
//	SCI_SMR.BIT.PE = 0;
//	SCI_SMR.BIT.STOP = 0;
	// even parity (not required for 8-N-1)
//	SCI_SMR.BIT.OE = 0;
	// multiprocessor mode disabled
//	SCI_SMR.BIT.MP = 0;
	// n=0 (uses system clock)
//	SCI_SMR.BIT.CKS = 0;
// individual bit definitions shown above replaced by single statement below to reduce code size
	SCI_SMR.BYTE = 0;
	
	// baud rate
	SCI_BRR = BAUD_57600;
	
	// wait at least 1 bit time
	for (bit_delay=0; bit_delay<100000; bit_delay++);
	
	// disable transmit interrupts
//	SCI_SCR.BIT.TIE = 0;
	// disable receive and receive error interrupts
//	SCI_SCR.BIT.RIE = 0;
	// disable transmit end interrupts
//	SCI_SCR.BIT.TEIE = 0;
	// disable multiprocessor interrupts
//	SCI_SCR.BIT.MPIE = 0;
// individual bit definitions shown above replaced by single statement below to reduce code size
	SCI_SCR.BYTE = 0;
	
	// enable Tx and Rx
	SCI_SCR.BIT.TE = 1;
	SCI_SCR.BIT.RE = 1;
}

void SendByte (unsigned char b)
{
	while ( SCI_SSR.BIT.TDRE == 0 );
	SCI_TDR = b;
  	SCI_SSR.BIT.TDRE = 0;
}

void SendString (char* str)
{
	unsigned short us;
	
	us = 0;
	while ( str[us] != 0 )
	{
		SendByte ( (unsigned char) str[us] );
		us++;
	}
}

unsigned short GetByte (unsigned long timeout)
{
	//	timeout = time in ms for which to timeout the data reception
	//
	//	returns a 16-bit value
	//	upper (msb) byte contains status info
	//	lower (lsb) byte contains the data received from the SCI channel
	//
	//	status:
	//	OK
	//	ERROR
	//	TIMEOUT
	//
		
	union union_c2s c2s;
	
	unsigned long tick_count;
	
	tick_count = timeout / MS_PER_TIMER_COMPARE_MATCH;
	
  	StartDelayTimer();
  	
  	// wait for a byte to arrive
  	while ( (SCI_SSR.BIT.RDRF == 0) && (tick_count) )
  	{
    	// check for receive errors
    	if ( (SCI_SSR.BIT.ORER == 1) || (SCI_SSR.BIT.FER == 1) || (SCI_SSR.BIT.PER == 1) )
    	{
			// clear error flags
			SCI_SSR.BIT.ORER = 0;
			SCI_SSR.BIT.FER = 0;
			SCI_SSR.BIT.PER = 0;
			
			c2s.uc[0] = ERROR;			
			return (c2s.us);
    	}
    	
    	if ( GetDelayTimerStatus() )
    	{
    		StopDelayTimer();
    		if ( --tick_count )
    		{
    			StartDelayTimer();
    		}
    	}
  	}
  	
	if ( SCI_SSR.BIT.RDRF )
	{
		c2s.uc[1] = SCI_RDR;
	  	c2s.uc[0] = OK;
	  	SCI_SSR.BIT.RDRF = 0;
	}
	else
	{
    	c2s.uc[0] = TIMEOUT;
	}
  	
  	return (c2s.us);
}

unsigned char RxByteWaiting (void)
{
	//
	// returns 1 - if the RDRF bit is set
	// returns 0 - if RDRF bit is clear
	//
	if ( SCI_SSR.BIT.RDRF )
	{
		return (1);
	}
	else
	{
		return (0);
	}
}

void PurgeComms (unsigned long timeout)
{
	union union_c2s c2s;
	
	do {
		c2s.us = GetByte( timeout );
	} while( (c2s.uc[0] != TIMEOUT) && (c2s.uc[0] != ERROR) );
}
