/*****************************************************

	pas_open.c
	Copyright (C) Z-World, 2001
	
	Demonstrate use of DeviceMate to perform TCP on our
	behalf.  Shows use of passive open (listen) by implementing
	a server which returns "Hello world", then echoing whatever
	is received.

 	The \samples\dmunit\tcp.c program must be running on the
	DeviceMate processor.

 	When running, you will need to use another machine to telnet
	to port 1234 of the DeviceMate.
	
******************************************************/

/* Request use of TCP services */
#define USE_TC_TCPIP

/*
 * Uncomment this line if this program will be loaded over ethernet. This will
 * force the DevMate communication to use serial port A, re-using the programming
 * link that was used to download the program.
 */
//#define USE_TC_LOADER

#ifdef CC_VER
	/* Dynamic C */
	#memmap xmem
	#use "tc_conf.lib"
#else
	/* Non-Rabbit */
	#include "tc_conf.h"
	#include <stdio.h>	
#endif


#define NSOCK 1			/* Define bigger to accept more connections.
									Port numbers will be 1234, 1235, 1236... */

#define BOOFSIZE 256
char buf[NSOCK][BOOFSIZE];
char rxbuf[NSOCK][BOOFSIZE];
	
int main()
{
	int rc;
	int sock, sm1;
	int nrx, num_rx[NSOCK];
	int ntx, num_tx[NSOCK];
	int len;
	char * b, * rxb;
	int st, state[NSOCK];
#define S_LISTEN	1
#define S_DATE		2
#define S_ECHO		3
#define S_CLOSE	4
#define S_CLOSING	5
#define S_CLOSED	6
#define S_ERROR	7


	printf("Initializing 1...\n");
	devmate_init();

	/* Initialize TCP. */
	printf("2...\n");
	rc = devmate_sock_init(NULL, NULL, NULL, NULL, NULL, NULL);
	if (rc <= 0) {
		printf("Failed devmate_sock_init.\n");
		exit(20);
	}

	/*
	 * Open sockets in passive mode
	 */
	for (sock = 0; sock < NSOCK; sock++) {
		state[sock] = S_CLOSED;
	}

	for (sock = 1;;) {
		sm1 = sock - 1;
		st = state[sm1];
		b = &buf[sm1][0];
		rxb = &rxbuf[sm1][0];
		ntx = num_tx[sm1];
		nrx = num_rx[sm1];

		switch (st) {
			case S_LISTEN:
				if (devmate_tcp_isestablished(sock)) {
					printf("Socket %d established\n", sock);
					st = S_DATE;	// fall thru
					strcpy(b, "Hello world\n");
				}
				else
					break;
			case S_DATE:
				len = strlen(b);
				if (ntx == len) {
					ntx = 0;
					printf("Socket %d going to echo\n", sock);
					st = S_ECHO;
					break;
				}
				rc = devmate_tcp_fastwrite(sock, b+ntx, len-ntx);
				if (rc < 0) {
					printf("fastwrite error sock %d\n", sock);
					st = S_CLOSE;
					break;
				}
				ntx += rc;
				break;
			case S_ECHO:
				len = sizeof(rxbuf[0]);
				if (len > nrx) {
					rc = devmate_tcp_fastread(sock, rxb+nrx, len-nrx);
					if (rc < 0) {
						printf("fastread error sock %d\n", sock);
						st = S_CLOSE;
						break;
					}
					nrx += rc;
				}
				if (nrx > ntx) {
					rc = devmate_tcp_fastwrite(sock, rxb+ntx, nrx-ntx);
					if (rc < 0) {
						printf("fastwrite echo error sock %d\n", sock);
						st = S_CLOSE;
						break;
					}
					ntx += rc;
					if (rc) {
						len = nrx - ntx;
						memcpy(rxb, rxb+ntx, len);
						nrx -= ntx;
						ntx = 0;
					}
				}
				break;
			case S_CLOSE:
				devmate_tcp_close(sock);
				printf("socket %d closing...\n", sock);
				st = S_CLOSING;
			case S_CLOSING:
				if (devmate_tcp_isclosed(sock)) {
					printf("...socket %d closed.\n", sock);
					st = S_CLOSED;
					// fall thru;
				}
				else
					break;
			case S_CLOSED:
				if ((rc = devmate_tcp_listen(sock, 1234+sm1, NULL, 0)) > 0) {
					printf("Socket %d listening\n", sock);
					st = S_LISTEN;
					ntx = 0;
					nrx = 0;
				}
				else if (rc < 0) {
					printf("Listen failed\n");
					st = S_CLOSE;
				}
				break;
		}
		
		devmate_tick();

		state[sm1] = st;
		num_tx[sm1] = ntx;
		num_rx[sm1] = nrx;
		sock++;
		if (sock == NSOCK+1)
			sock = 1;
	}

	printf("All done\n");
	
	return 0;
}