/*
    FreeRTOS V6.0.4 - Copyright (C) 2010 Real Time Engineers Ltd.

    ***************************************************************************
    *                                                                         *
    * If you are:                                                             *
    *                                                                         *
    *    + New to FreeRTOS,                                                   *
    *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
    *    + Looking for basic training,                                        *
    *    + Wanting to improve your FreeRTOS skills and productivity           *
    *                                                                         *
    * then take a look at the FreeRTOS eBook                                  *
    *                                                                         *
    *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
    *                  http://www.FreeRTOS.org/Documentation                  *
    *                                                                         *
    * A pdf reference manual is also available.  Both are usually delivered   *
    * to your inbox within 20 minutes to two hours when purchased between 8am *
    * and 8pm GMT (although please allow up to 24 hours in case of            *
    * exceptional circumstances).  Thank you for your support!                *
    *                                                                         *
    ***************************************************************************

    This file is part of the FreeRTOS distribution.

    FreeRTOS is free software; you can redistribute it and/or modify it under
    the terms of the GNU General Public License (version 2) as published by the
    Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
    ***NOTE*** The exception to the GPL is included to allow you to distribute
    a combined work that includes FreeRTOS without being obliged to provide the
    source code for proprietary components outside of the FreeRTOS kernel.
    FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
    more details. You should have received a copy of the GNU General Public 
    License and the FreeRTOS license exception along with FreeRTOS; if not it 
    can be viewed here: http://www.freertos.org/a00114.html and also obtained 
    by writing to Richard Barry, contact details for whom are available on the
    FreeRTOS WEB site.

    1 tab == 4 spaces!

    http://www.FreeRTOS.org - Documentation, latest information, license and
    contact details.

    http://www.SafeRTOS.com - A version that is certified for use in safety
    critical systems.

    http://www.OpenRTOS.com - Commercial support, development, porting,
    licensing and training services.
*/

/*
    Implements a simplistic WEB server.  Every time a connection is made and
    data is received a dynamic page that shows the current TCP/IP statistics
    is generated and returned.  The connection is then closed.

    This file was adapted from a FreeRTOS lwIP slip demo supplied by a third
    party.
*/

/* ------------------------ System includes ------------------------------- */
#if defined(STM32F4XX)
#include "stm32f4xx.h"
#elif defined(STM32F2XX)
#include "stm32f2xx.h"
#endif

/* ------------------------ FreeRTOS includes ----------------------------- */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/* ------------------------ lwIP includes --------------------------------- */
#include "lwip/api.h"
#include "lwip/tcpip.h"
#include "lwip/ip.h"
#include "lwip/memp.h"
#include "lwip/stats.h"
#include "netif/loopif.h"

/* ------------------------ Project includes ------------------------------ */
#include <string.h>
#include "main.h"
#include "webserver.h"
#include "wlan_intf.h"

#define CONFIG_READ_FLASH	1
#ifdef CONFIG_READ_FLASH

#if (CONFIG_PLATFORM_AMEBA_X == 0)

#include <flash/stm32_flash.h>
#if defined(STM32F2XX)
#include <stm32f2xx_flash.h>
#elif defined(STM32F4XX)	 
#include <stm32f4xx_flash.h>
#elif defined(STM32f1xx)	 
#include <stm32f10x_flash.h>
#endif

#else
#include "flash_api.h"
#include "device_lock.h"
#define DATA_SECTOR     AP_SETTING_SECTOR
#undef BACKUP_SECTOR
#define BACKUP_SECTOR	(FLASH_SYSTEM_DATA_ADDR-0x1000)

#endif
#endif
/* ------------------------ Defines --------------------------------------- */
/* The size of the buffer in which the dynamic WEB page is created. */
#define webMAX_PAGE_SIZE       (3200/* 2800 */) /*FSL: buffer containing array*/
#define LOCAL_BUF_SIZE        800
#define AP_SETTING_ADDR			AP_SETTING_SECTOR
/* Standard GET response. */
#define webHTTP_OK  "HTTP/1.0 200 OK\r\nContent-type: text/html\r\n\r\n"

/* The port on which we listen. */
#define webHTTP_PORT            ( 80 )

/* Delay on close error. */
#define webSHORT_DELAY          ( 10 )

#define USE_DIV_CSS 1

#if USE_DIV_CSS

/* Format of the dynamic page that is returned on each connection. */
#define webHTML_HEAD_START \
"<html>\
<head>\
"
/*
<meta http-equiv=\"Content-Type\" content=\"text/html;charset=gb2312>\
<meta http-equiv=\"Cache-Control\" CONTENT=\"no-cache\">\
<meta http-equiv=\"Expires\" CONTENT=\"0\">\
*/

#define webHTML_TITLE \
"<title>Realtek SoftAP Config UI</title>"

#define webHTML_BODY_START \
"</head>\
<body  onLoad=\"onChangeSecType()\">\
<form method=\"post\" onSubmit=\"return onSubmitForm()\" accept-charset=\"utf-8\">\
<div class=\"wrapper\">\
<div class=\"header\">\
Realtek SoftAP Configuration\
</div>"



