From 87f0ee073bbe3d8184869d586cc4a7d317509c1f Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Wed, 14 Feb 2024 16:30:46 +0700 Subject: [PATCH] recovery mode class --- .../lib/ESPMegaPRO/ESPMegaRecovery.cpp | 66 +++++++++++++++++++ .../lib/ESPMegaPRO/ESPMegaRecovery.hpp | 33 ++++++++++ .../lib/ESPMegaPRO/ESPMegaWebServer.hpp | 22 +++---- 3 files changed, 110 insertions(+), 11 deletions(-) create mode 100644 ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaRecovery.cpp create mode 100644 ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaRecovery.hpp diff --git a/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaRecovery.cpp b/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaRecovery.cpp new file mode 100644 index 0000000..f9343a3 --- /dev/null +++ b/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaRecovery.cpp @@ -0,0 +1,66 @@ +#include +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; +} diff --git a/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaRecovery.hpp b/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaRecovery.hpp new file mode 100644 index 0000000..16415cf --- /dev/null +++ b/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaRecovery.hpp @@ -0,0 +1,33 @@ +#include +#include +/** + * @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; +}; \ No newline at end of file diff --git a/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaWebServer.hpp b/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaWebServer.hpp index 6559b67..ebe9bff 100644 --- a/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaWebServer.hpp +++ b/ESPMegaPRO-OS-SDK/lib/ESPMegaPRO/ESPMegaWebServer.hpp @@ -35,17 +35,6 @@ class ESPMegaWebServer void saveCredentialsToFRAM(); AsyncWebServer* getServer(); 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 void dashboardHandler(AsyncWebServerRequest *request); 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 restAPIHandler(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; }; \ No newline at end of file