/* ********************************
  DEMO1: 8000 TCP/IP DIO demo
  File name: demo1.c
  Compiler: Borland C++ 3.1
  Compile mode: large
  Simple Command set for this Demo
  DO command
   #SiDDDD for 16 bit DO modules example:I-8056,I-8057
   #SiDD for 8 bit DO modules example:I-8054,I-8068
   # => command header
   S => Slot variable
   i => slot number
   DD => byte data
   DDDD => WORD data
   for example #S055AA => send the Data 0x55aa to slot 0
  DI command
   $Si => Read DI and DO read back
   $ => command header
   S => Slot variable
   i => slot number
   for example $S1 => read the DI from slot 1
   If user want to add his program
	just modify the function "User_Program".
	
The Differences between	iPAC-8000 library and old library are as below:
1. call GetIP,GetIP2 and etc function to get Network configuration from eeprom ,not GeSaveIP and lhip
   (GeSaveIP and lhip have been removed on the iPAC-8000 library ,the GetIP and etc function is defind at 8000a.h)
2.For iPAC-8000 , there is no need to deal with Ninit() and Portinit (NetStart function replaces then)     
	
  ********************************* */



#include <stdlib.h>
#include <stdio.h>
#include <alloc.h>
#include "Lib\vp2k.h"
#include "Lib\vp2k_lcd.h"
#include "Lib\tcpip32.h"
#include "Lib\MFS.h"

#define BUFSIZE 1024       /* read/write buffer size */
#define SERVICE 10000      /* define the service port for Server */
#define SOCKETS 32         /* define the maximum number of sockets */
#define QLEN    SOCKETS-1  /* maximum connection queue length */




int es;       /* flag to run ES (service loop) */
fd_set rfds;  /* set of socket file descriptors for reading */

typedef struct socket_state {
  int                active;  /* socket is active */
  int                init;    /* socket just initiated */
  struct sockaddr_in sin;     /* client address */
} socket_state;
socket_state sst[SOCKETS];    /* sockets state table */
//DIODATA DIODATA;
  char Message1[]="connected successful.";
  char ErrorMessage[]="Command Error!";
 //unsigned long far *TimeTicks=(unsigned long far *)0x0040006CL;

int User_Program(int skt,char *buf,int cc);
void killsockets(void);
/*************************************************************************
 * killsockets
 * clear, shutdown, and close all sockets
 *************************************************************************/
void killsockets()
{
  int i;
  FD_ZERO( &rfds );  /* clear FD set */

  for (i = 0; i < SOCKETS; i++) {
	if (sst[i].active) {       /* if socket lives, kill it */
	  shutdown( i, 0 );
	  closesocket( i );
	}
  }
}
/*************************************************************************
 * do_echo
 *
 * when client is connected, do echo here  or process message
 * Add the user process program here.
 *************************************************************************/
int do_echo( int skt )
{
  int i, cc, err=0;
  char buf[BUFSIZE];

  if (sst[skt].init)
  {
	sst[skt].init = 0;/* socket is just initiated */
	return err;
  }

   //err = cc = readsocket( skt, buf, strlen(buf)/*sizeof(buf)*/ );
  err = cc = recv( skt, buf, sizeof(buf),0 );// Read Socket data
  buf[cc] = '\0';
 if (err == 0)/* disconnected */
  {
	 shutdown( skt, 0 );//shutdown socket
	 closesocket( skt );//close socket
	 FD_CLR( skt, &rfds );//clear setting
	 sst[skt].active = 0;
	 return err;
  }

  if (err < 0)/* read error */
  {
	shutdown( skt, 0 );//shutdown socket
	closesocket( skt );//close socket
	FD_CLR( skt, &rfds );//clear setting
	sst[skt].active = 0;
	return err;
  }
//This send back is not necessary for every one
//_____________________________________________________
 err= send(skt,buf,cc,0);//echo string
 if(err < 0)
 {               /* write error */
	Print( "echo write error %d\n\r", err );
	shutdown( skt, 0 );
	closesocket( skt );
	FD_CLR( skt, &rfds );
	sst[skt].active = 0;
	return err;
 }
//_____________________________________________________
//force to terminal this program
 if (!strcmp("down", buf))
 {  /* shutdown echo server */
	es = 0;
	Print( "Server is Terminal\n\r");
	return err;
 }
// *************************************************************************/
 err = User_Program(skt,buf,cc);
// *************************************************************************/
 return err;
}

/*************************************************************************
 * main
 * program main routine
 *************************************************************************/

int   RxCounter=0;
int   RxCounterOut=0;

//struct ip host_ip =    { {192,168,255,2},{255,255,0,0} };
struct ip host_0 =  { {192,168,0,2},{255,255,255,0}};
struct ip host_1 =  { {192,168,0,3},{255,255,255,0}};
struct ip *host_ip[2]={&host_0,&host_1};

