ESP8266 WiFi Module Web Server library

ESP8266_WebServer.cpp

Committer:
sschocke
Date:
2015-01-04
Revision:
5:48b7fd921bef
Parent:
3:4ef7db7a95a7
Child:
6:34d93ea4d519

File content as of revision 5:48b7fd921bef:

#include "ESP8266_WebServer.h"

const char* opModes[] = {"ERROR", "Station", "SoftAP", "Station+SoftAP"};

ESP8266_WebServer::ESP8266_WebServer(Serial *espUART) {
    serial = espUART;
    rxptr = buffer;
    debugSerial = NULL;
    reqMode = false;
    reqLen = 0;
}

void ESP8266_WebServer::rxint(void) {
    char c = serial->getc();
    if( (c != 0x0A) && (c != 0x0D) && ((c < 0x20) || (c > 0x80)) ) return;
    if( !reqMode && c == '+' ) {
        if( echoMode ) {
            debugSerial->putc('~');
        }
        rxptrStored = rxptr;
        rxptr = reqBuffer;
        reqMode = true;
    }
    if( echoMode ) {
        debugSerial->putc(c);
    }
    if( reqMode && reqLen == 0 && c == ':' ) {
        if( echoMode ) {
            debugSerial->putc('!');
        }
        int numMatched = sscanf(reqBuffer,"+IPD,%*d,%d%n", &reqLen, &ipdLen);
        if( numMatched < 1 ) {
            reqMode = false;
            reqLen = 0;
            rxptr = rxptrStored;
            return;
        }
        reqLen += ipdLen + 1;
    }
    *rxptr = c;
    rxptr++;
    *rxptr = 0;
    if( reqMode && reqLen > 0 ) {
        if( echoMode ) {
            debugSerial->putc('#');
        }
        if( (int)(rxptr - reqBuffer) == reqLen ) {
            // Process it
            queueRequest();
            // Return to normal buffer mode
            reqMode = false;
            reqLen = 0;
            rxptr = rxptrStored;
        }
    }
}

void ESP8266_WebServer::debugBuffers(Serial* target) {
    target->printf("\r\n\r\nRequest Buffer '%s'\r\nReqLen=%d,ReqMode=%d\r\n", reqBuffer, reqLen, reqMode);    
}

void ESP8266_WebServer::readBuffer(void) {
    strncpy(reply, buffer, 1024);
    while(reqMode == true ) { wait_ms(10); }
    
    rxptr = buffer;
    *rxptr = 0;
}

short ESP8266_WebServer::data_waiting(void)
{
    char* ok = strstr(buffer, "OK\r\n");
    char* error = strstr(buffer, "ERROR\r\n");
    char* nochange = strstr(buffer, "no change\r\n");
    
    if( (ok != NULL) || (error != NULL ) || (nochange != NULL ) )
    {
        return 1;
    }

    return 0;
}

short ESP8266_WebServer::string_waiting(const char* str)
{
    char* pr = strstr(buffer, str);
    char* error = strstr(buffer, "ERROR\r\n");
    
    if( (pr != NULL) || (error != NULL ) )
    {
        return 1;
    }

    return 0;
}

