#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;
#define uint16_t WORD
typedef struct __attribute__((__packed__)) {                                                                                                                                                                                                                             
    unsigned char fileMarker1;                                                                                                                                                                                              
    unsigned char fileMarker2;                                                                                                                                                                                               
    unsigned int   bfSize;                                                                                                                                                                                                                   
    uint16_t unused1;                                                                                                                                                                                                                        
    uint16_t unused2;                                                                                                                                                                                                                        
    unsigned int   imageDataOffset;                                                                                                                                                            
} FILEHEADER;                                                                                                                                                                                                                                

typedef struct __attribute__((__packed__)) {                                                                                                                                                                                                                             
    unsigned int   biSize;                                                                                                                                                                                                                   
    int            width;                                                                                                                                                                
    int            height;                                                                                                                                                                     
    uint16_t planes;                                                                                                                                                                                                                         
    uint16_t bitPix;                                                                                                                                                                                                                         
    unsigned int   biCompression;                                                                                                                                                                                                            
    unsigned int   biSizeImage;                                                                                                                                                                                                              
    int            biXPelsPerMeter;                                                                                                                                                                                                          
    int            biYPelsPerMeter;                                                                                                                                                                                                          
    unsigned int   biClrUsed;                                                                                                                                                                                                                
    unsigned int   biClrImportant;                                                                                                                                                                                                           
} INFOHEADER;                                                                                                                                                                                                                                

typedef struct __attribute__((__packed__)) {                                                                                                                                                                                                                             
    unsigned char  b;                                                                                                                                                                                                                        
    unsigned char  g;                                                                                                                                                                                                                        
    unsigned char  r;                                                                                                                                                                                                                        
} IMAGE;

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;
}
char condense(char i)
{ 
  return (char)(i*255.0f/31.0f);
}

short transform(long input)// note that the last 8 bytes are ignored
{
  return condense(input&0xff) || (condense((input&0xff00)>>8)<<5)
    || (condense((input&0xff0000)>>16)<<10);
}

