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

#define WIN32_LEAN_AND_MEAN        /* define win 32 only */

void handle_error(void);           /* Error handler routine */
void write_file(char *buf);        /* Write details to log file */

unsigned atohex(str)
char *str; {

    unsigned n = 0;

    while (*str)
    {
		if (isdigit(*str))
		{
			n=16*n + *str - '0';
		}
	    else if (*str >= 'a' && *str <= 'f')
	    {
			n = 16*n + *str - 'a' + 10;
		}
	    else if( (*str == 'x') || (*str == 'X'))
    	{
    	}
    	else if(*str == '\n')
    	{
   	      return(n);
	    }
	    else
	    {
            printf("Invalid hex number");
	        return(0);
         }
	    str++;
    }
    return(n);
}

int main (int argc, char **argv)
{
  WORD wVersionRequested;          /* socket dll version info */ 
  WSADATA wsaData;                 /* data for socket lib initialisation */
  SOCKET sock;                     /* socket details */
  const int BUF_LEN=10000;         /* Buffer size for transfers */
  struct sockaddr_in address;      /* socket address stuff */
  struct hostent * host;           /* host stuff */
  int err;                         /* error trapping */
  float socklib_ver;               /* socket dll version */
  char File_Buf[BUF_LEN];          /* file buffer */
  char DomainName[100];            /* domain name from user */
  char HostName[100];              /* host name from user */
  time_t now;                      /* for date and time */
  static count=0;
  int bytes_recieved,bytes_recieved1,bytes_recieved2,bytes_recieved3;
  char send_data[1024],recv_data[1024],recv_data1[1024],recv_data2[1024],recv_data3[1024];
  char filename[100];
  char buffer[8200];
  FILE *fp;
  int size;
  int returnbytes,returnbytes1;
  unsigned char addr[10];
  unsigned char retbytes[10];
  unsigned int i=0, ii =0, jj =0;
  int length;
  int result;
  unsigned int requested_address;
  unsigned int temp1;
 
  if (argc < 3)                    /* check we have command line options */
  {
    printf("\nUsage: A2F_Mem_EthernetHost_Loader.exe filename target_IP_addr\n");
    exit(0);
  }
  wVersionRequested = MAKEWORD( 1, 1 );

   /* 
    * We need to call the WSAStartup routine BEFORE we try to use any of
    * the Winsock dll calls.
    */

   if ( WSAStartup( wVersionRequested, &wsaData ) != 0 )
     handle_error();

   /* Check socket DLL supports 1.1 or higher */

   socklib_ver = HIBYTE( wsaData.wVersion ) / 10.0;
   socklib_ver += LOBYTE( wsaData.wVersion );

   if ( socklib_ver < 1.1 )
   {
     printf ("\nError: socket library must support 1.1 or greater.\n");
     WSACleanup(); /* clean up before exit */
     exit(0);
   }

   /* write current date and time to log file and screen */

   time(&now);
   sprintf(File_Buf, "SmartFusion Session Started %.24s.\n\n", ctime(&now));
   write_file(File_Buf);

  /*
   * Open a socket. The AF_INET parameter tells windows we want to use the
   * internet. Other parameters for different networking can be chosen e.g.
   * for netbios, IPX etc. The SOCK_STREAM parameter lets windows know we want
   * to use TCP rather than UDP, and the final parameter will always be
   * zero for what we want to do and tells windows to use whatever
   * default communication protocol has been established (eg PPP and IP)
   */

   if ( (sock = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET )
     handle_error();

   /* We now need to initialise a couple of variables in the address
    * structure. Once again, to tell windows we are using the internet,
    * and also what port we want to use when connecting to a remote
    * computer. In this case it is port 43 which is the standard port for
    * whois. The htons routine is used to convert the way Intel chips
    * store data in memory, which is different compared to many other computers.
    * The standard is based on Motorola format.
    */

   address.sin_family=AF_INET;       /* internet */
   address.sin_port = htons(1234);     /* port 43 for whois */

   /* write to the log file and screen */

   sprintf(File_Buf,"Connecting to %s\n", HostName);
   write_file(File_Buf);


    /*
     * We should be connected to the server at this point
     * do recevie & Trasmit test
     */

    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);

       /*
    * host is a pointer to a structure of the predefined type hostent. We
    * need to call gethostbyname with the DNS name we want to use to return
    * a pointer to a hostent structure. This is so we can resolve an IP
    * address from our ISP's nameserver.
    */
    if ( (host=gethostbyname(argv[2])) == NULL )
      handle_error();

    /* we then initialise the address structure with the resolved IP address */

    address.sin_addr.s_addr=*((unsigned long *) host->h_addr);

    /* Now we're ready to actually connect to the whois server itself */
    printf("Got the Host\n");
    if ( (connect(sock,(struct sockaddr *) &address, sizeof(address))) != 0)
      handle_error();
    printf("Connected Ok\n");
    
    //send(sock,"Hello\0",6, 0);     

    while(1)
    {
          
          bytes_recieved=recv(sock,recv_data,7,0);
          
          i = 0;
          
          while(recv_data[i]!='\n')
          {
        
               recv_data1[i]= recv_data[i];            
               i++;  
          }
          
          recv_data1[i] = '\n';
          
          bytes_recieved1 = i--;
          
          
          requested_address = atohex(recv_data1);
          
//          printf("\nRecieved bytes for address bytes_recieved = %d,  bytes_recieved1 = %d\n " , bytes_recieved, bytes_recieved1);
          
//          printf("\nAddress recv_data = %s, recv_data = %s\n " , recv_data, recv_data1);
          
          //printf("\nAddress after conversion= %d\n " , requested_address);         
          
          printf(".");         
#if 0          
          
          recv_data[bytes_recieved-1] = '\0';
          
          printf("\nRecieved data = %d\n " , bytes_recieved);

          printf("\nAddress data = %s\n " , recv_data);
          
          requested_address = atohex(recv_data);
           
          printf("\nAddress after conversion= %d\n " , requested_address);
#endif          
             
         
     
	      bytes_recieved2=recv(sock,recv_data2,7,0);
	      
          i = 0;
          
          while(recv_data2[i]!='\n')
          {
        
               recv_data3[i]= recv_data2[i];            
               i++;  
          }
          recv_data3[i] = '\n';
          
          bytes_recieved3 = i--; 
          
          returnbytes1 = atohex(recv_data3);  
          
          //printf("\nRecieved bytes for returnbytes bytes_recieved2 = %d,  bytes_recieved3 = %d\n " , bytes_recieved2, bytes_recieved3);
          
          //printf("\nReturnbytes returnbytes = %s, recv_data = %s\n " , recv_data2, recv_data3);
          
          //printf("\nReturnbytes after conversion= %d\n " , returnbytes1);  
  
	      
         /* ii++;
          if(ii==5)
          ii++;*/
	      
	      
#if 0	      
          recv_data1[bytes_recieved1-1] = '\0';        
          

          printf("\nRecieved data = %d\n " , bytes_recieved1);

          printf("\ReturnBytes data = %s\n " , recv_data1);

	      returnbytes1 = atohex(recv_data1);	  
          
          printf("\nReturn bytes after the hex conversion= %d\n " , returnbytes1);  
 #endif         
          if(returnbytes1 == 0)
          {
              if(requested_address = 0xBABE)
              {
                   printf("Successfully Programed FPGA \n");
              }
              else
              {
                 printf("Successfully Programed FPGA \n");

              }
              fclose(fp);
              return 0;
           }

          fseek (fp , requested_address , SEEK_SET);
          
          result = fread (buffer,1,returnbytes1,fp);
        //  buffer[returnbytes1] ='\0';
          //buffer[returnbytes1+1] ='\n' ;                 
                  
          //buffer[returnbytes1] = "Q\n"; 
             
          send(sock,buffer,result, 0);       
          
                   
          fclose(fp);
          
		  fp = fopen(filename,"rb");  

        //  send(sock,"Q\n",strlen("Q\n"), 0);

#if 0
	      while(returnbytes1 > 0 )
          {
              
              if (size > 1024)
              {
    	          length  = 1024;
			  }
			  else
              {
                  length = returnbytes1;
              }

              printf("----");
              
              fseek (fp , requested_address , SEEK_SET);

              result = fread (buffer,1,length,fp);
              buffer[length] = '\0'; 
             
              send(sock,buffer,length, 0);  
              
              returnbytes1 -= length;
          }
         
          fclose(fp);
		  fp = fopen(filename,"rb");
#endif 		  
     }


  }

  void handle_error(void)
  {
    /*
     * Errors are handled by calling the WSAGetLastError routine which 
     * will return the last error as one of the following. As we develop
     * this tutorial, we will go into much more detail on what they mean
     * and what caused them.
     */

    switch ( WSAGetLastError() )
    {
      case WSANOTINITIALISED :
       	printf("Unable to initialise socket.\n");
      break;
      case WSAEAFNOSUPPORT :
        printf("The specified address family is not supported.\n");
      break;
      case WSAEADDRNOTAVAIL	:
        printf("Specified address is not available from the local machine.\n");
      break;
      case WSAECONNREFUSED :
        printf("The attempt to connect was forcefully rejected.\n"); 
        break; 
      case WSAEDESTADDRREQ	: 
        printf("address destination address is required.\n");
      break;
      case WSAEFAULT :
        printf("The namelen argument is incorrect.\n");
      break;
      case WSAEINVAL :
        printf("The socket is not already bound to an address.\n");
      break;
      case WSAEISCONN :
        printf("The socket is already connected.\n");
      break;
      case WSAEADDRINUSE :
        printf("The specified address is already in use.\n");
      break;
      case WSAEMFILE : 
        printf("No more file descriptors are available.\n");
      break;
      case WSAENOBUFS	:
        printf("No buffer space available. The socket cannot be created.\n");
      break;
      case WSAEPROTONOSUPPORT	:
        printf("The specified protocol is not supported.\n");
        break; 
      case WSAEPROTOTYPE :
        printf("The specified protocol is the wrong type for this socket.\n");
      break;
      case WSAENETUNREACH	: 
        printf("The network can't be reached from this host at this time.\n");
      break; 
      case WSAENOTSOCK :
         printf("The descriptor is not a socket.\n");
      break;
      case WSAETIMEDOUT	:
        printf("Attempt timed out without establishing a connection.\n");
      break;
      case WSAESOCKTNOSUPPORT	:
         printf("Socket type is not supported in this address family.\n");
      break;
      case WSAENETDOWN :
        printf("Network subsystem failure.\n");
      break;
      case WSAHOST_NOT_FOUND :
        printf("Authoritative Answer Host not found.\n");
      break;
      case WSATRY_AGAIN :
        printf("Non-Authoritative Host not found or SERVERFAIL.\n");
       break;
      case WSANO_RECOVERY	:
         printf("Non recoverable errors, FORMERR, REFUSED, NOTIMP.\n");
      break;
      case WSANO_DATA	:
        printf("Valid name, no data record of requested type.\n");
      break;
        case WSAEINPROGRESS	:
        printf("address blocking Windows Sockets operation is in progress.\n");
      break;
      case WSAEINTR	:
        printf("The (blocking) call was canceled via WSACancelBlockingCall().\n");
      break;
      default :
        printf("Unknown error.\n");
       break;
  }

  WSACleanup();
  exit(0);
}

void write_file(char *buf)
{
  /* writes results to a log file and also to the screen */

  FILE *fp=fopen("SmartFusionErrorlog.txt","a+");
  fprintf(fp,"%s\n",buf); 
  fclose(fp);
  printf("%s\n",buf);
}

void read_file(char *buf)
{
  /* writes results to a log file and also to the screen */

  FILE *fp=fopen("SmartFusionErrorlog.txt","a+");
  fprintf(fp,"%s\n",buf); 
  fclose(fp);
  printf("%s\n",buf);
}
