From 2dd2d03f6ced814383173c8fc6bf6d640ef743b2 Mon Sep 17 00:00:00 2001 From: Slider0007 <115730895+Slider0007@users.noreply.github.com> Date: Tue, 28 Feb 2023 18:25:27 +0100 Subject: [PATCH] SD card basic R/W check + folder/file presence check (#2085) * SD card basic RW check + folder structure check * Default LED blink repeat 2x * Abort booting when SD basic R/W check failed * SD R/W error+missing folder,file > load reduced UI --- code/components/jomjol_helper/Helper.h | 2 + .../components/jomjol_helper/sdcard_check.cpp | 166 ++++++++++++++++++ code/components/jomjol_helper/sdcard_check.h | 11 ++ code/components/jomjol_helper/statusled.cpp | 2 +- code/main/main.cpp | 49 ++++-- code/main/server_main.cpp | 11 +- 6 files changed, 220 insertions(+), 21 deletions(-) create mode 100644 code/components/jomjol_helper/sdcard_check.cpp create mode 100644 code/components/jomjol_helper/sdcard_check.h diff --git a/code/components/jomjol_helper/Helper.h b/code/components/jomjol_helper/Helper.h index f70e615f2..d2457bdd5 100644 --- a/code/components/jomjol_helper/Helper.h +++ b/code/components/jomjol_helper/Helper.h @@ -76,6 +76,8 @@ enum SystemStatusFlag_t { // One bit per error SYSTEM_STATUS_PSRAM_BAD = 1 << 0, // 1, Critical Error SYSTEM_STATUS_HEAP_TOO_SMALL = 1 << 1, // 2, Critical Error SYSTEM_STATUS_CAM_BAD = 1 << 2, // 4, Critical Error + SYSTEM_STATUS_SDCARD_CHECK_BAD = 1 << 3, // 8, Critical Error + SYSTEM_STATUS_FOLDER_CHECK_BAD = 1 << 4, // 16, Critical Error // Second Byte SYSTEM_STATUS_CAM_FB_BAD = 1 << (0+8), // 8, Flow still might work diff --git a/code/components/jomjol_helper/sdcard_check.cpp b/code/components/jomjol_helper/sdcard_check.cpp new file mode 100644 index 000000000..2b658f7dd --- /dev/null +++ b/code/components/jomjol_helper/sdcard_check.cpp @@ -0,0 +1,166 @@ +#include "sdcard_check.h" +#include +#include +#include +#include +#include +#include + +#include "esp_rom_crc.h" +#include "ClassLogFile.h" + +static const char *TAG = "SDCARD"; + +int SDCardCheckRW(void) +{ + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Basic R/W check started..."); + FILE* pFile = NULL; + int iCRCMessage = 0; + + pFile = fopen("/sdcard/sdcheck.txt","w"); + if (pFile == NULL) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E1) No able to open file to write"); + return -1; + } + else { + std::string sMessage = "This message is used for a SD-Card basic check!"; + iCRCMessage = esp_rom_crc16_le(0, (uint8_t*)sMessage.c_str(), sMessage.length()); + if (fwrite(sMessage.c_str(), sMessage.length(), 1, pFile) == 0 ) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E2) Not able to write file"); + fclose(pFile); + unlink("/sdcard/sdcheck.txt"); + return -2; + } + fclose(pFile); + } + + pFile = fopen("/sdcard/sdcheck.txt","r"); + if (pFile == NULL) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E3) Not able to open file to read back"); + unlink("/sdcard/sdcheck.txt"); + return -3; + } + else { + char cReadBuf[50]; + if (fgets(cReadBuf, sizeof(cReadBuf), pFile) == 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E4) Not able to read file back"); + fclose(pFile); + unlink("/sdcard/sdcheck.txt"); + return -4; + } + else { + if (esp_rom_crc16_le(0, (uint8_t*)cReadBuf, strlen(cReadBuf)) != iCRCMessage) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E5) Read back, but wrong CRC"); + fclose(pFile); + unlink("/sdcard/sdcheck.txt"); + return -5; + } + } + fclose(pFile); + } + + if (unlink("/sdcard/sdcheck.txt") != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Basic R/W check: (E6) Unable to delete the file"); + return -6; + } + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Basic R/W check successful"); + return 0; +} + + +bool SDCardCheckFolderFilePresence() +{ + struct stat sb; + bool bRetval = true; + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Folder/file presence check started..."); + /* check if folder exists: config */ + if (stat("/sdcard/config", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /config not found"); + bRetval = false; + } + + /* check if folder exists: html */ + if (stat("/sdcard/html", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /html not found"); + bRetval = false; + } + + /* check if folder exists: firmware */ + if (stat("/sdcard/firmware", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /firmware not found"); + bRetval = false; + } + + /* check if folder exists: img_tmp */ + if (stat("/sdcard/img_tmp", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /img_tmp not found"); + bRetval = false; + } + + /* check if folder exists: log */ + if (stat("/sdcard/log", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /log not found"); + bRetval = false; + } + + /* check if folder exists: demo */ + if (stat("/sdcard/demo", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: Folder /demo not found"); + bRetval = false; + } + + /* check if file exists: wlan.ini */ + if (stat("/sdcard/wlan.ini", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /wlan.ini not found"); + bRetval = false; + } + + /* check if file exists: config.ini */ + if (stat("/sdcard/config/config.ini", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /config/config.ini not found"); + bRetval = false; + } + + /* check if file exists: index.html */ + if (stat("/sdcard/html/index.html", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/index.html not found"); + bRetval = false; + } + + /* check if file exists: ota.html */ + if (stat("/sdcard/html/ota_page.html", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/ota.html not found"); + bRetval = false; + } + + /* check if file exists: log.html */ + if (stat("/sdcard/html/log.html", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/log.html not found"); + bRetval = false; + } + + /* check if file exists: common.js */ + if (stat("/sdcard/html/common.js", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/common.js not found"); + bRetval = false; + } + + /* check if file exists: gethost.js */ + if (stat("/sdcard/html/gethost.js", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/gethost.js not found"); + bRetval = false; + } + + /* check if file exists: version.txt */ + if (stat("/sdcard/html/version.txt", &sb) != 0) { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/version.txt not found"); + bRetval = false; + } + + if (bRetval) + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Folder/file presence check successful"); + + return bRetval; +} \ No newline at end of file diff --git a/code/components/jomjol_helper/sdcard_check.h b/code/components/jomjol_helper/sdcard_check.h new file mode 100644 index 000000000..8bcf10f36 --- /dev/null +++ b/code/components/jomjol_helper/sdcard_check.h @@ -0,0 +1,11 @@ +#pragma once + +#ifndef COMPONENTS_HELPER_SDCARD_CHECK_H +#define COMPONENTS_HELPER_SDCARD_CHECK_H + +#include "../../include/defines.h" + +int SDCardCheckRW(void); +bool SDCardCheckFolderFilePresence(void); + +#endif /* COMPONENTS_HELPER_SDCARD_CHECK_H */ diff --git a/code/components/jomjol_helper/statusled.cpp b/code/components/jomjol_helper/statusled.cpp index 158e5f626..770eb20f8 100644 --- a/code/components/jomjol_helper/statusled.cpp +++ b/code/components/jomjol_helper/statusled.cpp @@ -26,7 +26,7 @@ void task_StatusLED(void *pvParameter) gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT); // Set the GPIO as a push/pull output gpio_set_level(BLINK_GPIO, 1);// LED off - for (int i=0; i<3; ) // Default: repeat 3 times + for (int i=0; i<2; ) // Default: repeat 2 times { if (!StatusLEDDataInt.bInfinite) ++i; diff --git a/code/main/main.cpp b/code/main/main.cpp index 686b7f37f..2cd5af00e 100644 --- a/code/main/main.cpp +++ b/code/main/main.cpp @@ -42,6 +42,7 @@ #endif //ENABLE_MQTT #include "Helper.h" #include "statusled.h" +#include "sdcard_check.h" #include "../../include/defines.h" //#include "server_GPIO.h" @@ -201,15 +202,9 @@ extern "C" void app_main(void) return; // No way to continue without working SD card! } - // SD card: Create directories (if not already existing) + // SD card: Create log directories (if not already existing) // ******************************************** - bool bDirStatus = LogFile.CreateLogDirectories(); // needed for logging + image saving - bDirStatus = MakeDir("/sdcard/firmware"); // needed for firmware update - bDirStatus = MakeDir("/sdcard/img_tmp"); // needed for setting up alignment marks - bDirStatus = MakeDir("/sdcard/demo"); // needed for demo mode - if (!bDirStatus) { - StatusLED(SDCARD_CHECK, 1, false); - } + LogFile.CreateLogDirectories(); // mandatory for logging + image saving // ******************************************** // Highlight start of logfile logging @@ -219,7 +214,23 @@ extern "C" void app_main(void) LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Start ======================"); LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================================================="); - // Migrate parameter in config.ini to new naming (firmware 14.1 and newer) + // SD card: basic R/W check + // ******************************************** + int iSDCardStatus = SDCardCheckRW(); + if (iSDCardStatus < 0) { + if (iSDCardStatus <= -1 && iSDCardStatus >= -2) { // write error + StatusLED(SDCARD_CHECK, 1, true); + } + else if (iSDCardStatus <= -3 && iSDCardStatus >= -5) { // read error + StatusLED(SDCARD_CHECK, 2, true); + } + else if (iSDCardStatus == -6) { // delete error + StatusLED(SDCARD_CHECK, 3, true); + } + setSystemStatusFlag(SYSTEM_STATUS_SDCARD_CHECK_BAD); // reduced web interface going to be loaded + } + + // Migrate parameter in config.ini to new naming (firmware 15.0 and newer) // ******************************************** migrateConfiguration(); @@ -227,9 +238,12 @@ extern "C" void app_main(void) // ******************************************** setupTime(); // NTP time service: Status of time synchronization will be checked after every round (server_tflite.cpp) - // SD card: basic RW check + // SD card: Create further mandatory directories (if not already existing) + // Correct creation of these folders will be checked with function "SDCardCheckFolderFilePresence" // ******************************************** - // TODO + MakeDir("/sdcard/firmware"); // mandatory for OTA firmware update + MakeDir("/sdcard/img_tmp"); // mandatory for setting up alignment marks + MakeDir("/sdcard/demo"); // mandatory for demo mode // Check for updates // ******************************************** @@ -237,15 +251,18 @@ extern "C" void app_main(void) CheckUpdate(); // Start SoftAP for initial remote setup - // Note: Start AP if no wlan.ini and/or config.ini available, e.g. SD empty; function does not exit anymore until reboot + // Note: Start AP if no wlan.ini and/or config.ini available, e.g. SD card empty; function does not exit anymore until reboot // ******************************************** #ifdef ENABLE_SOFTAP CheckStartAPMode(); #endif - // SD card: Check folder structure + // SD card: Check presence of some mandatory folders / files // ******************************************** - // TODO + if (!SDCardCheckFolderFilePresence()) { + StatusLED(SDCARD_CHECK, 4, true); + setSystemStatusFlag(SYSTEM_STATUS_FOLDER_CHECK_BAD); // reduced web interface going to be loaded + } // Check version information // ******************************************** @@ -460,12 +477,12 @@ extern "C" void app_main(void) TFliteDoAutoStart(); } else if (isSetSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD) || // Non critical errors occured, we try to continue... - isSetSystemStatusFlag(SYSTEM_STATUS_NTP_BAD)) { + isSetSystemStatusFlag(SYSTEM_STATUS_NTP_BAD)) { LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Initialization completed with errors! Starting flow task ..."); TFliteDoAutoStart(); } else { // Any other error is critical and makes running the flow impossible. Init is going to abort. - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Initialization failed. Flow task start aborted!"); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Initialization failed. Flow task start aborted. Loading reduced web interface..."); } } diff --git a/code/main/server_main.cpp b/code/main/server_main.cpp index 54b519854..c2a0d781f 100644 --- a/code/main/server_main.cpp +++ b/code/main/server_main.cpp @@ -215,7 +215,10 @@ esp_err_t hello_main_handler(httpd_req_t *req) if (filetosend == "/sdcard/html/index.html") { if (isSetSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD) || // Initialization failed with crritical errors! - isSetSystemStatusFlag(SYSTEM_STATUS_CAM_BAD)) { + isSetSystemStatusFlag(SYSTEM_STATUS_CAM_BAD) || + isSetSystemStatusFlag(SYSTEM_STATUS_SDCARD_CHECK_BAD) || + isSetSystemStatusFlag(SYSTEM_STATUS_FOLDER_CHECK_BAD)) + { LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "We have a critical error, not serving main page!"); char buf[20]; @@ -228,13 +231,13 @@ esp_err_t hello_main_handler(httpd_req_t *req) } } - message += "
Please check jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes for more information!"; + message += "
Please check logs with log viewer and/or jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes for more information!"; message += "

"; message += " "; message += " "; message += " "; - httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, message.c_str()); - return ESP_FAIL; + httpd_resp_send(req, message.c_str(), message.length()); + return ESP_OK; } else if (isSetupModusActive()) { ESP_LOGD(TAG, "System is in setup mode --> index.html --> setup.html");