#include <stdio.h>
#include "xc.h"
#include "UART.h"
#include "config.h"

#include "../CommonCode/byte_buffer.h"
#include "../CommonCode/crit_section.h"

/* note: buff size must be power of 2 */
#define RX_BUFF_SIZE    128

static ByteBuffer rxBuff;
static unsigned char rxBuffData[RX_BUFF_SIZE];
static int rxOverFlowFlag;


#ifdef DEBUG


//#ifndef UART_H
//#define	UART_H
//#define BRATE1 259    //38400 Baud (BRGH = 1)  w/39960375 HZ clock Actual, Baud rate is 38423
//#define BRATE 86    //115200 Baud (BRGH = 1)   w/39960375 HZ clock, Actual Baud rate is 114829
//#define U_ENABLE_H 0x8808  //enable the UART Peripheral with BRGH = 1
//#define U_ENABLE_L 0x8008  //enable the UART Peripheral with BRGH = 1;
//#define U_NOFLOWCONTROL 0x0000
//#define U_TX  0x0400  //Enable transmission
//
//
//#define CTS1 _RD14
//#define RTS1 _LATD15
//#define TRTS1 TRISDbits.TRISD15
//
//#define CTS2 _RF12
//#define RTS2 _LATF13
//#define TRTS2 TRISFbits.TRISF13


void InitU1(void)
{
    U1BRG = BRATE;
    U1MODE = U_ENABLE_H | U_NOFLOWCONTROL;  //Enable in high speed mode without flow control
    U1STA = U_TX;
    TRTS1 = 0;  // make RTS output
    RTS1 = 1;  //set TRS default status
    _U1RXIF = 0; //Clear Interrupt
    _U1RXIE = 1;  //Enable Interrupt
    RTS1 = 0;  //Accept characters.
}  //InitU1


void InitU2(void)
{
    /* init buffers */
    rxBuff.data = rxBuffData;
    rxBuff.head = 0;
    rxBuff.tail = 0;
    rxBuff.ptr_mask = (RX_BUFF_SIZE - 1);
        
    /* init flag overflow flag */
    rxOverFlowFlag = 0;

    U2BRG = BRATE;
    U2MODE = U_ENABLE_H | U_NOFLOWCONTROL;  //Enable in high speed mode without flow control
    U2STA = U_TX;
    TRTS2 = 0;  // make RTS output
    RTS2 = 1;  //set TRS default status
    _U2RXIP = 6; //Set higher than DMA0
    _U2RXIF = 0; //Clear Interrupt
    _U2RXIE = 1;  //Enable Interrupt
    RTS2 = 0;  //Accept characters.
}  //InitU2

int putU1( int c)
{
    while(U1STAbits.UTXBF);  //This needs a timeout.
    U1TXREG = c;
    return c;
}  //putU1

void putsU1(char *s)
{
    while(*s)
        putU1(*s++);  // No protection for non null-terminated arguments.
}

char getU1(void) {
    RTS1 = 0;
    while (!U1STAbits.URXDA);
    RTS1 = 1;
    return U1RXREG;
} //getU1

/***************************************************************************/
/*                 deprecate old U2 access functions below                 */ 
/***************************************************************************/

int putU2( int c)
{
    //while (CTS);
    while(U2STAbits.UTXBF);  //This needs a timeout.
    U2TXREG = c;
    return c;
}  //putU2

void putsU2(char *s)
{
    while(*s)
        putU2(*s++);  // No protection for non null-terminated arguments.
}

char getU2(void) {
    RTS2 = 0;
    while (!U2STAbits.URXDA);
    RTS2 = 1;
    return U2RXREG;
} //getU2

/***************************************************************************/
/*                 deprecate old U2 access functions above                 */ 
/***************************************************************************/

int u2GetByte(unsigned char* b)
{
    int stat;

    /* try to get a byte from the buffer */
    EnterCriticalSection();
    stat = bufGet(b, &rxBuff);
    ExitCriticalSection();

    return stat;
}

int u2PutByte(unsigned char b)
{
    /* if there is room put in the next byte */
    if ( !U2STAbits.UTXBF )
    {
        U2TXREG = b; 
        return 1;
    }
    
    return 0;
}

int u2PutString(char* buff)
{
    int i = 0;
    
    while ( buff[i] != '\0' )
    {
        if ( u2PutByte((unsigned char)buff[i]) )
        {
            ++i;
        }
    }

    return 0;
}

int u2GetRxOverFlow()
{
    return rxOverFlowFlag;
}

void u2ClrRxOverFlow()
{
    rxOverFlowFlag = 0;
}

void __attribute__((__interrupt__, auto_psv)) _U2RXInterrupt(void)
{
    __asm__ volatile ("push CORCON");

    /* note: the standard buffer functions are not used here 
    as calling an external function from and interrupt service 
    routine increases interrupt overhead */
    /* grab all the bytes from the buffer */
    while ( U2STAbits.URXDA )
    {
        /* if the buffer is not full, put in the byte */
        if ( ((rxBuff.head + 1) & rxBuff.ptr_mask) == rxBuff.tail )
        {
            /* you need to get the byte out buffer or you will hang! */
            rxOverFlowFlag = U2RXREG;

            /* set overflow flag and bail */
            rxOverFlowFlag = 1;
        }
        else
        {
            /* if there is room in the buffer put the byte in it */
            rxBuff.data[rxBuff.head] = (unsigned char)U2RXREG;
            rxBuff.head = (rxBuff.head + 1) & rxBuff.ptr_mask;
        }
    }

    /* clear the interrupt and return */
    _U2RXIF = 0;

    __asm__ volatile ("pop CORCON");
}

#endif

