/********************************************************************
	ssi2.c
   Z-World, 2002

	This program demonstrates a basic Smart Star system running
	a WEB page.  It assumes you have Relay, ADC and DAC Voltage cards.

	The WEB page consists of three switches to open and close relays
	with indicator lights, three sets of up and down arrows to increase
	or	decrease analog output, and a monitor of three analog inputs.
		
  	This program is based on the "samples/tcpip/ssi.c" program.
        
	System setup
   ------------
   1. Install relay, DAC and ADC cards into Slots 0, 1, 2.

   2. Connect wires from DAC output channels to ADC input channels.
   
			DAC 0 <---> ADC 0      
			DAC 1 <---> ADC 1      
			DAC 2 <---> ADC 2      

   3. Connect V_USER to +RAW on backplane.
           
	Program Instructions
   --------------------
	1. Make all necessary changes in the configuration section.
   2. Compile and run this program.
	3. With your WEB browser access the WEB page running on the
      controller.
	4.	Select the slots where each card occupies and submit selections.
	5. Click a switch.  You should hear a relay switch contact.
	6. Click an arrow button to increase or decrease analog output.
		You should see the output monitored by the analog input.
		
********************************************************************/

// MACROS for the LED's
#define ON     1
#define OFF    0

#define LED0   0
#define LED1   1
#define LED2   2
#define LED3   3

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

/*
 * Change this value to your default gateway.  If you do
 * not correctly set this you will not be able to serve
 * pages outside your local network.
 *
 */
#define MY_GATEWAY      "10.10.6.1"

/*
 * You must change the following values to whatever
 * your local IP address and netmask are. Contact your
 * network administrator for these numbers.
 */
#define MY_IP_ADDRESS   "10.10.6.1"
#define MY_NETMASK      "255.255.255.0"

/*
 * TCP/IP modification - reduce TCP socket buffer
 * size, to allow more connections. This can be increased,
 * with increased performance, if the number of sockets
 * are reduced.  Note that this buffer size is split in
 * two for TCP sockets--1024 bytes for send and 1024 bytes
 * for receive.
 */
#define TCP_BUF_SIZE 2048
#define FORM_ERROR_BUF 256

/*
 * Web server configuration
 */

/*
 * only one socket and server are needed for a reserved port
 */
#define HTTP_MAXSERVERS 1
#define MAX_TCP_SOCKET_BUFFERS 1


/*
 * Our web server as seen from the clients.
 * This should be the address that the clients (netscape/IE)
 * use to access your server. Usually, this is your IP address.
 * If you are behind a firewall, though, it might be a port on
 * the proxy, that will be forwarded to the Rabbit board. The
 * commented out line is an example of such a situation.
 */

#define REDIRECTHOST  MY_IP_ADDRESS

//#define REDIRECTHOST  "demo.zweng.com:8240"

/********************************
 * End of configuration section *
 ********************************/

/*
 *  REDIRECTTO is used by each ledxtoggle cgi's to tell the
 *  browser which page to hit next.  The default REDIRECTTO
 *  assumes that you are serving a page that does not have
 *  any address translation applied to it.  
 *
 */

#define REDIRECTTO  "http://" REDIRECTHOST "/index.shtml"

#memmap xmem
#use "dcrtcp.lib"
#use "http.lib"

/*
 *  Notice that we have ximported in the source code for
 *  this program.  This allows us to <!--#include file="ssi.c"-->
 *  in the pages/showsrc.shtml.
 *
 */

#ximport "samples/smrtstar/tcpip/pages/ssi2.shtml"		index_html
#ximport "samples/smrtstar/tcpip/pages/rabbit1.gif"   rabbit1_gif
#ximport "samples/smrtstar/tcpip/pages/ledon.gif"     ledon_gif
#ximport "samples/smrtstar/tcpip/pages/ledoff.gif"    ledoff_gif
#ximport "samples/smrtstar/tcpip/pages/button.gif"    button_gif
#ximport "samples/smrtstar/tcpip/pages/uparrow.gif"   uparrow_gif
#ximport "samples/smrtstar/tcpip/pages/dnarrow.gif"   dnarrow_gif
#ximport "samples/smrtstar/tcpip/pages/showsrc.shtml" showsrc_shtml
#ximport "samples/smrtstar/tcpip/ssi2.c"           	ssi_c


/*
 *  In this case the .html is not the first type in the 
 *  type table.  This causes the default (no extension)
 *  to assume the shtml_handler.
 *
 */