int main(int argc, char *argv[])
{
	DCB dcb;
	HANDLE hCom;
	HANDLE *ptr;
	FILE *fp;
	long size,result,length,address,factor,temp,w_size;
	char filename[100];
	char buffer[8192];
	char buffer1[4096];
	char ret[8];
	char filesize[8];
	BOOL bReadRC;
	WORD no_args = 17;
	WORD no_files = 13;
	WORD index = 0;
	static DWORD iBytesRead = -1;
	char Ack[2]="a";
	long returnbytes;
	BOOL fSuccess;
	char pcCommPort[10]="\\\\.\\COM";
	char prevch;
	char crc = 0;
	char tim[8];

    time_t rawtime;
    struct tm  tstruct;
    time(&rawtime);
    tstruct = *localtime(&rawtime);
	if(argc <no_args)
	{

		printf("Usage for M2S_UARTHost_Loader: M2S_UARTHost_Loader.exe comportnumber time(HHMMSS) y/n filenames  \n");
		
		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());
		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 Smartfusion2 dev kit is running \n");
	printf("Reset the Dev Kit board before launching this host loader application\n\n");
	printf("Handshaking with Smartfusion2 Dev Kit Started \n");

while(index<no_files)
{
	SerialPutc(hCom,'h');
	ret[0] = SerialGetc(hCom);
	if (ret[0] == 'a')
	{
		SerialPutc(hCom,'n');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please reset the SmartFusion2 Dev Kit Board \n");
		printf("restart this hostloader application with correct perameters \n");
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'd')
	{
		SerialPutc(hCom,'s');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please reset the SmartFusion2 Dev Kit Board \n");
		printf("restart this hostloader application with correct perameters \n");
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'h')
	{
		SerialPutc(hCom,'a');
	}
	else
	{
	    printf("Handshake fail\n");
		printf("Please reset the SmartFusion2 Dev Kit Board \n");
		printf("restart this hostloader application with correct perameters \n");
		return 0;

	}

	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'k')
	{
		SerialPutc(hCom,'e');
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please reset the SmartFusion2 Dev Kit Board \n");
		printf("restart this hostloader application with correct perameters \n");
		return 0;

	}
	ret[0] = SerialGetc(hCom);

	if (ret[0] == 'r')
	{
		printf("HAND SHAKE is fine \n");
	}
	else
	{
		printf("Handshake fail\n");
		printf("Please reset the SmartFusion2 Dev Kit Board \n");
		printf("restart this hostloader application 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); */
	//send the time and copy or not
	if(tstruct.tm_hour >12)
	{
       tstruct.tm_hour -= 12;
    }
	tim[0] = tstruct.tm_hour/10+'0';
	tim[1] = tstruct.tm_hour%10+'0';
    tim[2] = tstruct.tm_min/10+'0';
	tim[3] = tstruct.tm_min%10+'0';
    tim[4] = tstruct.tm_sec/10+'0';
	tim[5] = tstruct.tm_sec%10+'0';
	//strcpy(time,argv[2]);
	 printf("system time = %s\n", tim);                                                                         
   
	ret[0] = SerialGetc(hCom);
	if (ret[0] == 'm')
	{
        //SerialPutc(hCom,Action_code[0]);
        tim[7] = argv[3][0];
        bWriteRC = WriteFile(hCom, tim, 8, &iBytesWritten,NULL);
	}
	
	if(argv[3][0] == 'n' || argv[3][0] == 'N')
	{
           	printf("\n\n\nDONE press ctrl+c\n");    
	        while(1);
	        return 0;
    }
    strcpy(filename,".\\images\\");
	strcat(filename, argv[index+4]);
	
	FILEHEADER fh;                                                                                                                                                                                                                           
    INFOHEADER ih;                                                                                                                                                                                                                           
    fp = fopen(filename,"rb");
    fread(&fh, sizeof(unsigned char), sizeof(FILEHEADER), fp);
    fread(&ih, sizeof(unsigned char), sizeof(INFOHEADER), fp);
    printf("fM1 = %c, fM2 = %c, bfS = %u, un1 = %hu, un2 = %hu, iDO = %u\n", fh.fileMarker1, fh.fileMarker2, fh.bfSize, fh.unused1, fh.unused2, fh.imageDataOffset);                                                                         
    printf("w = %d, h = %d biSizeImage = %d\n", ih.width, ih.height , ih.biSizeImage);
	// obtain file size:
              
    
    
	fseek (fp , 0 , SEEK_END);
	size = ftell (fp);
	rewind (fp);
    fseek (fp,0,fh.imageDataOffset);
    size = ih.biSizeImage;
    printf("file name :%s file size = %d\n", filename, size);
	ret[0] = SerialGetc(hCom);
	if (ret[0] == 'z')
	{
        itoa(size,filesize,10);       
		bWriteRC = WriteFile(hCom, filesize, 8, &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); 
		//printf("ret = %d\n", ret[0]);
		/*if(ret[0]=='y'&& (address+returnbytes)==size)
		{
			prevch=ret[0];
		//	printf("FPGA array is programmed and enabled.\n");
			continue;

		}
		else if(ret[0]==0&& (address+returnbytes)==size&&prevch=='y')
		{
			printf("error code =%d\n",ret[0]);
			bWriteRC = WriteFile(hCom, Ack, 1, &iBytesWritten,NULL);
			return (0);
		}
		else if(ret[0]=='f')
		{
			//printf("CRC Check Fail, Please veirfy the PDB file. Reset the Target IAP loader\n"); 
			return (0);
		}
		else*/
        
        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 *)&temp, 8,&iBytesRead,NULL);
		address = temp*8;
		if(bReadRC==0)
		{
			printf("Read address transaction fails from the target\n");   
		}
		printf("Requested address from the target =%d\n", address); 
        //address = address +  address/2 + fh.imageDataOffset; 
		//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 + fh.imageDataOffset , 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\n");
			exit (3);
		}
	
		//send the requested data to the target
		/*
		for(i =0 ; i<returnbytes;i += 2)
		{
                rgb565 = (buffer[j]>>3 )<<11  | (buffer[j+1]>>2)<<5 | buffer[j+2]>>3;
                buffer1[i+1] = rgb565>>8;
                buffer1[i] = rgb565;
                buffer1[i] = (  ((buffer[j]>>3 )<<11 && 0xF100) | ((buffer[j+1]>>2)<<5) | (buffer[j+2]>>3) ) >> 8;
                 buffer1[i+1]  = (  ((buffer[j]>>3 )<<11 && 0xF100) | ((buffer[j+1]>>2)<<5) | (buffer[j+2]>>3) ) & 0xFF;
                 
                  buffer1[i] = ( (  ((buffer[j+2]>>3 )<<11 & 0xF800) + ((buffer[j+1]>>2)<<5 & 0x07D0) + (buffer[j]>>3) & 0x001F ) >> 8 ) & 0xFF;
                 buffer1[i+1]  = ((  ((buffer[j+2]>>3 )<<11 & 0xF800) + ((buffer[j+1]>>2)<<5  & 0x07D0) + (buffer[j]>>3) & 0x001F ) )& 0xFF;
                 //buffer1[i+1] = 0x001F >> 8 &0xFF;
                 //buffer1[i] = 0x001F &0xFF;
                j= j+3;
        }*/
		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);
                index++;
                break;
        } 
		if(returnbytes == 0 && address >= size )
		{
                                         
                fclose(fp);
                index++;
                break;
           
                       
        }
		//fp = fopen(filename,"rb");    
	} 
}  
	printf("\n\n\nDONE press ctrl+c\n");    
	while(1)
	{
    }

	return (0);

}
