Răsfoiți Sursa

freertos: Test untested functions

Test cases were added for the following functions
- xTaskNotify(), xTaskNotifyGive(), xTaskNotifyFromISR(), vTaskNotifyGiveFromISR(),
- xTaskNotifyWait(), ulTaskNotifyTake()
- vTaskDelayUntil()

The following function was made smp compatible and tested as well
- eTaskGetState()
Darian Leung 8 ani în urmă
părinte
comite
637ba2e8bb

+ 3 - 8
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 );
 
 

+ 66 - 0
components/freertos/test/test_freertos_get_state.c

@@ -0,0 +1,66 @@
+#include <stdio.h>
+#include <stdlib.h>
+#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
+}

+ 74 - 0
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 <stdio.h>
+#include <stdlib.h>
+#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();
+}

+ 210 - 0
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 <stdio.h>
+#include <stdlib.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+#include <freertos/semphr.h>
+#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, &notify_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, &notify_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
+}
+
+