#include <p32xxxx.h>
#include <plib.h>					// Peripheral Library
#include <stdio.h>

// Config settings
#pragma config FWDTEN = OFF, FPBDIV = DIV_1
#pragma config OSCIOFNC = ON, POSCMOD = XT, FSOSCEN = OFF, FNOSC = PRI
#pragma config CP = OFF, BWP = OFF, PWP = OFF

// 1. define timing constant
#define LONG_DELAY	5000


#define DESIRED_BAUDRATE    	(9600)      //The desired BaudRate
int got_char = 1;
int char_val = 0;

int tx_cnt = 0;
int rx_cnt = 0;

void WriteString(const char *string); 

#if 1


// 3. the main program
main()
{
    int i = 0;
    char msg_buff[80];


    // disable JTAG port
    DDPCONbits.JTAGEN = 0;

    // 3.2 initialization
    TRISBbits.TRISB8 = 0;  //set B8 as output
    TRISBbits.TRISB9 = 0;  //set B9 as output
    T1CON = 0x8030; // TMR1 on, prescale 1:256 PB

#if 0

    /* from microProto */
    RPINR18bits.U1RXR = 10;  /* Make Pin RP11 U1RX */
    RPOR5bits.RP11R = 3;     /* Make Pin RP10 U1TX */
#endif

    //map uart pins
    RPB10R = 0x02; // set RPB10 as TX
    U2RXR = 0X03; //Set U2RX as ping RPB11

#if 0
    U1RXRbits.U1RXR = 4; //SET RX to RPB2
    RPB3Rbits.RPB3R = 1; //set RPB3 to U1 TX
#endif

	// Configure the device for maximum performance but do not change the PBDIV
	// Given the options, this function will change the flash wait states, RAM
	// wait state and enable prefetch cache but will not change the PBDIV.
	// The PBDIV value is already set via the pragma FPBDIV option above..
//	SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

	mPORTAClearBits(BIT_7); 		// Turn off RA7 on startup.
	mPORTASetPinsDigitalOut(BIT_7);	// Make RA7 as output.


	// Explorer-16 uses UART2 to connect to the PC.
	// This initialization assumes 36MHz Fpb clock. If it changes,
	// you will have to modify baud rate initializer.
    UARTConfigure(UART2, UART_ENABLE_PINS_TX_RX_ONLY); 
    UARTSetFifoMode(UART2, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY); 
    UARTSetLineControl(UART2, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1); 
    UARTSetDataRate(UART2, 3686400L, DESIRED_BAUDRATE); 
    UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX)); 

	// Configure UART2 RX Interrupt
	INTEnable(INT_SOURCE_UART_RX(UART2), INT_ENABLED); 
    INTSetVectorPriority(INT_VECTOR_UART(UART2), INT_PRIORITY_LEVEL_2); 
    INTSetVectorSubPriority(INT_VECTOR_UART(UART2), INT_SUB_PRIORITY_LEVEL_0); 

    // configure for multi-vectored mode 
    INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR); 
 
    // enable interrupts 
    INTEnableInterrupts(); 

    sprintf(msg_buff, "\r\nfooPIC32 %s, %s\r\n", __DATE__, __TIME__);
    WriteString(msg_buff);

    sprintf(msg_buff, "\r\nrx_cnt =  %i\r\n", rx_cnt);
    WriteString(msg_buff);

    sprintf(msg_buff, "tx_cnt =  %i\r\n", tx_cnt);
    WriteString(msg_buff);

    // 3.3 the main loop
    for(;;)
    {
        
        
        if ( i == 0 )
        {
            i = 1;
            PORTBbits.RB8 = 0;
            Nop();
            PORTBbits.RB9 = 1;
            Nop();
        }
        else
        {
            i = 0;
            PORTBbits.RB8 = 1;
            Nop();
            PORTBbits.RB9 = 0;
            Nop();
        }

        // 3.3.2 long pause, hand moving back to the left
        TMR1 = 	0;
        while ( TMR1 < LONG_DELAY)
        {

//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//Make sure RX pin is not an analog pin      !!!
//If it is configure the PCFG equivalent reg !!!
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
            
            if ( got_char )
            {
                sprintf(msg_buff, "got char '%c'\r\n", (char)char_val);
                WriteString(msg_buff);
                got_char = 0;
            }
        }

    } // main loop
} // main



// UART 2 interrupt handler
// it is set at priority level 2
void __ISR(_UART2_VECTOR, ipl2) IntUart2Handler(void)
{
	// Is this an RX interrupt?
	if(INTGetFlag(INT_SOURCE_UART_RX(UART2)))
	{
        ++rx_cnt;

		// Clear the RX interrupt Flag
	    INTClearFlag(INT_SOURCE_UART_RX(UART2));

        char_val = UART2;
        got_char = 1;

		// Echo what we just received.
		//PutCharacter(UARTGetDataByte(UART2));
	}

	// We don't care about TX interrupt
	if ( INTGetFlag(INT_SOURCE_UART_TX(UART2)) )
	{
        ++tx_cnt;
		INTClearFlag(INT_SOURCE_UART_TX(UART2));
	}
}

