#include "WiFiCtrl.h"
#include "string.h"
#include "driver/include/nmasic.h"
#include <stdint.h>
//#include "socket/include/socket.h"
#include "define.h"
#include "Terminal.h"
#include "driver/include/m2m_periph.h"
#include "ProtocolDefs.h"
#include "BoardCfg.h"
#include "timer.h"
#include "BootloaderProtocol.h"
#include "SPI_Flash.h"
#include "FlashMapping.h"
#include "NetworkProtocol.h"


/** IP address of host. */
uint32 gu32HostIp = 0;

/** Retry count. */
uint8 gu8RetryCount = 0;

/** TCP client socket handlers. */
static SOCKET tcp_client_socket = -1;
SOCKET TerminalSocket = -1, TerminalServerSocket = -1;
uint8 TerminalRxBuf[1024];

#ifdef USE_SYSLOG
SOCKET SyslogSocket = -1, SyslogServerSocket = -1;
uint8 SyslogRxBuf[200]; //Syslog shall not receive much data
#endif


SOCKET NetworkSocket = -1, NetworkServerSocket = -1;
uint8 NetworkRxBuf[1024];

SOCKET BootloaderSocket = -1, BootloaderServerSocket = -1;
uint8 BootloaderRxBuf[1024];

SOCKET AudioConsoleIFSocket = -1;
uint8 AudioConsoleIFRxBuf[1024];

/** Receive buffer definition. */
static uint8 gau8ReceivedBuffer[MAIN_WIFI_M2M_BUFFER_SIZE] = {0};

/** Wi-Fi status variable. */
static bool gbConnectedWifi = false;

/** Get host IP status variable. */
static bool gbHostIpByName = false;

/** TCP Connection status variable. */
static bool gbTcpConnection = false;

/** Server host name. */
static char server_host_name[] = MAIN_WEATHER_SERVER_NAME;


tstrWifiInitParam param;
uint8 mac_addr[6];
uint8 u8IsMacAddrValid;
struct sockaddr_in addr_in;
uint32 mCurIPAddress;

tstrM2MIPConfig mModuleIPConfig;

bool mWiFiInitOK = false;
char mWiFiState = WIFI_MODULE_OFF_STATE;	//JFM wifi module is always OFF at boot...


/**
 * \brief Callback function of IP address.
 *
 * \param[in] hostName Domain name.
 * \param[in] hostIp Server IP.
 *
 * \return None.
 */
static void resolve_cb(uint8 *hostName, uint32 hostIp)
{
	gu32HostIp     = hostIp;
	gbHostIpByName = true;
	char IP1,IP2,IP3,IP4;
	IP1 = IPV4_BYTE(hostIp, 0);
	IP2 = IPV4_BYTE(hostIp, 1);
	IP3 = IPV4_BYTE(hostIp, 2);
	IP4 = IPV4_BYTE(hostIp, 3);
	
	printf("Host IP is %d.%d.%d.%d\r\n",
            (int)IPV4_BYTE(hostIp, 0),
            (int)IPV4_BYTE(hostIp, 1),
            (int)IPV4_BYTE(hostIp, 2),
            (int)IPV4_BYTE(hostIp, 3));
	printf("Host Name is %s\r\n", hostName);
}



