| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- #include "sdkconfig.h"
- #include <iostream>
- #include <string>
- #include <vector>
- #include <regex>
- #include "esp_psram.h"
- #include "esp_pm.h"
- #include "psram.h"
- #include "esp_chip_info.h"
- #include "esp_vfs_fat.h"
- #include "ffconf.h"
- #include "driver/sdmmc_host.h"
- #include "defines.h"
- #include "Helper.h"
- #include "read_network_config.h"
- #include "network_init.h"
- #include "server_ota.h"
- #include "MainFlowControl.h"
- #include "ClassLogFile.h"
- #include "time_sntp.h"
- #include "statusled.h"
- #include "sdcard_check.h"
- #ifdef DISABLE_BROWNOUT_DETECTOR
- #include "soc/soc.h"
- #include "soc/rtc_cntl_reg.h"
- #endif
- extern const char *GIT_TAG;
- extern const char *GIT_REV;
- extern const char *GIT_BRANCH;
- extern const char *BUILD_TIME;
- extern std::string getFwVersion(void);
- extern std::string getHTMLversion(void);
- extern std::string getHTMLcommit(void);
- bool setCpuFrequency(void);
- static const char *TAG = "MAIN";
- bool init_nvs_sd_card()
- {
- esp_err_t ret = nvs_flash_init();
- if (ret == ESP_ERR_NVS_NO_FREE_PAGES)
- {
- ESP_ERROR_CHECK(nvs_flash_erase());
- ret = nvs_flash_init();
- }
- ESP_LOGD(TAG, "Using SDMMC peripheral");
- sdmmc_host_t host = SDMMC_HOST_DEFAULT();
- host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
- // For SoCs where the SD power can be supplied both via an internal or external (e.g. on-board LDO) power supply.
- // When using specific IO pins (which can be used for ultra high-speed SDMMC) to connect to the SD card
- // and the internal LDO power supply, we need to initialize the power supply first.
- #if SD_PWR_CTRL_LDO_INTERNAL_IO
- sd_pwr_ctrl_ldo_config_t ldo_config = {
- .ldo_chan_id = CONFIG_EXAMPLE_SD_PWR_CTRL_LDO_IO_ID,
- };
- sd_pwr_ctrl_handle_t pwr_ctrl_handle = NULL;
- ret = sd_pwr_ctrl_new_on_chip_ldo(&ldo_config, &pwr_ctrl_handle);
- if (ret != ESP_OK)
- {
- ESP_LOGE(TAG, "Failed to create a new on-chip LDO power control driver");
- return false;
- }
- host.pwr_ctrl_handle = pwr_ctrl_handle;
- #endif
- // This initializes the slot without card detect (CD) and write protect (WP) signals.
- // Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
- #ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
- sdmmc_slot_config_t slot_config = {
- .cd = SDMMC_SLOT_NO_CD,
- .wp = SDMMC_SLOT_NO_WP,
- };
- #else
- sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
- #endif
- // Set bus width to use:
- #ifdef __SD_USE_ONE_LINE_MODE__
- slot_config.width = 1;
- #ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
- slot_config.clk = GPIO_SDCARD_CLK;
- slot_config.cmd = GPIO_SDCARD_CMD;
- slot_config.d0 = GPIO_SDCARD_D0;
- #endif // end CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
- #else // else __SD_USE_ONE_LINE_MODE__
- slot_config.width = 4;
- #ifdef CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
- slot_config.d1 = GPIO_SDCARD_D1;
- slot_config.d2 = GPIO_SDCARD_D2;
- slot_config.d3 = GPIO_SDCARD_D3;
- #endif // end CONFIG_SOC_SDMMC_USE_GPIO_MATRIX
- #endif // end __SD_USE_ONE_LINE_MODE__
- // Enable internal pullups on enabled pins. The internal pullups
- // are insufficient however, please make sure 10k external pullups are
- // connected on the bus. This is for debug / example purpose only.
- slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
- // Der PullUp des GPIO13 wird durch slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
- // nicht gesetzt, da er eigentlich nicht benötigt wird,
- // dies führt jedoch bei schlechten Kopien des AI_THINKER Boards
- // zu Problemen mit der SD Initialisierung und eventuell sogar zur reboot-loops.
- // Um diese Probleme zu kompensieren, wird der PullUp manuel gesetzt.
- gpio_set_pull_mode(GPIO_SDCARD_D3, GPIO_PULLUP_ONLY); // HS2_D3
- // Options for mounting the filesystem.
- // If format_if_mount_failed is set to true, SD card will be partitioned and
- // formatted in case when mounting fails.
- esp_vfs_fat_sdmmc_mount_config_t mount_config = {
- .format_if_mount_failed = false,
- .max_files = 12, // previously -> 2022-09-21: 5, 2023-01-02: 7
- .allocation_unit_size = 0, // 0 = auto
- .disk_status_check_enable = 0,
- };
- sdmmc_card_t *card;
- const char mount_point[] = MOUNT_POINT;
- // 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.
- ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
- if (ret != ESP_OK)
- {
- if (ret == ESP_FAIL)
- {
- ESP_LOGE(TAG, "Failed to mount FAT filesystem on SD card. Check SD card filesystem (only FAT supported) or try another card");
- set_status_led(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");
- set_status_led(SDCARD_INIT, 2, true);
- }
- else
- {
- ESP_LOGE(TAG, "SD card init failed. Check error code or try another card");
- set_status_led(SDCARD_INIT, 3, true);
- }
- return false;
- }
- // sdmmc_card_print_info(stdout, card); // With activated CONFIG_NEWLIB_NANO_FORMAT --> capacity not printed correctly anymore
- save_sd_card_info(card);
- return true;
- }
- esp_err_t init_psram(void)
- {
- // Init external PSRAM
- // ********************************************
- esp_err_t result = esp_psram_init();
- if (result == ESP_FAIL)
- {
- // ESP_FAIL -> Failed to init PSRAM
- ESP_LOGE(TAG, "PSRAM init failed (%s)! PSRAM not found or defective", std::to_string(result).c_str());
- set_system_statusflag(SYSTEM_STATUS_PSRAM_BAD);
- set_status_led(PSRAM_INIT, 1, true);
- return ESP_FAIL;
- }
- else
- {
- // ESP_OK -> PSRAM init OK --> continue to check PSRAM size
- size_t psram_size = esp_psram_get_size();
- ESP_LOGI(TAG, "PSRAM size: %s byte (%s MB / %s MBit)", std::to_string(psram_size).c_str(), std::to_string(psram_size / 1024 / 1024).c_str(), std::to_string(psram_size / 1024 / 1024 * 8).c_str());
- // Check PSRAM size
- // ********************************************
- if (psram_size < (4 * 1024 * 1024))
- {
- // PSRAM is below 4 MBytes (32Mbit)
- ESP_LOGE(TAG, "PSRAM size >= 4MB (32Mbit) is mandatory to run this application");
- set_system_statusflag(SYSTEM_STATUS_PSRAM_BAD);
- set_status_led(PSRAM_INIT, 2, true);
- return ESP_FAIL;
- }
- else
- {
- // PSRAM size OK --> continue to check heap size
- size_t _hsize = get_heapsize();
- ESP_LOGI(TAG, "Total heap: %s byte", std::to_string(_hsize).c_str());
- // 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");
- set_system_statusflag(SYSTEM_STATUS_HEAP_TOO_SMALL);
- set_status_led(PSRAM_INIT, 3, true);
- return ESP_FAIL;
- }
- else
- {
- // HEAP size OK --> continue to reserve shared memory block and check camera init
- // Allocate static PSRAM memory regions
- if (reserve_psram_shared_region() == false)
- {
- ESP_LOGI(TAG, "Allocate static PSRAM memory regions failed, heap too small!");
- set_system_statusflag(SYSTEM_STATUS_HEAP_TOO_SMALL);
- set_status_led(PSRAM_INIT, 3, true);
- return ESP_FAIL;
- }
- else
- {
- ESP_LOGI(TAG, "Allocate static PSRAM memory regions ok");
- return ESP_OK;
- }
- }
- }
- }
- return ESP_OK;
- }
- esp_err_t init_camera(void)
- {
- Camera.set_flash_light_on_off(false);
- Camera.power_reset_camera();
- esp_err_t result = Camera.init_camera();
- // Check camera init
- // ********************************************
- if (result != ESP_OK)
- {
- // Camera init failed, retry to init
- char camStatusHex[33];
- sprintf(camStatusHex, "0x%02x", result);
- LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Camera init failed (" + std::string(camStatusHex) + "), retrying...");
- Camera.power_reset_camera();
- result = Camera.init_camera();
- Camera.set_flash_light_on_off(false);
- if (result != ESP_OK)
- {
- // Camera init failed again
- sprintf(camStatusHex, "0x%02x", result);
- LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera init failed (" + std::string(camStatusHex) + ")! Check camera module and/or proper electrical connection");
- set_system_statusflag(SYSTEM_STATUS_CAM_BAD);
- Camera.set_flash_light_on_off(false); // make sure flashlight is off
- set_status_led(CAM_INIT, 1, true);
- return ESP_FAIL;
- }
- }
- Camera.set_flash_light_on_off(false); // make sure flashlight is off before start of flow
- // Print camera infos
- // ********************************************
- char caminfo[50];
- sensor_t *sensor = esp_camera_sensor_get();
- sprintf(caminfo, "PID: 0x%02x, VER: 0x%02x, MIDL: 0x%02x, MIDH: 0x%02x", sensor->id.PID, sensor->id.VER, sensor->id.MIDH, sensor->id.MIDL);
- LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Camera info: " + std::string(caminfo));
- return ESP_OK;
- }
- extern "C" void app_main(void)
- {
- #ifdef DISABLE_BROWNOUT_DETECTOR
- WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); // disable brownout detector
- #endif
- #if (defined(BOARD_ESP32_S3_ETH_V1) || defined(BOARD_ESP32_S3_ETH_V2))
- // Configure IO Pad as General Purpose IO,
- // so that it can be connected to internal Matrix,
- // then combined with one or more peripheral signals.
- gpio_pad_select_gpio(PER_ENABLE);
- gpio_set_direction(PER_ENABLE, GPIO_MODE_OUTPUT);
- gpio_set_level(PER_ENABLE, 1);
- #endif
- // ********************************************
- // Highlight start of app_main
- // ********************************************
- ESP_LOGI(TAG, "\n\n\n\n================ Start app_main =================");
- // Init SD card
- // ********************************************
- if (!init_nvs_sd_card())
- {
- ESP_LOGE(TAG, "!!! Device init aborted at step: init_nvs_sd_card() !!!");
- set_system_statusflag(SYSTEM_STATUS_SDCARD_CHECK_BAD);
- vTaskDelay(2000 / portTICK_PERIOD_MS);
- return; // No way to continue without working SD card!
- }
- // Init external PSRAM
- // ********************************************
- if (init_psram() != ESP_OK)
- {
- ESP_LOGE(TAG, "!!! Device init aborted at step: init_psram() !!!");
- set_system_statusflag(SYSTEM_STATUS_PSRAM_BAD);
- vTaskDelay(2000 / portTICK_PERIOD_MS);
- return; // No way to continue without working PSRAM!
- }
- // SD card: basic R/W check
- // ********************************************
- int iSDCardStatus = SDCardCheckRW();
- if (iSDCardStatus < 0)
- {
- if (iSDCardStatus <= -1 && iSDCardStatus >= -2)
- {
- // write error
- set_status_led(SDCARD_CHECK, 1, true);
- }
- else if (iSDCardStatus <= -3 && iSDCardStatus >= -5)
- {
- // read error
- set_status_led(SDCARD_CHECK, 2, true);
- }
- else if (iSDCardStatus == -6)
- {
- // delete error
- set_status_led(SDCARD_CHECK, 3, true);
- }
- ESP_LOGE(TAG, "!!! Device init aborted at step: SDCardCheckRW() !!!");
- set_system_statusflag(SYSTEM_STATUS_SDCARD_CHECK_BAD);
- vTaskDelay(2000 / portTICK_PERIOD_MS);
- return; // No way to continue without working SD card!
- }
- // SD card: Create log directories (if not already existing)
- // ********************************************
- LogFile.CreateLogDirectories(); // mandatory for logging + image saving
- // SD card: Create further mandatory directories (if not already existing)
- // Correct creation of these folders will be checked with function "SDCardCheckFolderFilePresence"
- // ********************************************
- make_dir("/sdcard/firmware"); // mandatory for OTA firmware update
- make_dir("/sdcard/img_tmp"); // mandatory for setting up alignment marks
- make_dir("/sdcard/demo"); // mandatory for demo mode
- make_dir("/sdcard/config/certs"); // mandatory for mqtt certificates
- // SD card: Check presence of some mandatory folders / files
- // ********************************************
- if (!SDCardCheckFolderFilePresence())
- {
- set_status_led(SDCARD_CHECK, 4, true);
- set_system_statusflag(SYSTEM_STATUS_FOLDER_CHECK_BAD); // reduced web interface going to be loaded
- }
- // ********************************************
- // 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, "=================================================");
- // Check for updates
- // ********************************************
- ESP_LOGI(TAG, "check for updates");
- CheckOTAUpdateStatus();
- if (!CheckOTAUpdateAvailability())
- {
- // Check reboot reason
- // ********************************************
- ESP_LOGI(TAG, "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: " + get_reset_reason());
- 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: " + get_reset_reason());
- }
- // Set CPU Frequency
- // ********************************************
- ESP_LOGI(TAG, "set CPU Frequency");
- setCpuFrequency();
- #ifdef CONFIG_SOC_TEMP_SENSOR_SUPPORTED
- ESP_LOGI(TAG, "init Tempsensor");
- init_tempsensor();
- #endif
- // Init camera
- // ********************************************
- ESP_LOGI(TAG, "init camera");
- if (init_camera() != ESP_OK)
- {
- LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "!!! Error at step: init_camera() !!!");
- }
- // Check version information
- // ********************************************
- ESP_LOGI(TAG, "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
- versionFormated = "Tag: '" + std::string(GIT_TAG) + "', " + versionFormated;
- }
- LogFile.WriteToFile(ESP_LOG_INFO, TAG, versionFormated);
- 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, "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");
- }
- // Start webserver + register handler
- // ********************************************
- ESP_LOGI(TAG, "starting Webserver");
- if (init_network() != ESP_OK)
- {
- LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Webserver init failed. Device init aborted!");
- set_status_led(WLAN_INIT, 3, true);
- return;
- }
- // Set log level for wifi component to WARN level (default: INFO; only relevant for serial console)
- // ********************************************
- esp_log_level_set("wifi", ESP_LOG_WARN);
- // Init time (as early as possible, but SD card needs to be initialized)
- // ********************************************
- if (network_config.connection_type != NETWORK_CONNECTION_DISCONNECT)
- {
- ESP_LOGI(TAG, "setup Time");
- setupTime(); // NTP time service: Status of time synchronization will be checked after every round (server_tflite.cpp)
- }
- TickType_t xDelay = 2000 / portTICK_PERIOD_MS;
- ESP_LOGD(TAG, "main: sleep for: %ldms", (long)xDelay * CONFIG_FREERTOS_HZ / portTICK_PERIOD_MS);
- vTaskDelay(xDelay);
- // manual reset the time
- // ********************************************
- if (network_config.connection_type != NETWORK_CONNECTION_DISCONNECT)
- {
- ESP_LOGI(TAG, "manual reset the time");
- if (!time_manual_reset_sync())
- {
- LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Manual Time Sync failed during startup");
- }
- }
- // Print Device info
- // ********************************************
- ESP_LOGI(TAG, "print Device info");
- esp_chip_info_t chipInfo;
- esp_chip_info(&chipInfo);
- LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Device info: 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: " + get_sd_card_name() + ", Capacity: " + get_sd_card_capacity() + "MB, Free: " + get_sd_card_free_partition_space() + "MB");
- xDelay = 2000 / portTICK_PERIOD_MS;
- ESP_LOGD(TAG, "main: sleep for: %ldms", (long)xDelay * CONFIG_FREERTOS_HZ / portTICK_PERIOD_MS);
- vTaskDelay(xDelay);
- // Check main init + start TFlite task
- // ********************************************
- ESP_LOGI(TAG, "check main init");
- if (get_system_status() == 0)
- {
- // No error flag is set
- LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Initialization completed successfully");
- InitializeFlowTask();
- }
- else if (is_set_system_statusflag(SYSTEM_STATUS_CAM_FB_BAD) || is_set_system_statusflag(SYSTEM_STATUS_NTP_BAD))
- {
- // Non critical errors occured, we try to continue...
- LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Initialization completed with non-critical errors!");
- InitializeFlowTask();
- }
- 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. Loading reduced web interface...");
- }
- }
- }
- bool setCpuFrequency(void)
- {
- FILE *pFile = fopen(CONFIG_FILE, "r");
- if (pFile == NULL)
- {
- LogFile.WriteToFile(ESP_LOG_WARN, TAG, "No ConfigFile defined - exit setCpuFrequency()!");
- return false;
- }
- ClassFlow classFlow;
- std::string aktparamgraph = "";
- while (classFlow.GetNextParagraph(pFile, aktparamgraph))
- {
- if ((to_upper(aktparamgraph).compare("[SYSTEM]") == 0) || (to_upper(aktparamgraph).compare(";[SYSTEM]") == 0))
- {
- break;
- }
- }
- if ((to_upper(aktparamgraph).compare("[SYSTEM]") != 0) && (to_upper(aktparamgraph).compare(";[SYSTEM]") != 0))
- {
- fclose(pFile);
- return false;
- }
- string cpuFrequency = "160";
- esp_pm_config_t pm_config;
- std::vector<std::string> splitted;
- while (classFlow.getNextLine(pFile, &aktparamgraph) && !classFlow.isNewParagraph(aktparamgraph))
- {
- splitted = split_line(aktparamgraph);
- if (splitted.size() > 1)
- {
- std::string _param = to_upper(splitted[0]);
- if (_param == "CPUFREQUENCY")
- {
- cpuFrequency = splitted[1];
- }
- }
- }
- fclose(pFile);
- if (esp_pm_get_configuration(&pm_config) != ESP_OK)
- {
- LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read CPU Frequency!");
- return false;
- }
- if (cpuFrequency == "160")
- {
- // 160 is the default
- // No change needed
- }
- else if (cpuFrequency == "240")
- {
- pm_config.max_freq_mhz = 240;
- pm_config.min_freq_mhz = pm_config.max_freq_mhz;
-
- if (esp_pm_configure(&pm_config) != ESP_OK)
- {
- LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to set new CPU frequency!");
- return false;
- }
- }
- else
- {
- LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unknown CPU frequency: " + cpuFrequency + "! It must be 160 or 240!");
- return false;
- }
- if (esp_pm_get_configuration(&pm_config) == ESP_OK)
- {
- LogFile.WriteToFile(ESP_LOG_INFO, TAG, string("CPU frequency: ") + to_string(pm_config.max_freq_mhz) + " MHz");
- }
- return true;
- }
|