/*
   Copyright (c) 2015, Digi International Inc.

   Permission to use, copy, modify, and/or distribute this software for any
   purpose with or without fee is hereby granted, provided that the above
   copyright notice and this permission notice appear in all copies.

   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/**********************************************************
	echo_client.c

	This program is used with RCM3200 series controllers.
	
	The sample library, rcm3200.lib, contains a brdInit()
	function which initializes port pins. Modify this
	function to fit your application.

	Description
	===========
   This program demonstrates a basic client which will
	send a packet and wait for the server connect to echo
	it back.  After every number of sends and receives,
	transfer times are shown in the stdio window.
        
   Use echo_server.c to program a server controller.

   This program was adapted from \Samples\TCPIP\echo.c.
   
	Instructions
	============
   1. Modify the TCPCONFIG, REMOTE_IP, REMOTE_PORT,
      and MY_PORT to the appropriate settings for the
      network.
	2. Compile and run this program.
	
**********************************************************/
#class auto

#use rcm3200.lib    		//sample library used for this demo

//#define DCRTCP_DEBUG		// display tcp/ip debugging information
//#define DCRTCP_VERBOSE	// allow stepping through tcp/ip functions

/***********************************
 * Configuration                   *
 * -------------                   *
 * All fields in this section must *
 * be altered to match your local  *
 * network settings.               *
 ***********************************/

/*
 * Pick the predefined TCP/IP configuration for this sample.  See
 * LIB\TCPIP\TCP_CONFIG.LIB for instructions on how to set the
 * configuration.
 */
#define TCPCONFIG 1

#define MY_PORT			2222

//************************************************************************************************
#define	ETH_MTU		 1000
#define  BUFF_SIZE	 (ETH_MTU-40)		//must be smaller than (ETH_MTU - (IP Datagram + TCP Segment))
#define  TCP_BUF_SIZE ((ETH_MTU-40)*4)	// sets up (ETH_MTU-40)*2 bytes for Tx & Rx buffers

//************************************************************************************************
#memmap xmem
#use "dcrtcp.lib"

#define REMOTE_IP			"10.10.6.1"
#define REMOTE_PORT 		1111
#define NUM_OF_SENDS		1000
#define TIME_OUT			5000	// if in any state for more than a X milliseconds re-initialize

#define	RED		"\x1b[31m"	// foreground colors for printf
#define	GREEN		"\x1b[32m"	// foreground colors for printf
#define	BLUE		"\x1b[34m"	// foreground colors for printf

tcp_Socket sock;
int bytes,i,j;
long statetime;
static char buff[BUFF_SIZE];

///////////////////////////////////////////////////////////////////////

int receive_packet(void)
{
	/* receive the packet */
	bytes = sock_fastread(&sock,buff,BUFF_SIZE);
	switch(bytes)
	{
		case -1:
			return 4; // there was an error go to state 4 (WAIT_CLOSE)
		case  0:
			return 3; // connection is okay, but no data received, stay in RECEIVE state
		default:
			i--;
			statetime = MS_TIMER+TIME_OUT;	// reset time to be in the SEND state
			return 2;	//now go to state 2 (SEND)
	}
}

int send_packet(void)
{
	/* send a packet */
	memset(buff,'C',BUFF_SIZE);	// fill buffer with C's
	buff[BUFF_SIZE-1] = '\n';		// null terminate the buffer
	
	if(i<=0)
		return 3;
	
	bytes = sock_fastwrite(&sock,buff,BUFF_SIZE);
	switch(bytes)
	{
		case -1:
			return 2; // there was an error stay in SEND state and try again
		default:
			printf("%s%06d\r",BLUE,j++);		// number of packets send
			statetime = MS_TIMER+TIME_OUT;	// reset time to be in the RECEIVE state
			return 3;	//now go to state 3 (RECEIVE)
	}
}

void main()
{
	int state,status;
	long start;
	float endtime,TimePerTrans,TimePerByte,TimePerBit,BitsPerTime;
	state = 0;

	sock_init();
	
	while(1)
	{
		switch(state)
		{
			case 0:/*CREATE SESSION*/
				if(!tcp_open(&sock,MY_PORT,resolve(REMOTE_IP),REMOTE_PORT,NULL))
					printf("%sERROR OPENNING SOCKET!\n",RED);
				else
				{
					printf("%ssession created\n",GREEN);
					printf("%swaiting for socket to be established\n",GREEN);
					statetime = MS_TIMER+TIME_OUT;	// setup the time to be LISTEN state
					state++;									// complete move onto next state
					i = NUM_OF_SENDS;
					j=0;										// contains the number of packets sent
				}
				break;
			case 1:/*LISTEN*/
				if(sock_established(&sock))			// check for a connection
				{
					printf("%ssocket established\n",GREEN);
					start = MS_TIMER;						// time socket was established
					statetime = MS_TIMER+TIME_OUT;	// reset time to be in the SEND state
					state++;									//  we have connection so move on
				}
				else if ((long)(MS_TIMER-statetime) > 0)	// if time out and no sock
					state = 4;										//	  abort and re-init
				break;
			case 2:/*SEND*/
				state = send_packet();					// see function for details
				if ((long)(MS_TIMER-statetime) > 0) // if X millisecs and still waiting
					state = 4;								//	  abort and re-init
				break;
			case 3:/*RECEIVE*/
				state = receive_packet();				// see function for details
				if ((long)(MS_TIMER-statetime) > 0) // if X millisecs and still waiting
					state = 4;								//	  abort and re-init
				break;
			case 4:/*NO_WAIT_CLOSE*/
				printf("%sABORT SOCKET\n",RED);
				sock_abort(&sock);						// close the socket
				state = 0;									// go back to the INIT state
				printf("\n");
		}
		status = tcp_tick(&sock);
		
		if(i==0)
		{
			endtime = (float)(MS_TIMER-start)/(float)1000;
			TimePerTrans = endtime/(float)(NUM_OF_SENDS*2);
			TimePerByte	 = TimePerTrans/(float)BUFF_SIZE;
			TimePerBit	 = TimePerByte/(float)8;
			BitsPerTime	 = (float)1/TimePerBit;
			
			printf("%s\nTotal Transfer Time:	%+fsec\n",GREEN,endtime);
			printf("Time per Trans:	%+fsec/trans\n",TimePerTrans);
			printf("Time per Byte:	%+fsec/Byte\n", TimePerByte);
			printf("Time per Bit:	%+fsec/bit\n",  TimePerBit);
			printf("Bits per Time:	%+fbits/sec\n", BitsPerTime);
			i--;
			state = 4;
		}
	}	
}
