/*******************************************************************************
*                                                                              *
* Copyright 2010 Rheinmetall Canada Inc.                                  	   *
*                                                                              *
* No part of this document may be reproduced, stored in                        *
* a retrieval system, or transmitted, in any form or by any means,             *
* electronic, mechanical, photocopying, recording, or otherwise,               *
* without the prior written permission of Rheinmetall Canada Inc.              *
*                                                                              *
*******************************************************************************/
/*
	Description:
	This is a template file for standard C code file.

*/

/* ************************************************************************** */
/* ¤Revision:
000 20100616 JFM,
	Original version.

### YYYYMMDD Initial, Bug Identification
	Change description.
 */

/* ************************************************************************** */
/* Includes */
#include "define.h"
#include "InternalUart.h"
#include "uart.h"
#include <stdio.h>
//#include "Watchdog.h"
#include "digitalio.h"
#include "NetworkProtocol.h"

/* ************************************************************************** */
/* Local variables */
char acIntUartRxBuff[MAX_INTERNAL_UART_PORT][INTERNAL_UART_BUFFER_DEPTH];		//Rx Buffers
stInternalUartData astInternalUartData[MAX_INTERNAL_UART_PORT];		//port management data

unsigned int LoraData = 0;

void process(void);
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void InternalUartInit(void)
{	
	//Setup port 1 
	
	U1MODEbits.ON = 0;			//disable module
	U1STA = 0;
	U1STAbits.UTXEN = 0;		//disable transmitter
	IPC6bits.U1IP = 7;		//priority 7
	IPC6bits.U1IS = 0;		//sub-priority 3
	U1STAbits.UTXSEL = 0b01;	//interrupt when all characters are transmitted
//	U1STAbits.UTXSEL = 0b01;	//		//JFM 2012-08-27
	IFS0bits.U1TXIF = 0;		//clear interrupt flag
	IEC0bits.U1TXIE = 0;		//enable tx interrupt
	U1STAbits.URXISEL = 0b00;	//interrupt for each character received
	IFS0bits.U1RXIF = 0;
#ifdef POLL_UART1_RX
	IEC0bits.U1RXIE = 0;		//disable rx interrupts
#else
	IEC0bits.U1RXIE = 1;		//enable rx interrupts
#endif
	U1STAbits.URXEN = 1;		//enable receiver
	U1STAbits.UTXEN = 1;		//enable receiver
	U1MODEbits.ON = 0;			//disable module	
	
	//Setup port 2
	//
	U2MODEbits.ON = 0;			//disable module
	U2STA = 0;
	U2STAbits.UTXEN = 0;		//disable transmitter
	IPC8bits.U2IP = 7;		//priority 7
	IPC8bits.U2IS = 0;		//sub-priority 2
	U2STAbits.UTXSEL = 0b01;	//interrupt when all characters are transmitted
	IFS1bits.U2TXIF = 0;		//clear interrupt flag
	IEC1bits.U2TXIE = 0;		//enable tx interrupt
	U2STAbits.URXISEL = 0b00;	//interrupt for each character received
	IFS1bits.U2RXIF = 0;
#ifdef POLL_UART2_RX
	IEC1bits.U2RXIE = 0;		//disable rx interrupts
#else
	IEC1bits.U2RXIE = 1;		//enable rx interrupts
#endif
	U2STAbits.URXEN = 1;		//enable receiver
    U2STAbits.UTXEN = 1;
	U2MODEbits.ON = 0;			//disable module		


	int i;
	for(i = 0; i < MAX_INTERNAL_UART_PORT; i++)
	{
		astInternalUartData[i].pcTxDataPtr = 0;
		astInternalUartData[i].iNbFIFOPendingBytes = 0;
		astInternalUartData[i].iTxDataSize = 0;
		astInternalUartData[i].iTxDataCounter = 0;
		astInternalUartData[i].iIsBusy = 0;
		astInternalUartData[i].iIsOpened = 0;
		astInternalUartData[i].iUartHandle = 0;
	}
}

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
//int SetIntalUartInterrupts(int p_iUartPort, int p_iRxInterrupt,int p_iTxInterrupt)
//{
//	if(p_iUartPort > MAX_INTERNAL_UART_PORT)
//		return UART_INVALID_PORT;
//
//	switch(p_iUartPort)
//	{
//		case INTERNAL_UART_PORT_1:
//		{
//			if(p_iTxInterrupt)
//			{
//				IFS0bits.U1TXIF = 0;		//clear interrupt flag
//				IEC0bits.U1TXIE = 1;		//enable tx interrupt
//			}
//			else
//			{
//				IEC0bits.U1TXIE = 0;		//disable tx interrupt
//				U1STAbits.UTXEN = 1;		//This bit must be set when working without interrupts
//			}
//			if(p_iRxInterrupt)
//			{
//				IFS0bits.U1RXIF = 0;
//				IEC0bits.U1RXIE = 1;		//enable rx interrupt
//			}
//			else
//			{
//				IEC0bits.U1RXIE = 0;		//disable rx interrupt
//			}		
//			break;
//		}	
//		case INTERNAL_UART_PORT_2:
//		{	
//			if(p_iTxInterrupt)
//			{
//				IFS1bits.U2TXIF = 0;		//clear interrupt flag
//				IEC1bits.U2TXIE = 1;		//enable tx interrupt
//			}
//			else
//			{
//				IEC1bits.U2TXIE = 0;		//disable tx interrupt
//				U2STAbits.UTXEN = 1;		//This bit must be set when working without interrupts
//			}
//			if(p_iRxInterrupt)
//			{
//				IFS1bits.U2RXIF = 0;
//				IEC1bits.U2RXIE = 1;		//enable rx interrupt
//			}
//			else
//			{
//				IEC1bits.U2RXIE = 0;		//disable rx interrupt
//			}		
//			break;
//		}	
//		default:
//		{
//			return UART_INVALID_PORT;
//		}	
//	}	
//	return UART_OK;
//}	

