/**
 * \file   sys_uart.c
 *
 * \brief  SYS/BIOS UART Driver source file
 *
 * Copyright (c) 2012 Texas Instruments Incorporated ALL RIGHTS RESERVED
 * 
*/

#include "osdrv_uart.h"
#include "plat_uart.h"


Hwi_Handle uart3HwiHandle = NULL;
UART_ISR_FUNC uart3UsrISR = NULL;
char* uart3TxArray;
unsigned int uart3TxStrLength;


Hwi_Handle uart5HwiHandle = NULL;
UART_ISR_FUNC uart5UsrISR = NULL;
char* uart5TxArray;
unsigned int uart5TxStrLength;

/* Global variable to store the Interrupt number according to instance */
UInt  intNum;

static void UARTHandleError(UInt instance)
{
	UInt baseAddr = 0;
	switch(instance)
	{
	case 3:
		baseAddr = SOC_UART_3_REGS;
		break;
	case 5:
		baseAddr = SOC_UART_5_REGS;
		break;
	default:
		return;
	}	
	
    while((UARTRxErrorGet(baseAddr)))
    {
        /* Read a byte from the RBR if RBR has data.*/
    	UARTCharGetNonBlocking(baseAddr);
    }

}

Void UART5Isr(UArg arg)
{
    static unsigned int uart5count = 0;
    unsigned int intId = 0;

    /* Checking the source of UART interrupt. */
    intId = UARTIntIdentityGet(SOC_UART_5_REGS);

    switch(intId)
    {
        case UART_INTID_TX_THRES_REACH:
            if(0 != uart5TxStrLength)
            {
                UARTCharPut(SOC_UART_5_REGS, uart5TxArray[uart5count]);
                uart5TxStrLength--;
                uart5count++;
            }
            else
            {
                /* Disabling the THR interrupt. */
                UARTIntDisable(SOC_UART_5_REGS, UART_INT_THR);
                uart5count = 0;
            }
        break;
        case UART_INTID_RX_THRES_REACH:
        	if(uart5UsrISR)
        		uart5UsrISR(intId);
        	else
        		UARTCharGetNonBlocking(SOC_UART_5_REGS);
        break;

        case UART_INTID_RX_LINE_STAT_ERROR:
        case UART_INTID_CHAR_TIMEOUT:
        	if(uart5UsrISR)
        		uart5UsrISR(intId);
        	UARTHandleError(5);
        break;

        default:
        break;
    }
}


Void UART3Isr(UArg arg)
{
    static unsigned int count = 0;
    unsigned int intId = 0;

    /* Checking the source of UART interrupt. */
    intId = UARTIntIdentityGet(SOC_UART_3_REGS);

    switch(intId)
    {
        case UART_INTID_TX_THRES_REACH:
            if(0 != uart3TxStrLength)
            {
                UARTCharPut(SOC_UART_3_REGS, uart3TxArray[count]);
                uart3TxStrLength--;
                count++;
            }
            else
            {
                /* Disabling the THR interrupt. */
                UARTIntDisable(SOC_UART_3_REGS, UART_INT_THR);
                count = 0;
            }
        break;
        case UART_INTID_RX_THRES_REACH:
        	if(uart3UsrISR)
        		uart3UsrISR(intId);
        	else
        		UARTCharGetNonBlocking(SOC_UART_3_REGS);
        break;

        case UART_INTID_RX_LINE_STAT_ERROR:
        case UART_INTID_CHAR_TIMEOUT:
        	if(uart3UsrISR)
        		uart3UsrISR(intId);
        	UARTHandleError(3);
        break;

        default:
        break;
    }
}

Bool UartOpen(UInt instance,UART_ISR_FUNC isrFunc)
{
    Hwi_Params hwiParams;
	Hwi_FuncPtr  hwiFuncPointer = NULL;
	Hwi_Handle tempHwiHandler;
    Error_Block eb;
	
	switch(instance)
	{
	case 3:
		if(NULL != uart3HwiHandle )
			return FALSE;
		intNum = 44;
		hwiFuncPointer = UART3Isr;
		break;
	case 5:
		if(NULL != uart5HwiHandle )
			return FALSE;
		intNum = 46;
		hwiFuncPointer = UART5Isr;
		break;
	default:
		return FALSE;
	}

	UARTInit(instance);

    Hwi_Params_init(&hwiParams);
    Error_init(&eb);

    // set the argument you want passed to your ISR function
    hwiParams.arg = 1;
    // set the event id of the peripheral assigned to this interrupt
    hwiParams.priority = 0x24;

    tempHwiHandler  = Hwi_create(intNum ,hwiFuncPointer , &hwiParams, &eb);

    if (Error_check(&eb))
    {
    	return FALSE;
    }
	
	switch(instance)
	{
	case 3:
		uart3HwiHandle = tempHwiHandler;
		uart3UsrISR = isrFunc;
		break;
	case 5:
		uart5HwiHandle = tempHwiHandler;
		uart5UsrISR = isrFunc;
		break;
	default:
		return FALSE;
	}	
    Hwi_enableInterrupt(intNum);
	return TRUE;
}


Bool UARTPutChar(UInt instance,Char txChar)
{
	//UARTPut(instance,txChar);
	unsigned int baseAddr = 0;
	switch(instance)
	{
	case 3:
		if(NULL == uart3HwiHandle )
			return FALSE;	
		baseAddr = SOC_UART_3_REGS;
		break;
	case 5:
		if(NULL == uart5HwiHandle )
			return FALSE;		
		baseAddr = SOC_UART_5_REGS;
		break;
	default:
		return FALSE;
	}
	UARTCharPut(baseAddr,txChar );
	return TRUE;
}

Bool UARTGetChar(UInt instance,Char *rxChar)
{
	//Need error check here TODO
	//UARTGet(instance,&rxChar);
	unsigned int baseAddr = 0;
	switch(instance)
	{
	case 3:
		if(NULL == uart3HwiHandle )
			return FALSE;		
		baseAddr = SOC_UART_3_REGS;
		break;
	case 5:
		if(NULL == uart5HwiHandle )
			return FALSE;		
		baseAddr = SOC_UART_5_REGS;
		break;
	default:
		return FALSE;
	}
	*rxChar = UARTCharGet(baseAddr );
	return TRUE;
}

Bool UARTPutString(UInt instance,Char* buffer)
{
	//UARTPuts(instance,buffer);
	unsigned int baseAddr = 0;
	switch(instance)
	{
	case 3:
		if(NULL == uart3HwiHandle )
			return FALSE;		
		baseAddr = SOC_UART_3_REGS;
		uart3TxArray = buffer;
		uart3TxStrLength = strlen(buffer);
		break;
	case 5:
		if(NULL == uart5HwiHandle )
			return FALSE;		
		baseAddr = SOC_UART_5_REGS;
		uart5TxArray = buffer;
		uart5TxStrLength = strlen(buffer);
		break;
	default:
		return FALSE;
	}
	UARTIntEnable(baseAddr, UART_INT_THR);
	return TRUE;
}

Void UartClose(UInt instance)
{
	switch(instance)
	{
	case 3:
		if(NULL != uart3HwiHandle )
			Hwi_delete(&uart3HwiHandle);
		uart3UsrISR = NULL;
		uart3TxArray = NULL;
		uart3TxStrLength = 0;
		break;
	case 5:
		if(NULL != uart5HwiHandle )
			Hwi_delete(&uart5HwiHandle);
		uart5UsrISR = NULL;
		uart5TxArray = NULL;
		uart5TxStrLength = 0;
		break;
	default:
		break;
	}
}

unsigned int UartGetIntNum()
{
	return intNum;
}

