#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;
	int image_count=0,error_read = 0; 
	//char *argv[] = {"spi_loader.exe","33","golden_image_v0.spi","update_image_v2.spi","iap_image_v5.spi"};
	long size,result,length,address,factor,temp,t1,t2;
	char filename[100];
	char buffer[8192],c;
	char ret[8];
	char filesize[8];
	BOOL bReadRC;
	static DWORD iBytesRead = -1;
	char Ack[2]="a";
	char Ack1[2]="n";
		char Ack2[2]="f";
	long returnbytes;
	BOOL fSuccess;
	char pcCommPort[10]="\\\\.\\COM";
	char prevch;
	char crc = 0;
	char Action_code[2];
	time_t rawtime;
    struct tm  tstruct_start;
    struct tm  tstruct_end;
  
	if(argc <5)
	{

		printf("Usage for external spi loader: spi_loader.exe com_port_number golden_image_v0.spi update_image_v2.spi iap_image_v5.spi\n");
		printf("Press CTRL+C to exit \n");
		while(1);
		return 0;
	}
	
	
    
   

	strcat(pcCommPort,argv[1]);
	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());
		printf("Press CTRL+C to exit \n");
		while(1);
		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 opened by other application %d.\n", GetLastError());
		printf("Press CTRL+C to exit \n");
		while(1);
		return (2);
	}

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

	dcb.BaudRate = CBR_256000;//CBR_115200;//CBR_256000; // set the baud rate
	dcb.ByteSize = 8; // data size, xmit, and rcv
	dcb.Parity = NOPARITY; // no parity bit
	dcb.StopBits = ONESTOPBIT; // one stop bit
CommTimeouts.ReadIntervalTimeout= 0;
    CommTimeouts.ReadTotalTimeoutConstant=0;
    CommTimeouts.ReadTotalTimeoutMultiplier= 0;
    CommTimeouts.WriteTotalTimeoutConstant=0;
    CommTimeouts.WriteTotalTimeoutMultiplier=0;
    SetCommTimeouts(hCom,&CommTimeouts);
   
	fSuccess = SetCommState(hCom, &dcb);

	if (!fSuccess)
	{
		// Handle the error.
		printf ("Cann't set the UART port Settings %d.\n", GetLastError());
		printf("Press CTRL+C to exit \n");
		while(1);
		return (3);
	}

	printf ("Serial port %s successfully reconfigured.\n", pcCommPort);
	printf ("Ensure the PolarFire Kit is running .\n", pcCommPort);
		
	printf("Press 'Enter' to Program the External SPI flash ..\nIf you want to run programming options, change the DIP switch-1 position to OFF and power cycle the board.\n");
	scanf("%c",&c);

 	SerialPutc(hCom,'s');
	ret[0] = SerialGetc(hCom);
	if (ret[0] == 'a')
	{
		printf("The External SPI flash is erasing... \n");
		printf("Handshaking with PolarFire kit is in progress... \n");
	}
Sleep(6000);
while(image_count<3)
{
	
Sleep(2500);
	SerialPutc(hCom,'h');
	ret[0] = SerialGetc(hCom);
	if (ret[0] == 'a')
	{
		SerialPutc(hCom,'n');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please power cycle the PolarFire Kit Board \n");
		printf("restart this spi loader application with correct perameters . Press CTRL+C to exit \n");
		while(1);
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'd')
	{
		SerialPutc(hCom,'s');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please power cycle the PolarFire Kit Board \n");
		printf("restart this spi loader application with correct perameters . Press CTRL+C to exit \n");
		while(1);
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'h')
	{
		SerialPutc(hCom,'a');
	}
	else
	{
	   	printf("Handshake fail\n");
		printf("Please power cycle the PolarFire Kit Board \n");
		printf("restart this spi loader application with correct perameters . Press CTRL+C to exit \n");
		while(1);
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'k')
	{
		SerialPutc(hCom,'e');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please power cycle the PolarFire Kit Board \n");
		printf("restart this spi loader application with correct perameters . Press CTRL+C to exit \n");
		while(1);
		return 0;

	}
	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'r')
	{
		printf("HAND SHAKE is fine \n");
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please power cycle the PolarFire Kit Board \n");
		printf("restart this spi loader application with correct perameters . Press CTRL+C to exit \n");
		while(1);
		return 0;

	}

	printf("HAND SHAKE is fine \n");