void ESP8266_WebServer::Initialize(void) {
    readBuffer();
    serial->printf("AT+RST\r\n");
    wait_ms(1000);
    while( string_waiting("\r\nready\r\n") == 0 ) {
        wait_ms(100);
    }
    readBuffer();
    serial->printf("ATE0\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    
    if( debugSerial != NULL ) {
        debugSerial->printf("Done\r\nSetting operating mode...");
    }
    serial->printf("AT+CWMODE=3\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    
    if( debugSerial != NULL ) {
        debugSerial->printf("Done\r\nAccept Multiple connections...");
    }
    serial->printf("AT+CIPMUX=1\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    
    if( debugSerial != NULL ) {
        debugSerial->printf("Done\r\nStarting Web Server...");
    }
    
    serial->printf("AT+CIPSERVER=1,80\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
}

void ESP8266_WebServer::queueRequest(void) {
    if( strstr(reqBuffer, "HTTP") != NULL ) {
        ESP8266_WebRequest* request = new ESP8266_WebRequest(reqBuffer, debugSerial); 
        
        incoming.push(request);
    }
}

ESP8266_WebRequest* ESP8266_WebServer::GetRequest(void)
{
    if( incoming.empty() == false ) {
        ESP8266_WebRequest* temp = incoming.front();
        incoming.pop();
        temp->Read();
        
        return temp;
    }
        
    return NULL;
}

void ESP8266_WebServer::sendResponse(int linkID, int numBytes) {
    bool sent = false;
    
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("HTTP Reply Packet(%d bytes)\r\n", numBytes);
    }
    while( sent == false ) {
        while( reqMode == true ) { wait_ms(1); }
        serial->printf("AT+CIPSEND=%d,%d\r\n", linkID, numBytes);
        wait_ms(100);
        if( (string_waiting(">") == 1) ) {
            char* error = strstr(buffer, "ERROR\r\n");
            if( error != NULL ) { continue; }
            for( int i=0; i<numBytes; i++ ) {
                serial->putc(response[i]);
            }
            while( string_waiting("\r\nSEND OK\r\n") == 0 ) {
                wait_ms(10);
            }
            error = strstr(buffer, "ERROR\r\n");
            if( error != NULL ) { continue; }
            sent = true;
        }
    }
    readBuffer();
}

void ESP8266_WebServer::SendError(int linkID, std::string error) {
    SendError(linkID, error.c_str());
}
void ESP8266_WebServer::SendError(int linkID, const char* error) {
    sprintf(response, "HTTP/1.1 %s\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n%s", error, strlen(error), error);
    sendResponse(linkID, strlen(response));
}
void ESP8266_WebServer::Send404Error(int linkID) {
    SendError(linkID, "404 Not Found");
}

void ESP8266_WebServer::SendReply(int linkID, std::string reply, const char* mimeType) {
    SendReply(linkID, reply.c_str(), reply.length(), mimeType, 60);
}
void ESP8266_WebServer::SendReply(int linkID, std::string reply, const char* mimeType, int maxAge) {
    SendReply(linkID, reply.c_str(), reply.length(), mimeType, maxAge);
}

void ESP8266_WebServer::SendReply(int linkID, char const* reply, int replySize, const char* mimeType) {
    SendReply(linkID, reply, replySize, mimeType, 600);
}
void ESP8266_WebServer::SendReply(int linkID, char const* reply, const char* mimeType, int maxAge) {
    SendReply(linkID, reply, strlen(reply), mimeType, maxAge);
}
void ESP8266_WebServer::SendReply(int linkID, char const* reply, int replySize, const char* mimeType, int maxAge) {
    sprintf(response, "HTTP/1.1 200 OK\r\nContent-Type:%s\r\nContent-Length: %d\r\nCache-Control:max-age=%d\r\n\r\n", mimeType, replySize, maxAge);
    sendResponse(linkID, strlen(response));
    char const* sendPtr = reply;
    int bytesSent = 0;
    while( bytesSent < replySize ) {
        int bytesToSend = replySize - bytesSent;
        if( bytesToSend > sizeof(response) ) {
            bytesToSend = sizeof(response);
        }
        
        memcpy(response, sendPtr, bytesToSend);
        sendResponse(linkID, bytesToSend);
        sendPtr += bytesToSend;
        bytesSent += bytesToSend;
    }
}

void ESP8266_WebServer::SendFile(int linkID, FileHandle* file, const char* mimeType) {
    SendFile(linkID, file, mimeType, 86400);
}
void ESP8266_WebServer::SendFile(int linkID, FileHandle* file, const char* mimeType, int maxAge) {
    sprintf(response, "HTTP/1.1 200 OK\r\nContent-Type:%s\r\nContent-Length: %d\r\nCache-Control:max-age=%d\r\n\r\n", mimeType, file->flen(), maxAge);
    sendResponse(linkID, strlen(response));
    int numBytes = file->read(response, sizeof(response));
    while( numBytes > 0) {
        sendResponse(linkID, numBytes);
        numBytes = file->read(response, sizeof(response));
    }
}

std::string ESP8266_WebServer::GetStationMAC(void) {
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CIPSTAMAC?\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("Station MAC Reply: %s\r\n", reply);
    }
    
    std::string mac = std::string(reply);
    mac = mac.substr(1, 17);
    
    return mac;
}
std::string ESP8266_WebServer::GetAPMAC(void) {
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CIPAPMAC?\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("SoftAP MAC Reply: %s\r\n", reply);
    }
    
    std::string mac = std::string(reply);
    mac = mac.substr(1, 17);
    
    return mac;
}
std::string ESP8266_WebServer::GetStationIP(void) {
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CIPSTA?\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("Station IP Reply: %s\r\n", reply);
    }
    
    std::string ip = std::string(reply);
    ip = ip.substr(1, ip.find('"', 1) - 1);
    
    return ip;
}
std::string ESP8266_WebServer::GetAPIP(void) {
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CIPAP?\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("SoftAP IP Reply: %s\r\n", reply);
    }
    
    std::string ip = std::string(reply);
    ip = ip.substr(1, ip.find('"', 1) - 1);
    
    return ip;
}
int ESP8266_WebServer::GetOperatingMode(void) {
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CWMODE?\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("Operating Mode Reply: %s\r\n", reply);
    }
    
    return atoi(reply);
}
std::string ESP8266_WebServer::GetStationSSID(void) {
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CWJAP?\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("Station SSID Reply: %s\r\n", reply);
    }
    
    std::string ssid = std::string(reply);
    if( strstr(reply, "No AP\r\n") != NULL ) { return "(None)"; }
    ssid = ssid.substr(1, ssid.find('"', 1) - 1);
    
    return ssid;
}
std::list<std::string> ESP8266_WebServer::ListAvailableSSID(void) {
    std::list<std::string> apList;
    
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CWLAP\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("SSID List Reply: %s\r\n", reply);
    }
    
    char ssid[65];
    char apmac[20];
    int ecn;
    int rssi;
    int tokenLength;
    char* token = strstr(reply, "(");
    while( token != NULL ) {
        int numMatched = sscanf(token, "(%d,\"%[^\"]\",%d,\"%[0123456789abcdef:]\",%*d)\r\n%n", &ecn, ssid, &rssi, apmac, &tokenLength);
        if( numMatched < 4 ) {
            if( debugSerial != NULL ) {
                debugSerial->printf("SSID List Token Error: NumMatched=%d, SSID=%s\r\n", numMatched, ssid);
            }
            return apList;
        }
        if( debugSerial != NULL ) {
            debugSerial->printf("SSID List Token : SSID=%s, ECN=%d, RSSI=%d, APMAC=%s, TokenLength=%d\r\n", ssid, ecn, rssi, apmac, tokenLength);
        }
        apList.push_back(std::string(ssid));
        token += tokenLength;
        token = strstr(token, "(");
    }
    
    return apList;
}
std::string ESP8266_WebServer::GetFirmwareVersion(void) {
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+GMR\r\n");
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("Firmware Version Reply: %s\r\n", reply);
    }
    
    std::string ver = std::string(reply);
    ver = ver.substr(0, ver.find('\r'));
    
    return ver;
}

