intermediate: prepare ota upload
This commit is contained in:
parent
b591c7ff12
commit
8b9fabe9e4
|
@ -0,0 +1,130 @@
|
||||||
|
#include "GwUpdate.h"
|
||||||
|
#include <Update.h>
|
||||||
|
|
||||||
|
static String jsonError(String e){
|
||||||
|
e.replace('"',' ');
|
||||||
|
return "{\"status\":\""+e+"\"}";
|
||||||
|
}
|
||||||
|
class UpdateParam{
|
||||||
|
public:
|
||||||
|
String error;
|
||||||
|
size_t uplodaded=0;
|
||||||
|
bool hasError(){
|
||||||
|
return ! error.isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
bool GwUpdate::delayedRestart(){
|
||||||
|
return xTaskCreate([](void *p){
|
||||||
|
GwLog *logRef=(GwLog *)p;
|
||||||
|
logRef->logDebug(GwLog::LOG,"delayed reset started");
|
||||||
|
delay(800);
|
||||||
|
ESP.restart();
|
||||||
|
vTaskDelete(NULL);
|
||||||
|
},"reset",2000,logger,0,NULL) == pdPASS;
|
||||||
|
}
|
||||||
|
GwUpdate::GwUpdate(GwLog *log, GwWebServer *webserver, PasswordChecker checker)
|
||||||
|
{
|
||||||
|
this->checker=checker;
|
||||||
|
this->logger = log;
|
||||||
|
this->server = webserver->getServer();
|
||||||
|
server->on("/update", HTTP_POST, [&](AsyncWebServerRequest *request) {
|
||||||
|
// the request handler is triggered after the upload has finished...
|
||||||
|
// create the response, add header, and send response
|
||||||
|
String result="{\"status\":\"OK\"}";
|
||||||
|
bool updateOk=true;
|
||||||
|
if ( request->_tempObject == NULL){
|
||||||
|
//no data
|
||||||
|
LOG_DEBUG(GwLog::ERROR,"no data in update request");
|
||||||
|
result=jsonError("no data uploaded");
|
||||||
|
updateOk=false;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
UpdateParam *param=(UpdateParam *)(request->_tempObject);
|
||||||
|
updateOk=!param->hasError();
|
||||||
|
LOG_DEBUG(GwLog::LOG,"update finished status=%s %s (%d)",
|
||||||
|
(updateOk?"ok":"error"),
|
||||||
|
param->error.c_str(),
|
||||||
|
param->uplodaded
|
||||||
|
);
|
||||||
|
if (!updateOk){
|
||||||
|
result=jsonError(String("Update failed: ")+param->error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
AsyncWebServerResponse *response = request->beginResponse(200, "application/json",result);
|
||||||
|
response->addHeader("Connection", "close");
|
||||||
|
request->send(response);
|
||||||
|
updateRunning=false;
|
||||||
|
if (updateOk) delayedRestart();
|
||||||
|
}, [&](AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final) {
|
||||||
|
//Upload handler chunks in data
|
||||||
|
LOG_DEBUG(GwLog::DEBUG,"update chunk f=%s,idx=%d,len=%d,final=%d",
|
||||||
|
filename.c_str(),(int)index,(int)len,(int)final
|
||||||
|
);
|
||||||
|
UpdateParam *param=(UpdateParam *)request->_tempObject;
|
||||||
|
if (!index) {
|
||||||
|
if (param == NULL) {
|
||||||
|
param=new UpdateParam();
|
||||||
|
request->_tempObject=param;
|
||||||
|
}
|
||||||
|
if (updateRunning){
|
||||||
|
param->error="another update is running";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
updateRunning=true;
|
||||||
|
}
|
||||||
|
if (!param->hasError())
|
||||||
|
{
|
||||||
|
if (!request->hasParam("_hash", true))
|
||||||
|
{
|
||||||
|
LOG_DEBUG(GwLog::ERROR, "missing _hash in update");
|
||||||
|
param->error = "missing _hash";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (!checker(request->getParam("_hash")->value()))
|
||||||
|
{
|
||||||
|
LOG_DEBUG(GwLog::ERROR, "invalid _hash in update");
|
||||||
|
param->error = "invalid password";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (! param->hasError()){
|
||||||
|
int cmd=U_FLASH;
|
||||||
|
if (!Update.begin(UPDATE_SIZE_UNKNOWN, cmd)) { // Start with max available size
|
||||||
|
LOG_DEBUG(GwLog::ERROR,"unable to start update %s",Update.errorString());
|
||||||
|
param->error=Update.errorString();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (param && !param->hasError())
|
||||||
|
{
|
||||||
|
// Write chunked data to the free sketch space
|
||||||
|
if (len)
|
||||||
|
{
|
||||||
|
size_t wr = Update.write(data, len);
|
||||||
|
if (wr != len)
|
||||||
|
{
|
||||||
|
LOG_DEBUG(GwLog::ERROR, "invalid write, expected %d got %d", (int)len, (int)wr);
|
||||||
|
param->error="unable to write";
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
param->uplodaded+=wr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (final && ! param->hasError())
|
||||||
|
{ // if the final flag is set then this is the last frame of data
|
||||||
|
if (!Update.end(true))
|
||||||
|
{ //true to set the size to the current progress
|
||||||
|
LOG_DEBUG(GwLog::ERROR, "unable to end update %s", Update.errorString());
|
||||||
|
param->error=String("unable to end update:") + String(Update.errorString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#pragma once
|
||||||
|
#include "GwWebServer.h"
|
||||||
|
class GwUpdate{
|
||||||
|
public:
|
||||||
|
typedef bool (*PasswordChecker)(String hash);
|
||||||
|
private:
|
||||||
|
AsyncWebServer *server;
|
||||||
|
GwLog *logger;
|
||||||
|
PasswordChecker checker;
|
||||||
|
bool updateRunning=false;
|
||||||
|
public:
|
||||||
|
bool delayedRestart();
|
||||||
|
GwUpdate(GwLog *log,GwWebServer *webserver, PasswordChecker checker);
|
||||||
|
};
|
|
@ -15,5 +15,6 @@ class GwWebServer{
|
||||||
void begin();
|
void begin();
|
||||||
bool registerMainHandler(const char *url,RequestCreator creator);
|
bool registerMainHandler(const char *url,RequestCreator creator);
|
||||||
void handleAsyncWebRequest(AsyncWebServerRequest *request, GwRequestMessage *msg);
|
void handleAsyncWebRequest(AsyncWebServerRequest *request, GwRequestMessage *msg);
|
||||||
|
AsyncWebServer * getServer(){return server;}
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
|
@ -74,7 +74,7 @@ const unsigned long HEAP_REPORT_TIME=2000; //set to 0 to disable heap reporting
|
||||||
#include "GwSynchronized.h"
|
#include "GwSynchronized.h"
|
||||||
#include "GwUserCode.h"
|
#include "GwUserCode.h"
|
||||||
#include "GwStatistics.h"
|
#include "GwStatistics.h"
|
||||||
|
#include "GwUpdate.h"
|
||||||
|
|
||||||
//NMEA message channels
|
//NMEA message channels
|
||||||
#define N2K_CHANNEL_ID 0
|
#define N2K_CHANNEL_ID 0
|
||||||
|
@ -169,6 +169,8 @@ bool checkPass(String hash){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GwUpdate updater(&logger,&webserver,checkPass);
|
||||||
|
|
||||||
void updateNMEACounter(int id,const char *msg,bool incoming,bool fail=false){
|
void updateNMEACounter(int id,const char *msg,bool incoming,bool fail=false){
|
||||||
//we rely on the msg being long enough
|
//we rely on the msg being long enough
|
||||||
char key[6];
|
char key[6];
|
||||||
|
|
Loading…
Reference in New Issue