Implementation of the WifiPlusClick hardware module.

Dependents:   WifiPlusKlickExample

WifiPlusClick Libary

Overview

http://www.mikroe.com/img/development-tools/accessory-boards/click/wifi-plus/wifi_plus_click_main.png

This library implements the functionality exposed by a WifiPlusClick module from MikroElektronika (http://www.mikroe.com/click/wifi-plus/).

The WifiPlusClick module is an easy to handle module which provides access to up to 8 simultaneous socket objects - which is an an important aspect when you want to implement your own web server.

When I first started with the more commonly used Wifly module, I found out that the Wifly module does not reliably serve webpages which include other resources like images, JavaScript files or CSS files. The root cause seems to be the limitation that Wifly is only able to handle a single socket at this time. So I searched for an alternative and found this (actually cheaper) alternative :

WifiPlusClick HW Module

This module comes with its own limitations. The WifiPlusClick Module interface does not allow to use broadcasting or multicasting on UDP sockets. There are some additional limitations, but I think these are not so important. The following functionality is provided by the module and my library implementation :

  1. Wifi functionality
    1. Connections using AD-HOC or INFRASTRUCTURE mode
    2. List all available Wifi beacons
    3. WEP and WPA/WPA2 security modes including binary and ASCII keys
    4. reading binary WPA key after successfull Connection to speed up connection time
  2. Socket functionality
    1. UDP sockets
    2. TCP sockets

Limitations

I found the following limitations:

  1. UDP sockets cannot use multicasting or broadcasting
  2. set_option functionality is not provided by the HW
  3. 8 sockets can be configured with 1024 bytes of buffer each or 1 socket with 8192 bytes of buffer.

Sample application

Here is my sample application which you can use as a starting point.

Import programWifiPlusKlickExample

Example application of the WifiPlusClick library for use of WifiPlusClick HW Module from Mikroe.com

NOTE

The implementation of the Sockets in this library is still not completely tested. I only tested the TCP part of the sockets. Please let me know what your experiences are when using the library. I will be working on a multithreaded version of this library...

Wifi.cpp

Committer:
leihen
Date:
2013-07-29
Revision:
0:2a179bd4cc02

File content as of revision 0:2a179bd4cc02:

/* Copyright (c) 2013 Henry Leinen (henry[dot]leinen [at] online [dot] de)
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software
 * and associated documentation files (the "Software"), to deal in the Software without restriction,
 * including without limitation the rights to use, copy, modify, merge, publish, distribute,
 * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING
 * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. 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.
 */
#include "mbed.h"
#include "Wifi.h"
#include "DnsQuery.h"

#define DEBUG
#include "debug.h"

#define LOBYTE(x)       ((x)&0xFF)
#define HIBYTE(x)       (((x)>>8)&0xFF)

static Wifi::RX_STATE_t   state = Wifi::Idle;
static int ResponseType = 0;
static int DataLen = 0;
static int DataPtr = 0;

Wifi* Wifi::_Wifi = NULL;
  

Wifi::Wifi(PinName tx, PinName rx, PinName rst)
    : m_wifi(tx, rx), m_reset(rst), m_msgReceived(false), m_ackReceived(false), m_bWifiConnected(false), m_WifiConnectionError(NoFailure), m_lastError(NoError)
    , m_bScanResultsReady(false), m_NumLastScanResults(0)
{
    _Wifi = this;
    m_reset = 1;
    m_wifi.baud(115200);
    m_wifi.format(8, Serial::None, 2);

    m_buffer = new char [1024];

    if (m_buffer == NULL) {
        ERR("Failed to allocate buffer !");
        error("WIFI");
    }
    
    m_wifi.attach(this, &Wifi::rx_int);
}

void Wifi::Reset()
{
    m_reset = 0;
    wait(0.2);
    m_msgReceived = 0;
    m_ackReceived = false;
    m_bWifiConnected = false;
    m_WifiConnectionError = NoFailure;
    state = Idle;
    m_reset = 1;
    wait(0.2);
}

void Wifi::SendCommand(CMD_MSG_t cmd, int msgDataLen1, char* pData1, int msgDataLen2, char* pData2)
{
    //  Wifi Plus Click has little endian format (means LSB comes first)
    //  btw. MBED is also little endian format
    //  Send Header
    m_wifi.putc(0x55);
    m_wifi.putc(0xAA);
    //  Send Message Command
    m_wifi.putc( LOBYTE((short)cmd) );
    m_wifi.putc( HIBYTE((short)cmd) );
    //  Send Message Data1 Length
    m_wifi.putc( LOBYTE((short)msgDataLen1+msgDataLen2) );
    m_wifi.putc( HIBYTE((short)msgDataLen1+msgDataLen2) );
    
    //  Send Data1
    if ((msgDataLen1 > 0) && (pData1 != NULL)) {
        for (int i = 0 ; i < msgDataLen1 ; i++) {
            m_wifi.putc(pData1[i]);
        }
    }
    //  Send Data2
    if ((msgDataLen2 > 0) && (pData2 != NULL)) {
        for (int i = 0 ; i < msgDataLen2 ; i++) {
            m_wifi.putc(pData2[i]);
        }
    }
    
    //  Reset Acknowledge Recevied flag
    m_ackReceived = false;
    m_lastError = NoError;
    //  Send Trailer
    m_wifi.putc(0x45);
}
    
void Wifi::rx_int()
{
    char c = m_wifi.getc();

    switch (state) {
        case    Idle:
            if (c == 0x55) {
                state = Header1_received;
            } else {
                if (c == 0x00) {
                    m_ackReceived = true;
                    INFO("ACK");
                } else {
                    INFO("c = 0x%02x", c);
                }
            }
            break;
        case    Header1_received:
            if (c == 0xAA) {
                state = Header2_received;
                ResponseType = 0;
                DataLen = 0;
            } else {
                if (c == 0x55) {
                    state = Header1_received;
                } else {
                    state = Idle;
                }
            }
            break;
        case    Header2_received:
            ResponseType = c;
            state = MessageType_low_received;
            break;
        case    MessageType_low_received:
            ResponseType |= (((short)c)<<8);
            state = MessageType_high_received;
            break;
        case    MessageType_high_received:
            DataLen = c;
            state = DataLen_low_received;
            break;
        case    DataLen_low_received:
            DataLen |= (((short)c)<<8);
            if (DataLen == 0) {
                state = Awaiting_trailer;
            } else {
                DataPtr = 0;
                state = Data_receiving;
            }
            break;
        case    Data_receiving:
            m_buffer[DataPtr++] = c;
            if (DataPtr == DataLen) {
                state = Awaiting_trailer;
            }
            break;
        case Awaiting_trailer:
            if (c != 0x45) {
                ERR("Trailer information received is incorrect !");
                ERR("Full Message : ");
                ERR("Response Type : 0x%02x", ResponseType);
                for ( int i = 0; i < DataPtr++ ; i++) {
                    ERR ("0x%02x", m_buffer[i]);
                }
                ERR("Trailer : 0x%02x", c);
            } else {
                //  Complete Message received, so submit it for processing
                SubmitResponse((RSP_MSG_t)ResponseType, DataLen);
            }
            state = Idle;
            break;
        default:
            state = Idle;
    }
}

void Wifi::SubmitResponse(RSP_MSG_t rsp, int msgLen)
{
    //  Check if Event was received
    if (rsp == EVENT_MSG) {
        INFO("EVENT !!!!");
        switch( m_buffer[0] ) {
            case Event_IP_Address_Assigned :
                //  IP Address assigned, set the IP Address
                m_ipAddress.sin_addr.o1 = m_buffer[2];
                m_ipAddress.sin_addr.o2 = m_buffer[3];
                m_ipAddress.sin_addr.o3 = m_buffer[4];
                m_ipAddress.sin_addr.o4 = m_buffer[5];
                INFO("NEW IPADDRESS SET !");
                return;
            case Event_WiFi_Connection_Status_Changed :
                if ((m_buffer[1] == 1) || (m_buffer[1] == 4)) {
                    m_bWifiConnected = true;
                    m_WifiConnectionError = NoFailure;
                    INFO("EVENT      WIFI CONNECTED !");
                    DigitalOut led2(LED2);
                    led2 = 1;
                } else {
                    DigitalOut led2(LED2);
                    led2 = 0;
                    m_bWifiConnected = false;
                    m_WifiConnectionError = (CONN_ERROR_t)m_buffer[2];
                    if (m_buffer[1] != 2) {
                        m_WifiConnectionError = (CONN_ERROR_t)((char)m_WifiConnectionError+20);
                        DigitalOut led3(LED3);
                        led3 = 1;
                        
                    }
                    INFO("EVENT     WIFI DISCONNECTED !");
                }
                return;
            case Event_Error_Event :
                INFO("ERROR EVENT %d (%d, %d, %d, %d) !", *((short*)&m_buffer[2]), m_buffer[4], m_buffer[5], m_buffer[6], m_buffer[7]);
                m_lastError = (ERR_t)*((short*)&m_buffer[2]);
                return ;
            case Event_WiFi_Scan_Results_Ready :
                m_NumLastScanResults = m_buffer[1];
                INFO("SCAN RESULTS (#%d) READY !", m_NumLastScanResults);
                m_bScanResultsReady = true;
                return ;
            default:
                INFO("EVT %d", m_buffer[0])
                break;
        }
    } 

    if (m_msgReceived) {
        ERR("BUFFER FULL !");
    }
    m_msgResponse = rsp;
    m_msgDataLen = msgLen;
    m_msgReceived = true;
    INFO("Message received (%d)", rsp);
}


bool Wifi::WaitMessage(RSP_MSG_t msg, int timeout)
{
    Timer t;
    
    t.start();
    
    while(t.read_ms() < timeout) {
        if (m_msgReceived) {
            //  Successfully received a message
            if (m_msgResponse == msg) {
                //  Successfull received correct message
                m_msgReceived = false;
                return true;
            } else {
                //  Not the message we wanted to hear, so wait for next one
                m_msgReceived = false;
            }
        }
    }
    
    //  Timeout
    return false;
}

bool Wifi::WaitEvent(EVT_MSG_t evt, int timeout)
{
    Timer t;
    
    t.start();
    
    while(t.read_ms() < timeout) {
        if (m_msgReceived) {
            //  Successfully received a message
            if ((m_msgResponse == EVENT_MSG) && (m_buffer[0] == evt)) {
                //  Successfull received correct message
                m_msgReceived = false;
                return true;
            } else {
                //  Not the message or eventwe wanted to hear, so wait for next one
                m_msgReceived = false;
            }
        }
    }
    
    //  Timeout
    return false;
}

bool Wifi::WaitAck(int timeout)
{
    Timer t;
    
    t.start();
    
    while(t.read_ms() < timeout) {
        if (m_ackReceived) {
            INFO("ACK after %d ms", t.read_ms());
            m_ackReceived = false;
            return true;
        }
    }
    
    return false;
}




bool Wifi::ResetMsg()
{
    bool bRetVal = false;
    
    INFO("SENDING RESET_MSG");
    SendCommand(RESET_MSG, 0, NULL);

    if (WaitMessage (ACK_MSG, 1000)) {
        //  Now wait for the Startup Event
        
        if (WaitEvent (Event_Startup_Event, 10000)) {
            //  Startup Event received
            bRetVal = true;
            INFO("Successfully Reset the device !");
            INFO("Startup condition : 0x%02d", m_buffer[1]);
        } else {
            ERR("Did not receive a startup event from device after reset !");
        }
    } else {
        ERR("Did not get acknowledge from WifiPlusClick Board !");
    }
    
    return bRetVal;
}

bool Wifi::GetVersionMsg(char &sw_ver_lo, char &sw_ver_hi, char &rad_ver_lo, char &rad_ver_hi)
{
    bool bRetVal = false;
    
    INFO("SENDING GET_VERSION_MSG");
    SendCommand(GET_VERSION_MSG, 0, NULL);
    
    if (WaitAck (1000)) {
        //  Now wait for the asynchroneous Startup Event
        
        if (WaitEvent (Event_Startup_Event, 2000)) {
            //  Startup Event received
            bRetVal = true;
            sw_ver_hi = m_buffer[3];
            sw_ver_lo = m_buffer[2];
            rad_ver_hi = m_buffer[5];
            rad_ver_lo = m_buffer[4];
        } else {
            ERR("Did not receive an answer event from device after GET_VERSION_MSG !");
        }
    } else {
        ERR("Did not get acknowledge from WifiPlusClick Board !");
    }
    
    return bRetVal;
}

bool Wifi::GpioMsg(GPIO_IDX_t pin, GPIO_OP_t operation, GPIO_RES_t &result)
{
    char buf[2] = { (char)pin, (char)operation };
    bool bRetVal = false;
    
    INFO("SENDING GPIO_MSG");
    SendCommand(GPIO_MSG, 2, buf);
    
    if (WaitMessage (GPIO_RESPONSE_MSG, 1000)) {
        bRetVal = true;
        result = (GPIO_RES_t)m_buffer[1];
    } else {
        ERR("Did not get answer from device after GPIO_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetIpAddress(bool bUseDHCP, IPADDRESS_t *ipAddress)
{
    bool bRetVal = false;
    char buf[18] = {255, (bUseDHCP ? 0 : 1), 0};
            
    if (!bUseDHCP) {
        if ( ipAddress == NULL) {
            ERR("Invalid argument, ipAdress is NULL !");
            return false;
        }
        memcpy( &buf[2], (void*)ipAddress, 16 );
    } else {
        memset( &buf[2], 0, 16);
    }
    
    INFO("SENDING SET_IP_ADDRESS_MSG");
    SendCommand(SET_IP_ADDRESS_MSG, 18, buf);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_IP_ADDRESS_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetSubnetMask(IPADDRESS_t *NetworkMask)
{
    bool bRetVal = false;
    
    if (NetworkMask == NULL)
        return false;
        
    INFO("SENDING SET_NETWORK_MASK_MSG");
    SendCommand(SET_NETWORK_MASK_MSG, 16, NetworkMask->sin_addr.o);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_NETWORK_MASK_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetGatewayIpAddress(IPADDRESS_t *IPAddress)
{
    bool bRetVal = false;
    
    if (IPAddress == NULL)
        return false;
        
    INFO("SENDING SET_GATEWAY_IP_ADDRESS");
    SendCommand(SET_GATEWAY_IP_ADDRESS_MSG, 16, IPAddress->sin_addr.o);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_GATEWAY_IP_ADDRESS_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::GetNetworkStatus(char *MacAddress, IPADDRESS_t *IPAddress, IPADDRESS_t *NetworkMask, IPADDRESS_t *GatewayAddress, NET_STAT_t &stat)
{
    bool bRetVal = false;
    
    INFO("SENDING GET_NETWORK_STATUS_MSG");
    SendCommand(GET_NETWORK_STATUS_MSG, 0, NULL);
    
    if (WaitMessage (NETWORK_STATUS_RESPONSE_MSG, 1000)) {
        if (MacAddress != NULL) {
            memcpy (MacAddress, &m_buffer[1], 6);
        }
        if (IPAddress != NULL) {
            memcpy( IPAddress, &m_buffer[7], 4);
        }
        if (NetworkMask != NULL) {
            memcpy( NetworkMask, &m_buffer[23], 4);
        }
        if (GatewayAddress != NULL) {
            memcpy( GatewayAddress, &m_buffer[39], 4);
        }
        stat = (NET_STAT_t)m_buffer[55];
        bRetVal = true;
    } else {
        ERR("Did not get Response after GET_NETWORK_STATUS_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetMACAddress( char MACAddress[6])
{
    bool bRetVal = false;
    
    INFO("SENDING SET_MACADDRESS_MSG");
    SendCommand(SET_MACADDRESS_MSG, 6, MACAddress);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_MACADDRESS_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetARPTime(unsigned short ARPTime)
{
    char buf[2] = { ARPTime&0xFF, (ARPTime>>8)&0xFF };
    
    bool bRetVal = false;
    
    INFO("SENDING SET_ARP_TIME_MSG");
    SendCommand(SET_ARP_TIME_MSG, 2, buf);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_ARP_TIME_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetNetworkMode(char ProfileNum, NETW_MODE_t NetMode)
{
    char buf[2] = { ProfileNum, (char)NetMode };
    bool bRetVal = false;
    
    INFO("SENDING SET_CP_NETWORK_MODE_MSG");
    SendCommand(SET_CP_NETWORK_MODE_MSG, 2, buf);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_CP_NETWORK_MODE_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetPowerSaveMode(POWERSAVE_MODE_t pwrsave, short DTIM_Listen)
{
    bool bRetVal = false;
    char buf[4] = { (char)pwrsave, 0, LOBYTE(DTIM_Listen), HIBYTE(DTIM_Listen) };
    
    INFO("SENDING SET_POWER_SAVE_MODE_MSG");
    SendCommand(SET_POWER_SAVE_MODE_MSG, 4, buf);
    
    if (WaitMessage(ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_POWER_SAVE_MODE_MSG !");
    }
    
    return bRetVal;
}


bool Wifi::SetSSID(char Profile, const char* ssid)
{
    bool bRetVal = false;
    char len = strlen(ssid);
    char buf[2] = { Profile, len };
    
    if (len <= 32 ) {        
        INFO("SENDING SET_CP_SSID_MSG");
        SendCommand(SET_CP_SSID_MSG, 2, buf, len, (char*)ssid);
        
        if (WaitMessage (ACK_MSG, 10000)) {
            if (m_lastError != NoError) {
                ERR("Failed to set SSID with error code %d", m_lastError);
                m_lastError = NoError;
            } else {
                bRetVal = true;
            }
        } else {
            ERR("Did not get acknowledge after SET_CP_SSID_MSG !");
        }
    } else {
        ERR("SSID is too long !");
    }
    
    return bRetVal;
}

bool Wifi::SetRegionalDomain(DOMAIN_COUNTRY_CODE_t dcode)
{
    bool bRetVal = false;
    char buf[2] = { (char)dcode, 0 };
    
    INFO("SENDING SET_REGIONAL_DOMAIN_MSG");
    SendCommand(SET_REGIONAL_DOMAIN_MSG, 2, buf);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_REGIONAL_DOMAIN_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetChannelList(char numListItems, char *ListItems)
{
    bool bRetVal = false;
    char buf[2] = { numListItems, 0 };
        
    INFO("SENDING SET_CHANNEL_LIST_MSG");
    SendCommand(SET_CHANNEL_LIST_MSG, 2, buf, numListItems, ListItems);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_CHANNEL_LIST_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetRetryCount(char infrastructureRetryCount, char adhocRetryCount)
{
    bool bRetVal = false;
    char buf[2] = { infrastructureRetryCount, adhocRetryCount };
    
    INFO("SENDING SET_LIST_RETRY_COUNT_MSG");
    SendCommand(SET_LIST_RETRY_COUNT_MSG, 2, buf);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_LIST_RETRY_COUNT_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetSecurityOpen(char Profile)
{
    bool bRetVal = false;
    char buf[2] = { Profile, 0 };
    
    INFO("SENDING SET_CP_SECURITY_OPEN_MSG");
    SendCommand(SET_CP_SECURITY_OPEN_MSG, 2, buf);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_CP_SECURITY_OPEN_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetSecurityWEP40(char Profile, bool bSharedKey, char DefaultWEPKeyIdx, char SecurityKeys[20])
{
    bool bRetVal = false;
    char buf[4];
    
    buf[0] = Profile;
    buf[1] = bSharedKey ? 1 : 0;
    buf[2] = DefaultWEPKeyIdx;
    
    INFO("SENDING SET_CP_SECURITY_WEP40_MSG");
    SendCommand(SET_CP_SECURITY_WEP40_MSG, 4, buf, 20, SecurityKeys);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_CP_SECURITY_WEP40_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetSecurityWEP104(char Profile, bool bSharedKey, char DefaultWEPKeyIdx, char SecurityKeys[52])
{
    bool bRetVal = false;
    char buf[4];
    
    buf[0] = Profile;
    buf[1] = bSharedKey ? 1 : 0;
    buf[2] = DefaultWEPKeyIdx;
    
    INFO("SENDING SET_CP_SECURITY_WEP104_MSG");
    SendCommand(SET_CP_SECURITY_WEP104_MSG, 4, buf, 52, SecurityKeys);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        bRetVal = true;
    } else {
        ERR("Did not get acknowledge after SET_CP_SECURITY_WEP104_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SetSecurityWPA(char Profile, WPA_SECURITY_t sec, int len, const char* secKeyOrPSK)
{
    bool bRetVal = false;
    char buf[4];
    if ((secKeyOrPSK == NULL) || (*secKeyOrPSK == 0))
        return false;
            
    if (buf != NULL) {
        buf[0] = Profile;
        buf[1] = sec;
        buf[2] = 0;
        buf[3] = len;
        
        INFO("SENDING SET_CP_SECURITY_WPA_MSG");
        SendCommand(SET_CP_SECURITY_WPA_MSG, 4, buf, len, (char*)secKeyOrPSK);
        
        if (WaitMessage (ACK_MSG, 1000)) {
            bRetVal = true;
        } else {
            ERR("Did not get acknowledge after SET_CP_SECURITY_WPA_MSG !");
        }
    } else {
        ERR("Out of memory error in SetCPSecurityWPA !");
    }
    
    return bRetVal;
}

bool Wifi::GetWPAKey(char Profile, char Key[32])
{
    bool bRetVal = false;
    char buf[2] = { Profile, 0 };
    
    INFO("SENDING GET_CP_WPAKEY_MSG");
    SendCommand(GET_CP_WPAKEY_MSG, 2, buf);
    
    if (WaitMessage (WPAKEY_RESPONSE_MSG, 1000)) {
        bRetVal = true;
        memcpy(Key, m_buffer, 32);
    } else {
        ERR("Did not get answer from device !");
    }
    
    return bRetVal;
}

bool Wifi::ScanStartMsg(char Profile)
{
    bool bRetVal = false;
    
    if (m_bWifiConnected) {
        ERR("Can not start scan while Wifi is connected !");
    } else {
        char buf[2] = { Profile, 0 };
        
        INFO("SENDING SCAN_START_MSG");
        m_bScanResultsReady = false;
        m_NumLastScanResults = 0;
        SendCommand(SCAN_START_MSG, 2, buf);
        
        if (WaitMessage (ACK_MSG, 1000)) {
            bRetVal = true;
        } else {
            ERR("Did not get acknowledge after SCAN_START_MSG !");
        }
    }
    
    return bRetVal;
}

bool Wifi::ScanGetResults(char index, char ssid[32], AP_CONFIG_t &apCfg, short &beaconInterval, short &ATIMWindow, char &RSSI, NETW_MODE_t &bssType, char &channelNo)
{
    bool bRetVal = false;
    
    if (!m_bScanResultsReady) {
        ERR("No scan results !");
    } else {
        if (index >= m_NumLastScanResults) {
            ERR ("No more scan results !");
        } else {
            char buf[2] = { index, 0 };
            
            INFO("SENDING SCAN_GET_RESULTS_MSG");
            SendCommand(SCAN_GET_RESULTS_MSG, 2, buf);
            
            if (WaitMessage (SCAN_RESULT_MSG, 1000)) {
                bRetVal = true;
                memcpy(ssid, &m_buffer[7], m_buffer[6]);
                memcpy(&apCfg, &m_buffer[39], 1);
                beaconInterval = *(short*)&m_buffer[40];
                ATIMWindow = *(short*)&m_buffer[42];
                RSSI = m_buffer[52];
                bssType = (NETW_MODE_t)m_buffer[55];
                channelNo = m_buffer[56];
            } else {
                ERR("Did not receive message after SCAN_GET_RESULTS_MSG !");
            }
        }
    }
    
    return bRetVal;
}

bool Wifi::Connect(char Profile)
{
    bool bRetVal = false;
    
    if (m_bWifiConnected) {
        ERR("WIFI is already connected !");
    } else {
        char buf[2] = { Profile, 0 };
        
        INFO("SENDING WIFI_CONNECT_MSG");
        SendCommand(WIFI_CONNECT_MSG, 2, buf);
        
        if (WaitMessage (ACK_MSG, 1000)) {
            bRetVal = true;
        } else {
            ERR("Did not get any acknowledge after WIFI_CONNECT_MSG !");
        }
    }
    
    return bRetVal;
}

bool Wifi::Disconnect()
{
    bool bRetVal = false;
    
    if (!m_bWifiConnected) {
        ERR("WIFI is not yet connected !");
    } else {        
        INFO("SENDING WIFI_DISCONNECT_MSG");
        SendCommand(WIFI_DISCONNECT_MSG, 0, NULL);
        
        if (WaitMessage (ACK_MSG, 1000)) {
            bRetVal = true;
        } else {
            ERR("Did not get any acknowledge after WIFI_DISCONNECT_MSG !");
        }
        
   }
    
    return bRetVal;
}


bool Wifi::SocketAllocate(char nTCPSvr, char nTCPClnt, unsigned short TCPSvrRxBuf, unsigned short TCPSvrTxBuf, unsigned short TCPClntRxBuf, unsigned short TCPClntTxBuf)
{
    bool bRetVal = false;
    __packed struct _sendBuf {
        char _nTcpSvr;
        char _nTcpClnt;
        unsigned short _TcpSvrRxBuf, _TcpSvrTxBuf, _TcpClntRxBuf, _TcpClntTxBuf;
    } buf = { nTCPSvr, nTCPClnt, TCPSvrRxBuf, TCPSvrTxBuf, TCPClntRxBuf, TCPClntTxBuf };
    
    INFO("SENDING SOCKET_ALLOCATE_MSG");
    SendCommand(SOCKET_ALLOCATE_MSG, sizeof(buf), (char*)&buf);
    
    if (WaitMessage (SOCKET_ALLOCATE_RESPONSE_MSG, 2000)) {
        if (m_buffer[0] == 0) {
            bRetVal = true;
        } else if (m_buffer[0] == 0xFF) {
            ERR("Too many sockets requested in SOCKET_ALLOCATE_MSG !");
        } else  if (m_buffer[0] == 0xFE) {
            ERR("Too much buffer requested in SOCKET_ALLOCATE_MSG !");
        } else {
            ERR("Unknown error in SOCKET_ALLOCATE_MSG !");
        }
    } else {
        ERR("Did not get expected message SOCKET_ALLOCATE_RESPONSE_MSG !");
    }
    
    return bRetVal;
}



SOCKET_HANDLE_t Wifi::SocketCreate( SOCKET_TYPE_t sockType )
{
    char sockHandle = InvalidSocketHandle;
    char buf[2] = { sockType, 0 };
    
    INFO("SENDING SOCKET_CREATE_MSG");
    SendCommand(SOCKET_CREATE_MSG, 2, buf);
    
    if (WaitMessage (SOCKET_CREATE_RESPONSE_MSG, 1000)) {
        sockHandle = (SOCKET_HANDLE_t)m_buffer[0];
        if (m_buffer[0] == 254) {
            ERR("Invalid socket handle received after SOCKET_CREATE_MSG !");
        } else if (m_buffer[0] == 255) {
            ERR("Unknown socket type specified in call to SOCKET_CREATE_MSG !");
        } else {
            INFO("Valid socket handle received !");
        }
    } else {
        ERR("Did not get expected response after SOCKET_CREATE_MSG !");
    }
    
    return (SOCKET_HANDLE_t)sockHandle;
}

bool Wifi::SocketClose(SOCKET_HANDLE_t hSock)
{
    bool bRetVal = false;
    char buf[2] = { hSock, 0 };

    INFO("SENDING SOCKET_CLOSE_MSG");
    m_lastError = NoError;
    SendCommand(SOCKET_CLOSE_MSG, 2, buf);
    
    if (WaitMessage (ACK_MSG, 1000)) {
        wait(0.1);
        if (m_lastError != NoError) {
            bRetVal = false;
        } else {
            bRetVal = true;
        }                
    } else {
        ERR("Did not get expected acknowledge message after SOCKET_CLOSE_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SocketBind(SOCKET_HANDLE_t hSock, int Port)
{
    bool bRetVal = false;
    char buf[4] = { LOBYTE(Port), HIBYTE(Port), hSock, 0 };

    INFO("SENDING SOCKET_BIND_MSG");
    SendCommand(SOCKET_BIND_MSG, 4, buf);
    
    if (WaitMessage (SOCKET_BIND_RESPONSE_MSG, 1000)) {
        if (m_buffer[2] == 0) {
            bRetVal = true;
        } else {
            ERR("Bind operation return non-zero result !");
        }
    } else {
        ERR("Did not get expected acknowledge message after SOCKET_CLOSE_MSG !");
    }
    
    return bRetVal;
}

bool Wifi::SocketListen(SOCKET_HANDLE_t hSock, int& Backlog)
{
    bool bRetVal = false;
    char buf[2] = { hSock, Backlog };
    
    INFO("SENDING SOCKET_LISTEN_MSG");
    SendCommand(SOCKET_LISTEN_MSG, 2, buf);
    
    if (WaitMessage (SOCKET_LISTEN_RESPONSE_MSG, 1000)) {
        Backlog = m_buffer[1];
        if (m_buffer[0] != 255) {
            if (m_buffer[0] != 254) {
                bRetVal = true;
            } else {
                ERR("SOCKET Listen failed because a socket connection is currently in progress !");
            }
        } else {
            ERR("Socket Listen failed because the socket is already connected !");
        }
    } else {
        ERR("Did not get expected acknowledge message after SOCKET_LISTEN_RESPONSE !");
    }

    return bRetVal;
}

bool Wifi::SocketAccept(SOCKET_HANDLE_t hSock, SOCKET_HANDLE_t &client, int &remotePort, IPADDRESS_t &remoteAddress)
{
    bool bRetVal = false;
    char buf[2] = { hSock, 0 };
    
    INFO("SENDING SOCKET_ACCEPT_MSG");
    SendCommand(SOCKET_ACCEPT_MSG, 2, buf);
    
    if (WaitMessage (SOCKET_ACCEPT_RESPONSE_MSG, 1000)) {
        client = (SOCKET_HANDLE_t)m_buffer[0];
        remotePort = m_buffer[1] + ((int)m_buffer[2])<<8;
        memcpy(&remoteAddress, (const void*)&m_buffer[3], 4);
        bRetVal = true;
    } else {
        ERR("Did not get expected response after SOCKET_ACCEPT_MSG !");
    }
    
    return bRetVal;
}

SOCKET_HANDLE_t Wifi::SocketConnect(SOCKET_HANDLE_t hSock, IPADDRESS_t *IpAddress, int Port)
{
    SOCKET_HANDLE_t bRetVal = InvalidSocketHandle;
    char buf[4] = { hSock, 0, LOBYTE(Port), HIBYTE(Port) };
    
    INFO("SENDING SOCKET_CONNECT_MSG");
    SendCommand(SOCKET_CONNECT_MSG, 4, buf, 16, (char*)IpAddress);
    
    if (WaitMessage (SOCKET_CONNECT_RESPONSE_MSG, 1000)) {
        bRetVal = (SOCKET_HANDLE_t)m_buffer[0];
    } else {
        ERR("Did not get expected response after SOCKET_CONNECT_MSG !");
    }
    
    return bRetVal;
}

int Wifi::SocketSend(SOCKET_HANDLE_t hSock, char* data, int length)
{
    int nRetVal = -1;
    char buf[4] = { hSock, 0, LOBYTE(length), HIBYTE(length) };
    
    INFO("SENDING SOCKET_SEND_MSG");
    SendCommand(SOCKET_SEND_MSG, 4, buf, length, data);
    
    if (WaitMessage (SOCKET_SEND_RESPONSE_MSG, 1000)) {
        nRetVal = m_buffer[0] + ((int)m_buffer[1])<<8;
    } else {
        ERR("Did not get expected response after SOCKET_SEND_MSG !");
    }
    
    return nRetVal;
}

int Wifi::SocketRecv(SOCKET_HANDLE_t hSock, char* data, int length)
{
    int nRetVal = -1;
    char buf[4] = { hSock, 0, LOBYTE(length), HIBYTE(length) };
    
    INFO("SENDING SOCKET_RECV_MSG");
    SendCommand(SOCKET_RECV_MSG, 4, buf);
    
    if (WaitMessage (SOCKET_RECV_RESPONSE_MSG, 1000)) {
        nRetVal = m_buffer[2] + ((int)m_buffer[3])<<8;
        memcpy(data, &m_buffer[4], nRetVal);
    } else {
        ERR("Did not get expected response after SOCKET_RECV_MSG !");
    }
    
    return nRetVal;
}

int Wifi::SocketSendTo(SOCKET_HANDLE_t hSock, IPADDRESS_t* remoteAddress, int remotePort, char *data, int length)
{
    int nRetVal = -1;
    char buf[22] = { hSock, 0, LOBYTE(remotePort), HIBYTE(remotePort) };
    
    memcpy(&buf[4], remoteAddress, 16);
    buf[20] = LOBYTE(length);
    buf[21] = HIBYTE(length);
    INFO("SENDING SOCKET_SEND_TO_MSG");
    SendCommand(SOCKET_SEND_TO_MSG, 22, buf, length, data);
    
    if (WaitMessage (SOCKET_SEND_TO_RESPONSE_MSG, 1000)) {
        nRetVal = m_buffer[0] + (((int)m_buffer[1])<<8);
    } else {
        ERR("Did not get expected response after SOCKET_SEND_TO_MSG !");
    }
    
    return nRetVal;
}

int Wifi::SocketRecvFrom(SOCKET_HANDLE_t hSock, IPADDRESS_t *remoteAddress, int *port, char *data, int length)
{
    int nRetVal = -1;
    char buf[4] = { hSock, 0, LOBYTE(length), HIBYTE(length) };
    
    INFO("SENDING SOCKET_RECV_FROM_MSG");
    SendCommand(SOCKET_RECV_FROM_MSG, 4, buf);

    if (WaitMessage (SOCKET_RECV_FROM_RESPONSE_MSG, 1000)) {
        if (port != NULL)
            *port = m_buffer[2] + (((int)m_buffer[3])<<8);
        if (remoteAddress != NULL)
            memcpy(remoteAddress, &m_buffer[4], 4);
        nRetVal = m_buffer[20] + (((int)m_buffer[21])<<8);
        
        memcpy(data, &m_buffer[22], nRetVal > length ? length : nRetVal);
        if (nRetVal > length) {
            INFO("Socket received %d bytes on port %d which is more than the %d provided by buffer !", nRetVal, *port, length);
        }
    } else {
        ERR("Did not get expected response after SOCKET_RECV_FROM_MSG !");
    }
    
    return nRetVal;
}


int Wifi::gethostbyname(const char* host, IPADDRESS_t *IpAddress)
{
    //  First issue a get network status message to retrieve the gateway address. The gateway will be used as the DNS.
    IPADDRESS_t GatewayIP;
    NET_STAT_t     netStat;
    
    if (IpAddress == NULL)
        return -1;
    
    //  Get the gateway ip address for use as DNS server
    if (!GetNetworkStatus(NULL, NULL, NULL, &GatewayIP, netStat)) {
        return -1;
    }
    INFO("Using gateway on %d.%d.%d.%d as DNS !", GatewayIP.sin_addr.o1, GatewayIP.sin_addr.o2, GatewayIP.sin_addr.o3, GatewayIP.sin_addr.o4);        
    //  Now create the DNS query
    DnsQuery    dns(this, &GatewayIP);
    
    if( !dns.gethostbyname(host, *IpAddress) ) {
        ERR("Failed to get host by name !");
        return -1;
    }
    
    return 0;
}

int Wifi::convert(const char* hostip, IPADDRESS_t *ipAddress)
{
    if ((hostip == NULL) || (ipAddress == NULL))
        return -1;
        
    int nCnt = 0;
    int val = 0;
    while(*hostip != 0) {
        if (*hostip != '.') {
            val = val*10 + (*hostip)-'0';
        } else {
            if (nCnt > 3)
                return -1;
            ipAddress->sin_addr.o[nCnt++] = val;
            val = 0;
        }
    }
    ipAddress->sin_addr.o[nCnt++] = val;

    return 0;
}