瀏覽代碼

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
Slider0007 2 年之前
父節點
當前提交
2dd2d03f6c

+ 2 - 0
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

+ 166 - 0
code/components/jomjol_helper/sdcard_check.cpp

@@ -0,0 +1,166 @@
+#include "sdcard_check.h"
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+
+#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;
+}

+ 11 - 0
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 */

+ 1 - 1
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;

+ 33 - 16
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...");
     }
 }
 

+ 7 - 4
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 += "<br>Please check <a href=\"https://jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes\" target=_blank>jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes</a> for more information!";
+            message += "<br>Please check logs with log viewer and/or <a href=\"https://jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes\" target=_blank>jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes</a> for more information!";
             message += "<br><br><button onclick=\"window.location.href='/reboot';\">Reboot</button>";
             message += "&nbsp;<button onclick=\"window.open('/ota_page.html');\">OTA Update</button>";
             message += "&nbsp;<button onclick=\"window.open('/log.html');\">Log Viewer</button>";
             message += "&nbsp;<button onclick=\"window.open('/info.html');\">Show System Info</button>";
-            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");