/*
 * Copyright (c) 2016, Texas Instruments Incorporated
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * *  Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * *  Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * *  Neither the name of Texas Instruments Incorporated nor the names of
 *    its contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */


/***
 * \file:   uart.c
 *
 * \brief:  This file contains  Supporting routines for uart test application
 *
 * \n       This file contains support  routines to test uart
 * 
 */


#include "stdio.h"
#include "uart.h"

/***
 * \brief: Routine to get the value of a uart register.
 *
 * \b \Descr: This routine get the value of a uart register.This routine takes uart
 * \n         controller base addresss as a parameter along with that register offset as
 * \n         another parameter and returns the value of the register.
 * 
 *
 * \param:    uart		[IN]	uart controller base address
 *            reg         [IN]    register offset value
 *  
 * \return:   returns register value
 * 
 */
UINT32 _UART_rget
(
	UART_Handle uart,
	UINT32 reg
)
{
    UINT32 reg_value;
    UINT32 lcr;
    UINT32 preg32     = ( ( UINT32 )uart ) + ( reg & ~( USE_LCR_80 | USE_LCR_BF ) );
    UINT32 set_lcr_80 = ( ( UINT32 )reg ) & USE_LCR_80;
    UINT32 set_lcr_bf = ( ( UINT32 )reg ) & USE_LCR_BF;

    /* Set LCR if needed */
    if ( set_lcr_80 )
    {
        lcr = _UART_rget( uart, LCR_OFFSET );
        _UART_rset( uart, LCR_OFFSET, 0x80 );
    }
    if ( set_lcr_bf )
    {
        lcr = _UART_rget( uart, LCR_OFFSET );
        _UART_rset( uart, LCR_OFFSET, 0xbf );
    }

    /* Get UART register */
    reg_value = *( volatile UINT32* )( preg32 );

    /* Return LCR reg if necessary */
    if ( set_lcr_80 || set_lcr_bf )
        _UART_rset( uart, LCR_OFFSET, lcr );

    return reg_value;
}
/***
 * \brief: Routine to set the value of a uart register.
 *
 * \b \Descr: This routine set the value of a uart register.This routine takes uart
 * \n         controller base addresss as a parameter along with that register offset as
 * \n         another parameter and the value of the register.
 * 
 *
 * \param    uart		[IN]	uart controller base address
 *           reg        [IN]    register offset value
 * \return: VOID
 */
void _UART_rset
(
	UART_Handle uart,
	UINT32 reg,
	UINT32 reg_value
)
{
    UINT32 lcr;
    UINT32 preg32     = ( ( UINT32 )uart ) + ( reg & ~( USE_LCR_80 | USE_LCR_BF ) );
    UINT32 set_lcr_80 = ( ( UINT32 )reg ) & USE_LCR_80;
    UINT32 set_lcr_bf = ( ( UINT32 )reg ) & USE_LCR_BF;

    /* Set LCR if needed */
    if ( set_lcr_80 )
    {
        lcr = _UART_rget( uart, LCR_OFFSET );
        _UART_rset( uart, LCR_OFFSET, 0x80 );
    }
    if ( set_lcr_bf )
    {
        lcr = _UART_rget( uart, LCR_OFFSET );
        _UART_rset( uart, LCR_OFFSET, 0xbf );
    }

    /* Set UART register */
    *( volatile UINT32* )( preg32 ) = reg_value;

    /* Return LCR reg if necessary */
    if ( set_lcr_80 || set_lcr_bf )
        _UART_rset( uart, LCR_OFFSET, lcr );
}
/***
 * \brief: Routine to reset the uart  conntroller.
 *
 * \b \Descr: This routine resets the uart controller.This routine takes uart
 * \n         controller base addresss as a parameter.
 * 
 * \param:   uart  [IN]   uart to be resetted
 * \return:  VOID
 *
 */
void _UART_reset
(
	UART_Handle uart
)
{
    /* Reset Sequence */
    _UART_rset( uart, EFR, 0x10 );
    _UART_rset( uart, IER_OFFSET, 0 );
    _UART_rset( uart, MCR_OFFSET, 0 );
    _UART_rset( uart, EFR, 0 );
    _UART_rset( uart, LCR_OFFSET, 0 );
    _UART_rset( uart, MDR1_OFFSET, 0x07 );
}

/***
 * \brief:  Routine to Enable Hardware Flow Control
 *
 * \param:  uart  [IN]   uart on which Hardware Flow Control needs to be
 * \n       enabled.
 * \return: SUCCESS
 */
 
SINT16 UART_EnableHWFlowCntl
(
	UART_Handle uart
)
{
	UINT32 efr;
	
	switch (uart)
	{
		case DM8127_UART0_BASE:
		case DM8127_UART1_BASE:
		case DM8127_UART2_BASE:
		case DM8127_UART3_BASE:
			efr = _UART_rget( uart, EFR);
			_UART_rset( uart, EFR, efr | 0xC0);
			_UART_rset(uart, MCR_OFFSET, 0x2);
			break;
		default:
				return 1;
	}
	return 0; /* success */
}

