/*
1Client.c: Implement one TCP/IP client connection.
           Support one client for TCP port 10001.

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

Compile mode: Large

Project: Client.c
         ..\lib\7186el.Lib
         ..\lib\tcp_dm32.lib
         ..\lib\FW_nnnnn.LIB
         
Hordware: uPAC-7186EX

[Dec 18, 2008] by Liam
*/

#include<conio.h>
#include<stdio.h>
#include "..\lib\7186e.h"
#include "..\lib\Tcpip32.h"
#include "..\lib\MFW.h"

#define BUFSIZE 1460       /* read/write buffer size */

void do_GetResponse( int skt,int mode); //TCP client's callback function
void AutoConnect(int skt);
void ShowSocketStatus(void);

TCP_CLIENT TcpClient=  //Initialize a TCP Client with default IP 10.0.8.157 and port 10001
{
    "10.0.8.16",    //  char *ip;
    10000,      //  unsigned port;
    -1,     //  int socket;      
    0,      //  int tmpState;
    -2,     //  int     bConnected;
    2,      //  int iConnectTryCount;   //連線不成功時重試次數
    5000,       //  long    lConnetTimeout;     //等連線成功的 timeout 時間。(0 就用預設值 400ms)
    0,      //  long    ltmpT;
    do_GetResponse, //void  (*CallBackFun)(int skt);
    AutoConnect, //void (*LoopFun)(int skt);
};

char *GetModuleName(void)   /* User's program must support this function for UDP search */ 
{
    return "uPAC-7186EX-FW";
}

char *GetAliasName(void)    /* User's program must support this function for UDP search */ 
{
    return "test1" ;
} 

unsigned char MyIp[4];
unsigned long ltime1;
unsigned long ltime2;
unsigned long glConectCount;
int Prbconnected,PreTemp;

void XS_UserInit(int argc,char *argv[])
{
    extern int bAcceptBroadcast;
    extern unsigned long ACKDELAY;  /* vaariable in tcp.c */
    extern long MAXTXTOUT;
    extern unsigned long ET_TOUT;
    void UserLoop(void);
    
    char version[20];
    char MsgTest[]="command";
    int MsgTest_len=sizeof(MsgTest); 
    int i,port;
    
    InitLib();
    Print("sizeof(MsgTest)=%d\r\n",MsgTest_len);
    bAcceptBroadcast=0;
    ACKDELAY=200;
    XS_GetVersion(version);
    Print("[X-Server library]: version=%s ",version);
    XS_GetLibDate(version);
    Print("date=%s\r\n",version);
    GetTcpipLibDate(version);
    Print("Tcpip library version:%X, Library Date is %s\r\n",GetTcpipLibVer(),version);
    GetIp(MyIp);
    Print("IP=%d.%d.%d.%d\r\n",MyIp[0],MyIp[1],MyIp[2],MyIp[3]);
    //ET_TOUT=200;
    Print("ET_TOUT =%lu\r\n",ET_TOUT);

    /* for xs_09001.lib ~ xs_09003.lib NEED NOT the next 4 lines. */
    XS_AddSystemLoopFun(UserLoop); /* need add this line for the library 0.9.100 date after 2004/06/02 */
    
    for(i=1; i<argc; i++){ // Process of the arguments
        if(argv[i][0]=='/'){
            switch(argv[i][1]){
                case 'i': case 'I':
                    // set the IP address of the remote server.
                    TcpClient.ip=argv[i]+2;
                    Print("[remote IP=%s]",TcpClient.ip);
                    break;
                case 'p': case 'P':
                    // set the TCP port of the remote server.
                    if(1==sscanf(argv[i]+2,"%i",&port)){
                        TcpClient.port=port;
                        Print("[remote port=%u(%x)]",TcpClient.port,TcpClient.port);
                    }
                    break;
            }
        }
    }
    XS_AddUdpSocket(&XS_UdpSearch);
    bAcceptBroadcast=1;
    
    XS_AddClient(&TcpClient); //Add a client

    XS_AddSystemLoopFun(XS_SocketLoopFun);  
    XS_StartSocket();    //Called on xs09300.lib[2006/09/26] or later 
//  EnableWDT();
    MAXTXTOUT=6000UL; 
    ltime1=GetTimeTicks();  
    Prbconnected=TcpClient.bConnected;
    PreTemp=TcpClient.bConnected;

    Print("user init end: TcpClient.bConnected ==%s %d\r\n", TcpClient.ip, TcpClient.bConnected);
}

void XS_UserEnd(void)
{
    XS_StopSocket();
    DisableWDT();
}

unsigned status_8019as=0;
int Socket0=-1; 
extern int errno;
long st,old_dt;
unsigned char TestData='0';

unsigned long lltime,lchangetime; 
int giprint;

char Command[100];
int idx=0;

