recovery mode class

This commit is contained in:
Siwat Sirichai 2024-02-14 16:30:46 +07:00
parent 06b69da78f
commit 87f0ee073b
3 changed files with 110 additions and 11 deletions

View File

@ -0,0 +1,66 @@
#include <ESPMegaRecovery.hpp>
ESPMegaRecovery::ESPMegaRecovery()
{
// Initialize all the pointers to null
this->fram = nullptr;
this->web_server = nullptr;
this->fram_address = 0;
this->bootloop_counter = 0;
this->recovery_mode = false;
}
void ESPMegaRecovery::begin() {
// Retrieve the bootloop counter from the FRAM
if(this->fram != nullptr) {
this->bootloop_counter = this->fram->read8(this->fram_address);
}
// Inclement the bootloop counter
this->inclementBootloopCounter();
// If the bootloop counter is greater than 5, enter recovery mode
if(this->getBootloopCounter() > 5) {
this->enterRecoveryMode();
}
}
void ESPMegaRecovery::loop() {
// If the device is in recovery mode, block all other tasks
if(this->isRecoveryMode()) {
while(true) {
// This code will become the new loop
delay(1000);
}
}
}
void ESPMegaRecovery::enterRecoveryMode() {
// Set the recovery mode flag
this->recovery_mode = true;
// Remove web server binding
AsyncWebServer *server = this->web_server->getServer();
server->reset();
// Add OTA update and restart endpoint
auto bindedOtaRequestHandler = std::bind(&ESPMegaWebServer::otaRequestHandler, this->web_server, std::placeholders::_1);
auto bindedOtaUploadHandler = std::bind(&ESPMegaWebServer::otaUploadHandler, this->web_server, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3, std::placeholders::_4, std::placeholders::_5, std::placeholders::_6);
server->on("/ota_update", HTTP_POST, bindedOtaRequestHandler, bindedOtaUploadHandler);
server->on("/reboot", HTTP_GET, std::bind(&ESPMegaWebServer::rebootHandler, this->web_server, std::placeholders::_1));
}
void ESPMegaRecovery::bindFRAM(FRAM *fram, uint32_t address) {
this->fram = fram;
this->fram_address = address;
}
uint8_t ESPMegaRecovery::getBootloopCounter() {
return this->bootloop_counter;
}
void ESPMegaRecovery::inclementBootloopCounter() {
this->bootloop_counter++;
if(this->fram != nullptr) {
this->fram->write8(this->fram_address, this->bootloop_counter);
}
}
void ESPMegaRecovery::resetBootloopCounter() {
this->bootloop_counter = 0;
if(this->fram != nullptr) {
this->fram->write8(this->fram_address, this->bootloop_counter);
}
}
bool ESPMegaRecovery::isRecoveryMode() {
return this->recovery_mode;
}

View File

@ -0,0 +1,33 @@
#include <FRAM.h>
#include <ESPMegaWebServer.hpp>
/**
* @brief Recovery mode for ESPMega
* Recovery mode is a mode that is entered when the device is in a bootloop
* In this mode, the device will block all other tasks and wait for a new firmware to be uploaded over the air
* To exit recovery mode, the device must be restarted or a new firmware must be uploaded
* This is useful when the device is in a bootloop and the user can't access the device to upload a new firmware (ota bricking)
* The device is considered to be in a bootloop when it is restarted before RECOVERY_WATCHDOG_TIMEOUT seconds for 5 consecutive times
* The timer is started when the device's initialization is complete (enter loop)
*/
#define RECOVERY_WATCHDOG_TIMEOUT 15 // The time in seconds to wait for a restart before considering it a bootloop
class ESPMegaRecovery {
public:
ESPMegaRecovery();
void begin();
void loop();
void enterRecoveryMode(); // Enter recovery mode, Block all other tasks, start OTA server
void bindFRAM(FRAM* fram, uint32_t address); // Bind the FRAM block to store the bootloop counter
uint8_t getBootloopCounter(); // Get the bootloop counter
void inclementBootloopCounter(); // Increment the bootloop counter
void resetBootloopCounter(); // Reset the bootloop counter
bool isRecoveryMode(); // Check if the device is in recovery mode
private:
FRAM* fram;
uint32_t fram_address;
uint8_t bootloop_counter;
ESPMegaWebServer* web_server;
bool recovery_mode;
};

View File

@ -35,17 +35,6 @@ class ESPMegaWebServer
void saveCredentialsToFRAM(); void saveCredentialsToFRAM();
AsyncWebServer* getServer(); AsyncWebServer* getServer();
bool checkAuthentication(AsyncWebServerRequest *request); bool checkAuthentication(AsyncWebServerRequest *request);
private:
// FRAM
FRAM *fram;
// Credentials
char webUsername[32];
char webPassword[32];
// Web Server
AsyncWebServer *server;
uint16_t port;
// ESPMegaIoT
ESPMegaIoT *iot;
// Endpoints Handlers // Endpoints Handlers
void dashboardHandler(AsyncWebServerRequest *request); void dashboardHandler(AsyncWebServerRequest *request);
String dashboardProcessor(const String& var); String dashboardProcessor(const String& var);
@ -57,4 +46,15 @@ class ESPMegaWebServer
void otaUploadHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final); void otaUploadHandler(AsyncWebServerRequest *request, String filename, size_t index, uint8_t *data, size_t len, bool final);
void restAPIHandler(AsyncWebServerRequest *request); void restAPIHandler(AsyncWebServerRequest *request);
void rebootHandler(AsyncWebServerRequest *request); void rebootHandler(AsyncWebServerRequest *request);
private:
// FRAM
FRAM *fram;
// Credentials
char webUsername[32];
char webPassword[32];
// Web Server
AsyncWebServer *server;
uint16_t port;
// ESPMegaIoT
ESPMegaIoT *iot;
}; };