/**********************************************************************
Project:    Automatic cat feeder
Date:       march 19 2006
Author:     Jean-Fran�ois Martel
Target:     PIC 18F252
Compiler:   Microchip mcc18
Filename:	Protocol.c

File description:	Communication protocol implementation.


jean-francois.martel@polymtl.ca
**********************************************************************/
#include "define.h"
#include "NetworkProtocol.h"
#include "Uart.h"
#include <string.h>
#include "ProtocolDefs.h"
#include "MasterCtrlInterface.h"
#include "LoraNetworkInterface.h"




unsigned char mRxData[MAX_MESSAGE_SIZE+10], mTxData[MAX_MESSAGE_SIZE+10];
unsigned int DataSize = 0;
unsigned int DataCtr = 0;
unsigned int BufPtr = 0;
unsigned char RxPtr = 0;
unsigned char Command = 0;
unsigned char State = RxHeader;
unsigned char CRC = 0;
unsigned char SenderID = 0;
unsigned char SenderAddress = 0;
unsigned char Flags = 0;
unsigned char IsUpdating = 0;
unsigned char *BmpDataPtr = 0;

static char MyDeviceID = ID_SPRINKLER_DEVICE;

void ProtocolInit(void)
{
	ResetStateMachine();

}

void StateMachine(unsigned char Data)
{
	switch(State)
	{
		case Initialization:	//Reset all pointers and data...
		{
			DataSize = 0;
			BufPtr = 0;
			RxPtr = 0;
			Command = 0;
			CRC = 0;
			State = RxHeader;
			break;
		}
		case RxHeader:	//Wait for data header...
		{
			if(Data == FRAME_HEADER)
			{
				mRxData[BufPtr++] = Data;
				State = RxAdd;
				CRC ^= Data;
			}
			else
			{
				DataSize = 0;
				ResetStateMachine();
			}
			
			break;	
		}
		case RxAdd:	//Sender Address.
		{
			SenderAddress = Data;
			mRxData[BufPtr++] = Data;
		 	State = RxID;
		 	CRC ^= Data;
			break;
		}
		case RxID:			//Sender ID
		{
			mRxData[BufPtr++] = Data;
			State = RxMyID;
			SenderID = Data;
			CRC ^= Data;
			break;
		}
		case RxMyID:
		{
//			if(Data != MyDeviceID && Data != BROADCAST_VALUE)	//Message is not for this type of device and it's not a broadcast
//			{
//				ResetStateMachine();
//				break;
//			}
			mRxData[BufPtr++] = Data;
			State = RxMyAddress;
			CRC ^= Data;
			break;
		}
		case RxMyAddress:
		{
			if(Data != MY_DEVICE_ADDRESS && Data != BROADCAST_VALUE)	//Message is not for this device address and it's not a broadcast
			{
				ResetStateMachine();
				break;
			}
			mRxData[BufPtr++] = Data;
			State = RxFlags;
			CRC ^= Data;
			break;	
		}
		case RxFlags:
		{
			Flags = Data;
			mRxData[BufPtr++] = Data;
			State = RxCMD;
			CRC ^= Data;
			break;
		}
		case RxCMD:
		{
			Command = Data;
			mRxData[BufPtr++] = Data;
			State = RxSize1;
			CRC ^= Data;
			break;	
		}
		case RxSize1:	//Data size MSB
		{
			DataSize = 0;
			DataSize = (unsigned int)Data;
			DataSize <<= 8;
			mRxData[BufPtr++] = Data;
			
					
			State = RxSize2;
			CRC ^= Data;
			break;	
		}
        case RxSize2:	//Data size
		{
			DataSize |= (unsigned int)Data;
			DataSize <<= 8;
			mRxData[BufPtr++] = Data;
			
					
			State = RxSize3;
			CRC ^= Data;
			break;	
		}
        case RxSize3:	//Data size
		{
			DataSize |= (unsigned int)Data;
			DataSize <<= 8;
			mRxData[BufPtr++] = Data;
			
					
			State = RxSize4;
			CRC ^= Data;
			break;	
		}
		
		case RxSize4:	//Data size LSB
		{
			DataSize |= (unsigned int)Data;
			mRxData[BufPtr++] = Data;

			if(DataSize > MAX_MESSAGE_SIZE)
				ResetStateMachine();
			
			if(DataSize == 0)
				State = RxCRC;
			else
				State = RxData;
			
			CRC ^= Data;
			break;	
		}
		case RxData:
		{
			CRC ^= Data;

			mRxData[BufPtr++] = Data;
			DataCtr++;

			if(DataCtr == DataSize)
			{
				State = RxCRC;
			}
			
			break;
		}
		case RxCRC:
		{
			if(Data != CRC)
			{
				ResetStateMachine();
//				ProtocolAcknowledge(0,Command,0);
				break;
			}
//			NewMasterMessageReceived(mRxData);
            ExecuteMasterCommand(Command,ProtocolMsgDataPtr());
			ResetStateMachine();
			break;
		}
		default:
		{
			ResetStateMachine();
			break;
		}		
	}	
}