void UserLoop(void)
{ 
    long tmpt;
    int key,err;

    RefreshWDT();
    
    /*******************Debug only******************************/  
    if(GetTimeTicks()-ltime1>2000)
    {
        if(giprint)
            Print("TcpClient.bConnected, %d to %d takes %lu ms\r\n",PreTemp,TcpClient.bConnected,lchangetime);
        else
            Print("TcpClient.bConnected = %d\r\n",TcpClient.bConnected); 
        
        Print("TcpClient.iConnectTryCount = %d\r\n", TcpClient.iConnectTryCount); 
        Print("TcpClient.lConnetTimeout = %d\r\n", TcpClient.lConnetTimeout); 
        Print("TcpClient.socket = %d\r\n", TcpClient.socket);
        Print("TcpClient.tmpState = %d\r\n", TcpClient.tmpState); 
        Print("TcpClient.ltmpT = %lu\r\n", TcpClient.ltmpT);
        ltime1=GetTimeTicks();
   
    /*****************Connect to Server automaticaly********************************/
        if(TcpClient.bConnected==-1)
        {
            TcpClient.bConnected=-2;
            Print("Connection automatically\r\n",TcpClient.bConnected);
        }        
    }
    /*******************Debug only******************************/  
  
    if(Prbconnected!=TcpClient.bConnected)
    {
        giprint=1;
        lchangetime=GetTimeTicks()-lltime;
        lltime=GetTimeTicks();
        PreTemp=Prbconnected;
        Prbconnected=TcpClient.bConnected;
    }        
  
    // Check whether any data was inputted to command port or not
    // Command port of uPAC-7186EX is COM1
    if(Kbhit()){
        switch((key=Getch())){ 
            case 27: 
                //Press 'Esc' key to quit the program
                QuitMain=1;
                break;
            
            case 0x32: //'2''
                //Connect to server manually
                if(TcpClient.bConnected==-1)
                    TcpClient.bConnected=-2;
                break;
            
            default:
                //The other data come-in
                Command[idx]=key;
                if(idx<99)
                    idx++;   //Maximum characters of a string ==>99
                    
                Putch(key);
                if(key=='\r'){ 
                    //The terminal character of a string is '\r' (Press 'Enter' key)
                    Command[idx]=0;
                    Putch('\n');
                    if(Command[0]=='/'){    // '/' denotes that the inputted string was a command 
                        if(Command[1]=='Q'){
                            if(TcpClient.bConnected==1)
                                XS_CloseSocket(TcpClient.socket);   // Break the TCP connection
                        }
                        else if(Command[1]=='C'){
                            if(TcpClient.bConnected==-1)
                                TcpClient.bConnected=-2;    // Build the TCP connection
                        }
                        else if(Command[1]=='0' && Command[2]=='0'){
                            ShowSocketStatus();     // Show the socket status
                        }
                        else{
                            Print("Unsupport command\r\n");     // unknow command
                        }
                    }
                    else if(TcpClient.bConnected==1){
                        // The String that isn't the command will send to client
                        err= writesocket(TcpClient.socket,Command,idx);
                        Print(Command);
                        if(err<0){      // write error
                            Print( "write error %d, close client socket.\r\n", err);
                            XS_CloseSocket(TcpClient.socket);
                        }
                    }
                    else
                        Print("[do nothing]\r\n");
                        
                    idx=0;
                }                   
                break;
        }
    }
}

// When connection is establihed, it will be called per user loop
void AutoConnect(int skt)
{
    int err;
    char stemp[64];
  
    if (GetTimeTicks()-ltime2>3000)
    {
        Print("Autoconnect %lu\r\n",glConectCount);
        sprintf(stemp,"Send %lu\r\n",glConectCount++);      
        err=writesocket(skt,stemp,strlen(stemp));
        if(err<0){      // write error
            Print("write error %d, close client socket.\r\n", err);
            XS_CloseSocket(skt);
        }
        
        ltime2= GetTimeTicks();
    } 
}

char buf[BUFSIZE], SendBack[BUFSIZE+2];

// when client is connected, do echo here
void do_GetResponse(int skt, int mode)
{ 
    int i, cc, err, Sendlen;

    if(!mode)
    {
        if(TcpClient.bConnected==1)
        {
            Print("Connected\r\n");
            ltime2=GetTimeTicks();
            glConectCount=0;
        }
        else if(TcpClient.bConnected==-1)
            Print("%s connect failed\r\n",TcpClient.ip);       
    }
    else
    {
        err=cc=readsocket(skt, buf, sizeof(buf)-1);
        if(err<=0){         // error or disconnected by remote side
            Print("%d TcpClient close skt = %d\r\n", err, skt);
            XS_CloseSocket(skt);
        }
        else{
            for(i=0; i<cc; i++){
                Putch(buf[i]);
                if(buf[i]=='\r') Putch('\n');
            }
        }
    }
}

void main(int argc,char *argv[])
{
    XS_main(argc,argv);     // call the XS library main function
}

#define ESTABLISHED   1     // state machine states
#define FINWAIT_1     2
#define FINWAIT_2     3
#define CLOSED_WAIT   4
#define TIMEWAIT      5
#define LAST_ACK      6
#define CLOSED        7
#define SYN_SENT      8
#define SYN_RECEIVED  9
#define LISTEN       16

void ShowSocketStatus(void)
{
    int i;

    Puts("\r\n");
    for(i=0; i<MaxSocketNo; i++){
        Print("[%02d=%02d:", i, connblo[i].state);
        switch(connblo[i].state){
            case ESTABLISHED: Print("ESTABLISHED]"); break;
            case FINWAIT_1: Print("FINWAIT_1]"); break;
            case FINWAIT_2: Print("FINWAIT_2]"); break;
            case CLOSED_WAIT: Print("CLOSED_WAIT]"); break;
            case TIMEWAIT: Print("TIMEWAIT]"); break;
            case LAST_ACK: Print("LAST_ACK]"); break;
            case CLOSED: Print("CLOSED]"); break;
            case SYN_SENT: Print("SYN_SENT]"); break;
            case SYN_RECEIVED: Print("SYN_RECEIVED]"); break;
            case LISTEN: Print("LISTEN]"); break;
            case 0: Print("NOT_USED_YET]"); break;
            default: Print("!!!UnKnown STATE!!!]"); break;
        }
        
        Print(",stat=%x", connblo[i].blockstat);
        if(i & 1)
            Print("\r\n");
        else
            Print(" , ");
    }
}
