/******************************************************************************/
//
//							 Software License Agreement
//
// The software supplied herewith by Microchip Technology Incorporated 
// (the “Company”) for its PICmicro® Microcontroller is intended and 
// supplied to you, the Company’s customer, for use solely and 
// exclusively on Microchip PICmicro Microcontroller products. The 
// software is owned by the Company and/or its supplier, and is 
// protected under applicable copyright laws. All rights are reserved. 
//  Any use in violation of the foregoing restrictions may subject the 
// user to criminal sanctions under applicable laws, as well as to 
// civil liability for the breach of the terms and conditions of this 
// license.
//
// THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES, 
// WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED 
// TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
// PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT, 
// IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR 
// CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
//
/*****************************************************************************/
//	File:		RTDM.c
//
// This program along with MPLAB DMCI ( MPLAB 8.10 or higher) create an alternative link 
//between Host PC and target device for debugging applications in real-time. 
//It is required to include the RTDM.C file and RTDM.h into the application project 
//in order to send/receive data through the UART to/from the host PC running under 
//MPLAB (release 8.10 or higher) DMCI environment. 
// NOTE:DMCI included in MPLAB 8.10 or higher is ready and enabled to support data exchange 
//between the host PC and target device. Previous versions of DMCI do not support this feature. 
// NOTE: RTDM is currently supported by PIC24H, dsPIC30F and dsPIC33F processors
//
//
//	Written By:		M.Ellis, D. Torres,
//				Microchip Technology Inc
//						
// 
// The following files should be included in the MPLAB project:
//
//		RTDM.c			-- RTDM source code file
//		RTDM.h			-- RTDM header file
//		RTDMUSER.h		-- RTDM user definitions file
//		libpXXXX-coff.a		-- Your dsPIC/PIC24 Peripheral Library		
//		pXXXXXXX.gld		-- your dsPIC/PIC24 Linker script file
//				
//
/*****************************************************************************/
//
// Revision History
//
// 4/7/08  -- First Version Release
/****************************************************************************/
//
// Revision History
//
// 4/12/10  -- Added support for dsPIC33E and PIC24E (supports UART3 and UART4)
/****************************************************************************/

#include "RTDM.h"

/*+++++++++++++++++++++++++++++++ RTDM Variables ++++++++++++++++++++++++++++++++++++++++*/
/* Received data is stored in array RTDMRxBuffer  */
unsigned char RTDMRxBuffer[RTDM_RXBUFFERSIZE];
unsigned char * RTDMRxBufferLoLimit = RTDMRxBuffer;
unsigned char * RTDMRxBufferHiLimit = RTDMRxBuffer + RTDM_RXBUFFERSIZE - 1;
unsigned char * RTDMRxBufferIndex = RTDMRxBuffer;
unsigned char * RTDMRxBufferStartMsgPointer;
unsigned char * RTDMRxBufferEndMsgPointer;

/* Data to be transmitted using UART communication module */
const unsigned char RTDMTxdata[] = {'R','T','D','M','\0'};
const unsigned char RTDMSanityCheckOK[] = {'+','$','R','T','D','M','#',0x1B,0x86,'\0'}; 
const unsigned char RTDMWriteMemoryOK[] = {'+','$','O','K','#',0x4C,0x08,'\0'};
const unsigned char RTDMErrorIllegalFunction[] = {'-','$','E',0x01,'#',0xD3,0x6A,'\0'};
unsigned char RTDMErrorFrame[] = {'-','$','E',0,'#',0,0,'\0'};

/* Temp variables used to calculate the CRC16*/
unsigned int RTDMcrcTemp,RTDMcrcTempH,RTDMcrcTempL;

/*Structure enclosing the RTDM flags*/
struct {
			unsigned MessageReceived  :		1;
			unsigned TransmitNow	  :		1;
			unsigned unused :		14;     
		}	RTDMFlags; 


/* UART Configuration data */
/* Holds the value of uart config reg */
unsigned int RTDM_UART_MODE_VALUE;
/* Holds the information regarding uart	TX & RX interrupt modes */    	
unsigned int RTDM_UART_STA_VALUE; 

#if (RTDM_UART == 1)
/******************************************************************************
* Function:     RTDM_Start()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code initilizes the UART to be used to
*			exchange data wiht the host PC
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#if defined (RTDM_UART_V2)
int RTDM_Start()
{

	/********************** UART CONFIGURATIION ***************************/
	/* Turn off UART1 module */	
	CloseUART1();
	/* Configure UART2 receive and transmit interrupt */
	ConfigIntUART1(UART_RX_INT_EN & (UART_RX_INT_PR0+RTDM_UART_PRIORITY) & UART_TX_INT_DIS & UART_TX_INT_PR2);
	/* Configure UART1 module to transmit 8 bit data with one stopbit.  */ 
	RTDM_UART_MODE_VALUE = UART_EN & UART_IDLE_CON & UART_IrDA_DISABLE &
				UART_MODE_FLOW & UART_UEN_00 & UART_DIS_WAKE & 
				UART_DIS_LOOPBACK & UART_DIS_ABAUD & UART_UXRX_IDLE_ONE & 
				UART_BRGH_SIXTEEN & UART_NO_PAR_8BIT & UART_1STOPBIT;



	
	RTDM_UART_STA_VALUE  = UART_INT_TX_BUF_EMPTY  & UART_IrDA_POL_INV_ZERO &                  
	            UART_SYNC_BREAK_DISABLED & UART_TX_ENABLE & UART_INT_RX_CHAR & 
	            UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;
	
	
	OpenUART1(RTDM_UART_MODE_VALUE, RTDM_UART_STA_VALUE, RTDM_BRG);
	
	/************* RTDM Flags Configuration & Initial Values *****************/
	RTDMFlags.MessageReceived = 0;
	RTDMFlags.MessageReceived = 0;
	RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	RTDMRxBufferStartMsgPointer = 	RTDMRxBufferLoLimit;		
	RTDMRxBufferEndMsgPointer = RTDMRxBufferLoLimit;

    return 0;
}
#elif defined (RTDM_UART_V1)
int RTDM_Start()
{

	/********************** UART CONFIGURATIION ***************************/
	/* Turn off UART1 module */	
	CloseUART1();
	/* Configure UART2 receive and transmit interrupt */
	ConfigIntUART1(UART_RX_INT_EN & (UART_RX_INT_PR0+RTDM_UART_PRIORITY) & UART_TX_INT_DIS & UART_TX_INT_PR2);
	/* Configure UART1 module to transmit 8 bit data with one stopbit.  */ 
	RTDM_UART_MODE_VALUE = UART_EN & UART_IDLE_CON & 
                         UART_DIS_WAKE & UART_DIS_LOOPBACK & 
                         UART_DIS_ABAUD & UART_NO_PAR_8BIT & 
                         UART_1STOPBIT;
	
	RTDM_UART_STA_VALUE  = UART_INT_TX_BUF_EMPTY & UART_TX_PIN_NORMAL & 
                         UART_TX_ENABLE & UART_INT_RX_CHAR & 
	                       UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;
	
	
	OpenUART1(RTDM_UART_MODE_VALUE, RTDM_UART_STA_VALUE, RTDM_BRG);
	
	/************* RTDM Flags Configuration & Initial Values *****************/
	RTDMFlags.MessageReceived = 0;
	RTDMFlags.MessageReceived = 0;
	RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	RTDMRxBufferStartMsgPointer = 	RTDMRxBufferLoLimit;		
	RTDMRxBufferEndMsgPointer = RTDMRxBufferLoLimit;

    return 0;
}
#endif

