1
mirror of https://github.com/rvdbreemen/OTGW-firmware synced 2024-11-16 04:33:49 +01:00
OTGW-firmware/OTGW-ModUpdateServer-impl.h
Robert van den Breemen cf35d5bfaf Fix for OTA resets by hardware watchdog
This fixes the long outstanding issue of the reset during firmware upgrades. From now on it should be possible to flash over the air again.
2021-01-11 09:12:07 +01:00

178 lines
6.2 KiB
C++

/*
***************************************************************************
** Program : MonUpdateServer-impl.h
** Modified to work with OTGW Nodoshop Hardware Watchdog
**
** This is the ESP8266HTTPUpdateServer.h file
** Created and modified by Ivan Grokhotkov, Miguel Angel Ajo, Earle Philhower and many others
** see: https://github.com/esp8266/Arduino/tree/master/libraries/ESP8266HTTPUpdateServer
**
** ... and then modified by Willem Aandewiel
**
** License and credits
** Arduino IDE is developed and maintained by the Arduino team. The IDE is licensed under GPL.
**
** ESP8266 core includes an xtensa gcc toolchain, which is also under GPL.
**
***************************************************************************
*/
#include <Arduino.h>
#include <WiFiClient.h>
#include <WiFiServer.h>
#include <ESP8266WebServer.h>
#include <WiFiUdp.h>
#include <flash_hal.h>
#include <FS.h>
#include "StreamString.h"
#include "Wire.h"
#include "OTGW-ModUpdateServer.h"
#ifndef Debug
//#warning Debug() was not defined!
#define Debug(...) ({ Serial.print(__VA_ARGS__); })
#define Debugln(...) ({ Serial.println(__VA_ARGS__); })
#define Debugf(...) ({ Serial.printf(__VA_ARGS__); })
//#else
// #warning Seems Debug() is already defined!
#endif
namespace esp8266httpupdateserver {
using namespace esp8266webserver;
/**
static const char serverIndex2[] PROGMEM =
R"(<html charset="UTF-8">
<body>
<h1>ESP8266 Flash utility</h1>
<form method='POST' action='?cmd=0' enctype='multipart/form-data'>
<input type='hidden' name='cmd' value='0'>
<input type='file' accept='ino.bin' name='update'>
<input type='submit' value='Flash Firmware'>
</form>
<form method='POST' action='?cmd=100' enctype='multipart/form-data'>
<input type='hidden' name='cmd' value='100'>
<input type='file' accept='spiffs.bin' name='update'>
<input type='submit' value='Flash Spiffs'>
</form>
</html>)";
static const char successResponse[] PROGMEM =
"<META http-equiv=\"refresh\" content=\"15;URL=/\">Update <b>Success</b>!<br>Wait for DSMR-logger to reboot...";
**/
template <typename ServerType>
ESP8266HTTPUpdateServerTemplate<ServerType>::ESP8266HTTPUpdateServerTemplate(bool serial_debug)
{
_serial_output = serial_debug;
_server = NULL;
_username = emptyString;
_password = emptyString;
_authenticated = false;
}
template <typename ServerType>
void ESP8266HTTPUpdateServerTemplate<ServerType>::setup(ESP8266WebServerTemplate<ServerType> *server, const String& path, const String& username, const String& password)
{
_server = server;
_username = username;
_password = password;
// handler for the /update form page
_server->on(path.c_str(), HTTP_GET, [&](){
if(_username != emptyString && _password != emptyString && !_server->authenticate(_username.c_str(), _password.c_str()))
return _server->requestAuthentication();
_server->send_P(200, PSTR("text/html"), _serverIndex);
});
// handler for the /update form POST (once file upload finishes)
_server->on(path.c_str(), HTTP_POST, [&](){
if(!_authenticated)
return _server->requestAuthentication();
if (Update.hasError()) {
_server->send(200, F("text/html"), String(F("Update error: ")) + _updaterError);
} else {
_server->client().setNoDelay(true);
_server->send_P(200, PSTR("text/html"), _serverSuccess);
_server->client().stop();
delay(1000);
ESP.restart();
delay(3000);
}
},[&](){
// handler for the file upload, get's the sketch bytes, and writes
// them through the Update object
HTTPUpload& upload = _server->upload();
if(upload.status == UPLOAD_FILE_START){
_updaterError.clear();
if (_serial_output)
Serial.setDebugOutput(true);
_authenticated = (_username == emptyString || _password == emptyString || _server->authenticate(_username.c_str(), _password.c_str()));
if(!_authenticated){
if (_serial_output)
Debugln("Unauthenticated Update\n");
return;
}
WiFiUDP::stopAll();
if (_serial_output)
Debugf("Update: %s\r\n", upload.filename.c_str());
if (upload.name == "filesystem") {
size_t fsSize = ((size_t) &_FS_end - (size_t) &_FS_start);
close_all_fs();
if (!Update.begin(fsSize, U_FS)){//start with max available size
if (_serial_output) Update.printError(Serial);
}
} else {
uint32_t maxSketchSpace = (ESP.getFreeSketchSpace() - 0x1000) & 0xFFFFF000;
if (!Update.begin(maxSketchSpace, U_FLASH)){//start with max available size
_setUpdaterError();
}
}
} else if(_authenticated && upload.status == UPLOAD_FILE_WRITE && !_updaterError.length()){
if (_serial_output) Debug(".");
// Feed the dog before it bites!
Wire.beginTransmission(0x26); Wire.write(0xA5); Wire.endTransmission();
// End of feeding hack
if(Update.write(upload.buf, upload.currentSize) != upload.currentSize){
_setUpdaterError();
}
} else if(_authenticated && upload.status == UPLOAD_FILE_END && !_updaterError.length()){
if(Update.end(true)){ //true to set the size to the current progress
if (_serial_output) Debugf("\r\nUpdate Success: %u\r\nRebooting...\r\n", upload.totalSize);
} else {
_setUpdaterError();
}
if (_serial_output) Serial.setDebugOutput(false);
} else if(_authenticated && upload.status == UPLOAD_FILE_ABORTED){
Update.end();
if (_serial_output) Debugln("Update was aborted");
}
delay(0);
});
}
template <typename ServerType>
void ESP8266HTTPUpdateServerTemplate<ServerType>::setIndexPage(const char *indexPage)
{
_serverIndex = indexPage;
}
template <typename ServerType>
void ESP8266HTTPUpdateServerTemplate<ServerType>::setSuccessPage(const char *successPage)
{
_serverSuccess = successPage;
}
template <typename ServerType>
void ESP8266HTTPUpdateServerTemplate<ServerType>::_setUpdaterError()
{
if (_serial_output) Update.printError(Serial);
StreamString str;
Update.printError(str);
_updaterError = str.c_str();
}
};