/*
   Copyright (c) 2015, Digi International Inc.

   Permission to use, copy, modify, and/or distribute this software for any
   purpose with or without fee is hereby granted, provided that the above
   copyright notice and this permission notice appear in all copies.

   THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
/*******************************************************************************
        ucos.c

        A sample combining use of the TCP/IP stack (specificly, the web
        server) with uC/OS. This creates two tasks; one counts from 0 to
        15 in binary on the demo-board LEDs, and another that runs the web
        server that allows you to inspect the current state of the LEDs.
*******************************************************************************/
#class auto

/*
 * This sample requires setting up the demo board as well, as it blinks the LEDs.
 * Instructions on how to set this up can be found in samples/tcpip/http/ssi3.c
 */
  
/***********************************
 * Configuration                   *
 * -------------                   *
 * All fields in this section must *
 * be altered to match your local  *
 * network settings.               *
 ***********************************/

/*
 * Pick the predefined TCP/IP configuration for this sample.  See
 * LIB\TCPIP\TCP_CONFIG.LIB for instructions on how to set the
 * configuration.
 */
#define TCPCONFIG 1

/*
 * 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

/*
 * Web server configuration
 */

/*
 * Only one server is needed for a reserved port
 */
#define HTTP_MAXSERVERS 1
#define MAX_TCP_SOCKET_BUFFERS 1

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

/* MCOS configuration */
#define OS_MAX_TASKS           2  		// Maximum number of tasks system can create (less stat and idle tasks)
#define OS_MAX_EVENTS			 3			// MAX_UDP_SOCKET_BUFFERS + MAX_TCP_SOCKET_BUFFERS + 2
#define OS_SEM_EN					 1			// Enable semaphores
#define OS_TIME_DLY_HMSM_EN	 1			// Enable OSTimeDlyHMSM
#define STACK_CNT_256			 2			// LED update task + main()
#define STACK_CNT_2K         	 1			// TCP/IP needs a 2K stack

/*
 * IMPORTANT NOTE!
 *
 * It is important to note that the TCP/IP task REQUIRES a 2K stack!
 * This is because the function resolve() (a DNS lookup) creates a
 * udp socket on the stack. If DNS lookups are NOT needed, and
 * resolve() is never called, it is possible to run the TCP/IP stack
 * in only a 1K stack.
 *
 * Also note, all TCP/IP stack functions should be call from ONE (1)
 * thread only, or data corruption and/or system instability may result!
 */

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

/*
 * web page & graphics, for use in the web server
 */
#ximport "samples/tcpip/http/pages/ucos.shtml"      index_html
#ximport "samples/tcpip/http/pages/ledon.gif"      ledon_gif
#ximport "samples/tcpip/http/pages/ledoff.gif"     ledoff_gif

/*
 *  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 led1[15];
char led2[15];
char led3[15];
char led4[15];
char counter;	/* real counter for our lights */

/* 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}
};

const HttpSpec http_flashspec[] = 
{
   { HTTPSPEC_FILE,  "/",              index_html,    NULL, 0, NULL, NULL},
   { HTTPSPEC_FILE,  "/index.shtml",   index_html,    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_VARIABLE, "led1",  0,    led1, PTR16,   "%s", NULL},
   { HTTPSPEC_VARIABLE, "led2",  0,    led2, PTR16,   "%s", NULL},
   { HTTPSPEC_VARIABLE, "led3",  0,    led3, PTR16,   "%s", NULL},
   { HTTPSPEC_VARIABLE, "led4",  0,    led4, PTR16,   "%s", NULL},
};

/*
 *	Sets up the IO ports for our use.
 */
void io_init()
{
	// initialize port b
	WrPortI(PBDR, &PBDRShadow, 0x3f&PBDRShadow);			//set outputs 0 and 1

	// initialize port d
	WrPortI(PDDDR, &PDDDRShadow, 0x03|PDDDRShadow);		//set bits 0,1 to output
	WrPortI(PDDCR, &PDDCRShadow, 0xfc&PDDCRShadow);		//outputs driven hi/lo
	WrPortI(PDFR, &PDFRShadow, 0xf0&PDFRShadow);			//i/o normal
	WrPortI(PDDR, &PDDRShadow, 0xfc&PDDRShadow);			//set outputs 2 and 3
}

/*
 *	This function looks at 'counter', decodes it into binary, and
 * updates both the LEDs and the ledx[] arrays, indicating the
 * current status to the web server.
 */
void update_LEDs()
{
	// store the bit-pattern for the number 
	// and update the hardware LEDs
	if(counter & 0x08) {
	   strcpy(led1,"ledon.gif");
		WrPortI(PDDR, &PDDRShadow, 0x01|PDDRShadow);
	} else {
	   strcpy(led1,"ledoff.gif");
		WrPortI(PDDR, &PDDRShadow, 0xfe&PDDRShadow);
	}

	if(counter & 0x04) {
	   strcpy(led2,"ledon.gif");
		WrPortI(PDDR, &PDDRShadow, 0x02|PDDRShadow);
	} else {
	   strcpy(led2,"ledoff.gif");
		WrPortI(PDDR, &PDDRShadow, 0xfd&PDDRShadow);
	}

	if(counter & 0x02) {
	   strcpy(led3,"ledon.gif");
		WrPortI(PBDR, &PBDRShadow, 0x40|PBDRShadow);
	} else {
	   strcpy(led3,"ledoff.gif");
		WrPortI(PBDR, &PBDRShadow, 0xbf&PBDRShadow);
	}

	if(counter & 0x01) {
	   strcpy(led4,"ledon.gif");
		WrPortI(PBDR, &PBDRShadow, 0x80|PBDRShadow);
	} else {
	   strcpy(led4,"ledoff.gif");
		WrPortI(PBDR, &PBDRShadow, 0x7f&PBDRShadow);
	}
}

/*
 *	One of our two tasks. This is a simulation of a real-time
 * thread, manipulating the hardware, and posts data for the
 * other thread to moniter.
 *
 * This task simply updates the hardware and delays for two
 * seconds, to give a nice slow count.
 */
void blink_lights(void *ptr)
{
	for(;;) {
		counter++;
		if(counter > 15)
			counter = 0;

		update_LEDs();

		OSTimeDlyHMSM(0, 0, 2, 0); // delay a bit to slow down the count
	}		
}

/*
 * This task runs the web server, by callin http_hander(). Access to
 * the ledx[] arrays is allready indicated in the http_flashspec structure.
 */
void web_server(void *ptr)
{
	/* All TCP/IP stuff (ie: the web server) needs to be in one task only. */
	/* This is ok, as the only TCP/IP stuff we are doing is running the web server */
	for(;;) {
		http_handler();
	}
}

main()
{
	INT8U error;

	OSInit();

	io_init();			// init the LEDs
	sock_init();		// init the TCP/IP stack
	http_init();		// init the web server
	tcp_reserveport(80);
	
	/* shut off all LEDs (set count to 0, and display it in binary) */
	counter = 0;
	update_LEDs();
	
	/* Build the two tasks */
	error = OSTaskCreate(web_server, 	NULL, 2048, 1);
	error = OSTaskCreate(blink_lights,	NULL, 256, 0);

	/* start it all running */
	OSStart();
}