/******************************************************************************
* Function:     	CloseRTDM()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code closes the UART used to
*			exchange data wiht the host PC
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int CloseRTDM()
{
	int nRet = 0;
	CloseUART1();
	return nRet;
		
}

/******************************************************************************
* Function:     	RTDM_ProcessMsgs()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code process the message received and then 
*			executes the required task. These tasks are reading an specified memory
*			location, writing an specified memory location, receive a communication
*			link sanity check command, or being asked for the size of the bufffers.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int RTDM_ProcessMsgs()
{
	
	//Local pointer management variables
	unsigned long int * RTDMpu32AddressTemp;
	unsigned char     * RTDMpucWrData;
    unsigned char     * RTDMpucRdData;
    unsigned char     * RTDMpucWrAddr;	
    unsigned short      RTDMNumBytes;
    unsigned char       RTDMPacketBuf[16];
    
	unsigned int        RTDMProcessMsgsTemp1, RTDMProcessMsgsTemp2;
	unsigned int        N;

    if (!RTDMFlags.MessageReceived)
	{
		return -1;
	}


	RTDMcrcTemp = 
		RTDM_CumulativeCrc16
			(RTDMRxBufferStartMsgPointer, 
			(unsigned int)(RTDMRxBufferEndMsgPointer-RTDMRxBufferStartMsgPointer)+1, 
			0xFFFF);
			
	RTDMcrcTempH = (RTDMcrcTemp & 0xFF00)>>8;
	RTDMcrcTempL = RTDMcrcTemp & 0x00FF;
	RTDMProcessMsgsTemp1 = (unsigned int)*((RTDMRxBufferEndMsgPointer)+2);
	RTDMProcessMsgsTemp2 = (unsigned int)*((RTDMRxBufferEndMsgPointer)+1);



	RTDMRxBufferStartMsgPointer +=2;
	if((RTDMProcessMsgsTemp1 == (unsigned)RTDMcrcTempH) && (RTDMProcessMsgsTemp2 == RTDMcrcTempL))
	  {

		switch(*((RTDMRxBufferLoLimit)+1))
		  {
		  case 'm':
			/*************** Extract Address **************/
			//Capture address as 32 bit quantity to match protocol definition. 
			RTDMpu32AddressTemp = ((unsigned long *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to length field.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned long);
			 
			//Init a byte oriented data pointer  
			RTDMpucRdData = (unsigned char *) ((unsigned int) *RTDMpu32AddressTemp);

			/********* Extract Number of Bytes ************/			
			//Capture address as 16 bit quantity to match protocol definition. 
			RTDMNumBytes = *((unsigned short *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to start of data payload.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned short);
			
            //Init the CRC seed for the cumulative checksum calculation. 					
			RTDMcrcTemp = 0xffff;
			
			//Add packet header prefix
			RTDMPacketBuf[0] = '+';
			RTDMPacketBuf[1] = '$';
			//Add null terminator for putsUARTx function...
			RTDMPacketBuf[2] = 0; 
			
			//Calc header prefix checksum piece
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 2, RTDMcrcTemp);	
			//Calc data payload checksum
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMpucRdData, RTDMNumBytes, RTDMcrcTemp);			
			
			//Send packet header. Use string function to save code space... 
			putsUART1((unsigned int *)RTDMPacketBuf);
			while(BusyUART1()); 
			
			//Send data portion of message... 
			while(RTDMNumBytes--)
			 {
				WriteUART1(*RTDMpucRdData++);
				while(BusyUART1()); 
			 }
			
			//Add packet trailer   
		    RTDMPacketBuf[0] = '#';
		    RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 1, RTDMcrcTemp);			
		    
		    //Add checksum bytes to packet
			RTDMPacketBuf[1] = RTDMcrcTemp & 0x00FF;
			RTDMPacketBuf[2] = (RTDMcrcTemp & 0xFF00) >> 8;
			
			//Send packet trailer and checksum. 			
			for (N=0; N < 3; N++)
			{
				WriteUART1(RTDMPacketBuf[N]); 
				while(BusyUART1()); 
			}	
		  break;
		  
		  case 'M':
			{
			/*************** Extract Address **************/						
		    //Capture address as 32 bit quantity to match protocol definition. 
		    RTDMpu32AddressTemp = (unsigned long *) RTDMRxBufferStartMsgPointer;
		    
		    //Increment receive buffer pointer to length field.
		    RTDMRxBufferStartMsgPointer += sizeof(unsigned long);
		    		    
			// Init a byte oriented address pointer for use in incrementing 
			//through the address range properly as we write each byte of data
			//in the range (length) of this write request.   
			RTDMpucWrAddr = (unsigned char *) ((unsigned int) *RTDMpu32AddressTemp);

			/********* Extract Number of Bytes ************/
			//MEllis Capture length as 16 bit quantity to match protocol definition.
			RTDMNumBytes = *((unsigned short *) RTDMRxBufferStartMsgPointer);
			
			//MEllis Increment receive buffer pointer to start of data payload.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned short);
			
			/********** Extract Data ************/
			
			//Init a byte oriented data pointer so that we can increment a byte at at 
			//time for as many bytes as are in the range for this write. 
			RTDMpucWrData = RTDMRxBufferStartMsgPointer;
			
			//*** Write Data in specified RAM location *****			
			//Important to increment through address range using byte oriented address and data
			//pointers. Otherwise, single byte or odd byte ranges do not get written correctly. 
			while(RTDMNumBytes--)
			  {
    			*RTDMpucWrAddr++ = *RTDMpucWrData++;
    		  }
			  			
			//Transmit OK message
			putsUART1((unsigned int *)RTDMWriteMemoryOK);
			/* Wait for  transmission to complete */
			while(BusyUART1()); 
			break;
			}
		  case 's':
			{
			/* Load transmit buffer and transmit the same till null character is encountered */
			//Transmit OK message
			putsUART1((unsigned int *)RTDMSanityCheckOK);
			/* Wait for  transmission to complete */
			while(BusyUART1()); 
		    break;
			}
		  
		  case 'L':
		    RTDMcrcTemp = 0xffff; //Init the CRC seed.
			
			RTDMPacketBuf[0] = '+';
			RTDMPacketBuf[1] = '$';
			//Size of the RTDM Receive buffer.
			RTDMPacketBuf[2] = (sizeof(RTDMRxBuffer) & 0x00FF);
			RTDMPacketBuf[3] = (sizeof(RTDMRxBuffer) & 0xFF00) >> 8;
			//Note: We dod not utilize a transmit buffer since any data memory source is 
			//essentially already buffered. So the transmit limit is now just a way to 
			//limit the total message length that a client make with any single read request.
			RTDMPacketBuf[4] = (RTDM_MAX_XMIT_LEN & 0x00FF);
			RTDMPacketBuf[5] = (RTDM_MAX_XMIT_LEN & 0xFF00) >> 8;
			RTDMPacketBuf[6] = '#';		
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 7, RTDMcrcTemp);			
			RTDMPacketBuf[7] = (RTDMcrcTemp & 0x00FF);
			RTDMPacketBuf[8] = (RTDMcrcTemp & 0xFF00) >> 8;

			//Send completed message which is 9 bytes in length.
			for (N=0; N < 9; N++)
			{
				WriteUART1(RTDMPacketBuf[N]);
				while(BusyUART1()); 
			}	
			break;
		  
		  default:
			// ---> COMMAND SUPPORTED?? IF NOT ERROR HANDLER
			//Transmit ERROR message 1
			putsUART1 ((unsigned int *)RTDMErrorIllegalFunction);
			/* Wait for  transmission to complete */
			while(BusyUART1()); 
			break;
		  }
				   
	  }

	  memset(&RTDMRxBuffer, 0, sizeof(RTDMRxBuffer));
	  
	  RTDMFlags.MessageReceived = 0;
	  RTDMRxBufferIndex             = RTDMRxBufferLoLimit;
	  RTDMRxBufferStartMsgPointer   = RTDMRxBufferLoLimit;		
	  RTDMRxBufferEndMsgPointer     = RTDMRxBufferLoLimit;
	  
	  return 0;
}	

/******************************************************************************
* Function:     	_U1RXInterrupt(void)
*
* Output:		void
*
* Overview:	Here is where the RTDM receives the messages using the UART receiver 
*			interrupt, If polling method is selected in the RTDMUSER.h file then
*			the user application should call the RTDM_ProcessMsgs routine in order 
*			to precess up comming messages. If polling method is disabled then the 
*			RTDM_ProcessMsgs routine is called in the UART received interrupt
*			routine.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#if (RTDM_POLLING == YES)
/* This is UART1 receive ISR Polling RTDM Messages*/ 
void __attribute__((__interrupt__, no_auto_psv)) _U1RXInterrupt(void) 
{
    
    _U1RXIF = 0;
    
	/* Read the receive buffer until at least one or more character can be read */  
    while(DataRdyUART1())
      *(RTDMRxBufferIndex++) = ReadUART1();		

	RTDMRxBufferEndMsgPointer = RTDMRxBufferIndex-3;
	if(RTDMRxBufferIndex > (RTDMRxBufferHiLimit-1))
	  {
	  RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	  RTDMRxBufferEndMsgPointer = RTDMRxBufferHiLimit-1;
	  }
	
	if(*(RTDMRxBufferStartMsgPointer) == '$')
	{
	  if(*(RTDMRxBufferEndMsgPointer) == '#')
	  {
      	RTDMFlags.MessageReceived = 1;
      }
    }  
	else
	{
		RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	}
	
}  