//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------	
int OpenInternalPort(int p_iUartPort,int p_iUartHandle,char *p_pcHeadPtr, char *p_pcTailPtr, int p_iBaudRate, int p_iNbStopBits, int p_iParityEnable)
{
	if(p_iUartPort > MAX_INTERNAL_UART_PORT)
		return UART_INVALID_PORT;

	int iBRG = (PERIPHERAL_FREQ/(4*p_iBaudRate)) - 1;
	int iMask = 0;
	
	switch(p_iNbStopBits)
	{
		case INT_UART_ONE_STOP_BIT:
		{
			break;
		}
		case INT_UART_TWO_STOP_BITS:
		{
			iMask |= 0x00000001;
			break;
		}	
	}
	
	astInternalUartData[p_iUartPort].iUartHandle = p_iUartHandle;
	
	switch(p_iParityEnable)
	{
		case INT_UART_NO_PARITY:
		{
			break;
		}
		case INT_UART_EVEN_PARITY:
		{
			iMask |= 0x00000002;
			break;
		}
		case INT_UART_ODD_PARITY:
		{
			iMask |= 0x00000004;
			break;
		}	
	}
	
	switch(p_iUartPort)
	{
		case INTERNAL_UART_PORT_1:
		{
			INTERNAL_UART1_TX_PIN_DIR = PIN_OUTPUT;
			INTERNAL_UART1_TX_PIN = 1;
			U1MODE = iMask;
			U1MODEbits.BRGH = 1;
			U1BRG = iBRG;
			U1MODEbits.ON = 1;			//enable module
			break;
		}
		case INTERNAL_UART_PORT_2:
		{
			INTERNAL_UART2_TX_PIN_DIR = PIN_OUTPUT;
			INTERNAL_UART2_TX_PIN = 1;
			U2MODE = iMask;
			U2MODEbits.BRGH = 1;
			U2BRG = iBRG;
			U2MODEbits.ON = 1;			//enable module
			break;
		}	
	}
	
	astInternalUartData[p_iUartPort].iIsOpened = 1;

	return UART_OK;
}

//-----------------------------------------------------------------------------




