/* ------------------------------------------------------------------------------------------------ */
/* FILE :		Demo_110-113_CY5_A9_GCC.c															*/
/*																									*/
/* CONTENTS :																						*/
/*				Demo for the Zynq ZedBoard															*/
/*																									*/
/*				Compared to Demos #10->13, Demos #110->113 use the CMSIS OS API						*/
/*																									*/
/*				Demo #110 - Webserver using netconn with memory base file system					*/
/*				Demo #111 - Webserver using BSD sockets with memory base file system				*/
/*				Demo #112 - Webserver using netconn with micro-SD FatFS								*/
/*				Demo #113 - Webserver using BSD sockets with micro-SD FatFS							*/
/*																									*/
/*				Serial port settings:																*/
/*							Baud Rate: 115200														*/
/*							Data bits:      8														*/
/*							Stop bits:		1														*/
/*							Parity:      none														*/
/*							Flow Ctrl:   none														*/
/*							Emulation:   none														*/
/*																									*/
/*																									*/
/* Copyright (c) 2014, Code-Time Technologies Inc. All rights reserved.								*/
/*																									*/
/* Code-Time Technologies retains all right, title, and interest in and to this work				*/
/*																									*/
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS							*/
/* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF										*/
/* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL							*/
/* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR								*/
/* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,							*/
/* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR							*/
/* OTHER DEALINGS IN THE SOFTWARE.																	*/
/*																									*/
/*																									*/
/*	$Revision: 1.5 $																				*/
/*	$Date: 2014/03/12 16:59:36 $																	*/
/*																									*/
/* ------------------------------------------------------------------------------------------------ */

#if (((OS_DEMO) < 110) || ((OS_DEMO) > 113))
	#error "Wrong OS_DEMO value" 
#endif

#include <stdio.h>
#include "cmsis_os.h"
#include "WebServer.h"
#include "xparameters.h"
#include "xuartps_hw.h"

/* ------------------------------------------------ */

#define BAUDRATE	115200							/* Serial port baud rate						*/
#define SYS_FREQ	666666667						/* Processor clock frequency: 666 MHz			*/

#define DHCP_TASK_PRIO   	osPriorityNormal		/* Priority of the DHCP task					*/
#define LED_TASK_PRIO    	osPriorityLow			/* Priority of the LED flashing task			*/

#define USE_FAT_FS	(((OS_DEMO)==112)||((OS_DEMO)==113))
#define USE_SOCKET	(((OS_DEMO)==111)||((OS_DEMO)==113))

/* ------------------------------------------------ */

#if (USE_FAT_FS)
  DIR      g_Dir;
  FATFS    g_FileSys;
#endif

XGpio G_GpioButton;									/* Buttons gpio descriptor						*/
XGpio G_GpioLed;									/* LEDs gpio descriptor							*/
XGpio G_GpioSwitch;									/* Switches gpio descriptor						*/

int G_TaskLed7off;

/* ------------------------------------------------ */

int  GetKey(void);									/* Non-blocking keyboard input					*/
void EMACintHndl(void);								/* Emac interrupt, call XEmacsPS with argument	*/
extern void XEmacPs_IntrHandler(void *XEmacPsPtr);	/* Xilinxs EMAC interrupt handler				*/
int  __putchar(int);
void TIMERinit(unsigned int Reload);
void UARTinit(int BaudRate);
void TaskLed7(const void *Arg);
void TaskMain(const void *Arg);

osThreadDef(LwIP_DHCP_task, DHCP_TASK_PRIO, 1, 4096);
osThreadDef(TaskLed7, LED_TASK_PRIO,  1, 2048);
osThreadDef(TaskMain, osPriorityRealtime, 1, 4096);

osThreadId G_TaskMainID;


/* ------------------------------------------------------------------------------------------------ */

int main(void)
{
/* ------------------------------------------------ */
/* UART set-up										*/

	setvbuf(stdin,  NULL, _IONBF, 0);				/* By default, Newlib library flush the I/O		*/
	setvbuf(stdout, NULL, _IONBF, 0);				/* buffer when full or when new-line			*/

	putchar('\n');
	putchar('\n');

	while (0 != GetKey());							/* Remove stuff left in the UART RX buffer		*/

/* ------------------------------------------------ */
/* LED & switches setup								*/

	XGpio_Initialize(&G_GpioLed, XPAR_LED_DEVICE_ID);
	XGpio_SetDataDirection(&G_GpioLed, 1, 0);
	XGpio_DiscreteWrite(&G_GpioLed, 1, 0);			/* Turn off all the LEDs						*/

	XGpio_Initialize(&G_GpioButton, XPAR_BUTTON_DEVICE_ID);
	XGpio_SetDataDirection(&G_GpioButton, 1, 0xFFFFFFFF);

	XGpio_Initialize(&G_GpioSwitch, XPAR_SWITCH_DEVICE_ID);
	XGpio_SetDataDirection(&G_GpioSwitch, 1, 0xFFFFFFFF);

/* ------------------------------------------------ */
/* Start Abassi										*/

	osKernelStart(osThread(TaskMain), (void *)1234);

	for(;;);
}

/* ------------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------------ */
/* ------------------------------------------------------------------------------------------------ */

