task refactoring working, sometimes misses events, check priorities

This commit is contained in:
2026-04-12 01:45:32 +02:00
parent fdba6d5ad5
commit 095aa59f36
8 changed files with 202 additions and 52 deletions

View File

@@ -37,7 +37,7 @@ public:
struct color_t
{
uint8_t a, g, r, b;
uint8_t a, r, g, b;
};
union color_u

View File

@@ -64,7 +64,7 @@ build_flags =
-DARDUINO_USB_MODE=0
-DCONFIG_ASYNC_TCP_MAX_ACK_TIME=5000
-DCONFIG_ASYNC_TCP_PRIORITY=21
-DCONFIG_ASYNC_TCP_QUEUE_SIZE=64
-DCONFIG_ASYNC_TCP_QUEUE_SIZE=128
-DCONFIG_ASYNC_TCP_RUNNING_CORE=1
-DCONFIG_ASYNC_TCP_STACK_SIZE=4096
-DCONFIG_ASYNC_TCP_STACK_SIZE=8192
-fstack-protector-all

View File

@@ -17,7 +17,7 @@
#define CORE_0 0
#define CORE_1 1
#define RT_TASK_STACK 2048 // in words
#define RT_TASK_PRIORITY (configMAX_PRIORITIES - 6) // highest priority after wifi tasks
#define RT_TASK_PRIORITY (configMAX_PRIORITIES - 5) // highest priority after wifi tasks
struct isrParams
{

View File

@@ -31,7 +31,7 @@ void setup()
// Setup Logger
LOG_ATTACH_SERIAL(Serial);
LOG_SET_LEVEL(DebugLogLevel::LVL_INFO);
LOG_SET_LEVEL(DebugLogLevel::LVL_DEBUG);
// Print Processor Info
LOG_DEBUG("ESP32 Chip:", ESP.getChipModel());
@@ -82,19 +82,20 @@ void loop()
led.setStatus(RGBled::LedStatus::INIT);
bool running = true;
std::mutex fs_mutex;
LITTLEFSGuard fsGuard;
//////// INIT SPI PORTS ////////
bool spiA_ok = true;
bool spiB_ok = true;
// Init 2 SPI interfaces
SPIClass SPI_A(FSPI);
spiA_ok = SPI_A.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI);
SPI_A.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1
#ifdef CH_B_ENABLE
SPIClass SPI_B(HSPI);
spiB_ok = SPI_B.begin(SPI_B_SCK, SPI_B_MISO, SPI_B_MOSI);
SPI_B.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1
#endif
// SPIClass SPI_A(FSPI);
// spiA_ok = SPI_A.begin(SPI_A_SCK, SPI_A_MISO, SPI_A_MOSI);
// SPI_A.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1
// #ifdef CH_B_ENABLE
// SPIClass SPI_B(HSPI);
// spiB_ok = SPI_B.begin(SPI_B_SCK, SPI_B_MISO, SPI_B_MOSI);
// SPI_B.setDataMode(SPI_MODE1); // ADS1256 requires SPI mode 1
// #endif
if (!spiA_ok || !spiB_ok)
{
LOG_ERROR("Unable to Initialize SPI Busses");
@@ -106,20 +107,20 @@ void loop()
// Resources Initialization
std::shared_ptr<Devices> dev = std::make_shared<Devices>();
dev->m_spi_a = std::make_unique<SPIClass>(SPI_A);
dev->m_spi_b = std::make_unique<SPIClass>(SPI_B);
// dev->m_spi_a = std::make_unique<SPIClass>(SPI_A);
// dev->m_spi_b = std::make_unique<SPIClass>(SPI_B);
// Init ADC_A
dev->m_adc_a = std::make_unique<ADS1256>(ADC_A_DRDY, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, ADC_A_CS, 2.5, &SPI_A);
dev->m_adc_b = std::make_unique<ADS1256>(ADC_B_DRDY, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, ADC_B_CS, 2.5, &SPI_B);
// // Init ADC_A
// dev->m_adc_a = std::make_unique<ADS1256>(ADC_A_DRDY, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, ADC_A_CS, 2.5, &SPI_A);
// dev->m_adc_b = std::make_unique<ADS1256>(ADC_B_DRDY, ADS1256::PIN_UNUSED, ADS1256::PIN_UNUSED, ADC_B_CS, 2.5, &SPI_B);
dev->m_adc_a->InitializeADC();
dev->m_adc_a->setPGA(PGA_1);
dev->m_adc_a->setDRATE(DRATE_7500SPS);
// dev->m_adc_a->InitializeADC();
// dev->m_adc_a->setPGA(PGA_1);
// dev->m_adc_a->setDRATE(DRATE_7500SPS);
dev->m_adc_b->InitializeADC();
dev->m_adc_b->setPGA(PGA_1);
dev->m_adc_b->setDRATE(DRATE_7500SPS);
// dev->m_adc_b->InitializeADC();
// dev->m_adc_b->setPGA(PGA_1);
// dev->m_adc_b->setDRATE(DRATE_7500SPS);
const rtIgnitionTask::rtTaskParams taskA_params{
.rt_running = true,
@@ -183,8 +184,9 @@ void loop()
.rt_queue = nullptr,
.dev = dev};
auto task_A = rtIgnitionTask(taskA_params, 1024, 128, CORE_0, fs_mutex);
auto task_B = rtIgnitionTask(taskA_params, 1024, 128, CORE_1, fs_mutex);
auto task_A = rtIgnitionTask(taskA_params, 4096, 256, CORE_1, fs_mutex);
delay(50);
auto task_B = rtIgnitionTask(taskB_params, 4096, 256, CORE_1, fs_mutex);
// Ignition A on Core 0
auto ignA_task_success = task_A.getStatus() == rtIgnitionTask::OK ? pdPASS : pdFAIL;
@@ -197,23 +199,43 @@ void loop()
esp_restart();
}
const bool tasK_A_rt = task_A.start();
delay(50);
const bool task_B_rt = task_B.start();
if (tasK_A_rt != true || task_B_rt != true)
{
led.setStatus(RGBled::LedStatus::ERROR);
LOG_ERROR("Unable to start realtime tasks");
} else
LOG_DEBUG("Real Time Tasks A & B initialized");
led.setStatus(RGBled::LedStatus::OK);
LITTLEFSGuard fsGuard;
WebPage webPage(80, LittleFS); // Initialize webserver and Websocket
task_A.onMessage([&webPage](ignitionBoxStatusFiltered sts){
ArduinoJson::JsonDocument doc;
doc["box_a"] = sts.toJson();
doc["box_b"] = ArduinoJson::JsonDocument();
webPage.sendWsData(doc.as<String>());
});
task_B.onMessage([&webPage](ignitionBoxStatusFiltered sts){
ArduinoJson::JsonDocument doc;
doc["box_a"] = ArduinoJson::JsonDocument();
doc["box_b"] = sts.toJson();
webPage.sendWsData(doc.as<String>());
});
task_A.enableSave(true, "ignitionA_test.csv");
task_B.enableSave(true, "ignitionB_test.csv");
uint32_t last_loop = millis();
//////////////// INNER LOOP /////////////////////
while (running)
{
led.setStatus(RGBled::LedStatus::IDLE);
delay(100);
if ((millis() - last_loop) > 1000)
if ((millis() - last_loop) > 2000)
{
clearScreen();
Serial.println();
printRunningTasksMod(Serial);
last_loop = millis();
}

View File

@@ -296,20 +296,22 @@ rtIgnitionTask::rtIgnitionTask(const rtTaskParams params, const uint32_t history
m_params.rt_queue = m_queue;
// create PSram history vectors
m_history_0.resize(history_size);
m_history_1.resize(history_size);
m_history_0 = PSHistory(history_size);
m_history_1 = PSHistory(history_size);
// assing active and writable history
m_active_history = std::unique_ptr<PSHistory>(&m_history_0);
m_save_history = std::unique_ptr<PSHistory>(&m_history_1);
LOG_WARN("Starting Manager for [", m_params.name.c_str(), "]");
auto task_success = xTaskCreate(
// auto task_success = pdPASS;
auto task_success = xTaskCreatePinnedToCore(
rtIgnitionTask_manager,
(std::string("man_") + m_params.name).c_str(),
m_params.rt_stack_size,
8192,
(void *)this,
1,
&m_manager_handle);
m_params.rt_priority >> 2,
&m_manager_handle,
m_core);
if (task_success != pdPASS)
{
@@ -341,10 +343,12 @@ void rtIgnitionTask::run()
if (new_data == pdPASS)
{
m_last_data = millis();
m_manager_status = rtTaskStatus::RUNNING;
// if history buffer is full swap buffers and if enabled save history buffer
if (m_counter_status >= m_active_history->size())
{
LOG_DEBUG("Save for Buffer Full: ", m_counter_status);
m_counter_status = 0;
m_partial_save = false; // reset partial save flag on new data cycle
std::swap(m_active_history, m_save_history);
@@ -356,13 +360,21 @@ void rtIgnitionTask::run()
m_info_filtered.update(m_last_status);
(*m_active_history)[m_counter_status] = m_last_status;
if (m_on_message_cb && m_counter_status % 10)
{
m_on_message_cb(m_info_filtered);
}
// update data counter
m_counter_status++;
}
else
{
if (millis() - m_last_data > c_idle_time){
if (m_counter_status > 0 && !m_partial_save){
if (millis() - m_last_data > c_idle_time)
{
if (m_counter_status > 0 && !m_partial_save)
{
LOG_DEBUG("Save Partial: ", m_counter_status);
m_active_history->resize(m_counter_status);
saveHistory(*m_active_history, m_history_path);
m_active_history->resize(m_max_history);
@@ -434,13 +446,18 @@ void rtIgnitionTask::enableSave(const bool enable, const std::filesystem::path f
}
}
void rtIgnitionTask::onMessage(std::function<void(ignitionBoxStatusFiltered)> callaback)
{
m_on_message_cb = callaback;
}
void rtIgnitionTask::saveHistory(const rtIgnitionTask::PSHistory &history, const std::filesystem::path &file_name)
{
// Lock filesystem mutex to avoid concurrent access
std::lock_guard<std::mutex> fs_lock(m_fs_mutex);
// Check for free space
if (LittleFS.totalBytes() - LittleFS.usedBytes() < history.size() * sizeof(ignitionBoxStatus) * 200) // check if at least 1MB is free for saving history
if (LittleFS.totalBytes() - LittleFS.usedBytes() < history.size() * sizeof(ignitionBoxStatus)) // check if at least 1MB is free for saving history
{
LOG_ERROR("Not enough space in SPIFFS to save history");
return;
@@ -454,9 +471,8 @@ void rtIgnitionTask::saveHistory(const rtIgnitionTask::PSHistory &history, const
// if firt save remove old file and create new
auto save_flags = std::ios::out;
if (m_first_save && m_filesystem.exists(file_path.c_str()))
if (m_first_save)
{
m_first_save = false;
save_flags |= std::ios::trunc; // overwrite existing file
m_filesystem.remove(file_path.c_str()); // ensure file is removed before saving to avoid issues with appending to existing file in SPIFFS
LOG_INFO("Saving history to Flash, new file:", file_path.c_str());
@@ -477,12 +493,12 @@ void rtIgnitionTask::saveHistory(const rtIgnitionTask::PSHistory &history, const
// write csv header
if (m_first_save)
{
ofs << "TS,\
EVENTS_12,DLY_12,STAT_12,V_12_1,V_12_2,V_12_3,V_12_4,IGNITION_MODE_12,\
EVENTS_34,DLY_34,STAT_34,V_34_1,V_34_2,V_34_3,V_34_4,IGNITION_MODE_34,\
ENGINE_RPM,ADC_READTIME,N_QUEUE_ERRORS"
ofs << "TS,EVENTS_12,DLY_12,STAT_12,V_12_1,V_12_2,V_12_3,V_12_4,IGNITION_MODE_12,"
<< "EVENTS_34,DLY_34,STAT_34,V_34_1,V_34_2,V_34_3,V_34_4,IGNITION_MODE_34,"
<< "ENGINE_RPM,ADC_READTIME,N_QUEUE_ERRORS"
<< std::endl;
ofs.flush();
m_first_save = false;
}
for (const auto &entry : history)

View File

@@ -14,6 +14,7 @@
#include <FS.h>
#include <LittleFS.h>
#include <datasave.h>
#include <functional>
// ISR
#include "isr.h"
@@ -111,6 +112,8 @@ public:
void enableSave(const bool enable, const std::filesystem::path filename);
void onMessage(std::function<void(ignitionBoxStatusFiltered)> callaback);
private:
void saveHistory(const rtIgnitionTask::PSHistory &history, const std::filesystem::path &file_name);
@@ -147,7 +150,9 @@ private:
ignitionBoxStatus m_last_status;
ignitionBoxStatusFiltered m_info_filtered;
static const uint32_t c_idle_time = 2000; // in mS
std::function<void(ignitionBoxStatusFiltered)> m_on_message_cb = nullptr;
static const uint32_t c_idle_time = 10000; // in mS
static const uint32_t c_spark_timeout_max = 500; // uS
static const uint8_t c_adc_time = 4; // in mS
static const uint8_t c_io_time = 2; // in mS

View File

@@ -5,25 +5,69 @@
#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 printBits(uint32_t value)
{
std::string result;
for (int i = 31; i >= 0; i--) {
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) {
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"};
@@ -53,6 +97,68 @@ void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t
ulCurrentRunTime = ulTotalRunTime - ulLastRunTime;
ulLastRunTime = ulTotalRunTime;
// PRINT MEMORY INFO
printer.printf("\033[H");
printer.printf(COLOR_LBLUE "=================== ESP32 SYSTEM MONITOR ===================\n\n" COLOR_RESET);
// ===== 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);
@@ -79,4 +185,3 @@ void printRunningTasksMod(Print &printer, std::function<bool(const TaskStatus_t
}
printer.println();
}

View File

@@ -2,6 +2,7 @@
WebPage::WebPage(const uint8_t port, fs::FS &filesystem) : m_port(port), m_webserver(AsyncWebServer(port)), m_websocket(AsyncWebSocket("/ws")), m_filesystem(filesystem)
{
LOG_DEBUG("Initializing Web Server");
m_websocket.onEvent([this](AsyncWebSocket *server, AsyncWebSocketClient *client,
AwsEventType type, void *arg, uint8_t *data, size_t len)
{ onWsEvent(server, client, type, arg, data, len); });
@@ -17,6 +18,7 @@ WebPage::WebPage(const uint8_t port, fs::FS &filesystem) : m_port(port), m_webse
);
m_webserver.begin();
LOG_DEBUG("Webserver Init OK");
}
WebPage::~WebPage()