/*############################################################################################*/
/*############################################################################################*/
/**
 * \file    UsbManager.c
 * \author  Thibaut LALUQUE 3D-Ouest
 * \date    20/11/2014
 * \version 1.0
 * \brief 	Source file for USB Uart management (with FTDI).
 * \details All Right Reserved.
 */
/*############################################################################################*/
/*############################################################################################*/


/*############################################################################################*/
/*## INCLUDES ################################################################################*/
/*############################################################################################*/
#include "UsbManager.h"
/*############################################################################################*/
/*## END INCLUDES ############################################################################*/
/*############################################################################################*/


/*############################################################################################*/
/*## LOCAL DEFINES ###########################################################################*/
/*############################################################################################*/

/*############################################################################################*/
/*## END LOCAL DEFINES ######################################################################*/
/*############################################################################################*/


/*############################################################################################*/
/*## LOCAL FONCTIONS DECLARATION #############################################################*/
/*############################################################################################*/

/*############################################################################################*/
/*## END LOCAL FONCTIONS DECLARATION #########################################################*/
/*############################################################################################*/


/*############################################################################################*/
/*## LOCAL VARIABLES #########################################################################*/
/*############################################################################################*/

/*############################################################################################*/
/*## END LOCAL VARIABLES #####################################################################*/
/*############################################################################################*/

/*############################################################################################*/
/*## GLOBAL VARIABLES ########################################################################*/
/*############################################################################################*/
tUsbCtrl	UsbCtrl;
/*############################################################################################*/
/*## END GLOBAL VARIABLES ####################################################################*/
/*############################################################################################*/


/*############################################################################################*/
/*## LOCAL FONCTIONS #########################################################################*/
/*############################################################################################*/

/*############################################################################################*/
/*## END LOCAL FONCTIONS #####################################################################*/
/*############################################################################################*/


/*############################################################################################*/
/*## EXTERNAL FONCTIONS ######################################################################*/
/*############################################################################################*/
void UsbManagerInit (void) {

	UsbCtrl.cmdSize = 0;
	UsbCtrl.cmdSizeRequested = 0;
	UsbCtrl.msRef = 0;
	UsbCtrl.rxState.all = 0;
	UsbCtrl.commandId = 0;

	UsbUartInit();
	UsbUartEnableReceiver();
}

void UsbManager (void) {

	/*=== Manage overflow ===*/

	if(UsbUartCtrl.flags.bits.rxOverrun) {
		UsbUartDisableReceiver();
		UsbUartCtrl.rx.lastIn = 0;
		UsbUartCtrl.rx.lastOut = 0;
		UsbUartCtrl.rx.nbrChar = 0;
		UsbUartCtrl.flags.bits.stringReceived = 0;
		UsbUartCtrl.flags.bits.charReceived = 0;
		UsbUartEnableReceiver();

		UsbCtrl.cmdSize = 0;
		UsbCtrl.cmdSizeRequested = 0;
		UsbCtrl.msRef = 0;
		UsbCtrl.rxState.all = 0;
		UsbCtrl.commandId = 0;
	}

	if(UsbUartCtrl.flags.bits.txOverrun) {
		UsbUartDisableTransmitter();
		UsbUartCtrl.tx.lastIn = 0;
		UsbUartCtrl.tx.lastOut = 0;
		UsbUartCtrl.tx.nbrChar = 0;
		UsbUartCtrl.flags.bits.txOverrun = 0;
	}

	/*=== Manage module error ===*/

	if(UsbUartCtrl.flags.bits.moduleError) {
		UsbUartInit();
		UsbUartCtrl.flags.bits.moduleError = 0;

		UsbCtrl.cmdSize = 0;
		UsbCtrl.cmdSizeRequested = 0;
		UsbCtrl.msRef = 0;
		UsbCtrl.rxState.all = 0;
		UsbCtrl.commandId = 0;
	}

	/*=== Manage command receiving ===*/
	while(UsbUartCtrl.rx.nbrChar) {

		char read = UsbUartReadChar();		//Read current char

		UsbCtrl.msRef = TickGetMsCounter();

		//Controller is looking for cmd type
		if(UsbCtrl.rxState.all == 0) {
			if(read == USB_CMD_REMOTE || read == USB_CMD_PROTOCOLE || read == USB_CMD_RW || read == USB_CMD_RFIDECHO) {
				if(read != USB_CMD_RFIDECHO) {
					UsbCtrl.cmdType = read;
					UsbCtrl.rxState.bits.cmdTypeReceived = 1;
					UsbCtrl.command[UsbCtrl.commandId++] = read;
				} else {	//Porte dérobée pour le CR95 Echo
					UsbCtrl.cmdType = read;
					UsbCtrl.rxState.bits.cmdTypeReceived = 1;
					UsbCtrl.rxState.bits.sizeReceived = 1;
					UsbCtrl.rxState.bits.cmdComplete = 1;
					UsbCtrl.command[UsbCtrl.commandId++] = read;
					UsbManagerCmdDealer();
				}
			} else {		//Unknow type -> reset
				UsbCtrl.commandId = 0;
			}

		//Controller is looking for frame size
		} else if (UsbCtrl.rxState.all == USB_CMD_RXSTATE_TYPERECEIVED)  {
			UsbCtrl.cmdSizeRequested = read;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.rxState.bits.sizeReceived = 1;
			UsbCtrl.command[UsbCtrl.commandId++] = read;

		// Controller is waiting for complete frame
		} else if (UsbCtrl.rxState.all == (USB_CMD_RXSTATE_SIZERECEIVED | USB_CMD_RXSTATE_TYPERECEIVED) ) {
			UsbCtrl.command[UsbCtrl.commandId++] = read;
			UsbCtrl.cmdSize++;
			if(UsbCtrl.cmdSize == UsbCtrl.cmdSizeRequested) {
				UsbCtrl.rxState.bits.cmdComplete = 1;
				UsbManagerCmdDealer();
			}

		// Controller wait for command completion
		} else if (UsbCtrl.rxState.all == (USB_CMD_RXSTATE_SIZERECEIVED | USB_CMD_RXSTATE_TYPERECEIVED | USB_CMD_RXSTATE_CMDCOMPLETED) ) {

			//Don't care of incoming char

		// Controller Error -> reset
		} else {
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.commandId = 0;
		}
	}


	/*-- Too much time for command complete receiving --*/
	if(UsbCtrl.rxState.all & (USB_CMD_RXSTATE_TYPERECEIVED | USB_CMD_RXSTATE_SIZERECEIVED) != 0 ) {

		if( TickMilliSecElapsedFrom(UsbCtrl.msRef) > USB_CMD_MAX_TIME_MS_FOR_COMPLETE_CMD) {
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
		}
	}
}