/******************************************************************************
* Function:     	_U1RXInterrupt(void)
*
* Output:		void
*
* Overview:	Here is where the RTDM receives the messages using the UART receiver 
*			interrupt, If polling method is selected in the RTDMUSER.h file then
*			the user application should call the RTDM_ProcessMsgs routine in order 
*			to precess up comming messages. If polling method is disabled then the 
*			RTDM_ProcessMsgs routine is called in the UART received interrupt
*			routine.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#else
/* This is UART1 receive ISR without polling RTDM Messages */ 
void __attribute__((__interrupt__, no_auto_psv)) _U1RXInterrupt(void) 
{
    
    _U1RXIF = 0;
    
	/* Read the receive buffer until at least one or more character can be read */  
    while(DataRdyUART1())
      *(RTDMRxBufferIndex++) = ReadUART1();		

	RTDMRxBufferEndMsgPointer = RTDMRxBufferIndex-3;
	if(RTDMRxBufferIndex > (RTDMRxBufferHiLimit-1))
	  {
	  RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	  RTDMRxBufferEndMsgPointer = RTDMRxBufferHiLimit-1;
	  }
	
	if(*(RTDMRxBufferStartMsgPointer) == '$')
	{
	  if(*(RTDMRxBufferEndMsgPointer) == '#')
	  {
      	RTDMFlags.MessageReceived = 1;
      	RTDM_ProcessMsgs();
      }
    }  
	else
	{
		RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	}
	
}  
#endif

#elif (RTDM_UART == 2)
/******************************************************************************
* Function:    	 RTDM_Start()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code initilizes the UART to be used to
*			exchange data wiht the host PC
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#if defined (RTDM_UART_V2)
int RTDM_Start()
{

	/********************** UART CONFIGURATIION ******************************/
	/* Turn off UART2 module */	
	CloseUART2();
	
	/* Configure UART2 receive and transmit interrupt */
	ConfigIntUART2(UART_RX_INT_EN & (UART_RX_INT_PR0+RTDM_UART_PRIORITY)& UART_TX_INT_DIS & UART_TX_INT_PR2);
	
	/* Configure UART2 module to transmit 8 bit data with one stopbit.  */ 
	RTDM_UART_MODE_VALUE = UART_EN & UART_IDLE_CON & UART_IrDA_DISABLE &
				UART_MODE_FLOW & UART_UEN_00 & UART_DIS_WAKE & 
				UART_DIS_LOOPBACK & UART_DIS_ABAUD & UART_UXRX_IDLE_ONE & 
				UART_BRGH_SIXTEEN & UART_NO_PAR_8BIT & UART_1STOPBIT;



	
	RTDM_UART_STA_VALUE  = UART_INT_TX_BUF_EMPTY  & UART_IrDA_POL_INV_ZERO &                  
	            UART_SYNC_BREAK_DISABLED & UART_TX_ENABLE & UART_INT_RX_CHAR & 
	            UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;
	
	
	OpenUART2(RTDM_UART_MODE_VALUE, RTDM_UART_STA_VALUE, RTDM_BRG);
	
	
	/************* RTDM Flags Configuration & Initial Values *****************/
	RTDMFlags.MessageReceived = 0;
	RTDMFlags.MessageReceived = 0;
	RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	RTDMRxBufferStartMsgPointer = 	RTDMRxBufferLoLimit;		
	RTDMRxBufferEndMsgPointer = RTDMRxBufferLoLimit;

    return 0;
}
	#elif defined (RTDM_UART_V1)