#define webHTML_CSS \
"<style>\
body {\
text-align:center;\
font-family: 'Segoe UI';\
}\
.wrapper {\
text-align:left;\
margin:0 auto;\
margin-top:200px;\
border:#000;\
width:500px;\
}\
.header {\
background-color:#CF9;\
font-size:18px;\
line-height:50px;\
text-align:center;\
}\
.oneline {\
width:100%;\
border-left:#FC3 10px;\
font-size:15px;\
height:30px;\
margin-top:3px;\
}\
.left {\
background-color:#FF0;\
line-height:30px;\
height:100%;\
width:40%;\
float:left;\
padding-left:20px;\
}\
.right {\
margin-left:20px;\
}\
\
.box {\
width:40%;\
height:28px;\
margin-left:20px;\
\
}\
\
.btn {\
background-color:#CF9;\
height:40px;\
text-align:center;\
}\
\
.btn input {\
font-size:16px;\
height:30px;\
width:150px;\
border:0px;\
line-height:30px;\
margin-top:5px;\
border-radius:20px;\
background-color:#FFF;\
}\
.btn input:hover{\
cursor:pointer;\
background-color:#FB4044;\
}\
\
.foot {\
text-align:center;\
font-size:15px;\
line-height:20px;\
border:#CCC;\
}\
#pwd {\
display:none;\
}\
</style>"



#define webHTML_END \
" <div class=\"oneline btn\">\
<input  type=\"submit\" value=\"Submit\">\
</div>\
<div class=\"oneline foot\">\
Copyright &copy;realtek.com\
</div>\
 </div>\
 </form>\
</body>\
</html>\
"

#define webWaitHTML_START \
"<html location.href='wait.html'>\
<head>\
"
#define webWaitHTML_END \
"</head>\
<BODY>\
<p>\
<h2>SoftAP is now restarting!</h2>\
<h2>Please wait a moment and reconnect!</h2>\
</p>"\
"</BODY>\r\n" \
"</html>"

#define onChangeSecType \
"<script>\
function onChangeSecType()\
{\
x=document.getElementById(\"sec\");\
y=document.getElementById(\"pwd\");\
if(x.value == \"open\"){\
y.style.display=\"none\";\
}else{\
y.style.display=\"block\";\
}\
}\
</script>"

#define onSubmitForm \
"<script>\
function onSubmitForm()\
{\
x=document.getElementById(\"Ssid\");\
y=document.getElementById(\"pwd\");\
z=document.getElementById(\"pwd_val\");\
if(x.value.length>32)\
{\
alert(\"SoftAP SSID is too long!(1-32)\");\
return false;\
}\
/*if(!(/^[A-Za-z0-9]+$/.test(x.value)))\
{\
alert(\"SoftAP SSID can only be [A-Za-z0-9]\");\
return false;\
}*/\
if(y.style.display == \"block\")\
{\
if((z.value.length < 8)||(z.value.length>64))\
{\
alert(\"Password length is between 8 to 64\");\
return false;\
}\
}\
}\
</script>"



#else


/* Format of the dynamic page that is returned on each connection. */
#define webHTML_HEAD_START \
"<html>\
<head>\
"
/*
<meta http-equiv=\"Content-Type\" content=\"text/html;charset=gb2312>\
<meta http-equiv=\"Cache-Control\" CONTENT=\"no-cache\">\
<meta http-equiv=\"Expires\" CONTENT=\"0\">\
*/

#define webHTML_BODY_START \
"</head>\
<BODY onLoad=\"onChangeSecType()\">\
\r\n\r\n<form name=\"form\" method=\"post\" onsubmit=\"return onSubmitForm()\" accept-charset=\"utf-8\">\
<table width=\"500\">\
<tr>\
<td colspan=\"2\" style=\"background-color:#FFA500;text-align:center;\">\
<h2>Realtek SoftAP Configuration</h2>\
</td>\
</tr>"

#define webHTML_END \
"<tr>\
<td colspan=\"2\" style=\"background-color:#FFD700;text-align:center;height:40px\">\
<input type=\"submit\" value=\"Submit\"><br></td>\
</tr>\
<tr>\
<td colspan=\"2\" style=\"background-color:#FFA500;text-align:center;\">\
Copyright ?realtek.com</td>\
</tr>\
</table>\
\r\n</form>" \
"</BODY>\r\n" \
"</html>"

#define webWaitHTML_START \
"<html location.href='wait.html'>\
<head>\
"
#define webWaitHTML_END \
"</head>\
<BODY>\
<p>\
<h2>SoftAP is now restarting!</h2>\
<h2>Please wait a moment and reconnect!</h2>\
</p>"\
"</BODY>\r\n" \
"</html>"

#define onChangeSecType \
"<script>\
function onChangeSecType()\
{\
x=document.getElementById(\"sec\");\
y=document.getElementById(\"pwd_row\");\
if(x.value == \"open\"){\
y.style.display=\"none\";\
}else{\
y.style.display=\"block\";\
}\
}\
</script>"

#define onSubmitForm \
"<script>\
function onSubmitForm()\
{\
x=document.getElementById(\"Ssid\");\
y=document.getElementById(\"pwd_row\");\
z=document.getElementById(\"pwd\");\
if(x.value.length>32)\
{\
alert(\"SoftAP SSID is too long!(1-32)\");\
return false;\
}\
if(!(/^[A-Za-z0-9]+$/.test(x.value)))\
{\
alert(\"SoftAP SSID can only be [A-Za-z0-9]\");\
return false;\
}\
if(y.style.display == \"block\")\
{\
if((z.value.length < 8)||(z.value.length>64))\
{\
alert(\"Password length is between 8 to 64\");\
return false;\
}\
}\
}\
</script>"




#endif




/*
alert(\"Please enter your password!\");\
return false;\
}\
if(z.value.length < 8)\
{\
alert(\"Your password is too short!(8-64)\");\
return false;\
}\
if(z.value.length>64)\
{\
alert(\"Your password is too long!(8-64)\");\
*/

#define MAX_SOFTAP_SSID_LEN      32
#define MAX_PASSWORD_LEN          64
#define MAX_CHANNEL_NUM             13

