#include <string.h>
#include "LPC2300.h"
#include "interrupt.h"
#include "comm.h"


#define BUFFER_SIZE 128

#define PCLK		18000000
#define BPS 		230400
#define	DIVADDVAL	5
#define	MULVAL		8
#define	DLVAL		((int)((double)PCLK / BPS / 16 / (1 + (double)DIVADDVAL / MULVAL)))


static volatile struct
{
	int		rptr;
	int		wptr;
	int		count;
	BYTE	buff[BUFFER_SIZE];
} TxFifo0, RxFifo0;
static volatile int TxRun0;




void Isr_UART0 (void)
{
	int d, idx, cnt, iir;


	for (;;) {
		iir = U0IIR;			/* Get Interrupt ID*/
		if (iir & 1) break;		/* Exit if there is no interrupt */
		switch (iir & 6) {
		case 4:			/* Receive FIFO is half filled or timeout occured */
			idx = RxFifo0.wptr;
			cnt = RxFifo0.count;
			while (U0LSR & 0x01) {			/* Receive all data in the FIFO */
				d = U0RBR;
				if (cnt < BUFFER_SIZE) {	/* Store data if buffer is not full */
					RxFifo0.buff[idx] = d;
					cnt++;
					idx = (idx + 1) % BUFFER_SIZE;
				}
			}
			RxFifo0.wptr = idx;
			RxFifo0.count = cnt;
			break;

		case 2:			/* Transmisson FIFO empty */
			cnt = TxFifo0.count;
			if (cnt) {
				idx = TxFifo0.rptr;
				for (d = 12; d && cnt; d--, cnt--) {	/* Store data into FIFO (max 12 chrs) */
					U0THR = TxFifo0.buff[idx];
					idx = (idx + 1) % BUFFER_SIZE;
				}
				TxFifo0.rptr = idx;
				TxFifo0.count = cnt;
			} else {
				TxRun0 = 0;				/* When no data in the buffer, clear running flag */
			}
			break;

		default:		/* Data error or break detected */
			d = U0LSR;
			d = U0RBR;
			break;
		}
	}
}




int uart0_test (void)
{
	return RxFifo0.count;
}




BYTE uart0_get (void)
{
	BYTE d;
	int idx;

	/* Wait while Rx buffer is empty */
	while (!RxFifo0.count);

	U0IER = 0;				/* Disable interrupts */
	idx = RxFifo0.rptr;
	d = RxFifo0.buff[idx];	/* Get a byte from Rx buffer */
	RxFifo0.rptr = (idx + 1) % BUFFER_SIZE;
	RxFifo0.count--;
	U0IER = 0x07;			/* Enable interrupt */

	return d;
}




void uart0_put (BYTE d)
{
#if 0
	while (!(U0LSR & 0x20));
	U0THR = d;
#else
	int idx, cnt;

	/* Wait for buffer ready */
	while (TxFifo0.count >= BUFFER_SIZE);

	U0IER = 0x05;		/* Disable Tx Interrupt */
	if (!TxRun0) {		/* When not in runnig, trigger transmission */
		U0THR = d;
		TxRun0 = 1;
	} else {			/* When transmission is runnig, store the data into the Tx buffer */
		cnt = TxFifo0.count;
		idx = TxFifo0.wptr;
		TxFifo0.buff[idx] = d;
		TxFifo0.wptr = (idx + 1) % BUFFER_SIZE;
		TxFifo0.count = ++cnt;
	}
	U0IER = 0x07;		/* Enable Tx Interrupt */
#endif
}




void uart0_init (void)
{
	U0IER = 0x00;
	RegisterVector(UART0_INT, Isr_UART0, PRI_LOWEST, CLASS_IRQ);

	/* Attach UART0 unit to I/O pad */
	PINSEL0 = (PINSEL0 & 0xFFFFFF0F) | 0x50;

	/* Initialize UART0 */
	U0LCR = 0x83;			/* Select divisor latch */
	U0DLM = DLVAL / 256;	/* Initialize BRG */
	U0DLL = DLVAL % 256;
	U0FDR = (MULVAL << 4) | DIVADDVAL;
	U0LCR = 0x03;			/* Set serial format N81 and deselect divisor latch */
	U0FCR = 0x87;			/* Enable FIFO */
	U0TER = 0x80;			/* Enable Tansmission */

	/* Clear Tx/Rx FIFOs */
	TxFifo0.rptr = 0;
	TxFifo0.wptr = 0;
	TxFifo0.count = 0;
	RxFifo0.rptr = 0;
	RxFifo0.wptr = 0;
	RxFifo0.count = 0;

	/* Enable Tx/Rx/Error interrupts */
	U0IER = 0x07;
}