void TaskMain(const void *Arg)
{
char AddrTxt[32];
int  ii;											/* General purpose								*/
int  LastWait;										/* Last elapse time (to update display)			*/
char TimeMsg[] = "  DHCP in 5s.     ";				/* Message line to refresh every seconds		*/
int  WaitTime;										/* Elapsed time waiting for key pressed			*/

	G_TaskMainID  = osThreadGetId();				/* Needed by NetAddr.c and httpserver-xxxx.c	*/
	G_TaskLed7off = 0;								/* CGI_SSI controls the LEDs. No suspend in		*/
													/* CMSIS, so use a flag instead					*/
/* ------------------------------------------------ */
/* SysTick Set-up									*/

	OSisrInstall(29, TIMtick);						/* Install the OS timer tick function			*/
	TIMERinit(((((SYS_FREQ/2)/100000)*OS_TIMER_US)/(10)));
	GICenable(29, 128, 1);							/* Private timer interrupt ID is 29 prio=mid	*/

/* ------------------------------------------------ */
/* Attach the Ethernet interrupt handler			*/

	OSisrInstall(54, EMACintHndl);					/* Install the Ethernet interrupt				*/
	GICenable(54, 128, 1);							/* Enable the Ethernet interrupt				*/

/* ------------------------------------------------ */
/* MMC file system mounting							*/

  #if (USE_FAT_FS)
	OSisrInstall(56, MMCintHndl);					/* Install the MMC driver interrupt handler		*/
	GICenable(56, 128, 0);
  #endif

	OSeint(1);

/* ------------------------------------------------ */
/* Allow user selection static or dynamic address	*/

	puts("  lwIP  Webserver   ");
  #if (USE_SOCKET)
	puts("  with BSD sockets  ");
  #else
	puts("    with netconn    ");
  #endif
  #if (USE_FAT_FS)
	puts("   using MMC FAT FS ");
  #else
	puts("   using memory FS  ");
  #endif
	puts("Will use DHCP unless");
	puts("key pressed on UART ");
	puts(" or button pressed  ");

/* ------------------------------------------------ */
/* Default static Addresses & Mask					*/

	NetAddr_Init();

/* ------------------------------------------------ */
/* UART prompt and key pressed check				*/

	WaitTime = G_OStimCnt;
	LastWait = -1;
	do {
		ii = (1000*(G_OStimCnt-WaitTime))
		   / OS_TICK_PER_SEC;
		if (LastWait != (5999-ii)/1000) {
			LastWait = (5999-ii)/1000;
			TimeMsg[10] = '0' + LastWait;
			printf("\r%s", &TimeMsg[0]);
		}

		G_IPnetStatic = GetKey()					/* Check if user pressed a key					*/
		              | (0 != BUTTON_ALL());		/* or a press button							*/
	} while((ii < 5000)								/* Check for 5 seconds							*/
	  &&    (G_IPnetStatic == 0));					/* Or until a key is pressed					*/

	printf("\r                             \n");	/* Erase the remaining time from UART screen	*/

/* ------------------------------------------------ */
/* EMAC & lwIP initialization						*/

	LwIP_Init();
	http_server_init();

/* ------------------------------------------------ */
/* DHCP task creation								*/

	if (G_IPnetStatic == 0) {
		osThreadCreate(osThread(LwIP_DHCP_task), NULL);
	}

	osThreadCreate(osThread(TaskLed7), NULL);

	osSignalWait(3, osWaitForever);					/* Wait for Ethernet & file system to be ready	*/

	MTXLOCK_STDIO();
	puts("The Webserver is ready");
	MTXUNLOCK_STDIO();


	for( ;; ) {
		osThreadTerminate(osThreadGetId());
	}
}

/* ------------------------------------------------------------------------------------------------ */

void TaskLed7(const void *Arg)
{
int Toggle;

	Arg    = Arg;
	Toggle = 0;
	for( ;; ) {
		if (G_TaskLed7off == 0) {
			if(Toggle == 0) {
				LED_OFF(MY_LED_7);
			}
			else {
				LED_ON(MY_LED_7);
			}
		}
		Toggle = !Toggle;
		osDelay(250);
	}
}

/* ------------------------------------------------------------------------------------------------ */

void IdleTask(void)
{
	for(;;) {
		 __asm(" wfi");
	}
}

/* ------------------------------------------------------------------------------------------------ */

void TIMcallBack(void)
{
	return;
}

/* ------------------------------------------------------------------------------------------------ */

void EMACintHndl(void)
{
XScuGic_Config           *CfgPtr;
XScuGic_VectorTableEntry *TablePtr;
extern XScuGic_Config     XScuGic_ConfigTable[];

	CfgPtr   = &XScuGic_ConfigTable[0];
	TablePtr = &(CfgPtr->HandlerTable[54]);
	if (NULL != TablePtr->Handler) {
		TablePtr->Handler(TablePtr->CallBackRef);
	}

	return;
}

/* ------------------------------------------------------------------------------------------------ */
/* Private timer set-up																				*/
/* ------------------------------------------------------------------------------------------------ */

void TIMERinit(unsigned int Reload)
{

volatile unsigned int *TimReg;

	TimReg    = COREgetPeriph();					/* Private timer is at base of Peripherals		*/
	TimReg   += 0x600/sizeof(unsigned int);
	TimReg[2] = 0;									/* Disable timer & interrupts					*/
	TimReg[0] = Reload;								/* Private timer load value						*/
	TimReg[1] = Reload;								/* Start the count at reload value				*/
													/* Private timer control register				*/
	TimReg[2] = (0<<8)								/* Prescaler = /1								*/
	          | (1<<2)								/* Interrupt enable								*/
	          | (1<<1)								/* Auto-reload									*/
	          | (1<<0);								/* Timer enable									*/

	return;
}

/* ------------------------------------------------------------------------------------------------ */

int GetKey(void)
{
int RetVal;

	RetVal = 0;
	if (XUartPs_IsReceiveData(STDIN_BASEADDRESS)) {
		RetVal = XUartPs_RecvByte(STDIN_BASEADDRESS);
	}

	return(RetVal);
}

/* EOF */