int RTDM_Start()
{

	/********************** UART CONFIGURATIION ******************************/
	/* Turn off UART2 module */	
	CloseUART2();
	
	/* Configure UART2 receive and transmit interrupt */
	ConfigIntUART2(UART_RX_INT_EN & (UART_RX_INT_PR0+RTDM_UART_PRIORITY)& UART_TX_INT_DIS & UART_TX_INT_PR2);
	
	/* Configure UART2 module to transmit 8 bit data with one stopbit.  */ 
	RTDM_UART_MODE_VALUE = UART_EN & UART_IDLE_CON & 
                       UART_DIS_WAKE & UART_DIS_LOOPBACK & 
                       UART_DIS_ABAUD & UART_NO_PAR_8BIT & 
                       UART_1STOPBIT;
	
	RTDM_UART_STA_VALUE  = UART_INT_TX_BUF_EMPTY & UART_TX_PIN_NORMAL & 
                       UART_TX_ENABLE & UART_INT_RX_CHAR & 
                       UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;
	
	
	OpenUART2(RTDM_UART_MODE_VALUE, RTDM_UART_STA_VALUE, RTDM_BRG);
	
	
	/************* RTDM Flags Configuration & Initial Values *****************/
	RTDMFlags.MessageReceived = 0;
	RTDMFlags.MessageReceived = 0;
	RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	RTDMRxBufferStartMsgPointer = 	RTDMRxBufferLoLimit;		
	RTDMRxBufferEndMsgPointer = RTDMRxBufferLoLimit;

    return 0;
}
#endif
/******************************************************************************
* Function:     	CloseRTDM()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code closes the UART used to
*			exchange data wiht the host PC
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int CloseRTDM()
{
	int nRet = 0;
	CloseUART2();	
	return nRet;
}

/******************************************************************************
* Function:     	RTDM_ProcessMsgs()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code process the message received and then 
*			executes the required task. These tasks are reading an specified memory
*			location, writing an specified memory location, receive a communication
*			link sanity check command, or being asked for the size of the bufffers.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int RTDM_ProcessMsgs()
{
	
	//Local pointer management variables
	unsigned long int * RTDMpu32AddressTemp;
	unsigned char     * RTDMpucWrData;
    unsigned char     * RTDMpucRdData;
    unsigned char     * RTDMpucWrAddr;	
    unsigned short      RTDMNumBytes;
    unsigned char       RTDMPacketBuf[16];
    
	unsigned int        RTDMProcessMsgsTemp1, RTDMProcessMsgsTemp2;
	unsigned int        N;

    if (!RTDMFlags.MessageReceived)
	{
		return -1;
	}


	RTDMcrcTemp = 
		RTDM_CumulativeCrc16
		(RTDMRxBufferStartMsgPointer, 
		(unsigned int)(RTDMRxBufferEndMsgPointer-RTDMRxBufferStartMsgPointer)+1, 
		0xFFFF);
		
	RTDMcrcTempH = (RTDMcrcTemp & 0xFF00)>>8;
	RTDMcrcTempL = RTDMcrcTemp & 0x00FF;
	RTDMProcessMsgsTemp1 = (unsigned int)*((RTDMRxBufferEndMsgPointer)+2);
	RTDMProcessMsgsTemp2 = (unsigned int)*((RTDMRxBufferEndMsgPointer)+1);

	RTDMRxBufferStartMsgPointer +=2;
	if((RTDMProcessMsgsTemp1 == (unsigned)RTDMcrcTempH) && (RTDMProcessMsgsTemp2 == RTDMcrcTempL))
	  {

		switch(*((RTDMRxBufferLoLimit)+1))
		  {
		  case 'm':
			/*************** Extract Address **************/
			//Capture address as 32 bit quantity to match protocol definition. 
			RTDMpu32AddressTemp = ((unsigned long *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to length field.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned long);
			 
			//Init a byte oriented data pointer  
			RTDMpucRdData = (unsigned char *) ((unsigned int) *RTDMpu32AddressTemp);

			/********* Extract Number of Bytes ***********/			
			//Capture address as 16 bit quantity to match protocol definition. 
			RTDMNumBytes = *((unsigned short *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to start of data payload.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned short);
			
            //Init the CRC seed for the cumulative checksum calculation. 					
			RTDMcrcTemp = 0xffff;
			
			//Add packet header prefix
			RTDMPacketBuf[0] = '+';
			RTDMPacketBuf[1] = '$';
			//Add null terminator for putsUARTx function...
			RTDMPacketBuf[2] = 0; 
			
			//Calc header prefix checksum piece
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 2, RTDMcrcTemp);	
			//Calc data payload checksum
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMpucRdData, RTDMNumBytes, RTDMcrcTemp);			
			
			//Send packet header. Use string function to save code space... 
			putsUART2 ((unsigned int *)RTDMPacketBuf);
			while(BusyUART2()); 
			
			//Send data portion of message... 
			while(RTDMNumBytes--)
			 {
				WriteUART2(*RTDMpucRdData++);
				while(BusyUART2()); 
			 }
			
			//Add packet trailer   
		    RTDMPacketBuf[0] = '#';
		    RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 1, RTDMcrcTemp);			
		    
		    //Add checksum bytes to packet
			RTDMPacketBuf[1] = RTDMcrcTemp & 0x00FF;
			RTDMPacketBuf[2] = (RTDMcrcTemp & 0xFF00) >> 8;
			
			//Send packet trailer and checksum. 			
			for (N=0; N < 3; N++)
			{
				WriteUART2(RTDMPacketBuf[N]); 
				while(BusyUART2()); 
			}	
		  break;
		  
		  case 'M':
			{
			/*************** Extract Address **************/						
		    //Capture address as 32 bit quantity to match protocol definition. 
		    RTDMpu32AddressTemp = (unsigned long *) RTDMRxBufferStartMsgPointer;
		    
		    //Increment receive buffer pointer to length field.
		    RTDMRxBufferStartMsgPointer += sizeof(unsigned long);
		    		    
			//Init a byte oriented address pointer for use in incrementing 
			//through the address range properly as we write each byte of data
			//in the range (length) of this write request.   
			RTDMpucWrAddr = (unsigned char *) ((unsigned int) *RTDMpu32AddressTemp);

			/********* Extract Number of Bytes ************/
			//Capture length as 16 bit quantity to match protocol definition.
			RTDMNumBytes = *((unsigned short *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to start of data payload.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned short);
			
			/********** Extract Data ************/			
			//Init a byte oriented data pointer so that we can increment a byte at at 
			//time for as many bytes as are in the range for this write. 
			RTDMpucWrData = RTDMRxBufferStartMsgPointer;
			
			//*** Write Data in specified RAM location *****			
			//Important to increment through address range using byte oriented address and data
			//pointers. Otherwise, single byte or odd byte ranges do not get written correctly. 
			while(RTDMNumBytes--)
			  {
    			*RTDMpucWrAddr++ = *RTDMpucWrData++;
    		  }
			  			
			//Transmit OK message
			putsUART2((unsigned int *)RTDMWriteMemoryOK);
			/* Wait for  transmission to complete */
			while(BusyUART2()); 
			break;
			}
		  case 's':
			{
			/* Load transmit buffer and transmit the same till null character is encountered */
			//Transmit OK message
			putsUART2((unsigned int *)RTDMSanityCheckOK);
			/* Wait for  transmission to complete */
			while(BusyUART2()); 
		    break;
			}
		  
		  case 'L':
		    RTDMcrcTemp = 0xffff; //Init the CRC seed.
			
			RTDMPacketBuf[0] = '+';
			RTDMPacketBuf[1] = '$';
			//Size of the RTDM Receive buffer.
			RTDMPacketBuf[2] = (sizeof(RTDMRxBuffer) & 0x00FF);
			RTDMPacketBuf[3] = (sizeof(RTDMRxBuffer) & 0xFF00) >> 8;
			//Note: We dod not utilize a transmit buffer since any data memory source is 
			//essentially already buffered. So the transmit limit is now just a way to 
			//limit the total message length that a client make with any single read request.
			RTDMPacketBuf[4] = (RTDM_MAX_XMIT_LEN & 0x00FF);
			RTDMPacketBuf[5] = (RTDM_MAX_XMIT_LEN & 0xFF00) >> 8;
			RTDMPacketBuf[6] = '#';		
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 7, RTDMcrcTemp);			
			RTDMPacketBuf[7] = (RTDMcrcTemp & 0x00FF);
			RTDMPacketBuf[8] = (RTDMcrcTemp & 0xFF00) >> 8;

			//Send completed message which is 9 bytes in length.
			for (N=0; N < 9; N++)
			{
				WriteUART2(RTDMPacketBuf[N]);
				while(BusyUART2()); 
			}	
			break;

		  default:
			// ---> COMMAND SUPPORTED?? IF NOT ERROR HANDLER
			//Transmit ERROR message 1
			putsUART2 ((unsigned int *)RTDMErrorIllegalFunction);
			/* Wait for  transmission to complete */
			while(BusyUART2()); 
			break;
		  }
				   
	  }

	  memset(&RTDMRxBuffer, 0, sizeof(RTDMRxBuffer));
	  
	  RTDMFlags.MessageReceived = 0;
	  RTDMRxBufferIndex             = RTDMRxBufferLoLimit;
	  RTDMRxBufferStartMsgPointer   = RTDMRxBufferLoLimit;		
	  RTDMRxBufferEndMsgPointer     = RTDMRxBufferLoLimit;
	  
	  return 0;
}	

/******************************************************************************
* Function:     	_U2RXInterrupt(void)
*
* Output:		void
*
* Overview:	Here is where the RTDM receives the messages using the UART receiver 
*			interrupt, If polling method is selected in the RTDMUSER.h file then
*			the user application should call the RTDM_ProcessMsgs routine in order 
*			to precess up comming messages. If polling method is disabled then the 
*			RTDM_ProcessMsgs routine is called in the UART received interrupt
*			routine.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#if (RTDM_POLLING == YES)
/* This is UART2 receive ISR Polling RTDM Messages*/ 
void __attribute__((__interrupt__, no_auto_psv)) _U2RXInterrupt(void) 
{
    
    _U2RXIF = 0;
    
	/* Read the receive buffer until at least one or more character can be read */  
    while(DataRdyUART2())
      *(RTDMRxBufferIndex++) = ReadUART2();		

	RTDMRxBufferEndMsgPointer = RTDMRxBufferIndex-3;
	if(RTDMRxBufferIndex > (RTDMRxBufferHiLimit-1))
	  {
	  RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	  RTDMRxBufferEndMsgPointer = RTDMRxBufferHiLimit-1;
	  }
	
	if(*(RTDMRxBufferStartMsgPointer) == '$')
	{
	  if(*(RTDMRxBufferEndMsgPointer) == '#')
	  {
      	RTDMFlags.MessageReceived = 1;
      }
    }  
	else
	{
		RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	}
	
}  

/******************************************************************************
* Function:     	_U2RXInterrupt(void)
*
* Output:		void
*
* Overview:	Here is where the RTDM receives the messages using the UART receiver 
*			interrupt, If polling method is selected in the RTDMUSER.h file then
*			the user application should call the RTDM_ProcessMsgs routine in order 
*			to precess up comming messages. If polling method is disabled then the 
*			RTDM_ProcessMsgs routine is called in the UART received interrupt
*			routine.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#else
/* This is UART2 receive ISR without polling RTDM Messages */ 
void __attribute__((__interrupt__, no_auto_psv)) _U2RXInterrupt(void) 
{
    
    _U2RXIF = 0;
    
	/* Read the receive buffer until at least one or more character can be read */  
    while(DataRdyUART2())
      *(RTDMRxBufferIndex++) = ReadUART2();		

	RTDMRxBufferEndMsgPointer = RTDMRxBufferIndex-3;
	if(RTDMRxBufferIndex > (RTDMRxBufferHiLimit-1))
	  {
	  RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	  RTDMRxBufferEndMsgPointer = RTDMRxBufferHiLimit-1;
	  }
	
	if(*(RTDMRxBufferStartMsgPointer) == '$')
	{
	  if(*(RTDMRxBufferEndMsgPointer) == '#')
	  {
      	RTDMFlags.MessageReceived = 1;
      	RTDM_ProcessMsgs();
      }
    }  
	else
	{
		RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	}
	
}  
#endif

#elif (RTDM_UART == 3)
	
	#if (defined (RTDM_UART_V2) && (defined(__dsPIC33E__) || defined(__PIC24E__)) )
		