if(image_count == 0)
{
	time(&rawtime);
tstruct_start = *localtime(&rawtime);
printf("\n\n\nstart time %d:%d:%d\n",tstruct_start.tm_hour,tstruct_start.tm_min,tstruct_start.tm_sec); 
}
	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,".\\images\\");
	strcat(filename, argv[2+image_count]);
	

	fp = fopen(filename,"rb");
	// obtain file size:
	fseek (fp , 0 , SEEK_END);
	size = ftell (fp);
	rewind (fp);

	printf("file name = %s, size = %d\n",filename, size);
	ret[0] = SerialGetc(hCom);
	if (ret[0] == 'z')
	{
        itoa(size,filesize,10);       
		bWriteRC = WriteFile(hCom, filesize, 9, &iBytesWritten,NULL);
	}
	//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); 
		        
        if(ret[0]!='b')
			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 *)&t1, 1,&iBytesRead,NULL);
		
	
		if(bReadRC==0)
		{
			printf("Read address transaction fails from the target\n");   
		}
		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");   
		}  
		
		bReadRC =ReadFile(hCom, (char *)&t2, 1,&iBytesRead,NULL);
				if(bReadRC==0)
		{
			printf("Read address transaction fails from the target\n");   
		}
		
		temp = t1&0xff | ((t2<<8)&0xFF00);
		address = temp*4096;
		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 *)&t1, 1,&iBytesRead,NULL);
		if(bReadRC==0)
		{
			printf("Read address transaction fails from the target\n");   
		}
		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");   
		}  
		bReadRC =ReadFile(hCom, (char *)&t2, 1,&iBytesRead,NULL);
	
		//bReadRC =ReadFile(hCom, (char *)&returnbytes, 2,&iBytesRead,NULL);        
		if(bReadRC==0)
		{
			printf("Read number of returnbytes transcation fails from the target\n");   
		}
		returnbytes = t1&0xff | ((t2<<8)&0xFF00);
		if(returnbytes >4096 || returnbytes<0)
		{
			//bWriteRC = WriteFile(hCom, Ack2, 1, &iBytesWritten,NULL);
		//	bReadRC =ReadFile(hCom, (char *)&returnbytes, 4,&iBytesRead,NULL); 
		returnbytes = 4096;
		error_read++;
		}
		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, Ack1, 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 the target =%d\n", returnbytes);
        printf("Remaining bytes =%d\n", size - address-returnbytes);
		if (result != returnbytes)
		{
			printf("Can't open Input file: Please check the path of the file: Reading error, Press CTRL+C\n");
			while(1);
			exit (3);
		}
		//memset(buffer,'5',result);
		//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");   
		}
		//CRC check
		   factor = 1;
           crc = 0;
           while((returnbytes-1)/factor)
           {
              crc = crc^buffer[factor];
              factor = factor*2;
           }
          bWriteRC = WriteFile(hCom, &crc, 1, &iBytesWritten,NULL); 
          bReadRC = ReadFile(hCom, ret, 1,&iBytesRead,NULL); 
		  if(bReadRC==0)
		  {
			printf("Read Ack operation fail from target for the requested bytes\n");   
           }
           else
           printf("End of one transaction:Ack '%s' received from target for the data from the host\n",ret); 
       
        //CRC check ends
		
		if(address+returnbytes == size)
       {
            fclose(fp);    
            image_count++;
			 break;                      
        
		  
        } 
		if(returnbytes == 0 && address >= size )
		{
                                         
           fclose(fp);
           image_count++;
            break;
                       
        }
	//	fp = fopen(filename,"rb");    
	}  
} //for 3 images
	
	 time(&rawtime);
tstruct_end = *localtime(&rawtime);  
printf("\n\n\nstart time %d:%d:%d\n",tstruct_start.tm_hour,tstruct_start.tm_min,tstruct_start.tm_sec);  
printf("\nend time %d:%d:%d\n",tstruct_end.tm_hour,tstruct_end.tm_min,tstruct_end.tm_sec);
printf("\n\n\nDONE press ctrl+c to terminate the application.\n"); 
	while(1)
	{
    }

	return (0);

}
