#include <stdio.h>
#include <time.h>
#include <windows.h>

#define VC_EXTRALEAN
#include <string.h>

// Flow control flags

#define FC_DTRDSR 0x01
#define FC_RTSCTS 0x02
#define FC_XONXOFF 0x04

// ascii definitions

#define ASCII_BEL 0x07
#define ASCII_BS 0x08
#define ASCII_LF 0x0A
#define ASCII_CR 0x0D
#define ASCII_XON 0x11
#define ASCII_XOFF 0x13

BOOL bPortReady;
DCB dcb;
COMMTIMEOUTS CommTimeouts;
BOOL bWriteRC;
BOOL bReadRC;
DWORD iBytesWritten;
DWORD iBytesRead;


char SerialGetc(HANDLE hCom)
{
	BOOL bReadRC;
	char ret[4];

	static DWORD iBytesRead = -1;

	bReadRC = ReadFile(hCom, ret, 1,&iBytesRead,NULL);

	return ret[0];
}



void SerialPutc(HANDLE hCom, char txchar)
{
	BOOL bWriteRC;
	static DWORD iBytesWritten = -1;

	bWriteRC = WriteFile(hCom, &txchar, 1, &iBytesWritten,NULL);

	return;
}


int main(int argc, char *argv[])
{
	DCB dcb;
	HANDLE hCom;
	HANDLE *ptr;
	FILE *fp;
	long size,result,length,address;
	char filename[100];
	char buffer[8192];
	char ret[8];
	BOOL bReadRC;
	static DWORD iBytesRead = -1;
	char Ack[2]="a";
	long returnbytes;
	BOOL fSuccess;
	char pcCommPort[5]="COM";
	char prevch;
	unsigned char Action_code =16;
	if(argc <3)
	{

		printf("Usage for ASF2Memoryloader: ASF2Memoryloader.exe filename comportnumber\n");

		return 0;
	}


	strcat(pcCommPort,argv[2]);
	hCom = CreateFile( pcCommPort,
			GENERIC_READ | GENERIC_WRITE,
			0, // must be opened with exclusive-access
			NULL, // no security attributes
			OPEN_EXISTING, // must use OPEN_EXISTING
			0, // not overlapped I/O
			NULL // hTemplate must be NULL for comm devices
	);

	if (hCom == INVALID_HANDLE_VALUE)
	{
		// Handle the error.
		printf ("Cann't open UART port, Please close if the port is open by other application %d.\n", GetLastError());
		return (1);
	}

	// Build on the current configuration, and skip setting the size
	// of the input and output buffers with SetupComm.

	fSuccess = GetCommState(hCom, &dcb);

	if (!fSuccess)
	{
		// Handle the error.
		printf ("Cann't open UART port, Please close if the port is open by other application %d.\n", GetLastError());
		return (2);
	}

	// Fill in DCB: 57,600 bps, 8 data bits, no parity, and 1 stop bit.

	dcb.BaudRate = CBR_57600; // set the baud rate
	dcb.ByteSize = 8; // data size, xmit, and rcv
	dcb.Parity = NOPARITY; // no parity bit
	dcb.StopBits = ONESTOPBIT; // one stop bit

	fSuccess = SetCommState(hCom, &dcb);

	if (!fSuccess)
	{
		// Handle the error.
		printf ("Cann't set the UART port Settings %d.\n", GetLastError());
		return (3);
	}

	printf ("Serial port %s successfully reconfigured.\n", pcCommPort);
	printf("\n\nPlease make sure smart fusion dev kit is running \n");
	printf("target loader before launching host loader\n\n");
	printf("Handshaking with Smartfusion F2 uart \n");


	SerialPutc(hCom,'h');
	ret[0] = SerialGetc(hCom);
	if (ret[0] == 'a')
	{
		SerialPutc(hCom,'n');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please restart the target loader and \n");
		printf("restart the hostloader with correct perameters \n");
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'd')
	{
		SerialPutc(hCom,'s');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please restart the target loader and \n");
		printf("restart the hostloader with correct perameters \n");
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'h')
	{
		SerialPutc(hCom,'a');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please restart the target loader and \n");
		printf("restart the hostloader with correct perameters \n");
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'k')
	{
		SerialPutc(hCom,'e');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please restart the target loader and \n");
		printf("restart the hostloader with correct perameters \n");
		return 0;

	}

	printf("HAND SHAKE is fine \n");

	printf("Sending starting Ack ....\n");
	bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
	bReadRC = ReadFile(hCom, ret, 1,&iBytesRead,NULL);
	printf("Sending Action code ....\n");
	bWriteRC = WriteFile(hCom, &Action_code, 1, &iBytesWritten,NULL);
	printf("Action_code = %d\n", Action_code);
	//read the Ack from target
	bReadRC = ReadFile(hCom, ret, 1,&iBytesRead,NULL);
	strcpy(filename, argv[1]);
	fp = fopen(filename,"rb");
	// obtain file size:
	fseek (fp , 0 , SEEK_END);
	size = ftell (fp);
	rewind (fp);

	printf("size = %d\n", size);
	//Read the address and return bytes from target and transmit the requested number of bytes from that address to the target.
	//At the target side the data will be stored in internal memory and IAP will programm the FPGA with the stored data from internal memory.

	while(1)
	{
		//read the message from the target.
		bReadRC = ReadFile(hCom, ret, 1,&iBytesRead,NULL);
        //printf("ret = %d\n", ret[0]);

		if(ret[0]=='v')
		{
            prevch =ret[0];
            printf("Verifying NVM block---------------------\n");
			bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);            
            continue;
        }
		if(ret[0]=='p')
		{
			printf("Programming NVM block---------------------\n");
			bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);            			
			continue;

		}