/***
 * \brief: Routine to Disable Hardware Flow Control
 *
 * \param:   uart  [IN]   uart on which Hardware Flow Control needs to be
 * \n        disabled.
 * \return: SUCCESS
 */

SINT16 UART_DisableHWFlowCntl
(
	UART_Handle uart
)
{
	UINT32 efr;
	
	switch (uart)
	{
		case DM8127_UART0_BASE:
		case DM8127_UART1_BASE:
		case DM8127_UART2_BASE:
		case DM8127_UART3_BASE:
			efr = _UART_rget(uart, EFR);
			efr = efr & ~0xC0;
			_UART_rset(uart, EFR, efr);
			break;
		default:
				return 1;
	}
	
	return 0; /* success */
}


/***
 * \brief: Routine to open the uart .
 *
 * \b \Descr: This routine enables the uart .This routine takes uart id  as a parameter
 * \n         which gives information about which uart to be selected  along with that
 * \n         it takes baudrate as another parameter.
 * 
 *
 * \param     id   	    [IN]    uart to be opened
 *            baudrate  [IN]    uart Baudrate
 *
 *                                                                
 * \return:  uart base address on success
 * \n        0 on failure
 */
UART_Handle _UART_open
(
	UINT16 id,
	UINT32 baudrate
)
{
    UART_Handle uart;
    UINT32 efr, ier, fcr, lcr, mcr, mdr1;

    switch ( id )
    {
        /* RS232 - UART */
        case UART_0:
            uart = DM8127_UART0_BASE;
            ier  = 0x01;//ier  = 0x00; // No interrupts enabled
            fcr  = 0x57; // FIFO Mode, 16 character trigger level
            lcr  = 0x03; // 8 bits, no parity, 1 stop
            mcr  = 0x00; //
            mdr1 = 0x00;
            break;

        /* Expansion */
        case UART_1:
            uart = DM8127_UART1_BASE;
            ier  = 0x00; // No interrupts enabled
            fcr  = 0x57; // FIFO Mode, 16 character trigger level
            lcr  = 0x03; // 8 bits, no parity, 1 stop
            mcr  = 0x00; //
            mdr1 = 0x00;
            break;

        /* IR Remote */
        case UART_2:
            /*uart = DM8127_UART2_BASE;
            ier  = 0x00; // No interrupts enabled
            fcr  = 0x00; // Non-FIFO Mode
            lcr  = 0x03; // 8 bits, no parity, 1 stop
            mcr  = 0x00; //
            mdr1 = 0x06; // CIR*/
            uart = DM8127_UART2_BASE;
            ier  = 0x00; // No interrupts enabled
            fcr  = 0x57; // FIFO Mode, 16 character trigger level
            lcr  = 0x03; // 8 bits, no parity, 1 stop
            mcr  = 0x00; //
            mdr1 = 0x00;
            break;
        case UART_3:
            uart = DM8127_UART3_BASE;
            ier  = 0x00; // No interrupts enabled
            fcr  = 0x57; // FIFO Mode, 16 character trigger level
            lcr  = 0x03; // 8 bits, no parity, 1 stop
            mcr  = 0x00; //
            mdr1 = 0x00;
            break;
            
        default:
            return 0;
    }

    /* Reset the UART from any previous state */
    _UART_reset( uart );

    /* Set IER, FCR, LCR, MCR reg */
    efr = _UART_rget( uart, EFR );
    _UART_rset( uart, EFR, efr | 0x10 );
    _UART_rset( uart, IER_OFFSET, ier );
    _UART_rset( uart, FCR_OFFSET, fcr );
    _UART_rset( uart, LCR_OFFSET, lcr );
    _UART_rset( uart, MCR_OFFSET, mcr );
    _UART_rset( uart, EFR, efr );

    /* Set MDR1 - disable UART */
    _UART_rset( uart, MDR1_OFFSET, 0x07 );

    /* Set Baudrate */
    _UART_rset( uart, DLL, ( baudrate >> 0 ) & 0xff );
    _UART_rset( uart, DLH, ( baudrate >> 8 ) & 0xff );

    /* Set MDR1 - enable UART */
    _UART_rset( uart, MDR1_OFFSET, mdr1 );

    /* Return Handle */
    return uart;
}
#if 0
/** **************************************************************************
 * \n \brief Routine  to close the uart .
 *
 * This routine disables the uart by resetting the uart.This routine takes uart 
 * id as a parameter which gives information about which uart to be selected  
 * 
 * 
 *
 * \param   uart		[IN]    uart to be opened
 * \param   baudrate    [IN]    uart Baudrate 
 *
 *                                                                
 * \return        
 * \n        returns uart base address on success                                         
 * \n        returns 0 on failure
 *  
 * 
 */
