Skip to content

Commit

Permalink
Fixes and HTTP Post update example
Browse files Browse the repository at this point in the history
Because eboot first erases the space required for the new sketch, and
if the new sketch is larger then the old one, with the old way, part of
the beginning of new sketch will be deleted. Therefore for now I opted
to keep the max update size either half the available space for
sketches or what's left from the first one, whichever is smaller.
To be able to create a simple post mechanism for updates, I needed to
have a way to write the new binary, without knowing it's final size, so
I added an option to the end() method. Example in the WebServer
examples.
  • Loading branch information
John Doe authored and igrr committed Jul 6, 2015
1 parent 3427299 commit 0d969e9
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 13 deletions.
2 changes: 1 addition & 1 deletion cores/esp8266/Esp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
35 changes: 25 additions & 10 deletions cores/esp8266/Updater.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -64,35 +67,47 @@ 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");
#endif
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;
Expand Down
4 changes: 2 additions & 2 deletions cores/esp8266/Updater.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
70 changes: 70 additions & 0 deletions libraries/ESP8266WebServer/examples/WebUpdate/WebUpdate.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>

const char* host = "esp8266-webupdate";
const char* ssid = "........";
const char* password = "........";

ESP8266WebServer server(80);
const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";

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);
}

0 comments on commit 0d969e9

Please sign in to comment.