struct ip gateway_0 =  { {192,168,0,1},{255,255,255,0}};
struct ip gateway_1 =  { {192,168,0,1},{255,255,255,0}};
struct ip *gateway_ip[2]={&gateway_0,&gateway_1};
extern struct NETDATA *NetHost[2],*NetGateway[2];


main( int argc, char *argv[] )
{
  struct sockaddr_in ssin; /* client Internet endpoing address */
  int sin_len;             /* length of sockaddr_in */
  int s;                   /* master socket for listenning */
  int ss;                  /* slave socket got from accept */
  int type, protocol, err=0;

  int rc;                  /* return code of selectsocket */
  int i,ret,ver,SlotType;

//  unsigned long far *IntVectMain=(unsigned long far *)0x00000000L;

  struct timeval   seltime;
  unsigned char cIP_Net[4];
  unsigned char cMASK_Net[4];
  unsigned char cGATEWAY_Net[4];
  unsigned char cIP_Net2[4];
  unsigned char cMASK_Net2[4];
  unsigned char cGATEWAY_Net2[4];

	Print("------------Open 8000-----------\n\r");
	ver=GetLibVersion();
	Print("Library version is %d.%02d\n\r",ver>>8,ver&0xff);
	SlotType = GetNumberOfSlot();//slot4 or slot8
	Print("Current Slot Type = %d\n\r",SlotType);

  	InitLib();
  	mfs_Init();	
  	NetStart();
  /***************************************
   * Network Environment *
   ***************************************/
   	// call GetIP,GetIP2 and etc function to get Network configuration from eeprom (not GeSaveIP and lhip)
    GetIp(cIP_Net);
	Print("IP= %d.%d.%d.%d\n",cIP_Net[0],cIP_Net[1],cIP_Net[2],cIP_Net[3]);
	GetMask(cMASK_Net);
	Print("MASK= %d.%d.%d.%d\n",cMASK_Net[0],cMASK_Net[1],cMASK_Net[2],cMASK_Net[3]);
	GetGateway(cGATEWAY_Net);
	Print("GATEWAY= %d.%d.%d.%d\n",cGATEWAY_Net[0],cGATEWAY_Net[1],cGATEWAY_Net[2],cGATEWAY_Net[3]);

	GetIp2(cIP_Net2);
	Print("IP2= %d.%d.%d.%d\n",cIP_Net2[0],cIP_Net2[1],cIP_Net2[2],cIP_Net2[3]);
	GetMask2(cMASK_Net2);
	Print("MASK2= %d.%d.%d.%d\n",cMASK_Net2[0],cMASK_Net2[1],cMASK_Net2[2],cMASK_Net2[3]);
	GetGateway2(cGATEWAY_Net2);
	Print("GATEWAY2= %d.%d.%d.%d\n",cGATEWAY_Net2[0],cGATEWAY_Net2[1],cGATEWAY_Net2[2],cGATEWAY_Net2[3]);



/* For iPAC-8000 , there is no need to deal with Ninit() and Portinit (NetStart function replace then)  */
/*
#if 0
  err = Ninit();          
  if (err < 0)
  {
	Print( "Ninit() failed! error %d\n\r", err );
	return err;
  }
	Print( "Ninit() Successful! \n\r");

  err = Portinit( "*" );  
  if (err < 0)
  {
	Print( "Portinit() failed! error %d\n\r", err );
	Nterm();
	return err;
  }
	Print( "Portinit()  Successful! \n\r");
#endif
*/
   /**************************
   * allocate master socket *
   **************************/
  type = SOCK_STREAM;  /* TCP/IP */
  protocol = 0;        /* always 0 */
  err = s = socket( PF_INET, type, protocol );
  if (s < 0)
  {
	Print( "can't create socket! error %d\n\r", err );
	Nterm();
	return err;
  }
	Print( "create socket seccessful!\n\r");
  /********************************
   * addressing for master socket *
   ********************************/
  memset( &sst[s].sin, 0, sizeof(sst[s].sin) ); /* bzero is a unix system call */
  sst[s].sin.sin_family = AF_INET;
  sst[s].sin.sin_addr.s_addr = 0; /* INADDR_ANY is a 32bits zero value */
  sst[s].sin.sin_port = htons( SERVICE );

  /*******************
   * bind the socket *
   *******************/
  err = bind( s, (struct sockaddr *)&sst[s].sin, sizeof(sst[s].sin) );
  if (err < 0)
  {
	Print( "can't bind to port %d, error %d\n\r", SERVICE, err );
	closesocket( s );
	Nterm();
	return err;
  }
	Print( "bind to port %d seccessful!\n\r",SERVICE);

  /******************
   * make listening *
   ******************/
  err = listen( s, QLEN );
  if (type == SOCK_STREAM && err < 0)
  {
	closesocket( s );
	Nterm();
	return err;
  }
	Print( "Now Listening!\n\r");

  /**********
   * select *
   **********/
  FD_ZERO( &rfds );
  es = 1;
  for (i = 0; i < SOCKETS; i++)
  {
	sst[i].active = 0;
	sst[i].init   = 0;
  }
  sst[s].active = 1;  /* master socket is active */
  sin_len = sizeof( ssin );
  seltime.tv_sec=0;
  seltime.tv_usec=0;
// Main service loop
	Print( "Now Service loop!\n\r");
  while (es)
  {
	for (i = 0; i < SOCKETS; i++)
	{
		if (sst[i].active)
		{  /* re-join active sockets */
			FD_SET( i, &rfds );
		}
	}
	rc = selectsocket( SOCKETS, &rfds, NULL, NULL, &seltime  );//check the socket come in
	if (rc < 0)
	{
	   Print( "selectsocket error %d\n\r", rc );
	   break;
	}
	if( !rc )//no socket come in , continue waitting
	   continue;
	//some sockets come in
	for (i = 0; i < SOCKETS; i++)
	{  /* scan all possible sockets */
		if (FD_ISSET(i, &rfds))
		{
			if (i == s)
			{  /* master socket */
				memset( &ssin, 0, sizeof(ssin) );
				err = ss = accept( s, (struct sockaddr *)&ssin, &sin_len );
				if (err < 0)
				{
					Print( "accept error %d\n\r", err );
					break;
				}
				err=send( ss, Message1, strlen(Message1), 0 );//send connection message to client
				FD_SET( ss, &rfds );//set the setting
				sst[ss].active = 1;//active
				sst[ss].init   = 1;
				memcpy( &sst[ss].sin, &ssin, sin_len );
			}
			else
			{       /* slave socket */
				do_echo( i );//The client connection is accept and distribution to socket i
							//So the user can read the message(may be command string or other)
							//from the socket i.
							//remember each clinet connection If it is accept by this server
							//will cause one socket. So the maximun socket (connection) is 31.
							//In the other word, This server can be connected by 31 client maximun.
							//for the detail to read string,please refer to function "do_echo()".
			}
		}
	}
  }  /* service loop */
  killsockets();//will end the program
  Nterm();//close ethernet
  return err;
}
void Echo_Result(int skt,char *buf,int clen)
{
	int err;
	err=send( skt,buf,clen, 0 );//send message to client
	if(err < 0)
	{               /* write error */
		Print( "echo write error %d\n\r", err );
		shutdown( skt, 0 );
		closesocket( skt );
		FD_CLR( skt, &rfds );
		sst[skt].active = 0;
	}

}