SINT16 _UART_close( UART_Handle uart )
{
    _UART_reset( uart );
    return 0;
}
#endif

/***
 * \brief:  Routine to check reception is ready in  uart
 *
 * \b \Descr: This routine checks whether RX FIFO is ready in uart.This routine
 * \n         takes uart id  as a parameter which gives information about which
 * \n         uart to be selected.
 * 
 * \param     uart		    [IN]    uart base address
 *
 * \return:   1  if  reception ready
 * \n         0  if reception is not ready
 */
 
SINT16 _UART_rcvReady
(
	UART_Handle uart
)
{
    /* FIFO is not empty */
    if ( _UART_rget( uart, LSR_OFFSET ) & 0x01 )
        return 1;

    /* FIFO is empty */
       return 0;
}

/***
 * \brief: Routine to get one byte of data
 *
 * \b \Descr: This routine to get one byte of data.This routine takes uart id  as a
 * \n         parameter which gives information about which uart to be selected along with
 * \n         that it contains a buffer pointer to copy the data.
 *
 * \param      uart		    [IN]    uart base address
 * \n          *data         [IN]    buffer pointer to copy the received data
 *                                                                
 * \return  0 on successfull  completion of  the routine.
 */

SINT16 _UART_getChar
(
	UART_Handle uart,
	char* data
)
{
    /* Recv a byte */
    *data = _UART_rget( uart, RHR_OFFSET );
    return 0;
}
/***
 * \brief: Routine to check if transmission is ready in uart
 *
 * \b \Descr: This routine to check if Tx Fifo is ready or not.This routine takes
 * \n         uart id as a parameter which gives information about which uart to
 * \n         be selected .
 * 
 *
 * \param:    uart		    [IN]    uart base address
 *
 * \return:   0 if transmission is not ready
 *            1 if transmission i ready
 */
SINT16 _UART_xmtReady
(
	UART_Handle uart
)
{
    /* FIFO is empty */
    if ( _UART_rget( uart, LSR_OFFSET ) & 0x20 )
        return 1;

    /* FIFO is not empty */
    
        return 0;
}
/***
 * \brief: Routine to send a byte of data to uart
 *
 * \b \Descr: This routine sends one byte of data.This routine takes uart id  as a
 * \n         parameter which gives information about which uart to be selected
 * \n         along with that it contains a buffer pointer to copy the data.
 *
 * \param   uart		    [IN]    uart base address.
 *          *data         [IN]    buffer pointer to be copied.
 *                                                                
 * \return  0 on successfull  completion of  the routine.
 */

SINT16 _UART_putChar
(
	UART_Handle uart,
	UINT8 data
)
{
    /* Send a byte */
    _UART_rset( uart, THR_OFFSET, data );
    return 0;
}

/***
 * \brief: Routine receive a byte of data from uart.
 *
 * \b \Descr: This routine receive a byte of data from uart.This routine takes uart
 * \n         id  as a parameter which gives information about which uart to be
 * \n         selected along with that it takes bufferpointer as another parameter
 * \n         to copy the received data and timeout as another parameter.
 *
 * \param     uart		 [IN]     uart to be selected
 *            *rx       [IN]     Buffer pointer to copy received data
 *            timeout      [IN]     Timeout for receiving
 *                                                                
 * \return   1 on failure
 *           0 on success
 */
SINT16 uart_recv
(
	UART_Handle uart,
	char* rx,
	SINT32 timeout
)
{

	*rx ='*';
    /* Check if RX ready, if not timeout */
    while( _UART_rcvReady( uart ) == 0 );
    do
    {
    	_UART_getChar( uart, rx );
    }while(*rx == '*');
    {
#if 0
          if ( timeout-- < 0 )
          {
              printf("Error:Timeout occured while Receiving\n");
              return 1;
          }    
#endif
//          _UART_getChar( uart, rx );
    }  
    
    /* Read 1 byte */
//    _UART_getChar( uart, rx );
    return 0;
}
/***
 * \brief: Routine send a byte of data to uart.
 *
 * \b \Descr: This routine send a byte of data to uart.This routine takes uart id
 * \n         as a parameter which gives information about which uart to be
 * \n         selected along with that it takes buffer pointer as another parameter
 * \n       to send  data and timeout as another parameter.
 *
 * \param   uart	    [IN]    uart to be selected
 *          tx          [IN]    Data to be transmitted
 *          timeout     [IN]    Timeout for transmitting
 *                                                                
 * \return   1 on failure
 *           0 on success
 */
SINT16 uart_send
(
	UART_Handle uart,
	UINT8 tx,
	SINT32 timeout
)
{
    /* Check if TX ready, if not timeout */
    while( _UART_xmtReady( uart ) == 0 )
    {
    	
        if ( timeout-- < 0 )
        {
           printf("Error:Timeout occured while transmitting\n");
           return 1;
        }   
    
    }  
    
    /* Write 1 byte */
   _UART_putChar( uart, tx );
    
    return 0;    
}
