Class library for using the ESP8266 wifi module.

ESP8266.cpp

Committer:
grantphillips
Date:
2018-06-11
Revision:
0:30dd9c0f7559

File content as of revision 0:30dd9c0f7559:

#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;
            } 
        }*/
    }
}