int User_Program(int skt,char *buf,int clen)
{
// skt => client socket
// *buf => Client message
// clen => message Length
// Add user's control process program here
// and delete the below codes.
	DIODATA DIOData[8];
	int slot,dodata;
	char OutBuf[60];
	switch(buf[0])
	{
		case '$'://DI function this command string is not standard,user can define itself.
			  switch(buf[1])
			  {
				case 'S':case 's'://slot
					slot=ascii_to_hex(buf[2]);
					switch(NameOfModule[slot])
					{
						case 51:case 53://16 bit DI
							DIOData[slot].data16=DI_16(slot);
							sprintf(OutBuf,"%04X",DIOData[slot].data16);
							Echo_Result(skt,OutBuf,strlen(OutBuf));//send message to client
						break;
						case 56:case 57://16 bit DO read back
							sprintf(OutBuf,"%04X",DIOData[slot].data16);
							Echo_Result(skt,OutBuf,strlen(OutBuf));//send message to client
						break;
						case 54:case 55://8bit DI and 8 bit DO read back
							DIOData[slot].data8.di8=DI_8(slot);
							sprintf(OutBuf,"%04X",DIOData[slot].data16);
							Echo_Result(skt,OutBuf,strlen(OutBuf));//send message to client
						break;
						default:
							Echo_Result(skt,ErrorMessage,strlen(ErrorMessage));//send message to client
						break;
					}
				break;
				default:
					Echo_Result(skt,ErrorMessage,strlen(ErrorMessage));//send message to client
				break;
			  }
		break;
		case '#'://DO function
			  switch(buf[1])
			  {
				case 'S':case 's'://slot
					slot=ascii_to_hex(buf[2]);
					switch(NameOfModule[slot])
					{
						case 56:case 57://16 bit DO
							dodata = (ascii_to_hex(buf[3])<<12)+(ascii_to_hex(buf[4])<<8)
									+(ascii_to_hex(buf[5])<<4)+ascii_to_hex(buf[6]);
							DIOData[slot].data16=dodata;
							DO_16(slot,dodata);
							Echo_Result(skt,">",1);//send message to client
						break;
						case 54:case 55://8bit Do
							dodata = (ascii_to_hex(buf[3])<<4)+ascii_to_hex(buf[4]);
							DIOData[slot].data8.do8=dodata;
							DIO_DO_8(slot,dodata);
							Echo_Result(skt,">",1);//send message to client
						break;
						default:
							Echo_Result(skt,ErrorMessage,strlen(ErrorMessage));//send message to client
						break;
					}
				break;
				default:
					Echo_Result(skt,ErrorMessage,strlen(ErrorMessage));//send message to client
				break;
			  }
		break;
	}

 return 0;
}