void ProtocolAnalyzeNewData(unsigned char Data)
{
//	mRxData[RxPtr] = Data;
//	printf("%X",Data);
	StateMachine(Data);	
}
	
void ResetStateMachine(void)
{
	DataSize = 0;
	BufPtr = 0;
	RxPtr = 0;
	Command = 0;
	CRC = 0;
	State = RxHeader;
	DataCtr = 0;
	Flags = 0;
	SenderAddress = 0;
}

void ProtocolExecCmd(void)
{
	switch(Command)
	{
		case RX_GET_STATUS:
		{
			unsigned char StatusByte =0;
//			memcpy(&StatusByte, &IRRemoteStatus, sizeof(IRRemoteStatus));
//			ProtocolSendCmd(TX_DEADBOLT_STATUS,&StatusByte,sizeof(StatusByte),1,0);

			break;
		}
	}
}

void ProtocolAcknowledge(unsigned char Answer,unsigned char Cmd, unsigned char Data)
{
	unsigned char data[2];
	if(Answer == 1)
	{
		data[0] = PROTOCOL_ACK;		//CMD 
	}
	else
	{
		data[0] = PROTOCOL_NAK;		//CMD
	}
	data[1] = Cmd;

//	ProtocolSendCmd(TX_NETWORK_ACK,&data[0],2,1,0);
}



unsigned char ProtocolCalcCrc(unsigned char* Buffer,unsigned char size)
{
	unsigned char CRC = 0;
	unsigned char i;
	for(i = 0; i < size; i++)
		CRC ^= Buffer[i];

	return CRC;
}

unsigned char ProtocolIsReceiving(void)
{
	if(State == RxHeader)
		return 0;	// Idle...
	else
		return 1;	//receiving from serial port

}



unsigned char* ProtocolGetFrame(unsigned char DestDevice,unsigned char DestAddress, unsigned char SenderDevice, unsigned char Cmd, unsigned char *Data,unsigned int Size,unsigned char Flags, int *FrameSize)
{
    if(Size > MAX_MESSAGE_SIZE)
    {
        *FrameSize = 0;
        return &mTxData[FRAME_HEADER_INDEX];
    }
    
  	mTxData[FRAME_HEADER_INDEX] = FRAME_HEADER;	//header
	mTxData[FRAME_SENDER_ADDRESS_INDEX] = MY_DEVICE_ADDRESS;		//My Address
    mTxData[FRAME_SENDER_DEVICE_ID_INDEX] = SenderDevice;	//My ID
	mTxData[FRAME_DEST_DEVICE_ID_INDEX] = DestDevice;			//Destination ID
	mTxData[FRAME_DEST_ADDRESS_INDEX] = DestAddress ;//Address;				//Destination Address
	mTxData[FRAME_FLAGS_INDEX] = Flags;				//Flags
	mTxData[FRAME_COMMAND_INDEX] = Cmd;			//Command to send
    mTxData[FRAME_SIZE1_INDEX] = (unsigned char)((Size >> 24) & 0xFF);
    mTxData[FRAME_SIZE2_INDEX] = (unsigned char)((Size >> 16) & 0xFF);
    mTxData[FRAME_SIZE3_INDEX] = (unsigned char)((Size >> 8) & 0xFF);
    mTxData[FRAME_SIZE4_INDEX] = (unsigned char)(Size & 0xFF);
	memcpy((void*)&mTxData[FRAME_DATA_INDEX],(void*)Data,Size);			//Cmd data
	mTxData[Size+FRAME_DATA_INDEX] = ProtocolCalcCrc(mTxData,Size + FRAME_DATA_INDEX);		// CRC
    
    *FrameSize = Size + FRAME_INDEX_NBR;

    return &mTxData[FRAME_HEADER_INDEX];
	
}

unsigned char *ProtocolMsgDataPtr()
{
    return &mRxData[FRAME_DATA_INDEX];
}