/*
 * Copyright(C) Paul und Scherer (mct.de/mct.net)
 *
 * This example demonstrates how to...
 *
 *  ... communicate with the ethernet
 *      module via telnet (port #23).
 */

#include <conio.h>
#include "../usleep.h"
#include "net.h"

#define SN	(255L<<24|255L<<16|255L<<8|192)	// choose subnet mask
#define GW	(194L<<24| 64L<<16|159L<<8| 65)	//        gateway addr
#define IP	(194L<<24| 64L<<16|159L<<8| 77)	//        IP      addr
#define PN	23				//        port number (telnet)

#define BS	8192				// buffer size
#define BSC	3				//  code
#define MSK	0x1fff				// pointer mask

static unsigned char dbuf[BS];			// data buffer

/*
 * The ethernet module channel 0 is initialized in TCP server mode.
 *
 * On connect, the program keeps listening for data which is simply
 * echoed (loopback). Any key press disconnects.
 *
 * Note: No timeout while waiting for status!
 */
int
main(void)
{
	#define RDS	(rw-rr)			// read  data size
	#define URX	(BS-(rr&MSK))		// upper part of Rx buffer
	#define UTX	(BS-(tw&MSK))		// upper part of Tx buffer

	iic_init();				// initialize IIC bus interface
	while (iic_start(NET)) ;		// wait for NET device ready

	/*
	 * Initialize NET device.
	 */
	net_wl(NET_SMR, SN);			// subnet mask
	net_wl(NET_GAR, GW);			// gateway addr
	net_wl(NET_SIPR, IP);			// IP      addr
	net_wb(NET_RMSR, BSC);			// Rx data mem size
	net_wb(NET_TMSR, BSC);			// Tx data mem size
	net_wb(NET_C0_CR, 1);			// sys_init cmd
	while (!(net_rb(NET_C0_ISR)&1)) ;	// wait for init_ok

	printf("\n"
	       "TCP server\n"
	       "----------\n\n"
	       "     Subnet mask : %3d.%3d.%3d.%3d\n"
	       " Gateway address : %3d.%3d.%3d.%3d\n"
	       "      IP address : %3d.%3d.%3d.%3d\n",
		net_rb(NET_SMR ), net_rb(NET_SMR +1), net_rb(NET_SMR +2), net_rb(NET_SMR +3),
		net_rb(NET_GAR ), net_rb(NET_GAR +1), net_rb(NET_GAR +2), net_rb(NET_GAR +3),
		net_rb(NET_SIPR), net_rb(NET_SIPR+1), net_rb(NET_SIPR+2), net_rb(NET_SIPR+3)
	);

	while (1) {

		/*
		 * Initialize socket.
		 */
		net_wb(NET_C0_SOPR, 1);			// sock_stream(TCP)
		net_ww(NET_C0_SPR, PN);			// port number
		net_wb(NET_C0_CR, 2);			// sock_init cmd
		while (!(net_rb(NET_C0_ISR)&2)) ;	// wait for sinit_ok
		net_wb(NET_C0_CR, 8);			// listen cmd

		printf("\nDisconnected, waiting for connection (port #%d)...\n", net_rw(NET_C0_SPR));

		while (!(net_rb(NET_C0_ISR)&4)) ;	// wait for established

		printf("Connected (%d.%d.%d.%d), received data is echoed...\n",
			net_rb(NET_C0_DIR),
			net_rb(NET_C0_DIR+1),
			net_rb(NET_C0_DIR+2),
			net_rb(NET_C0_DIR+3)
		);

		while (!kbhit() && !(net_rb(NET_C0_ISR)&8)) {
			long rw, rr;				// Rx ptrs
			long tw;				// Tx wptr

			if (!(net_rb(NET_IR)&0x10)) continue;	// no data received

			net_wb(NET_IR, 0x10);			// clear C0R

			/*
			 * Read Rx r/w pointers (first read shadow register
			 * then delay min. 1.6us and read the real pointer).
			 */
			net_rb(NET_C0_SRW_PR), usleep(2), rw = net_rl(NET_C0_RW_PR);
			net_rb(NET_C0_SRR_PR), usleep(2), rr = net_rl(NET_C0_RR_PR);

			/*
			 * Read RDS bytes from RXB to dbuf starting
			 * from rr and wrap around at end of buffer.
			 */
			if ((rr&MSK)+RDS > BS) net_rn(NET_RXB+(rr&MSK), dbuf, URX), net_rn(NET_RXB, dbuf+URX, RDS-URX);
			else net_rn(NET_RXB+(rr&MSK), dbuf, RDS);

			net_wl(NET_C0_RR_PR, rw);		// update Rx rptr
			net_wb(NET_C0_CR, 0x40);		// recv cmd
			while (!(net_rb(NET_C0_ISR)&0x40)) ;	// wait for recv_ok

			printf("Data received (%d)", (int)RDS);

			while (net_rb(NET_C0_CR)&0x20) ;	// finish sending

			/*
			 * Read Tx write pointer (first read shadow register
			 * then delay min. 1.6us and read the real pointer).
			 */
			net_rb(NET_C0_STW_PR), usleep(2), tw = net_rl(NET_C0_TW_PR);

			/*
			 * Write RDS bytes from dbuf to TXB starting
			 * from tw and wrap around at end of buffer.
			 */
			if ((tw&MSK)+RDS > BS) net_wn(NET_TXB+(tw&MSK), dbuf, UTX), net_wn(NET_TXB, dbuf+UTX, RDS-UTX);
			else net_wn(NET_TXB+(tw&MSK), dbuf, RDS);

			net_wl(NET_C0_TW_PR, tw+RDS);		// update Tx wptr
			net_wb(NET_C0_CR, 0x20);		// send cmd

			puts(", and echoed.");
		}
		if (kbhit()) getch();			// remove pending char
		while (net_rb(NET_C0_CR)&0x20) ;	// finish sending

		net_wb(NET_C0_CR, 0x10);		// close cmd
		while (!(net_rb(NET_C0_ISR)&8)) ;	// wait for closed
		net_wb(NET_IR, 0x10);			// clear C0R
	}
}