#endif

#if 0


int main(void)
{ 
 
 #if 0
	#if defined (__32MX220F032D__) || defined (__32MX250F128D__) 
    U2RXRbits.U2RXR = 1; //SET RX to RPB5 
    RPB0Rbits.RPB0R = 2; //SET RPB0R to TX 
	#endif
    U2RXRbits.U2RXR = 1; //SET RX to RPB5 
    RPB0Rbits.RPB0R = 2; //SET RPB0R to TX 
#endif

    RPB10R = 0x02; // set RPB10 as TX
    U2RXR = 0X03; //Set U2RX as ping RPB11


	// Configure the device for maximum performance but do not change the PBDIV
	// Given the options, this function will change the flash wait states, RAM
	// wait state and enable prefetch cache but will not change the PBDIV.
	// The PBDIV value is already set via the pragma FPBDIV option above..
//	SYSTEMConfig(GetSystemClock(), SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);
    SYSTEMConfig(3686400L, SYS_CFG_WAIT_STATES | SYS_CFG_PCACHE);

	mPORTAClearBits(BIT_7); 		// Turn off RA7 on startup.
	mPORTASetPinsDigitalOut(BIT_7);	// Make RA7 as output.


	// Explorer-16 uses UART2 to connect to the PC.
	// This initialization assumes 36MHz Fpb clock. If it changes,
	// you will have to modify baud rate initializer.
    UARTConfigure(UART2, UART_ENABLE_PINS_TX_RX_ONLY); 
    UARTSetFifoMode(UART2, UART_INTERRUPT_ON_TX_NOT_FULL | UART_INTERRUPT_ON_RX_NOT_EMPTY); 
    UARTSetLineControl(UART2, UART_DATA_SIZE_8_BITS | UART_PARITY_NONE | UART_STOP_BITS_1); 
//    UARTSetDataRate(UART2, GetPeripheralClock(), DESIRED_BAUDRATE); 
    UARTSetDataRate(UART2, 3686400L, DESIRED_BAUDRATE); 
    UARTEnable(UART2, UART_ENABLE_FLAGS(UART_PERIPHERAL | UART_RX | UART_TX)); 

	// Configure UART2 RX Interrupt
	INTEnable(INT_SOURCE_UART_RX(UART2), INT_ENABLED); 
    INTSetVectorPriority(INT_VECTOR_UART(UART2), INT_PRIORITY_LEVEL_2); 
    INTSetVectorSubPriority(INT_VECTOR_UART(UART2), INT_SUB_PRIORITY_LEVEL_0); 

    // configure for multi-vectored mode 
    INTConfigureSystem(INT_SYSTEM_CONFIG_MULT_VECTOR); 
 
    // enable interrupts 
    INTEnableInterrupts(); 


   WriteString("*** UART Interrupt-driven Application Example ***\r\n");
   WriteString("*** Type some characters and observe echo and RA7 LED toggle ***\r\n");


	// Let interrupt handler do the work
	while (1);

	return 0;
} 

// UART 2 interrupt handler
// it is set at priority level 2
void __ISR(_UART2_VECTOR, ipl2) IntUart2Handler(void)
{
    // Is this an RX interrupt?
    if(INTGetFlag(INT_SOURCE_UART_RX(UART2)))
    {
        ++rx_cnt;

        // Clear the RX interrupt Flag
        INTClearFlag(INT_SOURCE_UART_RX(UART2));

        char_val = UART2;
        got_char = 1;

        // Echo what we just received.
        //PutCharacter(UARTGetDataByte(UART2));
    }

    // We don't care about TX interrupt
    if ( INTGetFlag(INT_SOURCE_UART_TX(UART2)) )
    {
        ++tx_cnt;
        INTClearFlag(INT_SOURCE_UART_TX(UART2));
    }
}


#endif

// helper functions
void WriteString(const char *string) 
{ 
    while(*string != '\0') 
    { 
        while(!UARTTransmitterIsReady(UART2)) 
            ; 
 
        UARTSendDataByte(UART2, *string); 
 
        string++; 
 
        while(!UARTTransmissionHasCompleted(UART2)) 
            ; 
    } 
} 
void PutCharacter(const char character) 
{ 
        while(!UARTTransmitterIsReady(UART2)) 
            ; 
 
        UARTSendDataByte(UART2, character); 
 
 
        while(!UARTTransmissionHasCompleted(UART2)) 
            ; 
}
