/**
 * \file  uartEcho.c
 *
 * \brief This is a sample application file which invokes some APIs
 *        from the UART device abstraction library to perform configuration,
 *        transmission and reception operations.
 */

/*
* Copyright (C) 2012 Texas Instruments Incorporated - http://www.ti.com/ 
*
*  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.
*/

#include "hw_psc_OMAPL138.h"
#include "soc_OMAPL138.h"
#include "interrupt.h"
#include "evmOMAPL138.h"
#include "hw_types.h"
#include "uart.h"
#include "psc.h"

/****************************************************************************/
/*                      LOCAL FUNCTION PROTOTYPES                           */
/****************************************************************************/
static void ConfigureIntUART(void);
static void SetupInt(void);
static void UARTIsr(void);

/****************************************************************************/
/*                      GLOBAL VARIABLES                                    */
/****************************************************************************/
char txArray[] = "StarterWare UART echo application\n\r";

/****************************************************************************/
/*                      LOCAL FUNCTION DEFINITIONS                          */
/****************************************************************************/

#define REGS_UART SOC_UART_1_REGS
#define UART_INT  SYS_INT_UARTINT1

int main(void)
{
    unsigned int intFlags = 0;
    unsigned int config = 0;

    /* Enabling the PSC for UART2.*/
    PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_UART1, PSC_POWERDOMAIN_ALWAYS_ON,
		     PSC_MDCTL_NEXT_ENABLE);

    PSCModuleControl(SOC_PSC_1_REGS, HW_PSC_UART2, PSC_POWERDOMAIN_ALWAYS_ON,
		     PSC_MDCTL_NEXT_ENABLE);

    /* Setup PINMUX */
    UARTPinMuxSetup(2, FALSE);
    UARTPinMuxSetup(1, FALSE);
    
    /* Enabling the transmitter and receiver*/
    UARTEnable(REGS_UART);

    /* 1 stopbit, 8-bit character, no parity */
    config = UART_WORDL_8BITS;

    /* Configuring the UART parameters*/
    UARTConfigSetExpClk(REGS_UART, SOC_UART_2_MODULE_FREQ,
                        BAUD_115200, config,
                        UART_OVER_SAMP_RATE_16);

    /* Enabling the FIFO and flushing the Tx and Rx FIFOs.*/
    UARTFIFOEnable(REGS_UART);

    /* Setting the UART Receiver Trigger Level*/
    UARTFIFOLevelSet(REGS_UART, UART_RX_TRIG_LEVEL_1);
    
    /*
    ** Enable AINTC to handle interrupts. Also enable IRQ interrupt in ARM 
    ** processor.
    */
    SetupInt();

    /* Configure AINTC to receive and handle UART interrupts. */
    ConfigureIntUART();

    /* Preparing the 'intFlags' variable to be passed as an argument.*/
    intFlags |= (UART_INT_LINE_STAT  |  \
                 UART_INT_TX_EMPTY |    \
                 UART_INT_RXDATA_CTI);

    /* Enable the Interrupts in UART.*/
    UARTIntEnable(REGS_UART, intFlags);

    UARTCharPutNonBlocking(REGS_UART, '1');

    while(1);
}

/*
** \brief   Interrupt Service Routine(ISR) to be executed on UART interrupts.
**          Depending on the source of interrupt, this 
**          1> writes to the serial communication console, or 
**          2> reads from the serial communication console, or 
**          3> reads the byte in RBR if receiver line error has occured.
*/

static void UARTIsr()
{
    static unsigned int length = sizeof(txArray);
    static unsigned int count = 0;
    unsigned char rxData = 0;
    unsigned int int_id = 0;

    /* This determines the cause of UART2 interrupt.*/
    int_id = UARTIntStatus(REGS_UART);

#ifdef _TMS320C6X
    // Clear UART2 system interrupt in DSPINTC
    IntEventClear(UART_INT);
#else
    /* Clears the system interupt status of UART2 in AINTC. */
    IntSystemStatusClear(UART_INT);
#endif
  
    /* Checked if the cause is transmitter empty condition.*/
    if(UART_INTID_TX_EMPTY == int_id)
    {
        if(0 < length)
        {
            /* Write a byte into the THR if THR is free. */
            UARTCharPutNonBlocking(REGS_UART, txArray[count]);
            length--;
            count++;
        }
        if(0 == length)
        {
            /* Disable the Transmitter interrupt in UART.*/
            UARTIntDisable(REGS_UART, UART_INT_TX_EMPTY);
        }
     }

    /* Check if the cause is receiver data condition.*/
    if(UART_INTID_RX_DATA == int_id)
    {
        rxData = UARTCharGetNonBlocking(REGS_UART);
        UARTCharPutNonBlocking(REGS_UART, rxData);
    }


    /* Check if the cause is receiver line error condition.*/
    if(UART_INTID_RX_LINE_STAT == int_id)
    {
        while(UARTRxErrorGet(REGS_UART))
        {
            /* Read a byte from the RBR if RBR has data.*/
            UARTCharGetNonBlocking(REGS_UART);
        }
    }

    return;
}

/*
** \brief   This function invokes necessary functions to configure the ARM
**          processor and ARM Interrupt Controller(AINTC) to receive and
**          handle interrupts.
*/


static void SetupInt(void)
{
	int i;
#ifdef _TMS320C6X
	// Initialize the DSP INTC
	IntDSPINTCInit();

	// Enable DSP interrupts globally
	IntGlobalEnable();
#else
    /* Initialize the ARM Interrupt Controller(AINTC). */
    IntAINTCInit();

    for (i = 0; i < NUM_INTERRUPTS; i++)
    {
    	IntUnRegister(i);
    }

    /* Enable IRQ in CPSR.*/     
    IntMasterIRQEnable();

    /* Enable the interrupts in GER of AINTC.*/
    IntGlobalEnable();

    /* Enable the interrupts in HIER of AINTC.*/
    IntIRQEnable();
#endif
}

/*
** \brief  This function confiugres the AINTC to receive UART interrupts.
*/ 
static void ConfigureIntUART(void)
{
#ifdef _TMS320C6X
	IntRegister(C674X_MASK_INT4, UARTIsr);
	IntEventMap(C674X_MASK_INT4, UART_INT);
	IntEnable(C674X_MASK_INT4);
#else
    /* Registers the UARTIsr in the Interrupt Vector Table of AINTC. */
    IntRegister(UART_INT, UARTIsr);

    /* Map the channel number 2 of AINTC to UART2 system interrupt. */
    IntChannelSet(UART_INT, 2);

    IntSystemEnable(UART_INT);
#endif
}

/****************************END OF FILE*************************************/