/******************************************************************************
* Function:    	 RTDM_Start()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code initilizes the UART to be used to
*			exchange data wiht the host PC
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int RTDM_Start()
{

	/********************** UART CONFIGURATIION ******************************/
	/* Turn off UART3 module */	
	CloseUART3();
	
	/* Configure UART3 receive and transmit interrupt */
	ConfigIntUART3(UART_RX_INT_EN & (UART_RX_INT_PR0+RTDM_UART_PRIORITY)& UART_TX_INT_DIS & UART_TX_INT_PR2);
	
	/* Configure UART3 module to transmit 8 bit data with one stopbit.  */ 
	RTDM_UART_MODE_VALUE = UART_EN & UART_IDLE_CON & UART_IrDA_DISABLE &
				UART_MODE_FLOW & UART_UEN_00 & UART_DIS_WAKE & 
				UART_DIS_LOOPBACK & UART_DIS_ABAUD & UART_UXRX_IDLE_ONE & 
				UART_BRGH_SIXTEEN & UART_NO_PAR_8BIT & UART_1STOPBIT;



	
	RTDM_UART_STA_VALUE  = UART_INT_TX_BUF_EMPTY  & UART_IrDA_POL_INV_ZERO &                  
	            UART_SYNC_BREAK_DISABLED & UART_TX_ENABLE & UART_INT_RX_CHAR & 
	            UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;
	
	
	OpenUART3(RTDM_UART_MODE_VALUE, RTDM_UART_STA_VALUE, RTDM_BRG);
	
	
	/************* RTDM Flags Configuration & Initial Values *****************/
	RTDMFlags.MessageReceived = 0;
	RTDMFlags.MessageReceived = 0;
	RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	RTDMRxBufferStartMsgPointer = 	RTDMRxBufferLoLimit;		
	RTDMRxBufferEndMsgPointer = RTDMRxBufferLoLimit;

    return 0;
}

/******************************************************************************
* Function:     	CloseRTDM()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code closes the UART used to
*			exchange data wiht the host PC
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int CloseRTDM()
{
	int nRet = 0;
	CloseUART3();	
	return nRet;
}

/******************************************************************************
* Function:     	RTDM_ProcessMsgs()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code process the message received and then 
*			executes the required task. These tasks are reading an specified memory
*			location, writing an specified memory location, receive a communication
*			link sanity check command, or being asked for the size of the bufffers.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int RTDM_ProcessMsgs()
{
	
	//Local pointer management variables
	unsigned long int * RTDMpu32AddressTemp;
	unsigned char     * RTDMpucWrData;
    unsigned char     * RTDMpucRdData;
    unsigned char     * RTDMpucWrAddr;	
    unsigned short      RTDMNumBytes;
    unsigned char       RTDMPacketBuf[16];
    
	unsigned int        RTDMProcessMsgsTemp1, RTDMProcessMsgsTemp2;
	unsigned int        N;

    if (!RTDMFlags.MessageReceived)
	{
		return -1;
	}


	RTDMcrcTemp = 
		RTDM_CumulativeCrc16
		(RTDMRxBufferStartMsgPointer, 
		(unsigned int)(RTDMRxBufferEndMsgPointer-RTDMRxBufferStartMsgPointer)+1, 
		0xFFFF);
		
	RTDMcrcTempH = (RTDMcrcTemp & 0xFF00)>>8;
	RTDMcrcTempL = RTDMcrcTemp & 0x00FF;
	RTDMProcessMsgsTemp1 = (unsigned int)*((RTDMRxBufferEndMsgPointer)+2);
	RTDMProcessMsgsTemp2 = (unsigned int)*((RTDMRxBufferEndMsgPointer)+1);

	RTDMRxBufferStartMsgPointer +=2;
	if((RTDMProcessMsgsTemp1 == (unsigned)RTDMcrcTempH) && (RTDMProcessMsgsTemp2 == RTDMcrcTempL))
	  {

		switch(*((RTDMRxBufferLoLimit)+1))
		  {
		  case 'm':
			/*************** Extract Address **************/
			//Capture address as 32 bit quantity to match protocol definition. 
			RTDMpu32AddressTemp = ((unsigned long *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to length field.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned long);
			 
			//Init a byte oriented data pointer  
			RTDMpucRdData = (unsigned char *) ((unsigned int) *RTDMpu32AddressTemp);

			/********* Extract Number of Bytes ***********/			
			//Capture address as 16 bit quantity to match protocol definition. 
			RTDMNumBytes = *((unsigned short *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to start of data payload.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned short);
			
            //Init the CRC seed for the cumulative checksum calculation. 					
			RTDMcrcTemp = 0xffff;
			
			//Add packet header prefix
			RTDMPacketBuf[0] = '+';
			RTDMPacketBuf[1] = '$';
			//Add null terminator for putsUARTx function...
			RTDMPacketBuf[2] = 0; 
			
			//Calc header prefix checksum piece
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 2, RTDMcrcTemp);	
			//Calc data payload checksum
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMpucRdData, RTDMNumBytes, RTDMcrcTemp);			
			
			//Send packet header. Use string function to save code space... 
			putsUART3 ((unsigned int *)RTDMPacketBuf);
			while(BusyUART3()); 
			
			//Send data portion of message... 
			while(RTDMNumBytes--)
			 {
				WriteUART3(*RTDMpucRdData++);
				while(BusyUART3()); 
			 }
			
			//Add packet trailer   
		    RTDMPacketBuf[0] = '#';
		    RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 1, RTDMcrcTemp);			
		    
		    //Add checksum bytes to packet
			RTDMPacketBuf[1] = RTDMcrcTemp & 0x00FF;
			RTDMPacketBuf[2] = (RTDMcrcTemp & 0xFF00) >> 8;
			
			//Send packet trailer and checksum. 			
			for (N=0; N < 3; N++)
			{
				WriteUART3(RTDMPacketBuf[N]); 
				while(BusyUART3()); 
			}	
		  break;
		  
		  case 'M':
			{
			/*************** Extract Address **************/						
		    //Capture address as 32 bit quantity to match protocol definition. 
		    RTDMpu32AddressTemp = (unsigned long *) RTDMRxBufferStartMsgPointer;
		    
		    //Increment receive buffer pointer to length field.
		    RTDMRxBufferStartMsgPointer += sizeof(unsigned long);
		    		    
			//Init a byte oriented address pointer for use in incrementing 
			//through the address range properly as we write each byte of data
			//in the range (length) of this write request.   
			RTDMpucWrAddr = (unsigned char *) ((unsigned int) *RTDMpu32AddressTemp);

			/********* Extract Number of Bytes ************/
			//Capture length as 16 bit quantity to match protocol definition.
			RTDMNumBytes = *((unsigned short *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to start of data payload.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned short);
			
			/********** Extract Data ************/			
			//Init a byte oriented data pointer so that we can increment a byte at at 
			//time for as many bytes as are in the range for this write. 
			RTDMpucWrData = RTDMRxBufferStartMsgPointer;
			
			//*** Write Data in specified RAM location *****			
			//Important to increment through address range using byte oriented address and data
			//pointers. Otherwise, single byte or odd byte ranges do not get written correctly. 
			while(RTDMNumBytes--)
			  {
    			*RTDMpucWrAddr++ = *RTDMpucWrData++;
    		  }
			  			
			//Transmit OK message
			putsUART3((unsigned int *)RTDMWriteMemoryOK);
			/* Wait for  transmission to complete */
			while(BusyUART3()); 
			break;
			}
		  case 's':
			{
			/* Load transmit buffer and transmit the same till null character is encountered */
			//Transmit OK message
			putsUART3((unsigned int *)RTDMSanityCheckOK);
			/* Wait for  transmission to complete */
			while(BusyUART3()); 
		    break;
			}
		  
		  case 'L':
		    RTDMcrcTemp = 0xffff; //Init the CRC seed.
			
			RTDMPacketBuf[0] = '+';
			RTDMPacketBuf[1] = '$';
			//Size of the RTDM Receive buffer.
			RTDMPacketBuf[2] = (sizeof(RTDMRxBuffer) & 0x00FF);
			RTDMPacketBuf[3] = (sizeof(RTDMRxBuffer) & 0xFF00) >> 8;
			//Note: We dod not utilize a transmit buffer since any data memory source is 
			//essentially already buffered. So the transmit limit is now just a way to 
			//limit the total message length that a client make with any single read request.
			RTDMPacketBuf[4] = (RTDM_MAX_XMIT_LEN & 0x00FF);
			RTDMPacketBuf[5] = (RTDM_MAX_XMIT_LEN & 0xFF00) >> 8;
			RTDMPacketBuf[6] = '#';		
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 7, RTDMcrcTemp);			
			RTDMPacketBuf[7] = (RTDMcrcTemp & 0x00FF);
			RTDMPacketBuf[8] = (RTDMcrcTemp & 0xFF00) >> 8;

			//Send completed message which is 9 bytes in length.
			for (N=0; N < 9; N++)
			{
				WriteUART3(RTDMPacketBuf[N]);
				while(BusyUART3()); 
			}	
			break;

		  default:
			// ---> COMMAND SUPPORTED?? IF NOT ERROR HANDLER
			//Transmit ERROR message 1
			putsUART3 ((unsigned int *)RTDMErrorIllegalFunction);
			/* Wait for  transmission to complete */
			while(BusyUART3()); 
			break;
		  }
				   
	  }

	  memset(&RTDMRxBuffer, 0, sizeof(RTDMRxBuffer));
	  
	  RTDMFlags.MessageReceived = 0;
	  RTDMRxBufferIndex             = RTDMRxBufferLoLimit;
	  RTDMRxBufferStartMsgPointer   = RTDMRxBufferLoLimit;		
	  RTDMRxBufferEndMsgPointer     = RTDMRxBufferLoLimit;
	  
	  return 0;
}	

