#include <p24FJ128GA006.h>
#include <stdio.h>
#include "serial.h"

volatile u_char sio_rxd[MAX_SIO_COUNT];
volatile int sio_head;				/* a pointer to serial Rx buffer */
int sio_tail;				/* a pointer to serial Rx buffer */

UARTHANDLER	uart_handler;

#if (__C30_VERSION__ >= 300)
void __attribute__((interrupt, auto_psv)) _U1RXInterrupt(void)
#else
void _ISR _U1RXInterrupt(void)
#endif
{
	IFS0bits.U1RXIF = 0;	// flag clear

	sio_rxd[sio_head] = U1RXREG;
	
	sio_head++;
	
	if (sio_head == sio_tail)
	{
		sio_head--;	/* buffer full. */
	}
	if (sio_head >= MAX_SIO_COUNT)		/* for ring buffer */
	{
		sio_head = 0;
		if (sio_head == sio_tail) sio_head = MAX_SIO_COUNT;
	}
}

void uart_init(void)
{
	int old_ipl;

	U1BRG = Fcy / 16 / BAUD - 1;
	U1TXREG = 0;
	U1STAbits.UTXEN = 1;
	
	SET_AND_SAVE_CPU_IPL(old_ipl, 7);
	IFS0bits.U1RXIF = 0;	// flag clear
	IPC2bits.U1RXIP = 1;	// priority 1
	IEC0bits.U1RXIE = 1;	// uart1 rx interrupt
	RESTORE_CPU_IPL(old_ipl);

	uart_handler.uart_get_handler = uart0_getchar;
	uart_handler.uart_put_handler = uart0_putchar;

	sio_head = 0;
	sio_tail = 0;

	U1MODEbits.UARTEN = 1;

	uart0_putchar(0);
	uart0_putchar(0);
	uart0_putchar(0);
}

u_int uart_keyhit(u_char uart)
{
	if(sio_head >= sio_tail ) return (sio_head-sio_tail);
	else return (MAX_SIO_COUNT-(sio_tail-sio_head));
}

void uart0_putchar(char c)
{
	while (U1STAbits.UTXBF) ;
	if(!U1STAbits.UTXEN) U1STAbits.UTXEN = 1;
	U1TXREG = c;
}

char uart0_getchar(void)
{
	char c;
	while (sio_head == sio_tail);
	
	c = sio_rxd[sio_tail++];
	
	if (sio_tail >= MAX_SIO_COUNT) sio_tail = 0;

	return c;
}

int write (int handle, void *buffer, unsigned int len)
{		
	int i;

	for (i = len; i; --i) {
		uart0_putchar(*(char*)buffer++);
	}
    return len; 
}

int read(int handle, void *buffer, unsigned int len)
{
	int i;

	for (i = len; i; --i)
	{
		*(char*)buffer++ = uart0_getchar();
	}
	len -= i;

	return(len);
}

void uart_puts(u_char uart, char * str)
{
	int i;
	i = 0;
	while (str[i]) (*uart_handler.uart_put_handler)(str[i++]);
}

int uart_gets(u_char uart, char * str, char bpasswordtype, int max_len)
{
	char c;
	char * tsrc = str;
	char IsFirst = 1;
	int len = 0;
	
	while ((c = (*uart_handler.uart_get_handler)()) != 0x0D)
	{      
		if (IsFirst && c=='!')
		{
			while(*str != '\0') (*uart_handler.uart_put_handler)(*str++);
			IsFirst = 0;
			len++;
			continue;
		}
		if (c == 0x08 && tsrc != str)
		{
	       		(*uart_handler.uart_put_handler)(0x08);
			(*uart_handler.uart_put_handler)(' ');
			(*uart_handler.uart_put_handler)(0x08);
			str--;
			len--;
			continue;
		}
		else if (c == 0x1B)
		{
			while (tsrc != str)
			{
		       		(*uart_handler.uart_put_handler)(0x08);
				(*uart_handler.uart_put_handler)(' ');
				(*uart_handler.uart_put_handler)(0x08);
				str--;
				len--;
			}
			IsFirst = 1;
			continue;			
		}
		else if ((c < 32 || c > 126) && c != '\t')	continue; 
		if(len < max_len)
		{
			if(bpasswordtype) (*uart_handler.uart_put_handler)('*');
			else (*uart_handler.uart_put_handler)(c);
			*str++ = c;
			len++;
			IsFirst = 0;
		}
	}
	*str = '\0';
	uart_puts(0, "\r\n");
	
	return len;
}

void uart_flush_rx(void)
{
	sio_head = sio_tail;
}


