//io.c
//
//Program to send and receive text messages with Hyperterminal
//and busy tokens with the test node
//
//Derek Marston and Peter Susi
//5/02/03

#include "common.h"
#include "iob32.h" //all IO and memory names

//	Authorize interrupts.

#define cli()	_asm("andcc #$EF")

#define SIZE	21	/* buffer size */
#define MSGLEN  16	/* max message length */
#define TDRE	0x80	/* transmit ready bit */
//#define OURADDR 'A'	//our node address
#define OURADDR ''

char KBbuff[SIZE];	/* reception buffer */
char RxTokbuff[SIZE];   /* receive token buffer */
char RdyTokbuff[SIZE];  /* to send token buffer */
char Displaybuff[SIZE]; /* display buffer */

char *kbptr;		//keyboard buffer pointer
char *rxptr;		//receive token buffer pointer
char *rdyptr;		//send token buffer pointer
char *dispptr;		//display buffer pointer

int RecFlag;
int Data2SendFlag;
int DispFlag;


void main(void)
{

//load stack pointer...can be done in linker file

	Init();
	ConfigUSART();
	ConfigSCI();
	cli();


	for(;;)
	{
		if (Data2SendFlag)
		{
			Data2SendFlag = 0x00;
			SendBusy();
		}
		//SendFree();
		//infinite loop
	}
}

//Initializes ports and pointers to buffers
void Init()
{
	DDRA = 0x8F;
	/*
	pin 0 = USART reset
	pin 1 = Read'
	pin 2 = Write'
	pin 3 = command/data'

	pin 4 = TxRDY
	pin 5 = RxRDY
	pin 6 = unused

	pin 7 = output square wave for debug purposes

	*/

	DDRB = 0xFF; //PORTB is command/status/data register of USART
	//set to output to initialize USART

	//initialize pointers
	kbptr = &KBbuff[0];
	rxptr = &RxTokbuff[0];
	rdyptr = &RdyTokbuff[0];
	dispptr = &Displaybuff[0];

	//initialize static members in busy token buffer
	RdyTokbuff[0] = 0xAA;
	RdyTokbuff[1] = 0xBB;
	RdyTokbuff[2] = OURADDR;

	RdyTokbuff[SIZE-2] = 0x0D;
	RdyTokbuff[SIZE-1] = 0xAA;

	//initialize flags
	RecFlag = 0;
	Data2SendFlag = 0;
	DispFlag = 0;
}

/*Configure 8251 USART for:
;		Asyncronous serial data
;		Baud Rate Factor = 16
;		8Bit data, no parity
;		1 stop bit
;		Enable transmitter
*/
void ConfigUSART()
{
	PORTB = 0x4E; //send initialization code to USART

	PORTA = 0x07; //set pin 0 high for USART hardware reset

	wait();

	PORTA = 0x06; //end reset pulse

	PORTA = 0x0E; //set USART ready for COMMAND
	PORTA = 0x0A; //Set USART ready for WRITE 
	PORTA = 0x0E; //end write pulse

	wait();

	PORTB = 0x05; //send second byte of initialization code

	PORTA = 0x0E; //set USART ready for COMMAND
	PORTA = 0x0A; //Set USART ready for WRITE 
	PORTA = 0x0E; //end write pulse

	wait();

	PORTA = 0x06; //set USART to idle mode}
}

//delay a few clock cycles
//
void wait(void)
{
	int count;
	for (count = 0; count < 4; count++)
	{}
}

//copy contents of one buffer to another
//
void CopyBuff(char *src, char *dest, int numbytes)
{	
	int c;

	for (c = 0; c < numbytes; c++)
	{
		*dest++ = *src++;
	}
}

//display the contents of the display buffer to the hyperterminal window

void Display()
{
	int c;
	for (dispptr = &Displaybuff[0]; *dispptr != 0x0D; dispptr++)
		CharOut(*dispptr);

}

//Configures port for Asynchronous serial 8-bit data, no parity, 1 stop bit
//enable the transmitter and receiver
void ConfigSCI()
{
	
	SC0CR1 = 0x00; 	
 		// enable Tx, Rx and RxInterrupt

	SC0CR2 = 0x2C;

	SC0BDL = 0x34;	//BR divisor for 9600 BPS

}

//Waits for the transmitter to be ready (until TDRE bit in the Status Register is 1)
//then writes the contents of the passed parameter (one byte) to the Data Register
void CharOut(char tosend)
{
//	BIT_CHAR temp;
//	temp.byte = SC0SR1;
//	while (!temp.b.b7)
//	{}

	while (!(SC0SR1 & TDRE))  //TDRE is defined above
	{}	

	SC0DRL = tosend;
}	

//Outputs text messages to the Hyperterminal Screen for debugging purposes
//
void StrOut(char *msg, int len)
{
	int c;
	for (c = 0; c < len; c++)
		CharOut(msg[c]);
	CharOut(0x0D);
}

// Reads last byte from the Data register and returns it.

char GetKey()
{
	return SC0DRL;
}

//Wait for one byte to arrive at the USART and return it.
char Receive()
{
	char DATA;

	DDRA = 0x8F;

	while (!(PORTA & BIT5))	//wait for RxRdy signal
	{
		PORTA = 0x86;
	}

	PORTA = 0x06;

//      Put USART in COMMAND mode to read status register
//	PORTA = 0x0E;
//	PORTA = 0x0C;  //COMMAND and READ
//	while (!(PORTB & 0x02))
//	{}
//	PORTA = 0x06;   //Put USART back into IDLE mode

	wait();

	DDRB = 0x00; 	//set Port B to input
	PORTA = 0x84;	//Pulse READ command for USART

//	CharOut(PORTB);
	DATA = PORTB;
//	CharOut(0x0D);

	PORTA = 0x06;	//end READ pulse
	return DATA;  //get data

}

