Boot phase: Add more error handling + provide verbose output in error cases (#2020)

* WLAN: add error handling

* WLAN: parameter global struct

* WLAN.ini -> more info text

* RSSIThreshold

* Rename logs

* Boot process: error handling

* Update texts

* Comments

* Init sequence

* Prepare for check dir creation

* add check makedir, update logs

* Blink code for OTA+SoftAP

* Blink code for missing time snyc

* Update

* reboot -> switch LED off

* Update log texts

* Update

* Update log texts

* create empty default folders at startup

* Update

* Adapt log level

* Print log level switch

* Update

* Update text

* Add SD free space to log

* WIFI/MQTT disconnect message set to WARN (+ ERROR)
This commit is contained in:
Slider0007
2023-02-25 21:12:52 +01:00
committed by GitHub
parent a8f8189543
commit 7a9f61a8d8
25 changed files with 1101 additions and 747 deletions

View File

@@ -40,7 +40,9 @@
#ifdef ENABLE_MQTT
#include "server_mqtt.h"
#endif //ENABLE_MQTT
//#include "Helper.h"
#include "Helper.h"
#include "statusled.h"
#include "../../include/defines.h"
//#include "server_GPIO.h"
@@ -83,7 +85,6 @@ extern std::string getFwVersion(void);
extern std::string getHTMLversion(void);
extern std::string getHTMLcommit(void);
std::vector<std::string> splitString(const std::string& str);
bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith);
bool replace(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt);
@@ -93,6 +94,7 @@ void migrateConfiguration(void);
static const char *TAG = "MAIN";
bool Init_NVS_SDCard()
{
esp_err_t ret = nvs_flash_init();
@@ -100,9 +102,8 @@ bool Init_NVS_SDCard()
ESP_ERROR_CHECK(nvs_flash_erase());
ret = nvs_flash_init();
}
////////////////////////////////////////////////
ESP_LOGI(TAG, "Using SDMMC peripheral");
ESP_LOGD(TAG, "Using SDMMC peripheral");
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
// This initializes the slot without card detect (CD) and write protect (WP) signals.
@@ -110,20 +111,19 @@ bool Init_NVS_SDCard()
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
// To use 1-line SD mode, uncomment the following line:
#ifdef __SD_USE_ONE_LINE_MODE__
slot_config.width = 1;
#endif
#ifdef __SD_USE_ONE_LINE_MODE__
slot_config.width = 1;
#endif
// GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
// Internal pull-ups are not sufficient. However, enabling internal pull-ups
// does make a difference some boards, so we do that here.
gpio_set_pull_mode(GPIO_NUM_15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes
gpio_set_pull_mode(GPIO_NUM_2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes
#ifndef __SD_USE_ONE_LINE_MODE__
gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only
gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only
#endif
#ifndef __SD_USE_ONE_LINE_MODE__
gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only
gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only
#endif
gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes
// Options for mounting the filesystem.
@@ -135,246 +135,308 @@ bool Init_NVS_SDCard()
.allocation_unit_size = 16 * 1024
};
sdmmc_card_t* card;
// Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
// Please check its source code and implement error recovery when developing
// production applications.
sdmmc_card_t* card;
ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
ESP_LOGE(TAG, "Failed to mount filesystem. "
"If you want the card to be formatted, set format_if_mount_failed = true.");
} else {
ESP_LOGE(TAG, "Failed to initialize the card (%s). "
"Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
ESP_LOGE(TAG, "Failed to mount FAT filesystem on SD card. Check SD card filesystem (only FAT supported) or try another card");
StatusLED(SDCARD_INIT, 1, true);
}
else if (ret == 263) { // Error code: 0x107 --> usually: SD not found
ESP_LOGE(TAG, "SD card init failed. Check if SD card is properly inserted into SD card slot or try another card");
StatusLED(SDCARD_INIT, 2, true);
}
else {
ESP_LOGE(TAG, "SD card init failed. Check error code or try another card");
StatusLED(SDCARD_INIT, 3, true);
}
return false;
}
sdmmc_card_print_info(stdout, card);
//sdmmc_card_print_info(stdout, card); // With activated CONFIG_NEWLIB_NANO_FORMAT --> capacity not printed correctly anymore
SaveSDCardInfo(card);
return true;
}
void task_MainInitError_blink(void *pvParameter)
{
gpio_pad_select_gpio(BLINK_GPIO);
gpio_set_direction(BLINK_GPIO, GPIO_MODE_OUTPUT);
TickType_t xDelay;
xDelay = 100 / portTICK_PERIOD_MS;
ESP_LOGD(TAG, "SD-Card could not be inialized - STOP THE PROGRAMM HERE");
while (1)
{
gpio_set_level(BLINK_GPIO, 1);
vTaskDelay( xDelay );
gpio_set_level(BLINK_GPIO, 0);
vTaskDelay( xDelay );
}
vTaskDelete(NULL); //Delete this task if it exits from the loop above
}
extern "C" void app_main(void)
{
//#ifdef CONFIG_HEAP_TRACING_STANDALONE
#if defined HEAP_TRACING_MAIN_WIFI || defined HEAP_TRACING_MAIN_START
//register a buffer to record the memory trace
ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) );
#endif
//#ifdef CONFIG_HEAP_TRACING_STANDALONE
#if defined HEAP_TRACING_MAIN_WIFI || defined HEAP_TRACING_MAIN_START
//register a buffer to record the memory trace
ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) );
#endif
TickType_t xDelay;
#ifdef DISABLE_BROWNOUT_DETECTOR
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
#endif
#ifdef DISABLE_BROWNOUT_DETECTOR
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //disable brownout detector
#endif
ESP_LOGI(TAG, "\n\n\n\n\n"); // Add mark on log to see when it restarted
#ifdef HEAP_TRACING_MAIN_START
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
#endif
// ********************************************
// Highlight start of app_main
// ********************************************
ESP_LOGI(TAG, "\n\n\n\n================ Start app_main =================");
// Init camera
// ********************************************
PowerResetCamera();
esp_err_t camStatus = Camera.InitCam();
Camera.LightOnOff(false);
xDelay = 2000 / portTICK_PERIOD_MS;
ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay);
vTaskDelay( xDelay );
xDelay = 2000 / portTICK_PERIOD_MS;
ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
vTaskDelay( xDelay );
// Init SD card
// ********************************************
if (!Init_NVS_SDCard())
{
xTaskCreate(&task_MainInitError_blink, "task_MainInitError_blink", configMINIMAL_STACK_SIZE * 64, NULL, tskIDLE_PRIORITY+1, NULL);
return; // No way to continue without SD-Card!
ESP_LOGE(TAG, "Device init aborted!");
return; // No way to continue without working SD card!
}
// SD card: Create 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);
}
// ********************************************
// Highlight start of logfile logging
// Default Log Level: INFO -> Everything which needs to be logged during boot should be have level INFO, WARN OR ERROR
// ********************************************
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
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)
// ********************************************
migrateConfiguration();
setupTime();
// Init time (as early as possible, but SD card needs to be initialized)
// ********************************************
setupTime(); // NTP time service: Status of time synchronization will be checked after every round (server_tflite.cpp)
string versionFormated = getFwVersion() + ", Date/Time: " + std::string(BUILD_TIME) + \
// SD card: basic RW check
// ********************************************
// TODO
// Check for updates
// ********************************************
CheckOTAUpdate();
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
// ********************************************
#ifdef ENABLE_SOFTAP
CheckStartAPMode();
#endif
// SD card: Check folder structure
// ********************************************
// TODO
// Check version information
// ********************************************
std::string versionFormated = getFwVersion() + ", Date/Time: " + std::string(BUILD_TIME) + \
", Web UI: " + getHTMLversion();
if (std::string(GIT_TAG) != "") { // We are on a tag, add it as prefix
string versionFormated = "Tag: '" + std::string(GIT_TAG) + "', " + versionFormated;
versionFormated = "Tag: '" + std::string(GIT_TAG) + "', " + versionFormated;
}
LogFile.CreateLogDirectories();
MakeDir("/sdcard/demo"); // needed for demo mode
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Startup ====================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, versionFormated);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason());
#ifdef DEBUG_ENABLE_SYSINFO
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device Info : " + get_device_info() );
ESP_LOGD(TAG, "Device infos %s", get_device_info().c_str());
#endif
#endif //DEBUG_ENABLE_SYSINFO
#ifdef USE_HIMEM_IF_AVAILABLE
#ifdef DEBUG_HIMEM_MEMORY_CHECK
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Himem mem check : " + himem_memory_check() );
ESP_LOGD(TAG, "Himem mem check %s", himem_memory_check().c_str());
#endif
#endif
CheckIsPlannedReboot();
CheckOTAUpdate();
CheckUpdate();
#ifdef ENABLE_SOFTAP
CheckStartAPMode(); // if no wlan.ini and/or config.ini --> AP ist startet and this function does not exit anymore until reboot
#endif
#ifdef HEAP_TRACING_MAIN_WIFI
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
#endif
char *ssid = NULL, *passwd = NULL, *hostname = NULL, *ip = NULL, *gateway = NULL, *netmask = NULL, *dns = NULL; int rssithreshold = 0;
LoadWlanFromFile(WLAN_CONFIG_FILE, ssid, passwd, hostname, ip, gateway, netmask, dns, rssithreshold);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "WLAN-Settings - RSSI-Threshold: " + to_string(rssithreshold));
if (ssid != NULL && passwd != NULL)
#ifdef __HIDE_PASSWORD
ESP_LOGD(TAG, "WLan: %s, XXXXXX", ssid);
#else
ESP_LOGD(TAG, "WLan: %s, %s", ssid, passwd);
#endif
else
ESP_LOGD(TAG, "No SSID and PASSWORD set!!!");
if (hostname != NULL)
ESP_LOGD(TAG, "Hostname: %s", hostname);
else
ESP_LOGD(TAG, "Hostname not set");
if (ip != NULL && gateway != NULL && netmask != NULL)
ESP_LOGD(TAG, "Fixed IP: %s, Gateway %s, Netmask %s", ip, gateway, netmask);
if (dns != NULL)
ESP_LOGD(TAG, "DNS IP: %s", dns);
wifi_init_sta(ssid, passwd, hostname, ip, gateway, netmask, dns, rssithreshold);
xDelay = 2000 / portTICK_PERIOD_MS;
ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay);
vTaskDelay( xDelay );
#ifdef HEAP_TRACING_MAIN_WIFI
ESP_ERROR_CHECK( heap_trace_stop() );
heap_trace_dump();
#endif
#ifdef HEAP_TRACING_MAIN_START
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
#endif
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================== Main Started =================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
if (getHTMLcommit().substr(0, 7) == "?")
LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Failed to read file html/version.txt to parse Web UI version"));
if (getHTMLcommit().substr(0, 7) != std::string(GIT_REV).substr(0, 7)) { // Compare the first 7 characters of both hashes
LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Web UI version (") + getHTMLcommit() + ") does not match firmware version (" + std::string(GIT_REV) + ") !");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Please make sure to setup the SD-Card properly (check the documentation) or re-install using the AI-on-the-edge-device__update__*.zip!");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Web UI version (" + getHTMLcommit() + ") does not match firmware version (" + std::string(GIT_REV) + ")");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Recommendation: Repeat installation using AI-on-the-edge-device__update__*.zip");
}
std::string zw = getCurrentTimeString("%Y%m%d-%H%M%S");
ESP_LOGD(TAG, "time %s", zw.c_str());
// Check reboot reason
// ********************************************
CheckIsPlannedReboot();
if (!getIsPlannedReboot() && (esp_reset_reason() == ESP_RST_PANIC)) { // If system reboot was not triggered by user and reboot was caused by execption
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Reset reason: " + getResetReason());
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Device was rebooted due to a software exception! Log level is set to DEBUG until the next reboot. "
"Flow init is delayed by 5 minutes to check the logs or do an OTA update");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Keep device running until crash occurs again and check logs after device is up again");
LogFile.setLogLevel(ESP_LOG_DEBUG);
}
else {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason());
}
#ifdef HEAP_TRACING_MAIN_START
ESP_ERROR_CHECK( heap_trace_stop() );
heap_trace_dump();
#endif
#ifdef HEAP_TRACING_MAIN_START
ESP_ERROR_CHECK( heap_trace_stop() );
heap_trace_dump();
#endif
#ifdef HEAP_TRACING_MAIN_WIFI
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
#endif
/* Check if PSRAM can be initalized */
esp_err_t ret;
ret = esp_spiram_init();
if (ret == ESP_FAIL) { // Failed to init PSRAM, most likely not available or broken
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize PSRAM (" + std::to_string(ret) + ")!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Either your device misses the PSRAM chip or it is broken!");
setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
}
else { // PSRAM init ok
/* Check if PSRAM provides at least 4 MB */
size_t psram_size = esp_spiram_get_size();
// size_t psram_size = esp_psram_get_size(); // comming in IDF 5.0
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "The device has " + std::to_string(psram_size/1024/1024) + " MBytes of PSRAM");
if (psram_size < (4*1024*1024)) { // PSRAM is below 4 MBytes
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "At least 4 MBytes are required!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Does the device really have a 4 Mbytes PSRAM?");
setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
// Read WLAN parameter and start WIFI
// ********************************************
int iWLANStatus = LoadWlanFromFile(WLAN_CONFIG_FILE);
if (iWLANStatus == 0) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "WLAN config loaded, init WIFI...");
if (wifi_init_sta() != ESP_OK) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "WIFI init failed. Device init aborted!");
StatusLED(WLAN_INIT, 3, true);
return;
}
}
/* Check available Heap memory */
size_t _hsize = getESPHeapSize();
if (_hsize < 4000000) { // Check available Heap memory for a bit less than 4 MB (a test on a good device showed 4187558 bytes to be available)
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Not enough Heap memory available. Expected around 4 MBytes, but only " + std::to_string(_hsize) + " Bytes are available! That is not enough for this firmware!");
setSystemStatusFlag(SYSTEM_STATUS_HEAP_TOO_SMALL);
} else { // Heap memory is ok
if (camStatus != ESP_OK) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Failed to initialize camera module, retrying...");
PowerResetCamera();
esp_err_t camStatus = Camera.InitCam();
Camera.LightOnOff(false);
xDelay = 2000 / portTICK_PERIOD_MS;
ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay);
vTaskDelay( xDelay );
if (camStatus != ESP_OK) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize camera module!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Check that your camera module is working and connected properly!");
setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD);
}
} else { // Test Camera
if (!Camera.testCamera()) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera Framebuffer cannot be initialized!");
/* Easiest would be to simply restart here and try again,
how ever there seem to be systems where it fails at startup but still work corectly later.
Therefore we treat it still as successed! */
setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD);
}
else {
Camera.LightOnOff(false);
}
}
else if (iWLANStatus == -1) { // wlan.ini not available, potentially empty or content not readable
StatusLED(WLAN_INIT, 1, true);
return; // No way to continue without reading the wlan.ini
}
else if (iWLANStatus == -2) { // SSID or password not configured
StatusLED(WLAN_INIT, 2, true);
return; // No way to continue with empty SSID or password!
}
xDelay = 2000 / portTICK_PERIOD_MS;
ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay*10);
ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
vTaskDelay( xDelay );
// Set log level for wifi component to WARN level (default: INFO; only relevant for serial console)
// ********************************************
esp_log_level_set("wifi", ESP_LOG_WARN);
#ifdef HEAP_TRACING_MAIN_WIFI
ESP_ERROR_CHECK( heap_trace_stop() );
heap_trace_dump();
#endif
#ifdef DEBUG_ENABLE_SYSINFO
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device Info : " + get_device_info() );
ESP_LOGD(TAG, "Device infos %s", get_device_info().c_str());
#endif
#endif //DEBUG_ENABLE_SYSINFO
#ifdef USE_HIMEM_IF_AVAILABLE
#ifdef DEBUG_HIMEM_MEMORY_CHECK
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Himem mem check : " + himem_memory_check() );
ESP_LOGD(TAG, "Himem mem check %s", himem_memory_check().c_str());
#endif
#endif
// Init external PSRAM
// ********************************************
esp_err_t PSRAMStatus = esp_spiram_init();
if (PSRAMStatus != ESP_OK) { // ESP_FAIL -> Failed to init PSRAM
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "PSRAM init failed (" + std::to_string(PSRAMStatus) + ")! PSRAM not found or defective");
setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
StatusLED(PSRAM_INIT, 1, true);
}
else { // ESP_OK -> PSRAM init OK --> continue to check PSRAM size
size_t psram_size = esp_spiram_get_size(); // size_t psram_size = esp_psram_get_size(); // comming in IDF 5.0
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "PSRAM size: " + std::to_string(psram_size) + " byte (" + std::to_string(psram_size/1024/1024) +
"MB / " + std::to_string(psram_size/1024/1024*8) + "MBit)");
// Check PSRAM size
// ********************************************
if (psram_size < (4*1024*1024)) { // PSRAM is below 4 MBytes (32Mbit)
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "PSRAM size >= 4MB (32Mbit) is mandatory to run this application");
setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
StatusLED(PSRAM_INIT, 2, true);
}
else { // PSRAM size OK --> continue to check heap size
size_t _hsize = getESPHeapSize();
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Total heap: " + std::to_string(_hsize) + " byte");
// Check heap memory
// ********************************************
if (_hsize < 4000000) { // Check available Heap memory for a bit less than 4 MB (a test on a good device showed 4187558 bytes to be available)
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Total heap >= 4000000 byte is mandatory to run this application");
setSystemStatusFlag(SYSTEM_STATUS_HEAP_TOO_SMALL);
StatusLED(PSRAM_INIT, 3, true);
}
else { // HEAP size OK --> continue to check camera init
// Check camera init
// ********************************************
if (camStatus != ESP_OK) { // Camera init failed, retry to init
char camStatusHex[33];
sprintf(camStatusHex,"0x%02x", camStatus);
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Camera init failed (" + std::string(camStatusHex) + "), retrying...");
PowerResetCamera();
camStatus = Camera.InitCam();
Camera.LightOnOff(false);
xDelay = 2000 / portTICK_PERIOD_MS;
ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
vTaskDelay( xDelay );
if (camStatus != ESP_OK) { // Camera init failed again
sprintf(camStatusHex,"0x%02x", camStatus);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera init failed (" + std::string(camStatusHex) +
")! Check camera module and/or proper electrical connection");
setSystemStatusFlag(SYSTEM_STATUS_CAM_BAD);
StatusLED(CAM_INIT, 1, true);
}
}
else { // ESP_OK -> Camera init OK --> continue to perform camera framebuffer check
// Camera framebuffer check
// ********************************************
if (!Camera.testCamera()) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera framebuffer check failed");
// Easiest would be to simply restart here and try again,
// how ever there seem to be systems where it fails at startup but still work correctly later.
// Therefore we treat it still as successed! */
setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD);
StatusLED(CAM_INIT, 2, false);
}
Camera.LightOnOff(false); // make sure flashlight is off before start of flow
// Print camera infos
// ********************************************
char caminfo[50];
sensor_t * s = esp_camera_sensor_get();
sprintf(caminfo, "PID: 0x%02x, VER: 0x%02x, MIDL: 0x%02x, MIDH: 0x%02x", s->id.PID, s->id.VER, s->id.MIDH, s->id.MIDL);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Camera info: " + std::string(caminfo));
}
}
}
}
// Print Device info
// ********************************************
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device info: CPU frequency: " + std::to_string(CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) +
"Mhz, CPU cores: " + std::to_string(chipInfo.cores) +
", Chip revision: " + std::to_string(chipInfo.revision));
// Print SD-Card info
// ********************************************
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "SD card info: Name: " + getSDCardName() + ", Capacity: " +
getSDCardCapacity() + "MB, Free: " + getSDCardFreePartitionSpace() + "MB");
xDelay = 2000 / portTICK_PERIOD_MS;
ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
vTaskDelay( xDelay );
// Start webserver + register handler
// ********************************************
ESP_LOGD(TAG, "starting servers");
server = start_webserver();
@@ -391,25 +453,23 @@ extern "C" void app_main(void)
ESP_LOGD(TAG, "Before reg server main");
register_server_main_uri(server, "/sdcard");
/* Testing */
// Only for testing purpose
//setSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD);
//setSystemStatusFlag(SYSTEM_STATUS_PSRAM_BAD);
/* Main Init has successed or only an error which allows to continue operation */
// Check main init + start TFlite task
// ********************************************
if (getSystemStatus() == 0) { // No error flag is set
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Initialization completed successfully!");
ESP_LOGD(TAG, "Before do autostart");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Initialization completed successfully! Starting flow task ...");
TFliteDoAutoStart();
}
else if (isSetSystemStatusFlag(SYSTEM_STATUS_CAM_FB_BAD) || // Non critical errors occured, we try to continue...
isSetSystemStatusFlag(SYSTEM_STATUS_NTP_BAD)) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Initialization completed with errors, but trying to continue...");
ESP_LOGD(TAG, "Before do autostart");
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.
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Initialization failed. Not starting flows!");
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!");
}
}