#if INCLUDE_uxTaskGetStackHighWaterMark
	static volatile unsigned portBASE_TYPE uxHighWaterMark_web = 0;
#endif

/* ------------------------ Prototypes ------------------------------------ */
static void     vProcessConnection( struct netconn *pxNetCon );

/*------------------------------------------------------------------------------*/
/*                            GLOBALS                                          */
/*------------------------------------------------------------------------------*/
rtw_wifi_setting_t wifi_setting = {RTW_MODE_NONE, {0}, 0, RTW_SECURITY_OPEN, {0}, 0};




#ifndef WLAN0_NAME
  #define WLAN0_NAME		"wlan0"
#endif

#ifndef WLAN1_NAME
  #define WLAN1_NAME      	"wlan1"
#endif 

static void LoadWifiSetting(void)
{
    const char *ifname = WLAN0_NAME;

    if(rltk_wlan_running(WLAN1_IDX))
    {//STA_AP_MODE
    	ifname = WLAN1_NAME;
    }

    wifi_get_setting(ifname, &wifi_setting);

    //printf("\r\nLoadWifiSetting(): wifi_setting.ssid=%s\n", wifi_setting.ssid); 
    //printf("\r\nLoadWifiSetting(): wifi_setting.channel=%d\n", wifi_setting.channel);
    //printf("\r\nLoadWifiSetting(): wifi_setting.security_type=%d\n", wifi_setting.security_type); 
    //printf("\r\nLoadWifiSetting(): wifi_setting.password=%s\n", wifi_setting.password); 
}

#if CONFIG_READ_FLASH
#if (CONFIG_PLATFORM_AMEBA_X == 0)
void LoadWifiConfig(void)
{
    rtw_wifi_config_t local_config;
    uint32_t address;
#ifdef STM32F10X_XL
    address = 0x08080000;   //bank2 domain
#else
    uint16_t sector_nb = FLASH_Sector_11;
    address = flash_SectorAddress(sector_nb);
#endif
    printf("\r\nLoadWifiConfig(): Read from FLASH!\n"); 
    flash_Read(address, (char *)&local_config, sizeof(local_config));
    
    printf("\r\nLoadWifiConfig(): local_config.boot_mode=0x%x\n", local_config.boot_mode); 
    printf("\r\nLoadWifiConfig(): local_config.ssid=%s\n", local_config.ssid); 
    printf("\r\nLoadWifiConfig(): local_config.channel=%d\n", local_config.channel);
    printf("\r\nLoadWifiConfig(): local_config.security_type=%d\n", local_config.security_type); 
    printf("\r\nLoadWifiConfig(): local_config.password=%s\n", local_config.password);

    if(local_config.boot_mode == 0x77665502)
    {
        wifi_setting.mode = RTW_MODE_AP;
        if(local_config.ssid_len > 32)
            local_config.ssid_len = 32;
        memcpy(wifi_setting.ssid, local_config.ssid, local_config.ssid_len);
        wifi_setting.ssid[local_config.ssid_len] = '\0';
        wifi_setting.channel = local_config.channel;
        wifi_setting.security_type = local_config.security_type;
        if(local_config.password_len > 64)
            local_config.password_len = 64;
        memcpy(wifi_setting.password, local_config.password, local_config.password_len);
        wifi_setting.password[local_config.password_len] = '\0';
    }
    else
    {
        LoadWifiSetting();
    }
}

int StoreApInfo(void)
{
	rtw_wifi_config_t wifi_config;
	uint32_t address;
#ifdef STM32F10X_XL
	address = 0x08080000;	//bank2 domain
#else
	uint16_t sector_nb = FLASH_Sector_11;
	address = flash_SectorAddress(sector_nb);
#endif
	// clean wifi_config first
	memset(&wifi_config, 0x00, sizeof(rtw_wifi_config_t));

	wifi_config.boot_mode = 0x77665502;
	memcpy(wifi_config.ssid, wifi_setting.ssid, strlen((char*)wifi_setting.ssid));
	wifi_config.ssid_len = strlen((char*)wifi_setting.ssid);
	wifi_config.security_type = wifi_setting.security_type;
	memcpy(wifi_config.password, wifi_setting.password, strlen((char*)wifi_setting.password));
	wifi_config.password_len= strlen((char*)wifi_setting.password);
	wifi_config.channel = wifi_setting.channel;

	printf("\n\rWritting boot mode 0x77665502 and Wi-Fi setting to flash ...");
#ifdef STM32F10X_XL
	FLASH_ErasePage(address);
#else
	flash_EraseSector(sector_nb);
#endif
	flash_Wrtie(address, (char *)&wifi_config, sizeof(rtw_wifi_config_t));

	return 0;
}


#else

