1219 lines
57 KiB
C
1219 lines
57 KiB
C
|
/*
|
||
|
* FreeRTOS V202212.00
|
||
|
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||
|
*
|
||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||
|
* this software and associated documentation files (the "Software"), to deal in
|
||
|
* the Software without restriction, including without limitation the rights to
|
||
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||
|
* the Software, and to permit persons to whom the Software is furnished to do so,
|
||
|
* subject to the following conditions:
|
||
|
*
|
||
|
* The above copyright notice and this permission notice shall be included in all
|
||
|
* copies or substantial portions of the Software.
|
||
|
*
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||
|
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||
|
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||
|
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||
|
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||
|
*
|
||
|
* https://www.FreeRTOS.org
|
||
|
* https://github.com/FreeRTOS
|
||
|
*
|
||
|
*/
|
||
|
|
||
|
|
||
|
/*
|
||
|
* Tests the behaviour of arrays of task notifications per task. The tests in this
|
||
|
* file are additive to those implemented in FreeRTOS/Demo/Common/Minimal/TaskNotify.c.
|
||
|
*/
|
||
|
|
||
|
/* Standard includes. */
|
||
|
#include <limits.h>
|
||
|
|
||
|
/* Scheduler include files. */
|
||
|
#include "FreeRTOS.h"
|
||
|
#include "task.h"
|
||
|
#include "timers.h"
|
||
|
|
||
|
/* Demo program include files. */
|
||
|
#include "TaskNotifyArray.h"
|
||
|
|
||
|
#if ( configTASK_NOTIFICATION_ARRAY_ENTRIES < 3 )
|
||
|
#error This file tests direct to task notification arrays and needs configTASK_NOTIFICATION_ARRAY_ENTRIES to be at least 3.
|
||
|
#endif
|
||
|
|
||
|
/* Allow parameters to be overridden on a demo by demo basis. */
|
||
|
#ifndef notifyNOTIFY_ARRAY_TASK_STACK_SIZE
|
||
|
#define notifyNOTIFY_ARRAY_TASK_STACK_SIZE configMINIMAL_STACK_SIZE
|
||
|
#endif
|
||
|
|
||
|
#define notifyTASK_PRIORITY ( tskIDLE_PRIORITY )
|
||
|
|
||
|
/* Constants used in tests when setting/clearing bits. */
|
||
|
#define notifyUINT32_MAX ( ( uint32_t ) 0xffffffff )
|
||
|
#define notifyUINT32_HIGH_BYTE ( ( uint32_t ) 0xff000000 )
|
||
|
#define notifyUINT32_LOW_BYTE ( ( uint32_t ) 0x000000ff )
|
||
|
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
/*
|
||
|
* Implementation of the task that runs the tests - the task runs some tests
|
||
|
* itself, and others where notifications are sent from a software timer or
|
||
|
* an interrupt (specifically the tick hook function).
|
||
|
*/
|
||
|
static void prvNotifiedTask( void * pvParameters );
|
||
|
|
||
|
/*
|
||
|
* Performs the tests that don't require notifications to be sent from a
|
||
|
* remote source.
|
||
|
*/
|
||
|
static void prvSingleTaskTests( void );
|
||
|
|
||
|
/*
|
||
|
* Uses a software timer to send notifications to the task while the task is
|
||
|
* suspended.
|
||
|
*/
|
||
|
static void prvTestNotifyTaskWhileSuspended( void );
|
||
|
|
||
|
/*
|
||
|
* Uses a software timer to send notifications to the index within the array of
|
||
|
* task notifications on which the task is blocked. The task should unblock and
|
||
|
* the state of all the other task notifications within the array should remain
|
||
|
* unchanged.
|
||
|
*/
|
||
|
static void prvBlockOnTheNotifiedIndexed( void );
|
||
|
|
||
|
/*
|
||
|
* As per prvBlockOnTheNotifiedIndexed(), but this time the notification comes from
|
||
|
* the tick hook function, so from an interrupt rather than from a software timer.
|
||
|
*/
|
||
|
static void prvBlockOnNotificationsComingFromInterrupts( void );
|
||
|
|
||
|
/*
|
||
|
* As per prvBlockOnTheNotifiedIndexed(), except this time the notification is
|
||
|
* sent to an index within the task notification array on which the task is not
|
||
|
* blocked, so this time the task should not unblock and the state of all the
|
||
|
* task notifications other than the one to which the notification was actually
|
||
|
* sent should remain unchanged.
|
||
|
*/
|
||
|
static void prvBlockOnANonNotifiedIndexed( void );
|
||
|
|
||
|
/*
|
||
|
* Callback of the software timer used to send notifications for the
|
||
|
* prvBlockOnTheNotifiedIndexed() and prvBlockOnANonNotifiedIndexed() tests.
|
||
|
*/
|
||
|
static void prvNotifyingTimerCallback( TimerHandle_t xTimer );
|
||
|
|
||
|
/*
|
||
|
* Callback for a timer that is used by the prvTestNotifyTaskWhileSuspended()
|
||
|
* test.
|
||
|
*/
|
||
|
static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer );
|
||
|
|
||
|
/*
|
||
|
* Utility function to create pseudo random numbers.
|
||
|
*/
|
||
|
static UBaseType_t prvRand( void );
|
||
|
|
||
|
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
/* Counters used to check the task has not stalled. ulFineCycleCount is
|
||
|
* incremented within each test. ulCourseCycleCounter is incremented one every
|
||
|
* loop of all the tests to ensure each test is actually executing. The check task
|
||
|
* calls xAreTaskNotificationArrayTasksStillRunning() (implemented within this
|
||
|
* file) to check both counters are changing. */
|
||
|
static volatile uint32_t ulFineCycleCount = 0, ulCourseCycleCounter = 0;
|
||
|
|
||
|
/* The handle of the task that runs the tests and receives the notifications
|
||
|
* from the software timers and interrupts. */
|
||
|
static TaskHandle_t xTaskToNotify = NULL;
|
||
|
|
||
|
/* The software timers used to send notifications to the main test task. */
|
||
|
static TimerHandle_t xIncrementingIndexTimer = NULL;
|
||
|
static TimerHandle_t xNotifyWhileSuspendedTimer = NULL;
|
||
|
|
||
|
/* Used by the pseudo random number generating function. */
|
||
|
static size_t uxNextRand = 0;
|
||
|
|
||
|
/* Used to communicate when to send a task notification to the tick hook tests. */
|
||
|
static volatile BaseType_t xSendNotificationFromISR = pdFALSE;
|
||
|
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
void vStartTaskNotifyArrayTask( void )
|
||
|
{
|
||
|
const TickType_t xIncrementingIndexTimerPeriod = pdMS_TO_TICKS( 100 );
|
||
|
const TickType_t xSuspendTimerPeriod = pdMS_TO_TICKS( 50 );
|
||
|
|
||
|
/* Create the software timers used for these tests. The timer callbacks send
|
||
|
* notifications to this task. */
|
||
|
xNotifyWhileSuspendedTimer = xTimerCreate( "SingleNotify", xSuspendTimerPeriod, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback );
|
||
|
xIncrementingIndexTimer = xTimerCreate( "Notifier", xIncrementingIndexTimerPeriod, pdFALSE, NULL, prvNotifyingTimerCallback );
|
||
|
configASSERT( xNotifyWhileSuspendedTimer );
|
||
|
configASSERT( xIncrementingIndexTimer );
|
||
|
|
||
|
/* Create the task that performs some tests by itself, then loops around
|
||
|
* being notified by both a software timer and an interrupt. */
|
||
|
xTaskCreate( prvNotifiedTask, /* Function that implements the task. */
|
||
|
"ArrayNotified", /* Text name for the task - for debugging only - not used by the kernel. */
|
||
|
notifyNOTIFY_ARRAY_TASK_STACK_SIZE, /* Task's stack size in words, not bytes!. */
|
||
|
NULL, /* Task parameter, not used in this case. */
|
||
|
notifyTASK_PRIORITY, /* Task priority, 0 is the lowest. */
|
||
|
&xTaskToNotify ); /* Used to pass a handle to the task out if needed, otherwise set to NULL. */
|
||
|
|
||
|
/* Pseudo seed the random number generator. */
|
||
|
uxNextRand = ( size_t ) prvRand;
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvNotifiedTask( void * pvParameters )
|
||
|
{
|
||
|
/* Remove compiler warnings about unused parameters. */
|
||
|
( void ) pvParameters;
|
||
|
|
||
|
/* Loop through each set of test functions in turn. See the comments above
|
||
|
* the respective function prototypes above for more details. */
|
||
|
for( ; ; )
|
||
|
{
|
||
|
prvSingleTaskTests();
|
||
|
prvTestNotifyTaskWhileSuspended();
|
||
|
prvBlockOnTheNotifiedIndexed();
|
||
|
prvBlockOnANonNotifiedIndexed();
|
||
|
prvBlockOnNotificationsComingFromInterrupts();
|
||
|
ulCourseCycleCounter++;
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvSingleTaskTests( void )
|
||
|
{
|
||
|
const TickType_t xTicksToWait = pdMS_TO_TICKS( 100UL );
|
||
|
BaseType_t xReturned;
|
||
|
uint32_t ulNotifiedValue, ulLoop, ulNotifyingValue, ulPreviousValue, ulExpectedValue;
|
||
|
TickType_t xTimeOnEntering, xTimeNow, xTimeDifference;
|
||
|
const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;
|
||
|
const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;
|
||
|
UBaseType_t uxIndexToTest, uxOtherIndexes;
|
||
|
|
||
|
|
||
|
/* ------------------------------------------------------------------------
|
||
|
* Check blocking when there are no notifications. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* Send notifications to the task notification in each index of the
|
||
|
* task notification array other than the one on which this task will
|
||
|
* block. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
if( uxOtherIndexes != uxIndexToTest )
|
||
|
{
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxOtherIndexes, 0, eNoAction );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
xTimeOnEntering = xTaskGetTickCount();
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* Should have blocked for the entire block time. */
|
||
|
xTimeNow = xTaskGetTickCount();
|
||
|
xTimeDifference = xTimeNow - xTimeOnEntering;
|
||
|
configASSERT( xTimeDifference >= xTicksToWait );
|
||
|
configASSERT( xReturned == pdFAIL );
|
||
|
configASSERT( ulNotifiedValue == 0UL );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
( void ) ulNotifiedValue;
|
||
|
|
||
|
/* Clear all the other notifications within the array of task
|
||
|
* notifications again ready for the next round. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
if( uxOtherIndexes != uxIndexToTest )
|
||
|
{
|
||
|
xReturned = xTaskNotifyStateClearIndexed( xTaskToNotify, uxOtherIndexes );
|
||
|
|
||
|
/* The notification state was set above so expect it to still be
|
||
|
* set. */
|
||
|
configASSERT( xReturned == pdTRUE );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ------------------------------------------------------------------------
|
||
|
* Check no blocking when notifications are pending. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* First notify the task notification at index uxIndexToTest within this
|
||
|
* task's own array of task notifications - this would not be a normal
|
||
|
* thing to do and is done here for test purposes only. */
|
||
|
xReturned = xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
|
||
|
|
||
|
/* Even through the 'without overwrite' action was used the update should
|
||
|
* have been successful. */
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* No bits should have been pending previously. */
|
||
|
configASSERT( ulPreviousValue == 0 );
|
||
|
( void ) ulPreviousValue;
|
||
|
|
||
|
/* The task should now have a notification pending in the task
|
||
|
* notification at index uxIndexToTest within the task notification array,
|
||
|
* and so not time out. */
|
||
|
xTimeOnEntering = xTaskGetTickCount();
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
|
||
|
xTimeNow = xTaskGetTickCount();
|
||
|
xTimeDifference = xTimeNow - xTimeOnEntering;
|
||
|
configASSERT( xTimeDifference < xTicksToWait );
|
||
|
|
||
|
/* The task should have been notified, and the notified value should
|
||
|
* be equal to ulFirstNotifiedConst. */
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
( void ) ulNotifiedValue;
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* Check the non-overwriting functionality. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* Send notifications to all indexes with the array of task
|
||
|
* notifications other than the one on which this task will block. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
if( uxOtherIndexes != uxIndexToTest )
|
||
|
{
|
||
|
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxOtherIndexes, ulFirstNotifiedConst, eSetValueWithOverwrite );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* The notification is performed twice using two different notification
|
||
|
* values. The action says don't overwrite so only the first notification
|
||
|
* should pass and the value read back should also be that used with the
|
||
|
* first notification. The notification is sent to the task notification at
|
||
|
* index uxIndexToTest within the array of task notifications. */
|
||
|
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );
|
||
|
configASSERT( xReturned == pdFAIL );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* Waiting for the notification should now return immediately so a block
|
||
|
* time of zero is used. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||
|
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
( void ) ulNotifiedValue;
|
||
|
|
||
|
/* Clear all the other task notifications within the array of task
|
||
|
* notifications again ready for the next round. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
if( uxOtherIndexes != uxIndexToTest )
|
||
|
{
|
||
|
xReturned = xTaskNotifyStateClearIndexed( xTaskToNotify, uxOtherIndexes );
|
||
|
configASSERT( xReturned == pdTRUE );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
ulNotifiedValue = ulTaskNotifyValueClearIndexed( xTaskToNotify, uxOtherIndexes, notifyUINT32_MAX );
|
||
|
|
||
|
/* The notification value was set to ulFirstNotifiedConst in all
|
||
|
* the other indexes, so expect it to still have that value. */
|
||
|
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* Do the same again, only this time use the overwriting version. This time
|
||
|
* both notifications should pass, and the value written the second time should
|
||
|
* overwrite the value written the first time, and so be the value that is read
|
||
|
* back. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
if( uxOtherIndexes != uxIndexToTest )
|
||
|
{
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxOtherIndexes, ulFirstNotifiedConst, eSetValueWithOverwrite );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithOverwrite );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, notifyUINT32_MAX, &ulNotifiedValue, 0 );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
|
||
|
( void ) ulNotifiedValue;
|
||
|
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
if( uxOtherIndexes != uxIndexToTest )
|
||
|
{
|
||
|
xReturned = xTaskNotifyStateClearIndexed( xTaskToNotify, uxOtherIndexes );
|
||
|
configASSERT( xReturned == pdTRUE );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
ulNotifiedValue = ulTaskNotifyValueClearIndexed( xTaskToNotify, uxOtherIndexes, notifyUINT32_MAX );
|
||
|
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* For each task notification within the array of task notifications, check
|
||
|
* notifications with no action pass without updating the value. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* First set the notification values of the task notification at index
|
||
|
* uxIndexToTest of the array of task notification to
|
||
|
* ulSecondNotifiedValueConst. */
|
||
|
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* Even though ulFirstNotifiedConst is used as the value next, the value
|
||
|
* read back should remain at ulSecondNotifiedConst as the action is set
|
||
|
* to eNoAction. */
|
||
|
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eNoAction );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* All task notifications in the array of task notifications up to and
|
||
|
* including index uxIndexToTest should still contain the same value. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ )
|
||
|
{
|
||
|
/* First zero is bits to clear on entry, the second is bits to clear on
|
||
|
* exist, the last 0 is the block time. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
|
||
|
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* All array indexes in the array of task notifications after index
|
||
|
* uxIndexToTest should still contain 0 as they have not been set in this
|
||
|
* loop yet. This time use ulTaskNotifyValueClearIndexed() instead of
|
||
|
* xTaskNotifyWaitIndexed(), just for test coverage. */
|
||
|
for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
/* This time 0 is the bits to clear parameter - so clearing no bits. */
|
||
|
ulNotifiedValue = ulTaskNotifyValueClearIndexed( NULL, uxOtherIndexes, 0 );
|
||
|
configASSERT( ulNotifiedValue == 0 );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* Check incrementing values. For each task notification in the array of task
|
||
|
* notifications in turn, send ulMaxLoop increment notifications, then ensure
|
||
|
* the received value is as expected - which should be
|
||
|
* ulSecondNotificationValueConst plus how ever many times to loop iterated. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
|
||
|
{
|
||
|
/* Increment the value of the task notification at index
|
||
|
* uxIndexToTest within the array of task notifications. */
|
||
|
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, 0, eIncrement );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* All array indexes up to and including uxIndexToTest should still
|
||
|
* contain the updated value. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ )
|
||
|
{
|
||
|
/* First zero is bits to clear on entry, the second is bits to clear on
|
||
|
* exist, the last 0 is the block time. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
|
||
|
configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* Should not be any notifications pending now. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, 0 );
|
||
|
configASSERT( xReturned == pdFAIL );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
( void ) ulNotifiedValue;
|
||
|
|
||
|
/* All notifications values in the array of task notifications after
|
||
|
* index uxIndexToTest should still contain the un-incremented
|
||
|
* ulSecondNotifiedValueConst as they have not been set in this loop yet.
|
||
|
* This time use ulTaskNotifyValueClearIndexed() instead of xTaskNotifyWaitIndexed(),
|
||
|
* just for test coverage. */
|
||
|
for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
/* This time 0 is the bits to clear parameter - so clearing no bits. */
|
||
|
ulNotifiedValue = ulTaskNotifyValueClearIndexed( NULL, uxOtherIndexes, 0 );
|
||
|
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Clear all bits ready for next test. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* Start with all bits clear. */
|
||
|
ulTaskNotifyValueClearIndexed( NULL, uxIndexToTest, notifyUINT32_MAX );
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* For each task notification in the array of task notifications in turn, check
|
||
|
* all bits in the notification's value can be set by notifying the task with
|
||
|
* one additional bit set on each notification, and exiting the loop when all
|
||
|
* the bits are found to be set. As there are 32-bits the loop should execute
|
||
|
* 32 times before all the bits are found to be set. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
ulNotifyingValue = 0x01;
|
||
|
ulLoop = 0;
|
||
|
|
||
|
do
|
||
|
{
|
||
|
/* Set the next bit in the value of the task notification at index
|
||
|
* uxIndexToTest within the array of task notifications. */
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulNotifyingValue, eSetBits );
|
||
|
|
||
|
/* Wait for the notified value - which of course will already be
|
||
|
* available. Don't clear the bits on entry or exit as this loop is
|
||
|
* exited when all the bits are set. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, 0 );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
ulLoop++;
|
||
|
|
||
|
/* Use the next bit on the next iteration around this loop. */
|
||
|
ulNotifyingValue <<= 1UL;
|
||
|
} while( ulNotifiedValue != notifyUINT32_MAX );
|
||
|
|
||
|
/* As a 32-bit value was used the loop should have executed 32 times before
|
||
|
* all the bits were set. */
|
||
|
configASSERT( ulLoop == 32 );
|
||
|
|
||
|
/* The value of each task notification within the array of task
|
||
|
* notifications up to and including index uxIndexToTest should still have
|
||
|
* all bits set. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ )
|
||
|
{
|
||
|
/* First zero is bits to clear on entry, the second is bits to clear on
|
||
|
* exist, the last 0 is the block time. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
|
||
|
configASSERT( ulNotifiedValue == notifyUINT32_MAX );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* The value of each task notification within the array of task
|
||
|
* notifications after index uxIndexToTest should still contain 0 as they
|
||
|
* have not been set in this loop yet. This time use ulTaskNotifyValueClearIndexed()
|
||
|
* instead of xTaskNotifyWaitIndexed(), just for test coverage. */
|
||
|
for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
/* This time 0 is the bits to clear parameter - so clearing no bits. */
|
||
|
ulNotifiedValue = ulTaskNotifyValueClearIndexed( NULL, uxOtherIndexes, 0 );
|
||
|
configASSERT( ulNotifiedValue == 0 );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* For each task notification within the array of task notifications in turn,
|
||
|
* check bits are cleared on entry but not on exit when a notification fails
|
||
|
* to arrive before timing out - both with and without a timeout value. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* Wait for the notification - but this time it is not given by anything
|
||
|
* and should return pdFAIL. The parameters are set to clear bit zero on
|
||
|
* entry and bit one on exit. As no notification was received only the bit
|
||
|
* cleared on entry should actually get cleared. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
|
||
|
configASSERT( xReturned == pdFAIL );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* Send a notification with no action to the task notification at index
|
||
|
* uxIndexToTest within the array of task notifications. This should not
|
||
|
* update the bits even though notifyUINT32_MAX is used as the notification
|
||
|
* value. */
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX, eNoAction );
|
||
|
|
||
|
/* All array indexes up to and including uxIndexToTest within the array
|
||
|
* of task notifications should have the modified value. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ )
|
||
|
{
|
||
|
/* Reading back the value should find bit 0 is clear, as this was cleared
|
||
|
* on entry, but bit 1 is not clear as it will not have been cleared on exit
|
||
|
* as no notification was received. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
|
||
|
|
||
|
if( uxOtherIndexes == uxIndexToTest )
|
||
|
{
|
||
|
/* This is the index being used this time round the loop and its
|
||
|
* notification state was set immediately above. */
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Nothing should have set this index's notification state again. */
|
||
|
configASSERT( xReturned == pdFAIL );
|
||
|
}
|
||
|
|
||
|
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* All array indexes after uxIndexToTest should still contain notifyUINT32_MAX
|
||
|
* left over from the previous test. This time use xTaskNotifyValueClear()
|
||
|
* instead of xTaskNotifyWaitIndexed(), just for test coverage. */
|
||
|
for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
/* This time 0 is the bits to clear parameter - so clearing no bits. */
|
||
|
ulNotifiedValue = ulTaskNotifyValueClearIndexed( NULL, uxOtherIndexes, 0 );
|
||
|
configASSERT( ulNotifiedValue == notifyUINT32_MAX );
|
||
|
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* Now try clearing the bit on exit. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* The task is notified first using the task notification at index
|
||
|
* uxIndexToTest within the array of task notifications. */
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, 0, eNoAction );
|
||
|
xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, ulBit1, &ulNotifiedValue, 0 );
|
||
|
|
||
|
/* However as the bit is cleared on exit, after the returned notification
|
||
|
* value is set, the returned notification value should not have the bit
|
||
|
* cleared... */
|
||
|
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
|
||
|
|
||
|
/* ...but reading the value back again should find that the bit was indeed
|
||
|
* cleared internally. The returned value should be pdFAIL however as nothing
|
||
|
* has notified the task in the mean time. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, 0x00, &ulNotifiedValue, 0 );
|
||
|
configASSERT( xReturned == pdFAIL );
|
||
|
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* No other indexes should have a notification pending. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
if( uxOtherIndexes != uxIndexToTest )
|
||
|
{
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
|
||
|
configASSERT( xReturned == pdFAIL );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/*-------------------------------------------------------------------------
|
||
|
* For each task notification within the array of task notifications, try
|
||
|
* querying the previous value while notifying a task. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, 0x00, eSetBits, &ulPreviousValue );
|
||
|
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
|
||
|
|
||
|
/* Clear all bits. */
|
||
|
xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, notifyUINT32_MAX, &ulNotifiedValue, 0 );
|
||
|
xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, 0x00, eSetBits, &ulPreviousValue );
|
||
|
configASSERT( ulPreviousValue == 0 );
|
||
|
|
||
|
ulExpectedValue = 0;
|
||
|
|
||
|
for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )
|
||
|
{
|
||
|
/* Set the next bit up, and expect to receive the last bits set (so
|
||
|
* the previous value will not yet have the bit being set this time
|
||
|
* around). */
|
||
|
xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulLoop, eSetBits, &ulPreviousValue );
|
||
|
configASSERT( ulExpectedValue == ulPreviousValue );
|
||
|
ulExpectedValue |= ulLoop;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ---------------------------------------------------------------------- */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* Clear the previous notifications. */
|
||
|
xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
|
||
|
}
|
||
|
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* No task notification within the array of task notifications should
|
||
|
* have any notification pending, so an attempt to clear the notification
|
||
|
* state should fail. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
configASSERT( xTaskNotifyStateClearIndexed( NULL, uxOtherIndexes ) == pdFALSE );
|
||
|
}
|
||
|
|
||
|
/* Get the task to notify itself using the task notification at index
|
||
|
* uxIndexToTest within the array of task notifications. This is not a
|
||
|
* normal thing to do, and is only done here for test purposes. */
|
||
|
xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
|
||
|
|
||
|
/* Now the notification state should be eNotified, so it should now be
|
||
|
* possible to clear the notification state. Other indexes should still
|
||
|
* not have a notification pending - likewise uxIndexToTest should not have
|
||
|
* a notification pending once it has been cleared. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
if( uxOtherIndexes == uxIndexToTest )
|
||
|
{
|
||
|
configASSERT( xTaskNotifyStateClearIndexed( NULL, uxOtherIndexes ) == pdTRUE );
|
||
|
}
|
||
|
|
||
|
configASSERT( xTaskNotifyStateClearIndexed( NULL, uxOtherIndexes ) == pdFALSE );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* ------------------------------------------------------------------------
|
||
|
* For each task notification within the array of task notifications, clear
|
||
|
* bits in the notification value. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* Get the task to set all bits in its task notification at index
|
||
|
* uxIndexToTest within its array of task notifications. This is not a
|
||
|
* normal thing to do, and is only done here for test purposes. */
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX, eSetBits );
|
||
|
|
||
|
/* Now clear the top bytes - the returned value from the first call
|
||
|
* should indicate that previously all bits were set. */
|
||
|
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_HIGH_BYTE ) == notifyUINT32_MAX );
|
||
|
|
||
|
/* Next clear the bottom bytes - the returned value this time should
|
||
|
* indicate that the top byte was clear (before the bottom byte was
|
||
|
* cleared. */
|
||
|
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_LOW_BYTE ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE ) );
|
||
|
|
||
|
/* Next clear all bytes - the returned value should indicate that previously the
|
||
|
* high and low bytes were clear. */
|
||
|
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) );
|
||
|
|
||
|
/* Now all bits should be clear. */
|
||
|
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == 0 );
|
||
|
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, 0UL ) == 0 );
|
||
|
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == 0 );
|
||
|
|
||
|
/* Now the notification state should be eNotified, so it should now be
|
||
|
* possible to clear the notification state. */
|
||
|
configASSERT( xTaskNotifyStateClearIndexed( NULL, uxIndexToTest ) == pdTRUE );
|
||
|
configASSERT( xTaskNotifyStateClearIndexed( NULL, uxIndexToTest ) == pdFALSE );
|
||
|
}
|
||
|
|
||
|
/* Incremented to show the task is still running. */
|
||
|
ulFineCycleCount++;
|
||
|
|
||
|
/* Leave all bits cleared. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, NULL, 0 );
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer )
|
||
|
{
|
||
|
static uint32_t ulCallCount = 0;
|
||
|
static UBaseType_t uxIndexToNotify = 0;
|
||
|
|
||
|
/* Remove compiler warnings about unused parameters. */
|
||
|
( void ) xExpiredTimer;
|
||
|
|
||
|
/* Callback for a timer that is used to send notifications to a task while
|
||
|
* it is suspended. The timer tests the behaviour when 1: a task waiting for a
|
||
|
* notification is suspended and then resumed without ever receiving a
|
||
|
* notification, and 2: when a task waiting for a notification receives a
|
||
|
* notification while it is suspended. Run one of two tests on every other
|
||
|
* invocation of this callback. The notification is sent to the task
|
||
|
* notification at index uxIndexToNotify. */
|
||
|
if( ( ulCallCount & 0x01 ) == 0 )
|
||
|
{
|
||
|
vTaskSuspend( xTaskToNotify );
|
||
|
configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
|
||
|
vTaskResume( xTaskToNotify );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
vTaskSuspend( xTaskToNotify );
|
||
|
|
||
|
/* Sending a notification while the task is suspended should pass, but
|
||
|
* not cause the task to resume. */
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, 1, eSetValueWithOverwrite );
|
||
|
|
||
|
/* Use the next task notification within the array of task notifications
|
||
|
* the next time around. */
|
||
|
uxIndexToNotify++;
|
||
|
|
||
|
if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES )
|
||
|
{
|
||
|
uxIndexToNotify = 0;
|
||
|
}
|
||
|
|
||
|
/* Make sure giving the notification didn't resume the task. */
|
||
|
configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
|
||
|
|
||
|
vTaskResume( xTaskToNotify );
|
||
|
}
|
||
|
|
||
|
ulCallCount++;
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvNotifyingTimerCallback( TimerHandle_t xNotUsed )
|
||
|
{
|
||
|
static BaseType_t uxIndexToNotify = 0;
|
||
|
|
||
|
( void ) xNotUsed;
|
||
|
|
||
|
/* "Give" the task notification (which increments the target task
|
||
|
* notification value) at index uxIndexToNotify within the array of task
|
||
|
* notifications. */
|
||
|
xTaskNotifyGiveIndexed( xTaskToNotify, uxIndexToNotify );
|
||
|
|
||
|
/* Use the next task notification within the array of task notifications the
|
||
|
* next time around. */
|
||
|
uxIndexToNotify++;
|
||
|
|
||
|
if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES )
|
||
|
{
|
||
|
uxIndexToNotify = 0;
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static void prvTestNotifyTaskWhileSuspended( void )
|
||
|
{
|
||
|
UBaseType_t uxIndexToTest, uxOtherIndexes;
|
||
|
BaseType_t xReturned;
|
||
|
uint32_t ulNotifiedValue;
|
||
|
|
||
|
/* Raise the task's priority so it can suspend itself before the timer
|
||
|
* expires. */
|
||
|
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
|
||
|
|
||
|
/* Perform the test on each task notification within the array or task
|
||
|
* notifications. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
/* Ensure no notifications within the array of task notifications are
|
||
|
* pending. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, NULL, 0 );
|
||
|
configASSERT( xReturned == pdFALSE );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* Start the timer that will try notifying this task while it is
|
||
|
* suspended, then wait for a notification. The first time the callback
|
||
|
* executes the timer will suspend the task, then resume the task, without
|
||
|
* ever sending a notification to the task. */
|
||
|
ulNotifiedValue = 0;
|
||
|
xTimerStart( xNotifyWhileSuspendedTimer, portMAX_DELAY );
|
||
|
|
||
|
/* Check a notification is not received on the task notification at
|
||
|
* index uxIndexToTest within the array of task notifications. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, portMAX_DELAY );
|
||
|
configASSERT( xReturned == pdFALSE );
|
||
|
configASSERT( ulNotifiedValue == 0 );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* Check none of the task notifications within the array of task
|
||
|
* notifications as been notified. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
|
||
|
configASSERT( xReturned == pdFALSE );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
}
|
||
|
|
||
|
/* Start the timer that will try notifying this task while it is
|
||
|
* suspended, then wait for a notification at index uxIndexToTest within
|
||
|
* the array of task notifications. The second time the callback executes
|
||
|
* the timer will suspend the task, notify the task, then resume the task
|
||
|
* (previously it was suspended and resumed without being notified). */
|
||
|
xTimerStart( xNotifyWhileSuspendedTimer, portMAX_DELAY );
|
||
|
|
||
|
/* Check a notification is only received in the index within the array
|
||
|
* of task notifications under test. */
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, portMAX_DELAY );
|
||
|
configASSERT( xReturned == pdPASS );
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
configASSERT( ulNotifiedValue != 0 );
|
||
|
|
||
|
/* Check a notification is not received in any index within the array
|
||
|
* of task notifications at and below the index being tested have a notification
|
||
|
* value, and that indexes above the index being tested to not have
|
||
|
* notification values. */
|
||
|
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
|
||
|
{
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
|
||
|
configASSERT( xReturned == pdFALSE );
|
||
|
|
||
|
if( uxOtherIndexes <= uxIndexToTest )
|
||
|
{
|
||
|
configASSERT( ulNotifiedValue == 1 );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
configASSERT( ulNotifiedValue == 0 );
|
||
|
}
|
||
|
|
||
|
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
( void ) ulNotifiedValue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Return the task to its proper priority */
|
||
|
vTaskPrioritySet( NULL, notifyTASK_PRIORITY );
|
||
|
|
||
|
/* Incremented to show the task is still running. */
|
||
|
ulFineCycleCount++;
|
||
|
|
||
|
/* Leave all bits cleared. */
|
||
|
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
|
||
|
{
|
||
|
xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, NULL, 0 );
|
||
|
}
|
||
|
}
|
||
|
/* ------------------------------------------------------------------------ */
|
||
|
|
||
|
static void prvBlockOnTheNotifiedIndexed( void )
|
||
|
{
|
||
|
const TickType_t xTimerPeriod = pdMS_TO_TICKS( 100 ), xMargin = pdMS_TO_TICKS( 50 ), xDontBlock = 0;
|
||
|
UBaseType_t uxIndex, uxIndexToNotify;
|
||
|
uint32_t ulReceivedValue;
|
||
|
BaseType_t xReturned;
|
||
|
|
||
|
/* Set the value of each notification in the array of task notifications to
|
||
|
* the value of its index position plus 1 so everything starts in a known
|
||
|
* state, then clear the notification state ready for the next test. Plus 1 is
|
||
|
* used because the index under test will use 0. */
|
||
|
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
|
||
|
{
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndex, uxIndex + 1, eSetValueWithOverwrite );
|
||
|
xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndex );
|
||
|
}
|
||
|
|
||
|
/* Perform the test on each task notification within the array of task
|
||
|
* notifications. */
|
||
|
for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ )
|
||
|
{
|
||
|
/* Set the notification value of the index being tested to 0 so the
|
||
|
* notification value increment/decrement functions can be tested. */
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, 0, eSetValueWithOverwrite );
|
||
|
xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndexToNotify );
|
||
|
|
||
|
/* Start the software timer then wait for it to notify this task. Block
|
||
|
* on the notification index we expect to receive the notification on. The
|
||
|
* margin is to ensure the task blocks longer than the timer period. */
|
||
|
xTimerStart( xIncrementingIndexTimer, portMAX_DELAY );
|
||
|
ulReceivedValue = ulTaskNotifyTakeIndexed( uxIndexToNotify, pdFALSE, xTimerPeriod + xMargin );
|
||
|
|
||
|
/* The notification value was initially zero, and should have been
|
||
|
* incremented by the software timer, so now one. It will also have been
|
||
|
* decremented again by the call to ulTaskNotifyTakeIndexed() so gone back
|
||
|
* to 0. */
|
||
|
configASSERT( ulReceivedValue == 1UL );
|
||
|
( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* No other notification indexes should have changed, and therefore should
|
||
|
* still have their value set to their index plus 1 within the array of
|
||
|
* notifications. */
|
||
|
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
|
||
|
{
|
||
|
if( uxIndex != uxIndexToNotify )
|
||
|
{
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xDontBlock );
|
||
|
configASSERT( xReturned == pdFALSE );
|
||
|
configASSERT( ulReceivedValue == ( uxIndex + 1 ) );
|
||
|
( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
( void ) xReturned;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Reset the notification value for the index just tested back to the
|
||
|
* index value plus 1 ready for the next iteration around this loop. */
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, uxIndexToNotify + 1, eSetValueWithOverwrite );
|
||
|
xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndexToNotify );
|
||
|
|
||
|
/* Incremented to show the task is still running. */
|
||
|
ulFineCycleCount++;
|
||
|
}
|
||
|
}
|
||
|
/* ------------------------------------------------------------------------ */
|
||
|
|
||
|
static void prvBlockOnANonNotifiedIndexed( void )
|
||
|
{
|
||
|
const TickType_t xTimerPeriod = pdMS_TO_TICKS( 100 ), xMargin = pdMS_TO_TICKS( 50 ), xDontBlock = 0;
|
||
|
UBaseType_t uxIndex, uxIndexToNotify;
|
||
|
uint32_t ulReceivedValue;
|
||
|
BaseType_t xReturned;
|
||
|
TickType_t xTimeBeforeBlocking, xTimeNow, xTimeDifference;
|
||
|
|
||
|
/* Set all notify values within the array of tasks notifications to zero
|
||
|
* ready for the next test. */
|
||
|
for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ )
|
||
|
{
|
||
|
ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToNotify, notifyUINT32_MAX );
|
||
|
}
|
||
|
|
||
|
/* Perform the test for each notification within the array of task
|
||
|
* notifications. */
|
||
|
for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ )
|
||
|
{
|
||
|
/* Start the software timer then wait for it to notify this task. Block
|
||
|
* on a notification index that we do not expect to receive the notification
|
||
|
* on. The margin is to ensure the task blocks longer than the timer period. */
|
||
|
xTimerStart( xIncrementingIndexTimer, portMAX_DELAY );
|
||
|
xTimeBeforeBlocking = xTaskGetTickCount();
|
||
|
|
||
|
if( uxIndexToNotify == ( configTASK_NOTIFICATION_ARRAY_ENTRIES - 1 ) )
|
||
|
{
|
||
|
/* configTASK_NOTIFICATION_ARRAY_ENTRIES - 1 is to be notified, so
|
||
|
* block on index 0. */
|
||
|
uxIndex = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* The next index to get notified will be uxIndexToNotify, so block
|
||
|
* on uxIndexToNotify + 1 */
|
||
|
uxIndex = uxIndexToNotify + 1;
|
||
|
}
|
||
|
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xTimerPeriod + xMargin );
|
||
|
|
||
|
/* The notification will have been sent to task notification at index
|
||
|
* uxIndexToNotify in this task by the timer callback after xTimerPeriodTicks.
|
||
|
* The notification should not have woken this task, so xReturned should
|
||
|
* be false and at least xTimerPeriod + xMargin ticks should have passed. */
|
||
|
configASSERT( xReturned == pdFALSE );
|
||
|
xTimeNow = xTaskGetTickCount();
|
||
|
xTimeDifference = xTimeNow - xTimeBeforeBlocking;
|
||
|
configASSERT( xTimeDifference >= ( xTimerPeriod + xMargin ) );
|
||
|
( void ) xReturned; /* Remove compiler warnings if configASSERT() is not defined. */
|
||
|
( void ) xTimeBeforeBlocking;
|
||
|
( void ) xTimeDifference;
|
||
|
|
||
|
/* Only the notification at index position uxIndexToNotify should be
|
||
|
* set. Calling this function will clear it again. */
|
||
|
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
|
||
|
{
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xDontBlock );
|
||
|
|
||
|
if( uxIndex == uxIndexToNotify )
|
||
|
{
|
||
|
/* Expect the notification state to be set and the notification
|
||
|
* value to have been incremented. */
|
||
|
configASSERT( xReturned == pdTRUE );
|
||
|
configASSERT( ulReceivedValue == 1 );
|
||
|
|
||
|
/* Set the notification value for this array index back to 0. */
|
||
|
ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndex, notifyUINT32_MAX );
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Expect the notification state to be clear and the notification
|
||
|
* value to remain at zer0. */
|
||
|
configASSERT( xReturned == pdFALSE );
|
||
|
configASSERT( ulReceivedValue == 0 );
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/* Incremented to show the task is still running. */
|
||
|
ulFineCycleCount++;
|
||
|
}
|
||
|
}
|
||
|
/* ------------------------------------------------------------------------ */
|
||
|
|
||
|
static void prvBlockOnNotificationsComingFromInterrupts( void )
|
||
|
{
|
||
|
UBaseType_t uxIndex, uxIndexToNotify;
|
||
|
uint32_t ulReceivedValue;
|
||
|
BaseType_t xReturned;
|
||
|
const TickType_t xDontBlock = 0;
|
||
|
|
||
|
/* Set the value of each notification within the array of task notifications
|
||
|
* to zero so the task can block on xTaskNotifyTake(). */
|
||
|
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
|
||
|
{
|
||
|
xTaskNotifyIndexed( xTaskToNotify, uxIndex, 0, eSetValueWithOverwrite );
|
||
|
xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndex );
|
||
|
}
|
||
|
|
||
|
/* Perform the test on each task notification within the array of task
|
||
|
* notifications. */
|
||
|
for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ )
|
||
|
{
|
||
|
/* Tell the interrupt to send the next notification. */
|
||
|
taskENTER_CRITICAL();
|
||
|
{
|
||
|
/* Don't expect to find xSendNotificationFromISR set at this time as
|
||
|
* the interrupt should have cleared it back to pdFALSE last time it
|
||
|
* executed. */
|
||
|
configASSERT( xSendNotificationFromISR == pdFALSE );
|
||
|
xSendNotificationFromISR = pdTRUE;
|
||
|
}
|
||
|
taskEXIT_CRITICAL();
|
||
|
|
||
|
/* Wait for a notification on the task notification at index
|
||
|
* uxIndexToNotify within the array of task notifications. */
|
||
|
ulReceivedValue = ulTaskNotifyTakeIndexed( uxIndexToNotify, pdTRUE, portMAX_DELAY );
|
||
|
|
||
|
/* Interrupt should have reset xSendNotificationFromISR after it sent
|
||
|
* the notification. */
|
||
|
configASSERT( xSendNotificationFromISR == pdFALSE );
|
||
|
|
||
|
/* The notification value was initially zero, and should have been
|
||
|
* incremented by the interrupt, so now one. */
|
||
|
configASSERT( ulReceivedValue == 1UL );
|
||
|
( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
|
||
|
/* No other notification indexes should have changed, and therefore should
|
||
|
* still have their value set to 0. The value in array index uxIndexToNotify
|
||
|
* should also have been decremented back to zero by the call to
|
||
|
* ulTaskNotifyTakeIndexed(). */
|
||
|
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
|
||
|
{
|
||
|
xReturned = xTaskNotifyWaitIndexed( uxIndexToNotify, 0, 0, &ulReceivedValue, xDontBlock );
|
||
|
configASSERT( xReturned == pdFALSE );
|
||
|
configASSERT( ulReceivedValue == 0 );
|
||
|
( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
|
||
|
( void ) xReturned;
|
||
|
}
|
||
|
|
||
|
/* Incremented to show the task is still running. */
|
||
|
ulFineCycleCount++;
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
void xNotifyArrayTaskFromISR( void )
|
||
|
{
|
||
|
static BaseType_t xAPIToUse = 0;
|
||
|
uint32_t ulPreviousValue;
|
||
|
const uint32_t ulUnexpectedValue = 0xff;
|
||
|
static UBaseType_t uxIndexToNotify = 0;
|
||
|
|
||
|
/* Check the task notification demo task was actually created. */
|
||
|
configASSERT( xTaskToNotify );
|
||
|
|
||
|
/* The task sets xSendNotificationFromISR to pdTRUE each time it wants this
|
||
|
* interrupt (this function runs in the RTOS tick hook) to send the next
|
||
|
* notification. */
|
||
|
if( xSendNotificationFromISR == pdTRUE )
|
||
|
{
|
||
|
xSendNotificationFromISR = pdFALSE;
|
||
|
|
||
|
/* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
|
||
|
* and xTaskNotifyAndQueryFromISR(). The notification is set to the task
|
||
|
* notification at index uxIndexToNotify within the array of task
|
||
|
* notifications. */
|
||
|
switch( xAPIToUse )
|
||
|
{
|
||
|
case 0:
|
||
|
vTaskNotifyGiveIndexedFromISR( xTaskToNotify, uxIndexToNotify, NULL );
|
||
|
xAPIToUse++;
|
||
|
break;
|
||
|
|
||
|
case 1:
|
||
|
xTaskNotifyIndexedFromISR( xTaskToNotify, uxIndexToNotify, 0, eIncrement, NULL );
|
||
|
xAPIToUse++;
|
||
|
break;
|
||
|
|
||
|
case 2:
|
||
|
ulPreviousValue = ulUnexpectedValue;
|
||
|
xTaskNotifyAndQueryIndexedFromISR( xTaskToNotify, uxIndexToNotify, 0, eIncrement, &ulPreviousValue, NULL );
|
||
|
configASSERT( ulPreviousValue == 0 );
|
||
|
xAPIToUse = 0;
|
||
|
break;
|
||
|
|
||
|
default: /* Should never get here!. */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* Use the next index in the array of task notifications the next time
|
||
|
* around. */
|
||
|
uxIndexToNotify++;
|
||
|
|
||
|
if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES )
|
||
|
{
|
||
|
uxIndexToNotify = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
/* This is called to check the created tasks are still running and have not
|
||
|
* detected any errors. */
|
||
|
BaseType_t xAreTaskNotificationArrayTasksStillRunning( void )
|
||
|
{
|
||
|
static uint32_t ulLastFineCycleCount = 0, ulLastCourseCycleCount = 0, ulCallCount = 0;
|
||
|
const uint32_t ulCallsBetweenCourseCycleCountChecks = 3UL;
|
||
|
static BaseType_t xErrorStatus = pdPASS;
|
||
|
|
||
|
/* Check the cycle count is still incrementing to ensure the task is still
|
||
|
* actually running. The fine counter is incremented within individual test
|
||
|
* functions. The course counter is incremented one each time all the test
|
||
|
* functions have been executed to ensure all the tests are running. */
|
||
|
if( ulLastFineCycleCount == ulFineCycleCount )
|
||
|
{
|
||
|
xErrorStatus = pdFAIL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ulLastFineCycleCount = ulFineCycleCount;
|
||
|
}
|
||
|
|
||
|
ulCallCount++;
|
||
|
|
||
|
if( ulCallCount >= ulCallsBetweenCourseCycleCountChecks )
|
||
|
{
|
||
|
ulCallCount = 0;
|
||
|
|
||
|
if( ulLastCourseCycleCount == ulCourseCycleCounter )
|
||
|
{
|
||
|
xErrorStatus = pdFAIL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
ulLastCourseCycleCount = ulCourseCycleCounter;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return xErrorStatus;
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|
||
|
|
||
|
static UBaseType_t prvRand( void )
|
||
|
{
|
||
|
const size_t uxMultiplier = ( size_t ) 0x015a4e35, uxIncrement = ( size_t ) 1;
|
||
|
|
||
|
/* Utility function to generate a pseudo random number. */
|
||
|
uxNextRand = ( uxMultiplier * uxNextRand ) + uxIncrement;
|
||
|
return( ( uxNextRand >> 16 ) & ( ( size_t ) 0x7fff ) );
|
||
|
}
|
||
|
/*-----------------------------------------------------------*/
|