static void socket_cb(SOCKET sock, uint8 u8Msg, void *pvMsg)
{
	/* Check for socket event on TCP socket. */
    
    //if(sock == TerminalSocket)
    {
        switch(u8Msg)
        {
			case SOCKET_MSG_BIND:
			{
				tstrSocketBindMsg *pstrBind = (tstrSocketBindMsg*)pvMsg;
				if(pstrBind->status == 0)
				{
					if(sock == TerminalServerSocket)
					{
						listen(TerminalServerSocket, 0);
					}
					else if(sock == SyslogServerSocket)
					{
						listen(SyslogServerSocket,0);                                
					}
					else if(sock == NetworkServerSocket)
					{
						listen(NetworkServerSocket,0);
					}
					else if(sock == BootloaderServerSocket)
					{
						listen(BootloaderServerSocket,0);
						printf("Bootloader server started\n");
					}
				}
				else
				{
					printf("Bind Failed\n");
				}
				break;
			}
			case SOCKET_MSG_LISTEN:
			{
				
				tstrSocketListenMsg *pstrListen = (tstrSocketListenMsg*)pvMsg;
				if(pstrListen->status != 0)
				{
					printf("socket %d listen Failed. Error: %d\n",(int)sock, pstrListen->status);
					break;
				}
				if(sock == SyslogServerSocket)
				{
					m2m_periph_gpio_set_val(M2M_PERIPH_GPIO3,1);
				}
				
				break;
			}
			case SOCKET_MSG_ACCEPT:
			{
				// New Socket is accepted.
				tstrSocketAcceptMsg *pstrAccept = (tstrSocketAcceptMsg *)pvMsg;
				if(pstrAccept->sock >= 0)
				{
					if(sock == TerminalServerSocket)
					{
						memset(TerminalRxBuf,0,sizeof(TerminalRxBuf));
						// Get the accepted socket.
						TerminalSocket = pstrAccept->sock;
						recv(TerminalSocket, TerminalRxBuf, sizeof(TerminalRxBuf), 0);
						SendTerminalData("Bienvenue au chalet!\nLe chalet parle en anglais comme Mr. Pepin\nIf you need help... type help\n\n",strlen("Bienvenue au chalet!\nLe chalet parle en anglais comme Mr. Pepin\nIf you need help... type help\n\n"));
						//                        SendSyslogData("Terminal client connected\n",strlen("Terminal client connected\n"));
						printf("Terminal client connected\n");
						m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4,1);
					}
					else if(sock == SyslogServerSocket)
					{
						memset(SyslogRxBuf,0,sizeof(SyslogRxBuf));
						// Get the accepted socket.
						SyslogSocket = pstrAccept->sock;
						recv(SyslogSocket, SyslogRxBuf, sizeof(SyslogRxBuf), 0);
						m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4,1);
						SendSyslogData("Syslog Welcome\n",strlen("Syslog Welcome\n"));
					}
					else if(sock == NetworkServerSocket)
					{
						memset(NetworkRxBuf,0,sizeof(NetworkRxBuf));
						// Get the accepted socket.
						NetworkSocket = pstrAccept->sock;
						recv(NetworkSocket, NetworkRxBuf, sizeof(NetworkRxBuf), 0);
						printf("Network client connected\n");
					}
					else if(sock == BootloaderServerSocket)
					{
						memset(BootloaderRxBuf,0,sizeof(BootloaderRxBuf));
						// Get the accepted socket.
						BootloaderSocket = pstrAccept->sock;
						recv(BootloaderSocket, BootloaderRxBuf, sizeof(BootloaderRxBuf), 0);
						printf("Bootloader client connected\n");
					}
					
				}
				else
				{
					printf("Socket %d : Accept Failed\n", sock);
				}
				break;
				
			}
            case SOCKET_MSG_CONNECT:
            {
                // Connect Event Handler.
                tstrSocketConnectMsg *pstrConnect = (tstrSocketConnectMsg*)pvMsg;
                if(pstrConnect->s8Error == 0)
                {
                    //connected..
                    
                    if(sock == AudioConsoleIFSocket)
                    {
                        recv(AudioConsoleIFSocket, AudioConsoleIFRxBuf, sizeof(AudioConsoleIFRxBuf), 0);
                        printf("Audio console interface connected to MasterCtrl\n"); 
                        
                    }
                }
                else
                {
                    printf("TCP Connection Failed\n");
                }
                break;
            }
			case SOCKET_MSG_RECV:
			{
				tstrSocketRecvMsg *pstrRecvMsg = (tstrSocketRecvMsg*)pvMsg;
				if((pstrRecvMsg->pu8Buffer != NULL) && (pstrRecvMsg->s16BufferSize > 0))
				{
					// Process the received message
					if(sock == TerminalSocket)
					{
						//Fwd data to Terminal...
						recv(TerminalSocket, TerminalRxBuf, sizeof(TerminalRxBuf), 0);
						RxTerminalBuf(TerminalRxBuf, pstrRecvMsg->s16BufferSize);
						
					}
					else if(sock == SyslogSocket)
					{
						//Fwd data to stdin...
						recv(SyslogSocket, SyslogRxBuf, sizeof(SyslogRxBuf), 0);
                        RxSyslogBuf(SyslogRxBuf, pstrRecvMsg->s16BufferSize);
					}
					else if(sock == NetworkSocket)
					{
						recv(NetworkSocket, NetworkRxBuf, sizeof(NetworkRxBuf), 0);
					}
					else if(sock == BootloaderSocket)
					{
						if(recv(BootloaderSocket, BootloaderRxBuf, sizeof(BootloaderRxBuf), 0) != 0)
						{
							char toto;
							toto = 1;
						}
						BootloaderProtocolProtocolAnalyzeNewData(pstrRecvMsg->pu8Buffer, pstrRecvMsg->s16BufferSize);
						
					}
                    else if(sock == AudioConsoleIFSocket)
                    {
                        recv(AudioConsoleIFSocket, AudioConsoleIFRxBuf, sizeof(AudioConsoleIFRxBuf), 0);
                        
                        ProtocolAnalyzeBuffer(AudioConsoleIFRxBuf, pstrRecvMsg->s16BufferSize,NETWORK_PROTOCOL_USER_AUDIO_CONSOLE_IF);
                    }
				}
				else    //Socket must be closed.
				{
					if(sock == TerminalSocket)
					{
						shutdown(TerminalSocket);
						TerminalSocket = -1;
						//                        SendSyslogData("Terminal client disconnected\n",strlen("Terminal client disconnected\n"));
						printf("Terminal client disconnected\n");
						m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4,0);
					}
					else if(sock == SyslogSocket)
					{
						shutdown(SyslogSocket);
						SyslogSocket = -1;
						m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4,0);
					}
					else if(sock == NetworkSocket)
					{
						shutdown(NetworkSocket);
						NetworkSocket = -1;
						printf("Network client disconnected\n");
					}
					else if(sock == BootloaderSocket)
					{
						shutdown(BootloaderSocket);
						BootloaderSocket = -1;
						printf("Bootloader client disconnected\n");
						BootloaderDeactivateBootloader();
					}
                    else if(sock == AudioConsoleIFSocket)
                    {
                        shutdown(AudioConsoleIFSocket);
                        AudioConsoleIFSocket = -1;
                        printf("Audio Console Interface with Master Ctrl disconnected\n");
                    }
  				}
				break;
			}
			case SOCKET_MSG_SEND:
			{
				if(sock == SyslogSocket)
				{
					
				} 
			}
        }
    }
    
}