void LoadWifiConfig(void)
{


    flash_t flash;

    rtw_wifi_config_t local_config;
    uint32_t address;

    address = DATA_SECTOR;

    
    //memset(&local_config,0,sizeof(rtw_wifi_config_t));
    printf("\r\nLoadWifiConfig(): Read from FLASH!\n"); 
   // flash_Read(address, &local_config, sizeof(local_config));

    device_mutex_lock(RT_DEV_LOCK_FLASH);
    flash_stream_read(&flash, address, sizeof(rtw_wifi_config_t),(uint8_t *)(&local_config));
	device_mutex_unlock(RT_DEV_LOCK_FLASH);

    printf("\r\nLoadWifiConfig(): local_config.boot_mode=0x%x\n", local_config.boot_mode); 
    printf("\r\nLoadWifiConfig(): local_config.ssid=%s\n", local_config.ssid); 
    printf("\r\nLoadWifiConfig(): local_config.channel=%d\n", local_config.channel);
    printf("\r\nLoadWifiConfig(): local_config.security_type=%d\n", local_config.security_type); 
    printf("\r\nLoadWifiConfig(): local_config.password=%s\n", local_config.password);

    if(local_config.boot_mode == 0x77665502)
    {
        wifi_setting.mode = RTW_MODE_AP;
        if(local_config.ssid_len > 32)
            local_config.ssid_len = 32;
        memcpy(wifi_setting.ssid, local_config.ssid, local_config.ssid_len);
        wifi_setting.ssid[local_config.ssid_len] = '\0';
        wifi_setting.channel = local_config.channel;
        if(local_config.security_type == 1)
          wifi_setting.security_type = RTW_SECURITY_WPA2_AES_PSK;
        else
          wifi_setting.security_type = RTW_SECURITY_OPEN;
        if(local_config.password_len > 64)
            local_config.password_len = 64;
        memcpy(wifi_setting.password, local_config.password, local_config.password_len);
        wifi_setting.password[local_config.password_len] = '\0';
    }
    else
    {
        LoadWifiSetting();
    }

}

int StoreApInfo(void)
{

    flash_t flash;

    rtw_wifi_config_t wifi_config;
    uint32_t address;
    uint32_t data,i = 0;

    // clean wifi_config first
    memset(&wifi_config, 0x00, sizeof(rtw_wifi_config_t));

    address = DATA_SECTOR;

    wifi_config.boot_mode = 0x77665502;
    memcpy(wifi_config.ssid, wifi_setting.ssid, strlen((char*)wifi_setting.ssid));
    wifi_config.ssid_len = strlen((char*)wifi_setting.ssid);
    wifi_config.security_type = wifi_setting.security_type;
    if(wifi_setting.security_type !=0)
        wifi_config.security_type = 1;
    else
        wifi_config.security_type = 0;
    memcpy(wifi_config.password, wifi_setting.password, strlen((char*)wifi_setting.password));
    wifi_config.password_len= strlen((char*)wifi_setting.password);
    wifi_config.channel = wifi_setting.channel;
    printf("\n\rWritting boot mode 0x77665502 and Wi-Fi setting to flash ...");
    //printf("\n\r &wifi_config = 0x%x",&wifi_config);

   flash_read_word(&flash,address,&data);

   
    if(data == ~0x0UL){
	  device_mutex_lock(RT_DEV_LOCK_FLASH);
      flash_stream_write(&flash, address,sizeof(rtw_wifi_config_t), (uint8_t *)&wifi_config);
	  device_mutex_unlock(RT_DEV_LOCK_FLASH);
    }else{
    //flash_EraseSector(sector_nb);
      
        device_mutex_lock(RT_DEV_LOCK_FLASH);
        flash_erase_sector(&flash,BACKUP_SECTOR);
        for(i = 0; i < 0x1000; i+= 4){
            flash_read_word(&flash, DATA_SECTOR + i, &data);
            if(i < sizeof(rtw_wifi_config_t))
            {
                 memcpy(&data,(char *)(&wifi_config) + i,4);
                 //printf("\n\r Wifi_config + %d = 0x%x",i,(void *)(&wifi_config + i));
                 //printf("\n\r Data = %d",data);
            }
            flash_write_word(&flash, BACKUP_SECTOR + i,data);
        }
        flash_read_word(&flash,BACKUP_SECTOR + 68,&data);
        //printf("\n\r Base + BACKUP_SECTOR + 68 wifi channel = %d",data);
        //erase system data
        flash_erase_sector(&flash, DATA_SECTOR);
        //write data back to system data
        for(i = 0; i < 0x1000; i+= 4){
            flash_read_word(&flash, BACKUP_SECTOR + i, &data);
            flash_write_word(&flash, DATA_SECTOR + i,data);
        }
                  //erase backup sector
           flash_erase_sector(&flash, BACKUP_SECTOR);
        }
        device_mutex_unlock(RT_DEV_LOCK_FLASH);
	//flash_Wrtie(address, (char *)&wifi_config, sizeof(rtw_wifi_config_t));
	//flash_stream_write(&flash, address,sizeof(rtw_wifi_config_t), (uint8_t *)&wifi_config);
	//flash_stream_read(&flash, address, sizeof(rtw_wifi_config_t),data);
        //flash_stream_read(&flash, address, sizeof(rtw_wifi_config_t),data);
	//printf("\n\r Base + 0x000FF000 +4  wifi config  = %s",data[4]);
        //printf("\n\r Base + 0x000FF000 +71 wifi channel = %d",data[71]);

	return 0;
}

int EraseApinfo(void){
	flash_t flash;
	uint32_t address;

	address = DATA_SECTOR;
	device_mutex_lock(RT_DEV_LOCK_FLASH);
	flash_erase_sector(&flash, address);
	device_mutex_unlock(RT_DEV_LOCK_FLASH);
	return 0;
}
#endif

#endif

static void RestartSoftAP(void)
{
	//printf("\r\nRestartAP: ssid=%s", wifi_setting.ssid);
	//printf("\r\nRestartAP: ssid_len=%d", strlen((char*)wifi_setting.ssid));
	//printf("\r\nRestartAP: security_type=%d", wifi_setting.security_type);
	//printf("\r\nRestartAP: password=%s", wifi_setting.password);
	//printf("\r\nRestartAP: password_len=%d", strlen((char*)wifi_setting.password));
	//printf("\r\nRestartAP: channel=%d\n", wifi_setting.channel);
	wifi_restart_ap(wifi_setting.ssid,
					wifi_setting.security_type,
					wifi_setting.password,
					strlen((char*)wifi_setting.ssid),
					strlen((char*)wifi_setting.password),
					wifi_setting.channel);
}