//-----------------------------------------------------------------------------
int SendInternalUartData(char *p_pcDataBuf, int p_iDataSize, int p_iUartPort, char *p_pcSourceBufferHead, char *p_pcSourceBufferTail)
{
	int iBufSize;
	int iAvailableBufSize;
	char *p_cDataPointer;
	int i;
	stInternalUartData *p_stUartDataPtr = &astInternalUartData[p_iUartPort];
	
	if(p_stUartDataPtr->iIsOpened == 0)
		return UART_PORT_NOT_OPENED;
	
	//We use a FIFO stack that must be empty before a new transaction can occur
	//if(p_stUartDataPtr->iNbFIFOPendingBytes != 0)	//If FIFO not empty
	if(p_stUartDataPtr->iIsBusy == 1)
		return UART_PORT_BUSY;						//no space is available so flag the port as BUSY...
		
	iBufSize = p_iDataSize;
	if(iBufSize > INTERNAL_UART_BUFFER_DEPTH)
		iBufSize = INTERNAL_UART_BUFFER_DEPTH;
	
	p_cDataPointer = p_stUartDataPtr->pcTxDataPtr = &p_stUartDataPtr->acIntUartTxFIFO[0];
	p_stUartDataPtr->iNbFIFOPendingBytes = iBufSize;
	
	//Fill FIFO with data;
	for(i = 0; i< iBufSize; i++)
	{	
		*p_cDataPointer++ = *p_pcDataBuf++;	
		
		if(p_pcDataBuf > p_pcSourceBufferTail)	//check for wrapping of source data circular buffer.
			p_pcDataBuf = p_pcSourceBufferHead;
	}
	
	p_stUartDataPtr->iIsBusy = 1;	//informative flag to know we are TXing.
	
	//Begin Transmission
	//A TX interrupt will be generated immediately after setting UTXEN
	switch(p_iUartPort)
	{
		case INTERNAL_UART_PORT_1:
		{
			if(IEC0bits.U1TXIE)
			{
				//We consider at this point that the data has been sent for the upper layer.
				DataSentNotification(p_stUartDataPtr->iUartHandle,iBufSize);
				U1STAbits.UTXEN = 1;
			}	
			else
			{
				int i;
				for(i = 0; i < iBufSize; i++)
				{
//					KickWatchdog();
					U1TXREG = *p_stUartDataPtr->pcTxDataPtr++;
					while(U1STAbits.TRMT == 0);
				}
				p_stUartDataPtr->iIsBusy = 0;
				DataSentNotification(p_stUartDataPtr->iUartHandle,iBufSize);
			}	
			break;
		}
		case INTERNAL_UART_PORT_2:
		{
			if(IEC1bits.U2TXIE)
			{
				//We consider at this point that the data has been sent for the upper layer.
				DataSentNotification(p_stUartDataPtr->iUartHandle,iBufSize);
				U2STAbits.UTXEN = 1;
			}	
			else
			{
				int i;
				for(i = 0; i < iBufSize; i++)
				{
//					KickWatchdog();
					U2TXREG = *p_stUartDataPtr->pcTxDataPtr++;
					while(U2STAbits.TRMT == 0);
				}
				p_stUartDataPtr->iIsBusy = 0;
				DataSentNotification(p_stUartDataPtr->iUartHandle,iBufSize);
			}
			
			break;
		}
	}	
	
	return UART_OK;
}

int SendInternalUartDataBlocking(char *p_pcDataBuf, int p_iDataSize, int p_iUartPort)
{
	int i;
	int temp = IEC1;
	switch(p_iUartPort)
	{
		case INTERNAL_UART_PORT_1:
		{
			IEC0bits.U1TXIE = 0;
			for(i = 0; i < p_iDataSize; i++)
			{
				//LORA_MODULE_TX_LED_PIN = ~ LORA_MODULE_TX_LED_PIN;
				U1TXREG = *p_pcDataBuf++;
				while(U1STAbits.TRMT == 0);
			}
			//LORA_MODULE_TX_LED_PIN = LED_OFF;
			IFS0bits.U1TXIF = 0;
			IEC1 = temp;
			break;
		}
		case INTERNAL_UART_PORT_2:
		{
			IEC1bits.U2TXIE = 0;
			for(i = 0; i < p_iDataSize; i++)
			{
				//LORA_MODULE_TX_LED_PIN = ~ LORA_MODULE_TX_LED_PIN;
				U2TXREG = *p_pcDataBuf++;
				while(U2STAbits.TRMT == 0);
			}
		//	LORA_MODULE_TX_LED_PIN = LED_OFF;
			IFS1bits.U2TXIF = 0;
			IEC1 = temp;
			
			
			break;
		}
	}
	return UART_OK;
}