static void set_dev_name_to_mac(uint8 *name, uint8 *mac_addr)
{
	/* Name must be in the format WINC1500_00:00 */
	uint16 len;
    
	//	len = m2m_strlen(name);
	if (len >= 5) {
		name[len - 1] = MAIN_HEX2ASCII((mac_addr[5] >> 0) & 0x0f);
		name[len - 2] = MAIN_HEX2ASCII((mac_addr[5] >> 4) & 0x0f);
		name[len - 4] = MAIN_HEX2ASCII((mac_addr[4] >> 0) & 0x0f);
		name[len - 5] = MAIN_HEX2ASCII((mac_addr[4] >> 4) & 0x0f);
	}
}

/**
 * \brief Callback to get the Wi-Fi status update.
 *
 * \param[in] u8MsgType Type of Wi-Fi notification.
 * \param[in] pvMsg A pointer to a buffer containing the notification parameters.
 *
 * \return None.
 */
static void wifi_cb(uint8 u8MsgType, void *pvMsg)
{
	switch (u8MsgType) {
		case M2M_WIFI_RESP_CON_STATE_CHANGED: {
			tstrM2mWifiStateChanged *pstrWifiState = (tstrM2mWifiStateChanged *)pvMsg;
			if (pstrWifiState->u8CurrState == M2M_WIFI_CONNECTED) 
			{
				printf("Wi-Fi connected\r\n");
				
                if(mUseDHCP == true)
                {
                    //			m2m_wifi_request_dhcp_client();
                }
                else
                {
                    m2m_wifi_set_static_ip(&mModuleIPConfig);
                    gbConnectedWifi = true;
                    mCurIPAddress = mModuleIPConfig.u32StaticIP;
                }
				
                //#ifndef USE_STATIC_IP
                //				//			m2m_wifi_request_dhcp_client();
                //#else
                //				m2m_wifi_set_static_ip(&mModuleIPConfig);
                //				gbConnectedWifi = true;
                //				mCurIPAddress = mModuleIPConfig.u32StaticIP;
                //#endif
				mWiFiState = WIFI_CONNECTED_STATE;
			} else if (pstrWifiState->u8CurrState == M2M_WIFI_DISCONNECTED) 
			{
				printf("Wi-Fi disconnected\r\n");
				gbConnectedWifi = false;
				mWiFiState = WIFI_DISCONNECTED_STATE;
				CloseSockets();
				m2m_periph_gpio_set_val(M2M_PERIPH_GPIO3,0);
				mCurIPAddress = 0xFFFFFFFF;
			}
			
			break;
		}
		
		case M2M_WIFI_REQ_DHCP_CONF: 
		{
			tstrM2MIPConfig *IPConfig;
			IPConfig = (tstrM2MIPConfig*)pvMsg;
            //			mCurIPAddress = *(uint32*)pvMsg;
			
			mCurIPAddress = IPConfig->u32StaticIP;
			
			unsigned char ip1,ip2,ip3,ip4;
			ip1 = IPV4_BYTE(mCurIPAddress,0);
			ip2 = IPV4_BYTE(mCurIPAddress,1);
			ip3 = IPV4_BYTE(mCurIPAddress,2);
			ip4 = IPV4_BYTE(mCurIPAddress,3);
			
			
			/* Turn LED0 on to declare that IP address received. */
			//		printf("Wi-Fi IP is %u.%u.%u.%u\r\n", pu8IPAddress[0], pu8IPAddress[1], pu8IPAddress[2], pu8IPAddress[3]);
			gbConnectedWifi = true;
			/* Obtain the IP Address by network name */
			gethostbyname((uint8 *)server_host_name);
			break;
		}
		
		case M2M_WIFI_RESP_PROVISION_INFO: 
		{
			tstrM2MProvisionInfo *pstrProvInfo = (tstrM2MProvisionInfo *)pvMsg;
			printf("wifi_cb: M2M_WIFI_RESP_PROVISION_INFO.\r\n");
			
			if (pstrProvInfo->u8Status == M2M_SUCCESS) {
				m2m_wifi_connect((char *)pstrProvInfo->au8SSID,
                        strlen((char *)pstrProvInfo->au8SSID),
                        pstrProvInfo->u8SecType,
                        pstrProvInfo->au8Password,
                        M2M_WIFI_CH_ALL);
			} else {
				printf("wifi_cb: Provision failed.\r\n");
			}
		} break;
		
		default: {
			break;
		}
	}
}


