Host library for controlling a WiConnect enabled Wi-Fi module.

Dependents:   wiconnect-ota_example wiconnect-web_setup_example wiconnect-test-console wiconnect-tcp_server_example ... more

NetworkInterface.cpp

Committer:
aymangrais
Date:
2015-09-28
Revision:
42:8ffb253b09e7
Parent:
31:59fac148a8d5
Child:
40:4b4306f3d829

File content as of revision 42:8ffb253b09e7:

/**
 * ACKme WiConnect Host Library is licensed under the BSD licence: 
 * 
 * Copyright (c)2014 ACKme Networks.
 * All rights reserved. 
 * 
 * Redistribution and use in source and binary forms, with or without modification, 
 * are permitted provided that the following conditions are met: 
 * 
 * 1. Redistributions of source code must retain the above copyright notice, 
 * this list of conditions and the following disclaimer. 
 * 2. Redistributions in binary form must reproduce the above copyright notice, 
 * this list of conditions and the following disclaimer in the documentation 
 * and/or other materials provided with the distribution. 
 * 3. The name of the author may not be used to endorse or promote products 
 * derived from this software without specific prior written permission. 
 * 
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS AND ANY EXPRESS OR IMPLIED 
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
 * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
 * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
 * OF SUCH DAMAGE.
 */

#include "Wiconnect.h"
#include "internal/common.h"
#include "api/StringUtil.h"


#define IPV4_FORMAT "%u.%u.%u.%u"
#define IPV4_ARGS(ip) \
    (int)(((ip) >>  0) & 0xff), \
    (int)(((ip) >>  8) & 0xff), \
    (int)(((ip) >> 16) & 0xff), \
    (int)(((ip) >> 24) & 0xff)