/******************************************************************************
* Function:     	_U3RXInterrupt(void)
*
* Output:		void
*
* Overview:	Here is where the RTDM receives the messages using the UART receiver 
*			interrupt, If polling method is selected in the RTDMUSER.h file then
*			the user application should call the RTDM_ProcessMsgs routine in order 
*			to precess up comming messages. If polling method is disabled then the 
*			RTDM_ProcessMsgs routine is called in the UART received interrupt
*			routine.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#if (RTDM_POLLING == YES)
/* This is UART3 receive ISR Polling RTDM Messages*/ 
void __attribute__((__interrupt__, no_auto_psv)) _U3RXInterrupt(void) 
{
    
    _U3RXIF = 0;
    
	/* Read the receive buffer until at least one or more character can be read */  
    while(DataRdyUART3())
      *(RTDMRxBufferIndex++) = ReadUART3();		

	RTDMRxBufferEndMsgPointer = RTDMRxBufferIndex-3;
	if(RTDMRxBufferIndex > (RTDMRxBufferHiLimit-1))
	  {
	  RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	  RTDMRxBufferEndMsgPointer = RTDMRxBufferHiLimit-1;
	  }
	
	if(*(RTDMRxBufferStartMsgPointer) == '$')
	{
	  if(*(RTDMRxBufferEndMsgPointer) == '#')
	  {
      	RTDMFlags.MessageReceived = 1;
      }
    }  
	else
	{
		RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	}
	
}  

/******************************************************************************
* Function:     	_U3RXInterrupt(void)
*
* Output:		void
*
* Overview:	Here is where the RTDM receives the messages using the UART receiver 
*			interrupt, If polling method is selected in the RTDMUSER.h file then
*			the user application should call the RTDM_ProcessMsgs routine in order 
*			to precess up comming messages. If polling method is disabled then the 
*			RTDM_ProcessMsgs routine is called in the UART received interrupt
*			routine.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#else
/* This is UART3 receive ISR without polling RTDM Messages */ 
void __attribute__((__interrupt__, no_auto_psv)) _U3RXInterrupt(void) 
{
    
    _U3RXIF = 0;
    
	/* Read the receive buffer until at least one or more character can be read */  
    while(DataRdyUART3())
      *(RTDMRxBufferIndex++) = ReadUART3();		

	RTDMRxBufferEndMsgPointer = RTDMRxBufferIndex-3;
	if(RTDMRxBufferIndex > (RTDMRxBufferHiLimit-1))
	  {
	  RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	  RTDMRxBufferEndMsgPointer = RTDMRxBufferHiLimit-1;
	  }
	
	if(*(RTDMRxBufferStartMsgPointer) == '$')
	{
	  if(*(RTDMRxBufferEndMsgPointer) == '#')
	  {
      	RTDMFlags.MessageReceived = 1;
      	RTDM_ProcessMsgs();
      }
    }  
	else
	{
		RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	}
	
}  
#endif

#else 
	#error UART3 not avaialable on the current device

#endif

#elif (RTDM_UART == 4)
	
	#if (defined (RTDM_UART_V2) && (defined(__dsPIC33E__) || defined(__PIC24E__)) )
		
/******************************************************************************
* Function:    	 RTDM_Start()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code initilizes the UART to be used to
*			exchange data wiht the host PC
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int RTDM_Start()
{

	/********************** UART CONFIGURATIION ******************************/
	/* Turn off UART4 module */	
	CloseUART4();
	
	/* Configure UART4 receive and transmit interrupt */
	ConfigIntUART4(UART_RX_INT_EN & (UART_RX_INT_PR0+RTDM_UART_PRIORITY)& UART_TX_INT_DIS & UART_TX_INT_PR2);
	
	/* Configure UART4 module to transmit 8 bit data with one stopbit.  */ 
	RTDM_UART_MODE_VALUE = UART_EN & UART_IDLE_CON & UART_IrDA_DISABLE &
				UART_MODE_FLOW & UART_UEN_00 & UART_DIS_WAKE & 
				UART_DIS_LOOPBACK & UART_DIS_ABAUD & UART_UXRX_IDLE_ONE & 
				UART_BRGH_SIXTEEN & UART_NO_PAR_8BIT & UART_1STOPBIT;



	
	RTDM_UART_STA_VALUE  = UART_INT_TX_BUF_EMPTY  & UART_IrDA_POL_INV_ZERO &                  
	            UART_SYNC_BREAK_DISABLED & UART_TX_ENABLE & UART_INT_RX_CHAR & 
	            UART_ADR_DETECT_DIS & UART_RX_OVERRUN_CLEAR;
	
	
	OpenUART4(RTDM_UART_MODE_VALUE, RTDM_UART_STA_VALUE, RTDM_BRG);
	
	
	/************* RTDM Flags Configuration & Initial Values *****************/
	RTDMFlags.MessageReceived = 0;
	RTDMFlags.MessageReceived = 0;
	RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	RTDMRxBufferStartMsgPointer = 	RTDMRxBufferLoLimit;		
	RTDMRxBufferEndMsgPointer = RTDMRxBufferLoLimit;

    return 0;
}