View File

@@ -8,6 +8,7 @@
#include "time_sntp.h"
#include "connect_wlan.h"
#include "read_wlanini.h"
#include "version.h"
@@ -83,7 +84,7 @@ esp_err_t info_get_handler(httpd_req_t *req)
else if (_task.compare("Hostname") == 0)
{
std::string zw;
zw = std::string(hostname);
zw = std::string(wlan_config.hostname);
httpd_resp_sendstr(req, zw.c_str());
return ESP_OK;
}

View File

@@ -27,6 +27,7 @@
#include "server_help.h"
#include "defines.h"
#include "Helper.h"
#include "statusled.h"
#include "server_ota.h"
#include "lwip/err.h"
@@ -40,22 +41,24 @@
bool isConfigINI = false;
bool isWlanINI = false;
static const char *TAG = "wifi softAP";
static const char *TAG = "WIFI AP";
static void wifi_event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_id == WIFI_EVENT_AP_STACONNECTED) {
wifi_event_ap_staconnected_t* event = (wifi_event_ap_staconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" join, AID=%d",
ESP_LOGI(TAG, "station " MACSTR " join, AID=%d",
MAC2STR(event->mac), event->aid);
} else if (event_id == WIFI_EVENT_AP_STADISCONNECTED) {
wifi_event_ap_stadisconnected_t* event = (wifi_event_ap_stadisconnected_t*) event_data;
ESP_LOGI(TAG, "station "MACSTR" leave, AID=%d",
ESP_LOGI(TAG, "station " MACSTR " leave, AID=%d",
MAC2STR(event->mac), event->aid);
}
}
void wifi_init_softAP(void)
{
ESP_ERROR_CHECK(esp_netif_init());
@@ -87,7 +90,7 @@ void wifi_init_softAP(void)
ESP_ERROR_CHECK(esp_wifi_set_config(WIFI_IF_AP, &wifi_config));
ESP_ERROR_CHECK(esp_wifi_start());
ESP_LOGI(TAG, "wifi_init_softap finished. SSID:%s password:%s channel:%d",
ESP_LOGI(TAG, "started with SSID \"%s\", password: \"%s\", channel: %d. Connect to AP and open http://192.168.4.1",
EXAMPLE_ESP_WIFI_SSID, EXAMPLE_ESP_WIFI_PASS, EXAMPLE_ESP_WIFI_CHANNEL);
}
@@ -136,18 +139,18 @@ void SendHTTPResponse(httpd_req_t *req)
httpd_resp_send_chunk(req, message.c_str(), strlen(message.c_str()));
// message = "</tr><tr><td> Hostname</td><td><input type=\"text\" name=\"hostname\" id=\"hostname\"></td><td></td>";
// message += "</tr><tr><td>Fixed IP</td><td><input type=\"text\" name=\"ip\" id=\"ip\"></td><td>Leave emtpy if set by router</td></tr>";
// message += "<tr><td>gateway</td><td><input type=\"text\" name=\"gateway\" id=\"gateway\"></td><td>Leave emtpy if set by router</td></tr>";
// message += "<tr><td>netmask</td><td><input type=\"text\" name=\"netmask\" id=\"netmask\"></td><td>Leave emtpy if set by router</td>";
// message += "</tr><tr><td>DNS</td><td><input type=\"text\" name=\"dns\" id=\"dns\"></td><td>Leave emtpy if set by router</td></tr>";
// message += "<tr><td>RSSI Threshold</td><td><input type=\"number\" name=\"name\" id=\"threshold\" min=\"-100\" max=\"0\" step=\"1\" value = \"0\"></td><td>WLAN Mesh Parameter: Threshold for RSSI value to check for start switching access point in a mesh system.Possible values: -100 to 0, 0 = disabled - Value will be transfered to wlan.ini at next startup)</td></tr>";
// message += "</tr><tr><td>Fixed IP</td><td><input type=\"text\" name=\"ip\" id=\"ip\"></td><td>Leave emtpy if set by router (DHCP)</td></tr>";
// message += "<tr><td>Gateway</td><td><input type=\"text\" name=\"gateway\" id=\"gateway\"></td><td>Leave emtpy if set by router (DHCP)</td></tr>";
// message += "<tr><td>Netmask</td><td><input type=\"text\" name=\"netmask\" id=\"netmask\"></td><td>Leave emtpy if set by router (DHCP)</td>";
// message += "</tr><tr><td>DNS</td><td><input type=\"text\" name=\"dns\" id=\"dns\"></td><td>Leave emtpy if set by router (DHCP)</td></tr>";
// message += "<tr><td>RSSI Threshold</td><td><input type=\"number\" name=\"name\" id=\"threshold\" min=\"-100\" max=\"0\" step=\"1\" value = \"0\"></td><td>WLAN Mesh Parameter: Threshold for RSSI value to check for start switching access point in a mesh system (if actual RSSI is lower). Possible values: -100 to 0, 0 = disabled - Value will be transfered to wlan.ini at next startup)</td></tr>";
// httpd_resp_send_chunk(req, message.c_str(), strlen(message.c_str()));
message = "<button class=\"button\" type=\"button\" onclick=\"wr()\">Write wlan.ini</button>";
message += "<script language=\"JavaScript\">async function wr(){";
message += "api = \"/config?\"+\"ssid=\"+document.getElementById(\"ssid\").value+\"&pwd=\"+document.getElementById(\"password\").value;";
// message += "api = \"/config?\"+\"ssid=\"+document.getElementById(\"ssid\").value+\"&pwd=\"+document.getElementById(\"password\").value+\"&hn=\"+document.getElementById(\"hostname\").value+\"&ip=\"+document.getElementById(\"ip\").value+\"&gw=\"+document.getElementById(\"gateway\").value+\"&nm=\"+document.getElementById(\"netmask\").value+\"&dns=\"+document.getElementById(\"dns\").value+\"&rssi=\"+document.getElementById(\"threshold\").value;";
// message += "api = \"/config?\"+\"ssid=\"+document.getElementById(\"ssid\").value+\"&pwd=\"+document.getElementById(\"password\").value+\"&hn=\"+document.getElementById(\"hostname\").value+\"&ip=\"+document.getElementById(\"ip\").value+\"&gw=\"+document.getElementById(\"gateway\").value+\"&nm=\"+document.getElementById(\"netmask\").value+\"&dns=\"+document.getElementById(\"dns\").value+\"&rssithreshold=\"+document.getElementById(\"threshold\").value;";
message += "fetch(api);await new Promise(resolve => setTimeout(resolve, 1000));location.reload();}</script>";
httpd_resp_send_chunk(req, message.c_str(), strlen(message.c_str()));
return;
@@ -164,8 +167,6 @@ void SendHTTPResponse(httpd_req_t *req)
}
esp_err_t test_handler(httpd_req_t *req)
{
SendHTTPResponse(req);
@@ -182,7 +183,7 @@ esp_err_t reboot_handlerAP(httpd_req_t *req)
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update.");
doRebootOTA();
return ESP_OK;
};
}
esp_err_t config_ini_handler(httpd_req_t *req)
@@ -201,9 +202,10 @@ esp_err_t config_ini_handler(httpd_req_t *req)
std::string hn = ""; // hostname
std::string ip = "";
std::string gw = ""; // gateway
std::string nm = ""; // nm
std::string nm = ""; // netmask
std::string dns = "";
std::string rssi = "";
std::string rssithreshold = ""; //rssi threshold for WIFI roaming
std::string text = "";
if (httpd_req_get_url_query_str(req, _query, 400) == ESP_OK)
@@ -258,77 +260,106 @@ esp_err_t config_ini_handler(httpd_req_t *req)
dns = UrlDecode(std::string(_valuechar));
}
if (httpd_query_key_value(_query, "rssi", _valuechar, 30) == ESP_OK)
if (httpd_query_key_value(_query, "rssithreshold", _valuechar, 30) == ESP_OK)
{
ESP_LOGD(TAG, "rssi is found: %s", _valuechar);
rssi = UrlDecode(std::string(_valuechar));
ESP_LOGD(TAG, "rssithreshold is found: %s", _valuechar);
rssithreshold = UrlDecode(std::string(_valuechar));
}
};
}
FILE* configfilehandle = fopen(WLAN_CONFIG_FILE, "w");
text = ";++++++++++++++++++++++++++++++++++\n";
text += "; AI on the edge - WLAN configuration\n";
text += "; ssid: Name of WLAN network (mandatory), e.g. \"WLAN-SSID\"\n";
text += "; password: Password of WLAN network (mandatory), e.g. \"PASSWORD\"\n\n";
fputs(text.c_str(), configfilehandle);
if (ssid.length())
ssid = "ssid = \"" + ssid + "\"\n";
else
ssid = ";ssid = \"\"\n";
ssid = "ssid = \"\"\n";
fputs(ssid.c_str(), configfilehandle);
if (pwd.length())
pwd = "password = \"" + pwd + "\"\n";
else
pwd = ";password = \"\"\n";
pwd = "password = \"\"\n";
fputs(pwd.c_str(), configfilehandle);
text = "\n;++++++++++++++++++++++++++++++++++\n";
text += "; Hostname: Name of device in network\n";
text += "; This parameter can be configured via WebUI configuration\n";
text += "; Default: \"watermeter\", if nothing is configured\n\n";
fputs(text.c_str(), configfilehandle);
if (hn.length())
hn = "hostname = \"" + hn + "\"\n";
else
hn = ";hostname = \"\"\n";
hn = ";hostname = \"watermeter\"\n";
fputs(hn.c_str(), configfilehandle);
text = "\n;++++++++++++++++++++++++++++++++++\n";
text += "; Fixed IP: If you like to use fixed IP instead of DHCP (default), the following\n";
text += "; parameters needs to be configured: ip, gateway, netmask are mandatory, dns optional\n\n";
fputs(text.c_str(), configfilehandle);
if (ip.length())
ip = "ip = \"" + ip + "\"\n";
else
ip = ";ip = \"\"\n";
ip = ";ip = \"xxx.xxx.xxx.xxx\"\n";
fputs(ip.c_str(), configfilehandle);
if (gw.length())
gw = "gateway = \"" + gw + "\"\n";
else
gw = ";gateway = \"\"\n";
gw = ";gateway = \"xxx.xxx.xxx.xxx\"\n";
fputs(gw.c_str(), configfilehandle);
if (nm.length())
nm = "netmask = \"" + nm + "\"\n";
else
nm = ";netmask = \"\"\n";
nm = ";netmask = \"xxx.xxx.xxx.xxx\"\n";
fputs(nm.c_str(), configfilehandle);
text = "\n;++++++++++++++++++++++++++++++++++\n";
text += "; DNS server (optional, if no DNS is configured, gateway address will be used)\n\n";
fputs(text.c_str(), configfilehandle);
if (dns.length())
dns = "dns = \"" + dns + "\"\n";
else
dns = ";dns = \"\"\n";
dns = ";dns = \"xxx.xxx.xxx.xxx\"\n";
fputs(dns.c_str(), configfilehandle);
if (rssi.length())
rssi = "RSSIThreshold = \"" + rssi + "\"\n";
text = "\n;++++++++++++++++++++++++++++++++++\n";
text += "; WIFI Roaming:\n";
text += "; Network assisted roaming protocol is activated by default\n";
text += "; AP / mesh system needs to support roaming protocol 802.11k/v\n";
text += ";\n";
text += "; Optional feature (usually not neccessary):\n";
text += "; RSSI Threshold for client requested roaming query (RSSI < RSSIThreshold)\n";
text += "; Note: This parameter can be configured via WebUI configuration\n";
text += "; Default: 0 = Disable client requested roaming query\n\n";
fputs(text.c_str(), configfilehandle);
if (rssithreshold.length())
rssithreshold = "RSSIThreshold = " + rssithreshold + "\n";
else
rssi = ";rssi = \"\"\n";
fputs(rssi.c_str(), configfilehandle);
rssithreshold = "RSSIThreshold = 0\n";
fputs(rssithreshold.c_str(), configfilehandle);
fflush(configfilehandle);
fclose(configfilehandle);
std::string zw = "ota without parameter - should not be the case!";
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
httpd_resp_send_chunk(req, NULL, 0);
ESP_LOGE(TAG, "end config.ini");
httpd_resp_send(req, zw.c_str(), zw.length());
ESP_LOGD(TAG, "end config.ini");
return ESP_OK;
};
}
esp_err_t upload_post_handlerAP(httpd_req_t *req)
@@ -470,21 +501,28 @@ httpd_handle_t start_webserverAP(void)
return NULL;
}
void CheckStartAPMode()
{
isConfigINI = FileExists(CONFIG_FILE);
isWlanINI = FileExists(WLAN_CONFIG_FILE);
if (!isConfigINI or !isWlanINI)
if (!isConfigINI)
ESP_LOGW(TAG, "config.ini not found!");
if (!isWlanINI)
ESP_LOGW(TAG, "wlan.ini not found!");
if (!isConfigINI || !isWlanINI)
{
ESP_LOGI(TAG, "Starting access point for remote configuration");
StatusLED(AP_OR_OTA, 2, true);
wifi_init_softAP();
start_webserverAP();
while(1) { // wait until reboot within task_do_Update_ZIP
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
}
#endif //#ifdef ENABLE_SOFTAP