now this shit works

Dependencies:   BufferedSerial

Dependents:   IoTWeatherStation

Fork of ESP8266NodeMCUInterface by ESP8266

Files at this revision

API Documentation at this revision

Comitter:
geky
Date:
Wed Jun 03 21:44:20 2015 +0000
Parent:
35:22d30e936e4c
Child:
45:3cfb7406d993
Child:
46:4abb80f0a920
Commit message:
Reimplemented ESP8266 driver using the Nodemcu firmware

Changed in this revision

BufferedSerial.lib Show annotated file Show diff for this revision Revisions of this file
ESP8266/ESP8266.cpp Show annotated file Show diff for this revision Revisions of this file
ESP8266/ESP8266.h Show annotated file Show diff for this revision Revisions of this file
ESP8266Interface.cpp Show annotated file Show diff for this revision Revisions of this file
ESP8266Interface.h Show annotated file Show diff for this revision Revisions of this file
Socket/Endpoint.cpp Show annotated file Show diff for this revision Revisions of this file
Socket/TCPSocketConnection.cpp Show annotated file Show diff for this revision Revisions of this file
Socket/UDPSocket.cpp Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/BufferedSerial.lib	Wed Jun 03 21:44:20 2015 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/sam_grove/code/BufferedSerial/#9ee15ae3d1a3
--- a/ESP8266/ESP8266.cpp	Fri May 01 18:29:38 2015 +0000
+++ b/ESP8266/ESP8266.cpp	Wed Jun 03 21:44:20 2015 +0000
@@ -1,454 +1,395 @@
-/* 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 "ESP8266.h"
-#include "Endpoint.h"
-#include <string>
-#include <algorithm>
-
-//Debug is disabled by default
-#ifdef DEBUG
-#define DBG(x, ...)  printf("[ESP8266 : DBG]"x"\r\n", ##__VA_ARGS__);
-#define WARN(x, ...) printf("[ESP8266 : WARN]"x"\r\n", ##__VA_ARGS__);
-#define ERR(x, ...)  printf("[ESP8266 : ERR]"x"\r\n", ##__VA_ARGS__);
-#else
-#define DBG(x, ...)
-#define WARN(x, ...)
-#define ERR(x, ...)
-#endif
-
-#ifdef DEBUG
-#define INFO(x, ...) printf("[ESP8266 : INFO]"x"\r\n", ##__VA_ARGS__);
-#else
-#define INFO(x, ...)
-#endif
-
-#define ESP_MAX_TRY_JOIN 3
-#define ESP_MAXID 4 // the largest possible ID Value (max num of sockets possible)
-
-extern Serial pc;
-
-ESP8266 * ESP8266::inst;
-char* ip = NULL;
-
-ESP8266::ESP8266(   PinName tx, PinName rx, PinName _reset, const char * ssid, const char * phrase, uint32_t baud):
-    wifi(tx, rx), reset_pin(_reset), buf_ESP8266(256)
-{
-    memset(&state, 0, sizeof(state));
-
-    // change all ' ' in '$' in the ssid and the passphrase
-    strcpy(this->ssid, ssid);
-    for (int i = 0; i < strlen(ssid); i++) {
-        if (this->ssid[i] == ' ')
-            this->ssid[i] = '$';
-    }
-    strcpy(this->phrase, phrase);
-    for (int i = 0; i < strlen(phrase); i++) {
-        if (this->phrase[i] == ' ')
-            this->phrase[i] = '$';
-    }
-
-
-    inst = this;
-    attach_rx(false);
-
-    wifi.baud(baud); // initial baud rate of the ESP8266
-
-    state.associated = false;
-    state.cmdMode = false;
-}
-
-bool ESP8266::join()
-{
-    sendCommand( "AT+CWMODE=1", "change", NULL, 1000);
-    string cmd="AT+CWJAP=\""+(string)this->ssid+"\",\""+(string)this->phrase+"\"";
-    if( sendCommand( cmd.c_str(), "OK", NULL, 10000) ) {
-        // successfully joined the network
-        state.associated = true;
-        INFO("\r\nssid: %s\r\nphrase: %s\r\nsecurity: %s\r\n\r\n", this->ssid, this->phrase);
-        return true;
-    }
-    return false;
-}
-
-bool ESP8266::connect()
-{
-    sendCommand("AT+CWDHCP=1,1","OK",NULL,1000); // DHCP Enabled in Station Mode
-    return ESP8266::join();
-}
-
-bool ESP8266::is_connected()
-{
-    return true;
-}
-
-bool ESP8266::start(bool type,char* ip, int port, int id)
-{
-    // Error Check
-    if(id > ESP_MAXID) {
-        ERR("startUDPMulti: max id is: %d, id given is %d",ESP_MAXID,id);
-        return false;
-    }
-    // Single Connection Mode
-    if(id < 0) {
-        DBG("Start Single Connection Mode");
-        char portstr[5];
-        char idstr[2];
-        bool check [3] = {0};
-        sprintf(idstr,"%d",id);
-        sprintf(portstr, "%d", port);
-        switch(type) {
-            case ESP_UDP_TYPE : //UDP
-                check[0] = sendCommand(( "AT+CIPSTART=\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
-                break;
-            case ESP_TCP_TYPE : //TCP
-                check[0] = sendCommand(( "AT+CIPSTART=\"TCP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
-                break;
-            default:
-                ERR("Default hit for starting connection, this shouldnt be possible!!");
-                break;
-        }
-        check[1] = sendCommand("AT+CIPMODE=1", "OK", NULL, 1000);// go into transparent mode
-        check[2] = sendCommand("AT+CIPSEND", ">", NULL, 1000);// go into transparent mode
-        // check that all commands were sucessful
-        if(check[0] and check[1] and check[2]) {
-            DBG("Data Mode\r\n");
-            state.cmdMode = false;
-            return true;
-        } else {
-            DBG("\r\nstartUDPTransparent Failed for ip:%s, port:%d\r\n",ip,port);
-            return false;
-        }
-    }
-    // Multi Connection Mode
-    else {
-        //TODO: impliment Multi Connection Mode
-        ERR("Not currently Supported!");
-        return false;
-        
-//        DBG("Start Multi Connection Mode");
-//        char portstr[5];
-//        char idstr[2];
-//        bool check [3] = {0};
-//        sprintf(idstr,"%d",id);
-//        sprintf(portstr, "%d", port);
-//        switch(type) {
-//            case ESP_UDP_TYPE : //UDP
-//                check[0] = sendCommand(( "AT+CIPSTART=" + (string) idstr + ",\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
-//                break;
-//            case ESP_TCP_TYPE : //TCP
-//                check[0] = sendCommand(( "AT+CIPSTART=" + (string) idstr + ",\"TCP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
-//                break;
-//            default:
-//                ERR("Default hit for starting connection, this shouldnt be possible!!");
-//                break;
-//        }
-    }
-}
-
-bool ESP8266::startUDP(char* ip, int port)
-{
-    char portstr[5];
-    sprintf(portstr, "%d", port);
-    sendCommand(( "AT+CIPSTART=\"UDP\",\"" + (string) ip + "\"," + (string) portstr ).c_str(), "OK", NULL, 10000);
-
-    sendCommand("AT+CIPMODE=1", "OK", NULL, 1000);// go into transparent mode
-    sendCommand("AT+CIPSEND", ">", NULL, 1000);// go into transparent mode
-    DBG("Data Mode\r\n");
-    state.cmdMode = false;
-
-    return true;
-}
-
-bool ESP8266::close()
-{
-    send("+++",3);
-    wait(1);
-    state.cmdMode = true;
-    sendCommand("AT+CIPCLOSE","OK", NULL, 10000);
-    return true;
-}
-
-bool ESP8266::disconnect()
-{
-    // if already disconnected, return
-    if (!state.associated)
-        return true;
-    // send command to quit AP
-    sendCommand("AT+CWQAP", "OK", NULL, 10000);
-    state.associated = false;
-    return true;
-}
-
-/*
-    Assuming Returned data looks like this:
-    +CIFSR:STAIP,"192.168.11.2"
-    +CIFSR:STAMAC,"18:fe:34:9f:3a:f5"
-    grabbing IP from first set of quotation marks
-*/
-char* ESP8266::getIPAddress()
-{
-    char result[30] = {0};
-    int check = 0;
-    check = sendCommand("AT+CIFSR", NULL, result, 1000);
-    //pc.printf("\r\nReceivedInfo for IP Command is: %s\r\n",result);
-    ip = ipString;
-    if(check) {
-        // Success
-        string resultString(result);
-        uint8_t pos1 = 0, pos2 = 0;
-        //uint8_t pos3 = 0, pos4 = 0;
-        pos1 = resultString.find("+CIFSR:STAIP");
-        pos1 = resultString.find('"',pos1);
-        pos2 = resultString.find('"',pos1+1);
-        //pos3 = resultString.find('"',pos2+1); //would find mac address
-        //pos4 = resultString.find('"',pos3+1);
-        strncpy(ipString,resultString.substr(pos1,pos2).c_str(),sizeof(ipString));
-        ipString[pos2 - pos1 +1] = 0; // null terminate string correctly.
-        DBG("IP: %s\r\n",ipString);
-        ip = ipString;
-
-    } else {
-        // Failure
-        DBG("getIPAddress() failed\r\n");
-        ip = NULL;
-    }
-    return ip;
-}
-
-bool ESP8266::gethostbyname(const char * host, char * ip)
-{
-    string h = host;
-    int nb_digits = 0;
-
-    // no dns needed
-    int pos = h.find(".");
-    if (pos != string::npos) {
-        string sub = h.substr(0, h.find("."));
-        nb_digits = atoi(sub.c_str());
-    }
-    //printf("substrL %s\r\n", sub.c_str());
-    if (count(h.begin(), h.end(), '.') == 3 && nb_digits > 0) {
-        strcpy(ip, host);
-        return true;
-    } else {
-        // dns needed, not currently available
-        ERR("gethostbyname(): DNS Not currently available, only use IP Addresses!");
-        return false;
-    }
-}
-
-void ESP8266::reset()
-{
-    reset_pin = 0;
-    wait(0.2);
-    reset_pin = 1;
-    wait(1);
-
-    //send("+++",3);
-    //wait(1);
-    state.cmdMode = true;
-    sendCommand("AT", "OK", NULL, 1000);
-    sendCommand("AT+RST", "ready", NULL, 10000);
-    state.associated = false;
-
-}
-
-bool ESP8266::reboot()
-{
-    reset();
-    return true;
-}
-
-void ESP8266::handler_rx(void)
-{
-    //read characters
-    char c;
-    while (wifi.readable()) {
-        c=wifi.getc();
-        buf_ESP8266.queue(c);
-        //if (state.cmdMode) pc.printf("%c",c); //debug echo, needs fast serial console to prevent UART overruns
-    }
-}
-
-void ESP8266::attach_rx(bool callback)
-{
-    if (!callback)
-        wifi.attach(NULL);
-    else
-        wifi.attach(this, &ESP8266::handler_rx);
-}
-
-int ESP8266::readable()
-{
-    return buf_ESP8266.available();
-}
-
-int ESP8266::writeable()
-{
-    return wifi.writeable();
-}
-
-char ESP8266::getc()
-{
-    char c=0;
-    while (!buf_ESP8266.available());
-    buf_ESP8266.dequeue(&c);
-    return c;
-}
-
-int ESP8266::putc(char c)
-{
-    while (!wifi.writeable() || wifi.readable()); //wait for echoed command characters to be read first
-    return wifi.putc(c);
-}
-
-void ESP8266::flush()
-{
-    buf_ESP8266.flush();
-}
-
-int ESP8266::send(const char * buf, int len)
-{
-    //TODO: need to add handler for data > 2048B, this is the max packet size of the ESP8266.
-    const char* bufptr=buf;
-    for(int i=0; i<len; i++) {
-        putc((int)*bufptr++);
-    }
-    return len;
-}
-
-bool ESP8266::sendCommand(const char * cmd, const char * ACK, char * res, int timeout)
-{
-    char read;
-    size_t found = string::npos;
-    string checking;
-    Timer tmr;
-    int result = 0;
-
-    DBG("will send: %s\r\n",cmd);
-
-    attach_rx(true);
-
-    //We flush the buffer
-    while (readable())
-        getc();
-
-    if (!ACK || !strcmp(ACK, "NO")) {
-        for (int i = 0; i < strlen(cmd); i++) {
-            result = (putc(cmd[i]) == cmd[i]) ? result + 1 : result;
-            wait(.005); // prevents stuck recieve ready (?) need to let echoed character get read first
-        }
-        putc(13); //CR
-        wait(.005); // wait for echo
-        putc(10); //LF
-
-    } else {
-        //We flush the buffer
-        while (readable())
-            getc();
-
-        tmr.start();
-        for (int i = 0; i < strlen(cmd); i++) {
-            result = (putc(cmd[i]) == cmd[i]) ? result + 1 : result;
-            wait(.005); // wait for echo
-        }
-        putc(13); //CR
-        wait(.005); // wait for echo
-        putc(10); //LF
-
-        while (1) {
-            if (tmr.read_ms() > timeout) {
-                //We flush the buffer
-                while (readable())
-                    getc();
-
-                DBG("check: %s\r\n", checking.c_str());
-
-                attach_rx(true);
-                return -1;
-            } else if (readable()) {
-                read = getc();
-                printf("%c",read); //debug echo
-                if ( read != '\r' && read != '\n') {
-                    checking += read;
-                    found = checking.find(ACK);
-                    if (found != string::npos) {
-                        wait(0.01);
-
-                        //We flush the buffer
-                        while (readable())
-                            read = getc();
-                        printf("%c",read); //debug echo
-                        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() > 2) {
-                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 (readable()) {
-                    tmr.start();
-                    read = 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 (readable())
-        getc();
-
-    attach_rx(true);
-    DBG("result: %d\r\n", result)
-    return result;
-}
+/* 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 "ESP8266.h"
+#include "Endpoint.h"
+#include <string>
+#include <algorithm>
+
+//Debug is disabled by default
+#if 0
+#define DBG(x, ...)  printf("[ESP8266 : DBG]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__); 
+#define WARN(x, ...) printf("[ESP8266 : WARN]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__); 
+#define ERR(x, ...)  printf("[ESP8266 : ERR]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__); 
+#define INFO(x, ...) printf("[ESP8266 : INFO]"x" \t[%s,%d]\r\n", ##__VA_ARGS__,__FILE__,__LINE__); 
+#ifndef ESP8266_ECHO
+#define ESP8266_ECHO 1
+#endif
+#else
+#define DBG(x, ...)
+#define WARN(x, ...)
+#define ERR(x, ...)
+#define INFO(x, ...)
+#endif
+
+
+ESP8266 *ESP8266::_inst;
+
+ESP8266::ESP8266(PinName tx, PinName rx, PinName reset, int baud, int timeout) :
+        _serial(tx, rx), _reset_pin(reset) {
+    INFO("Initializing ESP8266 object");
+    
+    _baud = baud;
+    _timeout = timeout;
+    
+    _serial.baud(_baud);
+    
+    _inst = this;
+}
+
+bool ESP8266::reset() {
+    _reset_pin = 0;
+    wait_us(20);
+    _reset_pin = 1;
+    
+    // Send reboot command in case reset is not connected
+    return command("\x03\r\n" "node.restart()") && execute();
+}
+
+bool ESP8266::init() {
+    // Reset device to clear state
+    return reset();
+}
+
+bool ESP8266::connect(const char *ssid, const char *phrase) {
+    // Configure as station with passed ssid and passphrase
+    if (!(command("wifi.setmode(wifi.STATION);") &&
+          command("wifi.sta.config('") &&
+          command(ssid) &&
+          command("','") &&
+          command(phrase) &&
+          command("')") &&
+          execute()))
+        return false;
+        
+    // Wait for an IP address
+    // TODO WISHLIST make this a seperate check so it can run asynch?
+    Timer timer;
+    timer.start();
+    
+    while (true) {
+        int ip_len = 15;
+        
+        if (!(command("ip=wifi.sta.getip();") &&
+              command("print(ip)") &&
+              execute(_ip, &ip_len)))
+            return false;
+        
+        _ip[ip_len] = 0;
+        
+        if (strcmp(_ip, "nil") != 0)
+            return true;
+        
+        if (timer.read_ms() > _timeout)
+            return false;
+    }
+}
+
+bool ESP8266::disconnect() {
+    int ip_len = 15;
+    
+    if (!(command("wifi.sta.disconnect();") &&
+          command("ip=wifi.sta.getip();") &&
+          command("print(ip)") &&
+          execute(_ip, &ip_len)))
+        return false;
+        
+    _ip[ip_len] = 0;
+    
+    return (strcmp(_ip, "nil") == 0);
+}
+
+bool ESP8266::is_connected() {
+    return (strcmp(_ip, "nil") != 0);
+}
+
+bool ESP8266::open(bool type, char* ip, int port, int id) {
+    // Create the actual connection
+    if (!(command("c=net.createConnection(") &&
+          command(type ? "net.TCP" : "net.UDP") &&
+          command(")") &&
+          execute()))
+        return false;
+        
+    // Setup handlers for connecting and disconnecting
+    if (!(command("cc=nil;") &&
+          command("c:on('connection',function() cc=true end);") &&
+          command("c:on('disconnection',function() cc=false end)") &&
+          execute()))
+        return false;
+    
+    // Setup functions for sending and recieving characters on the esp side
+    if (!(command("cm='';") &&
+          command("function cs(n) c:send(n) end;") &&
+          command("function cr(n) print(cm:sub(1,n)); cm=cm:sub(n+1,-1) end;") && 
+          command("function ca() print(#cm) end;") &&
+          command("c:on('receive',function(c,n) cm=cm..n end)") && 
+          execute()))
+        return false;
+    
+    // Convert port to a string    
+    char port_buf[16];
+    sprintf(port_buf, "%d", port);
+        
+    // Connect to the ip address
+    if (!(command("c:connect(") &&
+          command(port_buf) &&
+          command(",'") &&
+          command(ip) &&
+          command("')") &&
+          execute()))
+        return false;
+        
+    // Wait for it to connect
+    // TODO WISHLIST make this a seperate check so it can run asynch?
+    Timer timer;
+    timer.start();
+    
+    while (true) {
+        char con_buf[5];
+        int con_len = 5;
+        
+        if (!(command("print(cc)") && execute(con_buf, &con_len)))
+            return false;
+        
+        if (memcmp(con_buf, "true", con_len) == 0)
+            return true;
+        else if (memcmp(con_buf, "false", con_len) == 0)
+            return false;
+        
+        if (timer.read_ms() > _timeout)
+            return false;
+    }
+}
+    
+bool ESP8266::close() {
+    return command("c:close();" "c=nil") && execute();
+}
+
+bool ESP8266::send(const char *buffer, int len) {
+    if (!(command("cs('") &&
+          payload(buffer, len) &&
+          command("')") &&
+          execute()))
+        return false;
+    
+    return true;
+}
+
+bool ESP8266::recv(char *buffer, int *len) {
+    char len_buf[16];
+    sprintf(len_buf, "%d", *len);
+    
+    if (!(command("cr(") &&
+          command(len_buf) &&
+          command(")") && 
+          execute(buffer, len)))
+        return false;
+    
+    return true;
+}
+
+int ESP8266::putc(char c) {
+    char buffer[1] = { c };
+    
+    return send(buffer, 1) ? 0 : -1;
+}
+
+int ESP8266::getc() {
+    char buffer[1];
+    
+    while (true) {
+        int len = 1;
+        
+        if (!recv(buffer, &len))
+            return -1;
+            
+        if (len > 0)
+            break;
+    }
+    
+    return buffer[0];
+}
+
+int ESP8266::writeable() {
+    // Always succeeds since message can be temporarily stored on the esp
+    return 1;
+}
+
+int ESP8266::readable() {
+    char count_buf[16];
+    int count_len = 15;
+    
+    if (!(command("ca()") && execute(count_buf, &count_len)))
+        return false;
+        
+    count_buf[count_len] = 0;
+    return atoi(count_buf);
+}   
+
+const char *ESP8266::getIPAddress() {
+    if (strcmp(_ip, "nil") != 0)
+        return _ip;
+    else
+        return 0;
+}
+
+bool ESP8266::getHostByName(const char *host, char *ip) {
+    if (!(command("dh='") && 
+          command(host) &&
+          command("';") &&
+          command("dn=nil;") &&
+          command("if dh:match('%d+.%d+.%d+.%d+') then ") &&
+          command("dn=dh ") &&
+          command("else ") &&
+          command("dc=net.createConnection(net.TCP);") &&
+          command("dc:dns(dh,function(dc,ip) dn=ip end);") &&
+          command("dc=nil ") &&
+          command("end") &&
+          execute()))
+        return false;
+
+    // Wait for a response
+    Timer timer;
+    timer.start();
+    
+    while (true) {
+        int ip_len = 15;
+        
+        if (!(command("print(dn)") && execute(ip, &ip_len)))
+            return false;
+            
+        ip[ip_len] = 0;
+            
+        if (strcmp(ip, "nil") != 0)
+            return true;
+        
+        if (timer.read_ms() > _timeout)
+            return false;
+    }
+}
+
+int ESP8266::serialgetc() {
+    Timer timer;
+    timer.start();
+    
+    while (true) {
+        if (_serial.readable()) {
+            char c = _serial.getc();
+#ifdef ESP8266_ECHO
+            printf("%c", c);
+#endif
+            return c;
+        }
+            
+        if (timer.read_ms() > _timeout)
+            return -1;
+    }
+}
+
+int ESP8266::serialputc(char c) {
+    Timer timer;
+    timer.start();
+    
+    while (true) {
+        if (_serial.writeable())
+            return _serial.putc(c);
+            
+        if (timer.read_ms() > _timeout)
+            return -1;
+    }
+}
+
+bool ESP8266::discardEcho() {
+    while (true) {
+        int c = serialgetc();
+        
+        if (c < 0)
+            return false;
+        else if (c == '>')
+            return true;
+    }
+}
+
+bool ESP8266::command(const char *cmd) {
+    DBG("command sent:\t %s", cmd);
+    
+    for (int i = 0; cmd[i]; i++) {
+        if (serialputc(cmd[i]) < 0)
+            return false;
+    }
+    
+    return true;
+}
+
+bool ESP8266::payload(const char *data, int len) {
+    for (int i = 0; i < len; i++) {
+        int a = data[i] / 100;
+        int b = (data[i] - a*100) / 10;
+        int c = (data[i] - a*100 - b*10);
+        
+        if (serialputc('\\') < 0 ||
+            serialputc(a + '0') < 0 ||
+            serialputc(b + '0') < 0 ||
+            serialputc(c + '0') < 0)
+            return false;
+    }
+    
+    return true;
+}   
+
+bool ESP8266::execute(char *resp_buf, int *resp_len) {
+    // Finish command with a newline
+    if (serialputc('\r') < 0 || serialputc('\n') < 0)
+        return false;
+        
+    // Drop echoed string
+    while (true) {
+        int c = serialgetc();
+        
+        if (c < 0)
+            return false;
+        else if (c == '\n')
+            break;
+    }
+        
+    // Read in response if any
+    if (resp_buf && resp_len) {
+        int i;
+        
+        for (i = 0; i < *resp_len; i++) {
+            int c = serialgetc();
+                
+            if (c < 0)
+                return false;
+            
+            if (c == '\r') {
+                *resp_len = i;
+                break;
+            }
+            
+            resp_buf[i] = c;
+        }
+        
+        DBG("command response:\t %.*s", *resp_len, resp_buf);
+    }
+    
+    // Flush to next prompt
+    return discardEcho();
+}
--- a/ESP8266/ESP8266.h	Fri May 01 18:29:38 2015 +0000
+++ b/ESP8266/ESP8266.h	Wed Jun 03 21:44:20 2015 +0000
@@ -1,212 +1,238 @@
-/* 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.
- *
- * @section DESCRIPTION
- *
- * ESP8266 serial wifi module
- *
- * Datasheet:
- *
- * http://www.electrodragon.com/w/Wi07c
- */
-
-#ifndef ESP8266_H
-#define ESP8266_H
-
-#include "mbed.h"
-#include "CBuffer.h"
-
-#define DEFAULT_WAIT_RESP_TIMEOUT 500
-#define ESP_TCP_TYPE 1
-#define ESP_UDP_TYPE 0 
-
-/**
- * The ESP8266 class
- */
-class ESP8266
-{
-
-public:
-    /**
-    * Constructor
-    *
-    * @param tx mbed pin to use for tx line of Serial interface
-    * @param rx mbed pin to use for rx line of Serial interface
-    * @param reset reset pin of the wifi module ()
-    * @param ssid ssid of the network
-    * @param phrase WEP, WPA or WPA2 key
-    * @param baud the baudrate of the serial connection
-    */
-    ESP8266( PinName tx, PinName rx, PinName reset, const char * ssid, const char * phrase, uint32_t baud );
-
-    /**
-    * Connect the wifi module to the ssid contained in the constructor.
-    *
-    * @return true if connected, false otherwise
-    */
-    bool join();
-
-    /**
-    * Same as Join: connect to the ssid and get DHCP settings
-    * @return true if successful
-    */
-    bool connect();
-    
-    /**
-    * Check connection to the access point
-    * @return true if successful
-    */
-    bool is_connected();
-
-    /**
-    * Disconnect the ESP8266 module from the access point
-    *
-    * @return true if successful
-    */
-    bool disconnect();
-    
-    /*
-    * Start up a UDP or TCP Connection
-    * @param type 0 for UDP, 1 for TCP
-    * @param ip A string that contains the IP, no quotes
-    * @param port Numerical port number to connect to
-    * @param id number between 0-4, if defined it denotes ID to use in multimode (Default to Single connection mode with -1)
-    * @return true if sucessful, 0 if fail
-    */
-    bool start(bool type, char* ip, int port, int id = -1);
-
-    /*
-    * Legacy Start for UDP only connection in transparent mode
-    * @param ip A string that contains the IP, no quotes
-    * @param port Numerical port number to connect to
-    */
-    bool startUDP(char* ip, int port);
-
-    /**
-    * Close a connection
-    *
-    * @return true if successful
-    */
-    bool close();
-    
-    /**
-    * Return the IP address 
-    * @return IP address as a string
-    */
-    char* getIPAddress();
-
-    /**
-    * Return the IP address from host name
-    * @return true on success, false on failure
-    */    
-    bool gethostbyname(const char * host, char * ip);
-
-    /**
-    * Reset the wifi module
-    */
-    void reset();
-    
-    /**
-    * Reboot the wifi module
-    */
-    bool reboot();
-
-    /**
-    * Check if characters are available
-    *
-    * @return number of available characters
-    */
-    int readable();
-
-    /**
-    * Check if characters are available
-    *
-    * @return number of available characters
-    */
-    int writeable();
-
-    /**
-    * Read a character
-    *
-    * @return the character read
-    */
-    char getc();
-
-    /**
-    * Write a character
-    *
-    * @param the character which will be written
-    */
-    int putc(char c);
-
-    /**
-    * Flush the buffer
-    */
-    void flush();
-
-    /**
-    * Send a command to the wifi module. Check if the module is in command mode. If not enter in command mode
-    *
-    * @param str string to be sent
-    * @param ACK string which must be acknowledge by the wifi module. If ACK == NULL, no string has to be acknoledged. (default: "NO")
-    * @param res this field will contain the response from the wifi module, result of a command sent. This field is available only if ACK = "NO" AND res != NULL (default: NULL)
-    *
-    * @return true if successful
-    */
-    bool sendCommand(const char * cmd, const char * ack = NULL, char * res = NULL, int timeout = DEFAULT_WAIT_RESP_TIMEOUT);
-
-    /**
-    * Send a string to the wifi module by serial port. This function desactivates the user interrupt handler when a character is received to analyze the response from the wifi module.
-    * Useful to send a command to the module and wait a response.
-    *
-    *
-    * @param str string to be sent
-    * @param len string length
-    * @param ACK string which must be acknowledge by the wifi module. If ACK == NULL, no string has to be acknoledged. (default: "NO")
-    * @param res this field will contain the response from the wifi module, result of a command sent. This field is available only if ACK = "NO" AND res != NULL (default: NULL)
-    *
-    * @return true if ACK has been found in the response from the wifi module. False otherwise or if there is no response in 5s.
-    */
-    int send(const char * buf, int len);
-
-    static ESP8266 * getInstance() {
-        return inst;
-    };
-
-protected:
-    RawSerial wifi;
-    DigitalOut reset_pin;
-    char phrase[30];
-    char ssid[30];
-    char ipString[20];
-    CircBuffer<char> buf_ESP8266;
-
-    static ESP8266 * inst;
-
-    void attach_rx(bool null);
-    void handler_rx(void);
-
-
-    typedef struct STATE {
-        bool associated;
-        bool cmdMode;
-    } State;
-
-    State state;
-};
-
+/* 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.
+ *
+ * @section DESCRIPTION
+ *
+ * ESP8266 serial wifi module
+ *
+ * Datasheet:
+ *
+ * http://www.electrodragon.com/w/Wi07c
+ */
+
+#ifndef ESP8266_H
+#define ESP8266_H
+
+#include "mbed.h"
+#include "CBuffer.h"
+#include "BufferedSerial.h"
+
+#define ESP_TCP_TYPE 1
+#define ESP_UDP_TYPE 0 
+
+/**
+ * The ESP8266 class
+ */
+class ESP8266
+{
+
+public:
+    /**
+    * Constructor
+    *
+    * @param tx mbed pin to use for tx line of Serial interface
+    * @param rx mbed pin to use for rx line of Serial interface
+    * @param reset reset pin of the wifi module ()
+    * @param baud the baudrate of the serial connection
+    * @param timeout the timeout of the serial connection
+    */
+    ESP8266(PinName tx, PinName rx, PinName reset, int baud = 9600, int timeout = 3000);
+    
+    /**
+    * Initialize the wifi hardware
+    *
+    * @return true if successful
+    */
+    bool init();
+
+    /**
+    * Connect the wifi module to the specified ssid.
+    *
+    * @param ssid ssid of the network
+    * @param phrase WEP, WPA or WPA2 key
+    * @return true if successful
+    */
+    bool connect(const char *ssid, const char *phrase);
+    
+    /**
+    * Check connection to the access point
+    * @return true if successful
+    */
+    bool is_connected();
+
+    /**
+    * Disconnect the ESP8266 module from the access point
+    *
+    * @return true if successful
+    */
+    bool disconnect();
+    
+    /*
+    * Start up a UDP or TCP Connection
+    *
+    * @param type 0 for UDP, 1 for TCP
+    * @param ip A string that contains the IP, no quotes
+    * @param port Numerical port number to connect to
+    * @param id number between 0-4, if defined it denotes ID to use in multimode (Default to Single connection mode with -1)
+    * @return true if sucessful, 0 if fail
+    */
+    bool open(bool type, char* ip, int port, int id = -1);
+    
+    /**
+    * Close a connection
+    *
+    * @return true if successful
+    */
+    bool close();
+    
+    /**
+    * Read a character or block
+    *
+    * @return the character read or -1 on error
+    */
+    int getc();
+    
+    /**
+    * Write a character
+    *
+    * @param the character which will be written
+    * @return -1 on error
+    */
+    int putc(char c);
+    
+    /**
+    * Write a string
+    *
+    * @param buffer the buffer that will be written
+    * @param len the length of the buffer
+    * @return true on success
+    */
+    bool send(const char *buffer, int len);
+
+    /**
+    * Read a string without blocking
+    *
+    * @param buffer the buffer that will be written
+    * @param len the length of the buffer, is replaced by read length
+    * @return true on success
+    */
+    bool recv(char *buffer, int *len);
+    
+    /**
+    * Check if wifi is writable
+    *
+    * @return 1 if wifi is writable
+    */
+    int writeable();
+    
+    /**
+    * Check if wifi is readable
+    *
+    * @return number of characters available
+    */
+    int readable();
+    
+    /**
+    * Return the IP address 
+    * @return IP address as a string
+    */
+    const char *getIPAddress();
+
+    /**
+    * Return the IP address from host name
+    * @return true on success, false on failure
+    */    
+    bool getHostByName(const char *host, char *ip);
+
+    /**
+    * Reset the wifi module
+    */
+    bool reset();
+
+    /**
+    * Obtains the current instance of the ESP8266
+    */
+    static ESP8266 *getInstance() {
+        return _inst;
+    };
+    
+private:
+    /**
+    * Read a character with timeout
+    *
+    * @return the character read or -1 on timeout
+    */
+    int serialgetc();
+    
+    /**
+    * Write a character
+    *
+    * @param the character which will be written
+    * @return -1 on timeout
+    */
+    int serialputc(char c);
+    
+    /**
+    * Discards echoed characters
+    *
+    * @return true if successful
+    */
+    bool discardEcho();
+    
+    /**
+    * Send part of a command to the wifi module.
+    *
+    * @param cmd string to be sent
+    * @param len optional length of cmd
+    * @param sanitize flag indicating if cmd is actually payload and needs to be escaped
+    * @return true if successful
+    */
+    bool command(const char *cmd);
+    
+    /**
+    * Sanitizes and sends payload to wifi module 
+    *
+    * @param data data to send
+    * @param len length of data
+    * @return true if successful
+    */
+    bool payload(const char *data, int len);
+    
+    /**
+    * Execute the command sent by command
+    *
+    * @param resp_buf pointer to buffer to store response from the wifi module
+    * @param resp_len len of buffer to store response from the wifi module, is replaced by read length
+    * @return true if successful
+    */
+    bool execute(char *resp_buffer = 0, int *resp_len = 0);
+
+protected:
+    BufferedSerial _serial;
+    DigitalOut _reset_pin;
+
+    static ESP8266 * _inst;
+    
+    // TODO WISHLIST: ipv6?
+    // this requires nodemcu support
+    char _ip[16];
+    
+    int _baud;
+    int _timeout;
+};
+
 #endif
\ No newline at end of file
--- a/ESP8266Interface.cpp	Fri May 01 18:29:38 2015 +0000
+++ b/ESP8266Interface.cpp	Wed Jun 03 21:44:20 2015 +0000
@@ -1,28 +1,22 @@
 #include "ESP8266Interface.h"
 
-ESP8266Interface::ESP8266Interface( PinName tx, PinName rx, PinName reset,
-                                const char * ssid, const char * phrase, uint32_t baud ) :
-    ESP8266(tx, rx, reset, ssid, phrase, baud )
-{
+ESP8266Interface::ESP8266Interface(PinName tx, PinName rx, PinName reset, 
+                                   int baud, int timeout) :
+        ESP8266(tx, rx, reset, baud, timeout) {
 }
 
-int ESP8266Interface::init()
-{
-    ESP8266::reset();
-    return 0;
+bool ESP8266Interface::init() {
+    return ESP8266::init();
 }
 
-bool ESP8266Interface::connect()
-{
-    return ESP8266::connect();
+bool ESP8266Interface::connect(const char * ssid, const char * phrase) {
+    return ESP8266::connect(ssid, phrase);
 }
 
-int ESP8266Interface::disconnect()
-{
+int ESP8266Interface::disconnect() {
     return ESP8266::disconnect();
 }
 
-char * ESP8266Interface::getIPAddress()
-{
+const char *ESP8266Interface::getIPAddress() {
     return ESP8266::getIPAddress();
 }
\ No newline at end of file
--- a/ESP8266Interface.h	Fri May 01 18:29:38 2015 +0000
+++ b/ESP8266Interface.h	Wed Jun 03 21:44:20 2015 +0000
@@ -32,40 +32,42 @@
     /**
     * Constructor
     *
-    * \param tx mbed pin to use for tx line of Serial interface
-    * \param rx mbed pin to use for rx line of Serial interface
-    * \param reset reset pin of the wifi module ()
-    * \param ssid ssid of the network
-    * \param phrase WEP or WPA key
-    * \param baud the baudrate of the serial connection (defaults to 115200, diff revs of the firmware use diff baud rates
+    * @param tx mbed pin to use for tx line of Serial interface
+    * @param rx mbed pin to use for rx line of Serial interface
+    * @param reset reset pin of the wifi module ()
+    * @param baud the baudrate of the serial connection
+    * @param timeout the timeout of the serial connection
     */
-  ESP8266Interface(PinName tx, PinName rx, PinName reset, const char * ssid, const char * phrase, uint32_t baud = 115200 );
-
-  /** Initialize the interface with DHCP.
-  * Initialize the interface and configure it to use DHCP (no connection at this point).
-  * \return 0 on success, a negative number on failure
-  */
-  int init(); //With DHCP
+    ESP8266Interface(PinName tx, PinName rx, PinName reset, int baud = 9600, int timeout = 3000);
+    
+    /**
+    * Initialize the wifi hardware
+    *
+    * @return true if successful
+    */
+    bool init();
 
-  /** Connect
-  * Bring the interface up, start DHCP if needed.
-  * \return 0 on success, a negative number on failure
-  */
-  bool connect();
+    /**
+    * Connect the wifi module to the specified ssid.
+    *
+    * @param ssid ssid of the network
+    * @param phrase WEP, WPA or WPA2 key
+    * @return true if successful
+    */
+    bool connect(const char *ssid, const char *phrase);
   
-  /** Disconnect
-  * Bring the interface down
-  * \return 0 on success, a negative number on failure
-  */
-  int disconnect();
+    /**
+    * Disconnect the ESP8266 module from the access point
+    *
+    * @return true if successful
+    */
+    int disconnect();
   
-  /** Get IP address
-  *
-  * \return ip address
-  */
-  char* getIPAddress();
-  
-private:
+    /** Get IP address
+    *
+    * @return Either a pointer to the internally stored IP address or null if not connected
+    */
+    const char *getIPAddress();
 };
 
 #include "UDPSocket.h"
--- a/Socket/Endpoint.cpp	Fri May 01 18:29:38 2015 +0000
+++ b/Socket/Endpoint.cpp	Wed Jun 03 21:44:20 2015 +0000
@@ -42,7 +42,7 @@
 int Endpoint::set_address(const char* host, const int port)
 {
     //Resolve DNS address or populate hard-coded IP address
-    if(ESP8266->gethostbyname(host, _ipAddress)) {
+    if(ESP8266->getHostByName(host, _ipAddress)) {
         _port = port;
         return 0;
     } else {
--- a/Socket/TCPSocketConnection.cpp	Fri May 01 18:29:38 2015 +0000
+++ b/Socket/TCPSocketConnection.cpp	Wed Jun 03 21:44:20 2015 +0000
@@ -51,7 +51,7 @@
 //        return -1;
 //    }
 //    _is_connected = true;
-    _is_connected = ESP8266->start(ESP_TCP_TYPE,_ipAddress,_port);
+    _is_connected = ESP8266->open(ESP_TCP_TYPE,_ipAddress,_port);
     if(_is_connected) { //success
         return 0;
     } else { // fail
@@ -71,16 +71,14 @@
         return -1;
     }
     Timer tmr;
-    int idx = 0;
     tmr.start();
     while ((tmr.read_ms() < _timeout) || _blocking) {
 
-        idx += wifi->send(data, length);
-
-        if (idx == length)
-            return idx;
+        if (wifi->send(data, length))
+            return length;
     }
-    return (idx == 0) ? -1 : idx;
+    
+    return -1;
 
     //return wifi->send(data,length);
 //
@@ -211,7 +209,6 @@
 //    _is_connected = (n != 0);
 //
 //    return n;
-
 }
 
 // -1 if unsuccessful, else number of bytes received
@@ -240,5 +237,8 @@
 //        }
 //    }
 //    return readLen;
-    return 0;
+    if (!wifi->recv(data, &length))
+        return -1;
+        
+    return length;
 }
--- a/Socket/UDPSocket.cpp	Fri May 01 18:29:38 2015 +0000
+++ b/Socket/UDPSocket.cpp	Wed Jun 03 21:44:20 2015 +0000
@@ -53,7 +53,7 @@
     // initialize transparent mode if not already done
     if(!endpoint_configured) {
         // initialize UDP (default id of -1 means transparent mode)
-        if(!wifi->start(ESP_UDP_TYPE, remote._ipAddress, remote._port, remote._id)) {
+        if(!wifi->open(ESP_UDP_TYPE, remote._ipAddress, remote._port, remote._id)) {
             return(-1);
         }
         endpoint_configured = true;