/*************************************************************************************************/
NetworkInterface::NetworkInterface(Wiconnect *wiconnect_)
{
    wiconnect = wiconnect_;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::ping(const char *domain, uint32_t *timeMsPtr)
{
    WiconnectResult result;

    CHECK_OTHER_COMMAND_EXECUTING();

    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("ping %s",  (domain == NULL) ? "-g" : domain)) &&
            timeMsPtr != NULL)
    {
        if(sscanf(wiconnect->internalBuffer, "Ping reply in %ums", (unsigned int*)timeMsPtr) != 1)
        {
            result = WICONNECT_RESPONSE_PARSE_ERROR;
        }
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::lookup(const char *domain, uint32_t *ipAddressPtr)
{
    WiconnectResult result;

    CHECK_OTHER_COMMAND_EXECUTING();

    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("nlo %s", domain)))
    {
        if(!NetworkInterface::strToIp(wiconnect->internalBuffer, ipAddressPtr))
        {
            result = WICONNECT_RESPONSE_PARSE_ERROR;
        }
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::setDhcpEnabled(bool enabled)
{
    WiconnectResult result;

    CHECK_OTHER_COMMAND_EXECUTING();

    result = wiconnect->sendCommand(CMD_SET_NETWORK_DHCP, enabled);

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::getDhcpEnabled(bool *enabledPtr)
{
    WiconnectResult result;

    CHECK_OTHER_COMMAND_EXECUTING();

    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("get network.dhcp.enabled")))
    {
        int32_t enabled;
        if(WICONNECT_SUCCEEDED(result, wiconnect->responseToInt32(&enabled)))
        {
            *enabledPtr = (bool)enabled;
        }
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::setIpSettings(uint32_t ip, uint32_t netmask, uint32_t gateway)
{
    WiconnectResult result = WICONNECT_ERROR;

    enum
    {
        FS_SET_IP,
        FS_SET_NETMASK,
        FS_SET_GATEWAY
    };

    CHECK_OTHER_COMMAND_EXECUTING();

    if(wiconnect->internalProcessingState == FS_SET_IP)
    {
        if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand(CMD_SET_STATIC_IP, IPV4_ARGS(ip))))
        {
            wiconnect->internalProcessingState = FS_SET_NETMASK;
        }
    }

    if(wiconnect->internalProcessingState == FS_SET_NETMASK)
    {
        if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand(CMD_SET_STATIC_NETMASK, IPV4_ARGS(netmask))))
        {
            wiconnect->internalProcessingState = FS_SET_GATEWAY;
        }
    }

    if(wiconnect->internalProcessingState == FS_SET_GATEWAY)
    {
        if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand(CMD_SET_STATIC_GATEWAY, IPV4_ARGS(gateway))))
        {
        }
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::setIpSettings(const char* ipStr, const char* netmaskStr, const char* gatewayStr)
{
    uint32_t ip, nm, gw;

    if( !NetworkInterface::strToIp(ipStr, &ip) ||
        !NetworkInterface::strToIp(netmaskStr, &nm) ||
        !NetworkInterface::strToIp(gatewayStr, &gw))
    {
        return WICONNECT_ERROR;
    }
    return setIpSettings(ip, nm, gw);
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::getIpSettings(uint32_t *ip, uint32_t *netmask, uint32_t *gateway)
{
    WiconnectResult result = WICONNECT_ERROR;

    enum
    {
        FS_GET_IP,
        FS_GET_NETMASK,
        FS_GET_GATEWAY
    };

    CHECK_OTHER_COMMAND_EXECUTING();

    if(wiconnect->internalProcessingState == FS_GET_IP)
    {
        if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("get network.ip")))
        {
            if(!NetworkInterface::strToIp(wiconnect->internalBuffer, ip))
            {
                result = WICONNECT_RESPONSE_PARSE_ERROR;
            }
            else
            {
                wiconnect->internalProcessingState = FS_GET_NETMASK;
            }
        }
    }

    if(wiconnect->internalProcessingState == FS_GET_NETMASK)
    {
        if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("get network.netmask")))
        {
            if(!NetworkInterface::strToIp(wiconnect->internalBuffer, netmask))
            {
                result = WICONNECT_RESPONSE_PARSE_ERROR;
            }
            else
            {
                wiconnect->internalProcessingState = FS_GET_GATEWAY;
            }
        }
    }

    if(wiconnect->internalProcessingState == FS_GET_GATEWAY)
    {
        if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("get network.gateway")))
        {
            if(!NetworkInterface::strToIp(wiconnect->internalBuffer, gateway))
            {
                result = WICONNECT_RESPONSE_PARSE_ERROR;
            }
        }
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::setDnsAddress(uint32_t dnsAddress)
{
    WiconnectResult result;

    CHECK_OTHER_COMMAND_EXECUTING();

    result = wiconnect->sendCommand("set static.dns %d.%d.%d.%d", IPV4_ARGS(dnsAddress));

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::getDnsAddress(uint32_t *dnsAddress)
{
    WiconnectResult result;

    CHECK_OTHER_COMMAND_EXECUTING();

    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("get static.dns")))
    {
        if(!NetworkInterface::strToIp(wiconnect->internalBuffer, dnsAddress))
        {
            result = WICONNECT_RESPONSE_PARSE_ERROR;
        }
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::getRssi(int32_t *rssiPtr)
{
    WiconnectResult result;

    CHECK_OTHER_COMMAND_EXECUTING();

    *rssiPtr = -999;

    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("rssi")))
    {
        result = wiconnect->responseToInt32(rssiPtr);
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::getSignalStrength(NetworkSignalStrength *signalStrengthPtr)
{
    WiconnectResult result;
    int32_t rssiDbm;

    if(WICONNECT_SUCCEEDED(result, getRssi(&rssiDbm)))
    {
        *signalStrengthPtr = NetworkInterface::rssiToSignalStrength(rssiDbm);
    }
    else if(result == WICONNECT_CMD_RESPONSE_ERROR)
    {
        *signalStrengthPtr = NETWORK_RSSI_UNKNOWN;
        result = WICONNECT_SUCCESS;
    }

    return result;
}

/*************************************************************************************************/
WiconnectResult NetworkInterface::getMacAddress(MacAddress *macAddress)
{
    WiconnectResult result;

    CHECK_OTHER_COMMAND_EXECUTING();

    if(WICONNECT_SUCCEEDED(result, wiconnect->sendCommand("get wlan.mac")))
    {
        if(!Wiconnect::strToMacAddress(wiconnect->internalBuffer, macAddress))
        {
            result = WICONNECT_RESPONSE_PARSE_ERROR;
        }
    }

    CHECK_CLEANUP_COMMAND();

    return result;
}


/*************************************************************************************************/
const char* NetworkInterface::getIpAddress(char *ipStrBuffer)
{
    SET_STR_BUFFER(ipStrBuffer, 17);

    if(wiconnect->nonBlocking)
    {
        return "Err";
    }

    if(wiconnect->sendCommand(ptr, 17, "get network.ip") != WICONNECT_SUCCESS)
    {
        strcpy(ptr, "0.0.0.0");
    }

    return ptr;
}


//-----------------------------------------------------------------------------------------------


/*************************************************************************************************/
bool NetworkInterface::strToIp(const char *str, uint32_t *intPtr)
{
    if (!intPtr)
    {
        return false;
    }
    uint32_t ip = 0;
    int i;
    const char *tok;

    for(i = 0; i < 4; ++i, str = tok)
    {
        uint8_t nibble;
        char buf[4];

        tok = strchr(str, '.');
        if(tok == NULL)
        {
            if(i < 3)
            {
                return false;
            }
            strcpy(buf, str);
        }
        else
        {
            strncpy(buf, str, tok - str);
            ++tok;
        }

        if(!StringUtil::strToUint8(buf, &nibble))
        {
            return false;
        }
        ip |= (((uint32_t)nibble) << 24);
        if(i < 3)
        {
            ip = (ip >> 8UL);
        }
    }

    if(i != 4)
    {
        return false;
    }

    *intPtr = ip;

    return true;
}

/*************************************************************************************************/
const char* NetworkInterface::ipToStr(uint32_t ip, char *ipStrBuffer)
{
    SET_STR_BUFFER(ipStrBuffer, 17);

    sprintf(ptr, IPV4_FORMAT, IPV4_ARGS(ip));
    return ptr;
}

/*************************************************************************************************/
const char* NetworkInterface::networkStatusToStr(NetworkStatus status)
{
    switch(status)
    {
    case NETWORK_STATUS_DOWN:
        return "Down";
    case NETWORK_STATUS_WIFI_ONLY:
        return "WiFi Only";
    case NETWORK_STATUS_UP:
        return "Up";
    default:
        return "Unknown";
    }
}

/*************************************************************************************************/
const char* NetworkInterface::networkJoinResultToStr(NetworkJoinResult joinResult)
{
    switch(joinResult)
    {
    case NETWORK_JOIN_RESULT_NONE:
        return "None";
    case NETWORK_JOIN_RESULT_SUCCESS:
        return "Success";
    case NETWORK_JOIN_RESULT_JOINING:
        return "Joining";
    case NETWORK_JOIN_RESULT_NO_SSID:
        return "No SSID";
    case NETWORK_JOIN_RESULT_NO_PASSWORD:
        return "No Password";
    case NETWORK_JOIN_RESULT_BAD_SECURITY:
        return "Bad Security Setting";
    case NETWORK_JOIN_RESULT_NOT_FOUND:
        return "Network Not Found";
    case NETWORK_JOIN_RESULT_FAILED:
        return "Failed";
    case NETWORK_JOIN_RESULT_ABORTED:
        return "Aborted";
    default:
        return "Unknown";
    }
}


/*************************************************************************************************/
const char* NetworkInterface::signalStrengthToStr(NetworkSignalStrength signalStrenth)
{
    switch(signalStrenth)
    {
    case NETWORK_RSSI_EXCELLENT:
        return "Excellent";
    case NETWORK_RSSI_VERY_GOOD:
        return "Very Good";
    case NETWORK_RSSI_GOOD:
        return "Good";
    case NETWORK_RSSI_POOR:
        return "Poor";
    case NETWORK_RSSI_VERY_POOR:
        return "Very Poor";
    case NETWORK_RSSI_UNKNOWN:
    default:
        return "Unknown";
    }
}

/*************************************************************************************************/
NetworkSignalStrength NetworkInterface::rssiToSignalStrength(int rssi_dbm)
{
    if(rssi_dbm > -20)
    {
        return NETWORK_RSSI_EXCELLENT;
    }
    else if(rssi_dbm > -35)
    {
        return NETWORK_RSSI_VERY_GOOD;
    }
    else if(rssi_dbm > -50)
    {
        return NETWORK_RSSI_GOOD;
    }
    else if(rssi_dbm > -70)
    {
        return NETWORK_RSSI_POOR;
    }
    else
    {
        return NETWORK_RSSI_VERY_POOR;
    }
}


typedef struct
{
    const char* key;
    NetworkSecurity value;
} NetworkSecurityTableEntry;

static const NetworkSecurityTableEntry networkSecurityTable[] = {
        {"Auto",       NETWORK_SECURITY_UNKNOWN},
        {"Open",       NETWORK_SECURITY_OPEN},
        {"Unknown",    NETWORK_SECURITY_UNKNOWN},
        {"WEP",        NETWORK_SECURITY_WEP_PSK},
        {"WPA-AES",    NETWORK_SECURITY_WPA_AES_PSK},
        {"WPA-TKIP",   NETWORK_SECURITY_WPA_TKIP_PSK},
        {"WPA2-AES",   NETWORK_SECURITY_WPA2_AES_PSK},
        {"WPA2-Mixed", NETWORK_SECURITY_WPA2_MIXED_PSK},
        {"WPA2-TKIP",  NETWORK_SECURITY_WPA2_TKIP_PSK},
};


/*************************************************************************************************/
NetworkSecurity NetworkInterface::strToNetworkSecurity(const char *str)
{
    const NetworkSecurityTableEntry *end = &networkSecurityTable[ARRAY_COUNT(networkSecurityTable)];

    for(const NetworkSecurityTableEntry *e = networkSecurityTable; e < end; ++e)
    {
        if(StringUtil::strcasecmp(e->key, str) == 0)
        {
            return e->value;
        }
    }
    return NETWORK_SECURITY_UNKNOWN;
}

/*************************************************************************************************/
const char* NetworkInterface::networkSecurityToStr(NetworkSecurity security)
{
    const NetworkSecurityTableEntry *end = &networkSecurityTable[ARRAY_COUNT(networkSecurityTable)];

    for(const NetworkSecurityTableEntry *e = networkSecurityTable; e < end; ++e)
    {
        if(e->value == security)
        {
            return e->key;
        }
    }
    return "Unknown";
}

/*************************************************************************************************/
bool NetworkInterface::strToSsid(const char *str, Ssid *ssid)
{
#define ESCAPE_CHARACTER_DELIMITER '\\'
#define HEX_ESCAPE_CHARACTER 'x'
    int c;
    uint8_t *ssidPtr = ssid->val;
    uint32_t ssidLen = 0;

    while((c = (int)(*str++)) != 0)
    {
        if(c == ESCAPE_CHARACTER_DELIMITER)
        {
            if(*str == HEX_ESCAPE_CHARACTER)
            {
                c = StringUtil::hexToInt(str+1);
                if(c == -1)
                    return false;
                str += 3;
            }
            else
            {
                return false;
            }
        }
        if(ssidLen >= sizeof(ssid->val))
            return false;
        ++ssidLen;
        *ssidPtr++ = (uint8_t)c;
    }

    ssid->len = ssidLen;

    return true;
}

/*************************************************************************************************/
const char* NetworkInterface::ssidToStr(const Ssid *ssid, char *ssidStrBuffer)
{
    SET_STR_BUFFER(ssidStrBuffer, sizeof(SsidStrBuffer));
    const char *src = (const char*)ssid->val;
    int len = ssid->len;
    char *buf = ptr;

    while(len--)
    {
        if(*src >= 0x20 && *src <= 0x7E)
        {
            *ptr++ = *src;
        }
        else
        {
            ptr += sprintf(ptr, "\\x%02X", (*src) & 0xff);
        }
        ++src;
    }
    *ptr = 0;
    return buf;
}

/*************************************************************************************************/
bool NetworkInterface::strToMacAddress(const char *str, MacAddress *macAddress)
{
    const char* strPtr = str;
    uint8_t *macPtr = (uint8_t*)macAddress->octet;

    for(int count = 0; count < 6; ++count)
    {
        if(count < 5)
        {
            const char *idx = strchr(strPtr, ':');
            if(idx == NULL)
            {
                return false;
            }
        }
        int num = StringUtil::hexToInt(strPtr);
        if(num == -1)
        {
            return false;
        }
        *macPtr++ = (uint8_t)num;
        strPtr += 3;
    }

    return true;
}

/*************************************************************************************************/
const char* NetworkInterface::macAddressToStr(const MacAddress *macAddress, char *macStrBuffer)
{
    SET_STR_BUFFER(macStrBuffer, sizeof(MacAddressStrBuffer));
    const uint8_t *mac = macAddress->octet;

    sprintf(ptr, "%02X:%02X:%02X:%02X:%02X:%02X",
            (unsigned int)mac[0],
            (unsigned int)mac[1],
            (unsigned int)mac[2],
            (unsigned int)mac[3],
            (unsigned int)mac[4],
            (unsigned int)mac[5]);

    return ptr;
}