void UsbManagerCmdDealer (void) {

	/*=== Remote command ===*/
	if(UsbCtrl.cmdType == USB_CMD_REMOTE) {

		/*-- echo request --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_ECHO) {

			char answer[] = {USB_CMD_REMOTE, 0x01, USB_CMD_REMOTE_echo, 0x00};

			UsbUartSendString(answer);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		/*-- current date requested --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_GET_TIME) {

			char answer[7];
			unsigned long rtcTime = RtcGetTime();

			answer[0] = USB_CMD_REMOTE;
			answer[1] = 5;
			answer[2] = USB_CMD_REMOTE_GET_TIME;
			answer[3] = (unsigned char)(rtcTime >> 24) & 0xFF;
			answer[4] = (unsigned char)(rtcTime >> 16) & 0xFF;
			answer[5] = (unsigned char)(rtcTime >> 8) & 0xFF;
			answer[6] = (unsigned char)(rtcTime) & 0xFF;

			UsbUartSendData(answer,7);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		/*-- set current date --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_SET_TIME) {

			char answer[3];
			unsigned long rtcTime;

			rtcTime = ( ( (unsigned long)(UsbCtrl.command[3]) & 0xFF ) << 24 ) |
					( ( (unsigned long)(UsbCtrl.command[4]) & 0xFF ) << 16 ) |
					( ( (unsigned long)(UsbCtrl.command[5]) & 0xFF ) << 8 ) |
					( ( (unsigned long)(UsbCtrl.command[6]) & 0xFF ) );

			RtcSetTime(rtcTime);

			answer[0] = USB_CMD_REMOTE;
			answer[1] = 1;
			answer[2] = USB_CMD_REMOTE_SET_TIME;
			UsbUartSendData(answer,3);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		/*-- get battery status --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_GET_BATTERY) {

			char answer[12];

			answer[0] = USB_CMD_REMOTE;
			answer[1] = 10;
			answer[2] = USB_CMD_REMOTE_GET_BATTERY;
			answer[3] = (unsigned char)((BQBatteryStatus.cellVoltage >> 8) & 0xFF);
			answer[4] = (unsigned char)((BQBatteryStatus.cellVoltage) & 0xFF);
			answer[5] = (BQBatteryStatus.stateOfCharge);
			answer[6] = (unsigned char)((BQBatteryStatus.fullCapacity >> 8) & 0xFF);
			answer[7] = (unsigned char)((BQBatteryStatus.fullCapacity) & 0xFF);
			answer[8] = (unsigned char)((BQBatteryStatus.timeToEmpty >> 8) & 0xFF);
			answer[9] = (unsigned char)((BQBatteryStatus.timeToEmpty) & 0xFF);
			answer[10] = (unsigned char)((BQBatteryStatus.timeToFull >> 8) & 0xFF);
			answer[11] = (unsigned char)((BQBatteryStatus.timeToFull) & 0xFF);

			UsbUartSendData(answer,12);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		/*-- set diving parameters --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_SET_DIVING) {

			DivingParameters.depth = UsbCtrl.command[3];
			DivingParameters.filterMSB = UsbCtrl.command[4];
			DivingParameters.filterLSB = UsbCtrl.command[5];

			unsigned short result = MemoryManagerWriteDiving(&DivingParameters);

			char answer[3];

			answer[0] = USB_CMD_REMOTE;
			answer[1] = 1;

			if(result == 0) {
				answer[2] = USB_CMD_REMOTE_SET_DIVING;
			} else {
				answer[2] = USB_CMD_REMOTE_ERROR;
			}

			UsbUartSendData(answer,3);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		/*-- get diving parameters --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_GET_DIVING) {

			char answer[3];

			answer[0] = USB_CMD_REMOTE;

			/*-- checksum --*/
			MemoryManagerCheckDiving(&DivingParameters);
			if(MemoryManagerCtrl.isValid.bits.diving) {
				answer[1] = 4;
				answer[2] = USB_CMD_REMOTE_GET_DIVING;
				answer[3] = DivingParameters.depth;
				answer[4] = DivingParameters.filterMSB;
				answer[5] = DivingParameters.filterLSB;
				UsbUartSendData(answer,6);
			} else {
				answer[1] = 1;
				answer[2] = USB_CMD_REMOTE_ERROR;
				UsbUartSendData(answer,3);
			}

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		/*-- get firmware revision --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_GET_FIRMWARE) {

			char answer[7];

			answer[0] = USB_CMD_REMOTE;
			answer[1] = 3;
			answer[2] = USB_CMD_REMOTE_GET_FIRMWARE;
			answer[3] = GLOBAL_FIRMWARE_REVISION;
			answer[4] = GLOBAL_FIRMWARE_RAMIFICATION;

			UsbUartSendData(answer,5);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}


		/*-- get serial --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_GET_SERIAL) {

			char answer[11];

			answer[0] = USB_CMD_REMOTE;

			MemoryManagerCheckDiving(&DivingParameters);
			if(MemoryManagerCtrl.isValid.bits.serial) {
				answer[1] = 9;
				answer[2] = USB_CMD_REMOTE_GET_SERIAL;

				unsigned char i;
				for(i=0 ; i<MEMORYMANAGER_SERIAL_BLOCK_SIZE-1 ; i++) {
					answer[3+i] = *(((unsigned char*)&SerialParameters.serial) + i);
				}

				UsbUartSendData(answer,11);
			} else {
				answer[1] = 1;
				answer[2] = USB_CMD_REMOTE_ERROR;
				UsbUartSendData(answer,3);
			}

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		/*-- Set serial --*/
		if(UsbCtrl.command[2] == USB_CMD_REMOTE_SET_SERIAL) {

			unsigned char i;

			for(i=0 ; i<MEMORYMANAGER_SERIAL_BLOCK_SIZE-1 ; i++) {
				*(((unsigned char*)&SerialParameters.serial) + i) = UsbCtrl.command[3+i];
			}

			unsigned short result = MemoryManagerWriteSerial(&SerialParameters);

			char answer[3];

			answer[0] = USB_CMD_REMOTE;
			answer[1] = 1;

			if(result == 0) {
				answer[2] = USB_CMD_REMOTE_SET_SERIAL;
			} else {
				answer[2] = USB_CMD_REMOTE_ERROR;
			}

			UsbUartSendData(answer,3);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		if(UsbCtrl.command[2] == USB_CMD_REMOTE_CLEAR_MEM) {

			unsigned short result = MemoryManagerClearLog();

			char answer[3];

			answer[0] = USB_CMD_REMOTE;
			answer[1] = 1;

			if(result == 0) {
				answer[2] = USB_CMD_REMOTE_CLEAR_MEM;
			} else {
				answer[2] = USB_CMD_REMOTE_ERROR;
			}

			UsbUartSendData(answer,3);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		if(UsbCtrl.command[2] == USB_CMD_REMOTE_GET_NBRLOG) {

			char answer[5];

			answer[0] = USB_CMD_REMOTE;
			answer[1] = 3;
			answer[2] = USB_CMD_REMOTE_GET_NBRLOG;
			answer[3] = (unsigned char)((MemoryManagerCtrl.nbrLog >> 8) & 0x000000FF);
			answer[4] = (unsigned char)((MemoryManagerCtrl.nbrLog >> 0) & 0x000000FF);

			UsbUartSendData(answer,5);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}

		if(UsbCtrl.command[2] == USB_CMD_REMOTE_GET_LOG) {

			unsigned short logId = ((unsigned short)UsbCtrl.command[3] << 8) | (unsigned short)UsbCtrl.command[4];

			/*-- Send log --*/
			if(logId < MemoryManagerCtrl.nbrLog) {

				tMemoryManagerLog log;
				signed short result;

				result = MemoryManagerReadLog(logId,&log);

				if(result == -1) {
					char answer[11];
					answer[0] = USB_CMD_REMOTE;
					answer[1] = 1;
					answer[2] = USB_CMD_REMOTE_ERROR;
					UsbUartSendData(answer,3);
				} else {
					char answer[11];
					answer[0] = USB_CMD_REMOTE;
					answer[1] = MEMORYMANAGER_LOG_SIZE + 1;
					answer[2] = USB_CMD_REMOTE_GET_LOG;

					answer[3] = (char)((log.date>>24) & 0xFF);
					answer[4] = (char)((log.date>>16) & 0xFF);
					answer[5] = (char)((log.date>>8) & 0xFF);
					answer[6] = (char)((log.date>>0) & 0xFF);

					answer[7] = (char)((log.logOp>>24) & 0xFF);
					answer[8] = (char)((log.logOp>>16) & 0xFF);
					answer[9] = (char)((log.logOp>>8) & 0xFF);
					answer[10] = (char)((log.logOp>>0) & 0xFF);

					UsbUartSendData(answer,11);
					UsbUartSendData((char*)&(log.srdData),SRD_MEMORY_NBR_BYTE);
				}

			/*-- Error --*/
			} else {
				char answer[3];
				answer[0] = USB_CMD_REMOTE;
				answer[1] = 1;
				answer[2] = USB_CMD_REMOTE_ERROR;
				UsbUartSendData(answer,3);
			}

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;
		}


	/*=== Protocole command ===*/
	} else if (UsbCtrl.cmdType == USB_CMD_PROTOCOLE) {

		char answer[2];

		answer[0] = 0;
		answer[1] = 0;
		UsbUartSendData(answer,2);

		//Acknowledge command
		UsbCtrl.commandId = 0;
		UsbCtrl.rxState.all = 0;
		UsbCtrl.cmdSize = 0;
		UsbCtrl.cmdSizeRequested = 0;

	/*=== Read / Write operation ====*/
	} else if (UsbCtrl.cmdType == USB_CMD_RW) {

		unsigned short result = RFIDManagerSendBridgeCommand(UsbCtrl.command, UsbCtrl.cmdSize + 2);

		if(result == -1) {	//Error

			char answer[2];

			answer[0] = 0x87;
			answer[1] = 0x00;
			UsbUartSendData(answer,2);

			//Acknowledge command
			UsbCtrl.commandId = 0;
			UsbCtrl.rxState.all = 0;
			UsbCtrl.cmdSize = 0;
			UsbCtrl.cmdSizeRequested = 0;

		} else {
			//Wait for completion -> This is RFIDManager which trig the end of this job
		}

	/*=== RFID ECHO command ===*/
	} else if (UsbCtrl.cmdType == USB_CMD_RFIDECHO) {

		char answer[1];

		answer[0] = 0x55;
		UsbUartSendData(answer,1);

		//Acknowledge command
		UsbCtrl.commandId = 0;
		UsbCtrl.rxState.all = 0;
		UsbCtrl.cmdSize = 0;
		UsbCtrl.cmdSizeRequested = 0;

	} else {
		//This is an error
		//Acknowledge command
		UsbCtrl.commandId = 0;
		UsbCtrl.rxState.all = 0;
		UsbCtrl.cmdSize = 0;
		UsbCtrl.cmdSizeRequested = 0;
	}

}

void UsbManagerSendCR95Error (void) {
	char answer[2];

	answer[0] = 0x87;
	answer[1] = 0x00;
	UsbUartSendData(answer,2);

	//Acknowledge command
	UsbCtrl.commandId = 0;
	UsbCtrl.rxState.all = 0;
	UsbCtrl.cmdSize = 0;
	UsbCtrl.cmdSizeRequested = 0;
}

void UsbManagerSendCR95Result (char* result, unsigned short length) {

	UsbUartSendData(result,length);

	//Acknowledge command
	UsbCtrl.commandId = 0;
	UsbCtrl.rxState.all = 0;
	UsbCtrl.cmdSize = 0;
	UsbCtrl.cmdSizeRequested = 0;
}
/*############################################################################################*/
/*## END EXTERNAL FONCTIONS ##################################################################*/
/*############################################################################################*/