int InitWiFi()
{
	tstrWifiInitParam param;
	int8_t            ret;
    
    gbTcpConnection = false;
    TimerStart(WIFI_RECONNECT_TIMER,1);
	mCurIPAddress = 0xFFFFFFFF;
	
	char IP1,IP2,IP3,IP4,GW1,GW2,GW3,GW4;
	
	//Load WiFi parameters from flash if present
	if(SPIFlashIsPresent() == 1 && USE_IP_STORED_IN_FLASH == 1)
	{
		char StoredIPConfig[11];
		if(SPIFlashReadBuffer(StoredIPConfig,11,FLASH_WIFI_IP_ADDRESS) !=  RET_ERROR)
		{
			mUseDHCP = StoredIPConfig[8];	//Use DHCP
			//if(mUseDHCP == 0)
			{
				IP1 = StoredIPConfig[0];
				IP2 = StoredIPConfig[1];
				IP3 = StoredIPConfig[2];
				IP4 = StoredIPConfig[3];
				
				GW1 = StoredIPConfig[4];
				GW2 = StoredIPConfig[5];
				GW3 = StoredIPConfig[6];
				GW4 = StoredIPConfig[7];
				
				if((IP1 == (char)0xFF) && (IP2 == (char)0xFF) && (IP3 == (char)0xFF) && (IP4 == (char)0xFF) || \
                        ((GW1 == (char)0xFF && GW2 == (char)0xFF && GW3 == (char)0xFF && GW4 == (char)0xFF)))
				{
					IP1 = STATIC_IP_ADDRESS_1;
					IP2 = STATIC_IP_ADDRESS_2;
					IP3 = STATIC_IP_ADDRESS_3;
					IP4 = STATIC_IP_ADDRESS_4;
					
					GW1 = GATEWAY_ADDRESS_1;
					GW2 = GATEWAY_ADDRESS_2;
					GW3 = GATEWAY_ADDRESS_3;
					GW4 = GATEWAY_ADDRESS_4;
				}
			}
			char APNameLength, APPassLenght;
			APNameLength = StoredIPConfig[9];
			APPassLenght = StoredIPConfig[10];
			
			if((APNameLength > 64) || APPassLenght > 64)
			{
				strcpy(mAPName,HOME_AP_NAME);
				strcpy(mAPPassword,HOME_AP_PWD);
			}
			else
			{
				if(SPIFlashReadBuffer(mAPName,APNameLength,FLASH_WIFI_IP_ADDRESS+11) !=  RET_OK)
				{
					strcpy(mAPName,HOME_AP_NAME);
				}
				if(SPIFlashReadBuffer(mAPPassword,APPassLenght,FLASH_WIFI_IP_ADDRESS+11+APNameLength) !=  RET_OK)
				{
					strcpy(mAPPassword,HOME_AP_PWD);
				}
				
			}
			
		}
	}
	else
	{
		IP1 = STATIC_IP_ADDRESS_1;
		IP2 = STATIC_IP_ADDRESS_2;
		IP3 = STATIC_IP_ADDRESS_3;
		IP4 = STATIC_IP_ADDRESS_4;
		
		GW1 = GATEWAY_ADDRESS_1;
		GW2 = GATEWAY_ADDRESS_2;
		GW3 = GATEWAY_ADDRESS_3;
		GW4 = GATEWAY_ADDRESS_4;
		
		strcpy(mAPPassword,HOME_AP_PWD);
		strcpy(mAPName,HOME_AP_NAME);
		
#ifdef USE_STATIC_IP
		mUseDHCP = 0;
#else
		mUseDHCP = 1;
#endif
	}
    
    
    memset(&mModuleIPConfig,0,sizeof(mModuleIPConfig));
	//    mModuleIPConfig.u32StaticIP = IP_TO_U32(STATIC_IP_ADDRESS_1,STATIC_IP_ADDRESS_2,STATIC_IP_ADDRESS_3,STATIC_IP_ADDRESS_4);
	mModuleIPConfig.u32StaticIP = IP_TO_U32(IP1,IP2,IP3,IP4);
    mModuleIPConfig.u32DNS = IP_TO_U32(DEFAULT_DNS_ADD_1,DEFAULT_DNS_ADD_2,DEFAULT_DNS_ADD_3,DEFAULT_DNS_ADD_4);
    //  mModuleIPConfig.u32AlternateDNS  = IP_TO_U32(ALT_DNS_ADD_1,ALT_DNS_ADD_2,ALT_DNS_ADD_3,ALT_DNS_ADD_4);
	//    mModuleIPConfig.u32Gateway  = IP_TO_U32(GATEWAY_ADDRESS_1,GATEWAY_ADDRESS_2,GATEWAY_ADDRESS_3,GATEWAY_ADDRESS_4);
	mModuleIPConfig.u32Gateway  = IP_TO_U32(GW1,GW2,GW3,GW4);
    mModuleIPConfig.u32SubnetMask  = IP_TO_U32(SUBNET_MASK_1,SUBNET_MASK_2,SUBNET_MASK_3,SUBNET_MASK_4);
    
    /* Initialize the BSP. */
	//	nm_bsp_init();
	/* Initialize Wi-Fi parameters structure. */
	memset((uint8_t *)&param, 0, sizeof(tstrWifiInitParam));
	/* Initialize Wi-Fi driver with data and status callbacks. */
	param.pfAppWifiCb = (void*) &wifi_cb;
	ret               = m2m_wifi_init(&param);
	if (M2M_SUCCESS != ret) 
    {
        mWiFiInitOK = false;
        mWiFiState = WIFI_INIT_ERROR_STATE;
        return RET_ERROR;
	}
    mWiFiInitOK = true;
    
    mWiFiState = WIFI_DISCONNECTED_STATE;
    
    socketInit();
	registerSocketCallback(socket_cb, resolve_cb);
    
    //Get MAC address from the module
	m2m_wifi_get_otp_mac_address(mac_addr, &u8IsMacAddrValid);
	if (!u8IsMacAddrValid) {
		m2m_wifi_set_mac_address(gau8MacAddr);
	}
    
    //Get the working MAC address from driver.
	m2m_wifi_get_mac_address(gau8MacAddr);
    
    //Initialize the human readable MAC address based on the working MAC
	set_dev_name_to_mac((uint8 *)gacDeviceName, gau8MacAddr);
    
    //Use the MAC to define the SSID of the module
	set_dev_name_to_mac((uint8 *)gstrM2MAPConfig.au8SSID, gau8MacAddr);
    
	//	m2m_wifi_set_device_name((uint8 *)gacDeviceName, (uint8)m2m_strlen((uint8 *)gacDeviceName));
    
    //#ifdef USE_STATIC_IP
    //    //Use static ip --> disable dhcp client before connecting
    //    m2m_wifi_enable_dhcp(0);
    //#endif
    //    if(m2m_wifi_connect(HOME_AP_NAME,sizeof(HOME_AP_NAME),HOME_AP_SEC_TYPE,HOME_AP_PWD,M2M_WIFI_CH_ALL) != M2M_SUCCESS)
    //    {
    //        //wifi connect error...
    //        printf("error");
    //    }
	
	if(mUseDHCP == 1)
	{
		m2m_wifi_enable_dhcp(1);
	}
	else
	{
		m2m_wifi_enable_dhcp(0);
    }
	if(m2m_wifi_connect(mAPName,strlen(mAPName),HOME_AP_SEC_TYPE,mAPPassword,M2M_WIFI_CH_ALL) != M2M_SUCCESS)
    {
        //wifi connect error...
        printf("Wifi Connect error");
    }
	
    tstrPerphInitParam tst;
    
    m2m_periph_init(&tst);
	
    //Set all IOs as inputs except the LED (IO3)..
    m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO3,1);
    m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO4,1);
    m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO15,1);
    m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO16,0);
    m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO18,0);
    //    m2m_periph_gpio_set_dir(M2M_PERIPH_GPIO6,0);
    
    m2m_periph_gpio_set_val(M2M_PERIPH_GPIO3,0);
    m2m_periph_gpio_set_val(M2M_PERIPH_GPIO4,0);
    m2m_periph_gpio_set_val(M2M_PERIPH_GPIO15,0);
    m2m_periph_gpio_set_val(M2M_PERIPH_GPIO16,0);
    m2m_periph_gpio_set_val(M2M_PERIPH_GPIO18,0);
    //   m2m_periph_gpio_set_val(M2M_PERIPH_GPIO6,0);
    
    
    TimerStart(WIFI_RECONNECT_TIMER,WIFI_CONNECT_TIMEOUT);
    
    
    //	m2m_wifi_start_provision_mode((tstrM2MAPConfig *)&gstrM2MAPConfig, (char *)gacHttpProvDomainName, 1);
    //	printf("Provision Mode started.\r\nConnect to [%s] via AP[%s] and fill up the page.\r\n",
    //	       MAIN_HTTP_PROV_SERVER_DOMAIN_NAME,
    //	       gstrM2MAPConfig.au8SSID);
}