//Transmit toTx via external USART (connected to PortB)
void Transmit(char toTx)
{

	while (!(PORTA & BIT4))  //waits until USART is ready to transmit
	{}

	DDRB = 0xFF;  //set PORTB to output on all pins

	PORTB = toTx;  //set data on USART's data bus via portB
	

	PORTA = 0x02; //Set USART ready for WRITE data
	PORTA = 0x06; //end write pulse


/*
	PORTA = (PORTA | ~BIT2);//activates Write signal on USART 

	PORTA = (PORTA & BIT2);  //deactivates write signal
*/
//	wait();		//kills time to let USART use data

}

//send a Free Token (AA FF AA)
void SendFree(void)
{
	Transmit(0xAA);
	Transmit(0xFF);
	Transmit(0xAA);
}

//Send a busy token according to data in RdyBuff

void SendBusy()
{
	for (rdyptr=&RdyTokbuff[0]; rdyptr < &RdyTokbuff[SIZE]; rdyptr++)
		Transmit(*rdyptr);
}

// Interrupt Routine for recieving Hyperterminal bytes
//
@interrupt void _SCIRx_ISR(void)
{
        SC0SR1; // read Status Reg to clear interrupt 	

	*kbptr = SC0DRL;   // put char in keyboard buffer

	SC0DRL = *kbptr;    // Echo back byte


	if (*kbptr == 0x1B)
		SendFree();  //send a free token when Esc is pressed

	else if (*kbptr == 0x08)
		kbptr--;    //don't transmit backspace character
			   // or previous character

	else if (++kbptr >= &KBbuff[MSGLEN] || *(kbptr-1) == 0x0D)
	{
		kbptr = &KBbuff[0];
		CopyBuff(&KBbuff[0], &RdyTokbuff[3], MSGLEN);
		Data2SendFlag = 1;
		CharOut(0x0D);  // see on screen that message was sent.
		CharOut('>');
	}


}


//Interrupt Routine triggered on RxRdy (tied to IRQ, or PE1)
// to receive network data.
//
@interrupt void _IRQ_ISR(void)
{
	// generate square wave on interrupt
	//square();
	CollectToken();
}

void CollectToken()
{
	RecFlag = 0x00;
	rxptr = &RxTokbuff[0];		//initialize pointer


	if ((*rxptr = Receive()) == 0xAA) //get first byte, see if it's AA
	{
		rxptr++;
//		StrOut("first byte is AA", 16);
//			Receive();
//			StrOut("Rx ok", 5);

		if ((*rxptr = Receive()) == 0xFF) //see if second byte is FF
		{
			rxptr++;

//			StrOut("next byte is FF ", 16);
	
			if ((*rxptr = Receive()) == 0xAA) //if third byte is AA
			{
				SendFree();//temp debug code
				CharOut('F');
				CharOut('r');
				CharOut('e');
				CharOut('e');
				CharOut(0x0D);

				RecFlag = 0xFF; // then it's a valid free token
				return;
			}
		}
			
		else if (*rxptr == 0xBB) //if second byte is not FF, 
		{					//see if it is BB
			rxptr++;
			//StrOut("Busy here", 9);
			//BusyHere
			for (;rxptr < &RxTokbuff[SIZE]; rxptr++)
			{
				*rxptr = Receive();
			} // get the rest of the bytes
				
		
			if (*(rxptr-1) == 0xAA)
			{
				CharOut(0x0D);				
				CharOut('B');//temp debug code
				CharOut('u');
				CharOut('s');
				CharOut('y');
				CharOut(0x0D);

				RecFlag = 0xBF;
			}

			CopyBuff(&RxTokbuff[0], &Displaybuff[0], SIZE);
			Display();

			return;
		}	

		else if (*rxptr == 0xAA) //if second byte is AA
			StrOut("Nerfy!",6);

		else
			//StrOut("Not FF or BB", 12);
			CharOut(*rxptr);
	}
	else
		StrOut("Not even first AA",17);


	return;
}

/*
;Name:		ProcessFreeToken
;Input:		None
;Output:	None
;Destroys:	A, X, Y, Flags
;Desc:		Send a busy token if there is data to send
;		Otherwise send a free token

ProcessFreeToken:
	clr	RecFlag		;token received
	ldaa	Data2SendFlag	;do we have data2send?
	bne	prepBusy	;yes
	
	jsr	sendFree	;no-pass free on
	rts	
prepBusy:
	ldx	#KBBuff
	ldy	#RecBuff	;actually, this is the 
				;Tx Buffer now.  HAHAHA

	ldaa	#0BBh		;append leading BB to token
	staa	0,y
	iny

	ldaa	#US		;put our node address into 
	staa	0,y		;the source byte of token
	iny

	jsr	CopyBuff	;copy busy token
				;into Tx/Rx buffer
	jsr	sendBusy
	clr	Data2SendFlag
//	rts
*/

//Generates a square wave on all pins of Port A.  Use for debugging.
//
void square(void)
{
	DDRA = 0xFF;

	for(;;) //generate a square wave on all pins of Port A
	{
		PORTA = 0x00;	//turn bit off
		wait();

		PORTA = 0xFF; //(PORTA & BIT7);	//turn bit on
		wait();
	}	

}
