diff --git a/cores/esp8266/Esp.cpp b/cores/esp8266/Esp.cpp index 4e0b75106..3bec3830c 100644 --- a/cores/esp8266/Esp.cpp +++ b/cores/esp8266/Esp.cpp @@ -350,7 +350,7 @@ uint32_t EspClass::getFreeSketchSpace() { uint32_t usedSize = getSketchSize(); // round one sector up uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); - uint32_t freeSpaceEnd = (uint32_t)&_SPIFFS_start - 0x40200000; + uint32_t freeSpaceEnd = (uint32_t)&_SPIFFS_start - 0x40200000 - (5 * FLASH_SECTOR_SIZE); #ifdef DEBUG_SERIAL DEBUG_SERIAL.printf("usedSize=%u freeSpaceStart=%u freeSpaceEnd=%u\r\n", usedSize, freeSpaceStart, freeSpaceEnd); diff --git a/cores/esp8266/Updater.cpp b/cores/esp8266/Updater.cpp index c957428ff..194a21e9b 100644 --- a/cores/esp8266/Updater.cpp +++ b/cores/esp8266/Updater.cpp @@ -35,11 +35,14 @@ bool UpdaterClass::begin(size_t size){ _error = 0; uint32_t usedSize = ESP.getSketchSize(); - uint32_t freeSpaceStart = (usedSize + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); - uint32_t freeSpaceEnd = (uint32_t)&_SPIFFS_start - 0x40200000; + uint32_t freeSpaceEnd = (uint32_t)&_SPIFFS_start - 0x40200000 - (5 * FLASH_SECTOR_SIZE); uint32_t roundedSize = (size + FLASH_SECTOR_SIZE - 1) & (~(FLASH_SECTOR_SIZE - 1)); + uint32_t freeSpaceStart = freeSpaceEnd - roundedSize; - if(roundedSize > (freeSpaceEnd - freeSpaceStart)){ + //new sketch can not be more then half the size or more than the free space + //this means that max sketch size is (1MB - 20KB) / 2 for flash 2MB and above + //and the current sketch should not be more than that either + if(freeSpaceStart < usedSize || roundedSize > (freeSpaceEnd/2)){ _error = UPDATE_ERROR_SPACE; #ifdef DEBUG_UPDATER printError(DEBUG_UPDATER); @@ -64,7 +67,7 @@ bool UpdaterClass::begin(size_t size){ return true; } -bool UpdaterClass::end(){ +bool UpdaterClass::end(bool evenIfRemaining){ if(_size == 0){ #ifdef DEBUG_UPDATER DEBUG_UPDATER.println("no update"); @@ -72,27 +75,39 @@ bool UpdaterClass::end(){ return false; } - if(_buffer) os_free(_buffer); - _bufferLen = 0; - - if(hasError() || !isFinished()){ + if(hasError() || (!isFinished() && !evenIfRemaining)){ #ifdef DEBUG_UPDATER DEBUG_UPDATER.printf("premature end: res:%u, pos:%u/%u\n", getError(), progress(), _size); #endif + if(_buffer) os_free(_buffer); + _bufferLen = 0; _currentAddress = 0; _startAddress = 0; _size = 0; return false; } + if(evenIfRemaining){ + if(_bufferLen > 0){ + _writeBuffer(); + } + _size = progress(); + } + if(_buffer) os_free(_buffer); + _bufferLen = 0; + _currentAddress = 0; + eboot_command ebcmd; ebcmd.action = ACTION_COPY_RAW; ebcmd.args[0] = _startAddress; ebcmd.args[1] = 0x00000; ebcmd.args[2] = _size; eboot_command_write(&ebcmd); - - _currentAddress = 0; + +#ifdef DEBUG_UPDATER + DEBUG_UPDATER.printf("Staged: address:0x%08X, size:0x%08X\n", _startAddress, _size); +#endif + _startAddress = 0; _size = 0; _error = UPDATE_ERROR_OK; diff --git a/cores/esp8266/Updater.h b/cores/esp8266/Updater.h index ec5b0c4d9..df3e8fa38 100644 --- a/cores/esp8266/Updater.h +++ b/cores/esp8266/Updater.h @@ -40,12 +40,12 @@ class UpdaterClass { If all bytes are written this call will write the config to eboot and return true - If there is already an update running but is not finished + If there is already an update running but is not finished and !evenIfRemainanig or there is an error this will clear everything and return false the last error is available through getError() */ - bool end(); + bool end(bool evenIfRemaining = false); /* Prints the last error to an output stream diff --git a/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino b/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino new file mode 100644 index 000000000..d72ab1345 --- /dev/null +++ b/libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +const char* host = "esp8266-webupdate"; +const char* ssid = "........"; +const char* password = "........"; + +ESP8266WebServer server(80); +const char* serverIndex = "
"; + +void setup(void){ + Serial.begin(115200); + Serial.println(); + Serial.println("Booting Sketch..."); + WiFi.mode(WIFI_AP_STA); + WiFi.begin(ssid, password); + if(WiFi.waitForConnectResult() == WL_CONNECTED){ + MDNS.begin(host); + server.on("/", HTTP_GET, [](){ + server.sendHeader("Connection", "close"); + server.sendHeader("Access-Control-Allow-Origin", "*"); + server.send(200, "text/html", serverIndex); + }); + server.onFileUpload([](){ + if(server.uri() != "/update") return; + HTTPUpload& upload = server.upload(); + if(upload.status == UPLOAD_FILE_START){ + Serial.setDebugOutput(true); + Serial.printf("Update: %s\n", upload.filename.c_str()); + uint32_t maxSketchSpace = ((ESP.getFreeSketchSpace() + ESP.getSketchSize()) / 2) & 0xFFFFF000; + if(!Update.begin(maxSketchSpace)){//start with max available size + Update.printError(Serial); + return; + } + } else if(upload.status == UPLOAD_FILE_WRITE){ + if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){ + Update.printError(Serial); + return; + } + } else if(upload.status == UPLOAD_FILE_END){ + if(Update.end(true)){ //true to set the size to the current progress + Serial.printf("Update Success: %u\nRebooting...\n", upload.totalSize); + } else { + Update.printError(Serial); + } + Serial.setDebugOutput(false); + } + yield(); + }); + 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(); + }); + server.begin(); + MDNS.addService("http", "tcp", 80); + + Serial.println("Ready! Open http:\/\/%s.local in your browser\n", host); + } else { + Serial.println("WiFi Failed"); + } +} + +void loop(void){ + server.handleClient(); + delay(1); +}