Tuned for OS2 to reduce flash code size for smaller MCU's. Added further functions since 2018 v1.7 firmware. Improved faster large web page sending. Built in fast NTP Client time and RTC setting function. ATParser message handling improvements and updated.

Dependencies:  

Dependents:   ESP8266-NTP-Test

ESP8266.cpp

Committer:
star297
Date:
2019-02-14
Revision:
3:ffdde9d17dd1
Parent:
2:072248e430d0

File content as of revision 3:ffdde9d17dd1:


#include "ESP8266.h"

ESP8266::ESP8266(PinName tx, PinName rx, bool debug)
    : _serial(tx, rx, 1024), _parser(_serial)   // set our buffer to ESP max buffer size
{
    _serial.baud(115200);
    _parser.debugOn(debug);
    _parser.send("ATE0");     // set no ESP echo
}

bool ESP8266::reset(void)
{
    if (_parser.send("AT+RST")          // soft reset ESP
        && _parser.recv("OK\r\nready")
        && _parser.send("ATE0")     // set no ESP echo
        && _parser.recv("OK")) {
        return true;
        }   
    else return false;
}

bool ESP8266::startup(int mode)
{
    //only 3 valid modes
    if(mode < 1 || mode > 3) {
        return false;
    }  
         _parser.send("AT+CWMODE=%d", mode)       //set mode 
        && _parser.recv("OK")
        && _parser.send("AT+CIPMUX=1") 
        && _parser.recv("OK");
     return true;
}

bool ESP8266::startServer(int mode,int port,int timeout)
{    
        //only 3 valid modes
    if(mode < 1 || mode > 3) {
        return false;
    }
         _parser.send("AT+CWMODE=%d",mode)        //set mode
        && _parser.recv("OK")
        && _parser.send("AT+CIPMUX=1") 
        && _parser.recv("OK")
        && _parser.send("AT+CIPSERVER=1,%d",port)   //start server at port 80
        && _parser.recv("OK")    
        && _parser.send("AT+CIPSTO=%d",timeout)     //Server timeout=5 seconds
        && _parser.recv("OK");    
        
     return true;
}

const char *ESP8266::getFirmware(void)
{
    int previous_timeout = _parser._timeout; // get current ESP timeout
    setTimeout(200);   
    _parser.send("AT+GMR");
    _parser.getESP((char*)_firmware);
     setTimeout(previous_timeout);   // restore previous ESP timeout       
    return _firmware;
}

bool ESP8266::dhcp(bool enabled, int mode)
{
    //only 3 valid modes
    if(mode < 0 || mode > 2) {
        return false;
    }
    return _parser.send("AT+CWDHCP=%d,%d", enabled?1:0, mode)
        && _parser.recv("OK");
}

bool ESP8266::connect(const char *ap, const char *passPhrase)
{
    strcpy(_ssid, ap);
    return _parser.send("AT+CWJAP=\"%s\",\"%s\"", ap, passPhrase)
        && _parser.recv("OK");
}

bool ESP8266::disconnect(void)
{
    return _parser.send("AT+CWQAP") && _parser.recv("OK");
}

const char *ESP8266::getIPAddress(void)
{
    if (!(_parser.send("AT+CIFSR")
        && _parser.recv("+CIFSR:APIP,\"%[^\"]\"", _APIP_buffer)
        && _parser.recv("+CIFSR:APMAC,\"%[^\"]\"", _APMAC_buffer)
        && _parser.recv("+CIFSR:STAIP,\"%[^\"]\"", _STAIP_buffer)
        && _parser.recv("+CIFSR:STAMAC,\"%[^\"]\"", _STAMAC_buffer)
        && _parser.recv("OK"))) {
        return 0;
    }
    return _STAIP_buffer;
}

const char *ESP8266::getMACAddress(void)
{
    if (!(_parser.send("AT+CIFSR")
        && _parser.recv("+CIFSR:STAMAC,\"%[^\"]\"", _STAMAC_buffer)
        && _parser.recv("OK"))) {
        return 0;
    }
    return _STAMAC_buffer;
}

bool ESP8266::isConnected(void)
{ 
    if(strcmp(getIPAddress(),"0.0.0.0")==0) {return 0;}
        else {return 1;}
}

bool ESP8266::open(const char *type, int id, const char* addr, int port)
{
    //IDs only 0-4
    if(id > 4) {
        return false;
    }
    return _parser.send("AT+CIPSTART=%d,\"%s\",\"%s\",%d", id, type, addr, port)
        && _parser.recv("OK");
}

bool ESP8266::send(int id, const void *data, uint32_t amount)
{
    //May take a second try if device is busy
    for (unsigned i = 0; i < 2; i++) {
        if (_parser.send("AT+CIPSEND=%d,%d", id, amount)
            && _parser.recv(">")
            && _parser.write((char*)data, (int)amount) >= 0) {
            while(!_parser.recv("SEND OK"));    // wait for ESP response to confirm data sent
            return true;
        }
    }
    return false;
}