//		else if( (ret[0]== '0') && (prevch=='v') /*&& ((address+returnbytes)==size)*/)
		else if( (ret[0]== 'z'))
		{
			printf("Programming NVM block successful\n");
			bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
			return (0);
		}
		else if(ret[0]== '$') /*&& (address+returnbytes)==size)*/
		{
			printf("error code =%d\n",ret[0]);
			printf("Programming NVM block unsuccessful\n");
			bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
			return (0);
		}
#if 0		
		else if( (ret[0] == 'y') )/* && (prevch=='v')&& ((address+returnbytes)==size) ) */
		{
			printf("Verify done NVM block\n");
			bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
//			return (0);
            continue;
		}
#endif

		else if(ret[0]=='f')
		{
			printf("CRC Check Fail, Please veirfy the PDB file. Reset the Target IAP loader\n");
			bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);            			
			return (0);
		}
		else if(ret[0]!='b')
		{   printf("%c", ret[0]);
			bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
			continue;
        }

		if(bReadRC==0)
		{
			printf("No transction started from the target.Begin transaction Ack 'b' fails\n");
		}

		printf("============Begin transaction Ack '%s' is received from the target=============\n",ret);
		//send Ack message to the target as an acknowledgement for receiving the begin transaction Ack 'b'.
		bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
		if(bWriteRC==0)
		{
			printf("Sending Ack message 'a' fails for an acknowledgement of receiving the begin transaction Ack 'b'\n");
		}
		//read address from target
		bReadRC =ReadFile(hCom, (char *)&address, 8,&iBytesRead,NULL);
		if(bReadRC==0)
		{
			printf("Read address transaction fails from the target\n");
		}
		printf("Requested address from the target =%d\n", address);
		//send an Ack to the target as an acknowledgment for receiving the address
		bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
		if(bWriteRC==0)
		{
			printf("Sending Ack message fails for the received address\n");
		}
		//read returnbytes from target
		bReadRC =ReadFile(hCom, (char *)&returnbytes, 4,&iBytesRead,NULL);
		if(bReadRC==0)
		{
			printf("Read number of returnbytes transcation fails from the target\n");
		}
		printf("Requested returnbytes from the target =%d\n", returnbytes);
		//send an Ack to the target as an acknowledgment for receiving the returnbytes
		bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
		if(bWriteRC==0)
		{
			printf("Sending Ack message fails for the received returnbytes\n");
		}
		//set the file pointer to the requested address
		fseek (fp , address , SEEK_SET);
		//read the requested number of bytes from the file into buffer
		result = fread (buffer,1,returnbytes,fp);

		printf("bytes read from the file=%d\n", result);
		printf("requested bytes from the target =%d\n", returnbytes);

		if (result != returnbytes)
		{
			printf("Can't open Input file: Please check the path of the file: Reading error\n");
			exit (3);
		}
		//send the requested data to the target
		bWriteRC = WriteFile(hCom, buffer, returnbytes, &iBytesWritten,NULL);
		printf("Sending the data to the target...............................................\n");
		//read an Ack from the target to ensure that the whole data is received by the target
		bReadRC = ReadFile(hCom, ret, 1,&iBytesRead,NULL);
		if(bReadRC==0)
		{
			printf("Read Ack operation fail from target for the requested bytes\n");
		}
		bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
		if(bWriteRC==0)
		{
			printf("Sending Ack message fails for the received endof one transaction\n");
		}


		printf("End of one transaction:Ack '%s' received from target for the data from the host\n",ret);
		fclose(fp);
		strcpy(filename, argv[1]);
		fp = fopen(filename,"rb");
//        rewind (fp);
	}
	printf("Some thing is Wrong with the target,the control shouldn't come here\n");

	return (0);

}