int TurnOFFWiFi()
{
    int shit;
    
    CloseSockets();
    socketDeinit();   
    m2m_wifi_disconnect();
    m2m_wifi_deinit(&shit);
    
    WIFI_CHP_EN_PIN = 0;
    WIFI_CHP_RST_PIN = 0;
    mWiFiInitOK = false;
    gbConnectedWifi = false;
    HEARTBEAT_LED_2_PIN = LED_OFF;
	mCurIPAddress = 0xFFFFFFFF;
    
    //    WIFI
    mWiFiState = WIFI_MODULE_OFF_STATE;
    return RET_OK;
}

int CloseSockets()
{
    gbTcpConnection = false;
    shutdown(TerminalServerSocket);
    if(TerminalSocket != -1)
    {
        shutdown(TerminalSocket);
    }
    
    shutdown(NetworkServerSocket);
    if(NetworkSocket != -1)
    {
        shutdown(NetworkSocket);
    }
    
#ifdef USE_SYSLOG
    shutdown(SyslogServerSocket);
    if(SyslogSocket != -1)
    {
        shutdown(SyslogSocket);
    }
#endif
	
	shutdown(BootloaderServerSocket);
	if(BootloaderSocket != -1)
	{
		shutdown(BootloaderSocket);
	}
}


char GetWiFiSate()
{
    return mWiFiState;
}