/******************************************************************************
* Function:     	CloseRTDM()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code closes the UART used to
*			exchange data wiht the host PC
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int CloseRTDM()
{
	int nRet = 0;
	CloseUART4();	
	return nRet;
}

/******************************************************************************
* Function:     	RTDM_ProcessMsgs()
*
* Output:		return 0 if no errors
*
* Overview:	Here is where the RTDM code process the message received and then 
*			executes the required task. These tasks are reading an specified memory
*			location, writing an specified memory location, receive a communication
*			link sanity check command, or being asked for the size of the bufffers.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
int RTDM_ProcessMsgs()
{
	
	//Local pointer management variables
	unsigned long int * RTDMpu32AddressTemp;
	unsigned char     * RTDMpucWrData;
    unsigned char     * RTDMpucRdData;
    unsigned char     * RTDMpucWrAddr;	
    unsigned short      RTDMNumBytes;
    unsigned char       RTDMPacketBuf[16];
    
	unsigned int        RTDMProcessMsgsTemp1, RTDMProcessMsgsTemp2;
	unsigned int        N;

    if (!RTDMFlags.MessageReceived)
	{
		return -1;
	}


	RTDMcrcTemp = 
		RTDM_CumulativeCrc16
		(RTDMRxBufferStartMsgPointer, 
		(unsigned int)(RTDMRxBufferEndMsgPointer-RTDMRxBufferStartMsgPointer)+1, 
		0xFFFF);
		
	RTDMcrcTempH = (RTDMcrcTemp & 0xFF00)>>8;
	RTDMcrcTempL = RTDMcrcTemp & 0x00FF;
	RTDMProcessMsgsTemp1 = (unsigned int)*((RTDMRxBufferEndMsgPointer)+2);
	RTDMProcessMsgsTemp2 = (unsigned int)*((RTDMRxBufferEndMsgPointer)+1);

	RTDMRxBufferStartMsgPointer +=2;
	if((RTDMProcessMsgsTemp1 == (unsigned)RTDMcrcTempH) && (RTDMProcessMsgsTemp2 == RTDMcrcTempL))
	  {

		switch(*((RTDMRxBufferLoLimit)+1))
		  {
		  case 'm':
			/*************** Extract Address **************/
			//Capture address as 32 bit quantity to match protocol definition. 
			RTDMpu32AddressTemp = ((unsigned long *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to length field.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned long);
			 
			//Init a byte oriented data pointer  
			RTDMpucRdData = (unsigned char *) ((unsigned int) *RTDMpu32AddressTemp);

			/********* Extract Number of Bytes ***********/			
			//Capture address as 16 bit quantity to match protocol definition. 
			RTDMNumBytes = *((unsigned short *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to start of data payload.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned short);
			
            //Init the CRC seed for the cumulative checksum calculation. 					
			RTDMcrcTemp = 0xffff;
			
			//Add packet header prefix
			RTDMPacketBuf[0] = '+';
			RTDMPacketBuf[1] = '$';
			//Add null terminator for putsUARTx function...
			RTDMPacketBuf[2] = 0; 
			
			//Calc header prefix checksum piece
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 2, RTDMcrcTemp);	
			//Calc data payload checksum
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMpucRdData, RTDMNumBytes, RTDMcrcTemp);			
			
			//Send packet header. Use string function to save code space... 
			putsUART4 ((unsigned int *)RTDMPacketBuf);
			while(BusyUART4()); 
			
			//Send data portion of message... 
			while(RTDMNumBytes--)
			 {
				WriteUART4(*RTDMpucRdData++);
				while(BusyUART4()); 
			 }
			
			//Add packet trailer   
		    RTDMPacketBuf[0] = '#';
		    RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 1, RTDMcrcTemp);			
		    
		    //Add checksum bytes to packet
			RTDMPacketBuf[1] = RTDMcrcTemp & 0x00FF;
			RTDMPacketBuf[2] = (RTDMcrcTemp & 0xFF00) >> 8;
			
			//Send packet trailer and checksum. 			
			for (N=0; N < 3; N++)
			{
				WriteUART4(RTDMPacketBuf[N]); 
				while(BusyUART4()); 
			}	
		  break;
		  
		  case 'M':
			{
			/*************** Extract Address **************/						
		    //Capture address as 32 bit quantity to match protocol definition. 
		    RTDMpu32AddressTemp = (unsigned long *) RTDMRxBufferStartMsgPointer;
		    
		    //Increment receive buffer pointer to length field.
		    RTDMRxBufferStartMsgPointer += sizeof(unsigned long);
		    		    
			//Init a byte oriented address pointer for use in incrementing 
			//through the address range properly as we write each byte of data
			//in the range (length) of this write request.   
			RTDMpucWrAddr = (unsigned char *) ((unsigned int) *RTDMpu32AddressTemp);

			/********* Extract Number of Bytes ************/
			//Capture length as 16 bit quantity to match protocol definition.
			RTDMNumBytes = *((unsigned short *) RTDMRxBufferStartMsgPointer);
			
			//Increment receive buffer pointer to start of data payload.
			RTDMRxBufferStartMsgPointer += sizeof(unsigned short);
			
			/********** Extract Data ************/			
			//Init a byte oriented data pointer so that we can increment a byte at at 
			//time for as many bytes as are in the range for this write. 
			RTDMpucWrData = RTDMRxBufferStartMsgPointer;
			
			//*** Write Data in specified RAM location *****			
			//Important to increment through address range using byte oriented address and data
			//pointers. Otherwise, single byte or odd byte ranges do not get written correctly. 
			while(RTDMNumBytes--)
			  {
    			*RTDMpucWrAddr++ = *RTDMpucWrData++;
    		  }
			  			
			//Transmit OK message
			putsUART4((unsigned int *)RTDMWriteMemoryOK);
			/* Wait for  transmission to complete */
			while(BusyUART4()); 
			break;
			}
		  case 's':
			{
			/* Load transmit buffer and transmit the same till null character is encountered */
			//Transmit OK message
			putsUART4((unsigned int *)RTDMSanityCheckOK);
			/* Wait for  transmission to complete */
			while(BusyUART4()); 
		    break;
			}
		  
		  case 'L':
		    RTDMcrcTemp = 0xffff; //Init the CRC seed.
			
			RTDMPacketBuf[0] = '+';
			RTDMPacketBuf[1] = '$';
			//Size of the RTDM Receive buffer.
			RTDMPacketBuf[2] = (sizeof(RTDMRxBuffer) & 0x00FF);
			RTDMPacketBuf[3] = (sizeof(RTDMRxBuffer) & 0xFF00) >> 8;
			//Note: We dod not utilize a transmit buffer since any data memory source is 
			//essentially already buffered. So the transmit limit is now just a way to 
			//limit the total message length that a client make with any single read request.
			RTDMPacketBuf[4] = (RTDM_MAX_XMIT_LEN & 0x00FF);
			RTDMPacketBuf[5] = (RTDM_MAX_XMIT_LEN & 0xFF00) >> 8;
			RTDMPacketBuf[6] = '#';		
			RTDMcrcTemp = RTDM_CumulativeCrc16(RTDMPacketBuf, 7, RTDMcrcTemp);			
			RTDMPacketBuf[7] = (RTDMcrcTemp & 0x00FF);
			RTDMPacketBuf[8] = (RTDMcrcTemp & 0xFF00) >> 8;

			//Send completed message which is 9 bytes in length.
			for (N=0; N < 9; N++)
			{
				WriteUART4(RTDMPacketBuf[N]);
				while(BusyUART4()); 
			}	
			break;

		  default:
			// ---> COMMAND SUPPORTED?? IF NOT ERROR HANDLER
			//Transmit ERROR message 1
			putsUART4 ((unsigned int *)RTDMErrorIllegalFunction);
			/* Wait for  transmission to complete */
			while(BusyUART4()); 
			break;
		  }
				   
	  }

	  memset(&RTDMRxBuffer, 0, sizeof(RTDMRxBuffer));
	  
	  RTDMFlags.MessageReceived = 0;
	  RTDMRxBufferIndex             = RTDMRxBufferLoLimit;
	  RTDMRxBufferStartMsgPointer   = RTDMRxBufferLoLimit;		
	  RTDMRxBufferEndMsgPointer     = RTDMRxBufferLoLimit;
	  
	  return 0;
}	

/******************************************************************************
* Function:     	_U4RXInterrupt(void)
*
* Output:		void
*
* Overview:	Here is where the RTDM receives the messages using the UART receiver 
*			interrupt, If polling method is selected in the RTDMUSER.h file then
*			the user application should call the RTDM_ProcessMsgs routine in order 
*			to precess up comming messages. If polling method is disabled then the 
*			RTDM_ProcessMsgs routine is called in the UART received interrupt
*			routine.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#if (RTDM_POLLING == YES)
/* This is UART4 receive ISR Polling RTDM Messages*/ 
void __attribute__((__interrupt__, no_auto_psv)) _U4RXInterrupt(void) 
{
    
    _U4RXIF = 0;
    
	/* Read the receive buffer until at least one or more character can be read */  
    while(DataRdyUART4())
      *(RTDMRxBufferIndex++) = ReadUART4();		

	RTDMRxBufferEndMsgPointer = RTDMRxBufferIndex-3;
	if(RTDMRxBufferIndex > (RTDMRxBufferHiLimit-1))
	  {
	  RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	  RTDMRxBufferEndMsgPointer = RTDMRxBufferHiLimit-1;
	  }
	
	if(*(RTDMRxBufferStartMsgPointer) == '$')
	{
	  if(*(RTDMRxBufferEndMsgPointer) == '#')
	  {
      	RTDMFlags.MessageReceived = 1;
      }
    }  
	else
	{
		RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	}
	
}  