u32 web_atoi(char* s)
{
	int num=0,flag=0;
	u32 i;

	for(i=0;i<=strlen(s);i++)
	{
		if(s[i] >= '0' && s[i] <= '9')
			num = num * 10 + s[i] -'0';
		else if(s[0] == '-' && i==0) 
			flag =1;
		else 
			break;
	}

	if(flag == 1)
		num = num * -1;

	return(num); 
}

static void CreateSsidTableItem(char *pbuf, u8_t *ssid, u8_t ssid_len)
{
    char local_ssid[MAX_SOFTAP_SSID_LEN+1];

    if(ssid_len > MAX_SOFTAP_SSID_LEN)
        ssid_len = MAX_SOFTAP_SSID_LEN;
    memcpy(local_ssid, ssid, ssid_len);
    local_ssid[ssid_len] = '\0';

#if USE_DIV_CSS
    sprintf(pbuf, "<div class=\"oneline\"><div class=\"left\">SoftAP SSID:</div> <div class=\"right\">" \
			"<input class=\"box\" type=\"text\" name=\"Ssid\" id=\"Ssid\" value=\"%s\"></div></div>",
                        local_ssid);
#else
    sprintf(pbuf, "<tr>"
                        "<td style=\"background-color:#FFD700;width:100px;\">"
                        "<b>SoftAP SSID:</b><br>"
                        "</td>"
                        "<td style=\"background-color:#eeeeee;height:30px;width:400px;\">"
                        "<input type=\"text\" name=\"Ssid\" id=\"Ssid\" value=\"%s\"><br>"
                        "</td>"
                        "</tr>", 
                        local_ssid);

#endif
    //printf("\r\nstrlen(SsidTableItem)=%d\n", strlen(pbuf));	
}

static void CreateSecTypeTableItem(char *pbuf, u32_t sectype)
{
    u8_t flag[2] = {0, 0};

    if(sectype == RTW_SECURITY_OPEN)
	flag[0] = 1;
    else if(sectype == RTW_SECURITY_WPA2_AES_PSK)
        flag[1] = 1;
    else	
        return;

#if USE_DIV_CSS
    sprintf(pbuf, "<div class=\"oneline\"><div class=\"left\">Security Type: </div><div class=\"right\">"\
             	"<select  class=\"box\" name=\"Security Type\"  id=\"sec\" onChange=onChangeSecType()>"\
             	"<option value=\"open\" %s>OPEN</option><option value=\"wpa2-aes\" %s>WPA2-AES</option>"\
             	"</select></div></div>",
                        flag[0]?"selected":"",
                        flag[1]?"selected":"");
#else
    sprintf(pbuf, "<tr>"
                        "<td style=\"background-color:#FFD700;width:100px;\">"
                        "<b>Security Type:</b><br>"
                        "</td>"
                        "<td style=\"background-color:#eeeeee;height:30px;\">"
                        "<select name=\"Security Type\"  id=\"sec\" onChange=onChangeSecType()>"
                        "<option value=\"open\" %s>OPEN</option>"
                        "<option value=\"wpa2-aes\" %s>WPA2-AES</option>"
                        "</select>"
                        "</td>"
                        "</tr>",
                        flag[0]?"selected":"",
                        flag[1]?"selected":"");


#endif

    //printf("\r\nstrlen(SecTypeTableItem)=%d\n", strlen(pbuf));	
}

static void CreatePasswdTableItem(char *pbuf, u8_t *password, u8_t passwd_len)
{
    char local_passwd[MAX_PASSWORD_LEN+1];

    if(passwd_len > MAX_PASSWORD_LEN)
        passwd_len = MAX_PASSWORD_LEN;
    if(passwd_len > 0)
    {
        memcpy(local_passwd, password, passwd_len);
        local_passwd[passwd_len] = '\0';
    }

#if USE_DIV_CSS

     sprintf(pbuf,	"<div class=\"oneline\" id=\"pwd\"><div class=\"left\">Password: </div>"\
				"<div class=\"right\" >"\
				"<input  class=\"box\" id=\"pwd_val\" type=\"text\" name=\"Password\" value=\"%s\" >"\
				" </div></div>",
                        passwd_len?local_passwd:"");
#else
    sprintf(pbuf, "<tr id=\"pwd_row\">"
                        "<td style=\"background-color:#FFD700;width:100px;\">"
                        "<b>Password:</b><br>"
                        "</td>"
                        "<td style=\"background-color:#eeeeee;height:30px;\">"
                        "<input type=\"text\" name=\"Password\" id=\"pwd\" value=\"%s\" ><br>"
                        "</td>"
                        "</tr>", 
                        passwd_len?local_passwd:"");


#endif


    //printf("\r\nstrlen(passwordTableItem)=%d\n", strlen(pbuf));	
}