void TickInternalUart(void)
{
#ifdef POLL_UART1_RX

	if(U1STAbits.URXDA == 1)
	{
		if(U1STAbits.OERR)		//Buffer overrun error.  Data is lost.
		{
			U1STAbits.OERR = 0;
		}	
		
		int i = 0;
		while(U1STAbits.URXDA && i < INTERNAL_UART_BUFFER_DEPTH)
		{
			char NewByte = U1RXREG;
	//		DriveProtocolRxData(&NewByte,1);
			acIntUartRxBuff[INTERNAL_UART_PORT_1][i++] = NewByte;			
		}
//		UartReceiveData(UART_1,&acIntUartRxBuff[INTERNAL_UART_PORT_1][0], i);
//		DriveProtocolRxData(&acIntUartRxBuff[INTERNAL_UART_PORT_1][0], i);
	}	
#endif

#ifdef POLL_UART2_RX
	if(U2STAbits.URXDA == 1)
	{
		int i = 0;
		while(U2STAbits.URXDA == 1 && i < INTERNAL_UART_BUFFER_DEPTH)
		{
			char NewByte = U2RXREG;
		//	acIntUartRxBuff[INTERNAL_UART_PORT_2][i++] = NewByte;	
			LORA_MODULE_RX_LED_PIN = ~LORA_MODULE_RX_LED_PIN;
           ProtocolAnalyzeNewData(NewByte);
		   

//                LoraData <<= 8;
//                unsigned int toto = NewByte;
//                toto &= 0x000000FF;
//                LoraData |= toto;
//                
//                if(LoraData == 0xDEADBEEF)
//                {
//                    HEARTBEAT_LED_1_PIN = ~HEARTBEAT_LED_1_PIN;
//                    LORA_ACTIVITY_LED_PIN = ~LORA_ACTIVITY_LED_PIN;
//                    LoraData = 0;
//                }
//            HEARTBEAT_LED_2_PIN = ~HEARTBEAT_LED_2_PIN;
		}
		if(U2STAbits.OERR)		//Buffer overrun error.  Data is lost.
		{
			U2STAbits.OERR = 0;
			printf("Overrun\n");
		}	
//		UartReceiveData(UART_2,&acIntUartRxBuff[INTERNAL_UART_PORT_2][0], i);
	//	CUProtocolRxData(&acIntUartRxBuff[INTERNAL_UART_PORT_2][0], i);
	}
#endif

}		

//-----------------------------------------------------------------------------


//-----------------------------------------------------------------------------
void __ISR(_UART_1_VECTOR, ipl7) InternalUart1AInterrupt(void)      //Internal UART 1 = port série vers le Network
{
	stInternalUartData *p_acUartDataPtr = &astInternalUartData[INTERNAL_UART_PORT_1];
	
	if(IFS0bits.U1TXIF && IEC0bits.U1TXIE)
	{
		IFS0bits.U1TXIF = 0;
		
		//Check if there is still data to send in FIFO
		if(p_acUartDataPtr->iNbFIFOPendingBytes == 0)
		{
			U1STAbits.UTXEN = 0;	//all data sent, stop transmitter
			p_acUartDataPtr->iIsBusy = 0;
			
		}
		else
		{
			do
			{	
				U1TXREG = *p_acUartDataPtr->pcTxDataPtr++;	//send data
				p_acUartDataPtr->iNbFIFOPendingBytes--;
				
			}
			while((U1STAbits.UTXBF == 0) && 	//while there is space in buffer
				  (p_acUartDataPtr->iNbFIFOPendingBytes != 0));	//and data to send

			// HCAM
//			if(p_acUartDataPtr->iNbFIFOPendingBytes == 0)
//			{
//			//	U1STAbits.UTXEN = 0;	//all data sent, stop transmitter
//				p_acUartDataPtr->iIsBusy = 0;
//			}
		}
			
		
	}
	if(IFS0bits.U1RXIF && IEC0bits.U1RXIE)
	{
		char NewByte;
		int i;
		
		IFS0bits.U1RXIF = 0;
		
		if(U1STAbits.OERR)		//Buffer overrun error.  Data is lost.
		{
			U1STAbits.OERR = 0;
			IFS0bits.U1RXIF = 0;
			printf("UART1 OERR\n");
			return;
		}	
		
		i = 0;
		while(U1STAbits.URXDA)
		{
			NewByte = U1RXREG;
			acIntUartRxBuff[INTERNAL_UART_PORT_1][i++] = NewByte;			
		}

		UartReceiveData(p_acUartDataPtr->iUartHandle,&acIntUartRxBuff[INTERNAL_UART_PORT_1][0], i);
		
		
	}	
}
//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
void __ISR(_UART_2_VECTOR, ipl7) InternalUart2Interrupt(void)       //UART2 = port série vers le module LoRa
{
	stInternalUartData *p_acUartDataPtr = &astInternalUartData[INTERNAL_UART_PORT_2];
	if(IFS1bits.U2TXIF && IEC1bits.U2TXIE)
	{
		IFS1bits.U2TXIF = 0;
		//Check if there is still data to send in FIFO
		if(p_acUartDataPtr->iNbFIFOPendingBytes == 0)
		{
			U2STAbits.UTXEN = 0;	//all data sent, stop transmitter
			p_acUartDataPtr->iIsBusy = 0;
			//LORA_MODULE_TX_LED_PIN = LED_OFF;
		}
		else
		{
			do
			{	
				U2TXREG = *p_acUartDataPtr->pcTxDataPtr++;	//send data
				p_acUartDataPtr->iNbFIFOPendingBytes--;
			}
			while((U2STAbits.UTXBF == 0) && 	//while there is space in buffer
				  (p_acUartDataPtr->iNbFIFOPendingBytes != 0));	//and data to send
		}
		
	}
	if(IFS1bits.U2RXIF && IEC1bits.U2RXIE)
	{
		IFS1bits.U2RXIF = 0;
		char NewByte;
		int i;
		
		if(U2STAbits.OERR)		//Buffer overrun error.  Data is lost.
		{
			U2STAbits.OERR = 0;
			IFS1bits.U2RXIF = 0;
			printf("UART2 OERR\n");
			return;
		}	
		i = 0;
		while(U2STAbits.URXDA)
		{
			NewByte = U2RXREG;
			acIntUartRxBuff[INTERNAL_UART_PORT_2][i++] = NewByte;
		}
		UartReceiveData(p_acUartDataPtr->iUartHandle,&acIntUartRxBuff[INTERNAL_UART_PORT_2][0], i);
	
	}	
}	