/******************************************************************************
* Function:     	_U4RXInterrupt(void)
*
* Output:		void
*
* Overview:	Here is where the RTDM receives the messages using the UART receiver 
*			interrupt, If polling method is selected in the RTDMUSER.h file then
*			the user application should call the RTDM_ProcessMsgs routine in order 
*			to precess up comming messages. If polling method is disabled then the 
*			RTDM_ProcessMsgs routine is called in the UART received interrupt
*			routine.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
#else
/* This is UART4 receive ISR without polling RTDM Messages */ 
void __attribute__((__interrupt__, no_auto_psv)) _U4RXInterrupt(void) 
{
    
    _U4RXIF = 0;
    
	/* Read the receive buffer until at least one or more character can be read */  
    while(DataRdyUART4())
      *(RTDMRxBufferIndex++) = ReadUART4();		

	RTDMRxBufferEndMsgPointer = RTDMRxBufferIndex-3;
	if(RTDMRxBufferIndex > (RTDMRxBufferHiLimit-1))
	  {
	  RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	  RTDMRxBufferEndMsgPointer = RTDMRxBufferHiLimit-1;
	  }
	
	if(*(RTDMRxBufferStartMsgPointer) == '$')
	{
	  if(*(RTDMRxBufferEndMsgPointer) == '#')
	  {
      	RTDMFlags.MessageReceived = 1;
      	RTDM_ProcessMsgs();
      }
    }  
	else
	{
		RTDMRxBufferIndex = RTDMRxBufferLoLimit;
	}
	
}  
#endif

#else 
	#error UART4 not avaialable on the current device

#endif

#else
	#error Please define the UART to be used by RTDM in RTDMuserdef.h file
#endif

//Conditionally compile for speed performance or minimum code size.
#if (RTDM_MIN_CODE_SIZE == NO)

//When RTDM_MIN_CODE_SIZE is not defined we employ a table driven crc 
//calculation with pre-calculated polyniomial values to speed-up 
//checksum calculation time. 

const unsigned int crc_16_tab[] = {
  0x0000, 0xc0c1, 0xc181, 0x0140, 0xc301, 0x03c0, 0x0280, 0xc241,
  0xc601, 0x06c0, 0x0780, 0xc741, 0x0500, 0xc5c1, 0xc481, 0x0440,
  0xcc01, 0x0cc0, 0x0d80, 0xcd41, 0x0f00, 0xcfc1, 0xce81, 0x0e40,
  0x0a00, 0xcac1, 0xcb81, 0x0b40, 0xc901, 0x09c0, 0x0880, 0xc841,
  0xd801, 0x18c0, 0x1980, 0xd941, 0x1b00, 0xdbc1, 0xda81, 0x1a40,
  0x1e00, 0xdec1, 0xdf81, 0x1f40, 0xdd01, 0x1dc0, 0x1c80, 0xdc41,
  0x1400, 0xd4c1, 0xd581, 0x1540, 0xd701, 0x17c0, 0x1680, 0xd641,
  0xd201, 0x12c0, 0x1380, 0xd341, 0x1100, 0xd1c1, 0xd081, 0x1040,
  0xf001, 0x30c0, 0x3180, 0xf141, 0x3300, 0xf3c1, 0xf281, 0x3240,
  0x3600, 0xf6c1, 0xf781, 0x3740, 0xf501, 0x35c0, 0x3480, 0xf441,
  0x3c00, 0xfcc1, 0xfd81, 0x3d40, 0xff01, 0x3fc0, 0x3e80, 0xfe41,
  0xfa01, 0x3ac0, 0x3b80, 0xfb41, 0x3900, 0xf9c1, 0xf881, 0x3840,
  0x2800, 0xe8c1, 0xe981, 0x2940, 0xeb01, 0x2bc0, 0x2a80, 0xea41,
  0xee01, 0x2ec0, 0x2f80, 0xef41, 0x2d00, 0xedc1, 0xec81, 0x2c40,
  0xe401, 0x24c0, 0x2580, 0xe541, 0x2700, 0xe7c1, 0xe681, 0x2640,
  0x2200, 0xe2c1, 0xe381, 0x2340, 0xe101, 0x21c0, 0x2080, 0xe041,
  0xa001, 0x60c0, 0x6180, 0xa141, 0x6300, 0xa3c1, 0xa281, 0x6240,
  0x6600, 0xa6c1, 0xa781, 0x6740, 0xa501, 0x65c0, 0x6480, 0xa441,
  0x6c00, 0xacc1, 0xad81, 0x6d40, 0xaf01, 0x6fc0, 0x6e80, 0xae41,
  0xaa01, 0x6ac0, 0x6b80, 0xab41, 0x6900, 0xa9c1, 0xa881, 0x6840,
  0x7800, 0xb8c1, 0xb981, 0x7940, 0xbb01, 0x7bc0, 0x7a80, 0xba41,
  0xbe01, 0x7ec0, 0x7f80, 0xbf41, 0x7d00, 0xbdc1, 0xbc81, 0x7c40,
  0xb401, 0x74c0, 0x7580, 0xb541, 0x7700, 0xb7c1, 0xb681, 0x7640,
  0x7200, 0xb2c1, 0xb381, 0x7340, 0xb101, 0x71c0, 0x7080, 0xb041,
  0x5000, 0x90c1, 0x9181, 0x5140, 0x9301, 0x53c0, 0x5280, 0x9241,
  0x9601, 0x56c0, 0x5780, 0x9741, 0x5500, 0x95c1, 0x9481, 0x5440,
  0x9c01, 0x5cc0, 0x5d80, 0x9d41, 0x5f00, 0x9fc1, 0x9e81, 0x5e40,
  0x5a00, 0x9ac1, 0x9b81, 0x5b40, 0x9901, 0x59c0, 0x5880, 0x9841,
  0x8801, 0x48c0, 0x4980, 0x8941, 0x4b00, 0x8bc1, 0x8a81, 0x4a40,
  0x4e00, 0x8ec1, 0x8f81, 0x4f40, 0x8d01, 0x4dc0, 0x4c80, 0x8c41,
  0x4400, 0x84c1, 0x8581, 0x4540, 0x8701, 0x47c0, 0x4680, 0x8641,
  0x8201, 0x42c0, 0x4380, 0x8341, 0x4100, 0x81c1, 0x8081, 0x4040
};

/******************************************************************************
* Function:     	RTDM_CumulativeCrc16 
				(unsigned char *buf, 
				unsigned int u16Length, 
				unsigned int u16CRC)
*
* Output:		return CRC16
*
* Overview:	This routine calculates the polynomial for the checksum byte using
*			a coefficients table. 
*			This approach has a faster performance but consumes a higher amount of 
*			program memory
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/
unsigned int RTDM_CumulativeCrc16(unsigned char *buf, unsigned int bsize, unsigned int crcSeed)
{
   unsigned char * pData = buf;

   while (bsize--)
    {
   		crcSeed = (unsigned int)(crcSeed >> 8) ^ crc_16_tab[(crcSeed ^ *pData++) & 0xff];
    }		
   
  return crcSeed;

}

#else //This is when the _RTDM_CODE_FOOTPRINT = RTDM_MIN_SIZE



/******************************************************************************
* Function:     	RTDM_CumulativeCrc16 
				(unsigned char *buf, 
				unsigned int u16Length, 
				unsigned int u16CRC)
*
* Output:		return CRC16
*
* Overview:	This routine calculates the polynomial for the checksum byte on the fly
*			every time. Saves code space because no const table is required. 
*			This approach saves code space but yields slower throughput 
*			performance.
*
* Note:		Some processors may have more UART modules, that is why it is required to
*			specify wich UART module is going to be used by RTDM	
*******************************************************************************/

int wcopy;
unsigned int RTDM_CumulativeCrc16 (unsigned char *buf, unsigned int u16Length, unsigned int u16CRC)
{
	unsigned int u16Poly16   = 0xA001; // Bits 15, 13 and 0 
	unsigned int DATA_BITS   = 8;      // Number of data bits 
	unsigned int u16BitIdx;
	unsigned int u16MsgIdx;
	unsigned int u16MsgByte;

    for ( u16MsgIdx = 0; u16MsgIdx < u16Length; u16MsgIdx++)
	{
		asm("mov.w w14,_wcopy");
		u16MsgByte = 0x00FF & *buf++;
		for( u16BitIdx = 0; u16BitIdx < DATA_BITS; u16BitIdx++)
		{
			if ( (u16CRC ^ u16MsgByte) & 0x0001 )
			 {
				 u16CRC = ( u16CRC >> 1 ) ^ u16Poly16;
			 }
			else
			 {
				u16CRC = u16CRC >> 1;
			 }
			
			u16MsgByte >>= 1; // Right shift one to get to next bit 
		}
	}

	return u16CRC;
}

#endif /* End of #ifndef compilation condition. */