bool IsWiFiConnected()
{
    return mWiFiState == WIFI_CONNECTED_STATE;
}

uint32 GetCurIPAddress()
{
	return mCurIPAddress;
}

void TickWiFi()
{
    if(mWiFiInitOK == false)
    {
        return;
    }
    if(mWiFiState == WIFI_DISCONNECTED_STATE && gbConnectedWifi == false)//we should be connected.. if the timer is expired, retry
    {        
        if(IsTimerExpired(WIFI_RECONNECT_TIMER))
        {
            //m2m_wifi_disconnect();
            //m2m_wifi_connect(HOME_AP_NAME,sizeof(HOME_AP_NAME),HOME_AP_SEC_TYPE,HOME_AP_PWD,M2M_WIFI_CH_ALL);
			m2m_wifi_connect(mAPName,strlen(mAPName),HOME_AP_SEC_TYPE,mAPPassword,M2M_WIFI_CH_ALL);
            TimerStart(WIFI_RECONNECT_TIMER,WIFI_CONNECT_TIMEOUT);
        }
    }
    
	//    if(IsTimerExpired(WIFI_TICK_TIMER))
	//    {
	m2m_wifi_handle_events();
	//        TimerStart(WIFI_TICK_TIMER,1);
	//    }
    
    if (gbConnectedWifi && !gbTcpConnection) 
    {
        
        
        OpenTerminalServer();
        //OpenNetworkServer();
		//	OpenBootloaderServer();
		//	BootloaderActivateBootloader();
#ifdef USE_SYSLOG
        OpenSyslogServer();
#endif
        gbTcpConnection = true;
    }
}


