mirror of
https://git.aixiao.me/aixiao/Danger-alarm.git
synced 2025-07-29 19:13:39 +08:00
initial
This commit is contained in:
720
SOFTWARE-FreeRTOS/Common/Minimal/TaskNotify.c
Normal file
720
SOFTWARE-FreeRTOS/Common/Minimal/TaskNotify.c
Normal file
@@ -0,0 +1,720 @@
|
||||
/*
|
||||
* 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 ) );
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
Reference in New Issue
Block a user