/**********************************************************************
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 "MasterCtrlInterface.h"
#include "LoraNetworkInterface.h"
#include "LTENetworkInterface.h"
#include "AudioConsoleInterface.h"




static char MyDeviceID = ID_SPRINKLER_DEVICE;

char mFrameData[MAX_MESSAGE_SIZE+10];

ProtocolData_t mAudioConsoleIFProtocolData;
ProtocolData_t mMasterCtrlIFData;


void ProtocolInit(int User)
{
    ProtocolData_t *DataStruct;
    switch(User)
    {
        case NETWORK_PROTOCOL_USER_AUDIO_CONSOLE_IF:
        {
            DataStruct = &mAudioConsoleIFProtocolData;
            break;
        }
        case NETWORK_PROTOCOL_USER_MASTER_CTRL_IF:
        {
            DataStruct = &mMasterCtrlIFData;
            break;
        }
        default:
            return;
            break;
    }
	ResetStateMachine(DataStruct);

}

void StateMachine(unsigned char Data,ProtocolData_t *ProtocolData )
{
	switch(ProtocolData->State)
	{
		case Initialization:	//Reset all pointers and data...
		{
			ProtocolData->DataSize = 0;
			ProtocolData->BufPtr = 0;
			ProtocolData->RxPtr = 0;
			ProtocolData->Command = 0;
			ProtocolData->CRC = 0;
			ProtocolData->State = RxHeader;
			break;
		}
		case RxHeader:	//Wait for data header...
		{
			if(Data == FRAME_HEADER)
			{
				ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
				ProtocolData->State = RxAdd;
				ProtocolData->CRC ^= Data;
			}
			else
			{
				ProtocolData->DataSize = 0;
				ResetStateMachine(ProtocolData);
			}
			
			break;	
		}
		case RxAdd:	//Sender Address.
		{
			ProtocolData->SenderAddress = Data;
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
		 	ProtocolData->State = RxID;
		 	ProtocolData->CRC ^= Data;
			break;
		}
		case RxID:			//Sender ID
		{
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			ProtocolData->State = RxMyID;
			ProtocolData->SenderID = Data;
			ProtocolData->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;
//			}
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			ProtocolData->State = RxMyAddress;
			ProtocolData->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(ProtocolData);
				break;
			}
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			ProtocolData->State = RxFlags;
			ProtocolData->CRC ^= Data;
			break;	
		}
		case RxFlags:
		{
			ProtocolData->Flags = Data;
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			ProtocolData->State = RxCMD;
			ProtocolData->CRC ^= Data;
			break;
		}
		case RxCMD:
		{
			ProtocolData->Command = Data;
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			ProtocolData->State = RxSize1;
			ProtocolData->CRC ^= Data;
			break;	
		}
		case RxSize1:	//Data size MSB
		{
			ProtocolData->DataSize = 0;
			ProtocolData->DataSize = (unsigned int)Data;
			ProtocolData->DataSize <<= 8;
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			
					
			ProtocolData->State = RxSize2;
			ProtocolData->CRC ^= Data;
			break;	
		}
        case RxSize2:	//Data size
		{
			ProtocolData->DataSize |= (unsigned int)Data;
			ProtocolData->DataSize <<= 8;
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			
					
			ProtocolData->State = RxSize3;
			ProtocolData->CRC ^= Data;
			break;	
		}
        case RxSize3:	//Data size
		{
			ProtocolData->DataSize |= (unsigned int)Data;
			ProtocolData->DataSize <<= 8;
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			
					
			ProtocolData->State = RxSize4;
			ProtocolData->CRC ^= Data;
			break;	
		}
		
		case RxSize4:	//Data size LSB
		{
			ProtocolData->DataSize |= (unsigned int)Data;
			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;

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

			ProtocolData->mRxData[ProtocolData->BufPtr++] = Data;
			ProtocolData->DataCtr++;

			if(ProtocolData->DataCtr == ProtocolData->DataSize)
			{
				ProtocolData->State = RxCRC;
			}
			
			break;
		}
		case RxCRC:
		{
			if(Data != ProtocolData->CRC)
			{
				ResetStateMachine(ProtocolData);
//				ProtocolAcknowledge(0,Command,0);
				break;
			}
//			NewMasterMessageReceived(mRxData);
            if(ProtocolData == &mAudioConsoleIFProtocolData)
            {
                AudioConsoleIFExecuteMasterCommand(ProtocolData->SenderID,ProtocolData->Command,ProtocolMsgDataPtr(ProtocolData),ProtocolData->DataSize);
//                ExecuteLoraMasterCommand(ProtocolData->Command,ProtocolMsgDataPtr(ProtocolData),ProtocolData->DataSize);
            }
            else if(ProtocolData == &mMasterCtrlIFData)
            {
//                ExecuteLTEMasterCommand(ProtocolData->SenderID, ProtocolData->Command,ProtocolMsgDataPtr(ProtocolData),ProtocolData->DataSize);
            }
			ResetStateMachine(ProtocolData);
			break;
		}
		default:
		{
			ResetStateMachine(ProtocolData);
			break;
		}		
	}	
}
void ProtocolAnalyzeBuffer(unsigned char *Data, int size, int User)
{
    int i = 0;
    for(i = 0; i < size; i++)
    {
        ProtocolAnalyzeNewData(Data[i],User);
    }
}

void ProtocolAnalyzeNewData(unsigned char Data, int User)
{
    ProtocolData_t *DataStruct;
    switch(User)
    {
        case NETWORK_PROTOCOL_USER_AUDIO_CONSOLE_IF:
        {
            DataStruct = &mAudioConsoleIFProtocolData;
            break;
        }
        case NETWORK_PROTOCOL_USER_MASTER_CTRL_IF:
        {
            DataStruct = &mMasterCtrlIFData;
            break;
        }
        default:
            return;
            break;
    }
//	mRxData[RxPtr] = Data;
//	printf("%X",Data);
	StateMachine(Data, DataStruct);	
}
	
void ResetStateMachine(ProtocolData_t *ProtocolData)
{
    ProtocolData->DataSize = 0;
	ProtocolData->BufPtr = 0;
	ProtocolData->RxPtr = 0;
	ProtocolData->Command = 0;
	ProtocolData->CRC = 0;
	ProtocolData->State = RxHeader;
	ProtocolData->DataCtr = 0;
	ProtocolData->Flags = 0;
	ProtocolData->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 &mFrameData[FRAME_HEADER_INDEX];
    }
    
    
    
  	mFrameData[FRAME_HEADER_INDEX] = FRAME_HEADER;	//header
	mFrameData[FRAME_SENDER_ADDRESS_INDEX] = MY_DEVICE_ADDRESS;		//My Address
    mFrameData[FRAME_SENDER_DEVICE_ID_INDEX] = SenderDevice;	//My ID
	mFrameData[FRAME_DEST_DEVICE_ID_INDEX] = DestDevice;			//Destination ID
	mFrameData[FRAME_DEST_ADDRESS_INDEX] = DestAddress ;//Address;				//Destination Address
	mFrameData[FRAME_FLAGS_INDEX] = Flags;				//Flags
	mFrameData[FRAME_COMMAND_INDEX] = Cmd;			//Command to send
    mFrameData[FRAME_SIZE1_INDEX] = (unsigned char)((Size >> 24) & 0xFF);
    mFrameData[FRAME_SIZE2_INDEX] = (unsigned char)((Size >> 16) & 0xFF);
    mFrameData[FRAME_SIZE3_INDEX] = (unsigned char)((Size >> 8) & 0xFF);
    mFrameData[FRAME_SIZE4_INDEX] = (unsigned char)(Size & 0xFF);
	memcpy((void*)&mFrameData[FRAME_DATA_INDEX],(void*)Data,Size);			//Cmd data
	mFrameData[Size+FRAME_DATA_INDEX] = ProtocolCalcCrc(mFrameData,Size + FRAME_DATA_INDEX);		// CRC
    
    *FrameSize = Size + FRAME_INDEX_NBR;

    return &mFrameData[FRAME_HEADER_INDEX];
	
}

unsigned char *ProtocolMsgDataPtr(ProtocolData_t *ProtocolData)
{
    return &ProtocolData->mRxData[FRAME_DATA_INDEX];
}