//Terminal server implementation

int OpenTerminalServer()
{
    struct sockaddr_in strAddr;
    
    TerminalServerSocket = socket(AF_INET, SOCK_STREAM,0);
    uint16 TerminalPort = TERMINAL_SERVER_PORT;
    if(TerminalServerSocket >= 0)
    {
        strAddr.sin_family = AF_INET;
        strAddr.sin_port = _htons(TerminalPort);
        strAddr.sin_addr.s_addr = 0;
        
        bind(TerminalServerSocket, (struct sockaddr*)&strAddr, sizeof(struct sockaddr_in));
        return RET_OK;
    }
    else
    {
        return RET_ERROR;
    }
}
void SendTerminalData(uint8 *data, int size)
{
    if(TerminalSocket != -1)
    {
        send(TerminalSocket,data,size,0);
        recv(TerminalSocket,TerminalRxBuf,sizeof(TerminalRxBuf),0);
    }
}
void SentTerminalByte(uint8 data)
{
    if(TerminalSocket != -1)
    {
        send(TerminalSocket,&data,1,0);
        recv(TerminalSocket,TerminalRxBuf,sizeof(TerminalRxBuf),0);
    }
}

int OpenNetworkServer()
{
    struct sockaddr_in strAddr;
    
    NetworkServerSocket = socket(AF_INET, SOCK_STREAM,0);
    uint16 ServerPort = NETWORK_SERVER_PORT;
    if(NetworkServerSocket >= 0)
    {
        strAddr.sin_family = AF_INET;
        strAddr.sin_port = _htons(ServerPort);
        strAddr.sin_addr.s_addr = 0;
        
        bind(NetworkServerSocket, (struct sockaddr*)&strAddr, sizeof(struct sockaddr_in));
        return RET_OK;
    }
    else
    {
        return RET_ERROR;
    }
}
void SendNetworkData(uint8 *data, int size)
{
    if(NetworkSocket != -1)
    {
        send(NetworkSocket,data,size,0);
        recv(NetworkSocket,TerminalRxBuf,sizeof(TerminalRxBuf),0);
    }
}
void SentNetworkByte(uint8 data)
{
    if(NetworkSocket != -1)
    {
        send(NetworkSocket,&data,1,0);
        recv(NetworkSocket,TerminalRxBuf,sizeof(TerminalRxBuf),0);
    }  
}

