/*
Project: Ethernet Client demo program with timer interrupt function

Compiler: BC++ 3.1, 
          Turbo C++ 1.01(3.01) (free from http://cc.codegear.com/free/cpp)
          
Compile mode: large

Project: TCP_Clie.C
         ..\..\lib\7186el.lib
         ..\..\lib\tcp_dm32.lib

Details:
    This demo sends string "11test" to another 7188E/8000E that running a Xserver program. 
    The Xserver default supports command "11" for testing. It will responses a string in 
    "<11(Data)>" format. 
    In this demo, the data is "test", thus each time, the program should receive "<11test>", 
    totally 8 bytes.                                    
                                                                      
[Nov 3, 2008] by Liam                                               
*/

#include <stdlib.h>
#include "..\..\lib\7186e.h"
#include "..\..\lib\Tcpip32.h"

//variables declared in TCP/IP library.
extern int errno;
extern long ET_TOUT;    /* basic timeout value */

int Ethernet_Init(void)
{
    /*
    Return:
         0: ok.
        -1: function "llip" error
        -2: function "Ninit" error
        -3: function "Portinit" error
    */
    int iRet;
    struct ip host_ip;
    
    GetSavedIp((struct ip*)&host_ip);
    iRet=lhip("7186EX", &host_ip);
    if(iRet!=NoError) return -1;
    
    iRet=Ninit();
    if(iRet!=NoError) return -2;
    
    iRet=Portinit( "*" );  /* initiate network device */
    if(iRet!=NoError) return -3;
    
    return 0;
}

int Ethernet_Connect(unsigned char *cRemoteIP,int iRemoteTCPPort,long lConnect_Timeout)
{
    /*
    cRemoteIP: Remote IP address, for example: "192.168.255.1"
    iRemoteTCPPort: Remote TCP port number
    lConnect_Timeout: timeout (unit: ms)
    
    Return: >=0  :ok, return socket number
             <0  :error, return -1.
    */
    extern int errno;
    int iSocketNumber,iRet;
    unsigned long lStartTimeTick;
    int iTemp;
    
    struct sockaddr_in sktRemoteServer;  
    
    iSocketNumber=socket(PF_INET,SOCK_STREAM,0);   
    if(iSocketNumber>=0)
    {    
        YIELD();
        memset(&sktRemoteServer, 0, sizeof(sktRemoteServer)); /* bzero is a unix system call */
        sktRemoteServer.sin_family = AF_INET;          
        sktRemoteServer.sin_addr.s_addr = inet_addr(cRemoteIP);
        sktRemoteServer.sin_port = htons( iRemoteTCPPort );    
        YIELD();
        
        SOCKET_NOBLOCK(iSocketNumber);   /*Set Non-blocking mode*/
        ET_TOUT=300L;  //300ms, ET_TOUT has less than 800ms (WatchDog reboot time)
        iRet=connect(iSocketNumber, (struct sockaddr *)&sktRemoteServer, sizeof(sktRemoteServer));
        if(iRet) /* unsuccessful connection not 0 */
        {       
            lStartTimeTick=*TimeTicks;
            
            if(errno==EINPROGRESS)
            {
                while((*TimeTicks-lStartTimeTick)<lConnect_Timeout)
                {
                    RefreshWDT();
                    YIELD();
                    if(SOCKET_ISOPEN(iSocketNumber)) 
                    {
                        ET_TOUT=300L;
                        iTemp=iSocketNumber;
                        break; 
                    }
                    else
                    {
                        //printCom1("Open socket error\n\r");
                        iTemp=-1;
                    }
                }
                if(iTemp==-1)
                    closesocket(iSocketNumber);    
                iSocketNumber=iTemp;
            }
            else
            {
                closesocket(iSocketNumber);
                iSocketNumber=-1; 
            }
        }
    }
    else
        iSocketNumber=-1;

    if(iSocketNumber>=0)
    {
        SOCKET_BLOCK(iSocketNumber);
        return iSocketNumber;     
    }
    else
    {
        RefreshWDT(); 
        return -1;
    }
} 

int Ethernet_Receive(int iSocket,char *cInBuf,int iMaxLen,int iTimeout)
{
    /*
    iSocket: Socket number
    *cInBuf: Buffer to store received data
    iMaxLen: Max length to receive
    iTimeout: timeout to receive data (unit: ms)
    
    Return:  >0 : ok, return received data length.
            <=0 : error, doesn't receive any data.
    */
    int iLength;
    
    SOCKET_RXTOUT(iSocket, iTimeout); //set the receive timeout for a connection//
    iLength= recv(iSocket,cInBuf,iMaxLen,0); //MSG_OOB
    
    SOCKET_BLOCK(iSocket);
    YIELD();
    if (iLength>=0)
        cInBuf[iLength]=0;
        
    return iLength;
}

int iLoop=0, iSocket;

void Interrupt_Fun(void)
{
    int iRet;
    
    //DO is used to generate square wave for testing.
    
    iLoop++;
}

int main(void)
{
    int iRet, iLength;
    
    char sInBuffer[100];
    
//Step1. Initate the controller.
    InitLib();
    InstallCom1(115200, 8, 0, 1);
    
//Step2. Initial the Ethernet adapter.
    iRet=Ethernet_Init();
    if(iRet==NoError)
        printCom1("Inint Ethernet ok.\n\r");
    else
        printCom1("Inint Ethernet error.\n\r");
    
//Step3. Connect to remote 7188E/8000E or PC.
    iSocket=Ethernet_Connect("10.0.8.135", 10000, 2000);//TCP port=10000, Timeout=2000 ms.
    if(iSocket>=0)
        printCom1("Connect ok, socket=%d\n\r", iSocket);
    else
        printCom1("Connect error.\n\r");
        
//Step4. Install a timer interrupt function.      
    InstallUserTimerFunction_us(5000, Interrupt_Fun);//install a 1ms timer interrupt.
    
//Step5. Begin the loop function
    for(;;)
    {
        if(iLoop>=6)    //Send "11test" to the remote 7188E/8000E or PC every 5 ms.
        {
            YIELD();
            iRet= send(iSocket, "11test", 6, 0);    //6 bytes, 0:MSG_OOB
            YIELD();
            iLoop=0;
        }    
        
        //Check whether receive any package.
        iLength=Ethernet_Receive(iSocket,sInBuffer, 50, 0);
        if(iLength>0)
        {
            sInBuffer[iLength]=0;
            printCom1("%s", sInBuffer);
            if(iLength!=8)  //Should get "<11test>", totally 8 bytes.
                printCom1("\n\rLength error\n\r");
        }

        //Press any key to terminate the program.
        if(IsCom(1))
        {
            closesocket(iSocket);  
            return 0;
        }
    }
}    