#include "SystemInfo.h" #include "freertos/task.h" #include "esp_log.h" #include "esp_flash.h" #include "esp_mac.h" #include "esp_chip_info.h" #include "esp_system.h" #include "esp_partition.h" #include "esp_app_desc.h" #include "esp_psram.h" #include "esp_wifi.h" #include "esp_ota_ops.h" #define TAG "SystemInfo" size_t SystemInfo::GetFlashSize() { uint32_t flash_size; if (esp_flash_get_size(NULL, &flash_size) != ESP_OK) { ESP_LOGE(TAG, "Failed to get flash size"); return 0; } return (size_t)flash_size; } size_t SystemInfo::GetMinimumFreeHeapSize() { return esp_get_minimum_free_heap_size(); } size_t SystemInfo::GetFreeHeapSize() { return esp_get_free_heap_size(); } std::string SystemInfo::GetMacAddress() { uint8_t mac[6]; esp_read_mac(mac, ESP_MAC_WIFI_STA); char mac_str[18]; snprintf(mac_str, sizeof(mac_str), "%02x:%02x:%02x:%02x:%02x:%02x", mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]); return std::string(mac_str); } std::string SystemInfo::GetChipModelName() { return std::string(CONFIG_IDF_TARGET); } std::string SystemInfo::GetJsonString() { /* { "flash_size": 4194304, "psram_size": 0, "minimum_free_heap_size": 123456, "mac_address": "00:00:00:00:00:00", "chip_model_name": "esp32s3", "chip_info": { "model": 1, "cores": 2, "revision": 0, "features": 0 }, "application": { "name": "my-app", "version": "1.0.0", "compile_time": "2021-01-01T00:00:00Z" "idf_version": "4.2-dev" "elf_sha256": "" }, "partition_table": [ "app": { "label": "app", "type": 1, "subtype": 2, "address": 0x10000, "size": 0x100000 } ], "ota": { "label": "ota_0" } } */ std::string json = "{"; json += "\"flash_size\":" + std::to_string(GetFlashSize()) + ","; json += "\"psram_size\":" + std::to_string(esp_psram_get_size()) + ","; json += "\"minimum_free_heap_size\":" + std::to_string(GetMinimumFreeHeapSize()) + ","; json += "\"mac_address\":\"" + GetMacAddress() + "\","; json += "\"chip_model_name\":\"" + GetChipModelName() + "\","; json += "\"chip_info\":{"; esp_chip_info_t chip_info; esp_chip_info(&chip_info); json += "\"model\":" + std::to_string(chip_info.model) + ","; json += "\"cores\":" + std::to_string(chip_info.cores) + ","; json += "\"revision\":" + std::to_string(chip_info.revision) + ","; json += "\"features\":" + std::to_string(chip_info.features); json += "},"; json += "\"application\":{"; auto app_desc = esp_app_get_description(); json += "\"name\":\"" + std::string(app_desc->project_name) + "\","; json += "\"version\":\"" + std::string(app_desc->version) + "\","; json += "\"compile_time\":\"" + std::string(app_desc->date) + "T" + std::string(app_desc->time) + "Z\","; json += "\"idf_version\":\"" + std::string(app_desc->idf_ver) + "\","; char sha256_str[65]; for (int i = 0; i < 32; i++) { snprintf(sha256_str + i * 2, sizeof(sha256_str) - i * 2, "%02x", app_desc->app_elf_sha256[i]); } json += "\"elf_sha256\":\"" + std::string(sha256_str) + "\""; json += "},"; json += "\"partition_table\": ["; esp_partition_iterator_t it = esp_partition_find(ESP_PARTITION_TYPE_ANY, ESP_PARTITION_SUBTYPE_ANY, NULL); while (it) { const esp_partition_t *partition = esp_partition_get(it); json += "{"; json += "\"label\":\"" + std::string(partition->label) + "\","; json += "\"type\":" + std::to_string(partition->type) + ","; json += "\"subtype\":" + std::to_string(partition->subtype) + ","; json += "\"address\":" + std::to_string(partition->address) + ","; json += "\"size\":" + std::to_string(partition->size); json += "},"; it = esp_partition_next(it); } json.pop_back(); // Remove the last comma json += "],"; json += "\"ota\":{"; auto ota_partition = esp_ota_get_running_partition(); json += "\"label\":\"" + std::string(ota_partition->label) + "\""; json += "}"; // Close the JSON object json += "}"; return json; } esp_err_t SystemInfo::PrintRealTimeStats(TickType_t xTicksToWait) { #define ARRAY_SIZE_OFFSET 5 TaskStatus_t *start_array = NULL, *end_array = NULL; UBaseType_t start_array_size, end_array_size; configRUN_TIME_COUNTER_TYPE start_run_time, end_run_time; esp_err_t ret; uint32_t total_elapsed_time; //Allocate array to store current task states start_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET; start_array = (TaskStatus_t*)malloc(sizeof(TaskStatus_t) * start_array_size); if (start_array == NULL) { ret = ESP_ERR_NO_MEM; goto exit; } //Get current task states start_array_size = uxTaskGetSystemState(start_array, start_array_size, &start_run_time); if (start_array_size == 0) { ret = ESP_ERR_INVALID_SIZE; goto exit; } vTaskDelay(xTicksToWait); //Allocate array to store tasks states post delay end_array_size = uxTaskGetNumberOfTasks() + ARRAY_SIZE_OFFSET; end_array = (TaskStatus_t*)malloc(sizeof(TaskStatus_t) * end_array_size); if (end_array == NULL) { ret = ESP_ERR_NO_MEM; goto exit; } //Get post delay task states end_array_size = uxTaskGetSystemState(end_array, end_array_size, &end_run_time); if (end_array_size == 0) { ret = ESP_ERR_INVALID_SIZE; goto exit; } //Calculate total_elapsed_time in units of run time stats clock period. total_elapsed_time = (end_run_time - start_run_time); if (total_elapsed_time == 0) { ret = ESP_ERR_INVALID_STATE; goto exit; } printf("| Task | Run Time | Percentage\n"); //Match each task in start_array to those in the end_array for (int i = 0; i < start_array_size; i++) { int k = -1; for (int j = 0; j < end_array_size; j++) { if (start_array[i].xHandle == end_array[j].xHandle) { k = j; //Mark that task have been matched by overwriting their handles start_array[i].xHandle = NULL; end_array[j].xHandle = NULL; break; } } //Check if matching task found if (k >= 0) { uint32_t task_elapsed_time = end_array[k].ulRunTimeCounter - start_array[i].ulRunTimeCounter; uint32_t percentage_time = (task_elapsed_time * 100UL) / (total_elapsed_time * CONFIG_FREERTOS_NUMBER_OF_CORES); printf("| %-16s | %8lu | %4lu%%\n", start_array[i].pcTaskName, task_elapsed_time, percentage_time); } } //Print unmatched tasks for (int i = 0; i < start_array_size; i++) { if (start_array[i].xHandle != NULL) { printf("| %s | Deleted\n", start_array[i].pcTaskName); } } for (int i = 0; i < end_array_size; i++) { if (end_array[i].xHandle != NULL) { printf("| %s | Created\n", end_array[i].pcTaskName); } } ret = ESP_OK; exit: //Common return path free(start_array); free(end_array); return ret; }