bool ESP8266_WebServer::SetOperatingMode(int mode) {
    if( debugSerial != NULL ) {
        debugSerial->printf("Set Operating Mode to %s(%d)\r\n", opModes[mode], mode);
    }
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CWMODE=%d\r\n", mode);
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("Set Operating Mode Reply: %s\r\n", reply);
    }
    if( strstr(reply, "\r\nOK\r\n") != NULL ) { return true; }
    return false;
}

bool ESP8266_WebServer::SetStationSSID(std::string newAP, std::string password) {
    if( debugSerial != NULL ) {
        debugSerial->printf("Set Station SSID to %s, Password=%s\r\n", newAP.c_str(), password.c_str());
    }
    while( reqMode == true ) { wait_ms(1); }
    readBuffer();
    serial->printf("AT+CWJAP=\"%s\",\"%s\"\r\n", newAP.c_str(), password.c_str());
    while( data_waiting() == 0 ) {
        wait_ms(10);
    }
    readBuffer();
    if( debugSerial != NULL ) {
        debugSerial->printf("Set Station SSID Reply: %s\r\n", reply);
    }
    if( strstr(reply, "\r\nOK\r\n") != NULL ) { return true; }
    
    return false;
}

ESP8266_WebRequest::ESP8266_WebRequest(const char* packet, Serial* debug) {
    int sz = strlen(packet);
    data = (char *)malloc(sz+1);
    memcpy(data, packet, sz+1);
    debugSerial = debug;
}

