/***************************************************************************//**
 *   @file   BerkeleyTCPClient.c
 *   @brief  Berekely TCP client implementation exemple
 *   @author Kévin MARCHAND(Kevin.marchand@intelligence-electronique.com)
********************************************************************************
 * Copyright 2014(c) PLCD, Inc.
 *
 * Cette application utilise les API des sockets BSD (Berekely), et démarre une
 * connexion TCP sur le port <b>PORTNUM</b>. Cette exemple se connecte à www.google.com
 * en effectuant une résolution DNS et transmet la requete "sendRequest" au
 * serveur WEB de Google.
 *  - Cette exemple peut être adapté pour effectuer d'autres opérations.
 *
********************************************************************************
 *   SVN Revision: 1
*******************************************************************************/

/******************************************************************************/
/***************************** Include Files **********************************/
/******************************************************************************/
#include "TCPIPStack/TCPIPConfig.h"

#if defined(STACK_USE_BERKELEY_API)

#include "Include/TCPIPStack/TCPIP.h"

#define PORTNUM 80
static ROM BYTE ServerName[] =  "www.google.com";

// Ceci est spécifique à cet exemple de client HTTP
static BYTE sendRequest[] = "GET /search?as_q=Microchip&as_sitesearch=microchip.com HTTP/1.0\r\nHost: www.google.com\r\nConnection: close\r\n\r\n";

/***************************************************************************//**
 * @brief Machine d'état gérant la connexion.
 * @pre: La stack TCPIP doit être initialiser
 * @param none.
 * @return none.
*******************************************************************************/
void BerkeleyTCPClient(void)
{
#if defined(STACK_USE_DNS)
    static SOCKET bsdClientSocket;
    static struct sockaddr_in addr;
    char recvBuffer[9];
    int i;
    int addrlen;
   
    static enum
    {
	DNS_START_RESOLUTION = 0,
	DNS_GET_RESULT,
        BSD_START,
        BSD_CONNECT,
        BSD_SEND,
        BSD_OPERATION,
        BSD_CLOSE,
        BSD_DONE
    } BSDClientState = BSD_DONE;

    switch(BSDClientState)
    {
	    case DNS_START_RESOLUTION:
	    	if(DNSBeginUsage())
	    	{
		    	DNSResolveROM(ServerName, DNS_TYPE_A);
		    	BSDClientState = DNS_GET_RESULT;
		    }
	    	break;
	    
	    case DNS_GET_RESULT:
	    	if(!DNSIsResolved((IP_ADDR*)&addr.sin_addr.S_un.S_addr))
	    		break;
	    		
	    	if(!DNSEndUsage())
	    	{
				#if defined(STACK_USE_UART)
				putrsUART((ROM char*)"Could not resolve ServerName[] to IP address.\r\n");
				#endif
		    	BSDClientState = BSD_DONE;
		    	break;
		    }

	    	BSDClientState = BSD_START;			
	    	// No break; here.
	    
        case BSD_START:
            // Create a socket for this client to connect with 
            if((bsdClientSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == INVALID_SOCKET )
                return;
         
			#if defined(STACK_USE_UART)
			putrsUART((ROM char*)"\r\n\r\nConnecting using Berkeley Sockets TCP API...\r\n");
			putrsUART((ROM char*)"   Note: this demo will do nothing if an underlying TCP_PURPOSE_BERKELEY_CLIENT type \r\n"
								 "   socket is unavailable, as declared by the TCPSocketInitializer[] array in \r\n"
								 "   TCPIPConfig.h.\r\n\r\n");
			#endif
         	         
            BSDClientState = BSD_CONNECT;
            break;

        case BSD_CONNECT:
            addr.sin_port = PORTNUM;
            addrlen = sizeof(struct sockaddr);
            if(connect( bsdClientSocket, (struct sockaddr*)&addr, addrlen) < 0)
            	return;

            BSDClientState = BSD_SEND;
            // No break needed

        case BSD_SEND:
            //send TCP data
            send(bsdClientSocket, (const char*)sendRequest, strlen((char*)sendRequest), 0);  
            BSDClientState = BSD_OPERATION;
            break;
        
        case BSD_OPERATION:
            // Obtian and print the server reply
            while(1)
            {
		i = recv(bsdClientSocket, recvBuffer, sizeof(recvBuffer)-1, 0); //get the data from the recv queue

                if(i == 0)
                    break;
                
                if(i< 0) //error condition
                {
                    BSDClientState = BSD_CLOSE;
                    break;
                }
                
                #if defined(STACK_USE_UART)
                recvBuffer[i] = '\0';	// Null terminate data
                putsUART((char*)recvBuffer);
                #endif

                if(BSDClientState == BSD_OPERATION)
                    break;
            }
            break;
         
        case BSD_CLOSE:
            closesocket(bsdClientSocket);
            BSDClientState = BSD_DONE;
            // No break needed
            
        case BSD_DONE:
            if(BUTTON1_IO == 0u)
            	BSDClientState = DNS_START_RESOLUTION;
            break;
         
        default:
            return;
    }
//#if defined(STACK_USE_DNS)
#else
    #warning You must define STACK_USE_DNS for BerkeleyTCPClient to work
#endif
}

#endif //#if defined(STACK_USE_BERKELEY_API)

