Class library for using the ESP8266 wifi module.

Files at this revision

API Documentation at this revision

Comitter:
grantphillips
Date:
Mon Jun 11 17:56:55 2018 +0000
Commit message:
V1.0

Changed in this revision

ESP8266.cpp Show annotated file Show diff for this revision Revisions of this file
ESP8266.h Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ESP8266.cpp	Mon Jun 11 17:56:55 2018 +0000
@@ -0,0 +1,443 @@
+#include "ESP8266.h"
+#include "mbed.h"
+
+/***************************** Public functions ******************************/
+ESP8266::ESP8266(PinName Tx, PinName Rx, PinName Rst) : esp(Tx, Rx), _rst(Rst) {
+    esp.baud(115200);
+    mDEBUG = false;
+}
+
+bool ESP8266::startup(uint8_t mode) {
+    
+    if(mode < 1 || mode > 3)    //only 3 valid modes
+        return false;
+    _rst=0;
+    wait(1.0);
+    _rst=1;
+    wait(1.0);
+    if(!kick())             //check if connected
+        return(false);
+    if(!reset())            //reset ESP8266
+        return(false);
+    if(!setWiFiMode(mode))  //set the WiFi mode
+        return(false);
+    if(!setMux(true))       //set to multiple connections
+        return false;
+
+    rxtemp_idx=0;
+    //rxmsg_idx= 0;           
+    new_rxmsg = false;    
+    rxpass1=false, rxpass2=false, rxpass3=false;
+    
+    return true;
+}
+
+void ESP8266::getVersion(char* version) {
+    string ver;
+
+    eATGMR(ver);
+    strcpy(version, ver.c_str());
+}
+
+void ESP8266::getAPList(char* list) {
+    string lst;
+    
+    eATCWLAP(lst);
+    strcpy(list, lst.c_str());
+}
+
+bool ESP8266::setSoftAPParam(string ssid, string pwd, uint8_t chl, uint8_t ecn) {
+    return sATCWSAP(ssid, pwd, chl, ecn);
+}
+
+bool ESP8266::DHCP(bool enabled, int mode) {
+    return sATCWDHCP(enabled, mode);
+}
+
+bool ESP8266::joinAP(string ssid, string pwd) {
+    return sATCWJAP(ssid, pwd);
+}
+
+void ESP8266::getLocalIP(char* LocalIP) {
+    string lst;
+    
+    eATCIFSR(lst);
+    strcpy(LocalIP, lst.c_str());
+}
+
+bool ESP8266::setLocalIP(string LocalIP) {
+    return sATCIPSTA(LocalIP);
+}
+
+bool ESP8266::setSoftAPIP(string LocalIP) {
+    return sATCIPAP(LocalIP);
+}
+
+bool ESP8266::TCPServerStart(uint32_t port) {
+    if (sATCIPSERVER(1, port)) {
+        esp.attach(this,&ESP8266::RxInterrupt);
+        return true;
+    }
+    return false;
+}
+
+bool ESP8266::TCPPacketReceived(void) {
+    return new_rxmsg;
+}
+
+void ESP8266::TCPPacketRead(uint8_t *ID, uint32_t *LEN, char DATA[]) {
+    *ID = packetID;
+    *LEN = packetLen;
+    strcpy(DATA, packetData);
+    new_rxmsg=false;
+}
+
+bool ESP8266::TCPPacketSend(uint8_t ID, uint32_t LEN, char DATA[]) {
+    bool ret;
+    
+    esp.attach(NULL);
+    ret=sATCIPSENDMultiple(ID, DATA, LEN);
+    esp.attach(this,&ESP8266::RxInterrupt);
+    return ret;
+}
+
+/***************************** Private functions *****************************/
+bool ESP8266::kick(void) {
+    return eAT();
+}
+
+bool ESP8266::reset(void) {
+    unsigned long start;
+    if (eATRST()) {
+        wait_ms(2000);
+        t.start();
+        start = t.read_ms();
+        while (t.read_ms() - start < 3000) {
+            if (eAT()) {
+                wait_ms(1500); /* Waiting for stable */
+                return true;
+            }
+            wait_ms(100);
+        }
+    }
+    return false;
+}
+
+bool ESP8266::setWiFiMode(uint8_t mode) {
+    switch(mode) {
+        case 1:  {
+                    if (sATCWMODE(1)) 
+                        return true;
+                    else
+                        return false;  
+                 } 
+        case 2:  {
+                    if (sATCWMODE(2)) 
+                        return true;
+                    else
+                        return false;  
+                 } 
+        case 3:  {
+                    if (sATCWMODE(3)) 
+                        return true;
+                    else
+                        return false;  
+                 } 
+        default: return false;
+    } 
+}
+
+bool ESP8266::setMux(bool onoff) {
+    if(onoff)
+        return sATCIPMUX(1);
+    else
+        return sATCIPMUX(0);
+}
+
+bool ESP8266::recvFind(string target, uint32_t timeout) {
+    string data_tmp;
+    data_tmp = recvString(target, timeout);
+    if (data_tmp.find(target) != std::string::npos) {
+        return true;
+    }
+    return false;
+}
+
+string ESP8266::recvString(string target, uint32_t timeout) {
+    string data;
+    char a;
+    t.start();
+    unsigned long start = t.read_ms();
+    while (t.read_ms() - start < timeout) {
+        while(esp.readable() > 0) {
+            a = esp.getc();
+            data += a;
+        }
+        if (data.find(target) != std::string::npos) {
+            break;
+        }   
+    }
+    t.stop();
+    
+    return data;
+}
+
+string ESP8266::recvString(string target1, string target2, uint32_t timeout) {
+    string data;
+    char a;
+    t.start();
+    unsigned long start = t.read_ms();
+    while (t.read_ms() - start < timeout) {
+        while(esp.readable() > 0) {
+            a = esp.getc();
+            data += a;
+        }
+        if (data.find(target1) != std::string::npos) {
+            break;
+        } else if (data.find(target2) != std::string::npos) {
+            break;
+        }
+    }
+    t.stop();
+
+    return data;
+}
+
+string ESP8266::recvString(string target1, string target2, string target3, uint32_t timeout) {
+    string data;
+    char a;
+    t.start();
+    unsigned long start = t.read_ms();
+    while (t.read_ms() - start < timeout) {
+        while(esp.readable() > 0) {
+            a = esp.getc();
+            data += a;
+        }
+        if (data.find(target1) != std::string::npos) {
+            break;
+        } else if (data.find(target2) != std::string::npos) {
+            break;
+        } else if (data.find(target3) != std::string::npos) {
+            break;
+        }
+    }
+    t.stop();
+
+    return data;
+}
+
+bool ESP8266::recvFindAndFilter(string target, string begin, string end, string &data, uint32_t timeout) {
+    string data_tmp;
+    data_tmp = recvString(target, timeout);
+    if (data_tmp.find(target) != std::string::npos) {
+        int32_t index1 = data_tmp.find(begin);
+        int32_t index2 = data_tmp.find(end);
+        if (index1 != std::string::npos && index2 != std::string::npos) {
+            index1 += begin.length();
+            data = data_tmp.substr(index1, index2-index1);
+            return true;
+        }
+    }
+    data = "";
+    return false;
+}
+
+
+
+
+/************************ Private AT Command Functions ***********************/
+bool ESP8266::eAT(void) {
+    esp.printf("AT\r\n");
+    return recvFind("OK", 2000);
+}
+
+bool ESP8266::eATRST(void) {
+    esp.printf("AT+RST\r\n");
+    return recvFind("OK", 2000);
+}
+
+bool ESP8266::eATGMR(string &version) {
+    esp.printf("AT+GMR\r\n");
+    return recvFindAndFilter("OK", "\r\r\n", "\r\nSDK", version);    
+}
+
+bool ESP8266::sATCWMODE(uint8_t mode) {
+    string data;
+    esp.printf("AT+CWMODE=%d\r\n", mode);
+    
+    data = recvString("OK", "no change");
+    if (data.find("OK") != std::string::npos || data.find("no change") != std::string::npos) {
+        return true;
+    }
+    return false;
+}
+
+bool ESP8266::sATCIPMUX(uint8_t mode)
+{
+    string data;
+    esp.printf("AT+CIPMUX=%d\r\n",mode);
+    
+    data = recvString("OK", "Link is builded");
+    if (data.find("OK") != std::string::npos) {
+        return true;
+    }
+    return false;
+}
+
+bool ESP8266::eATCWLAP(string &list) {
+    string data;
+    esp.printf("AT+CWLAP\r\n");
+    return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", list, 10000);
+}
+
+bool ESP8266::sATCWJAP(string ssid, string pwd) {
+    string data;
+    esp.printf("AT+CWJAP=\"%s\",\"%s\"\r\n", ssid.c_str(), pwd.c_str());
+    
+    data = recvString("OK", "FAIL", 15000);
+    if (data.find("OK") != std::string::npos) {
+        return true;
+    }
+    return false;
+}
+
+bool ESP8266::eATCIFSR(string &list) {
+    esp.printf("AT+CIFSR\r\n");
+    return recvFindAndFilter("OK", "\r\r\n", "\r\n\r\nOK", list);
+}
+
+bool ESP8266::sATCIPSERVER(uint8_t mode, uint32_t port) {
+    string data;
+    if (mode) {
+        esp.printf("AT+CIPSERVER=1,%d\r\n", port);
+        
+        data = recvString("OK", "no change");
+        if (data.find("OK") != std::string::npos || data.find("no change") != std::string::npos) {
+            return true;
+        }
+        return false;
+    } else {
+        esp.printf("AT+CIPSERVER=0\r\n");
+        return recvFind("\r\r\n");
+    }
+}
+
+bool ESP8266::sATCIPSENDMultiple(uint8_t mux_id, char buffer[], uint32_t len) {
+    //esp.flush();
+    esp.printf("AT+CIPSEND=%d,%d\r\n", mux_id, len);
+    if (recvFind(">", 5000)) {
+        //esp.flush();
+        for (uint32_t i = 0; i < len; i++) {
+            esp.printf("%c",buffer[i]);
+        }
+        return recvFind("SEND OK", 10000);
+    }
+    return false;
+}
+
+bool ESP8266::sATCWSAP(string ssid, string pwd, uint8_t chl, uint8_t ecn)
+{
+    string data;
+    esp.printf("AT+CWSAP=\"%s\",\"%s\",%d,%d\r\n", ssid.c_str(), pwd.c_str(), chl, ecn);
+    
+    data = recvString("OK", "ERROR", 5000);
+    if (data.find("OK") != std::string::npos) {
+        return true;
+    }
+    return false;
+}
+
+bool ESP8266::sATCWDHCP(bool enabled, int mode) {
+    if(mode < 0 || mode > 2) {
+        return false;
+    }
+    esp.printf("AT+CWDHCP=%d,%d\r\n", enabled?1:0, mode);
+    return recvFind("OK", 2000);
+}
+
+bool ESP8266::sATCIPSTA(string ip) {
+    esp.printf("AT+CIPSTA=\"%s\"\r\n", ip.c_str());
+    return recvFind("OK", 2000);
+}
+
+bool ESP8266::sATCIPAP(string ip) {
+    esp.printf("AT+CIPAP=\"%s\"\r\n", ip.c_str());
+    return recvFind("OK", 2000);
+}
+
+/************************* Private Callback Functions *************************/
+void ESP8266::RxInterrupt(void)
+{
+    char c;
+    
+    c = esp.getc();                              //read the incoming character
+    if(c == '\n') {
+        //rxmsg_idx = 0;
+        rxpass1=false;
+        rxpass2=false;
+        rxpass3=false;
+        rxtemp_idx=0;
+        //new_rxmsg=false;
+    }
+    
+    if(rxpass1 && rxpass2 && rxpass3) {
+        if(rxtemp_idx < packetLen-1) {
+            rxtemp[rxtemp_idx] = c;
+            rxtemp_idx++;
+        }
+        else {
+            rxtemp[rxtemp_idx] = c;
+            rxtemp[rxtemp_idx+1] = '\0';
+            strcpy(packetData, rxtemp);
+            //rxmsg_idx = 0;
+            rxpass1=false;
+            rxpass2=false;
+            rxpass3=false;
+            rxtemp_idx=0;
+            new_rxmsg=true;
+        }
+    }
+    else if(rxpass1 && rxpass2) {
+        if(c != ':') {
+            rxtemp[rxtemp_idx] = c;
+            rxtemp_idx++;
+        }
+        else {
+            rxtemp[rxtemp_idx] = '\0';
+            packetLen= atoi(rxtemp);
+            rxtemp_idx=0;
+            rxpass3=true;
+        }
+    }
+    else if(rxpass1) {
+        if(c != ',') {
+            rxtemp[rxtemp_idx] = c;
+            rxtemp_idx++;
+        }
+        else {
+            rxtemp[rxtemp_idx] = '\0';
+            packetID = atoi(rxtemp);
+            rxtemp_idx=0;
+            rxpass2=true;
+        }
+    }
+    else {
+        rxtemp[rxtemp_idx] = c;
+        rxtemp_idx++;
+        
+        if(rxtemp_idx == 6) {
+            if(rxtemp[1] == '+' && rxtemp[2] == 'I' && rxtemp[3] == 'P' && rxtemp[4] == 'D' && rxtemp[5] == ',') {
+                rxpass1 = true;
+            } 
+        }
+        /*
+        rxmsg[rxmsg_idx] = c;
+        rxmsg_idx++;
+        
+        if(rxmsg_idx == 6) {
+            if(rxmsg[1] == '+' && rxmsg[2] == 'I' && rxmsg[3] == 'P' && rxmsg[4] == 'D' && rxmsg[5] == ',') {
+                rxpass1 = true;
+            } 
+        }*/
+    }
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ESP8266.h	Mon Jun 11 17:56:55 2018 +0000
@@ -0,0 +1,251 @@
+/* ESP8266 Library v1.0
+ * Copyright (c) 2017 Grant Phillips
+ * grant.phillips@nmmu.ac.za
+ * 
+ * This library was adapted from the WeeESP8266 version by ITEAD STUDIO.
+ * (https://os.mbed.com/users/itead/code/WeeESP8266/)
+ *
+ * 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.
+ */
+ 
+#ifndef ESP8266_H
+#define ESP8266_H
+ 
+#include "mbed.h"
+#include <string>
+ 
+/** Class library for using the ESP8266 wifi module.
+ */
+ 
+class ESP8266 {
+  public:
+    /** Create a ESP8266 object connected to the specified pins. 
+    * @param Tx Pin used to connect to ESP8266's Tx pin
+    * @param Rx Pin used to connect to ESP8266's Rx pin
+    */
+    ESP8266(PinName Tx, PinName Rx, PinName Rst);
+    
+    /** Starts the ESP8266 in a specified mode.
+    * @param mode The WiFi mode the ESP8266 must be set to (1=Station, 2=SoftAP, 3=Station+SoftAP)
+    *
+    * @retval true - succesfull
+    * @retval false - not succesfull
+    */
+    bool startup(uint8_t mode);
+    
+    /** Get the version of AT Command Set from the ESP8266.
+    * 
+    * @param version String variable where version will be stored. 
+    */
+    void getVersion(char* version);
+    
+    /** Search available AP list and return it.
+    * 
+    * @param list String variable where AP list will be stored.
+    * @note This method will occupy a lot of memeory(hundreds of Bytes to a couple of KBytes). 
+    *  Do not call this method unless you must and ensure that your board has enough memory left.
+    */
+    void getAPList(char* list);
+    
+    /** Set SoftAP parameters. 
+     * 
+     * @param ssid SSID of SoftAP. 
+     * @param pwd PASSWORD of SoftAP. 
+     * @param chl the channel (1 - 13, default: 7). 
+     * @param ecn the way of encrypstion (0 - OPEN, 1 - WEP, 
+     *  2 - WPA_PSK, 3 - WPA2_PSK, 4 - WPA_WPA2_PSK, default: 4). 
+     * @note This method should not be called when station mode. 
+     */
+    bool setSoftAPParam(string ssid, string pwd, uint8_t chl = 7, uint8_t ecn = 4);
+    
+    /** Enable/Disable DHCP
+    *
+    * @param enabled DHCP enabled when true
+    * @param mode mode of DHCP 0-softAP, 1-station, 2-both
+    * @return true only if ESP8266 enables/disables DHCP successfully
+    */
+    bool DHCP(bool enabled, int mode);
+    
+    /** Join in AP. 
+    *
+    * @param ssid SSID of AP to join in. 
+    * @param pwd Password of AP to join in. 
+    * @retval true - success.
+    * @retval false - failure.
+    * @note This method will take a couple of seconds. 
+    */
+    bool joinAP(string ssid, string pwd);
+    
+    /** Get the local IP address of ESP8266. 
+    *
+    * @param version String variable where version will be stored. 
+    */
+    void getLocalIP(char* LocalIP);
+    
+    /** Sets the IP Address of the ESP8266 Station. 
+    *
+    * @param LocalIP The IP Address of the ESP8266 Station
+    * @retval true - success.
+    * @retval false - failure.
+    */
+    bool setLocalIP(string LocalIP);
+    
+    /** Sets the IP Address of the ESP8266 SoftAP. 
+    *
+    * @param LocalIP The IP Address of the ESP8266 SoftAP
+    * @retval true - success.
+    * @retval false - failure.
+    */
+    bool setSoftAPIP(string LocalIP);
+    
+    /** Start TCP Server(Only in multiple mode). 
+    * 
+    * After started, only methods TCPPacketSend, TCPPacketRead, and TCPPacketArrived can be used. 
+    * Once TCPServerStop is called, all other methods can be used again.
+    *
+    * @param port The port number to listen on (default: 333).
+    * @retval true - success.
+    * @retval false - failure.
+    */
+    bool TCPServerStart(uint32_t port = 333);
+    
+    /** Indicates whether a new packet has arrived from a connected client. 
+    * 
+    * @retval true - A new packet has arrived.
+    * @retval false - No new packets have arrived.
+    */
+    bool TCPPacketReceived(void);
+    
+    /** Reads the current received TCP packet
+    *
+    * @param ID Pointer for the ID of client for the new received packet.
+    * @param LEN Pointer for the length of the new received packet.
+    * @param DATA String pointer for the string of the new received packet.
+    */
+    void TCPPacketRead(uint8_t *ID, uint32_t *LEN, char DATA[]);
+    
+    /** Send a data packet using TCP to a specified client.
+    * 
+    * @param ID The identifier of client to send the packet to (available value: 0 - 4). 
+    * @param LEN The length of packet to send. 
+    * @param DATA The buffer of data to send. 
+    * @retval true - success.
+    * @retval false - failure.
+    */
+    bool TCPPacketSend(uint8_t ID, uint32_t LEN, char DATA[]);
+    
+    
+  private:
+    Serial esp;             //Serial object for connecting to ESP8266
+    DigitalOut _rst;
+    bool mDEBUG;   
+    Timer t;
+    
+    char packetData[1000];
+    int packetID;
+    int packetLen;
+    char rxtemp[1000];
+    int rxtemp_idx;
+    bool new_rxmsg;     //flag to indicate if a new complete message was received
+    bool rxpass1, rxpass2, rxpass3;
+    void RxInterrupt(void); //Interrupt to receive data when TCP server is set
+    
+    bool eAT(void);
+    bool eATRST(void);
+    bool eATGMR(string &version);
+    bool sATCWMODE(uint8_t mode);
+    bool sATCIPMUX(uint8_t mode);
+    bool eATCWLAP(string &list);
+    bool sATCWJAP(string ssid, string pwd);
+    bool eATCIFSR(string &list);
+    bool sATCIPSERVER(uint8_t mode, uint32_t port = 333);
+    bool sATCIPSENDMultiple(uint8_t mux_id, char buffer[], uint32_t len);
+    bool sATCWSAP(string ssid, string pwd, uint8_t chl, uint8_t ecn);
+    bool sATCWDHCP(bool enabled, int mode);
+    bool sATCIPSTA(string ip);
+    bool sATCIPAP(string ip);
+/*
+
+bool qATCWMODE(uint8_t *mode);
+
+
+
+bool eATCWQAP(void);
+bool sATCWSAP(string ssid, string pwd, uint8_t chl, uint8_t ecn);
+bool eATCWLIF(string &list);
+
+bool eATCIPSTATUS(string &list);
+bool eATCIFSR(string &list);
+
+    */
+    
+    
+    
+    
+    /** Verify whether ESP8266 is connected correctly or not.
+    * @param None
+    * 
+    * @retval true - connected.
+    * @retval false - not connected or found.
+    */
+    bool kick(void);
+    
+    /** Restart ESP8266 by "AT+RST". This method will take 3 seconds or more. 
+    *
+    * @retval true - success.
+    * @retval false - failure.
+    */
+    bool reset(void);
+    
+    /** Sets the ESP8266's WiFi mode.
+    * @param mode The WiFi mode the ESP8266 must be set to (1=Station, 2=SoftAP, 3=Station+SoftAP)
+    *
+    * @retval true - success.
+    * @retval false - failure.
+    */
+    bool setWiFiMode(uint8_t mode);
+    
+    /** Enable of disable multiple connections on the ESP8266
+    * @param onoff Value to Enable(=true) or Disable(=false) multiple connections.
+    *
+    * @retval true - success.
+    * @retval false - failure.
+    */
+    bool setMux(bool onoff);
+    
+    /* Receive data from uart and search first target. Return true if target found, false for timeout. */
+    bool recvFind(string target, uint32_t timeout = 1000);
+    
+    /* Receive data from uart. Return all received data if target found or timeout. */
+    string recvString(string target, uint32_t timeout = 1000);
+    
+    /* Receive data from uart. Return all received data if one of target1 and target2 found or timeout. */
+    string recvString(string target1, string target2, uint32_t timeout = 1000);
+
+    /* Receive data from uart. Return all received data if one of target1, target2 and target3 found or timeout. */
+    string recvString(string target1, string target2, string target3, uint32_t timeout = 1000);
+    
+    /* Receive data from uart and search first target and cut out the substring between begin and end(excluding begin and end self). 
+    * Return true if target found, false for timeout. */
+    bool recvFindAndFilter(string target, string begin, string end, string &data, uint32_t timeout = 1000);
+    
+    
+};
+ 
+#endif
\ No newline at end of file