static void CreateChannelTableItem(char *pbuf, u8_t channel)
{
    u8_t flag[MAX_CHANNEL_NUM+1] = {0};

    if(channel > MAX_CHANNEL_NUM){
        printf("Channel(%d) is out of range!\n", channel);
        channel = 1;
    }
    flag[channel] = 1;

#if USE_DIV_CSS

   sprintf(pbuf, "<div class=\"oneline\"><div class=\"left\">Channel: </div>"
			   "<div class=\"right\"><select  class=\"box\" name=\"Channel\">"
                        "<option value=\"1\" %s>1</option>"
                        "<option value=\"2\" %s>2</option>"
                        "<option value=\"3\" %s>3</option>"
                        "<option value=\"4\" %s>4</option>"
                        "<option value=\"5\" %s>5</option>"
                        "<option value=\"6\" %s>6</option>"
                        "<option value=\"7\" %s>7</option>"
                        "<option value=\"8\" %s>8</option>"
                        "<option value=\"9\" %s>9</option>"
                        "<option value=\"10\" %s>10</option>"
                        "<option value=\"11\" %s>11</option>"
			   "</select> </div> </div>",
				
                        flag[1]?"selected":"",
                        flag[2]?"selected":"",
                        flag[3]?"selected":"",
                        flag[4]?"selected":"",
                        flag[5]?"selected":"",
                        flag[6]?"selected":"",
                        flag[7]?"selected":"",
                        flag[8]?"selected":"",
                        flag[9]?"selected":"",
                        flag[10]?"selected":"",
                        flag[11]?"selected":"");
#else
  	 sprintf(pbuf, "<tr>"
                        "<td style=\"background-color:#FFD700;width:100px;\">"
                        "<b>Channel:</b><br>"
                        "</td>"
                        "<td style=\"background-color:#eeeeee;height:30px;\">"
                        "<select name=\"Channel\">"
                        "<option value=\"1\" %s>1</option>"
                        "<option value=\"2\" %s>2</option>"
                        "<option value=\"3\" %s>3</option>"
                        "<option value=\"4\" %s>4</option>"
                        "<option value=\"5\" %s>5</option>"
                        "<option value=\"6\" %s>6</option>"
                        "<option value=\"7\" %s>7</option>"
                        "<option value=\"8\" %s>8</option>"
                        "<option value=\"9\" %s>9</option>"
                        "<option value=\"10\" %s>10</option>"
                        "<option value=\"11\" %s>11</option>"
                        "</select>"
                        "</td>"
                        "</tr>",
                        flag[1]?"selected":"",
                        flag[2]?"selected":"",
                        flag[3]?"selected":"",
                        flag[4]?"selected":"",
                        flag[5]?"selected":"",
                        flag[6]?"selected":"",
                        flag[7]?"selected":"",
                        flag[8]?"selected":"",
                        flag[9]?"selected":"",
                        flag[10]?"selected":"",
                        flag[11]?"selected":"");


#endif

    //printf("\r\nstrlen(ChannelTableItem)=%d\n", strlen(pbuf));	
}

static void GenerateIndexHtmlPage(portCHAR* cDynamicPage, portCHAR *LocalBuf)
{
        /* Generate the page index.html...
           ... First the page header. */
        strcpy( cDynamicPage, webHTML_HEAD_START );
        
        /* Add script */
        strcat( cDynamicPage, onChangeSecType );
        strcat( cDynamicPage, onSubmitForm);
#if USE_DIV_CSS
        /* add css */
        strcat( cDynamicPage, webHTML_CSS);

        strcat( cDynamicPage, webHTML_TITLE);
#endif
        /* Add Body start */
        strcat( cDynamicPage, webHTML_BODY_START );
        
        /* Add SSID */
        CreateSsidTableItem(LocalBuf, wifi_setting.ssid, strlen((char*)wifi_setting.ssid));
        strcat( cDynamicPage, LocalBuf );
        
        /* Add SECURITY TYPE  */
        CreateSecTypeTableItem(LocalBuf, wifi_setting.security_type);
        strcat( cDynamicPage, LocalBuf );

        /* Add PASSWORD */
        CreatePasswdTableItem(LocalBuf, wifi_setting.password, strlen((char*)wifi_setting.password));
        strcat( cDynamicPage, LocalBuf );
       
        /* Add CHANNEL  */
        CreateChannelTableItem(LocalBuf, wifi_setting.channel);
        strcat( cDynamicPage, LocalBuf );

        /* ... Finally the page footer. */
        strcat( cDynamicPage, webHTML_END );
        //printf("\r\nGenerateIndexHtmlPage(): %s\n", cDynamicPage);
        printf("\r\nGenerateIndexHtmlPage Len: %d\n", strlen( cDynamicPage ));
}

static void GenerateWaitHtmlPage(portCHAR* cDynamicPage)
{
        /* Generate the dynamic page...
           ... First the page header. */
        strcpy( cDynamicPage, webWaitHTML_START );

        /* ... Finally the page footer. */
        strcat( cDynamicPage, webWaitHTML_END);

        //printf("\r\nGenerateWaitHtmlPage(): %s\n",  cDynamicPage);
        //printf("\r\nGenerateWaitHtmlPage Len: %d\n", strlen( cDynamicPage ));
}

static void http_translate_url_encode(char *ptr)
{

	char *data = ptr;
	char tmp_data[3] = {0};
	char outdata[33] = {0};
	int buffer;
	char *outdata_ptr = outdata;

	while (*data != '\0') {

		if (*data == '%') {
			if ((*(data + 1) != 0) &&  (*(data + 2) != 0)) {
				tmp_data[0] = *(data + 1);
				tmp_data[1] = *(data + 2);
				sscanf(tmp_data, "%x", &buffer);
				*outdata_ptr = (char)buffer;

				/* destroy data */
				*data  = 0;
				*(data+1)  = 0;
				*(data+2)  = 0;
				
				data += 2;
				outdata_ptr++;
			}
			
		} else {
		  *outdata_ptr = *data;
		  if (*data == '+')
		    *outdata_ptr = ' ';
		  outdata_ptr++;
		}
		data++;
	}
	strcpy(ptr, outdata);

}

