diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index 44541a54a..e56cb1a01 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -275,6 +275,23 @@ config TIMER_QUEUE_LENGTH For most uses the default value of 10 is OK. +config FREERTOS_USE_TRACE_FACILITY + bool "Enable FreeRTOS trace facility" + default n + help + If enabled, configUSE_TRACE_FACILITY will be defined as 1 in FreeRTOS. + This will allow the usage of trace facility functions such as + uxTaskGetSystemState(). + +config FREERTOS_USE_STATS_FORMATTING_FUNCTIONS + bool "Enable FreeRTOS stats formatting functions" + depends on FREERTOS_USE_TRACE_FACILITY + default n + help + If enabled, configUSE_STATS_FORMATTING_FUNCTIONS will be defined as 1 in + FreeRTOS. This will allow the usage of stats formatting functions such + as vTaskList(). + menuconfig FREERTOS_DEBUG_INTERNALS bool "Debug FreeRTOS internals" default n diff --git a/components/freertos/include/freertos/FreeRTOSConfig.h b/components/freertos/include/freertos/FreeRTOSConfig.h index 3ccd3fda6..e38c1426d 100644 --- a/components/freertos/include/freertos/FreeRTOSConfig.h +++ b/components/freertos/include/freertos/FreeRTOSConfig.h @@ -190,8 +190,19 @@ #define configTOTAL_HEAP_SIZE (&_heap_end - &_heap_start)//( ( size_t ) (64 * 1024) ) #define configMAX_TASK_NAME_LEN ( CONFIG_FREERTOS_MAX_TASK_NAME_LEN ) -#define configUSE_TRACE_FACILITY 0 /* Used by vTaskList in main.c */ -#define configUSE_STATS_FORMATTING_FUNCTIONS 0 /* Used by vTaskList in main.c */ + +#ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY +#define configUSE_TRACE_FACILITY 1 /* Used by uxTaskGetSystemState(), and other trace facility functions */ +#endif + +#ifdef CONFIG_FREERTOS_USE_STATS_FORMATTING_FUNCTIONS +#define configUSE_STATS_FORMATTING_FUNCTIONS 1 /* Used by vTaskList() */ +#endif + +#ifdef CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS +#define configGENERATE_RUN_TIME_STATS 1 /* Used by vTaskGetRunTimeStats() */ +#endif + #define configUSE_TRACE_FACILITY_2 0 /* Provided by Xtensa port patch */ #define configBENCHMARK 0 /* Provided by Xtensa port patch */ #define configUSE_16_BIT_TICKS 0 diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index 24373a91e..f6931c401 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -2292,7 +2292,6 @@ UBaseType_t uxTaskGetNumberOfTasks( void ) { UBaseType_t uxTask = 0, uxQueue = configMAX_PRIORITIES; - UNTESTED_FUNCTION(); taskENTER_CRITICAL(&xTaskQueueMutex); { /* Is there a space in the array for each task in the system? */ @@ -3678,7 +3677,6 @@ BaseType_t xTaskGetAffinity( TaskHandle_t xTask ) volatile TCB_t *pxNextTCB, *pxFirstTCB; UBaseType_t uxTask = 0; - UNTESTED_FUNCTION(); if( listCURRENT_LIST_LENGTH( pxList ) > ( UBaseType_t ) 0 ) { listGET_OWNER_OF_NEXT_ENTRY( pxFirstTCB, pxList ); @@ -4268,7 +4266,6 @@ For ESP32 FreeRTOS, vTaskExitCritical implements both portEXIT_CRITICAL and port TaskStatus_t *pxTaskStatusArray; volatile UBaseType_t uxArraySize, x; char cStatus; - UNTESTED_FUNCTION(); /* * PLEASE NOTE: diff --git a/components/freertos/test/test_freertos_eventgroups.c b/components/freertos/test/test_freertos_eventgroups.c index 8d5a5fb32..2b79060f4 100644 --- a/components/freertos/test/test_freertos_eventgroups.c +++ b/components/freertos/test/test_freertos_eventgroups.c @@ -5,6 +5,7 @@ #include "freertos/semphr.h" #include "freertos/queue.h" #include "freertos/event_groups.h" +#include "driver/timer.h" #include "unity.h" #define BIT_CALL (1 << 0) @@ -117,3 +118,85 @@ TEST_CASE("FreeRTOS Event Group Sync", "[freertos]") vEventGroupDelete(eg); } +/*-----------------Test case for event group trace facilities-----------------*/ +#ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY +/* + * Test event group Trace Facility functions such as + * xEventGroupClearBitsFromISR(), xEventGroupSetBitsFromISR() + */ + +//Use a timer to trigger an ISr +#define TIMER_DIVIDER 10000 +#define TIMER_COUNT 1000 +#define TIMER_NUMBER 0 +#define SET_BITS 0xAA +#define CLEAR_BITS 0x55 + +static bool event_grp_cleared = false; + +static void IRAM_ATTR event_group_isr() +{ + TIMERG0.int_clr_timers.t0 = 1; + TIMERG0.hw_timer[xPortGetCoreID()].config.alarm_en = 1; + if(!event_grp_cleared){ + xEventGroupClearBitsFromISR(eg, CLEAR_BITS); + event_grp_cleared = true; + }else{ + xEventGroupSetBitsFromISR(eg, SET_BITS, NULL); + timer_pause(TIMER_GROUP_0, TIMER_NUMBER); + } +} + + +static void test_event_group_trace_facility(void* arg) +{ + //Setup timer for ISR + int timer_group = TIMER_GROUP_0; + int timer_idx = TIMER_NUMBER; + timer_config_t config; + config.alarm_en = 1; + config.auto_reload = 1; + config.counter_dir = TIMER_COUNT_UP; + config.divider = TIMER_DIVIDER; + config.intr_type = TIMER_INTR_LEVEL; + config.counter_en = TIMER_PAUSE; + timer_init(timer_group, timer_idx, &config); //Configure timer + timer_pause(timer_group, timer_idx); //Stop timer counter + timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); //Load counter value + timer_set_alarm_value(timer_group, timer_idx, TIMER_COUNT); //Set alarm value + timer_enable_intr(timer_group, timer_idx); //Enable timer interrupt + timer_set_auto_reload(timer_group, timer_idx, 1); //Auto Reload + timer_isr_register(timer_group, timer_idx, event_group_isr, NULL, ESP_INTR_FLAG_IRAM, NULL); //Set ISR handler + + //Start timer to trigger isr + timer_start(TIMER_GROUP_0, TIMER_NUMBER); + TEST_ASSERT(xEventGroupWaitBits(eg, SET_BITS, pdFALSE, pdTRUE, portMAX_DELAY)); + //Check clear was successful + TEST_ASSERT((xEventGroupGetBits(eg) & CLEAR_BITS) == 0); + + //Give semaphore to signal done + xSemaphoreGive(done_sem); + vTaskDelete(NULL); + +} + +TEST_CASE("FreeRTOS Event Group ISR", "[freertos]") +{ + + done_sem = xSemaphoreCreateBinary(); + eg = xEventGroupCreate(); + xEventGroupSetBits(eg, CLEAR_BITS); //Set bits to be cleared by ISR + + xTaskCreatePinnedToCore(test_event_group_trace_facility, "Testing Task", 4096, NULL, configMAX_PRIORITIES - 1, NULL, 0); + + //Wait until task and isr have finished testing + xSemaphoreTake(done_sem, portMAX_DELAY); + //Clean up + vSemaphoreDelete(done_sem); + vEventGroupDelete(eg); + + vTaskDelay(10); //Give time for idle task to clear up delted tasks + +} + +#endif //CONFIG_FREERTOS_USE_TRACE_FACILITY diff --git a/components/freertos/test/test_freertos_trace_utilities.c b/components/freertos/test/test_freertos_trace_utilities.c new file mode 100644 index 000000000..da01b8a05 --- /dev/null +++ b/components/freertos/test/test_freertos_trace_utilities.c @@ -0,0 +1,132 @@ +/* + * Test FreeRTOS trace facility functions. These following functions are enabled + * when configUSE_TRACE_FACILITY is defined 1 in FreeRTOS. + * Tasks: uxTaskGetTaskNumber(), uxTaskSetTaskNumber() + * Queues: ucQueueGetQueueType(), vQueueSetQueueNumber(), uxQueueGetQueueNumber() + * Event Groups: xEventGroupSetBitsFromISR(), xEventGroupClearBitsFromISR(), uxEventGroupGetNumber() + * + * Note: uxTaskGetSystemState() is tested in a separate unit test + */ +#include +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/event_groups.h" +#include "unity.h" + +#ifdef CONFIG_FREERTOS_USE_TRACE_FACILITY +#define TSK_PRIORITY (UNITY_FREERTOS_PRIORITY + 1) + +#define NO_OF_CORES portNUM_PROCESSORS +#define BIN_SEM_QUEUE_TYPE queueQUEUE_TYPE_BINARY_SEMAPHORE //Expected Queue Type + +static QueueHandle_t test_queues[NO_OF_CORES]; +static TaskHandle_t task_handles[NO_OF_CORES]; + +void task_test_trace_utilities(void *arg) +{ + int core = xPortGetCoreID(); + TaskHandle_t handle = xTaskGetCurrentTaskHandle(); + uint32_t id = (uint32_t)arg; + + vTaskSetTaskNumber(handle, (UBaseType_t)id); //cast and store id as task number + vQueueSetQueueNumber(test_queues[core], id); //store id as queue number + + //Wait to start + xSemaphoreTake(test_queues[core], portMAX_DELAY); + + //Tests on this core + TEST_ASSERT(uxTaskGetTaskNumber(task_handles[core]) == (0x0F << (core))); + TEST_ASSERT(uxQueueGetQueueNumber(test_queues[core]) == (0x0F << (core))); + TEST_ASSERT(ucQueueGetQueueType(test_queues[core]) == BIN_SEM_QUEUE_TYPE) + + //Test on other core +#ifndef CONFIG_FREERTOS_UNICORE + TEST_ASSERT(uxTaskGetTaskNumber(task_handles[!core]) == (0x0F << (!core))); + TEST_ASSERT(uxQueueGetQueueNumber(test_queues[!core]) == (0x0F << (!core))); + TEST_ASSERT(ucQueueGetQueueType(test_queues[!core]) == BIN_SEM_QUEUE_TYPE) +#endif + + xSemaphoreGive(test_queues[core]); //Signal done + vTaskDelete(NULL); +} + +TEST_CASE("Test freertos trace facility functions", "[freertos]") +{ + for(int i = 0; i < NO_OF_CORES; i++){ + test_queues[i] = xSemaphoreCreateBinary(); //Create a queue as binary semaphore for each core + xTaskCreatePinnedToCore(task_test_trace_utilities, "Test Task", 4096, (void *)(0x0F << i), TSK_PRIORITY, &task_handles[i], i); + } + + vTaskDelay(10); + + //Start the tasks + for(int i = NO_OF_CORES - 1; i >= 0; i--){ + xSemaphoreGive(test_queues[i]); + } + + vTaskDelay(10); //Small delay to ensure semaphores are taken + + //Wait for done + for(int i = 0; i < NO_OF_CORES; i++){ + xSemaphoreTake(test_queues[i], portMAX_DELAY); + vSemaphoreDelete(test_queues[i]); + } + + vTaskDelay(10); //Give time for idle task to clean up +} + + +#define MAX_TASKS 15 +#define TASKS_TO_CREATE 5 + +static TaskHandle_t created_handles[TASKS_TO_CREATE]; +static TaskStatus_t *tsk_status_array; + +void created_task(void* arg) +{ + while(1){ + vTaskDelay(100); + } +} + +TEST_CASE("Test freertos uxTaskGetSystemState", "[freertos]") +{ + tsk_status_array = calloc(MAX_TASKS, sizeof(TaskStatus_t)); + for(int i = 0; i < TASKS_TO_CREATE; i++){ + xTaskCreatePinnedToCore(created_task, "Created Task", 1024, NULL, TSK_PRIORITY, &created_handles[i], 0); + } + + //Get System states + int no_of_tasks = uxTaskGetSystemState(tsk_status_array, MAX_TASKS, NULL); + TEST_ASSERT((no_of_tasks > 0) && (no_of_tasks <= MAX_TASKS)); + + //Check if get system state has got all created tasks + bool not_found = false; + for(int i = 0; i < TASKS_TO_CREATE; i++){ + bool found = false; + for(int j = 0; j < MAX_TASKS; j++){ + if(tsk_status_array[j].xHandle == created_handles[i]){ + found = true; + break; + } + } + if(!found){ + not_found = true; + break; + } + } + TEST_ASSERT(not_found == false); + + //Cleanup + for(int i = 0; i < TASKS_TO_CREATE; i++){ + vTaskDelete(created_handles[i]); + } + free(tsk_status_array); + vTaskDelay(10); +} + +#endif //CONFIG_FREERTOS_USE_TRACE_FACILITY + diff --git a/components/freertos/test/test_uxGetSystemState_Bugfix.c b/components/freertos/test/test_uxGetSystemState_Bugfix.c deleted file mode 100644 index e7e447f68..000000000 --- a/components/freertos/test/test_uxGetSystemState_Bugfix.c +++ /dev/null @@ -1,67 +0,0 @@ -/* - Test Bugfix for uxTaskGetSystemState where getting system state immediately after creating - new tasks would lead them being include twice in the TaskStatusArray. Changed suspendScheduler - in function to taskENTER_CRITICAL -*/ - - -#include -#include "freertos/FreeRTOS.h" -#include "freertos/task.h" -#include "unity.h" - -#define CreatedTaskDelayTicks 1 -#define NumberOfTasksToCreate 4 -#define CreatedTaskPriority 10 -#define CoreToUse 1 - -#if (configUSE_TRACE_FACILITY) - -void TaskCallback (void* pxParam){ - int counter = 0; - while(1){ - counter++; - vTaskDelay(CreatedTaskDelayTicks); - } -} - -TEST_CASE("uxTaskGetSystemState Bugfix Test", "[freertos]") -{ - TaskStatus_t *TaskStatusArray; - TaskHandle_t *TaskHandles; - UBaseType_t NumberOfTasks = 0; - UBaseType_t StartingNumberOfTasks = 0; - - //Give Time for OS to remove dport tasks - vTaskDelay(1000); - - //Allocate TaskStatusArray - StartingNumberOfTasks = uxTaskGetNumberOfTasks(); - - - TaskStatusArray = pvPortMalloc((StartingNumberOfTasks+NumberOfTasksToCreate) * sizeof(TaskStatus_t)); - TaskHandles = pvPortMalloc((StartingNumberOfTasks+NumberOfTasksToCreate) * sizeof(TaskHandle_t)); - - - - //Create Tasks - for(int i = 0; i < NumberOfTasksToCreate; i++){ - xTaskCreatePinnedToCore(&TaskCallback, "Task" , 2048, NULL, CreatedTaskPriority, (TaskHandle_t*) &TaskHandles[i], CoreToUse); - } - NumberOfTasks = uxTaskGetSystemState(TaskStatusArray, (StartingNumberOfTasks+NumberOfTasksToCreate), NULL); - - //Check if any taska have been repeated in TaskStatusArray - if(NumberOfTasks != 0){ - printf("Tasks Created, Checking for Repeated Additions \n"); - for(int i = 0; i