EBIKE-FreeRTOS/Common/Minimal/TaskNotify.c
2024-04-14 18:38:39 +08:00

721 lines
29 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 direct task notifications.
*/
/* Standard includes. */
#include <limits.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "timers.h"
/* Demo program include files. */
#include "TaskNotify.h"
/* Allow parameters to be overridden on a demo by demo basis. */
#ifndef notifyNOTIFIED_TASK_STACK_SIZE
#define notifyNOTIFIED_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 )
#define notifySUSPENDED_TEST_TIMER_PERIOD pdMS_TO_TICKS( 50 )
/*-----------------------------------------------------------*/
/*
* Implementation of the task that gets notified.
*/
static void prvNotifiedTask( void * pvParameters );
/*
* Performs a few initial tests that can be done prior to creating the second
* task.
*/
static void prvSingleTaskTests( void );
/*
* Software timer callback function from which xTaskNotify() is called.
*/
static void prvNotifyingTimer( TimerHandle_t xTimer );
/*
* Utility function to create pseudo random numbers.
*/
static UBaseType_t prvRand( void );
/*
* Callback for a timer that is used during preliminary testing. 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.
*/
static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer );
/*-----------------------------------------------------------*/
/* Used to latch errors during the test's execution. */
static BaseType_t xErrorStatus = pdPASS;
/* Used to ensure the task has not stalled. */
static volatile uint32_t ulNotifyCycleCount = 0;
/* The handle of the task that receives the notifications. */
static TaskHandle_t xTaskToNotify = NULL;
/* Used to count the notifications sent to the task from a software timer and
* the number of notifications received by the task from the software timer. The
* two should stay synchronised. */
static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL;
/* The timer used to notify the task. */
static TimerHandle_t xTimer = NULL;
/* Used by the pseudo random number generating function. */
static size_t uxNextRand = 0;
/*-----------------------------------------------------------*/
void vStartTaskNotifyTask( void )
{
/* 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. */
"Notified", /* Text name for the task - for debugging only - not used by the kernel. */
notifyNOTIFIED_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 is needed, otherwise set to NULL. */
/* Pseudo seed the random number generator. */
uxNextRand = ( size_t ) prvRand;
}
/*-----------------------------------------------------------*/
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;
const uint32_t ulFirstNotifiedConst = 100001UL, ulSecondNotifiedValueConst = 5555UL, ulMaxLoops = 5UL;
const uint32_t ulBit0 = 0x01UL, ulBit1 = 0x02UL;
TimerHandle_t xSingleTaskTimer;
/* ------------------------------------------------------------------------
* Check blocking when there are no notifications. */
xTimeOnEntering = xTaskGetTickCount();
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
( void ) xReturned; /* In case configASSERT() is not defined. */
/* Should have blocked for the entire block time. */
if( ( xTaskGetTickCount() - xTimeOnEntering ) < xTicksToWait )
{
xErrorStatus = pdFAIL;
}
configASSERT( xReturned == pdFAIL );
configASSERT( ulNotifiedValue == 0UL );
( void ) xReturned; /* In case configASSERT() is not defined. */
( void ) ulNotifiedValue;
/* ------------------------------------------------------------------------
* Check no blocking when notifications are pending. First notify itself -
* this would not be a normal thing to do and is done here for test purposes
* only. */
xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
/* Even through the 'without overwrite' action was used the update should
* have been successful. */
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* 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, and so not time out. */
xTimeOnEntering = xTaskGetTickCount();
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
if( ( xTaskGetTickCount() - xTimeOnEntering ) >= xTicksToWait )
{
xErrorStatus = pdFAIL;
}
/* The task should have been notified, and the notified value should
* be equal to ulFirstNotifiedConst. */
configASSERT( xReturned == pdPASS );
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
( void ) xReturned; /* In case configASSERT() is not defined. */
( void ) ulNotifiedValue;
/* Incremented to show the task is still running. */
ulNotifyCycleCount++;
/*-------------------------------------------------------------------------
* Check the non-overwriting functionality. The notification is done 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. */
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithoutOverwrite );
configASSERT( xReturned == pdFAIL );
( void ) xReturned; /* In case configASSERT() is not defined. */
/* Waiting for the notification should now return immediately so a block
* time of zero is used. */
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS );
configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
( void ) xReturned; /* In case configASSERT() is not defined. */
( void ) ulNotifiedValue;
/*-------------------------------------------------------------------------
* 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. */
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
xReturned = xTaskNotify( xTaskToNotify, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
( void ) ulNotifiedValue;
/*-------------------------------------------------------------------------
* Check notifications with no action pass without updating the value. Even
* though ulFirstNotifiedConst is used as the value the value read back should
* remain at ulSecondNotifiedConst. */
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
( void ) ulNotifiedValue; /* In case configASSERT() is not defined. */
/*-------------------------------------------------------------------------
* Check incrementing values. 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( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
{
xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
}
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS );
configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
( void ) xReturned; /* In case configASSERT() is not defined. */
( void ) ulNotifiedValue;
/* Should not be any notifications pending now. */
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdFAIL );
( void ) xReturned; /* In case configASSERT() is not defined. */
( void ) ulNotifiedValue;
/*-------------------------------------------------------------------------
* Check all bits 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. */
ulNotifyingValue = 0x01;
ulLoop = 0;
/* Start with all bits clear. */
xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
do
{
/* Set the next bit in the task's notified value. */
xTaskNotify( xTaskToNotify, 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 = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* 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 );
/*-------------------------------------------------------------------------
* 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. Wait
* for the notification again - 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 = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
configASSERT( xReturned == pdFAIL );
( void ) xReturned; /* In case configASSERT() is not defined. */
/* Notify the task with no action so as not to update the bits even though
* notifyUINT32_MAX is used as the notification value. */
xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eNoAction );
/* Reading back the value should 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 = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS );
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
( void ) xReturned; /* In case configASSERT() is not defined. */
/*-------------------------------------------------------------------------
* Now try clearing the bit on exit. For that to happen a notification must be
* received, so the task is notified first. */
xTaskNotify( xTaskToNotify, 0, eNoAction );
xTaskNotifyWait( 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 = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdFAIL );
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
( void ) xReturned; /* In case configASSERT() is not defined. */
/*-------------------------------------------------------------------------
* Now try querying the previous value while notifying a task. */
xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
/* Clear all bits. */
xTaskNotifyWait( 0x00, notifyUINT32_MAX, &ulNotifiedValue, 0 );
xTaskNotifyAndQuery( xTaskToNotify, 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). */
xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );
configASSERT( ulExpectedValue == ulPreviousValue );
ulExpectedValue |= ulLoop;
}
/* ------------------------------------------------------------------------
* Clear the previous notifications. */
xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
/* The task should not have any notifications pending, so an attempt to clear
* the notification state should fail. */
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
/* Get the task to notify itself. This is not a normal thing to do, and is
* only done here for test purposes. */
xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
/* Now the notification state should be eNotified, so it should now be
* possible to clear the notification state. */
configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
/* ------------------------------------------------------------------------
* Clear bits in the notification value. */
/* Get the task to set all bits its own notification value. This is not a
* normal thing to do, and is only done here for test purposes. */
xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eSetBits );
/* Now clear the top bytes - the returned value from the first call should
* indicate that previously all bits were set. */
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, 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( ulTaskNotifyValueClear( xTaskToNotify, 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( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) );
/* Now all bits should be clear. */
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == 0 );
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, 0UL ) == 0 );
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == 0 );
/* Now the notification state should be eNotified, so it should now be
* possible to clear the notification state. */
configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
/* ------------------------------------------------------------------------
* Create a timer that will try notifying this task while it is suspended. */
xSingleTaskTimer = xTimerCreate( "SingleNotify", notifySUSPENDED_TEST_TIMER_PERIOD, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback );
configASSERT( xSingleTaskTimer );
/* Incremented to show the task is still running. */
ulNotifyCycleCount++;
/* Ensure no notifications are pending. */
xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
/* Raise the task's priority so it can suspend itself before the timer
* expires. */
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
/* 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( xSingleTaskTimer, portMAX_DELAY );
/* Check a notification is not received. */
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );
configASSERT( xReturned == pdFALSE );
configASSERT( ulNotifiedValue == 0 );
( void ) xReturned; /* In case configASSERT() is not defined. */
/* Incremented to show the task is still running. */
ulNotifyCycleCount++;
/* Start the timer that will try notifying this task while it is
* suspended, then wait for a notification. 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( xSingleTaskTimer, portMAX_DELAY );
/* Check a notification is received. */
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, portMAX_DELAY );
configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */
configASSERT( ulNotifiedValue != 0 );
/* Return the task to its proper priority and delete the timer as it is
* not used again. */
vTaskPrioritySet( NULL, notifyTASK_PRIORITY );
xTimerDelete( xSingleTaskTimer, portMAX_DELAY );
/* Incremented to show the task is still running. */
ulNotifyCycleCount++;
/* Leave all bits cleared. */
xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
}
/*-----------------------------------------------------------*/
static void prvSuspendedTaskTimerTestCallback( TimerHandle_t xExpiredTimer )
{
static uint32_t ulCallCount = 0;
/* Remove compiler warnings about unused parameters. */
( void ) xExpiredTimer;
/* Callback for a timer that is used during preliminary testing. 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. */
if( ulCallCount == 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. ulCallCount is just used as a convenient
* non-zero value. */
xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite );
/* Make sure giving the notification didn't resume the task. */
configASSERT( eTaskGetState( xTaskToNotify ) == eSuspended );
vTaskResume( xTaskToNotify );
}
ulCallCount++;
}
/*-----------------------------------------------------------*/
static void prvNotifyingTimer( TimerHandle_t xNotUsed )
{
( void ) xNotUsed;
xTaskNotifyGive( xTaskToNotify );
/* This value is also incremented from an interrupt. */
taskENTER_CRITICAL();
{
ulTimerNotificationsSent++;
}
taskEXIT_CRITICAL();
}
/*-----------------------------------------------------------*/
static void prvNotifiedTask( void * pvParameters )
{
const TickType_t xMaxPeriod = pdMS_TO_TICKS( 90 ), xMinPeriod = pdMS_TO_TICKS( 10 ), xDontBlock = 0;
TickType_t xPeriod;
const uint32_t ulCyclesToRaisePriority = 50UL;
/* Remove compiler warnings about unused parameters. */
( void ) pvParameters;
/* Run a few tests that can be done from a single task before entering the
* main loop. */
prvSingleTaskTests();
/* Create the software timer that is used to send notifications to this
* task. Notifications are also received from an interrupt. */
xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );
for( ; ; )
{
/* Start the timer again with a different period. Sometimes the period
* will be higher than the task's block time, sometimes it will be lower
* than the task's block time. */
xPeriod = prvRand() % xMaxPeriod;
if( xPeriod < xMinPeriod )
{
xPeriod = xMinPeriod;
}
/* Change the timer period and start the timer. */
xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );
/* Block waiting for the notification again with a different period.
* Sometimes the period will be higher than the task's block time,
* sometimes it will be lower than the task's block time. */
xPeriod = prvRand() % xMaxPeriod;
if( xPeriod < xMinPeriod )
{
xPeriod = xMinPeriod;
}
/* Block to wait for a notification but without clearing the
* notification count, so only add one to the count of received
* notifications as any other notifications will remain pending. */
if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )
{
ulTimerNotificationsReceived++;
}
/* Take a notification without clearing again, but this time without a
* block time specified. */
if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )
{
ulTimerNotificationsReceived++;
}
/* Wait for the next notification from the timer, clearing all
* notifications if one is received, so this time adding the total number
* of notifications that were pending as none will be left pending after
* the function call. */
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );
/* Occasionally raise the priority of the task being notified to test
* the path where the task is notified from an ISR and becomes the highest
* priority ready state task, but the pxHigherPriorityTaskWoken parameter
* is NULL (which it is in the tick hook that sends notifications to this
* task). */
if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )
{
vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );
/* Wait for the next notification again, clearing all notifications
* if one is received, but this time blocking indefinitely. */
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
/* Reset the priority. */
vTaskPrioritySet( xTaskToNotify, notifyTASK_PRIORITY );
}
else
{
/* Wait for the next notification again, clearing all notifications
* if one is received, but this time blocking indefinitely. */
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
}
/* Incremented to show the task is still running. */
ulNotifyCycleCount++;
}
}
/*-----------------------------------------------------------*/
void xNotifyTaskFromISR( void )
{
static BaseType_t xCallCount = 0, xAPIToUse = 0;
const BaseType_t xCallInterval = pdMS_TO_TICKS( 50 );
uint32_t ulPreviousValue;
const uint32_t ulUnexpectedValue = 0xff;
/* Check the task notification demo tasks were actually created. */
configASSERT( xTaskToNotify );
/* The task performs some tests before starting the timer that gives the
* notification from this interrupt. If the timer has not been created yet
* then the initial tests have not yet completed and the notification should
* not be sent. */
if( xTimer != NULL )
{
xCallCount++;
if( xCallCount >= xCallInterval )
{
/* It is time to 'give' the notification again. */
xCallCount = 0;
/* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
* and xTaskNotifyAndQueryFromISR(). */
switch( xAPIToUse )
{
case 0:
vTaskNotifyGiveFromISR( xTaskToNotify, NULL );
xAPIToUse++;
break;
case 1:
xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );
xAPIToUse++;
break;
case 2:
ulPreviousValue = ulUnexpectedValue;
xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );
configASSERT( ulPreviousValue != ulUnexpectedValue );
xAPIToUse = 0;
break;
default: /* Should never get here!. */
break;
}
ulTimerNotificationsSent++;
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check the created tasks are still running and have not
* detected any errors. */
BaseType_t xAreTaskNotificationTasksStillRunning( void )
{
static uint32_t ulLastNotifyCycleCount = 0;
const uint32_t ulMaxSendReceiveDeviation = 5UL;
/* Check the cycle count is still incrementing to ensure the task is still
* actually running. */
if( ulLastNotifyCycleCount == ulNotifyCycleCount )
{
xErrorStatus = pdFAIL;
}
else
{
ulLastNotifyCycleCount = ulNotifyCycleCount;
}
/* Check the count of 'takes' from the software timer is keeping track with
* the amount of 'gives'. */
if( ulTimerNotificationsSent > ulTimerNotificationsReceived )
{
if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )
{
xErrorStatus = pdFAIL;
}
}
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 ) );
}
/*-----------------------------------------------------------*/