static u8_t ProcessPostMessage(struct netbuf  *pxRxBuffer, portCHAR *LocalBuf)
{
    struct pbuf *p;
    portCHAR *pcRxString, *ptr;
    unsigned portSHORT usLength;
    u8_t bChanged = 0;
    rtw_security_t secType;
    u8_t channel;
    u8_t len = 0;
    
    pcRxString = LocalBuf;
    p = pxRxBuffer->p;
    usLength = p->tot_len;
    //printf("\r\n !!!!!!!!!POST!p->tot_len =%d p->len=%d\n", p->tot_len, p->len);            
    while(p)
    {
        memcpy(pcRxString, p->payload, p->len);
        pcRxString += p->len;
        p = p->next;
    }
    pcRxString = LocalBuf;
    pcRxString[usLength] = '\0';
    //printf("\r\n usLength=%d pcRxString = %s\n", usLength, pcRxString);

    ptr = (char*)strstr(pcRxString, "Ssid=");
    if(ptr)
    {
	//printf("ssid passed = %s\n", ptr);
        pcRxString = (char*)strstr(ptr, "&");
        *pcRxString++ = '\0';
        ptr += 5;
	http_translate_url_encode(ptr);
        if(strcmp((char*)wifi_setting.ssid, ptr))
        {
            bChanged = 1;
            len = strlen(ptr);
            if(len > MAX_SOFTAP_SSID_LEN){
                len = MAX_SOFTAP_SSID_LEN;
                ptr[len] = '\0';
            }
            strcpy((char*)wifi_setting.ssid, ptr);
        }
    }

	
    printf("\r\n get wifi_config.ssid = %s\n", wifi_setting.ssid);
    ptr = (char*)strstr(pcRxString, "Security+Type=");
    if(ptr)
    {
        pcRxString = (char*)strstr(ptr, "&");
        *pcRxString++ = '\0';
        ptr += 14;
        if(!strcmp(ptr, "open"))
           secType = RTW_SECURITY_OPEN;
        else if(!strcmp(ptr, "wpa2-aes"))
            secType = RTW_SECURITY_WPA2_AES_PSK;
        else
            secType = RTW_SECURITY_OPEN;
        if(wifi_setting.security_type != secType)
        {
            bChanged = 1;
            wifi_setting.security_type = secType;
        }
    }
    
    //printf("\r\n wifi_config.security_type = %d\n", wifi_setting.security_type);
    if(wifi_setting.security_type > RTW_SECURITY_OPEN)
    {
        ptr = (char*)strstr(pcRxString, "Password=");
        if(ptr)
        {
            pcRxString = (char*)strstr(ptr, "&");
            *pcRxString++ = '\0';
            ptr += 9;
            if(strcmp((char*)wifi_setting.password, ptr))
            {
                bChanged = 1;
                len = strlen(ptr);
                if(len > MAX_PASSWORD_LEN){
                    len = MAX_PASSWORD_LEN;
                    ptr[len] = '\0';
                }
                strcpy((char*)wifi_setting.password, ptr);
            }
        }
        //printf("\r\n wifi_config.password = %s\n", wifi_setting.password);
    }
    ptr = (char*)strstr(pcRxString, "Channel=");
    if(ptr)
    {
        ptr += 8;
        channel = web_atoi(ptr);
        if((channel>MAX_CHANNEL_NUM)||(channel < 1))
            channel = 1;
        if(wifi_setting.channel !=channel)
        {
            bChanged = 1;
            wifi_setting.channel = channel;
        }
    }
    //printf("\r\n wifi_config.channel = %d\n", wifi_setting.channel);
            
    return bChanged;
}

struct netconn *pxHTTPListener = NULL;
static void vProcessConnection( struct netconn *pxNetCon )
{
    static portCHAR cDynamicPage[webMAX_PAGE_SIZE];
    struct netbuf  *pxRxBuffer, *pxRxBuffer1 = NULL;
    portCHAR       *pcRxString;
    unsigned portSHORT usLength;
    static portCHAR LocalBuf[LOCAL_BUF_SIZE];
    u8_t bChanged = 0;
    int ret_recv = ERR_OK;
    int ret_accept = ERR_OK;

    /* Load WiFi Setting*/
    LoadWifiSetting();

    /* We expect to immediately get data. */
    port_netconn_recv( pxNetCon , pxRxBuffer, ret_recv);

    if( pxRxBuffer != NULL && ret_recv == ERR_OK)
    {
         /* Where is the data? */
        netbuf_data( pxRxBuffer, ( void * )&pcRxString, &usLength );

        //printf("\r\nusLength=%d pcRxString = \n%s\n", usLength, pcRxString);
	/* Is this a GET?  We don't handle anything else. */
        if( !strncmp( pcRxString, "GET", 3 ) )
        {
            //printf("\r\nusLength=%d pcRxString=%s \n", usLength, pcRxString);
            //pcRxString = cDynamicPage;

            /* Write out the HTTP OK header. */            
            netconn_write( pxNetCon, webHTTP_OK, ( u16_t ) strlen( webHTTP_OK ), NETCONN_COPY );

            /* Generate index.html page. */
            GenerateIndexHtmlPage(cDynamicPage, LocalBuf);
            
            /* Write out the dynamically generated page. */
            netconn_write( pxNetCon, cDynamicPage, ( u16_t ) strlen( cDynamicPage ), NETCONN_COPY );
        }
        else if(!strncmp( pcRxString, "POST", 4 ) )
        {
            /* Write out the HTTP OK header. */            
            netconn_write( pxNetCon, webHTTP_OK, ( u16_t ) strlen( webHTTP_OK ), NETCONN_COPY );
			
            bChanged = ProcessPostMessage(pxRxBuffer, LocalBuf);
            if(bChanged == 0){
                    port_netconn_recv( pxNetCon , pxRxBuffer1, ret_recv);
                    if(pxRxBuffer != NULL && ret_recv == ERR_OK){
                        bChanged = ProcessPostMessage(pxRxBuffer1, LocalBuf);
                        netbuf_delete( pxRxBuffer1 );
                    }
            }
            if(bChanged)
            {
                GenerateWaitHtmlPage(cDynamicPage);
                
                /* Write out the generated page. */
                netconn_write( pxNetCon, cDynamicPage, ( u16_t ) strlen( cDynamicPage ), NETCONN_COPY );

#if CONFIG_READ_FLASH
                StoreApInfo();
#endif
            }
            else
            {
                /* Generate index.html page. */
                GenerateIndexHtmlPage(cDynamicPage, LocalBuf);
                
                /* Write out the generated page. */
                netconn_write( pxNetCon, cDynamicPage, ( u16_t ) strlen( cDynamicPage ), NETCONN_COPY );
            }
        }
        netbuf_delete( pxRxBuffer );
    }
    netconn_close( pxNetCon );

    if(bChanged)
    {
        struct netconn *pxNewConnection;
        vTaskDelay(200/portTICK_RATE_MS);
        //printf("\r\n%d:before restart ap\n", xTaskGetTickCount());
        RestartSoftAP();
        //printf("\r\n%d:after restart ap\n", xTaskGetTickCount());
        pxHTTPListener->recv_timeout = 1;		
        port_netconn_accept( pxHTTPListener , pxNewConnection, ret_accept);
        if( pxNewConnection != NULL && ret_accept == ERR_OK)
        {
            //printf("\r\n%d: got a conn\n", xTaskGetTickCount());
            netconn_close( pxNewConnection );
            while( netconn_delete( pxNewConnection ) != ERR_OK )
            {
                vTaskDelay( webSHORT_DELAY );
            }
        }
        //printf("\r\n%d:end\n", xTaskGetTickCount());
        pxHTTPListener->recv_timeout = 0;		
    }
}

