diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino new file mode 100644 index 0000000000..13798adbfb --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/examples/WebUpdater/WebUpdater.ino @@ -0,0 +1,43 @@ +/* + To upload through terminal you can use: curl -F "image=@firmware.bin" esp8266-webupdate.local/update +*/ + +#include +#include +#include +#include +#include + +const char* host = "esp8266-webupdate"; +const char* ssid = "........"; +const char* password = "........"; + +ESP8266WebServer httpServer(80); +ESP8266HTTPUpdateServer httpUpdater; + +void setup(void){ + + Serial.begin(115200); + Serial.println(); + Serial.println("Booting Sketch..."); + WiFi.mode(WIFI_AP_STA); + WiFi.begin(ssid, password); + + while(WiFi.waitForConnectResult() != WL_CONNECTED){ + WiFi.begin(ssid, password); + Serial.println("WiFi failed, retrying."); + } + + MDNS.begin(host); + + httpUpdater.setup(&httpServer); + httpServer.begin(); + + MDNS.addService("http", "tcp", 80); + Serial.printf("HTTPUpdateServer ready! Open http://%s.local/update in your browser\n", host); +} + +void loop(void){ + httpServer.handleClient(); + delay(1); +} diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/keywords.txt b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/keywords.txt new file mode 100644 index 0000000000..08354a599d --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/keywords.txt @@ -0,0 +1,20 @@ +####################################### +# Syntax Coloring Map For HTTPUpdateServer +####################################### + +####################################### +# Datatypes (KEYWORD1) +####################################### + +ESP8266HTTPUpdateServer KEYWORD1 + +####################################### +# Methods and Functions (KEYWORD2) +####################################### + +begin KEYWORD2 +setup KEYWORD2 + +####################################### +# Constants (LITERAL1) +####################################### diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/library.properties b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/library.properties new file mode 100644 index 0000000000..5fd9988715 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/library.properties @@ -0,0 +1,9 @@ +name=ESP8266HTTPUpdateServer +version=1.0 +author=Ivan Grokhotkov, Miguel Ángel Ajo +maintainer=Ivan Grokhtkov +sentence=Simple HTTP Update server based on the ESP8266WebServer +paragraph=The library accepts HTTP post requests to the /update url, and updates the ESP8266 firmware. +category=Communication +url= +architectures=esp8266 diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp new file mode 100644 index 0000000000..2ed37c5022 --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.cpp @@ -0,0 +1,75 @@ +#include +#include +#include +#include +#include +#include "ESP8266HTTPUpdateServer.h" + + +const char* ESP8266HTTPUpdateServer::_serverIndex = +R"(
+ + +
+ )"; + +ESP8266HTTPUpdateServer::ESP8266HTTPUpdateServer(bool serial_debug) +{ + _serial_output = serial_debug; + _server = NULL; +} + +void ESP8266HTTPUpdateServer::setup(ESP8266WebServer *server) +{ + _server = server; + + // handler for the /update form page + _server->on("/update", HTTP_GET, [&](){ + _server->sendHeader("Connection", "close"); + _server->sendHeader("Access-Control-Allow-Origin", "*"); + _server->send(200, "text/html", _serverIndex); + }); + + // handler for the /update form POST (once file upload finishes) + _server->on("/update", HTTP_POST, [&](){ + _server->sendHeader("Connection", "close"); + _server->sendHeader("Access-Control-Allow-Origin", "*"); + _server->send(200, "text/plain", (Update.hasError())?"FAIL":"OK"); + ESP.restart(); + }); + + // handler for the file upload, get's the sketch bytes, and writes + // them through the Update object. + _server->onFileUpload([&](){ + if(_server->uri() != "/update") return; + HTTPUpload& upload = _server->upload(); + if(upload.status == UPLOAD_FILE_START){ + if (_serial_output) + Serial.setDebugOutput(true); + WiFiUDP::stopAll(); + if (_serial_output) + Serial.printf("Update: %s\n", upload.filename.c_str()); + uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000; + if(!Update.begin(maxSketchSpace)){//start with max available size + if (_serial_output) Update.printError(Serial); + } + } else if(upload.status == UPLOAD_FILE_WRITE){ + if (_serial_output) Serial.printf("."); + if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){ + if (_serial_output) Update.printError(Serial); + + } + } else if(upload.status == UPLOAD_FILE_END){ + if(Update.end(true)){ //true to set the size to the current progress + if (_serial_output) Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); + } else { + if (_serial_output) Update.printError(Serial); + } + if (_serial_output) Serial.setDebugOutput(false); + } else if(upload.status == UPLOAD_FILE_ABORTED){ + Update.end(); + if (_serial_output) Serial.println("Update was aborted"); + } + yield(); + }); +} diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h new file mode 100644 index 0000000000..5054af1e6f --- /dev/null +++ b/hardware/esp8266com/esp8266/libraries/ESP8266HTTPUpdateServer/src/ESP8266HTTPUpdateServer.h @@ -0,0 +1,18 @@ +#ifndef __HTTP_UPDATE_SERVER_H +#define __HTTP_UPDATE_SERVER_H + +class ESP8266WebServer; + +class ESP8266HTTPUpdateServer +{ + private: + bool _serial_output; + ESP8266WebServer *_server; + static const char *_serverIndex; + public: + ESP8266HTTPUpdateServer(bool serial_debug=false); + void setup(ESP8266WebServer *server=NULL); +}; + + +#endif diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h index 3388c9bcc2..35f0bf863d 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/ESP8266WebServer.h @@ -27,7 +27,8 @@ #include enum HTTPMethod { HTTP_ANY, HTTP_GET, HTTP_POST, HTTP_PUT, HTTP_PATCH, HTTP_DELETE, HTTP_OPTIONS }; -enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END }; +enum HTTPUploadStatus { UPLOAD_FILE_START, UPLOAD_FILE_WRITE, UPLOAD_FILE_END, + UPLOAD_FILE_ABORTED }; #define HTTP_DOWNLOAD_UNIT_SIZE 1460 #define HTTP_UPLOAD_BUFLEN 2048 @@ -116,6 +117,7 @@ template size_t streamFile(T &file, const String& contentType){ void _parseArguments(String data); static const char* _responseCodeToString(int code); bool _parseForm(WiFiClient& client, String boundary, uint32_t len); + bool _parseFormUploadAborted(); void _uploadWriteByte(uint8_t b); uint8_t _uploadReadByte(WiFiClient& client); void _prepareHeader(String& response, int code, const char* content_type, size_t contentLength); diff --git a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/Parsing.cpp b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/Parsing.cpp index 232fa0e034..216f20c3e4 100644 --- a/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/Parsing.cpp +++ b/hardware/esp8266com/esp8266/libraries/ESP8266WebServer/src/Parsing.cpp @@ -274,7 +274,7 @@ void ESP8266WebServer::_uploadWriteByte(uint8_t b){ uint8_t ESP8266WebServer::_uploadReadByte(WiFiClient& client){ int res = client.read(); if(res == -1){ - while(!client.available()) + while(!client.available() && client.connected()) yield(); res = client.read(); } @@ -387,13 +387,16 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t uint8_t argByte = _uploadReadByte(client); readfile: while(argByte != 0x0D){ + if (!client.connected()) return _parseFormUploadAborted(); _uploadWriteByte(argByte); argByte = _uploadReadByte(client); } argByte = _uploadReadByte(client); + if (!client.connected()) return _parseFormUploadAborted(); if (argByte == 0x0A){ argByte = _uploadReadByte(client); + if (!client.connected()) return _parseFormUploadAborted(); if ((char)argByte != '-'){ //continue reading the file _uploadWriteByte(0x0D); @@ -401,6 +404,7 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t goto readfile; } else { argByte = _uploadReadByte(client); + if (!client.connected()) return _parseFormUploadAborted(); if ((char)argByte != '-'){ //continue reading the file _uploadWriteByte(0x0D); @@ -481,3 +485,9 @@ bool ESP8266WebServer::_parseForm(WiFiClient& client, String boundary, uint32_t #endif return false; } + +bool ESP8266WebServer::_parseFormUploadAborted(){ + _currentUpload.status = UPLOAD_FILE_ABORTED; + if (_fileUploadHandler) _fileUploadHandler(); + return false; +}