diff --git a/components/freertos/tasks.c b/components/freertos/tasks.c index f6931c401..48acd2058 100644 --- a/components/freertos/tasks.c +++ b/components/freertos/tasks.c @@ -1294,7 +1294,6 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode TickType_t xTimeToWake; BaseType_t xAlreadyYielded=pdFALSE, xShouldDelay = pdFALSE; - UNTESTED_FUNCTION(); configASSERT( pxPreviousWakeTime ); configASSERT( ( xTimeIncrement > 0U ) ); configASSERT( uxSchedulerSuspended[ xPortGetCoreID() ] == 0 ); @@ -1457,18 +1456,17 @@ static void prvAddNewTaskToReadyList( TCB_t *pxNewTCB, TaskFunction_t pxTaskCode /*-----------------------------------------------------------*/ #if ( INCLUDE_eTaskGetState == 1 ) -/* ToDo: Make this multicore-compatible. */ eTaskState eTaskGetState( TaskHandle_t xTask ) { eTaskState eReturn; List_t *pxStateList; const TCB_t * const pxTCB = ( TCB_t * ) xTask; - TCB_t * curTCB = xTaskGetCurrentTaskHandle(); + TCB_t * curTCBcurCore = xTaskGetCurrentTaskHandle(); + TCB_t * curTCBothrCore = xTaskGetCurrentTaskHandleForCPU(!xPortGetCoreID()); //Returns NULL if Unicore - UNTESTED_FUNCTION(); configASSERT( pxTCB ); - if( pxTCB == curTCB ) + if( pxTCB == curTCBcurCore || pxTCB == curTCBothrCore ) { /* The task calling this function is querying its own state. */ eReturn = eRunning; @@ -4526,7 +4524,6 @@ TickType_t uxReturn; TickType_t xTimeToWake; uint32_t ulReturn; - UNTESTED_FUNCTION(); taskENTER_CRITICAL(&xTaskQueueMutex); { /* Only block if the notification count is not already non-zero. */ @@ -4849,7 +4846,6 @@ TickType_t uxReturn; eNotifyValue eOriginalNotifyState; BaseType_t xReturn = pdPASS; - UNTESTED_FUNCTION(); configASSERT( xTaskToNotify ); pxTCB = ( TCB_t * ) xTaskToNotify; @@ -4947,7 +4943,6 @@ TickType_t uxReturn; TCB_t * pxTCB; eNotifyValue eOriginalNotifyState; - UNTESTED_FUNCTION(); configASSERT( xTaskToNotify ); diff --git a/components/freertos/test/test_freertos_get_state.c b/components/freertos/test/test_freertos_get_state.c new file mode 100644 index 000000000..f0ad87d4a --- /dev/null +++ b/components/freertos/test/test_freertos_get_state.c @@ -0,0 +1,66 @@ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "unity.h" + +#define TSK_PRIORITY (UNITY_FREERTOS_PRIORITY + 1) + +static TaskHandle_t blocked_task_handle; +static TaskHandle_t suspended_task_handle; +static SemaphoreHandle_t done_sem; + +void test_task_get_state(void* arg) +{ + //Current task should return eRunning + TEST_ASSERT(eTaskGetState(xTaskGetCurrentTaskHandle()) == eRunning); + //Idle task of current core should return eReady + TEST_ASSERT(eTaskGetState(xTaskGetIdleTaskHandle()) == eReady); + //Blocked Task should return eBlocked + TEST_ASSERT(eTaskGetState(blocked_task_handle) == eBlocked); + //Suspended Task should return eSuspended + TEST_ASSERT(eTaskGetState(suspended_task_handle) == eSuspended); + + xSemaphoreGive(done_sem); + vTaskDelete(NULL); +} + +void blocked_task(void *arg) +{ + while(1){ + vTaskDelay(portMAX_DELAY); + } +} + +void suspended_task(void *arg) +{ + while(1){ + vTaskSuspend(NULL); + } +} + +TEST_CASE("Test eTaskGetState", "[freertos]") +{ + done_sem = xQueueCreateCountingSemaphore(portNUM_PROCESSORS, 0); + //Create blocked and suspended task + xTaskCreatePinnedToCore(blocked_task, "Blocked task", 1024, NULL, TSK_PRIORITY, &blocked_task_handle, tskNO_AFFINITY); + xTaskCreatePinnedToCore(suspended_task, "Suspended task", 1024, NULL, TSK_PRIORITY, &suspended_task_handle, tskNO_AFFINITY); + //Create testing task + for(int i = 0; i < portNUM_PROCESSORS; i++){ + xTaskCreatePinnedToCore(test_task_get_state, "Test task", 1024, NULL, TSK_PRIORITY, NULL, i); + } + + //Wait until done + for(int i = 0; i < portNUM_PROCESSORS; i++){ + xSemaphoreTake(done_sem, portMAX_DELAY); + } + //Clean up blocked and suspended tasks + vTaskDelete(blocked_task_handle); + blocked_task_handle = NULL; + vTaskDelete(suspended_task_handle); + suspended_task_handle = NULL; + vSemaphoreDelete(done_sem); + + vTaskDelay(10); //Give time for idle to actually delete the tasks +} diff --git a/components/freertos/test/test_freertos_task_delay_until.c b/components/freertos/test/test_freertos_task_delay_until.c new file mode 100644 index 000000000..b4cc7d5d6 --- /dev/null +++ b/components/freertos/test/test_freertos_task_delay_until.c @@ -0,0 +1,74 @@ +/* + Test for FreeRTOS vTaskDelayUntil() function by comparing the delay period of + the function to comparing it to ref clock. +*/ + +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include "freertos/semphr.h" +#include "freertos/FreeRTOSConfig.h" +#include "unity.h" +#include "test_utils.h" + +#define TSK_PRIORITY (UNITY_FREERTOS_PRIORITY + 1) + +#define NO_OF_CYCLES 5 +#define NO_OF_TASKS_PER_CORE 2 +#define TICKS_TO_DELAY 10 +#define TICK_RATE configTICK_RATE_HZ +#define TICK_PERIOD_US (1000000/TICK_RATE) +#define IDEAL_DELAY_PERIOD_MS ((1000*TICKS_TO_DELAY)/TICK_RATE) +#define IDEAL_DELAY_PERIOD_US (IDEAL_DELAY_PERIOD_MS*1000) + +#define TICKS_TO_MS(x) (((x)*1000)/TICK_RATE) +#define REF_TO_ROUND_MS(x) (((x)+500)/1000) + +static SemaphoreHandle_t task_delete_semphr; + +static void delaying_task(void* arg) +{ + uint64_t ref_prev, ref_current; + TickType_t last_wake_time; + TickType_t ticks_before_delay; + + vTaskDelay(1); //Delay until next tick to synchronize operations to tick boundaries + + last_wake_time = xTaskGetTickCount(); + ticks_before_delay = last_wake_time; + ref_prev = ref_clock_get(); + + for(int i = 0; i < NO_OF_CYCLES; i++){ + //Delay of TICKS_TO_DELAY + vTaskDelayUntil(&last_wake_time, TICKS_TO_DELAY); + //Get current ref clock + TEST_ASSERT_EQUAL(IDEAL_DELAY_PERIOD_MS, TICKS_TO_MS(xTaskGetTickCount() - ticks_before_delay)); + ref_current = ref_clock_get(); + TEST_ASSERT_UINT32_WITHIN(TICK_PERIOD_US, IDEAL_DELAY_PERIOD_US, (uint32_t)(ref_current - ref_prev)); + ref_prev = ref_current; + ticks_before_delay = last_wake_time; + } + + //Delete Task after prescribed number of cycles + xSemaphoreGive(task_delete_semphr); + vTaskDelete(NULL); +} + +TEST_CASE("Test vTaskDelayUntil", "[freertos]") +{ + task_delete_semphr = xQueueCreateCountingSemaphore(NO_OF_TASKS_PER_CORE*portNUM_PROCESSORS, 0); + ref_clock_init(); + + for(int i = 0; i < portNUM_PROCESSORS; i++){ + xTaskCreatePinnedToCore(delaying_task, "delay_pinned", 1024, NULL, TSK_PRIORITY, NULL, i); + xTaskCreatePinnedToCore(delaying_task, "delay_no_aff", 1024, NULL, TSK_PRIORITY, NULL, tskNO_AFFINITY); + } + + for(int i = 0; i < NO_OF_TASKS_PER_CORE*portNUM_PROCESSORS; i++){ + xSemaphoreTake(task_delete_semphr, portMAX_DELAY); + } + //Cleanup + vSemaphoreDelete(task_delete_semphr); + ref_clock_deinit(); +} diff --git a/components/freertos/test/test_freertos_task_notify.c b/components/freertos/test/test_freertos_task_notify.c new file mode 100644 index 000000000..f4647442f --- /dev/null +++ b/components/freertos/test/test_freertos_task_notify.c @@ -0,0 +1,210 @@ +/* + Test of FreeRTOS task notifications. This test creates a sender and receiver + task under different core permutations. For each permutation, the sender task + will test the xTaskNotify(), xTaskNotifyGive(), xTaskNotifyFromISR(), and + vTaskNotifyGiveFromISR(), whereas the receiver task will test + xTaskNotifyWait() and ulTaskNotifyTake(). +*/ +#include +#include +#include "freertos/FreeRTOS.h" +#include "freertos/task.h" +#include +#include "driver/timer.h" +#include "esp_ipc.h" +#include "unity.h" + +#define NO_OF_NOTIFS 4 +#define NO_OF_TASKS 2 //Sender and receiver +#define TIMER_DIVIDER 10000 +#define TIMER_COUNT 100 +#define MESSAGE 0xFF + +static uint32_t send_core_message = 0; +static TaskHandle_t rec_task_handle; +static bool isr_give = false; + +static SemaphoreHandle_t trigger_send_semphr; +static SemaphoreHandle_t task_delete_semphr; + +//Test tracking vars +static volatile uint32_t notifs_sent = 0; +static volatile uint32_t notifs_rec = 0; +static bool wrong_core = false; + +static void sender_task (void* arg){ + int curcore = xPortGetCoreID(); + + //Test xTaskNotify + xSemaphoreTake(trigger_send_semphr, portMAX_DELAY); + notifs_sent++; + xTaskNotify(rec_task_handle, (MESSAGE << curcore), eSetValueWithOverwrite); + + //Test xTaskNotifyGive + xSemaphoreTake(trigger_send_semphr, portMAX_DELAY); + notifs_sent++; + xTaskNotifyGive(rec_task_handle); + + //Test xTaskNotifyFromISR + xSemaphoreTake(trigger_send_semphr, portMAX_DELAY); + isr_give = false; + timer_start(TIMER_GROUP_0, curcore); + + //Test vTaskNotifyGiveFromISR + xSemaphoreTake(trigger_send_semphr, portMAX_DELAY); + isr_give = true; + timer_start(TIMER_GROUP_0, curcore); + + //Delete Task and Semaphores + xSemaphoreGive(task_delete_semphr); + vTaskDelete(NULL); +} + +static void receiver_task (void* arg){ + uint32_t notify_value; + + //Test xTaskNotifyWait from task + xTaskNotifyWait(0, 0xFFFFFFFF, ¬ify_value, portMAX_DELAY); + if(notify_value != send_core_message){ + wrong_core = true; + } + notifs_rec++; + + //Test ulTaskNotifyTake from task + xSemaphoreGive(trigger_send_semphr); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + notifs_rec++; + + //Test xTaskNotifyWait from ISR + xSemaphoreGive(trigger_send_semphr); + xTaskNotifyWait(0, 0xFFFFFFFF, ¬ify_value, portMAX_DELAY); + if(notify_value != send_core_message){ + wrong_core = true; + } + notifs_rec++; + + //Test ulTaskNotifyTake from ISR + xSemaphoreGive(trigger_send_semphr); + ulTaskNotifyTake(pdTRUE, portMAX_DELAY); + notifs_rec++; + + //Test complete, stop timer and delete task + xSemaphoreGive(task_delete_semphr); + vTaskDelete(NULL); +} + +static void IRAM_ATTR sender_ISR () +{ + int curcore = xPortGetCoreID(); + if(curcore == 0){ //Clear timer interrupt + //Clear intr and pause via direct reg access as IRAM ISR cannot access timer APIs + TIMERG0.int_clr_timers.t0 = 1; + TIMERG0.hw_timer[0].config.enable = 0; + }else{ + TIMERG0.int_clr_timers.t1 = 1; + TIMERG0.hw_timer[1].config.enable = 0; + } + //Re-enable alarm + TIMERG0.hw_timer[curcore].config.alarm_en = 1; + + if(isr_give){ //Test vTaskNotifyGiveFromISR() on same core + notifs_sent++; + vTaskNotifyGiveFromISR(rec_task_handle, NULL); + } + else { //Test xTaskNotifyFromISR() + notifs_sent++; + xTaskNotifyFromISR(rec_task_handle, (MESSAGE << curcore), eSetValueWithOverwrite, NULL); + } + portYIELD_FROM_ISR(); + return; +} + +static void timerg0_init(void *isr_handle) +{ + int timer_group = TIMER_GROUP_0; + int timer_idx = xPortGetCoreID(); + + 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; + + /*Configure timer*/ + timer_init(timer_group, timer_idx, &config); + /*Stop timer counter*/ + timer_pause(timer_group, timer_idx); + /*Load counter value */ + timer_set_counter_value(timer_group, timer_idx, 0x00000000ULL); + /*Set alarm value*/ + timer_set_alarm_value(timer_group, timer_idx, TIMER_COUNT); + /*Enable timer interrupt*/ + timer_enable_intr(timer_group, timer_idx); + //Auto Reload + timer_set_auto_reload(timer_group, timer_idx, 1); + /*Set ISR handler*/ + timer_isr_register(timer_group, timer_idx, sender_ISR, NULL, ESP_INTR_FLAG_IRAM, (intr_handle_t *)isr_handle); +} + +static void timerg0_deinit(void* isr_handle) +{ + int timer_group = TIMER_GROUP_0; + int timer_idx = xPortGetCoreID(); + intr_handle_t handle = *((intr_handle_t *) isr_handle); + //Pause timer then free registered ISR + timer_pause(timer_group, timer_idx); + esp_intr_free(handle); +} + +TEST_CASE("Test Task_Notify", "[freertos]") +{ + //Initialize and pause timers. Used to trigger ISR + intr_handle_t isr_handle_0 = NULL; + timerg0_init(&isr_handle_0); //Core 0 timer +#ifndef CONFIG_FREERTOS_UNICORE + intr_handle_t isr_handle_1 = NULL; + esp_ipc_call(1, timerg0_init, &isr_handle_1); //Core 1 timer +#endif + + trigger_send_semphr = xSemaphoreCreateBinary(); + task_delete_semphr = xQueueCreateCountingSemaphore(NO_OF_TASKS, 0); + + for(int i = 0; i < portNUM_PROCESSORS; i++){ //Sending Core + for(int j = 0; j < portNUM_PROCESSORS; j++){ //Receiving Core + //Reset Values + notifs_sent = 0; + notifs_rec = 0; + wrong_core = false; + + send_core_message = (0xFF << i); //0xFF if core 0, 0xFF0 if core 1 + + xTaskCreatePinnedToCore(receiver_task, "rec task", 1000, NULL, UNITY_FREERTOS_PRIORITY + 2, &rec_task_handle, j); + xTaskCreatePinnedToCore(sender_task, "send task", 1000, NULL, UNITY_FREERTOS_PRIORITY + 1, NULL, i); + vTaskDelay(5); //Wait for task creation to complete + + xSemaphoreGive(trigger_send_semphr); //Trigger sender task + for(int k = 0; k < NO_OF_TASKS; k++){ //Wait for sender and receiver task deletion + xSemaphoreTake(task_delete_semphr, portMAX_DELAY); + } + vTaskDelay(5); //Give time tasks to delete + + TEST_ASSERT(notifs_sent == NO_OF_NOTIFS); + TEST_ASSERT(notifs_rec == NO_OF_NOTIFS); + TEST_ASSERT(wrong_core == false); + } + } + + //Delete Semaphroes and timer ISRs + vSemaphoreDelete(trigger_send_semphr); + vSemaphoreDelete(task_delete_semphr); + timerg0_deinit(&isr_handle_0); + isr_handle_0 = NULL; +#ifndef CONFIG_FREERTOS_UNICORE + esp_ipc_call(1, timerg0_deinit, &isr_handle_1); + isr_handle_1 = NULL; +#endif +} + +