wifly/socket interface for wifly modules

Dependents:   PROJET_MATTHIEU_2019 PROJET_MATTHIEU_2019

Wifly/Wifly.cpp

Committer:
samux
Date:
2012-08-22
Revision:
1:8f04181f9ad8
Parent:
0:6ffb0aeb3972
Child:
2:d78b1f66e345

File content as of revision 1:8f04181f9ad8:

/* Copyright (C) 2012 mbed.org, MIT License
 *
 * 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 "Wifly.h"
#include <string>
#include <algorithm>

//Debug is disabled by default
#if 1
#define DBG(x, ...) std::printf("[Wifly : DBG]"x"\r\n", ##__VA_ARGS__);
#define WARN(x, ...) std::printf("[Wifly : WARN]"x"\r\n", ##__VA_ARGS__);
#define ERR(x, ...) std::printf("[Wifly : ERR]"x"\r\n", ##__VA_ARGS__);
#else
#define DBG(x, ...)
#define WARN(x, ...)
#define ERR(x, ...)
#endif

#define INFO(x, ...) printf("[Wifly : INFO]"x"\r\n", ##__VA_ARGS__);

Wifly * Wifly::inst;

Wifly::Wifly(   PinName tx, PinName rx, PinName _reset, PinName tcp_status, const char * ssid, const char * phrase, bool wpa):
    wifi(tx, rx), reset_pin(_reset), tcp_status(tcp_status), buf_wifly(256)
{
    this->wpa = wpa;
    this->phrase = phrase;
    this->ssid = ssid;
    inst = this;
    attach_rx(false);
    cmd_mode = false;
}

bool Wifly::join()
{
    char cmd[100];

    if (!sendCommand("set comm time 20\r", "AOK"))
        return false;

    if (!sendCommand("set comm size 128\r", "AOK"))
        return false;

    if (!sendCommand("set sys iofunc 0x40\r", "AOK"))
        return false;

    // no string sent to the tcp client
    if (!sendCommand("set comm remote 0\r", "AOK"))
        return false;

    // tcp protocol
    if (!sendCommand("set ip proto 2\r", "AOK"))
        return false;

    // tcp retry
    if (!sendCommand("set ip flags 0x7\r", "AOK"))
        return false;

    //no echo
    if (!sendCommand("set u m 1\r", "AOK"))
        return false;

    //dhcp
    sprintf(cmd, "set i d %d\r", (dhcp) ? 1 : 0);
    if (!sendCommand(cmd, "AOK"))
        return false;

    if (dhcp) {
        if (!sendCommand("get w\r", NULL, cmd))
            return false;

        // if the wlan parameters are already known, we just connect without resending all commands
        if ((string(cmd).find(ssid) != string::npos) && (string(cmd).find(phrase) != string::npos) ) {
            DBG("ssid found && phrase found\r\n");
            Timer tmr;
            tmr.start();
            while (tmr.read() < 2) {
                send("show c\r", 7, NULL, cmd);
                DBG("join: state of conn: %s\r\n", cmd);
                if ((cmd[2] - '0') & 0x01) {
                    INFO("\r\nssid: %s\r\nphrase: %s\r\nsecurity: %s\r\n\r\n", this->ssid, this->phrase, (wpa) ? "WPA" : "WEP");
                    // save
                    if (!sendCommand("save\r", "Stor"))
                        return false;
                    reboot();
                    return true;
                }
                wait(0.2);
            }
        }

        DBG("getw: %s\r\n", cmd);
    }

    // ssid
    sprintf(cmd, "set w s %s\r", ssid);
    if (!sendCommand(cmd, "AOK"))
        return false;

    //auth
    sprintf(cmd, "set w a %d\r", (wpa) ? 3 : 1);
    if (!sendCommand(cmd, "AOK"))
        return false;

    // if no dhcp, set ip, netmask and gateway
    if (!dhcp) {
        DBG("not dhcp\r");

        sprintf(cmd, "set i a %s\r\n", ip);
        if (!sendCommand(cmd, "AOK"))
            return false;

        sprintf(cmd, "set i n %s\r", netmask);
        if (!sendCommand(cmd, "AOK"))
            return false;

        sprintf(cmd, "set i g %s\r", gateway);
        if (!sendCommand(cmd, "AOK"))
            return false;
    }

    //key step
    if (wpa)
        sprintf(cmd, "set w p %s\r", phrase);
    else
        sprintf(cmd, "set w k %s\r", phrase);

    if (!sendCommand(cmd, "AOK"))
        return false;

    // auto join
    if (!sendCommand("set w j 1\r", "AOK"))
        return false;

    // save
    if (!sendCommand("save\r", "Stor"))
        return false;

    //join the network
    sprintf(cmd, "join %s\r", ssid);
    if (!sendCommand(cmd, "Associated"))
        return false;

    reboot();

    INFO("\r\nssid: %s\r\nphrase: %s\r\nsecurity: %s\r\n\r\n", this->ssid, this->phrase, (wpa) ? "WPA" : "WEP");
    return true;
}


bool Wifly::dnsLookup(const char * host, char * ip)
{
    string h = host;
    char cmd[30], rcv[30];
    int l = 0;
    char * point;
    int nb_digits = 0;

    // no dns needed
    if (atoi(host) > 0 && count(h.begin(), h.end(), '.') == 4) {
        strcpy(ip, host);
    }
    // dns needed
    else {
        sprintf(cmd, "lookup %s\r", host);
        if (!sendCommand(cmd, NULL, rcv))
            return false;
        DBG("lookup: %s\r\n", rcv);

        // look for the ip address
        char * begin = strstr(rcv, "=") + 1;
        for (int i = 0; i < 3; i++) {
            point = strstr(begin + l, ".");
            DBG("str: %s", begin + l);
            l += point - (begin + l) + 1;
        }
        DBG("str: %s", begin + l);
        while(*(begin + l + nb_digits) >= '0' && *(begin + l + nb_digits) <= '9') {
            DBG("digit: %c", *(begin + l + nb_digits));
            nb_digits++;
        }
        memcpy(ip, begin, l + nb_digits);
        ip[l+nb_digits] = 0;
        DBG("ip from dns: %s", ip);
    }
    return true;
}

bool Wifly::reboot()
{
    if (!sendCommand("reboot\r", "boot"))
        return false;
    wait(0.2);
    // wait that the module fetches an IP
    if (dhcp) {
        while(send("", 0, "DHCP=ON") == -1);
    } else {
        while(send("", 0, "Static") == -1);
    }
    flush();
    cmd_mode = false;
    return true;
}


void Wifly::flush()
{
    buf_wifly.flush();
}

bool Wifly::sendCommand(const char * cmd, const char * ack, char * res)
{
    if (!cmd_mode) {
        cmdMode();
    }
    if (send(cmd, strlen(cmd), ack, res) == -1) {
        ERR("sendCommand: cannot %s\r\n", cmd);
        exit();
        return false;
    }
    return true;
}

bool Wifly::cmdMode()
{
    if (send("$$$", 3, "CMD") == -1) {
        ERR("cannot enter in cmd mode\r\n");
        return false;
    }
    cmd_mode = true;
    return true;
}

bool Wifly::leave()
{
    if (!sendCommand("leave\r", "DeAuth"))
        return false;
    exit();
    return true;

}

bool Wifly::is_connected()
{
    return (tcp_status.read() ==  1) ? true : false;
}


void Wifly::reset()
{
    reset_pin = 0;
    wait(0.2);
    reset_pin = 1;
    wait(0.2);
}

bool Wifly::close()
{
    wait(0.25);
    if (!cmdMode())
        return false;
    if (send("close\r", 6, "CLOS") == -1)
        return false;
    exit();
    return true;
}


int Wifly::putc(char c)
{
    while (!wifi.writeable());
    return wifi.putc(c);
}


bool Wifly::read(char * str)
{
    int length = buf_wifly.available();
    if (length == 0)
        return false;
    for (int i = 0; i < length; i++)
        buf_wifly.dequeue(&str[i]);
    str[length] = 0;
    return true;
}


bool Wifly::exit()
{
    flush();
    if (send("exit\r", 5, "EXIT") == -1)
        return false;
    cmd_mode = false;
    return true;
}


int Wifly::readable()
{
    return buf_wifly.available();
}

int Wifly::writeable()
{
    return wifi.writeable();
}

char Wifly::getc()
{
    char c;
    while (!buf_wifly.available());
    buf_wifly.dequeue(&c);
    return c;
}

void Wifly::handler_rx(void)
{
    //read characters
    while (wifi.readable())
        buf_wifly.queue(wifi.getc());
}

void Wifly::attach_rx(bool callback)
{
    if (!callback)
        wifi.attach(NULL);
    else
        wifi.attach(this, &Wifly::handler_rx);
}


int Wifly::send(const char * str, int len, const char * ACK, char * res)
{
    char read;
    size_t found = string::npos;
    string checking;
    Timer tmr;
    int result = 0;

    DBG("will send: %s\r\n",str);

    attach_rx(false);

    //We flush the buffer
    while (wifi.readable())
        wifi.getc();

    if (!ACK || !strcmp(ACK, "NO")) {
        for (int i = 0; i < len; i++)
            result = (putc(str[i]) == str[i]) ? result + 1 : result;
    } else {
        //We flush the buffer
        while (wifi.readable())
            wifi.getc();

        tmr.start();
        for (int i = 0; i < len; i++)
            result = (putc(str[i]) == str[i]) ? result + 1 : result;

        while (1) {
            if (tmr.read() > 1.5) {
                //We flush the buffer
                while (wifi.readable())
                    wifi.getc();

                DBG("check: %s\r\n", checking.c_str());

                attach_rx(true);
                return -1;
            } else if (wifi.readable()) {
                read = wifi.getc();
                if ( read != '\r' && read != '\n') {
                    checking += read;
                    found = checking.find(ACK);
                    if (found != string::npos) {
                        wait(0.01);

                        //We flush the buffer
                        while (wifi.readable())
                            wifi.getc();

                        break;
                    }
                }
            }
        }
        DBG("check: %s\r\n", checking.c_str());

        attach_rx(true);
        return result;
    }

    //the user wants the result from the command (ACK == NULL, res != NULL)
    if ( res != NULL) {
        int i = 0;
        Timer timeout;
        timeout.start();
        tmr.reset();
        while (1) {
            if (timeout.read() > 3) {
                if (i == 0) {
                    res = NULL;
                    break;
                }
                res[i] = '\0';
                DBG("user str 1: %s\r\n", res);

                break;
            } else {
                if (tmr.read_ms() > 300) {
                    res[i] = '\0';
                    DBG("user str: %s\r\n", res);

                    break;
                }
                if (wifi.readable()) {
                    tmr.start();
                    read = wifi.getc();

                    // we drop \r and \n
                    if ( read != '\r' && read != '\n') {
                        res[i++] = read;
                    }
                }
            }
        }
        DBG("user str: %s\r\n", res);
    }

    //We flush the buffer
    while (wifi.readable())
        wifi.getc();

    attach_rx(true);
    DBG("result: %d\r\n", result)
    return result;
}