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

	udp_echo.c
	Copyright (C) Z-World, 2001
	
	Demonstrate use of the DeviceMate to send UDP datagrams.

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

 	In addition, a UDP echo server must be running on some other
	machine at ports 7656 (and 7657, if TWOSOCK defined).  This
	can be changed.
	
******************************************************/

/*
 * These definitions for this demo only.
 */
#define TWOSOCK
#define REMOTE_HOST "10.10.6.178"
#define REMOTE_PORT 7656

/* 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 BOOFSIZE 500
char buf[BOOFSIZE];
char buf2[BOOFSIZE];
char rxbuf[BOOFSIZE];
char rxbuf2[BOOFSIZE];
char msgbuf[80];

#define NTX 2000
	
int main()
{
	int rc;
	int socket, socket2;
	int len, len2;
	uint16 request_id;
	int ntx, ntx2;
	int nrx, nrx2;
	uint16 dgtx, dgtx2;
	uint16 dgrx, dgrx2;
	uint32 rhost;
	uint16 rport;
	uint32 stamp;
	uint32 rxto, rxto2;

	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
	 */
reopen_1:
	while (!(socket = devmate_udp_open(1, 0, REMOTE_HOST, REMOTE_PORT)))
		devmate_tick();
	if (socket < 0) {
		printf("Failed devmate_udp_open.\n");
		goto reopen_1;
	}
#ifdef TWOSOCK
reopen_2:
	while (!(socket2 = devmate_udp_open(2, 0, REMOTE_HOST, REMOTE_PORT+1)))
		devmate_tick();
	if (socket2 < 0) {
		printf("Failed devmate_udp_open 2.\n");
		goto reopen_2;
	}
#endif

	while (!devmate_tcp_isestablished(socket));
	printf("Established...\n");
#ifdef TWOSOCK
	while (!devmate_tcp_isestablished(socket2));
	printf("Established 2...\n");
#endif


	/*
	 * Write a string to the socket and read it back (assuming
	 * talking to echo server).
	 */
	memset(buf, '*', sizeof(buf));
	for (rc = 0; rc < BOOFSIZE; rc += 5) {
		sprintf(msgbuf, "%03d", rc);
		memcpy(buf + rc, msgbuf, 3);
	}
		
	//printf("Sending1: '%s'\n", buf);
#ifdef TWOSOCK
	memset(buf2, '%', sizeof(buf2));
	for (rc = 0; rc < BOOFSIZE; rc += 5) {
		sprintf(msgbuf, "%03d", rc);
		memcpy(buf2 + rc, msgbuf, 3);
	}
	//printf("Sending2: '%s'\n", buf2);
#endif
	len = len2 = sizeof(buf);
	ntx = 0;
	ntx2 = 0;
	nrx = 0;
	nrx2 = 0;
	dgtx = 0;
	dgtx2 = 0;
	dgrx = 0;
	dgrx2 = 0;


	if (devmate_tcp_error(socket)) {
		printf("Could not resolve\n");
		dgrx = NTX;
	}
#ifdef TWOSOCK
	if (devmate_tcp_error(socket2)) {
		printf("Could not resolve 2\n");
		dgrx2 = NTX;
	}
#endif

	while (dgrx < NTX
#ifdef TWOSOCK
			|| dgrx2 < NTX
#endif
			) {
		if (dgtx < NTX /*&& (dgrx == dgtx || MS_TIMER > rxto)*/) {
			rc = devmate_udp_send(socket, buf, len, ntx);
			if (rc < 0) {
				printf("Failed devmate_udp_sendto %d.\n", devmate_tcp_error(socket));
				exit(22);
			}
			ntx = rc;
			if (ntx == len) {
				//printf("Sent (1) %u bytes\n", ntx);
				ntx = 0;
				dgtx++;
				rxto = MS_TIMER + 2000;
				len-=100;
				if (len < 50)
					len = 500;
			}
		}

#ifdef TWOSOCK
		if (dgtx2 < NTX /*&& (dgrx2 == dgtx2 || MS_TIMER > rxto2)*/) {
			rc = devmate_udp_send(socket2, buf2, len2, ntx2);
			if (rc < 0) {
				printf("Failed 2 devmate_udp_sendto %d.\n", devmate_tcp_error(socket2));
				exit(22);
			}
			ntx2 = rc;
			if (ntx2 == len2) {
				//printf("Sent (2) %u bytes\n", ntx2);
				ntx2 = 0;
				dgtx2++;
				rxto2 = MS_TIMER + 2000;
				len2-=75;
				if (len2 < 75)
					len2 = 500;
			}
		}
#endif

		rc = devmate_udp_recvfrom(socket, &rhost, &rport);
		if (rc < 0) {
			printf("Failed devmate_udp_recvfrom %d.\n", devmate_tcp_error(socket));
			exit(23);
		}
		if (rc || rport) {
			// Read datagram in 'blocking' mode
			printf("Got (1) %u bytes from host %lX port %u\n", rc, rhost, rport);
			if (dgrx & 1) {
				nrx = 0;
				while (nrx < rc) {
					nrx = devmate_udp_recvdata(socket, rxbuf, sizeof(rxbuf), nrx);
					if (nrx < 0) {
						printf("Failed devmate_udp_recvdata %d.\n", devmate_tcp_error(socket));
						break;
					}
				}
			}
			dgrx++;
		}
		
#ifdef TWOSOCK
		rc = devmate_udp_recvfrom(socket2, &rhost, &rport);
		if (rc < 0) {
			printf("Failed 2 devmate_udp_recvfrom %d.\n", devmate_tcp_error(socket2));
			break;
		}
		if (rc || rport) {
			printf("Got (2) %u bytes from host %lX port %u\n", rc, rhost, rport);
			if (dgrx2 & 1) {
				// Read datagram in 'blocking' mode (every 2nd time)
				nrx2 = 0;
				while (nrx2 < rc) {
					nrx2 = devmate_udp_recvdata(socket2, rxbuf2, sizeof(rxbuf2), nrx2);
					if (nrx2 < 0) {
						printf("Failed 2 devmate_udp_recvdata %d.\n", devmate_tcp_error(socket2));
						break;
					}
				}
			}
			dgrx2++;
		}
#endif		
		devmate_tick();
	}

	printf("Sent (1) %u, received %u\n", dgtx, dgrx);
#ifdef TWOSOCK
	printf("Sent (2) %u, received %u\n", dgtx2, dgrx2);
#endif

	/*
	 * Close the socket.
	 */

	devmate_udp_close(socket);
#ifdef TWOSOCK
	devmate_udp_close(socket2);
#endif

	printf("All done\n");

	while (1) {
		devmate_tick();
	}
	
	return 0;
}