bool ESP8266::sendWebPage(int id, const char * page, uint32_t amount)
{
    unsigned int lenOfPacketToTx;
    unsigned int pageToSendAddress=0;
    // we test for 'SEND OK' otherwise comms fail, this function needs to escape, 3 second timeout.
    t.reset();t.start();    
    while(amount>0 && t.read()<3){
        if(amount>2048){amount-=2048;lenOfPacketToTx=2048;} //ESP send buffer limit
            else{lenOfPacketToTx=amount;amount=0;}                                
        _parser.send("AT+CIPSEND=%d,%d", id, lenOfPacketToTx);
        while(!_parser.recv(">"));      // wait for ready to send >            
        page=(page+pageToSendAddress);            
        while(lenOfPacketToTx--){
            _parser.putc(*page++);      // send page data
        }
        pageToSendAddress+=lenOfPacketToTx;
        while(!_parser.recv("SEND OK") && t.read()<2);                    
    }
    memset(request,'\0',sizeof(request));
    ipdLen=0;t.stop();t.reset();
    if(t.read()>2) return false; // comms failed     
        else return true;     
}

const char *ESP8266::recvWebRequest(void )
{   
    char dummy[50]; // this is not working as expected, we need add a 'dummy' field
    _parser.recv("+IPD,%d,%d:%s %s %s",&linkId,&ipdLen,requestType,request,dummy);
    return request;
}

int32_t ESP8266::recv(int id, void *data, uint32_t amount)
{
    int32_t recv_amount = -1;
    int recv_id;
    if (!(_parser.recv("+IPD,%d,%d:", &recv_id, &recv_amount)
        && recv_id == id
        && recv_amount <= amount
        && _parser.read((char*)data, recv_amount)
        && _parser.recv("OK"))) {
    }
    return recv_amount;
}

bool ESP8266::close(int id)
{
    int previous_timeout = _parser._timeout; // get current ESP timeout
    setTimeout(100);
    // May take a few try's if device is busy but keep short as possible ESP timeout retry delay.
    for (unsigned i = 0; i < 3; i++) {
        if (_parser.send("AT+CIPCLOSE=%d", id)
            && _parser.recv("OK")) {
            return true;
        }
    }
    setTimeout(previous_timeout);   // restore previous ESP timeout
    return false;
}

int8_t ESP8266::getRSSI()
{
    int previous_timeout = _parser._timeout; // get current ESP timeout
    setTimeout(5000);
    _parser.send("AT+CWLAPOPT=1,4");    // get current connection
    _parser.recv("OK");    
    int8_t rssi;
    if (!(_parser.send("AT+CWLAP=\"%s\"", _ssid)
        && _parser.recv("+CWLAP:(%d)", &rssi)
        && _parser.recv("OK"))) {
    }
    setTimeout(previous_timeout);   // restore previous ESP timeout 
    return rssi;
}

int32_t ESP8266::getNTP(char * NTPpool,int tzoffset, int setRTC)
{
    // example NTPpool = "1.nl.pool.ntp.org"
    // serial.printf("Seconds since 1970 = %d\r\n", esp.getNTP("1.nl.pool.ntp.org",3600));    
    const int NTP_PACKET_SIZE = 48;
    unsigned char packetBuffer[NTP_PACKET_SIZE];
    int NTP_OFFSET = (2208988800 - tzoffset);
    memset(packetBuffer, 0x00, NTP_PACKET_SIZE);
    // Initialize values needed to form NTP request
    packetBuffer[0]  = 0b11100011;      // LI, Version, Mode
    packetBuffer[1]  = 0;               // Stratum, or type of clock
    packetBuffer[2]  = 6;               // Polling Interval
    packetBuffer[3]  = 0xEC;            // Peer Clock Precision
    // [4]-[11]: 8 bytes of zero for Root Delay & Root Dispersion
    packetBuffer[12] = 49;
    packetBuffer[13] = 0x4E;
    packetBuffer[14] = 49;
    packetBuffer[15] = 52;
    int previous_timeout = _parser._timeout; // get current ESP timeout
    uint32_t recv_size = 0;
    int tries1 = 10;
    while ((recv_size != NTP_PACKET_SIZE) && (tries1 > 0)){
        tries1--;
        setTimeout(2000);        
        open("UDP", 1, NTPpool, 123);
        setTimeout(100);
        send(1, packetBuffer, NTP_PACKET_SIZE);
        int tries2 = 50;
        while ((recv_size != NTP_PACKET_SIZE) && (tries2 > 0)){
            tries2--;
            recv_size = recv(1, packetBuffer, NTP_PACKET_SIZE);
        }
    }
    setTimeout(previous_timeout);   // restore previous ESP timeout
    close(1);
    if(recv_size==48){
        uint32_t secsSince1970=((packetBuffer[40]<<24)|(packetBuffer[41]<<16)|(packetBuffer[42]<<8)|packetBuffer[43])-NTP_OFFSET;
        if (setRTC){set_time(secsSince1970);} // may need to add a second to offset any MCU delay
        return secsSince1970;
    }
    else{return 0;}   
}

void ESP8266::setTimeout(uint32_t timeout_ms)
{
    _parser.setTimeout(timeout_ms);
}

bool ESP8266::readable()
{
    return _serial.readable();
}

bool ESP8266::writeable()
{
    return _serial.writeable();
}