2024-02-14 09:30:46 +00:00
# include <ESPMegaRecovery.hpp>
ESPMegaRecovery : : ESPMegaRecovery ( )
{
// Initialize all the pointers to null
this - > fram = nullptr ;
this - > fram_address = 0 ;
this - > bootloop_counter = 0 ;
this - > recovery_mode = false ;
2024-05-19 10:40:11 +00:00
this - > web_server = nullptr ;
this - > iot = nullptr ;
2024-02-14 09:30:46 +00:00
}
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 ( ) ;
2024-05-19 10:15:49 +00:00
ESP_LOGV ( " ESPMegaRecovery " , " Bootloop counter: %d " , this - > getBootloopCounter ( ) ) ;
2024-02-14 09:30:46 +00:00
// If the bootloop counter is greater than 5, enter recovery mode
if ( this - > getBootloopCounter ( ) > 5 ) {
2024-05-19 10:40:11 +00:00
ESP_LOGE ( " ESPMegaRecovery " , " Bootloop detected " ) ;
2024-05-19 10:15:49 +00:00
// Reset the bootloop counter to prevent re-entering recovery mode
// The device might unintentionally restart multiple times
// By resetting the counter, the user can press reset once in recovery mode to exit
ESP_LOGD ( " ESPMegaRecovery " , " Resetting bootloop counter " ) ;
this - > resetBootloopCounter ( ) ;
2024-05-19 10:40:11 +00:00
ESP_LOGW ( " ESPMegaRecovery " , " Entering recovery mode " ) ;
this - > enterRecoveryMode ( ) ;
this - > loop ( ) ;
2024-02-14 09:30:46 +00:00
}
}
void ESPMegaRecovery : : loop ( ) {
// If the device is in recovery mode, block all other tasks
if ( this - > isRecoveryMode ( ) ) {
2024-05-19 10:15:49 +00:00
int i = 0 ;
2024-02-14 09:30:46 +00:00
while ( true ) {
2024-05-19 10:40:11 +00:00
if ( i % 10 = = 0 ) {
2024-05-19 10:15:49 +00:00
ESP_LOGV ( " ESPMegaRecovery " , " System is in recovery mode, no tasks will be executed " ) ;
ESP_LOGV ( " ESPMegaRecovery " , " Please upload a new firmware to exit recovery mode " ) ;
2024-05-19 10:40:11 +00:00
}
2024-02-14 09:30:46 +00:00
// This code will become the new loop
delay ( 1000 ) ;
2024-05-19 10:15:49 +00:00
i + + ;
2024-02-14 09:30:46 +00:00
}
}
2024-02-14 09:32:49 +00:00
// Watchdog timer
static bool booted = false ;
static uint32_t boot_time = millis ( ) ;
if ( ! booted ) {
if ( millis ( ) - boot_time > RECOVERY_WATCHDOG_TIMEOUT * 1000 ) {
2024-05-19 10:15:49 +00:00
ESP_LOGI ( " ESPMegaRecovery " , " System booted successfully, resetting bootloop counter " ) ;
2024-02-14 09:32:49 +00:00
this - > resetBootloopCounter ( ) ;
booted = true ;
}
}
2024-02-14 09:30:46 +00:00
}
void ESPMegaRecovery : : enterRecoveryMode ( ) {
// Set the recovery mode flag
this - > recovery_mode = true ;
2024-05-19 10:40:11 +00:00
// Enabling the IoT module
ESP_LOGI ( " ESPMegaRecovery " , " Enabling the IoT module " ) ;
this - > iot = new ESPMegaIoT ( ) ;
this - > iot - > bindFRAM ( this - > fram ) ;
ETH . begin ( ) ;
this - > iot - > bindEthernetInterface ( & ETH ) ;
ESP_LOGI ( " ESPMegaRecovery " , " Loading network configuration " ) ;
this - > iot - > loadNetworkConfig ( ) ;
ESP_LOGI ( " ESPMegaRecovery " , " Attempting to connect to the network " ) ;
this - > iot - > connectNetwork ( ) ;
// Start the web server
ESP_LOGI ( " ESPMegaRecovery " , " Starting the web server " ) ;
this - > web_server = new ESPMegaWebServer ( 80 , this - > iot ) ;
this - > web_server - > bindFRAM ( this - > fram ) ;
this - > web_server - > loadCredentialsFromFRAM ( ) ;
ESP_LOGI ( " ESPMegaRecovery " , " Aquiring the web server instance " ) ;
2024-02-14 09:30:46 +00:00
AsyncWebServer * server = this - > web_server - > getServer ( ) ;
2024-05-19 17:05:16 +00:00
server - > begin ( ) ;
2024-02-14 09:30:46 +00:00
// Add OTA update and restart endpoint
2024-05-19 10:40:11 +00:00
ESP_LOGI ( " ESPMegaRecovery " , " Adding OTA update and reboot endpoints " ) ;
2024-05-19 17:05:16 +00:00
auto bindedDashboardHandler = std : : bind ( & ESPMegaWebServer : : dashboardHandler , this - > web_server , std : : placeholders : : _1 ) ;
2024-02-14 09:30:46 +00:00
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 ) ;
2024-05-19 17:05:16 +00:00
auto bindedDeviceInfoHandler = std : : bind ( & ESPMegaRecovery : : getDeviceInfoHandler , this , std : : placeholders : : _1 ) ;
auto bindedConfigHandler = std : : bind ( & ESPMegaRecovery : : configHandler , this , std : : placeholders : : _1 ) ;
server - > on ( " / " , HTTP_GET , bindedDashboardHandler ) ;
2024-02-14 09:30:46 +00:00
server - > on ( " /ota_update " , HTTP_POST , bindedOtaRequestHandler , bindedOtaUploadHandler ) ;
server - > on ( " /reboot " , HTTP_GET , std : : bind ( & ESPMegaWebServer : : rebootHandler , this - > web_server , std : : placeholders : : _1 ) ) ;
2024-05-19 17:05:16 +00:00
server - > on ( " /get_device_info " , HTTP_GET , bindedDeviceInfoHandler ) ;
server - > on ( " /config " , HTTP_GET , bindedConfigHandler ) ;
2024-02-14 09:30:46 +00:00
}
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 ;
}
2024-05-19 17:05:16 +00:00
void ESPMegaRecovery : : getDeviceInfoHandler ( AsyncWebServerRequest * request ) {
if ( ! request - > authenticate ( this - > web_server - > getWebUsername ( ) , this - > web_server - > getWebPassword ( ) ) )
{
return request - > requestAuthentication ( ) ;
}
StaticJsonDocument < 512 > doc ;
doc [ " hostname " ] = this - > iot - > getNetworkConfig ( ) - > hostname ;
doc [ " ip_address " ] = this - > iot - > getIp ( ) . toString ( ) ;
doc [ " mac_address " ] = this - > iot - > getMac ( ) ;
doc [ " model " ] = BOARD_MODEL ;
doc [ " mqtt_server " ] = " Recovery " ;
doc [ " mqtt_port " ] = " Mode " ;
doc [ " base_topic " ] = " Recovery Mode " ;
doc [ " mqtt_connected " ] = " Recovery Mode " ;
doc [ " software_version " ] = " EMG-SAFE-1.0.0 " ;
doc [ " sdk_version " ] = SDK_VESRION ;
doc [ " idf_version " ] = IDF_VER ;
char buffer [ 512 ] ;
serializeJson ( doc , buffer ) ;
request - > send ( 200 , " application/json " , buffer ) ;
}
void ESPMegaRecovery : : configHandler ( AsyncWebServerRequest * request ) {
// Say Not Available in Recovery Mode
// Wait 3s then redirect to /
request - > send ( 500 , " text/html " , " <h1>RECOVERY MODE</h1><p>Configuration is not available in recovery mode</p><script>setTimeout(function(){window.location.href = '/';}, 1500);</script> " ) ;
}