ESP8266 WiFi Module Web Server library

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ESP8266_WebServer.cpp Source File

ESP8266_WebServer.cpp

00001 #include "ESP8266_WebServer.h"
00002 
00003 const char* opModes[] = {"ERROR", "Station", "SoftAP", "Station+SoftAP"};
00004 
00005 ESP8266_WebServer::ESP8266_WebServer(Serial *espUART) {
00006     serial = espUART;
00007     rxptr = buffer;
00008     debugSerial = NULL;
00009     reqMode = false;
00010     reqLen = 0;
00011 }
00012 
00013 void ESP8266_WebServer::rxint(void) {
00014     char c = serial->getc();
00015     if( (c != 0x0A) && (c != 0x0D) && ((c < 0x20) || (c > 0x80)) ) return;
00016     if( !reqMode && c == '+' ) {
00017         if( echoMode ) {
00018             debugSerial->putc('~');
00019         }
00020         rxptrStored = rxptr;
00021         rxptr = reqBuffer;
00022         reqMode = true;
00023     }
00024     if( echoMode ) {
00025         debugSerial->putc(c);
00026     }
00027     if( reqMode && reqLen == 0 && c == ':' ) {
00028         if( echoMode ) {
00029             debugSerial->putc('!');
00030         }
00031         int numMatched = sscanf(reqBuffer,"+IPD,%*d,%d%n", &reqLen, &ipdLen);
00032         if( numMatched < 1 ) {
00033             reqMode = false;
00034             reqLen = 0;
00035             rxptr = rxptrStored;
00036             return;
00037         }
00038         reqLen += ipdLen + 1;
00039     }
00040     *rxptr = c;
00041     rxptr++;
00042     *rxptr = 0;
00043     if( reqMode && reqLen > 0 ) {
00044         if( echoMode ) {
00045             debugSerial->putc('#');
00046         }
00047         if( (int)(rxptr - reqBuffer) == reqLen ) {
00048             // Process it
00049             queueRequest();
00050             // Return to normal buffer mode
00051             reqMode = false;
00052             reqLen = 0;
00053             rxptr = rxptrStored;
00054         }
00055     }
00056 }
00057 
00058 void ESP8266_WebServer::debugBuffers(Serial* target) {
00059     target->printf("\r\n\r\nRequest Buffer '%s'\r\nReqLen=%d,ReqMode=%d\r\n", reqBuffer, reqLen, reqMode);    
00060 }
00061 
00062 void ESP8266_WebServer::readBuffer(void) {
00063     strncpy(reply, buffer, sizeof(buffer));
00064     while(reqMode == true ) { wait_ms(10); }
00065     
00066     rxptr = buffer;
00067     *rxptr = 0;
00068 }
00069 
00070 short ESP8266_WebServer::data_waiting(void)
00071 {
00072     char* ok = strstr(buffer, "OK\r\n");
00073     char* error = strstr(buffer, "ERROR\r\n");
00074     char* nochange = strstr(buffer, "no change\r\n");
00075     
00076     if( (ok != NULL) || (error != NULL ) || (nochange != NULL ) )
00077     {
00078         return 1;
00079     }
00080 
00081     return 0;
00082 }
00083 
00084 short ESP8266_WebServer::string_waiting(const char* str)
00085 {
00086     char* pr = strstr(buffer, str);
00087     char* error = strstr(buffer, "ERROR\r\n");
00088     
00089     if( (pr != NULL) || (error != NULL ) )
00090     {
00091         return 1;
00092     }
00093 
00094     return 0;
00095 }
00096 
00097 void ESP8266_WebServer::ResetModule(void) {
00098     if( string_waiting("\r\nready\r\n") == 0 ) {
00099         readBuffer();
00100         serial->printf("ATE0\r\n");
00101         wait_ms(1000);
00102         
00103         if( string_waiting("\r\nready\r\n") == 0 ) {
00104             readBuffer();
00105             serial->printf("AT+RST\r\n");
00106             wait_ms(1000);
00107             while( string_waiting("\r\nready\r\n") == 0 ) {
00108                 wait_ms(100);
00109             }
00110         }
00111     }
00112     
00113     readBuffer();
00114     serial->printf("ATE0\r\n");
00115     while( data_waiting() == 0 ) {
00116         wait_ms(10);
00117     }
00118     readBuffer();
00119 }    
00120     
00121 void ESP8266_WebServer::Initialize(void) {
00122     if( debugSerial != NULL ) {
00123         debugSerial->printf("Done\r\nAccept Multiple connections...");
00124     }
00125     serial->printf("AT+CIPMUX=1\r\n");
00126     while( data_waiting() == 0 ) {
00127         wait_ms(10);
00128     }
00129     readBuffer();
00130     
00131     if( debugSerial != NULL ) {
00132         debugSerial->printf("Done\r\nStarting Web Server...");
00133     }
00134     
00135     serial->printf("AT+CIPSERVER=1,80\r\n");
00136     while( data_waiting() == 0 ) {
00137         wait_ms(10);
00138     }
00139     readBuffer();
00140 }
00141 
00142 void ESP8266_WebServer::queueRequest(void) {
00143     if( strstr(reqBuffer, "HTTP") != NULL ) {
00144         ESP8266_WebRequest* request = new ESP8266_WebRequest(reqBuffer, debugSerial); 
00145         
00146         incoming.push(request);
00147     }
00148 }
00149 
00150 ESP8266_WebRequest* ESP8266_WebServer::GetRequest(void)
00151 {
00152     if( incoming.empty() == false ) {
00153         ESP8266_WebRequest* temp = incoming.front();
00154         incoming.pop();
00155         temp->Read();
00156         
00157         return temp;
00158     }
00159         
00160     return NULL;
00161 }
00162 
00163 void ESP8266_WebServer::sendResponse(int linkID, int numBytes) {
00164     bool sent = false;
00165     
00166     readBuffer();
00167     if( debugSerial != NULL ) {
00168         debugSerial->printf("HTTP Reply Packet(%d bytes)\r\n", numBytes);
00169     }
00170     while( sent == false ) {
00171         while( reqMode == true ) { wait_ms(1); }
00172         serial->printf("AT+CIPSEND=%d,%d\r\n", linkID, numBytes);
00173         wait_ms(100);
00174         if( (string_waiting(">") == 1) ) {
00175             char* error = strstr(buffer, "ERROR\r\n");
00176             if( error != NULL ) { continue; }
00177             for( int i=0; i<numBytes; i++ ) {
00178                 serial->putc(response[i]);
00179             }
00180             while( string_waiting("\r\nSEND OK\r\n") == 0 ) {
00181                 wait_ms(10);
00182             }
00183             error = strstr(buffer, "ERROR\r\n");
00184             if( error != NULL ) { continue; }
00185             sent = true;
00186         }
00187     }
00188     readBuffer();
00189 }
00190 
00191 void ESP8266_WebServer::SendError(int linkID, std::string error) {
00192     SendError(linkID, error.c_str());
00193 }
00194 void ESP8266_WebServer::SendError(int linkID, const char* error) {
00195     sprintf(response, "HTTP/1.1 %s\r\nContent-Type: text/html\r\nContent-Length: %d\r\n\r\n%s", error, strlen(error), error);
00196     sendResponse(linkID, strlen(response));
00197 }
00198 void ESP8266_WebServer::Send404Error(int linkID) {
00199     SendError(linkID, "404 Not Found");
00200 }
00201 
00202 void ESP8266_WebServer::SendReply(int linkID, std::string reply, const char* mimeType) {
00203     SendReply(linkID, reply.c_str(), reply.length(), mimeType, 60);
00204 }
00205 void ESP8266_WebServer::SendReply(int linkID, std::string reply, const char* mimeType, int maxAge) {
00206     SendReply(linkID, reply.c_str(), reply.length(), mimeType, maxAge);
00207 }
00208 
00209 void ESP8266_WebServer::SendReply(int linkID, char const* reply, int replySize, const char* mimeType) {
00210     SendReply(linkID, reply, replySize, mimeType, 600);
00211 }
00212 void ESP8266_WebServer::SendReply(int linkID, char const* reply, const char* mimeType, int maxAge) {
00213     SendReply(linkID, reply, strlen(reply), mimeType, maxAge);
00214 }
00215 void ESP8266_WebServer::SendReply(int linkID, char const* reply, int replySize, const char* mimeType, int maxAge) {
00216     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);
00217     if( debugSerial != NULL ) {
00218         debugSerial->printf("HTTP Reply Header(%d bytes): %s\r\n", strlen(response), response);
00219     }
00220     sendResponse(linkID, strlen(response));
00221     char const* sendPtr = reply;
00222     int bytesSent = 0;
00223     while( bytesSent < replySize ) {
00224         int bytesToSend = replySize - bytesSent;
00225         if( bytesToSend > sizeof(response) ) {
00226             bytesToSend = sizeof(response);
00227         }
00228         
00229         memcpy(response, sendPtr, bytesToSend);
00230         sendResponse(linkID, bytesToSend);
00231         sendPtr += bytesToSend;
00232         bytesSent += bytesToSend;
00233     }
00234 }
00235 
00236 void ESP8266_WebServer::SendFile(int linkID, FileHandle* file, const char* mimeType) {
00237     SendFile(linkID, file, mimeType, 86400);
00238 }
00239 void ESP8266_WebServer::SendFile(int linkID, FileHandle* file, const char* mimeType, int maxAge) {
00240     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);
00241     if( debugSerial != NULL ) {
00242         debugSerial->printf("HTTP Reply Header(%d bytes): %s\r\n", strlen(response), response);
00243     }
00244     sendResponse(linkID, strlen(response));
00245     int numBytes = file->read(response, sizeof(response));
00246     while( numBytes > 0) {
00247         sendResponse(linkID, numBytes);
00248         numBytes = file->read(response, sizeof(response));
00249     }
00250 }
00251 
00252 int ESP8266_WebServer::SendStream(int linkID, char const* reply, int StreamSize,  int WindowSize, const char* mimeType, int maxAge) {
00253     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, StreamSize, maxAge);
00254     if( debugSerial != NULL ) {
00255         debugSerial->printf("HTTP Reply Header(%d bytes): %s\r\n", strlen(response), response);
00256     }
00257     sendResponse(linkID, strlen(response));
00258     return SendStream(linkID, reply, WindowSize);
00259 }
00260 
00261 std::string ESP8266_WebServer::GetStationMAC(void) {
00262     while( reqMode == true ) { wait_ms(1); }
00263     readBuffer();
00264     serial->printf("AT+CIPSTAMAC?\r\n");
00265     while( data_waiting() == 0 ) {
00266         wait_ms(10);
00267     }
00268     readBuffer();
00269     if( debugSerial != NULL ) {
00270         debugSerial->printf("Station MAC Reply: %s\r\n", reply);
00271     }
00272     
00273     std::string mac = std::string(reply);
00274     mac = mac.substr(1, 17);
00275     
00276     return mac;
00277 }
00278 std::string ESP8266_WebServer::GetAPMAC(void) {
00279     while( reqMode == true ) { wait_ms(1); }
00280     readBuffer();
00281     serial->printf("AT+CIPAPMAC?\r\n");
00282     while( data_waiting() == 0 ) {
00283         wait_ms(10);
00284     }
00285     readBuffer();
00286     if( debugSerial != NULL ) {
00287         debugSerial->printf("SoftAP MAC Reply: %s\r\n", reply);
00288     }
00289     
00290     std::string mac = std::string(reply);
00291     mac = mac.substr(1, 17);
00292     
00293     return mac;
00294 }
00295 std::string ESP8266_WebServer::GetStationIP(void) {
00296     while( reqMode == true ) { wait_ms(1); }
00297     readBuffer();
00298     serial->printf("AT+CIPSTA?\r\n");
00299     while( data_waiting() == 0 ) {
00300         wait_ms(10);
00301     }
00302     readBuffer();
00303     if( debugSerial != NULL ) {
00304         debugSerial->printf("Station IP Reply: %s\r\n", reply);
00305     }
00306     
00307     std::string ip = std::string(reply);
00308     ip = ip.substr(1, ip.find('"', 1) - 1);
00309     
00310     return ip;
00311 }
00312 std::string ESP8266_WebServer::GetAPIP(void) {
00313     while( reqMode == true ) { wait_ms(1); }
00314     readBuffer();
00315     serial->printf("AT+CIPAP?\r\n");
00316     while( data_waiting() == 0 ) {
00317         wait_ms(10);
00318     }
00319     readBuffer();
00320     if( debugSerial != NULL ) {
00321         debugSerial->printf("SoftAP IP Reply: %s\r\n", reply);
00322     }
00323     
00324     std::string ip = std::string(reply);
00325     ip = ip.substr(1, ip.find('"', 1) - 1);
00326     
00327     return ip;
00328 }
00329 int ESP8266_WebServer::GetOperatingMode(void) {
00330     while( reqMode == true ) { wait_ms(1); }
00331     readBuffer();
00332     serial->printf("AT+CWMODE?\r\n");
00333     while( data_waiting() == 0 ) {
00334         wait_ms(10);
00335     }
00336     readBuffer();
00337     if( debugSerial != NULL ) {
00338         debugSerial->printf("Operating Mode Reply: %s\r\n", reply);
00339     }
00340     
00341     return atoi(reply);
00342 }
00343 std::string ESP8266_WebServer::GetStationSSID(void) {
00344     while( reqMode == true ) { wait_ms(1); }
00345     readBuffer();
00346     serial->printf("AT+CWJAP?\r\n");
00347     while( data_waiting() == 0 ) {
00348         wait_ms(10);
00349     }
00350     readBuffer();
00351     if( debugSerial != NULL ) {
00352         debugSerial->printf("Station SSID Reply: %s\r\n", reply);
00353     }
00354     
00355     std::string ssid = std::string(reply);
00356     if( strstr(reply, "No AP\r\n") != NULL ) { return "(None)"; }
00357     ssid = ssid.substr(1, ssid.find('"', 1) - 1);
00358     
00359     return ssid;
00360 }
00361 std::list<std::string> ESP8266_WebServer::ListAvailableSSID(void) {
00362     std::list<std::string> apList;
00363     
00364     while( reqMode == true ) { wait_ms(1); }
00365     readBuffer();
00366     serial->printf("AT+CWLAP\r\n");
00367     while( data_waiting() == 0 ) {
00368         wait_ms(10);
00369     }
00370     readBuffer();
00371     if( debugSerial != NULL ) {
00372         debugSerial->printf("SSID List Reply: %s\r\n", reply);
00373     }
00374     
00375     char ssid[65];
00376     char apmac[20];
00377     int ecn;
00378     int rssi;
00379     int tokenLength;
00380     char* token = strstr(reply, "(");
00381     while( token != NULL ) {
00382         int numMatched = sscanf(token, "(%d,\"%[^\"]\",%d,\"%[0123456789abcdef:]\",%*d)\r\n%n", &ecn, ssid, &rssi, apmac, &tokenLength);
00383         if( numMatched < 4 ) {
00384             if( debugSerial != NULL ) {
00385                 debugSerial->printf("SSID List Token Error: NumMatched=%d, SSID=%s\r\n", numMatched, ssid);
00386             }
00387             return apList;
00388         }
00389         if( debugSerial != NULL ) {
00390             debugSerial->printf("SSID List Token : SSID=%s, ECN=%d, RSSI=%d, APMAC=%s, TokenLength=%d\r\n", ssid, ecn, rssi, apmac, tokenLength);
00391         }
00392         apList.push_back(std::string(ssid));
00393         token += tokenLength;
00394         token = strstr(token, "(");
00395     }
00396     
00397     return apList;
00398 }
00399 std::string ESP8266_WebServer::GetFirmwareVersion(void) {
00400     while( reqMode == true ) { wait_ms(1); }
00401     readBuffer();
00402     serial->printf("AT+GMR\r\n");
00403     while( data_waiting() == 0 ) {
00404         wait_ms(10);
00405     }
00406     readBuffer();
00407     if( debugSerial != NULL ) {
00408         debugSerial->printf("Firmware Version Reply: %s\r\n", reply);
00409     }
00410     
00411     std::string ver = std::string(reply);
00412     ver = ver.substr(0, ver.find('\r'));
00413     
00414     return ver;
00415 }
00416 
00417 int ESP8266_WebServer::SendStream(int linkID, char const* reply, int WindowSize) {
00418     char const* sendPtr = reply;
00419     int bytesSent = 0;
00420     while( bytesSent < WindowSize ) {
00421         int bytesToSend = WindowSize - bytesSent;
00422         if( bytesToSend > sizeof(response) ) {
00423             bytesToSend = sizeof(response);
00424         }
00425         
00426         memcpy(response, sendPtr, bytesToSend);
00427         sendResponse(linkID, bytesToSend);
00428         sendPtr += bytesToSend;
00429         bytesSent += bytesToSend;
00430     }
00431     
00432     return bytesSent;
00433 }
00434 
00435 bool ESP8266_WebServer::SetOperatingMode(int mode) {
00436     if( debugSerial != NULL ) {
00437         debugSerial->printf("Set Operating Mode to %s(%d)\r\n", opModes[mode], mode);
00438     }
00439     
00440     while( reqMode == true ) { wait_ms(1); }
00441     readBuffer();
00442     serial->printf("AT+CWMODE=%d\r\n", mode);
00443     while( data_waiting() == 0 ) {
00444         wait_ms(10);
00445     }
00446     readBuffer();
00447     if( debugSerial != NULL ) {
00448         debugSerial->printf("Set Operating Mode Reply: %s\r\n", reply);
00449     }
00450     if( strstr(reply, "\r\nOK\r\n") != NULL ) { return true; }
00451     return false;
00452 }
00453 
00454 bool ESP8266_WebServer::SetStationSSID(std::string newAP, std::string password) {
00455     if( debugSerial != NULL ) {
00456         debugSerial->printf("Set Station SSID to %s, Password=%s\r\n", newAP.c_str(), password.c_str());
00457     }
00458     while( reqMode == true ) { wait_ms(1); }
00459     readBuffer();
00460     serial->printf("AT+CWJAP=\"%s\",\"%s\"\r\n", newAP.c_str(), password.c_str());
00461     while( data_waiting() == 0 ) {
00462         wait_ms(10);
00463     }
00464     readBuffer();
00465     if( debugSerial != NULL ) {
00466         debugSerial->printf("Set Station SSID Reply: %s\r\n", reply);
00467     }
00468     if( strstr(reply, "\r\nOK\r\n") != NULL ) { return true; }
00469     
00470     return false;
00471 }
00472 
00473 ESP8266_WebRequest::ESP8266_WebRequest(const char* packet, Serial* debug) {
00474     int sz = strlen(packet);
00475     data = (char *)malloc(sz+1);
00476     memcpy(data, packet, sz+1);
00477     debugSerial = debug;
00478 }
00479 
00480 void ESP8266_WebRequest::Read(void) {
00481     int bytesRecv, ipdLen, linkID;
00482     int numMatched = sscanf(data,"+IPD,%d,%d:%n", &linkID, &bytesRecv, &ipdLen);
00483     if( numMatched != 2 ) {
00484         if( debugSerial != NULL ) {
00485             debugSerial->printf("IPD ERROR : Matched %d, LinkID=%d, BytesRecv=%d, IPD Header Len=%d\r\n", numMatched, linkID, bytesRecv, ipdLen);
00486         }
00487         return;
00488     }
00489 
00490     if( debugSerial != NULL ) {
00491         debugSerial->printf("IPD Data: LinkID=%d, BytesRecv=%d, IPD Header Len=%d\r\n", linkID, bytesRecv, ipdLen);
00492     }
00493     if( strstr(data, "HTTP") != NULL ) {
00494         if( debugSerial != NULL ) {
00495             debugSerial->printf("Got HTTP Request\r\n");
00496         }
00497         char* httpPacket = data + ipdLen;
00498         if( debugSerial != NULL ) {
00499             debugSerial->printf("HTTP Packet: %s\r\n", httpPacket);
00500         }
00501         char* httpMethod = (char*)malloc(16);
00502         char* httpURI = (char*)malloc(256);
00503         
00504         int numMatched = sscanf(httpPacket, "%s %s HTTP/%*c.%*c", httpMethod, httpURI);
00505         if( numMatched != 2 ) {
00506             if( debugSerial != NULL ) {
00507                 debugSerial->printf("HTTP ERROR : Matched %d, Method=%s, URI=%s\r\n", numMatched, httpMethod, httpURI);
00508             }
00509             
00510             free(httpMethod);
00511             free(httpURI);
00512             return;
00513         }
00514         
00515         LinkID = linkID;
00516         Method = httpMethod;
00517         URI = httpURI;
00518         int pos = URI.find('?');
00519         if(pos != string::npos ) {
00520             string params = URI.substr(pos+1);
00521             URI = URI.substr(0,pos);
00522             pos = params.find('=');
00523             while( pos != string::npos ) {
00524                 string name = params.substr(0,pos);
00525                 string value = params.substr(pos+1);
00526                 pos = params.find('&');
00527                 if( pos == string::npos )
00528                 {
00529                     if( debugSerial != NULL ) {
00530                         debugSerial->printf("HTTP GET Parameter %s=%s\r\n", name.c_str(), value.c_str());
00531                     }
00532                     Parameters[name] = value;
00533                     break;
00534                 }
00535                 
00536                 value = value.substr(0,value.find('&'));
00537                 params = params.substr(pos+1);
00538                 pos = params.find('=');
00539                 if( debugSerial != NULL ) {
00540                     debugSerial->printf("HTTP GET Parameter %s=%s\r\n", name.c_str(), value.c_str());
00541                 }
00542                 Parameters[name] = value;
00543             }
00544         }
00545         if( debugSerial != NULL ) {
00546             debugSerial->printf("HTTP %s %s\r\n", httpMethod, httpURI);
00547         }
00548         
00549         free(httpMethod);
00550         free(httpURI);
00551     }
00552 }
00553 
00554 ESP8266_WebRequest::~ESP8266_WebRequest()
00555 {
00556     free(data);
00557 }