void ESP8266_WebRequest::Read(void) {
    int bytesRecv, ipdLen, linkID;
    int numMatched = sscanf(data,"+IPD,%d,%d:%n", &linkID, &bytesRecv, &ipdLen);
    if( numMatched != 2 ) {
        if( debugSerial != NULL ) {
            debugSerial->printf("IPD ERROR : Matched %d, LinkID=%d, BytesRecv=%d, IPD Header Len=%d\r\n", numMatched, linkID, bytesRecv, ipdLen);
        }
        return;
    }

    if( debugSerial != NULL ) {
        debugSerial->printf("IPD Data: LinkID=%d, BytesRecv=%d, IPD Header Len=%d\r\n", linkID, bytesRecv, ipdLen);
    }
    if( strstr(data, "HTTP") != NULL ) {
        if( debugSerial != NULL ) {
            debugSerial->printf("Got HTTP Request\r\n");
        }
        char* httpPacket = data + ipdLen;
        if( debugSerial != NULL ) {
            debugSerial->printf("HTTP Packet: %s\r\n", httpPacket);
        }
        int numMatched = sscanf(httpPacket, "%s %s HTTP/%*c.%*c", httpMethod, httpURI);
        if( numMatched != 2 ) {
            if( debugSerial != NULL ) {
                debugSerial->printf("HTTP ERROR : Matched %d, Method=%s, URI=%s\r\n", numMatched, httpMethod, httpURI);
            }
            return;
        }
        
        LinkID = linkID;
        Method = httpMethod;
        URI = httpURI;
        int pos = URI.find('?');
        if(pos != string::npos ) {
            string params = URI.substr(pos+1);
            URI = URI.substr(0,pos);
            pos = params.find('=');
            while( pos != string::npos ) {
                string name = params.substr(0,pos);
                string value = params.substr(pos+1);
                pos = params.find('&');
                if( pos == string::npos )
                {
                    if( debugSerial != NULL ) {
                        debugSerial->printf("HTTP GET Parameter %s=%s\r\n", name.c_str(), value.c_str());
                    }
                    Parameters[name] = value;
                    break;
                }
                
                value = value.substr(0,value.find('&'));
                params = params.substr(pos+1);
                pos = params.find('=');
                if( debugSerial != NULL ) {
                    debugSerial->printf("HTTP GET Parameter %s=%s\r\n", name.c_str(), value.c_str());
                }
                Parameters[name] = value;
            }
        }
        if( debugSerial != NULL ) {
            debugSerial->printf("HTTP %s %s\r\n", httpMethod, httpURI);
        }
    }
}

ESP8266_WebRequest::~ESP8266_WebRequest()
{
    free(data);
}