//Printf Server Implementation
#ifdef USE_SYSLOG
int OpenSyslogServer()
{
    struct sockaddr_in strAddr;
    
    SyslogServerSocket = socket(AF_INET, SOCK_STREAM,0);
    uint16 ServerPort = SYSLOG_SERVER_PORT;
    if(SyslogServerSocket >= 0)
    {
        strAddr.sin_family = AF_INET;
        strAddr.sin_port = _htons(ServerPort);
        strAddr.sin_addr.s_addr = 0;
        
        bind(SyslogServerSocket, (struct sockaddr*)&strAddr, sizeof(struct sockaddr_in));
        return RET_OK;
    }
    else
    {
        return RET_ERROR;
    }
}
void SendSyslogData(uint8 *data, int size)
{
    if(SyslogSocket != -1);
    {
        send(SyslogSocket,data,size,0);
        recv(SyslogSocket,SyslogRxBuf,sizeof(SyslogRxBuf),0); 
    }
}
void SendSyslogByte(uint8 data)
{
    if(SyslogSocket != -1)
    {
        send(SyslogSocket,&data,1,0);
        recv(SyslogSocket,SyslogRxBuf,sizeof(SyslogRxBuf),0);
    }
}

int IsSyslogClientConnected()
{
    if(SyslogSocket == -1)
    {
        return 0;
    }
    
    return 1;
}
#endif

int OpenBootloaderServer()
{
    struct sockaddr_in strAddr;
    
    BootloaderServerSocket = socket(AF_INET, SOCK_STREAM,0);
    uint16 ServerPort = BOOTLOADER_SERVER_PORT;
    if(BootloaderServerSocket >= 0)
    {
        strAddr.sin_family = AF_INET;
        strAddr.sin_port = _htons(ServerPort);
        strAddr.sin_addr.s_addr = 0;
        
        bind(BootloaderServerSocket, (struct sockaddr*)&strAddr, sizeof(struct sockaddr_in));
        return RET_OK;
    }
    else
    {
        return RET_ERROR;
    }
}
int CloseBootloaderServer()
{
	shutdown(BootloaderServerSocket);
	BootloaderServerSocket = -1;
	if(BootloaderSocket != -1)
	{
		shutdown(BootloaderSocket);
		BootloaderSocket = -1;
	}
}
void SendBootloaderData(uint8 *data, int size)
{
    if(BootloaderSocket != -1);
    {
        send(BootloaderSocket,data,size,0);
        recv(BootloaderSocket,BootloaderRxBuf,sizeof(BootloaderRxBuf),0); 
    }
}
void SendSBootloaderByte(uint8 data)
{
    if(BootloaderSocket != -1)
    {
        send(BootloaderSocket,&data,1,0);
        recv(BootloaderSocket,BootloaderRxBuf,sizeof(BootloaderRxBuf),0);
    }
}

int IsBootloaderClientConnected()
{
    if(BootloaderSocket == -1)
    {
        return 0;
    }
    
    return 1;
}

int ConnectAudioInterface()
{
    if(IsWiFiConnected() == false)
    {
        return 0;
    }
    
    struct sockaddr_in strAddr;
    
    AudioConsoleIFSocket = socket(AF_INET, SOCK_STREAM,0);
    uint16 ServerPort = MASTERCTRL_SERVER_PORT;
    if(AudioConsoleIFSocket >= 0)
    {
        strAddr.sin_family = AF_INET;
        strAddr.sin_port = _htons(ServerPort);
        strAddr.sin_addr.s_addr = IP_TO_U32(MASTERCTRL_IP_ADDRESS_1,MASTERCTRL_IP_ADDRESS_2,MASTERCTRL_IP_ADDRESS_3,MASTERCTRL_IP_ADDRESS_4);
        
        connect(AudioConsoleIFSocket, (struct sockaddr*)&strAddr, sizeof(struct sockaddr_in));
        return RET_OK;
    }
    else
    {
        return RET_ERROR;
    }
    return 1;
}
int DisconnectAudioInterface()
{
    shutdown(AudioConsoleIFSocket);
	AudioConsoleIFSocket = -1;
    
    return 1;
}
int SendAudioInterfaceData(uint8 *data, int size)
{
    if(AudioConsoleIFSocket != -1);
    {
        send(AudioConsoleIFSocket,data,size,0);
        recv(AudioConsoleIFSocket,AudioConsoleIFRxBuf,sizeof(AudioConsoleIFRxBuf),0); 
    }
    return 1;
}
int IsAudioInterfaceConnected()
{
    if(AudioConsoleIFSocket < 0)
    {
        return 0;
    }
    
    return 1;
}