//-----------------------------------------------------------------------------

//-----------------------------------------------------------------------------
/// Resets UART1 without closing it.  Used when comm crashes.
void ResetUart1(void)
{
	U1MODEbits.ON = 0;			//disable module
	
	U1STAbits.UTXEN = 0;		//disable transmitter
	
	IEC0bits.U1TXIE = 0;		//disable tx interrupt
	IFS0bits.U1TXIF = 0;		//clear interrupt flag
	IEC0bits.U1TXIE = 0;		//enable tx interrupt
	IEC0bits.U1RXIE = 0;		//disable rx interrupts
	IEC0bits.U1RXIE = 0;		//disable rx interrupts
	IFS0bits.U1RXIF = 1;
#ifdef POLL_UART1_RX
	IEC0bits.U1RXIE = 0;		//disable rx interrupts
#else
	IEC0bits.U1RXIE = 1;		//enable rx interrupts
#endif
	U1STAbits.URXEN = 1;		//enable receiver
	
	astInternalUartData[INTERNAL_UART_PORT_1].pcTxDataPtr = &astInternalUartData[INTERNAL_UART_PORT_1].acIntUartTxFIFO[0];
	astInternalUartData[INTERNAL_UART_PORT_1].iTxDataSize = 0;
	astInternalUartData[INTERNAL_UART_PORT_1].iIsBusy = 0;
	
	U1MODEbits.ON = 1;			//enable module
}
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
void ResetUart2(void)
{
		//Setup port 2
	//
	U2MODEbits.ON = 0;			//disable module

	U2STAbits.UTXEN = 0;		//disable transmitter

	IEC1bits.U2TXIE = 0;		//disable tx interrupt
	IFS1bits.U2TXIF = 0;		//clear interrupt flag
	IEC1bits.U2TXIE = 0;		//enable tx interrupt
	IEC1bits.U2RXIE = 0;		//disable rx interrupts
	IFS1bits.U2RXIF = 1;
#ifdef POLL_UART2_RX
	IEC1bits.U2RXIE = 0;		//disable rx interrupts
#else
	IEC1bits.U2RXIE = 1;		//enable rx interrupts
#endif
	U2STAbits.URXEN = 1;		//enable receiver
	
	
	astInternalUartData[INTERNAL_UART_PORT_2].pcTxDataPtr = &astInternalUartData[INTERNAL_UART_PORT_2].acIntUartTxFIFO[0];
	astInternalUartData[INTERNAL_UART_PORT_2].iTxDataSize = 0;
	astInternalUartData[INTERNAL_UART_PORT_2].iIsBusy = 0;
	
	U2MODEbits.ON = 1;			//disable module
	
}	
//-----------------------------------------------------------------------------

void process(void)
{
}	


//EOF