/* the default for / must be first */
const HttpType http_types[] =
{
   { ".shtml", "text/html", shtml_handler}, // ssi
   { ".html", "text/html", NULL},           // html
   { ".cgi", "", NULL},                     // cgi
   { ".gif", "image/gif", NULL}
};

/*
 *  Each ledx contains a text string that is either
 *  "ledon.gif" or "ledoff.gif"  This string is toggled
 *  each time the ledxtoggle.cgi is requested from the 
 *  browser.
 *
 */

char led_LED0[15];
char led_LED1[15];
char led_LED2[15];
char led_LED3[15];
char relaycard[15];
char adccard[15];
char daccard[15];
char rcselected[15];
char dcselected[15];
char acselected[15];
char rcslotvalue[15];
char dcslotvalue[15];
char acslotvalue[15];
int relayslot, dacslot, adcslot;
int initdacflag, initadcflag, initrelayflag;
float dac0value, dac1value, dac2value;
float adc0value, adc1value, adc2value;
const static char* slotoptions[] =
{
	"Slot 0",
	"Slot 1",
	"Slot 2"
};

#define MAX_FORMSIZE	16
typedef struct {
	char name[MAX_FORMSIZE];
	char value[MAX_FORMSIZE];
} FORMType;
#define MAXSLOTS 3
FORMType FORMSpec[MAXSLOTS];

/*
 *  Instead of sending other text back from the cgi's
 *  we have decided to redirect them to the original page.
 *  the cgi_redirectto forms a header which will redirect
 *  the browswer back to the main page.
 *
 */

