Files
AstroRotaxMonitor/RotaxMonitor/src/utils.cpp
T
Emanuele Trabattoni 7da58c8a49 Set time from browser
2026-04-12 14:40:58 +02:00

195 lines
6.5 KiB
C++

#include "utils.h"
#include "freertos_stats.h"
#include "sdkconfig.h"
#include "freertos/FreeRTOS.h"
#include "freertos/portable.h"
#include "esp_heap_caps.h"
#include "esp_system.h"
#include "esp_spi_flash.h"
#include "esp_partition.h"
#include "LittleFS.h"
#include <vector>
#include <algorithm>
#include <functional>
#define FREERTOS_TASK_NUMBER_MAX_NUM 256 // RunTime stats for how many Tasks to be stored
std::string printBits(uint32_t value)
{
std::string result;
for (int i = 31; i >= 0; i--)
{
// ottieni il singolo bit
result += ((value >> i) & 1) ? '1' : '0';
// aggiungi uno spazio ogni 8 bit, tranne dopo l'ultimo
if (i % 8 == 0 && i != 0)
{
result += ' ';
}
}
return result;
}
// ANSI colors
#define BAR_WIDTH 30
#define COLOR_RESET "\033[0m"
#define COLOR_RED "\033[31m"
#define COLOR_GREEN "\033[32m"
#define COLOR_BLUE "\033[34m"
#define COLOR_MAGENTA "\033[35m"
#define COLOR_CYAN "\033[36m"
#define COLOR_YELLOW "\033[33m"
#define COLOR_WHITE "\033[37m"
#define COLOR_LBLUE "\033[94m"
void printBar(Print &printer, const char *label, size_t used, size_t total, const char *color)
{
float perc = total > 0 ? ((float)used / total) : 0;
int filled = perc * BAR_WIDTH;
printer.printf("%s%-12s [" COLOR_RESET, color, label);
for (int i = 0; i < BAR_WIDTH; i++)
{
if (i < filled)
printer.printf("%s#%s", color, COLOR_RESET);
else
printer.printf("-");
}
printer.printf("] %s%6.2f%%%s (%5.3f/%5.3f)MB\n",
color,
perc * 100.0,
COLOR_RESET,
(used / 1024.0f / 1024.0f),
(total / 1024.0f / 1024.0f));
}
void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t &a, const TaskStatus_t &b)> orderBy)
{
static const char *taskStates[] = {"Running", "Ready", "Blocked", "Suspended", "Deleted", "Invalid"};
static uint32_t ulRunTimeCounters[FREERTOS_TASK_NUMBER_MAX_NUM];
static uint32_t ulLastRunTime = 0;
uint32_t ulCurrentRunTime = 0, ulTaskRunTime = 0;
uint32_t ulTotalRunTime = 0;
std::vector<TaskStatus_t> pxTaskStatusArray;
UBaseType_t uxArraySize = 0;
// Take a snapshot of the number of tasks in case it changes while this function is executing.
uxArraySize = uxTaskGetNumberOfTasks();
pxTaskStatusArray.resize(uxArraySize);
// Generate raw status information about each task.
uxArraySize = uxTaskGetSystemState(pxTaskStatusArray.data(), uxArraySize, &ulTotalRunTime);
if (orderBy == nullptr)
std::sort(pxTaskStatusArray.begin(), pxTaskStatusArray.end(), [](const TaskStatus_t &a, const TaskStatus_t &b)
{ return a.xTaskNumber < b.xTaskNumber; });
else
std::sort(pxTaskStatusArray.begin(), pxTaskStatusArray.end(), orderBy);
// Compute system total runtime
ulCurrentRunTime = ulTotalRunTime - ulLastRunTime;
ulLastRunTime = ulTotalRunTime;
// PRINT MEMORY INFO
printer.printf("\033[H");
printer.printf(COLOR_LBLUE "=================== ESP32 SYSTEM MONITOR ===================\n" COLOR_RESET);
std::string buffer;
time_t now = time(nullptr);
struct tm *t = localtime(&now);
buffer.resize(64);
strftime(buffer.data(), sizeof(buffer), "%Y-%m-%d %H:%M:%S", t);
printer.printf(COLOR_YELLOW "=============== Datetime: %s ===============\n\n" COLOR_RESET, buffer.c_str());
// ===== HEAP =====
size_t freeHeap = esp_get_free_heap_size();
size_t totalHeap = heap_caps_get_total_size(MALLOC_CAP_DEFAULT);
printBar(printer, "HEAP", totalHeap - freeHeap, totalHeap, COLOR_GREEN);
// ===== RAM INTERNA =====
size_t freeInternal = heap_caps_get_free_size(MALLOC_CAP_INTERNAL);
size_t totalInternal = heap_caps_get_total_size(MALLOC_CAP_INTERNAL);
printBar(printer, "INTERNAL", totalInternal - freeInternal, totalInternal, COLOR_BLUE);
// ===== PSRAM =====
size_t totalPsram = heap_caps_get_total_size(MALLOC_CAP_SPIRAM);
if (totalPsram > 0)
{
size_t freePsram = heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
printBar(printer, "PSRAM", totalPsram - freePsram, totalPsram, COLOR_MAGENTA);
}
printer.printf("\n");
// ===== FLASH APP (approssimato) =====
const esp_partition_t *app_partition =
esp_partition_find_first(ESP_PARTITION_TYPE_APP,
ESP_PARTITION_SUBTYPE_APP_FACTORY,
NULL);
if (app_partition)
{
size_t totalAPP = app_partition->size; // dimensione reale partizione
size_t sketchSize = ESP.getSketchSize();
printBar(printer, "FLASH APP", sketchSize, totalAPP, COLOR_CYAN);
}
else
{
printer.printf(COLOR_YELLOW "%-12s [NOT FOUND]\n" COLOR_RESET, "FLASH APP");
}
// ===== LITTLEFS (corretto con partition table) =====
const esp_partition_t *fs_partition =
esp_partition_find_first(ESP_PARTITION_TYPE_DATA,
ESP_PARTITION_SUBTYPE_DATA_LITTLEFS,
"littlefs");
if (fs_partition)
{
size_t totalFS = fs_partition->size; // dimensione reale partizione
size_t usedFS = LittleFS.usedBytes(); // spazio usato reale
printBar(printer, "LITTLEFS", usedFS, totalFS, COLOR_YELLOW);
}
else
{
printer.printf(COLOR_YELLOW "%-12s [NOT FOUND]\n" COLOR_RESET, "LITTLEFS");
}
// ===== MIN HEAP =====
size_t minHeap = esp_get_minimum_free_heap_size();
printer.printf("%s\nMin Heap Ever:%s %u KB\n\n", COLOR_RED, COLOR_RESET, minHeap / 1024);
// Print Runtime Information
printer.printf("Tasks: %u, Runtime: %lus, Period: %luus\r\n", uxArraySize, ulTotalRunTime / 1000000, ulCurrentRunTime);
// Print Task Headers
printer.printf("Num\t Name\tLoad\tPrio\t Free\tCore\tState\r\n");
for (const auto &task : pxTaskStatusArray)
{
ulTaskRunTime = (task.ulRunTimeCounter - ulRunTimeCounters[task.xTaskNumber]);
ulRunTimeCounters[task.xTaskNumber] = task.ulRunTimeCounter;
ulTaskRunTime = (ulTaskRunTime * 100) / ulCurrentRunTime; // in percentage
printer.printf(
"%3u\t%16s"
"\t%3lu%%"
"\t%4u\t%5lu"
"\t%4c"
"\t%s\r\n",
task.xTaskNumber, task.pcTaskName,
ulTaskRunTime,
task.uxCurrentPriority, task.usStackHighWaterMark,
(task.xCoreID == tskNO_AFFINITY) ? '*' : ('0' + task.xCoreID),
taskStates[task.eCurrentState]);
}
printer.println();
}