diff --git a/RotaxMonitor/platformio.ini b/RotaxMonitor/platformio.ini index 41ef22d..c5d3aa7 100644 --- a/RotaxMonitor/platformio.ini +++ b/RotaxMonitor/platformio.ini @@ -27,14 +27,14 @@ monitor_port = /dev/ttyACM0 monitor_speed = 921600 build_type = release build_flags = - -DCORE_DEBUG_LEVEL=4 + -DCORE_DEBUG_LEVEL=1 -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MODE=0 -DCONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 - -DCONFIG_ASYNC_TCP_PRIORITY=20 - -DCONFIG_ASYNC_TCP_QUEUE_SIZE=128 + -DCONFIG_ASYNC_TCP_PRIORITY=21 + -DCONFIG_ASYNC_TCP_QUEUE_SIZE=64 -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 - -DCONFIG_ASYNC_TCP_STACK_SIZE=8192 + -DCONFIG_ASYNC_TCP_STACK_SIZE=4096 -fstack-protector-all [env:esp32-s3-devkitc1-n16r8-debug] @@ -61,8 +61,8 @@ build_flags = -DARDUINO_USB_CDC_ON_BOOT=0 -DARDUINO_USB_MODE=0 -DCONFIG_ASYNC_TCP_MAX_ACK_TIME=5000 - -DCONFIG_ASYNC_TCP_PRIORITY=20 - -DCONFIG_ASYNC_TCP_QUEUE_SIZE=128 + -DCONFIG_ASYNC_TCP_PRIORITY=21 + -DCONFIG_ASYNC_TCP_QUEUE_SIZE=64 -DCONFIG_ASYNC_TCP_RUNNING_CORE=1 - -DCONFIG_ASYNC_TCP_STACK_SIZE=8192 + -DCONFIG_ASYNC_TCP_STACK_SIZE=4096 -fstack-protector-all diff --git a/RotaxMonitor/src/isr.h b/RotaxMonitor/src/isr.h index ed2e4d1..bd1bea5 100644 --- a/RotaxMonitor/src/isr.h +++ b/RotaxMonitor/src/isr.h @@ -16,8 +16,8 @@ #define CORE_0 0 #define CORE_1 1 -#define RT_TASK_STACK 4096 // in words -#define RT_TASK_PRIORITY (configMAX_PRIORITIES - 4) // highest priority after wifi tasks +#define RT_TASK_STACK 2048 // in words +#define RT_TASK_PRIORITY (configMAX_PRIORITIES - 6) // highest priority after wifi tasks struct isrParams { diff --git a/RotaxMonitor/src/main.cpp b/RotaxMonitor/src/main.cpp index 4ac0bd7..a39faa4 100644 --- a/RotaxMonitor/src/main.cpp +++ b/RotaxMonitor/src/main.cpp @@ -15,10 +15,6 @@ #include #include -// FreeRTOS directives -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" - // Defines to enable channel B #define CH_B_ENABLE #define TEST @@ -76,6 +72,7 @@ void setup() initSparkPinInputs(); } +////////////////////// MAIN LOOP ////////////////////// void loop() { // global variables @@ -223,12 +220,12 @@ void loop() LOG_DEBUG("Real Time Tasks A & B initialized"); - ////////////////////// MAIN LOOP ////////////////////// bool partial_save = false; // flag to indicate if a partial save has been done after a timeout auto last_data = millis(); + auto last_info = millis(); + uint32_t counter_a = 0; uint32_t counter_b = 0; - uint32_t wait_count = 0; ignitionBoxStatus ign_info_A; @@ -240,12 +237,13 @@ void loop() LITTLEFSGuard fsGuard; WebPage webPage(80, LittleFS); // Initialize webserver and Websocket - while (running) + //////////////// INNER LOOP ///////////////////// + while (running) { auto dataA = pdFALSE; auto dataB = pdFALSE; - dataA = xQueueReceive(rt_taskA_queue, &ign_info_A, pdMS_TO_TICKS(10)); + dataA = xQueueReceive(rt_taskA_queue, &ign_info_A, 0); if (counter_a >= active_history_A->size()) // not concurrent with write task { counter_a = 0; @@ -255,7 +253,7 @@ void loop() } #ifdef CH_B_ENABLE - dataB = xQueueReceive(rt_taskB_queue, &ign_info_B, pdMS_TO_TICKS(10)); + dataB = xQueueReceive(rt_taskB_queue, &ign_info_B, 0); if (counter_b >= active_history_B->size()) // not concurrent with write task { counter_b = 0; @@ -274,7 +272,7 @@ void loop() { (*active_history_A)[counter_a++ % active_history_A->size()] = ign_info_A; ign_info_avg_A.update(ign_info_A); // update moving average with latest ignition status - Serial.printf("Data Received A: %d/%d\n\r", counter_a, (*active_history_A).size()); + // Serial.printf("Data Received A: %d/%d\n\r", counter_a, (*active_history_A).size()); if (counter_a % filter_k == 0) // send data every 10 samples { ArduinoJson::JsonDocument wsData; @@ -288,7 +286,7 @@ void loop() { (*active_history_B)[counter_b++ % active_history_B->size()] = ign_info_B; ign_info_avg_B.update(ign_info_B); // update moving average with latest ignition status - Serial.printf("Data Received B: %d/%d\n\r", counter_b, (*active_history_B).size()); + // Serial.printf("Data Received B: %d/%d\n\r", counter_b, (*active_history_B).size()); if (counter_b % filter_k == 0) // send data every 10 samples { ArduinoJson::JsonDocument wsData; @@ -298,7 +296,7 @@ void loop() } } #endif - if (dataA == pdFALSE && dataB == pdFALSE && millis() - last_data > 2000) + if (dataA == pdFALSE && dataB == pdFALSE && (millis() - last_data) > 2000) { if (!partial_save && counter_a > 0) // if timeout occurs but we have unsaved data, save it before next timeout { @@ -316,16 +314,23 @@ void loop() partial_save = true; first_save = true; } - Serial.printf("[%d] Waiting for data...\r", wait_count++); - delay(500); + //Serial.printf("[%d] Waiting for data...\r", wait_count++); + delay(100); } - } + + if ((millis() - last_info) > 1000) + { + clearScreen(); + Serial.println(); + printRunningTasksMod(Serial); + last_info = millis(); + + } + } //////////////// INNER LOOP ///////////////////// if (trigA_TaskHandle) vTaskDelete(trigA_TaskHandle); -#ifdef CH_B_ENABLE if (trigB_TaskHandle) vTaskDelete(trigB_TaskHandle); -#endif - ////////////////////// MAIN LOOP ////////////////////// -} + +} ////////////////////// MAIN LOOP ////////////////////// diff --git a/RotaxMonitor/src/utils.cpp b/RotaxMonitor/src/utils.cpp index 222f913..a1fad94 100644 --- a/RotaxMonitor/src/utils.cpp +++ b/RotaxMonitor/src/utils.cpp @@ -1,4 +1,15 @@ #include "utils.h" +#include "freertos_stats.h" +#include "sdkconfig.h" + +#include "freertos/FreeRTOS.h" +#include "freertos/portable.h" + +#include +#include +#include + +#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; @@ -12,3 +23,60 @@ std::string printBits(uint32_t value) { } return result; } + +void printRunningTasksMod(Print &printer, std::function 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 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 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(); +} + diff --git a/RotaxMonitor/src/utils.h b/RotaxMonitor/src/utils.h index 40a745e..f74653e 100644 --- a/RotaxMonitor/src/utils.h +++ b/RotaxMonitor/src/utils.h @@ -6,6 +6,8 @@ std::string printBits(uint32_t value); +void printRunningTasksMod(Print &printer, std::function orderBy = nullptr); + inline void swapHistory(PSRAMVector* active, PSRAMVector* writable) { auto *temp = active; active = writable; // switch active and writable buffers