int led_toggle0(HttpState* state)
{
	
	if (initrelayflag)
	{
	   if (strcmp(led_LED0,"ledon.gif")==0)
  		{
      	strcpy(led_LED0,"ledoff.gif");
			relayOut(ChanAddr(relayslot, 0),0);	//off
		}
	   else
   	{
      	strcpy(led_LED0,"ledon.gif");
	     	relayOut(ChanAddr(relayslot, 0),1);	//on
   	}
	}
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

int led_toggle1(HttpState* state)
{
	
	if (initrelayflag)
	{
	   if (strcmp(led_LED1,"ledon.gif")==0)
	  	{
   	   strcpy(led_LED1,"ledoff.gif");
			relayOut(ChanAddr(relayslot, 1),0);	//off
		}
   	else
	   {
   	   strcpy(led_LED1,"ledon.gif");
     		relayOut(ChanAddr(relayslot, 1),1);	//on
   	}	
	}
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

int led_toggle2(HttpState* state)
{
	
	if (initrelayflag)
	{
	   if (strcmp(led_LED2,"ledon.gif")==0)
	  	{
   	   strcpy(led_LED2,"ledoff.gif");
			relayOut(ChanAddr(relayslot, 2),0);	//off
		}
   	else
	   {
   	   strcpy(led_LED2,"ledon.gif");
     		relayOut(ChanAddr(relayslot, 2),1);	//on
	   }
	}
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

int dac0inc(HttpState* state)
{
	if (initdacflag)
	{
		dac0value+=0.25;
		anaOutVolts(ChanAddr(dacslot, 0), dac0value);
	}  	
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

int dac1inc(HttpState* state)
{
	if (initdacflag)
	{
		dac1value+=0.25;
		anaOutVolts(ChanAddr(dacslot, 1), dac1value);
	}  	
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

int dac2inc(HttpState* state)
{
	if (initdacflag)
	{
		dac2value+=0.25;
		anaOutVolts(ChanAddr(dacslot, 2), dac2value);
	}
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

int dac0dec(HttpState* state)
{
	if (initdacflag)
	{
		dac0value-=0.25;
		anaOutVolts(ChanAddr(dacslot, 0), dac0value);
  	}
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

int dac1dec(HttpState* state)
{
	if (initdacflag)
	{
		dac1value-=0.25;
		anaOutVolts(ChanAddr(dacslot, 1), dac1value);
	}  	
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

int dac2dec(HttpState* state)
{
	if (initdacflag)
	{
		dac2value-=0.25;
		anaOutVolts(ChanAddr(dacslot, 2), dac2value);
	}
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

/*
 * Parse one token 'foo=bar', matching 'foo' to the name field in
 * the struct, and storing 'bar' into the value
 */
void parse_token(HttpState* state, int select)
{
	int i, len;

	for(i=0; i<HTTP_MAXBUFFER; i++) {
		if(state->buffer[i] == '=')
			state->buffer[i] = '\0';
	}
	state->p = state->buffer + strlen(state->buffer) + 1;
	
	strncpy(FORMSpec[select].name, state->buffer, strlen(state->buffer));
	FORMSpec[select].name[strlen(state->buffer)] = '\0';
	strncpy(FORMSpec[select].value, state->p, strlen(state->p));
	FORMSpec[select].value[strlen(state->p)] = '\0';
	
/*	for(i=0; i<(sizeof(FORMSpec)/sizeof(FORMType)); i++)
	{
		if (!strcmp(FORMSpec[i].name,state->buffer))
		{
			len = (strlen(state->p)>MAX_FORMSIZE) ? MAX_FORMSIZE - 1: strlen(state->p);
			strncpy(FORMSpec[i].value, state->p, 1+len);
			FORMSpec[i].value[MAX_FORMSIZE - 1] = '\0';
		}
	}*/
}

/*
 * parse the url-encoded POST data into the FORMSpec struct
 * (ie: parse 'foo=bar&baz=qux' into the struct
 */
int parse_post(HttpState* state)
{
	int retval, i;

	i=0;
	while(1)
	{
		retval = sock_fastread(&state->s, state->p, 1);
		if (0 == retval)
		{
			*state->p = '\0';
			parse_token(state, i);
			
			return 1;
		}

		/* should this only be '&'? (allow the eoln as valid text?) */
		if ((*state->p == '&') || (*state->p == '\r') || (*state->p == '\n'))
		{
			/* found one token */
			*state->p = '\0';
			parse_token(state, i);
			i++;
			state->p = state->buffer;
		}
		else
		{
			state->p++;
		}
			
		if ((state->p - state->buffer) > HTTP_MAXBUFFER)
		{
			/* input too long */
			return 1;
		}
		
	}

	return 0; /* end of data - loop again to give it time to write more */
}


int setslot(HttpState* state)
{

int i, slot;

	state->p = state->buffer;

	parse_post(state);
			
	state->substate++;

	for (slot=0; slot<(sizeof(FORMSpec)/sizeof(FORMType)); slot++)
	{
		if (strcmp(FORMSpec[slot].value, "-1"))
		{
			if (!strcmp(FORMSpec[slot].name, "relaycard"))
			{
				relayslot = atoi(FORMSpec[slot].value);
				strcpy(rcselected, slotoptions[relayslot]);
				strcpy(rcslotvalue, FORMSpec[slot].value);
				initrelayflag=1;
			}
		
			if (!strcmp(FORMSpec[slot].name, "daccard"))
			{
				dacslot = atoi(FORMSpec[slot].value);
				strcpy(dcselected, slotoptions[dacslot]);
				strcpy(dcslotvalue, FORMSpec[slot].value);
		   	//get calibration constants
				for (i=0; i<8; i++)
				{
					anaOutEERd(ChanAddr(dacslot, i));
				}	
				anaOutEnable();
				anaOutVolts(ChanAddr(dacslot, 0), dac0value);
				anaOutVolts(ChanAddr(dacslot, 1), dac1value);
				anaOutVolts(ChanAddr(dacslot, 2), dac2value);
				initdacflag=1;
			}
				
			if (!strcmp(FORMSpec[slot].name, "adccard"))
			{
				adcslot = atoi(FORMSpec[slot].value);
				strcpy(acselected, slotoptions[adcslot]);
				strcpy(acslotvalue, FORMSpec[slot].value);
	   		//get calibration constants
				for (i=0; i<11; i++)
				{
					anaInEERd(ChanAddr(adcslot, i));
				}	
				initadcflag=1;
			}
		}
	}
	cgi_redirectto(state,REDIRECTTO);
   return 0;      
}


const HttpSpec http_flashspec[] = 
{
   { HTTPSPEC_FILE,  "/",              index_html,    NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/index.shtml",   index_html,    NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/showsrc.shtml", showsrc_shtml, NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/rabbit1.gif",   rabbit1_gif,   NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/ledon.gif",     ledon_gif,     NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/ledoff.gif",    ledoff_gif,    NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/button.gif",    button_gif,    NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/uparrow.gif",   uparrow_gif,   NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/dnarrow.gif",   dnarrow_gif,   NULL, 0, NULL, NULL},

   { HTTPSPEC_FILE,  "ssi.c",          ssi_c,         NULL, 0, NULL, NULL},

   { HTTPSPEC_VARIABLE, "led_LED0",  0,    led_LED0, PTR16,   "%s", NULL},
   { HTTPSPEC_VARIABLE, "led_LED1",  0,    led_LED1, PTR16,   "%s", NULL},
   { HTTPSPEC_VARIABLE, "led_LED2",  0,    led_LED2, PTR16,   "%s", NULL},
   { HTTPSPEC_FUNCTION, "/led_LED0.cgi",   0, led_toggle0, 0, NULL, NULL},
   { HTTPSPEC_FUNCTION, "/led_LED1.cgi",   0, led_toggle1, 0, NULL, NULL},
   { HTTPSPEC_FUNCTION, "/led_LED2.cgi",   0, led_toggle2, 0, NULL, NULL},
   
   { HTTPSPEC_VARIABLE, "relaycard",   0,  &relaycard, PTR16, "%s", NULL},
   { HTTPSPEC_VARIABLE, "adccard",   0,  &adccard, PTR16, "%s", NULL},
   { HTTPSPEC_VARIABLE, "daccard",   0,  &daccard, PTR16, "%s", NULL},
   { HTTPSPEC_VARIABLE, "rcselected",   0,  &rcselected, PTR16, "%s", NULL},
   { HTTPSPEC_VARIABLE, "dcselected",   0,  &dcselected, PTR16, "%s", NULL},
   { HTTPSPEC_VARIABLE, "acselected",   0,  &acselected, PTR16, "%s", NULL},
   { HTTPSPEC_VARIABLE, "rcslotvalue",   0,  &rcslotvalue, PTR16, "%s", NULL},
   { HTTPSPEC_VARIABLE, "dcslotvalue",   0,  &dcslotvalue, PTR16, "%s", NULL},
   { HTTPSPEC_VARIABLE, "acslotvalue",   0,  &acslotvalue, PTR16, "%s", NULL},
   { HTTPSPEC_FUNCTION, "setslot.cgi",   0, setslot, 0, NULL, NULL},
   
   { HTTPSPEC_VARIABLE,"dac0value",  0,   &dac0value, FLOAT32,   "%.2f", NULL},
   { HTTPSPEC_VARIABLE, "dac1value",  0,   &dac1value, FLOAT32,   "%.2f", NULL},
   { HTTPSPEC_VARIABLE, "dac2value",  0,	 &dac2value, FLOAT32,   "%.2f", NULL},
   { HTTPSPEC_VARIABLE, "adc0value",  0,   &adc0value, FLOAT32,   "%.2f", NULL},
   { HTTPSPEC_VARIABLE, "adc1value",  0,   &adc1value, FLOAT32,   "%.2f", NULL},
   { HTTPSPEC_VARIABLE, "adc2value",  0,	 &adc2value, FLOAT32,   "%.2f", NULL},
   
   { HTTPSPEC_FUNCTION, "/dac0up.cgi",   0, dac0inc, 0, NULL, NULL},
   { HTTPSPEC_FUNCTION, "/dac1up.cgi",   0, dac1inc, 0, NULL, NULL},
   { HTTPSPEC_FUNCTION, "/dac2up.cgi",   0, dac2inc, 0, NULL, NULL},
   { HTTPSPEC_FUNCTION, "/dac0dn.cgi",   0, dac0dec, 0, NULL, NULL},
   { HTTPSPEC_FUNCTION, "/dac1dn.cgi",   0, dac1dec, 0, NULL, NULL},
   { HTTPSPEC_FUNCTION, "/dac2dn.cgi",   0, dac2dec, 0, NULL, NULL},
};


int updateADC(HttpState* state)
{
   if (initadcflag)
   {
	  	adc0value = anaInVolts(ChanAddr(adcslot, 0));
  		adc1value = anaInVolts(ChanAddr(adcslot, 1));
	  	adc2value = anaInVolts(ChanAddr(adcslot, 2));
	}
   cgi_redirectto(state,REDIRECTTO);
   return 0;      
}

main()
{
HttpState* state;
	
   // initialize the controller
   brdInit();
	initdacflag=initadcflag=initrelayflag=0;
	dac0value=0.0;
	dac1value=1.25;
	dac2value=2.0;
	adc0value=adc1value=adc2value=0.0;
	
   // set the initial state of the LED's 
   strcpy(led_LED0,"ledoff.gif");  ledOut(LED0, OFF);
   strcpy(led_LED1,"ledoff.gif");  ledOut(LED1, OFF);
   strcpy(led_LED2,"ledoff.gif");  ledOut(LED2, OFF);
	strcpy(rcselected, "Choose");
	strcpy(dcselected, "Choose");
	strcpy(acselected, "Choose");
	strcpy(rcslotvalue, "-1");
	strcpy(dcslotvalue, "-1");
	strcpy(acslotvalue, "-1");

   sock_init();
   http_init();
   tcp_reserveport(80);

   // process WEB page requests and update the LED's
   while (1) {
      //update_leds();
      updateADC(state);
      http_handler();
   }
}

