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
diff -r 000000000000 -r 30dd9c0f7559 ESP8266.cpp
--- /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
diff -r 000000000000 -r 30dd9c0f7559 ESP8266.h
--- /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