#include <string.h>

#include "xparameters.h"
#include "xintc.h"
#include "xbasic_types.h"
#include "xgpio.h"
#include "xtmrctr.h"
#include "xemaclite.h"

#include "lwip_lib.h"

#define MAX_RECV_SIZE (1024)
#define MAX_SEND_SIZE (1460)

char* helloMsg = "\n\r\n\r\n\rWelcome to the echo server!\n\r";

int main()
{
	
	//make sure your stack is big enough for all of these variables!
	//recv_data is 1k by itself!
	uint8 ip[] = {192,168,0,30};
	int loopCt = 0;
	int i = 0;
	int recv_data_len = 0;
	int data_len = 0;
	uint8 recv_data[MAX_RECV_SIZE];
	uint8 *myBuf, *newBuf;
	
	xil_printf("\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n");

	xil_printf("Configure HyperTerminal to telnet to 192.168.0.30 on port 23.\n\r");
	xil_printf("* If you click the _Call_ icon, you should be connected.\n\r");
	xil_printf("* When you type a char, it should be printed here and echoed to telnet.\n\r");
	xil_printf("* If you click the _Hangup_ icon, the connection should be lost.\n\r");

	// Perform all the startup functions in one fell swoop
	// parameters:                  mac, ip, netmsk, gw, port, #bufs,  bufsize,     recvBufSize
	myBuf = lwip_lib_full_startup( NULL, ip, NULL,  NULL, 23,    15,  MAX_SEND_SIZE, MAX_RECV_SIZE );

	//Some notes:
	//* port 23 is a standard telnet port
	//* lwip lib will interact with the hardware using the "CANONICAL" definitions in xparameters.h:
	//	- XPAR_INTC_0_DEVICE_ID
	//	  o XPAR_INTC_0_EMACLITE_0_VEC_ID
	//	  o XPAR_INTC_0_TMRCTR_0_VEC_ID
	//	- XPAR_TMRCTR_0_DEVICE_ID
	//	- XPAR_EMACLITE_0_DEVICE_ID
	//
	// * the default MAC and subnet as defined in lwip_lib.c
	//   - uint8 DEFAULT_MAC[] = {0x00, 0x00, 0x00, 0x00, 0x22, 0x38};
	//   - uint8 DEFAULT_SUBNET[] = {0xFF, 0xFF, 0xFF, 0x00};
	
	//lwip_lib returns a buffer to fill for tx during initialization. if this is
	//NULL, then there was some error.
	if ( myBuf == NULL ) {
		xil_printf("Problem starting up.  Quitting.\r\n");
		exit(1);
	}
	
	xil_printf("Started lwip_lib ok\r\n");

	//Start interrupts up
	//lwip_lib and lwip configure interrupts, but the main program
	//enables them for the entire processor.
	microblaze_enable_interrupts();

	//Loop forever, accepting connections, and providing an echo server
	//when a connection is made.
	loopCt = 0;
	while(1)
	{
		//Wait for someone to connect to us.
		//lwip_lib_is_connected is a non-blocking function that will return
		//if we are connected. lwip_lib has configured lwip to prepare to 
		//receive a connection on the port specified in lwip_lib_full_startup.
		while( lwip_lib_is_connected() == XFALSE ) { }
	
		loopCt++;
		xil_printf("New connection started (%d made total)\r\n", loopCt);
			
		//When a new connection is made, lwip_lib cleans up it's internal
		//transmit buffer structure. So, even if we had a valid buffer
		//before the connection closed, we need to ask lwip_lib what the
		//current buffer is. This is done by calling the
		//lwip_lib_send_data(...) function with a NULL buffer parameter.
		myBuf = lwip_lib_send_data( NULL, 0 );

		//when we actually send data, lwip_lib will give us a new buffer.
		//we will assign this output to newBuf, because we will want to
		//check it for status before we fill it with data to transmit.
		newBuf = NULL;
		
		//We just made a new connection, so print the welcome message.
		//We have external memory, so we went crazy any used string.h!
		strcpy(myBuf, helloMsg);
		data_len = strlen(myBuf);
		
		// Send the data out and get a new buffer
		newBuf = lwip_lib_send_data( myBuf, data_len );
		if ( newBuf == NULL ) {
			xil_printf(" **** ERR: No buffer to write to!\r\n");
		} else if ( newBuf == myBuf ) {
			xil_printf(" **** ERR: Couldn't send buffer!\r\n");
		}
		myBuf = newBuf;
				
		while(1) {
			//Don't continue echo server if we have lost connection.
			if ( lwip_lib_is_connected() == XFALSE ) {
				xil_printf("Lost Connection!  Quitting\r\n");
				break;
			}
	
			// The application can receive data in this buffer
			recv_data_len = lwip_lib_receive_data( recv_data );
			//if we received some data, print it, and copy it to our
			//transmit buffer. This is a very ineffcient way to do the
			//copy (really use something like memcpy(...) in string.h,
			//and presumes our TX buffer size >= RX buffer size (which
			//is how this program is configured).
			if ( recv_data_len != 0 ) {

				xil_printf("Received data: ");
				for( i=0; i<recv_data_len; i++ ) {
					xil_printf("%02x",recv_data[i]);
					myBuf[i] = recv_data[i];
				}
				xil_printf("\r\n");
				
				// Send the data out and get a new buffer
				newBuf = lwip_lib_send_data( myBuf, recv_data_len );
				if ( newBuf == NULL ) {
					xil_printf(" **** ERR: No buffer to write to!\r\n");
				} else if ( newBuf == myBuf ) {
					xil_printf(" **** ERR: Couldn't send buffer!\r\n");
				}
				myBuf = newBuf;
				
			}
	
		}

		lwip_lib_close_connection();
		xil_printf("Done transmitting\r\n");

	}	

	//We should never get here
	while(1);
	return 0;
}