/*------------------------------------------------------------*/
xTaskHandle webs_task = NULL;
xSemaphoreHandle webs_sema = NULL;
u8_t webs_terminate = 0;
void vBasicWEBServer( void *pvParameters )
{
    struct netconn *pxNewConnection;
    //struct ip_addr  xIpAddr, xNetMast, xGateway;
    extern err_t ethernetif_init( struct netif *netif );
    int ret = ERR_OK;
    /* Parameters are not used - suppress compiler error. */
    ( void )pvParameters;

    /* Create a new tcp connection handle */
    pxHTTPListener = netconn_new( NETCONN_TCP );
    ip_set_option(pxHTTPListener->pcb.ip, SOF_REUSEADDR);
    netconn_bind( pxHTTPListener, NULL, webHTTP_PORT );
    netconn_listen( pxHTTPListener );

#if CONFIG_READ_FLASH
  /* Load wifi_config */
    LoadWifiConfig();
    RestartSoftAP();
#endif
    //printf("\r\n-0\n");

    /* Loop forever */
    for( ;; )
    {	
        if(webs_terminate)
            break;

        //printf("\r\n%d:-1\n", xTaskGetTickCount());
        /* Wait for connection. */
        port_netconn_accept( pxHTTPListener , pxNewConnection, ret);
        //printf("\r\n%d:-2\n", xTaskGetTickCount());

        if( pxNewConnection != NULL && ret == ERR_OK)
        {
            /* Service connection. */
            vProcessConnection( pxNewConnection );
            while( netconn_delete( pxNewConnection ) != ERR_OK )
            {
                vTaskDelay( webSHORT_DELAY );
            }
        }
        //printf("\r\n%d:-3\n", xTaskGetTickCount());
    }
    //printf("\r\n-4\n");
    if(pxHTTPListener)
    {
        netconn_close(pxHTTPListener);
        netconn_delete(pxHTTPListener);
        pxHTTPListener = NULL;
    }

    //printf("\r\nExit Web Server Thread!\n");
    xSemaphoreGive(webs_sema);
    vTaskDelete(NULL);
}

#define STACKSIZE				512
void start_web_server(void)
{
    	printf("\r\nWEB:Enter start web server!\n");
	webs_terminate = 0;
	if(webs_task == NULL)
	{
		if(xTaskCreate(vBasicWEBServer, (const char *)"web_server", STACKSIZE, NULL, tskIDLE_PRIORITY + 1, &webs_task) != pdPASS)
			printf("\n\rWEB: Create webserver task failed!\n");
	}
	if(webs_sema == NULL)
	{
		webs_sema = xSemaphoreCreateCounting(0xffffffff, 0);	//Set max count 0xffffffff
	}
    	//printf("\r\nWEB:Exit start web server!\n");
}

void stop_web_server(void)
{
    	//printf("\r\nWEB:Enter stop web server!\n");
	webs_terminate = 1;
   	if(pxHTTPListener)
		netconn_abort(pxHTTPListener);
	if(webs_sema)
	{
		if(xSemaphoreTake(webs_sema, 15 * configTICK_RATE_HZ) != pdTRUE)
		{
			if(pxHTTPListener)
			{
				netconn_close(pxHTTPListener);
  				netconn_delete(pxHTTPListener);
				pxHTTPListener = NULL;
			}
			printf("\r\nWEB: Take webs sema(%p) failed!!!!!!!!!!!\n", webs_sema);
		}
		vSemaphoreDelete(webs_sema);
		webs_sema = NULL;
	}
	if(webs_task)
	{
		vTaskDelete(webs_task);
		webs_task = NULL;
	}
    	printf("\r\nWEB:Exit stop web server!\n");		
}
