Add uncrustify github workflow (#659)

* Add uncrustify github workflow

* Fix exclusion pattern

* fix find expression

* exclude uncrustify files

* Uncrustify common demo and test files

* exlude white space checking files

* Fix EOL whitespace checker

* Remove whitespaces from EOL

* Fix space at EOL

* Fix find spaces at EOL

Co-authored-by: Archit Aggarwal <architag@amazon.com>
This commit is contained in:
alfred gedeon 2021-07-22 14:23:48 -07:00 committed by GitHub
parent dd80d615b5
commit ae92d8c6ee
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
191 changed files with 17540 additions and 17102 deletions

View file

@ -24,6 +24,38 @@ jobs:
run: | run: |
git-secrets --register-aws git-secrets --register-aws
git-secrets --scan git-secrets --scan
formatting:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install Uncrustify
run: sudo apt-get install uncrustify
- name: Run Uncrustify
run: |
uncrustify --version
find FreeRTOS/Demo/Common FreeRTOS/Test \( -name ethernet -o -name drivers -o -path 'FreeRTOS/Test/CMock/CMock' \) -prune -false -o -name "*.[hc]" -exec uncrustify --check -c tools/uncrustify.cfg {} +
- name: Check For Trailing Whitespace
run: |
set +e
ERROR=0
find . \( -name '.git' -o -path "./FreeRTOS/Test/CBMC/patches" -o -path "./FreeRTOS-Plus" -o -path "./FreeRTOS/Source" -o -path "./FreeRTOS/Test/CMock/CMock" -o -path "./FreeRTOS/Demo" \) -prune -false -o -type f -a -name "*" -exec grep -In -e "[[:blank:]]$" {} +
if [ "$?" = "0" ]; then
echo "Files have trailing whitespace."
ERROR=1
fi
find FreeRTOS/Demo/Common \( -name "ethernet" \) -prune -o -false -o -type f -a -name "*" -exec grep --color=yes -In -e "[[:blank:]]$" {} +
if [ "$?" = "0" ]; then
echo "Files have trailing whitespace."
exit 1
else
if [ "$ERROR" -eq "1" ]; then
exit 1
fi
exit 0
fi
doxygen: doxygen:
runs-on: ubuntu-20.04 runs-on: ubuntu-20.04
steps: steps:

View file

@ -68,6 +68,7 @@ int main()
#error "Invalid Selection...\nPlease Select a Demo application from the main command" #error "Invalid Selection...\nPlease Select a Demo application from the main command"
} }
#endif /* if ( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 ) */ #endif /* if ( mainCREATE_SIMPLE_BLINKY_DEMO_ONLY == 1 ) */
snprint
return 0; return 0;
} }

View file

@ -133,7 +133,8 @@ TaskParameters_t xROAccessTaskParameters =
.pvParameters = NULL, .pvParameters = NULL,
.uxPriority = tskIDLE_PRIORITY, .uxPriority = tskIDLE_PRIORITY,
.puxStackBuffer = xROAccessTaskStack, .puxStackBuffer = xROAccessTaskStack,
.xRegions = { .xRegions =
{
{ ucSharedMemory, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER }, { ucSharedMemory, 32, tskMPU_REGION_READ_ONLY | tskMPU_REGION_EXECUTE_NEVER },
{ ucROTaskFaultTracker, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER }, { ucROTaskFaultTracker, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
{ 0, 0, 0 }, { 0, 0, 0 },
@ -147,7 +148,8 @@ TaskParameters_t xRWAccessTaskParameters =
.pvParameters = NULL, .pvParameters = NULL,
.uxPriority = tskIDLE_PRIORITY, .uxPriority = tskIDLE_PRIORITY,
.puxStackBuffer = xRWAccessTaskStack, .puxStackBuffer = xRWAccessTaskStack,
.xRegions = { .xRegions =
{
{ ucSharedMemory, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER }, { ucSharedMemory, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
{ 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 },
@ -192,9 +194,9 @@ uint16_t usOffendingInstruction;
/* Determine if the offending instruction is a 32-bit instruction or /* Determine if the offending instruction is a 32-bit instruction or
* a 16-bit instruction. */ * a 16-bit instruction. */
if( usOffendingInstruction == 0x001F || if( ( usOffendingInstruction == 0x001F ) ||
usOffendingInstruction == 0x001E || ( usOffendingInstruction == 0x001E ) ||
usOffendingInstruction == 0x001D ) ( usOffendingInstruction == 0x001D ) )
{ {
/* Since the offending instruction is a 32-bit instruction, /* Since the offending instruction is a 32-bit instruction,
* increment the program counter by 4 to move to the next * increment the program counter by 4 to move to the next

View file

@ -77,7 +77,8 @@ TaskParameters_t xSecureCallingTaskParameters =
.pvParameters = NULL, .pvParameters = NULL,
.uxPriority = tskIDLE_PRIORITY, .uxPriority = tskIDLE_PRIORITY,
.puxStackBuffer = xSecureCallingTaskStack, .puxStackBuffer = xSecureCallingTaskStack,
.xRegions = { .xRegions =
{
{ ulNonSecureCounter, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER }, { ulNonSecureCounter, 32, tskMPU_REGION_READ_WRITE | tskMPU_REGION_EXECUTE_NEVER },
{ 0, 0, 0 }, { 0, 0, 0 },
{ 0, 0, 0 }, { 0, 0, 0 },

View file

@ -53,20 +53,20 @@
*/ */
/* /*
Changes from V1.00: * Changes from V1.00:
*
+ Reversed the priority and block times of the second two demo tasks so + Reversed the priority and block times of the second two demo tasks so
they operate as per the description above. + they operate as per the description above.
+
Changes from V2.0.0 + Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+
Changes from V4.0.2 + Changes from V4.0.2
+
+ The second set of tasks were created the wrong way around. This has been + The second set of tasks were created the wrong way around. This has been
corrected. + corrected.
*/ */
@ -96,16 +96,16 @@ typedef struct BLOCKING_QUEUE_PARAMETERS
static void vBlockingQueueProducer( void * pvParameters ); static void vBlockingQueueProducer( void * pvParameters );
/* Task function that removes the incrementing number from a queue and checks that /* Task function that removes the incrementing number from a queue and checks that
it is the expected number. */ * it is the expected number. */
static void vBlockingQueueConsumer( void * pvParameters ); static void vBlockingQueueConsumer( void * pvParameters );
/* Variables which are incremented each time an item is removed from a queue, and /* Variables which are incremented each time an item is removed from a queue, and
found to be the expected value. * found to be the expected value.
These are used to check that the tasks are still running. */ * These are used to check that the tasks are still running. */
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 }; static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
/* Variable which are incremented each time an item is posted on a queue. These /* Variable which are incremented each time an item is posted on a queue. These
are used to check that the tasks are still running. */ * are used to check that the tasks are still running. */
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 }; static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -125,14 +125,14 @@ const TickType_t xDontBlock = ( TickType_t ) 0;
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Create the queue used by the first two tasks to pass the incrementing number. /* Create the queue used by the first two tasks to pass the incrementing number.
Pass a pointer to the queue in the parameter structure. */ * Pass a pointer to the queue in the parameter structure. */
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) ); pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
/* The consumer is created first so gets a block time as described above. */ /* The consumer is created first so gets a block time as described above. */
pxQueueParameters1->xBlockTime = xBlockTime; pxQueueParameters1->xBlockTime = xBlockTime;
/* Pass in the variable that this task is going to increment so we can check it /* Pass in the variable that this task is going to increment so we can check it
is still running. */ * is still running. */
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] ); pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
/* Create the structure used to pass parameters to the producer task. */ /* Create the structure used to pass parameters to the producer task. */
@ -142,23 +142,23 @@ const TickType_t xDontBlock = ( TickType_t ) 0;
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue; pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
/* The producer is not going to block - as soon as it posts the consumer will /* The producer is not going to block - as soon as it posts the consumer will
wake and remove the item so the producer should always have room to post. */ * wake and remove the item so the producer should always have room to post. */
pxQueueParameters2->xBlockTime = xDontBlock; pxQueueParameters2->xBlockTime = xDontBlock;
/* Pass in the variable that this task is going to increment so we can check /* Pass in the variable that this task is going to increment so we can check
it is still running. */ * it is still running. */
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] ); pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
/* Note the producer has a lower priority than the consumer when the tasks are /* Note the producer has a lower priority than the consumer when the tasks are
spawned. */ * spawned. */
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL ); xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL ); xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
/* Create the second two tasks as described at the top of the file. This uses /* Create the second two tasks as described at the top of the file. This uses
the same mechanism but reverses the task priorities. */ * the same mechanism but reverses the task priorities. */
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) ); pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
@ -176,7 +176,7 @@ const TickType_t xDontBlock = ( TickType_t ) 0;
/* Create the last two tasks as described above. The mechanism is again just /* Create the last two tasks as described above. The mechanism is again just
the same. This time both parameter structures are given a block time. */ * the same. This time both parameter structures are given a block time. */
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) ); pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters5->xBlockTime = xBlockTime; pxQueueParameters5->xBlockTime = xBlockTime;
@ -215,14 +215,14 @@ short sErrorEverOccurred = pdFALSE;
else else
{ {
/* We have successfully posted a message, so increment the variable /* We have successfully posted a message, so increment the variable
used to check we are still running. */ * used to check we are still running. */
if( sErrorEverOccurred == pdFALSE ) if( sErrorEverOccurred == pdFALSE )
{ {
( *pxQueueParameters->psCheckVariable )++; ( *pxQueueParameters->psCheckVariable )++;
} }
/* Increment the variable we are going to post next time round. The /* Increment the variable we are going to post next time round. The
consumer will expect the numbers to follow in numerical order. */ * consumer will expect the numbers to follow in numerical order. */
++usValue; ++usValue;
} }
} }
@ -258,14 +258,14 @@ short sErrorEverOccurred = pdFALSE;
else else
{ {
/* We have successfully received a message, so increment the /* We have successfully received a message, so increment the
variable used to check we are still running. */ * variable used to check we are still running. */
if( sErrorEverOccurred == pdFALSE ) if( sErrorEverOccurred == pdFALSE )
{ {
( *pxQueueParameters->psCheckVariable )++; ( *pxQueueParameters->psCheckVariable )++;
} }
/* Increment the value we expect to remove from the queue next time /* Increment the value we expect to remove from the queue next time
round. */ * round. */
++usExpectedValue; ++usExpectedValue;
} }
} }
@ -281,11 +281,11 @@ static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, (
portBASE_TYPE xReturn = pdPASS, xTasks; portBASE_TYPE xReturn = pdPASS, xTasks;
/* Not too worried about mutual exclusion on these variables as they are 16 /* Not too worried about mutual exclusion on these variables as they are 16
bits and we are only reading them. We also only care to see if they have * bits and we are only reading them. We also only care to see if they have
changed or not. * changed or not.
*
Loop through each check variable and return pdFALSE if any are found not * Loop through each check variable and return pdFALSE if any are found not
to have changed since the last call. */ * to have changed since the last call. */
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ ) for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
{ {
@ -293,16 +293,16 @@ portBASE_TYPE xReturn = pdPASS, xTasks;
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] ) if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ]; sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
} }
return xReturn; return xReturn;
} }

View file

@ -53,10 +53,10 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -128,7 +128,7 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If an error has ever been recorded we stop incrementing the /* If an error has ever been recorded we stop incrementing the
check variable. */ * check variable. */
++sPollingProducerCount; ++sPollingProducerCount;
} }
@ -138,7 +138,7 @@ short sError = pdFALSE;
} }
/* Wait before we start posting again to ensure the consumer runs and /* Wait before we start posting again to ensure the consumer runs and
empties the queue. */ * empties the queue. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
} }
} }
@ -169,11 +169,12 @@ short sError = pdFALSE;
if( usData != usExpectedValue ) if( usData != usExpectedValue )
{ {
/* This is not what we expected to receive so an error has /* This is not what we expected to receive so an error has
occurred. */ * occurred. */
vPrintDisplayMessage( &pcTaskErrorMsg ); vPrintDisplayMessage( &pcTaskErrorMsg );
sError = pdTRUE; sError = pdTRUE;
/* Catch-up to the value we received so our next expected value /* Catch-up to the value we received so our next expected value
should again be correct. */ * should again be correct. */
usExpectedValue = usData; usExpectedValue = usData;
} }
else else
@ -181,16 +182,17 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* Only increment the check variable if no errors have /* Only increment the check variable if no errors have
occurred. */ * occurred. */
++sPollingConsumerCount; ++sPollingConsumerCount;
} }
} }
++usExpectedValue; ++usExpectedValue;
} }
} }
/* Now the queue is empty we block, allowing the producer to place more /* Now the queue is empty we block, allowing the producer to place more
items in the queue. */ * items in the queue. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
} }
} }

View file

@ -55,35 +55,35 @@
*/ */
/* /*
Changes from V1.00: * Changes from V1.00:
*
+ The priority of the Rx task has been lowered. Received characters are + The priority of the Rx task has been lowered. Received characters are
now processed (read from the queue) at the idle priority, allowing low + now processed (read from the queue) at the idle priority, allowing low
priority tasks to run evenly at times of a high communications overhead. + priority tasks to run evenly at times of a high communications overhead.
+
Changes from V1.01: + Changes from V1.01:
+
+ The Tx task now waits a pseudo random time between transmissions. + The Tx task now waits a pseudo random time between transmissions.
Previously a fixed period was used but this was not such a good test as + Previously a fixed period was used but this was not such a good test as
interrupts fired at regular intervals. + interrupts fired at regular intervals.
+
Changes From V1.2.0: + Changes From V1.2.0:
+
+ Use vSerialPutString() instead of single character puts. + Use vSerialPutString() instead of single character puts.
+ Only stop the check variable incrementing after two consecutive errors. + Only stop the check variable incrementing after two consecutive errors.
+
Changed from V1.2.5 + Changed from V1.2.5
+
+ Made the Rx task 2 priorities higher than the Tx task. Previously it was + Made the Rx task 2 priorities higher than the Tx task. Previously it was
only 1. This is done to tie in better with the other demo application + only 1. This is done to tie in better with the other demo application
tasks. + tasks.
+
Changes from V2.0.0 + Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+ Slight modification to task priorities. + Slight modification to task priorities.
+
*/ */
@ -99,7 +99,7 @@ Changes from V2.0.0
#include "print.h" #include "print.h"
/* The Tx task will transmit the sequence of characters at a pseudo random /* The Tx task will transmit the sequence of characters at a pseudo random
interval. This is the maximum and minimum block time between sends. */ * interval. This is the maximum and minimum block time between sends. */
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x15e ) #define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x15e )
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0xc8 ) #define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0xc8 )
@ -126,7 +126,7 @@ const char * const pcMessageToExchange = "Send this message over and over again
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n"; "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
/* Variables that are incremented on each cycle of each task. These are used to /* Variables that are incremented on each cycle of each task. These are used to
check that both tasks are still executing. */ * check that both tasks are still executing. */
volatile short sTxCount = 0, sRxCount = 0, sSemCount = 0; volatile short sTxCount = 0, sRxCount = 0, sSemCount = 0;
/* The handle to the semaphore test task. */ /* The handle to the semaphore test task. */
@ -134,7 +134,9 @@ static TaskHandle_t xSemTestTaskHandle = NULL;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartComTestTasks( unsigned portBASE_TYPE uxPriority, eCOMPort ePort, eBaud eBaudRate ) void vStartComTestTasks( unsigned portBASE_TYPE uxPriority,
eCOMPort ePort,
eBaud eBaudRate )
{ {
const unsigned portBASE_TYPE uxBufferLength = 255; const unsigned portBASE_TYPE uxBufferLength = 255;
@ -163,8 +165,8 @@ TickType_t xTimeToWait;
vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) ); vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) );
/* We have posted all the characters in the string - increment the variable /* We have posted all the characters in the string - increment the variable
used to check that this task is still running, then wait before re-sending * used to check that this task is still running, then wait before re-sending
the string. */ * the string. */
sTxCount++; sTxCount++;
xTimeToWait = xTaskGetTickCount(); xTimeToWait = xTaskGetTickCount();
@ -210,28 +212,30 @@ short sResyncRequired, sConsecutiveErrors, sLatchedError;
for( ; ; ) for( ; ; )
{ {
/* Receive a message from the com port interrupt routine. If a message is /* Receive a message from the com port interrupt routine. If a message is
not yet available the call will block the task. */ * not yet available the call will block the task. */
xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime ); xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime );
if( xGotChar == pdTRUE ) if( xGotChar == pdTRUE )
{ {
if( sResyncRequired == pdTRUE ) if( sResyncRequired == pdTRUE )
{ {
/* We got out of sequence and are waiting for the start of the next /* We got out of sequence and are waiting for the start of the next
transmission of the string. */ * transmission of the string. */
if( cRxedChar == '\n' ) if( cRxedChar == '\n' )
{ {
/* This is the end of the message so we can start again - with /* This is the end of the message so we can start again - with
the first character in the string being the next thing we expect * the first character in the string being the next thing we expect
to receive. */ * to receive. */
pcExpectedChar = pcMessageToExchange; pcExpectedChar = pcMessageToExchange;
sResyncRequired = pdFALSE; sResyncRequired = pdFALSE;
/* Queue a message for printing to say that we are going to try /* Queue a message for printing to say that we are going to try
again. */ * again. */
vPrintDisplayMessage( &pcTaskRestartMsg ); vPrintDisplayMessage( &pcTaskRestartMsg );
/* Stop incrementing the check variable, if consecutive errors occur. */ /* Stop incrementing the check variable, if consecutive errors occur. */
sConsecutiveErrors++; sConsecutiveErrors++;
if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS ) if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS )
{ {
sLatchedError = pdTRUE; sLatchedError = pdTRUE;
@ -244,17 +248,18 @@ short sResyncRequired, sConsecutiveErrors, sLatchedError;
if( cRxedChar != *pcExpectedChar ) if( cRxedChar != *pcExpectedChar )
{ {
/* This was not the expected character so post a message for /* This was not the expected character so post a message for
printing to say that an error has occurred. We will then wait * printing to say that an error has occurred. We will then wait
to resynchronise. */ * to resynchronise. */
vPrintDisplayMessage( &pcTaskErrorMsg ); vPrintDisplayMessage( &pcTaskErrorMsg );
sResyncRequired = pdTRUE; sResyncRequired = pdTRUE;
} }
else else
{ {
/* This was the expected character so next time we will expect /* This was the expected character so next time we will expect
the next character in the string. Wrap back to the beginning * the next character in the string. Wrap back to the beginning
of the string when the null terminator has been reached. */ * of the string when the null terminator has been reached. */
pcExpectedChar++; pcExpectedChar++;
if( *pcExpectedChar == '\0' ) if( *pcExpectedChar == '\0' )
{ {
pcExpectedChar = pcMessageToExchange; pcExpectedChar = pcMessageToExchange;
@ -266,7 +271,7 @@ short sResyncRequired, sConsecutiveErrors, sLatchedError;
} }
/* Increment the count that is used to check that this task is still /* Increment the count that is used to check that this task is still
running. This is only done if an error has never occurred. */ * running. This is only done if an error has never occurred. */
if( sLatchedError == pdFALSE ) if( sLatchedError == pdFALSE )
{ {
sRxCount++; sRxCount++;
@ -315,8 +320,8 @@ static short sLastTxCount = 0, sLastRxCount = 0, sLastSemCount = 0;
portBASE_TYPE xReturn; portBASE_TYPE xReturn;
/* Not too worried about mutual exclusion on these variables as they are 16 /* Not too worried about mutual exclusion on these variables as they are 16
bits and we are only reading them. We also only care to see if they have * bits and we are only reading them. We also only care to see if they have
changed or not. */ * changed or not. */
if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) ) if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) )
{ {
@ -338,8 +343,8 @@ portBASE_TYPE xReturn;
void vComTestUnsuspendTask( void ) void vComTestUnsuspendTask( void )
{ {
/* The task that is suspended on the semaphore will be referenced from the /* The task that is suspended on the semaphore will be referenced from the
Suspended list as it is blocking indefinitely. This call just checks that * Suspended list as it is blocking indefinitely. This call just checks that
the kernel correctly detects this and does not attempt to unsuspend the * the kernel correctly detects this and does not attempt to unsuspend the
task. */ * task. */
xTaskResumeFromISR( xSemTestTaskHandle ); xTaskResumeFromISR( xSemTestTaskHandle );
} }

View file

@ -44,10 +44,10 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -63,23 +63,23 @@ Changes from V2.0.0
#define deathSTACK_SIZE ( ( unsigned short ) 512 ) #define deathSTACK_SIZE ( ( unsigned short ) 512 )
/* The task originally created which is responsible for periodically dynamically /* The task originally created which is responsible for periodically dynamically
creating another four tasks. */ * creating another four tasks. */
static void vCreateTasks( void * pvParameters ); static void vCreateTasks( void * pvParameters );
/* The task function of the dynamically created tasks. */ /* The task function of the dynamically created tasks. */
static void vSuicidalTask( void * pvParameters ); static void vSuicidalTask( void * pvParameters );
/* A variable which is incremented every time the dynamic tasks are created. This /* A variable which is incremented every time the dynamic tasks are created. This
is used to check that the task is still running. */ * is used to check that the task is still running. */
static volatile short sCreationCount = 0; static volatile short sCreationCount = 0;
/* Used to store the number of tasks that were originally running so the creator /* Used to store the number of tasks that were originally running so the creator
task can tell if any of the suicidal tasks have failed to die. */ * task can tell if any of the suicidal tasks have failed to die. */
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0; static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5; static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5;
/* Used to store a handle to the tasks that should be killed by a suicidal task, /* Used to store a handle to the tasks that should be killed by a suicidal task,
before it kills itself. */ * before it kills itself. */
TaskHandle_t xCreatedTask1, xCreatedTask2; TaskHandle_t xCreatedTask1, xCreatedTask2;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -89,14 +89,14 @@ void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
unsigned portBASE_TYPE * puxPriority; unsigned portBASE_TYPE * puxPriority;
/* Create the Creator tasks - passing in as a parameter the priority at which /* Create the Creator tasks - passing in as a parameter the priority at which
the suicidal tasks should be created. */ * the suicidal tasks should be created. */
puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) ); puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
*puxPriority = uxPriority; *puxPriority = uxPriority;
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL ); xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );
/* Record the number of tasks that are running now so we know if any of the /* Record the number of tasks that are running now so we know if any of the
suicidal tasks have failed to be killed. */ * suicidal tasks have failed to be killed. */
uxTasksRunningAtStart = uxTaskGetNumberOfTasks(); uxTasksRunningAtStart = uxTaskGetNumberOfTasks();
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -110,8 +110,8 @@ const TickType_t xDelay = ( TickType_t ) 500 / portTICK_PERIOD_MS;
if( pvParameters != NULL ) if( pvParameters != NULL )
{ {
/* This task is periodically created four times. Tow created tasks are /* This task is periodically created four times. Tow created tasks are
passed a handle to the other task so it can kill it before killing itself. * passed a handle to the other task so it can kill it before killing itself.
The other task is passed in null. */ * The other task is passed in null. */
xTaskToKill = *( TaskHandle_t * ) pvParameters; xTaskToKill = *( TaskHandle_t * ) pvParameters;
} }
else else
@ -169,7 +169,7 @@ const char * const pcTaskStartMsg = "Create task started.\r\n";
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that the creator task is still running and that there /* This is called to check that the creator task is still running and that there
are not any more than four extra tasks. */ * are not any more than four extra tasks. */
portBASE_TYPE xIsCreateTaskStillRunning( void ) portBASE_TYPE xIsCreateTaskStillRunning( void )
{ {
static short sLastCreationCount = 0; static short sLastCreationCount = 0;
@ -180,6 +180,7 @@ unsigned portBASE_TYPE uxTasksRunningNow;
{ {
sReturn = pdFALSE; sReturn = pdFALSE;
} }
sLastCreationCount = sCreationCount; sLastCreationCount = sCreationCount;
uxTasksRunningNow = uxTaskGetNumberOfTasks(); uxTasksRunningNow = uxTaskGetNumberOfTasks();
@ -199,5 +200,3 @@ unsigned portBASE_TYPE uxTasksRunningNow;
return sReturn; return sReturn;
} }

View file

@ -91,19 +91,19 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+ Added a second, simple test that uses the functions + Added a second, simple test that uses the functions
vQueueReceiveWhenSuspendedTask() and vQueueSendWhenSuspendedTask(). + vQueueReceiveWhenSuspendedTask() and vQueueSendWhenSuspendedTask().
+
Changes from V3.1.1 + Changes from V3.1.1
+
+ Added a third simple test that uses the vTaskPrioritySet() function + Added a third simple test that uses the vTaskPrioritySet() function
while the scheduler is suspended. + while the scheduler is suspended.
+ Modified the controller task slightly to test the calling of + Modified the controller task slightly to test the calling of
vTaskResumeAll() while the scheduler is suspended. + vTaskResumeAll() while the scheduler is suspended.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -127,12 +127,12 @@ static void vContinuousIncrementTask( void * pvParameters );
static void vCounterControlTask( void * pvParameters ); static void vCounterControlTask( void * pvParameters );
/* The simple test functions that check sending and receiving while the /* The simple test functions that check sending and receiving while the
scheduler is suspended. */ * scheduler is suspended. */
static void vQueueReceiveWhenSuspendedTask( void * pvParameters ); static void vQueueReceiveWhenSuspendedTask( void * pvParameters );
static void vQueueSendWhenSuspendedTask( void * pvParameters ); static void vQueueSendWhenSuspendedTask( void * pvParameters );
/* The simple test functions that check raising and lowering of task priorities /* The simple test functions that check raising and lowering of task priorities
while the scheduler is suspended. */ * while the scheduler is suspended. */
static void prvChangePriorityWhenSuspendedTask( void * pvParameters ); static void prvChangePriorityWhenSuspendedTask( void * pvParameters );
static void prvChangePriorityHelperTask( void * pvParameters ); static void prvChangePriorityHelperTask( void * pvParameters );
@ -148,21 +148,21 @@ static void prvChangePriorityHelperTask( void *pvParameters );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Handles to the two counter tasks. These could be passed in as parameters /* Handles to the two counter tasks. These could be passed in as parameters
to the controller task to prevent them having to be file scope. */ * to the controller task to prevent them having to be file scope. */
static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle, xChangePriorityWhenSuspendedHandle; static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle, xChangePriorityWhenSuspendedHandle;
/* The shared counter variable. This is passed in as a parameter to the two /* The shared counter variable. This is passed in as a parameter to the two
counter variables for demonstration purposes. */ * counter variables for demonstration purposes. */
static unsigned long ulCounter; static unsigned long ulCounter;
/* Variable used in a similar way by the test that checks the raising and /* Variable used in a similar way by the test that checks the raising and
lowering of task priorities while the scheduler is suspended. */ * lowering of task priorities while the scheduler is suspended. */
static unsigned long ulPrioritySetCounter; static unsigned long ulPrioritySetCounter;
/* Variables used to check that the tasks are still operating without error. /* Variables used to check that the tasks are still operating without error.
Each complete iteration of the controller task increments this variable * Each complete iteration of the controller task increments this variable
provided no errors have been found. The variable maintaining the same value * provided no errors have been found. The variable maintaining the same value
is therefore indication of an error. */ * is therefore indication of an error. */
static unsigned short usCheckVariable = ( unsigned short ) 0; static unsigned short usCheckVariable = ( unsigned short ) 0;
static portBASE_TYPE xSuspendedQueueSendError = pdFALSE; static portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
static portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE; static portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
@ -172,6 +172,7 @@ static portBASE_TYPE xPriorityRaiseWhenSuspendedError = pdFALSE;
QueueHandle_t xSuspendedTestQueue; QueueHandle_t xSuspendedTestQueue;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
* Start the seven tasks as described at the top of the file. * Start the seven tasks as described at the top of the file.
* Note that the limited count task is given a higher priority. * Note that the limited count task is given a higher priority.
@ -198,11 +199,11 @@ static void vLimitedIncrementTask( void * pvParameters )
unsigned long * pulCounter; unsigned long * pulCounter;
/* Take a pointer to the shared variable from the parameters passed into /* Take a pointer to the shared variable from the parameters passed into
the task. */ * the task. */
pulCounter = ( unsigned long * ) pvParameters; pulCounter = ( unsigned long * ) pvParameters;
/* This will run before the control task, so the first thing it does is /* This will run before the control task, so the first thing it does is
suspend - the control task will resume it when ready. */ * suspend - the control task will resume it when ready. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
for( ; ; ) for( ; ; )
@ -228,17 +229,17 @@ unsigned long *pulCounter;
unsigned portBASE_TYPE uxOurPriority; unsigned portBASE_TYPE uxOurPriority;
/* Take a pointer to the shared variable from the parameters passed into /* Take a pointer to the shared variable from the parameters passed into
the task. */ * the task. */
pulCounter = ( unsigned long * ) pvParameters; pulCounter = ( unsigned long * ) pvParameters;
/* Query our priority so we can raise it when exclusive access to the /* Query our priority so we can raise it when exclusive access to the
shared variable is required. */ * shared variable is required. */
uxOurPriority = uxTaskPriorityGet( NULL ); uxOurPriority = uxTaskPriorityGet( NULL );
for( ; ; ) for( ; ; )
{ {
/* Raise our priority above the controller task to ensure a context /* Raise our priority above the controller task to ensure a context
switch does not occur while we are accessing this variable. */ * switch does not occur while we are accessing this variable. */
vTaskPrioritySet( NULL, uxOurPriority + 1 ); vTaskPrioritySet( NULL, uxOurPriority + 1 );
( *pulCounter )++; ( *pulCounter )++;
vTaskPrioritySet( NULL, uxOurPriority ); vTaskPrioritySet( NULL, uxOurPriority );
@ -278,7 +279,7 @@ const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
for( sLoops = 0; sLoops < priLOOPS; sLoops++ ) for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
{ {
/* Suspend the continuous count task so we can take a mirror of the /* Suspend the continuous count task so we can take a mirror of the
shared variable without risk of corruption. */ * shared variable without risk of corruption. */
vTaskSuspend( xContinuousIncrementHandle ); vTaskSuspend( xContinuousIncrementHandle );
ulLastCounter = ulCounter; ulLastCounter = ulCounter;
vTaskResume( xContinuousIncrementHandle ); vTaskResume( xContinuousIncrementHandle );
@ -287,14 +288,14 @@ const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
vTaskDelay( priSLEEP_TIME ); vTaskDelay( priSLEEP_TIME );
/* Check the shared variable again. This time to ensure mutual /* Check the shared variable again. This time to ensure mutual
exclusion the whole scheduler will be locked. This is just for * exclusion the whole scheduler will be locked. This is just for
demo purposes! */ * demo purposes! */
vTaskSuspendAll(); vTaskSuspendAll();
{ {
if( ulLastCounter == ulCounter ) if( ulLastCounter == ulCounter )
{ {
/* The shared variable has not changed. There is a problem /* The shared variable has not changed. There is a problem
with the continuous count task so flag an error. */ * with the continuous count task so flag an error. */
sError = pdTRUE; sError = pdTRUE;
xTaskResumeAll(); xTaskResumeAll();
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
@ -304,7 +305,6 @@ const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
xTaskResumeAll(); xTaskResumeAll();
} }
/* Second section: */ /* Second section: */
/* Suspend the continuous counter task so it stops accessing the shared variable. */ /* Suspend the continuous counter task so it stops accessing the shared variable. */
@ -314,10 +314,10 @@ const char * const pcTaskFailMsg = "Priority manipulation Task Failed\r\n";
ulCounter = ( unsigned long ) 0; ulCounter = ( unsigned long ) 0;
/* Resume the limited count task which has a higher priority than us. /* Resume the limited count task which has a higher priority than us.
We should therefore not return from this call until the limited count * We should therefore not return from this call until the limited count
task has suspended itself with a known value in the counter variable. * task has suspended itself with a known value in the counter variable.
The scheduler suspension is not necessary but is included for test * The scheduler suspension is not necessary but is included for test
purposes. */ * purposes. */
vTaskSuspendAll(); vTaskSuspendAll();
vTaskResume( xLimitedIncrementHandle ); vTaskResume( xLimitedIncrementHandle );
xTaskResumeAll(); xTaskResumeAll();
@ -403,16 +403,17 @@ portBASE_TYPE xGotValue;
do do
{ {
/* Suspending the scheduler here is fairly pointless and /* Suspending the scheduler here is fairly pointless and
undesirable for a normal application. It is done here purely * undesirable for a normal application. It is done here purely
to test the scheduler. The inner xTaskResumeAll() should * to test the scheduler. The inner xTaskResumeAll() should
never return pdTRUE as the scheduler is still locked by the * never return pdTRUE as the scheduler is still locked by the
outer call. */ * outer call. */
vTaskSuspendAll(); vTaskSuspendAll();
{ {
vTaskSuspendAll(); vTaskSuspendAll();
{ {
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK ); xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
} }
if( xTaskResumeAll() ) if( xTaskResumeAll() )
{ {
xSuspendedQueueReceiveError = pdTRUE; xSuspendedQueueReceiveError = pdTRUE;
@ -423,7 +424,6 @@ portBASE_TYPE xGotValue;
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
} while( xGotValue == pdFALSE ); } while( xGotValue == pdFALSE );
if( ulReceivedValue != ulExpectedValue ) if( ulReceivedValue != ulExpectedValue )
@ -432,6 +432,7 @@ portBASE_TYPE xGotValue;
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
} }
xSuspendedQueueReceiveError = pdTRUE; xSuspendedQueueReceiveError = pdTRUE;
} }
@ -454,11 +455,11 @@ const char * const pcTaskFailMsg = "Priority change when suspended task failed.\
for( ; ; ) for( ; ; )
{ {
/* Start with the counter at 0 so we know what the counter should be /* Start with the counter at 0 so we know what the counter should be
when we check it next. */ * when we check it next. */
ulPrioritySetCounter = ( unsigned long ) 0; ulPrioritySetCounter = ( unsigned long ) 0;
/* Resume the helper task. At this time it has a priority lower than /* Resume the helper task. At this time it has a priority lower than
ours so no context switch should occur. */ * ours so no context switch should occur. */
vTaskResume( xChangePriorityWhenSuspendedHandle ); vTaskResume( xChangePriorityWhenSuspendedHandle );
/* Check to ensure the task just resumed has not executed. */ /* Check to ensure the task just resumed has not executed. */
@ -478,8 +479,8 @@ const char * const pcTaskFailMsg = "Priority change when suspended task failed.\
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, ( configMAX_PRIORITIES - 1 ) ); vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, ( configMAX_PRIORITIES - 1 ) );
/* Again, even though the helper task has a priority greater than /* Again, even though the helper task has a priority greater than
ours, it should not have executed yet because the scheduler is * ours, it should not have executed yet because the scheduler is
suspended. */ * suspended. */
portENTER_CRITICAL(); portENTER_CRITICAL();
{ {
if( ulPrioritySetCounter != ( unsigned long ) 0 ) if( ulPrioritySetCounter != ( unsigned long ) 0 )
@ -493,10 +494,10 @@ const char * const pcTaskFailMsg = "Priority change when suspended task failed.\
xTaskResumeAll(); xTaskResumeAll();
/* Now the scheduler has been resumed the helper task should /* Now the scheduler has been resumed the helper task should
immediately preempt us and execute. When it executes it will increment * immediately preempt us and execute. When it executes it will increment
the ulPrioritySetCounter exactly once before suspending itself. * the ulPrioritySetCounter exactly once before suspending itself.
*
We should now always find the counter set to 1. */ * We should now always find the counter set to 1. */
portENTER_CRITICAL(); portENTER_CRITICAL();
{ {
if( ulPrioritySetCounter != ( unsigned long ) 1 ) if( ulPrioritySetCounter != ( unsigned long ) 1 )
@ -511,7 +512,7 @@ const char * const pcTaskFailMsg = "Priority change when suspended task failed.\
vTaskDelay( priSLEEP_TIME * 2 ); vTaskDelay( priSLEEP_TIME * 2 );
/* Set the priority of the helper task back ready for the next /* Set the priority of the helper task back ready for the next
execution of this task. */ * execution of this task. */
vTaskSuspendAll(); vTaskSuspendAll();
vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, tskIDLE_PRIORITY ); vTaskPrioritySet( xChangePriorityWhenSuspendedHandle, tskIDLE_PRIORITY );
xTaskResumeAll(); xTaskResumeAll();
@ -527,10 +528,10 @@ static void prvChangePriorityHelperTask( void *pvParameters )
for( ; ; ) for( ; ; )
{ {
/* This is the helper task for prvChangePriorityWhenSuspendedTask(). /* This is the helper task for prvChangePriorityWhenSuspendedTask().
It has it's priority raised and lowered. When it runs it simply * It has it's priority raised and lowered. When it runs it simply
increments the counter then suspends itself again. This allows * increments the counter then suspends itself again. This allows
prvChangePriorityWhenSuspendedTask() to know how many times it has * prvChangePriorityWhenSuspendedTask() to know how many times it has
executed. */ * executed. */
ulPrioritySetCounter++; ulPrioritySetCounter++;
vTaskSuspend( NULL ); vTaskSuspend( NULL );
} }
@ -541,12 +542,12 @@ static void prvChangePriorityHelperTask( void *pvParameters )
portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void ) portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
{ {
/* Keep a history of the check variables so we know if it has been incremented /* Keep a history of the check variables so we know if it has been incremented
since the last call. */ * since the last call. */
static unsigned short usLastTaskCheck = ( unsigned short ) 0; static unsigned short usLastTaskCheck = ( unsigned short ) 0;
portBASE_TYPE xReturn = pdTRUE; portBASE_TYPE xReturn = pdTRUE;
/* Check the tasks are still running by ensuring the check variable /* Check the tasks are still running by ensuring the check variable
is still incrementing. */ * is still incrementing. */
if( usCheckVariable == usLastTaskCheck ) if( usCheckVariable == usLastTaskCheck )
{ {
@ -572,7 +573,3 @@ portBASE_TYPE xReturn = pdTRUE;
usLastTaskCheck = usCheckVariable; usLastTaskCheck = usCheckVariable;
return xReturn; return xReturn;
} }

View file

@ -66,37 +66,37 @@
#define evtNO_DELAY 0 #define evtNO_DELAY 0
/* Just indexes used to uniquely identify the tasks. Note that two tasks are /* Just indexes used to uniquely identify the tasks. Note that two tasks are
'highest' priority. */ * 'highest' priority. */
#define evtHIGHEST_PRIORITY_INDEX_2 3 #define evtHIGHEST_PRIORITY_INDEX_2 3
#define evtHIGHEST_PRIORITY_INDEX_1 2 #define evtHIGHEST_PRIORITY_INDEX_1 2
#define evtMEDIUM_PRIORITY_INDEX 1 #define evtMEDIUM_PRIORITY_INDEX 1
#define evtLOWEST_PRIORITY_INDEX 0 #define evtLOWEST_PRIORITY_INDEX 0
/* Each event task increments one of these counters each time it reads data /* Each event task increments one of these counters each time it reads data
from the queue. */ * from the queue. */
static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 }; static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
/* Each time the controlling task posts onto the queue it increments the /* Each time the controlling task posts onto the queue it increments the
expected count of the task that it expected to read the data from the queue * expected count of the task that it expected to read the data from the queue
(i.e. the task with the highest priority that should be blocked on the queue). * (i.e. the task with the highest priority that should be blocked on the queue).
*
xExpectedTaskCounters are incremented from the controlling task, and * xExpectedTaskCounters are incremented from the controlling task, and
xTaskCounters are incremented from the individual event tasks - therefore * xTaskCounters are incremented from the individual event tasks - therefore
comparing xTaskCounters to xExpectedTaskCounters shows whether or not the * comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
correct task was unblocked by the post. */ * correct task was unblocked by the post. */
static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 }; static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
/* Handles to the four event tasks. These are required to suspend and resume /* Handles to the four event tasks. These are required to suspend and resume
the tasks. */ * the tasks. */
static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ]; static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ];
/* The single queue onto which the controlling task posts, and the four event /* The single queue onto which the controlling task posts, and the four event
tasks block. */ * tasks block. */
static QueueHandle_t xQueue; static QueueHandle_t xQueue;
/* Flag used to indicate whether or not an error has occurred at any time. /* Flag used to indicate whether or not an error has occurred at any time.
An error is either the queue being full when not expected, or an unexpected * An error is either the queue being full when not expected, or an unexpected
task reading data from the queue. */ * task reading data from the queue. */
static portBASE_TYPE xHealthStatus = pdPASS; static portBASE_TYPE xHealthStatus = pdPASS;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -108,23 +108,24 @@ static void prvMultiEventTask( void *pvParameters );
static void prvEventControllerTask( void * pvParameters ); static void prvEventControllerTask( void * pvParameters );
/* This is a utility function that posts data to the queue, then compares /* This is a utility function that posts data to the queue, then compares
xExpectedTaskCounters with xTaskCounters to ensure everything worked as * xExpectedTaskCounters with xTaskCounters to ensure everything worked as
expected. * expected.
*
The event tasks all have higher priorities the controlling task. Therefore * The event tasks all have higher priorities the controlling task. Therefore
the controlling task will always get preempted between writhing to the queue * the controlling task will always get preempted between writhing to the queue
and checking the task counters. * and checking the task counters.
*
@param xExpectedTask The index to the task that the controlling task thinks * @param xExpectedTask The index to the task that the controlling task thinks
should be the highest priority task waiting for data, and * should be the highest priority task waiting for data, and
therefore the task that will unblock. * therefore the task that will unblock.
*
@param xIncrement The number of items that should be written to the queue. * @param xIncrement The number of items that should be written to the queue.
*/ */
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement ); static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask,
portBASE_TYPE xIncrement );
/* This is just incremented each cycle of the controlling tasks function so /* This is just incremented each cycle of the controlling tasks function so
the main application can ensure the test is still running. */ * the main application can ensure the test is still running. */
static portBASE_TYPE xCheckVariable = 0; static portBASE_TYPE xCheckVariable = 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -135,11 +136,11 @@ void vStartMultiEventTasks( void )
xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) ); xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
/* Start the controlling task. This has the idle priority to ensure it is /* Start the controlling task. This has the idle priority to ensure it is
always preempted by the event tasks. */ * always preempted by the event tasks. */
xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
/* Start the four event tasks. Note that two have priority 3, one /* Start the four event tasks. Note that two have priority 3, one
priority 2 and the other priority 1. */ * priority 2 and the other priority 1. */
xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) ); xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) ); xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) ); xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
@ -164,7 +165,7 @@ const char * const pcTaskStartMsg = "Multi event task started.\r\n";
if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) ) if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
{ {
/* We unblocked by reading the queue - so simply increment /* We unblocked by reading the queue - so simply increment
the counter specific to this task instance. */ * the counter specific to this task instance. */
( *pxCounter )++; ( *pxCounter )++;
} }
else else
@ -188,10 +189,10 @@ portBASE_TYPE xDummy = 0;
for( ; ; ) for( ; ; )
{ {
/* All tasks are blocked on the queue. When a message is posted one of /* All tasks are blocked on the queue. When a message is posted one of
the two tasks that share the highest priority should unblock to read * the two tasks that share the highest priority should unblock to read
the queue. The next message written should unblock the other task with * the queue. The next message written should unblock the other task with
the same high priority, and so on in order. No other task should * the same high priority, and so on in order. No other task should
unblock to read data as they have lower priorities. */ * unblock to read data as they have lower priorities. */
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
@ -200,32 +201,32 @@ portBASE_TYPE xDummy = 0;
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
/* For the rest of these tests we don't need the second 'highest' /* For the rest of these tests we don't need the second 'highest'
priority task - so it is suspended. */ * priority task - so it is suspended. */
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ); vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
/* Now suspend the other highest priority task. The medium priority /* Now suspend the other highest priority task. The medium priority
task will then be the task with the highest priority that remains * task will then be the task with the highest priority that remains
blocked on the queue. */ * blocked on the queue. */
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ); vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
/* This time, when we post onto the queue we will expect the medium /* This time, when we post onto the queue we will expect the medium
priority task to unblock and preempt us. */ * priority task to unblock and preempt us. */
prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 ); prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
/* Now try resuming the highest priority task while the scheduler is /* Now try resuming the highest priority task while the scheduler is
suspended. The task should start executing as soon as the scheduler * suspended. The task should start executing as soon as the scheduler
is resumed - therefore when we post to the queue again, the highest * is resumed - therefore when we post to the queue again, the highest
priority task should again preempt us. */ * priority task should again preempt us. */
vTaskSuspendAll(); vTaskSuspendAll();
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ); vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
xTaskResumeAll(); xTaskResumeAll();
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
/* Now we are going to suspend the high and medium priority tasks. The /* Now we are going to suspend the high and medium priority tasks. The
low priority task should then preempt us. Again the task suspension is * low priority task should then preempt us. Again the task suspension is
done with the whole scheduler suspended just for test purposes. */ * done with the whole scheduler suspended just for test purposes. */
vTaskSuspendAll(); vTaskSuspendAll();
vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ); vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ); vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
@ -233,9 +234,9 @@ portBASE_TYPE xDummy = 0;
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 ); prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
/* Do the same basic test another few times - selectively suspending /* Do the same basic test another few times - selectively suspending
and resuming tasks and each time calling prvCheckTaskCounters() passing * and resuming tasks and each time calling prvCheckTaskCounters() passing
to the function the number of the task we expected to be unblocked by * to the function the number of the task we expected to be unblocked by
the post. */ * the post. */
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ); vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 ); prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
@ -261,19 +262,19 @@ portBASE_TYPE xDummy = 0;
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ); vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
/* Now when we resume the low priority task and write to the queue 3 /* Now when we resume the low priority task and write to the queue 3
times. We expect the low priority task to service the queue three * times. We expect the low priority task to service the queue three
times. */ * times. */
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ); vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH ); prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
/* Again suspend all tasks (only the low priority task is not suspended /* Again suspend all tasks (only the low priority task is not suspended
already). */ * already). */
vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ); vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
/* This time we are going to suspend the scheduler, resume the low /* This time we are going to suspend the scheduler, resume the low
priority task, then resume the high priority task. In this state we * priority task, then resume the high priority task. In this state we
will write to the queue three times. When the scheduler is resumed * will write to the queue three times. When the scheduler is resumed
we expect the high priority task to service all three messages. */ * we expect the high priority task to service all three messages. */
vTaskSuspendAll(); vTaskSuspendAll();
{ {
vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ); vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
@ -288,7 +289,7 @@ portBASE_TYPE xDummy = 0;
} }
/* The queue should not have been serviced yet!. The scheduler /* The queue should not have been serviced yet!. The scheduler
is still suspended. */ * is still suspended. */
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) ) if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
{ {
xHealthStatus = pdFAIL; xHealthStatus = pdFAIL;
@ -297,16 +298,17 @@ portBASE_TYPE xDummy = 0;
xTaskResumeAll(); xTaskResumeAll();
/* We should have been preempted by resuming the scheduler - so by the /* We should have been preempted by resuming the scheduler - so by the
time we are running again we expect the high priority task to have * time we are running again we expect the high priority task to have
removed three items from the queue. */ * removed three items from the queue. */
xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH; xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) ) if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
{ {
xHealthStatus = pdFAIL; xHealthStatus = pdFAIL;
} }
/* The medium priority and second high priority tasks are still /* The medium priority and second high priority tasks are still
suspended. Make sure to resume them before starting again. */ * suspended. Make sure to resume them before starting again. */
vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ); vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ); vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
@ -316,12 +318,13 @@ portBASE_TYPE xDummy = 0;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement ) static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask,
portBASE_TYPE xIncrement )
{ {
portBASE_TYPE xDummy = 0; portBASE_TYPE xDummy = 0;
/* Write to the queue the requested number of times. The data written is /* Write to the queue the requested number of times. The data written is
not important. */ * not important. */
for( xDummy = 0; xDummy < xIncrement; xDummy++ ) for( xDummy = 0; xDummy < xIncrement; xDummy++ )
{ {
if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE ) if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
@ -332,17 +335,17 @@ portBASE_TYPE xDummy = 0;
} }
/* All the tasks blocked on the queue have a priority higher than the /* All the tasks blocked on the queue have a priority higher than the
controlling task. Writing to the queue will therefore have caused this * controlling task. Writing to the queue will therefore have caused this
task to be preempted. By the time this line executes the event task will * task to be preempted. By the time this line executes the event task will
have executed and incremented its counter. Increment the expected counter * have executed and incremented its counter. Increment the expected counter
to the same value. */ * to the same value. */
( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement; ( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
/* Check the actual counts and expected counts really are the same. */ /* Check the actual counts and expected counts really are the same. */
if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) ) if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
{ {
/* The counters were not the same. This means a task we did not expect /* The counters were not the same. This means a task we did not expect
to unblock actually did unblock. */ * to unblock actually did unblock. */
xHealthStatus = pdFAIL; xHealthStatus = pdFAIL;
} }
} }
@ -353,7 +356,7 @@ portBASE_TYPE xAreMultiEventTasksStillRunning( void )
static portBASE_TYPE xPreviousCheckVariable = 0; static portBASE_TYPE xPreviousCheckVariable = 0;
/* Called externally to periodically check that this test is still /* Called externally to periodically check that this test is still
operational. */ * operational. */
if( xPreviousCheckVariable == xCheckVariable ) if( xPreviousCheckVariable == xCheckVariable )
{ {
@ -364,5 +367,3 @@ static portBASE_TYPE xPreviousCheckVariable = 0;
return xHealthStatus; return xHealthStatus;
} }

View file

@ -42,13 +42,13 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+
Changes from V2.1.1 + Changes from V2.1.1
+
+ The stack size now uses configMINIMAL_STACK_SIZE. + The stack size now uses configMINIMAL_STACK_SIZE.
+ String constants made file scope to decrease stack depth on 8051 port. + String constants made file scope to decrease stack depth on 8051 port.
*/ */
@ -74,7 +74,7 @@ typedef struct LED_PARAMETERS
} xLEDParameters; } xLEDParameters;
/* The task that is created eight times - each time with a different xLEDParaemtes /* The task that is created eight times - each time with a different xLEDParaemtes
structure passed in as the parameter. */ * structure passed in as the parameter. */
static void vLEDFlashTask( void * pvParameters ); static void vLEDFlashTask( void * pvParameters );
/* String to print if USE_STDIO is defined. */ /* String to print if USE_STDIO is defined. */
@ -93,7 +93,7 @@ const TickType_t xFlashRate = 125;
for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask ) for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask )
{ {
/* Create and complete the structure used to pass parameters to the next /* Create and complete the structure used to pass parameters to the next
created task. */ * created task. */
pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) ); pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) );
pxLEDParameters->uxLED = uxLEDTask; pxLEDParameters->uxLED = uxLEDTask;
pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( TickType_t ) uxLEDTask ) ); pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( TickType_t ) uxLEDTask ) );
@ -125,4 +125,3 @@ xLEDParameters *pxParameters;
vParTestToggleLED( pxParameters->uxLED ); vParTestToggleLED( pxParameters->uxLED );
} }
} }

View file

@ -26,10 +26,10 @@
*/ */
/* /*
Changes from V1.2.3 * Changes from V1.2.3
*
+ The created tasks now include calls to tskYIELD(), allowing them to be used + The created tasks now include calls to tskYIELD(), allowing them to be used
with the cooperative scheduler. + with the cooperative scheduler.
*/ */
/** /**
@ -64,15 +64,15 @@ Changes from V1.2.3
#define mathNUMBER_OF_TASKS ( 8 ) #define mathNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different floating point calculation. /* Four tasks, each of which performs a different floating point calculation.
Each of the four is created twice. */ * Each of the four is created twice. */
static void vCompetingMathTask1( void * pvParameters ); static void vCompetingMathTask1( void * pvParameters );
static void vCompetingMathTask2( void * pvParameters ); static void vCompetingMathTask2( void * pvParameters );
static void vCompetingMathTask3( void * pvParameters ); static void vCompetingMathTask3( void * pvParameters );
static void vCompetingMathTask4( void * pvParameters ); static void vCompetingMathTask4( void * pvParameters );
/* These variables are used to check that all the tasks are still running. If a /* These variables are used to check that all the tasks are still running. If a
task gets a calculation wrong it will * task gets a calculation wrong it will
stop incrementing its check variable. */ * stop incrementing its check variable. */
static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 }; static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -103,7 +103,7 @@ short sError = pdFALSE;
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
@ -118,7 +118,7 @@ short sError = pdFALSE;
taskYIELD(); taskYIELD();
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 ) if( fabs( d4 - dAnswer ) > 0.001 )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
@ -128,7 +128,7 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
@ -150,7 +150,7 @@ short sError = pdFALSE;
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
@ -165,7 +165,7 @@ short sError = pdFALSE;
taskYIELD(); taskYIELD();
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 ) if( fabs( d4 - dAnswer ) > 0.001 )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
@ -175,8 +175,8 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know * variable so we know
this task is still running okay. */ * this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
@ -199,14 +199,14 @@ short sError = pdFALSE;
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) ); pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ; ; ) for( ; ; )
{ {
dTotal1 = 0.0; dTotal1 = 0.0;
@ -226,6 +226,7 @@ short sError = pdFALSE;
} }
dDifference = dTotal1 - dTotal2; dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 ) if( fabs( dDifference ) > 0.001 )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
@ -237,7 +238,7 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
@ -258,14 +259,14 @@ short sError = pdFALSE;
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) ); pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ; ; ) for( ; ; )
{ {
dTotal1 = 0.0; dTotal1 = 0.0;
@ -285,6 +286,7 @@ short sError = pdFALSE;
} }
dDifference = dTotal1 - dTotal2; dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 ) if( fabs( dDifference ) > 0.001 )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
@ -296,7 +298,7 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
@ -307,12 +309,12 @@ short sError = pdFALSE;
portBASE_TYPE xAreMathsTaskStillRunning( void ) portBASE_TYPE xAreMathsTaskStillRunning( void )
{ {
/* Keep a history of the check variables so we know if they have been incremented /* Keep a history of the check variables so we know if they have been incremented
since the last call. */ * since the last call. */
static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 }; static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdTRUE, xTask; portBASE_TYPE xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
are still incrementing. */ * are still incrementing. */
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ ) for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
{ {
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] ) if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
@ -326,6 +328,3 @@ portBASE_TYPE xReturn = pdTRUE, xTask;
return xReturn; return xReturn;
} }

View file

@ -26,10 +26,10 @@
*/ */
/* /*
Changes from V1.2.3 * Changes from V1.2.3
*
+ The created tasks now include calls to tskYIELD(), allowing them to be used + The created tasks now include calls to tskYIELD(), allowing them to be used
with the cooperative scheduler. + with the cooperative scheduler.
*/ */
/** /**
@ -49,10 +49,10 @@ Changes from V1.2.3
*/ */
/* /*
Changes from V1.2.1 * Changes from V1.2.1
*
+ The constants used in the calculations are larger to ensure the + The constants used in the calculations are larger to ensure the
optimiser does not truncate them to 16 bits. + optimiser does not truncate them to 16 bits.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -69,14 +69,14 @@ Changes from V1.2.1
#define intgNUMBER_OF_TASKS ( 8 ) #define intgNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different calculation on four byte /* Four tasks, each of which performs a different calculation on four byte
variables. Each of the four is created twice. */ * variables. Each of the four is created twice. */
static void vCompeteingIntMathTask1( void * pvParameters ); static void vCompeteingIntMathTask1( void * pvParameters );
static void vCompeteingIntMathTask2( void * pvParameters ); static void vCompeteingIntMathTask2( void * pvParameters );
static void vCompeteingIntMathTask3( void * pvParameters ); static void vCompeteingIntMathTask3( void * pvParameters );
static void vCompeteingIntMathTask4( void * pvParameters ); static void vCompeteingIntMathTask4( void * pvParameters );
/* These variables are used to check that all the tasks are still running. If a /* These variables are used to check that all the tasks are still running. If a
task gets a calculation wrong it will stop incrementing its check variable. */ * task gets a calculation wrong it will stop incrementing its check variable. */
static volatile unsigned short usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 }; static volatile unsigned short usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -106,7 +106,7 @@ const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
@ -121,7 +121,7 @@ const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
taskYIELD(); taskYIELD();
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( l4 != lAnswer ) if( l4 != lAnswer )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
@ -131,7 +131,7 @@ const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
@ -151,7 +151,7 @@ const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
@ -166,7 +166,7 @@ const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
taskYIELD(); taskYIELD();
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( l4 != lAnswer ) if( l4 != lAnswer )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
@ -176,7 +176,7 @@ const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
@ -197,15 +197,15 @@ const char * const pcTaskFailMsg = "Integer math task 3 failed.\r\n";
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Create the array we are going to use for our check calculation. */ /* Create the array we are going to use for our check calculation. */
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) ); plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
/* Keep filling the array, keeping a running total of the values placed in the /* Keep filling the array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ; ; ) for( ; ; )
{ {
lTotal1 = ( long ) 0; lTotal1 = ( long ) 0;
@ -235,7 +235,7 @@ const char * const pcTaskFailMsg = "Integer math task 3 failed.\r\n";
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
@ -256,15 +256,15 @@ const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
vPrintDisplayMessage( &pcTaskStartMsg ); vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters; pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Create the array we are going to use for our check calculation. */ /* Create the array we are going to use for our check calculation. */
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) ); plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
/* Keep filling the array, keeping a running total of the values placed in the /* Keep filling the array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ; ; ) for( ; ; )
{ {
lTotal1 = ( long ) 0; lTotal1 = ( long ) 0;
@ -283,7 +283,6 @@ const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
lTotal2 += plArray[ usPosition ]; lTotal2 += plArray[ usPosition ];
} }
if( lTotal1 != lTotal2 ) if( lTotal1 != lTotal2 )
{ {
vPrintDisplayMessage( &pcTaskFailMsg ); vPrintDisplayMessage( &pcTaskFailMsg );
@ -295,7 +294,7 @@ const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
@ -306,12 +305,12 @@ const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
portBASE_TYPE xAreIntegerMathsTaskStillRunning( void ) portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
{ {
/* Keep a history of the check variables so we know if they have been incremented /* Keep a history of the check variables so we know if they have been incremented
since the last call. */ * since the last call. */
static unsigned short usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 }; static unsigned short usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdTRUE, xTask; portBASE_TYPE xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
are still incrementing. */ * are still incrementing. */
for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ ) for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ )
{ {
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] ) if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )

View file

@ -50,10 +50,10 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -102,5 +102,3 @@ char *pcMessage;
return NULL; return NULL;
} }
} }

View file

@ -52,21 +52,21 @@
*/ */
/* /*
Changes from V1.2.0: * Changes from V1.2.0:
*
+ The tasks that operate at the idle priority now use a lower expected + The tasks that operate at the idle priority now use a lower expected
count than those running at a higher priority. This prevents the low + count than those running at a higher priority. This prevents the low
priority tasks from signaling an error because they have not been + priority tasks from signaling an error because they have not been
scheduled enough time for each of them to count the shared variable to + scheduled enough time for each of them to count the shared variable to
the high value. + the high value.
+
Changes from V2.0.0 + Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than unsigned long. + TickType_t rather than unsigned long.
+
Changes from V2.1.1 + Changes from V2.1.1
+
+ The stack size now uses configMINIMAL_STACK_SIZE. + The stack size now uses configMINIMAL_STACK_SIZE.
+ String constants made file scope to decrease stack depth on 8051 port. + String constants made file scope to decrease stack depth on 8051 port.
*/ */
@ -144,8 +144,9 @@ const TickType_t xBlockTime = ( TickType_t ) 100;
} }
/* Do exactly the same to create the second set of tasks, only this time /* Do exactly the same to create the second set of tasks, only this time
provide a block time for the semaphore calls. */ * provide a block time for the semaphore calls. */
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) ); pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxSecondSemaphoreParameters != NULL ) if( pxSecondSemaphoreParameters != NULL )
{ {
vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore ); vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
@ -171,7 +172,7 @@ unsigned long ulCounter;
short sError = pdFALSE, sCheckVariableToUse; short sError = pdFALSE, sCheckVariableToUse;
/* See which check variable to use. sNextCheckVariable is not semaphore /* See which check variable to use. sNextCheckVariable is not semaphore
protected! */ * protected! */
portENTER_CRITICAL(); portENTER_CRITICAL();
sCheckVariableToUse = sNextCheckVariable; sCheckVariableToUse = sNextCheckVariable;
sNextCheckVariable++; sNextCheckVariable++;
@ -181,12 +182,12 @@ short sError = pdFALSE, sCheckVariableToUse;
vPrintDisplayMessage( &pcSemaphoreTaskStart ); vPrintDisplayMessage( &pcSemaphoreTaskStart );
/* A structure is passed in as the parameter. This contains the shared /* A structure is passed in as the parameter. This contains the shared
variable being guarded. */ * variable being guarded. */
pxParameters = ( xSemaphoreParameters * ) pvParameters; pxParameters = ( xSemaphoreParameters * ) pvParameters;
pulSharedVariable = pxParameters->pulSharedVariable; pulSharedVariable = pxParameters->pulSharedVariable;
/* If we are blocking we use a much higher count to ensure loads of context /* If we are blocking we use a much higher count to ensure loads of context
switches occur during the count. */ * switches occur during the count. */
if( pxParameters->xBlockTime > ( TickType_t ) 0 ) if( pxParameters->xBlockTime > ( TickType_t ) 0 )
{ {
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE; ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
@ -202,8 +203,8 @@ short sError = pdFALSE, sCheckVariableToUse;
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS ) if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
{ {
/* We have the semaphore and so expect any other tasks using the /* We have the semaphore and so expect any other tasks using the
shared variable to have left it in the state we expect to find * shared variable to have left it in the state we expect to find
it. */ * it. */
if( *pulSharedVariable != ulExpectedValue ) if( *pulSharedVariable != ulExpectedValue )
{ {
vPrintDisplayMessage( &pcPollingSemaphoreTaskError ); vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
@ -211,23 +212,25 @@ short sError = pdFALSE, sCheckVariableToUse;
} }
/* Clear the variable, then count it back up to the expected value /* Clear the variable, then count it back up to the expected value
before releasing the semaphore. Would expect a context switch or * before releasing the semaphore. Would expect a context switch or
two during this time. */ * two during this time. */
for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ ) for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
{ {
*pulSharedVariable = ulCounter; *pulSharedVariable = ulCounter;
if( *pulSharedVariable != ulCounter ) if( *pulSharedVariable != ulCounter )
{ {
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
vPrintDisplayMessage( &pcPollingSemaphoreTaskError ); vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
} }
sError = pdTRUE; sError = pdTRUE;
} }
} }
/* Release the semaphore, and if no errors have occurred increment the check /* Release the semaphore, and if no errors have occurred increment the check
variable. */ * variable. */
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE ) if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
{ {
vPrintDisplayMessage( &pcPollingSemaphoreTaskError ); vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
@ -243,10 +246,10 @@ short sError = pdFALSE, sCheckVariableToUse;
} }
/* If we have a block time then we are running at a priority higher /* If we have a block time then we are running at a priority higher
than the idle priority. This task takes a long time to complete * than the idle priority. This task takes a long time to complete
a cycle (deliberately so to test the guarding) so will be starving * a cycle (deliberately so to test the guarding) so will be starving
out lower priority tasks. Block for some time to allow give lower * out lower priority tasks. Block for some time to allow give lower
priority tasks some processor time. */ * priority tasks some processor time. */
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR ); vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
} }
else else
@ -254,8 +257,8 @@ short sError = pdFALSE, sCheckVariableToUse;
if( pxParameters->xBlockTime == ( TickType_t ) 0 ) if( pxParameters->xBlockTime == ( TickType_t ) 0 )
{ {
/* We have not got the semaphore yet, so no point using the /* We have not got the semaphore yet, so no point using the
processor. We are not blocking when attempting to obtain the * processor. We are not blocking when attempting to obtain the
semaphore. */ * semaphore. */
taskYIELD(); taskYIELD();
} }
} }
@ -281,5 +284,3 @@ portBASE_TYPE xTask, xReturn = pdTRUE;
return xReturn; return xReturn;
} }

View file

@ -47,7 +47,7 @@
#include "AbortDelay.h" #include "AbortDelay.h"
/* This file can only be used if the functionality it tests is included in the /* This file can only be used if the functionality it tests is included in the
build. Remove the whole file if this is not the case. */ * build. Remove the whole file if this is not the case. */
#if ( INCLUDE_xTaskAbortDelay == 1 ) #if ( INCLUDE_xTaskAbortDelay == 1 )
#if ( INCLUDE_xTaskGetHandle != 1 ) #if ( INCLUDE_xTaskGetHandle != 1 )
@ -111,7 +111,8 @@ static void prvPerformSingleTaskTests( void );
* Checks the amount of time a task spent in the Blocked state is within the * Checks the amount of time a task spent in the Blocked state is within the
* expected bounds. * expected bounds.
*/ */
static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime, TickType_t xExpectedBlockTime ); static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime,
TickType_t xExpectedBlockTime );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -120,7 +121,7 @@ static volatile BaseType_t xControllingCycles = 0, xBlockingCycles = 0;
static volatile BaseType_t xErrorOccurred = pdFALSE; static volatile BaseType_t xErrorOccurred = pdFALSE;
/* Each task needs to know the other tasks handle so they can send signals to /* Each task needs to know the other tasks handle so they can send signals to
each other. The handle is obtained from the task's name. */ * each other. The handle is obtained from the task's name. */
static const char * pcControllingTaskName = "AbtCtrl", * pcBlockingTaskName = "AbtBlk"; static const char * pcControllingTaskName = "AbtCtrl", * pcBlockingTaskName = "AbtBlk";
/* The maximum amount of time a task will block for. */ /* The maximum amount of time a task will block for. */
@ -128,8 +129,8 @@ const TickType_t xMaxBlockTime = pdMS_TO_TICKS( 100 );
const TickType_t xHalfMaxBlockTime = pdMS_TO_TICKS( 50 ); const TickType_t xHalfMaxBlockTime = pdMS_TO_TICKS( 50 );
/* The actual block time is dependent on the priority of other tasks in the /* The actual block time is dependent on the priority of other tasks in the
system so the actual block time might be greater than that expected, but it * system so the actual block time might be greater than that expected, but it
should be within an acceptable upper bound. */ * should be within an acceptable upper bound. */
const TickType_t xAllowableMargin = pdMS_TO_TICKS( 7 ); const TickType_t xAllowableMargin = pdMS_TO_TICKS( 7 );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -162,18 +163,19 @@ const TickType_t xStartMargin = 2UL;
xTaskNotify( xBlockingTask, ulTestToPerform, eSetValueWithOverwrite ); xTaskNotify( xBlockingTask, ulTestToPerform, eSetValueWithOverwrite );
/* The secondary task has a higher priority, so will now be in the /* The secondary task has a higher priority, so will now be in the
Blocked state to wait for a maximum of xMaxBlockTime. It expects that * Blocked state to wait for a maximum of xMaxBlockTime. It expects that
period to complete with a timeout. It will then block for * period to complete with a timeout. It will then block for
xMaxBlockTimeAgain, but this time it expects to the block time to abort * xMaxBlockTimeAgain, but this time it expects to the block time to abort
half way through. Block until it is time to send the abort to the * half way through. Block until it is time to send the abort to the
secondary task. xStartMargin is used because this task takes timing * secondary task. xStartMargin is used because this task takes timing
from the beginning of the test, whereas the blocking task takes timing * from the beginning of the test, whereas the blocking task takes timing
from the entry into the Blocked state - and as the tasks run at * from the entry into the Blocked state - and as the tasks run at
different priorities, there may be some discrepancy. Also, temporarily * different priorities, there may be some discrepancy. Also, temporarily
raise the priority of the controlling task to that of the blocking * raise the priority of the controlling task to that of the blocking
task to minimise discrepancies. */ * task to minimise discrepancies. */
vTaskPrioritySet( NULL, abtBLOCKING_PRIORITY ); vTaskPrioritySet( NULL, abtBLOCKING_PRIORITY );
vTaskDelay( xMaxBlockTime + xHalfMaxBlockTime + xStartMargin ); vTaskDelay( xMaxBlockTime + xHalfMaxBlockTime + xStartMargin );
if( xTaskAbortDelay( xBlockingTask ) != pdPASS ) if( xTaskAbortDelay( xBlockingTask ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -183,12 +185,12 @@ const TickType_t xStartMargin = 2UL;
vTaskPrioritySet( NULL, abtCONTROLLING_PRIORITY ); vTaskPrioritySet( NULL, abtCONTROLLING_PRIORITY );
/* Now wait to be notified that the secondary task has completed its /* Now wait to be notified that the secondary task has completed its
test. */ * test. */
ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
/* Did the entire test run for the expected time, which is two full /* Did the entire test run for the expected time, which is two full
block times plus the half block time caused by calling * block times plus the half block time caused by calling
xTaskAbortDelay()? */ * xTaskAbortDelay()? */
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, ( xMaxBlockTime + xMaxBlockTime + xHalfMaxBlockTime ) ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, ( xMaxBlockTime + xMaxBlockTime + xHalfMaxBlockTime ) );
/* Move onto the next test. */ /* Move onto the next test. */
@ -215,7 +217,7 @@ const uint32_t ulMax = 0xffffffffUL;
( void ) pvParameters; ( void ) pvParameters;
/* Start by performing a few tests to cover code not exercised in the loops /* Start by performing a few tests to cover code not exercised in the loops
below. */ * below. */
prvPerformSingleTaskTests(); prvPerformSingleTaskTests();
xControllingTask = xTaskGetHandle( pcControllingTaskName ); xControllingTask = xTaskGetHandle( pcControllingTaskName );
@ -280,10 +282,11 @@ TaskHandle_t xThisTask;
BaseType_t xReturned; BaseType_t xReturned;
/* Try unblocking this task using both the task and ISR versions of the API - /* Try unblocking this task using both the task and ISR versions of the API -
both should return false as this task is not blocked. */ * both should return false as this task is not blocked. */
xThisTask = xTaskGetCurrentTaskHandle(); xThisTask = xTaskGetCurrentTaskHandle();
xReturned = xTaskAbortDelay( xThisTask ); xReturned = xTaskAbortDelay( xThisTask );
if( xReturned != pdFALSE ) if( xReturned != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -300,23 +303,24 @@ BaseType_t xReturned;
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* Take a copy of the time as it is updated in the call to /* Take a copy of the time as it is updated in the call to
xTaskDelayUntil() but its original value is needed to determine the actual * xTaskDelayUntil() but its original value is needed to determine the actual
time spend in the Blocked state. */ * time spend in the Blocked state. */
xLastBlockTime = xTimeAtStart; xLastBlockTime = xTimeAtStart;
/* This first delay should just time out. */ /* This first delay should just time out. */
xReturned = xTaskDelayUntil( &xLastBlockTime, xMaxBlockTime ); xReturned = xTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
configASSERT( xReturned == pdTRUE ); configASSERT( xReturned == pdTRUE );
/* Remove compiler warning about value being set but not used in the case /* Remove compiler warning about value being set but not used in the case
configASSERT() is not defined. */ * configASSERT() is not defined. */
( void ) xReturned; ( void ) xReturned;
/* This second delay should be aborted by the primary task half way /* This second delay should be aborted by the primary task half way
through. Again take a copy of the time as it is updated in the call to * through. Again take a copy of the time as it is updated in the call to
vTaskDelayUntil() buts its original value is needed to determine the amount * vTaskDelayUntil() buts its original value is needed to determine the amount
of time actually spent in the Blocked state. This uses vTaskDelayUntil() * of time actually spent in the Blocked state. This uses vTaskDelayUntil()
in place of xTaskDelayUntil() for test coverage. */ * in place of xTaskDelayUntil() for test coverage. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
xLastBlockTime = xTimeAtStart; xLastBlockTime = xTimeAtStart;
vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime ); vTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
@ -328,8 +332,9 @@ BaseType_t xReturned;
xReturned = xTaskDelayUntil( &xLastBlockTime, xMaxBlockTime ); xReturned = xTaskDelayUntil( &xLastBlockTime, xMaxBlockTime );
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
configASSERT( xReturned == pdTRUE ); configASSERT( xReturned == pdTRUE );
/* Remove compiler warning about value being set but not used in the case /* Remove compiler warning about value being set but not used in the case
configASSERT() is not defined. */ * configASSERT() is not defined. */
( void ) xReturned; ( void ) xReturned;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -349,7 +354,7 @@ TickType_t xTimeAtStart;
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This second delay should be aborted by the primary task half way /* This second delay should be aborted by the primary task half way
through. */ * through. */
vTaskDelay( xMaxBlockTime ); vTaskDelay( xMaxBlockTime );
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
@ -372,22 +377,26 @@ uint32_t ulReturn;
/* This first delay should just time out. */ /* This first delay should just time out. */
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime ); ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
if( ulReturn != 0 ) if( ulReturn != 0 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This second delay should be aborted by the primary task half way /* This second delay should be aborted by the primary task half way
through. */ * through. */
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime ); ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
if( ulReturn != 0 ) if( ulReturn != 0 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
@ -395,10 +404,12 @@ uint32_t ulReturn;
/* This third delay should just time out again. */ /* This third delay should just time out again. */
ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime ); ulReturn = ulTaskNotifyTake( pdFALSE, xMaxBlockTime );
if( ulReturn != 0 ) if( ulReturn != 0 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -414,7 +425,7 @@ EventBits_t xBitsToWaitFor = ( EventBits_t ) 0x01, xReturn;
static StaticEventGroup_t xEventGroupBuffer; static StaticEventGroup_t xEventGroupBuffer;
/* Create the event group. Statically allocated memory is used so the /* Create the event group. Statically allocated memory is used so the
creation cannot fail. */ * creation cannot fail. */
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer ); xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
} }
#else #else
@ -422,29 +433,33 @@ EventBits_t xBitsToWaitFor = ( EventBits_t ) 0x01, xReturn;
xEventGroup = xEventGroupCreate(); xEventGroup = xEventGroupCreate();
configASSERT( xEventGroup ); configASSERT( xEventGroup );
} }
#endif #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This first delay should just time out. */ /* This first delay should just time out. */
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime ); xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
if( xReturn != 0x00 ) if( xReturn != 0x00 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This second delay should be aborted by the primary task half way /* This second delay should be aborted by the primary task half way
through. */ * through. */
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime ); xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
if( xReturn != 0x00 ) if( xReturn != 0x00 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
@ -452,10 +467,12 @@ EventBits_t xBitsToWaitFor = ( EventBits_t ) 0x01, xReturn;
/* This third delay should just time out again. */ /* This third delay should just time out again. */
xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime ); xReturn = xEventGroupWaitBits( xEventGroup, xBitsToWaitFor, pdTRUE, pdTRUE, xMaxBlockTime );
if( xReturn != 0x00 ) if( xReturn != 0x00 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Not really necessary in this case, but for completeness. */ /* Not really necessary in this case, but for completeness. */
@ -474,7 +491,7 @@ uint8_t uxRxData;
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{ {
/* Defines the memory that will actually hold the streams within the /* Defines the memory that will actually hold the streams within the
stream buffer. */ * stream buffer. */
static uint8_t ucStorageBuffer[ sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) + 1 ]; static uint8_t ucStorageBuffer[ sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) + 1 ];
/* The variable used to hold the stream buffer structure. */ /* The variable used to hold the stream buffer structure. */
@ -486,34 +503,38 @@ uint8_t uxRxData;
ucStorageBuffer, ucStorageBuffer,
&xStreamBufferStruct ); &xStreamBufferStruct );
} }
#else #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
{ {
xStreamBuffer = xStreamBufferCreate( sizeof( uint8_t ), xTriggerLevelBytes ); xStreamBuffer = xStreamBufferCreate( sizeof( uint8_t ), xTriggerLevelBytes );
configASSERT( xStreamBuffer ); configASSERT( xStreamBuffer );
} }
#endif #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This first delay should just time out. */ /* This first delay should just time out. */
xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime ); xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime );
if( xReturn != 0x00 ) if( xReturn != 0x00 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This second delay should be aborted by the primary task half way /* This second delay should be aborted by the primary task half way
through xMaxBlockTime. */ * through xMaxBlockTime. */
xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime ); xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime );
if( xReturn != 0x00 ) if( xReturn != 0x00 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
@ -521,10 +542,12 @@ uint8_t uxRxData;
/* This third delay should just time out again. */ /* This third delay should just time out again. */
xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime ); xReturn = xStreamBufferReceive( xStreamBuffer, &uxRxData, sizeof( uxRxData ), xMaxBlockTime );
if( xReturn != 0x00 ) if( xReturn != 0x00 )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Not really necessary in this case, but for completeness. */ /* Not really necessary in this case, but for completeness. */
@ -546,7 +569,7 @@ uint8_t ucItemToQueue;
static uint8_t ucQueueStorage[ sizeof( uint8_t ) ]; static uint8_t ucQueueStorage[ sizeof( uint8_t ) ];
/* Create the queue. Statically allocated memory is used so the /* Create the queue. Statically allocated memory is used so the
creation cannot fail. */ * creation cannot fail. */
xQueue = xQueueCreateStatic( xQueueLength, sizeof( uint8_t ), ucQueueStorage, &xQueueBuffer ); xQueue = xQueueCreateStatic( xQueueLength, sizeof( uint8_t ), ucQueueStorage, &xQueueBuffer );
} }
#else #else
@ -554,11 +577,12 @@ uint8_t ucItemToQueue;
xQueue = xQueueCreate( xQueueLength, sizeof( uint8_t ) ); xQueue = xQueueCreate( xQueueLength, sizeof( uint8_t ) );
configASSERT( xQueue ); configASSERT( xQueue );
} }
#endif #endif /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
/* This function tests aborting when in the blocked state waiting to send, /* This function tests aborting when in the blocked state waiting to send,
so the queue must be full. There is only one space in the queue. */ * so the queue must be full. There is only one space in the queue. */
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime ); xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
if( xReturn != pdPASS ) if( xReturn != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -569,22 +593,26 @@ uint8_t ucItemToQueue;
/* This first delay should just time out. */ /* This first delay should just time out. */
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime ); xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This second delay should be aborted by the primary task half way /* This second delay should be aborted by the primary task half way
through. */ * through. */
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime ); xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
@ -592,10 +620,12 @@ uint8_t ucItemToQueue;
/* This third delay should just time out again. */ /* This third delay should just time out again. */
xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime ); xReturn = xQueueSend( xQueue, &ucItemToQueue, xMaxBlockTime );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Not really necessary in this case, but for completeness. */ /* Not really necessary in this case, but for completeness. */
@ -614,7 +644,7 @@ SemaphoreHandle_t xSemaphore;
static StaticSemaphore_t xSemaphoreBuffer; static StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. Statically allocated memory is used so the /* Create the semaphore. Statically allocated memory is used so the
creation cannot fail. */ * creation cannot fail. */
xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer ); xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
} }
#else #else
@ -628,22 +658,26 @@ SemaphoreHandle_t xSemaphore;
/* This first delay should just time out. */ /* This first delay should just time out. */
xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime ); xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This second delay should be aborted by the primary task half way /* This second delay should be aborted by the primary task half way
through xMaxBlockTime. */ * through xMaxBlockTime. */
xReturn = xSemaphoreTake( xSemaphore, portMAX_DELAY ); xReturn = xSemaphoreTake( xSemaphore, portMAX_DELAY );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
@ -651,10 +685,12 @@ SemaphoreHandle_t xSemaphore;
/* This third delay should just time out again. */ /* This third delay should just time out again. */
xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime ); xReturn = xSemaphoreTake( xSemaphore, xMaxBlockTime );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Not really necessary in this case, but for completeness. */ /* Not really necessary in this case, but for completeness. */
@ -672,22 +708,26 @@ BaseType_t xReturn;
/* This first delay should just time out. */ /* This first delay should just time out. */
xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime ); xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
xTimeAtStart = xTaskGetTickCount(); xTimeAtStart = xTaskGetTickCount();
/* This second delay should be aborted by the primary task half way /* This second delay should be aborted by the primary task half way
through xMaxBlockTime. */ * through xMaxBlockTime. */
xReturn = xTaskNotifyWait( 0, 0, NULL, portMAX_DELAY ); xReturn = xTaskNotifyWait( 0, 0, NULL, portMAX_DELAY );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xHalfMaxBlockTime );
/* Note the time before the delay so the length of the delay is known. */ /* Note the time before the delay so the length of the delay is known. */
@ -695,15 +735,18 @@ BaseType_t xReturn;
/* This third delay should just time out again. */ /* This third delay should just time out again. */
xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime ); xReturn = xTaskNotifyWait( 0, 0, NULL, xMaxBlockTime );
if( xReturn != pdFALSE ) if( xReturn != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime ); prvCheckExpectedTimeIsWithinAnAcceptableMargin( xTimeAtStart, xMaxBlockTime );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime, TickType_t xExpectedBlockTime ) static void prvCheckExpectedTimeIsWithinAnAcceptableMargin( TickType_t xStartTime,
TickType_t xExpectedBlockTime )
{ {
TickType_t xTimeNow, xActualBlockTime; TickType_t xTimeNow, xActualBlockTime;
@ -717,8 +760,8 @@ TickType_t xTimeNow, xActualBlockTime;
} }
/* The actual block time can be greater than the expected block time, as it /* The actual block time can be greater than the expected block time, as it
depends on the priority of the other tasks, but it should be within an * depends on the priority of the other tasks, but it should be within an
acceptable margin. */ * acceptable margin. */
if( xActualBlockTime > ( xExpectedBlockTime + xAllowableMargin ) ) if( xActualBlockTime > ( xExpectedBlockTime + xAllowableMargin ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -732,7 +775,7 @@ static BaseType_t xLastControllingCycleCount = 0, xLastBlockingCycleCount = 0;
BaseType_t xReturn = pdPASS; BaseType_t xReturn = pdPASS;
/* Have both tasks performed at least one cycle since this function was /* Have both tasks performed at least one cycle since this function was
last called? */ * last called? */
if( xControllingCycles == xLastControllingCycleCount ) if( xControllingCycles == xLastControllingCycleCount )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;

View file

@ -78,16 +78,16 @@ typedef struct BLOCKING_QUEUE_PARAMETERS
static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters ); static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
/* Task function that removes the incrementing number from a queue and checks that /* Task function that removes the incrementing number from a queue and checks that
it is the expected number. */ * it is the expected number. */
static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters ); static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters );
/* Variables which are incremented each time an item is removed from a queue, and /* Variables which are incremented each time an item is removed from a queue, and
found to be the expected value. * found to be the expected value.
These are used to check that the tasks are still running. */ * These are used to check that the tasks are still running. */
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 }; static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
/* Variable which are incremented each time an item is posted on a queue. These /* Variable which are incremented each time an item is posted on a queue. These
are used to check that the tasks are still running. */ * are used to check that the tasks are still running. */
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 }; static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0, ( uint16_t ) 0, ( uint16_t ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -107,14 +107,14 @@ const TickType_t xDontBlock = ( TickType_t ) 0;
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Create the queue used by the first two tasks to pass the incrementing number. /* Create the queue used by the first two tasks to pass the incrementing number.
Pass a pointer to the queue in the parameter structure. */ * Pass a pointer to the queue in the parameter structure. */
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) ); pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) );
/* The consumer is created first so gets a block time as described above. */ /* The consumer is created first so gets a block time as described above. */
pxQueueParameters1->xBlockTime = xBlockTime; pxQueueParameters1->xBlockTime = xBlockTime;
/* Pass in the variable that this task is going to increment so we can check it /* Pass in the variable that this task is going to increment so we can check it
is still running. */ * is still running. */
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] ); pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
/* Create the structure used to pass parameters to the producer task. */ /* Create the structure used to pass parameters to the producer task. */
@ -124,23 +124,23 @@ const TickType_t xDontBlock = ( TickType_t ) 0;
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue; pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
/* The producer is not going to block - as soon as it posts the consumer will /* The producer is not going to block - as soon as it posts the consumer will
wake and remove the item so the producer should always have room to post. */ * wake and remove the item so the producer should always have room to post. */
pxQueueParameters2->xBlockTime = xDontBlock; pxQueueParameters2->xBlockTime = xDontBlock;
/* Pass in the variable that this task is going to increment so we can check /* Pass in the variable that this task is going to increment so we can check
it is still running. */ * it is still running. */
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] ); pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
/* Note the producer has a lower priority than the consumer when the tasks are /* Note the producer has a lower priority than the consumer when the tasks are
spawned. */ * spawned. */
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL ); xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL ); xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
/* Create the second two tasks as described at the top of the file. This uses /* Create the second two tasks as described at the top of the file. This uses
the same mechanism but reverses the task priorities. */ * the same mechanism but reverses the task priorities. */
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) ); pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( UBaseType_t ) sizeof( uint16_t ) );
@ -158,7 +158,7 @@ const TickType_t xDontBlock = ( TickType_t ) 0;
/* Create the last two tasks as described above. The mechanism is again just /* Create the last two tasks as described above. The mechanism is again just
the same. This time both parameter structures are given a block time. */ * the same. This time both parameter structures are given a block time. */
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) ); pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( UBaseType_t ) sizeof( uint16_t ) ); pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( UBaseType_t ) sizeof( uint16_t ) );
pxQueueParameters5->xBlockTime = xBlockTime; pxQueueParameters5->xBlockTime = xBlockTime;
@ -191,14 +191,14 @@ short sErrorEverOccurred = pdFALSE;
else else
{ {
/* We have successfully posted a message, so increment the variable /* We have successfully posted a message, so increment the variable
used to check we are still running. */ * used to check we are still running. */
if( sErrorEverOccurred == pdFALSE ) if( sErrorEverOccurred == pdFALSE )
{ {
( *pxQueueParameters->psCheckVariable )++; ( *pxQueueParameters->psCheckVariable )++;
} }
/* Increment the variable we are going to post next time round. The /* Increment the variable we are going to post next time round. The
consumer will expect the numbers to follow in numerical order. */ * consumer will expect the numbers to follow in numerical order. */
++usValue; ++usValue;
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
@ -231,14 +231,14 @@ short sErrorEverOccurred = pdFALSE;
else else
{ {
/* We have successfully received a message, so increment the /* We have successfully received a message, so increment the
variable used to check we are still running. */ * variable used to check we are still running. */
if( sErrorEverOccurred == pdFALSE ) if( sErrorEverOccurred == pdFALSE )
{ {
( *pxQueueParameters->psCheckVariable )++; ( *pxQueueParameters->psCheckVariable )++;
} }
/* Increment the value we expect to remove from the queue next time /* Increment the value we expect to remove from the queue next time
round. */ * round. */
++usExpectedValue; ++usExpectedValue;
} }
@ -263,11 +263,11 @@ static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( uint16_t ) 0
BaseType_t xReturn = pdPASS, xTasks; BaseType_t xReturn = pdPASS, xTasks;
/* Not too worried about mutual exclusion on these variables as they are 16 /* Not too worried about mutual exclusion on these variables as they are 16
bits and we are only reading them. We also only care to see if they have * bits and we are only reading them. We also only care to see if they have
changed or not. * changed or not.
*
Loop through each check variable to and return pdFALSE if any are found not * Loop through each check variable to and return pdFALSE if any are found not
to have changed since the last call. */ * to have changed since the last call. */
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ ) for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
{ {
@ -275,16 +275,16 @@ BaseType_t xReturn = pdPASS, xTasks;
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] ) if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
} }
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ]; sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
} }
return xReturn; return xReturn;
} }

View file

@ -69,7 +69,7 @@
#define ebALL_BITS ( ebBIT_0 | ebBIT_1 | ebBIT_2 | ebBIT_3 | ebBIT_4 | ebBIT_5 | ebBIT_6 | ebBIT_7 ) #define ebALL_BITS ( ebBIT_0 | ebBIT_1 | ebBIT_2 | ebBIT_3 | ebBIT_4 | ebBIT_5 | ebBIT_6 | ebBIT_7 )
/* Associate a bit to each task. These bits are used to identify all the tasks /* Associate a bit to each task. These bits are used to identify all the tasks
that synchronise with the xEventGroupSync() function. */ * that synchronise with the xEventGroupSync() function. */
#define ebSET_BIT_TASK_SYNC_BIT ebBIT_0 #define ebSET_BIT_TASK_SYNC_BIT ebBIT_0
#define ebWAIT_BIT_TASK_SYNC_BIT ebBIT_1 #define ebWAIT_BIT_TASK_SYNC_BIT ebBIT_1
#define ebRENDESVOUS_TASK_1_SYNC_BIT ebBIT_2 #define ebRENDESVOUS_TASK_1_SYNC_BIT ebBIT_2
@ -83,7 +83,7 @@ that synchronise with the xEventGroupSync() function. */
#define ebSHORT_DELAY pdMS_TO_TICKS( ( TickType_t ) 5 ) #define ebSHORT_DELAY pdMS_TO_TICKS( ( TickType_t ) 5 )
/* Used in the selective bits test which checks no, one or both tasks blocked on /* Used in the selective bits test which checks no, one or both tasks blocked on
event bits in a group are unblocked as appropriate as different bits get set. */ * event bits in a group are unblocked as appropriate as different bits get set. */
#define ebSELECTIVE_BITS_1 0x03 #define ebSELECTIVE_BITS_1 0x03
#define ebSELECTIVE_BITS_2 0x05 #define ebSELECTIVE_BITS_2 0x05
@ -130,13 +130,15 @@ static void prvTestSlaveTask( void *pvParameters );
* 'test slave' task to test the behaviour when the slave blocks on various * 'test slave' task to test the behaviour when the slave blocks on various
* event bit combinations. * event bit combinations.
*/ */
static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ); static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError,
TaskHandle_t xTestSlaveTaskHandle );
/* /*
* The part of the test that uses all the tasks to test the task synchronisation * The part of the test that uses all the tasks to test the task synchronisation
* behaviour. * behaviour.
*/ */
static BaseType_t prvPerformTaskSyncTests( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ); static BaseType_t prvPerformTaskSyncTests( BaseType_t xError,
TaskHandle_t xTestSlaveTaskHandle );
/* /*
* Two instances of prvSyncTask() are created. They start by calling * Two instances of prvSyncTask() are created. They start by calling
@ -157,7 +159,7 @@ static void prvSelectiveBitsTestSlaveFunction( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Variables that are incremented by the tasks on each cycle provided no errors /* Variables that are incremented by the tasks on each cycle provided no errors
have been found. Used to detect an error or stall in the test cycling. */ * have been found. Used to detect an error or stall in the test cycling. */
static volatile uint32_t ulTestMasterCycles = 0, ulTestSlaveCycles = 0, ulISRCycles = 0; static volatile uint32_t ulTestMasterCycles = 0, ulTestSlaveCycles = 0, ulISRCycles = 0;
/* The event group used by all the task based tests. */ /* The event group used by all the task based tests. */
@ -195,7 +197,7 @@ TaskHandle_t xTestSlaveTaskHandle;
configASSERT( xSyncTask2 ); configASSERT( xSyncTask2 );
/* Create the event group used by the ISR tests. The event group used by /* Create the event group used by the ISR tests. The event group used by
the tasks is created by the tasks themselves. */ * the tasks is created by the tasks themselves. */
xISREventGroup = xEventGroupCreate(); xISREventGroup = xEventGroupCreate();
configASSERT( xISREventGroup ); configASSERT( xISREventGroup );
} }
@ -216,8 +218,8 @@ TaskHandle_t xTestSlaveTaskHandle = ( TaskHandle_t ) pvParameters;
configASSERT( xEventGroup ); configASSERT( xEventGroup );
/* Perform the tests that block two tasks on different combinations of bits, /* Perform the tests that block two tasks on different combinations of bits,
then set each bit in turn and check the correct tasks unblock at the correct * then set each bit in turn and check the correct tasks unblock at the correct
times. */ * times. */
xError = prvSelectiveBitsTestMasterFunction(); xError = prvSelectiveBitsTestMasterFunction();
for( ; ; ) for( ; ; )
@ -227,7 +229,7 @@ TaskHandle_t xTestSlaveTaskHandle = ( TaskHandle_t ) pvParameters;
configASSERT( xEventGroup ); configASSERT( xEventGroup );
/* Perform the tests that check the behaviour when a single task is /* Perform the tests that check the behaviour when a single task is
blocked on various combinations of event bits. */ * blocked on various combinations of event bits. */
xError = prvBitCombinationTestMasterFunction( xError, xTestSlaveTaskHandle ); xError = prvBitCombinationTestMasterFunction( xError, xTestSlaveTaskHandle );
/* Perform the task synchronisation tests. */ /* Perform the task synchronisation tests. */
@ -237,7 +239,7 @@ TaskHandle_t xTestSlaveTaskHandle = ( TaskHandle_t ) pvParameters;
vEventGroupDelete( xEventGroup ); vEventGroupDelete( xEventGroup );
/* Now all the other tasks should have completed and suspended /* Now all the other tasks should have completed and suspended
themselves ready for the next go around the loop. */ * themselves ready for the next go around the loop. */
if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -269,37 +271,37 @@ static void prvSyncTask( void *pvParameters )
EventBits_t uxSynchronisationBit, uxReturned; EventBits_t uxSynchronisationBit, uxReturned;
/* A few tests that check the behaviour when two tasks are blocked on /* A few tests that check the behaviour when two tasks are blocked on
various different bits within an event group are performed before this task * various different bits within an event group are performed before this task
enters its infinite loop to carry out its main demo function. */ * enters its infinite loop to carry out its main demo function. */
prvSelectiveBitsTestSlaveFunction(); prvSelectiveBitsTestSlaveFunction();
/* The bit to use to indicate this task is at the synchronisation point is /* The bit to use to indicate this task is at the synchronisation point is
passed in as the task parameter. */ * passed in as the task parameter. */
uxSynchronisationBit = ( EventBits_t ) pvParameters; uxSynchronisationBit = ( EventBits_t ) pvParameters;
for( ; ; ) for( ; ; )
{ {
/* Now this task takes part in a task synchronisation - sometimes known /* Now this task takes part in a task synchronisation - sometimes known
as a 'rendezvous'. Its execution pattern is controlled by the 'test * as a 'rendezvous'. Its execution pattern is controlled by the 'test
master' task, which is responsible for taking this task out of the * master' task, which is responsible for taking this task out of the
Suspended state when it is time to test the synchronisation behaviour. * Suspended state when it is time to test the synchronisation behaviour.
See: http://www.freertos.org/xEventGroupSync.html. */ * See: http://www.freertos.org/xEventGroupSync.html. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* Set the bit that indicates this task is at the synchronisation /* Set the bit that indicates this task is at the synchronisation
point. The first time this is done the 'test master' task has a lower * point. The first time this is done the 'test master' task has a lower
priority than this task so this task will get to the sync point before * priority than this task so this task will get to the sync point before
the set bits task - test this by calling xEventGroupSync() with a zero * the set bits task - test this by calling xEventGroupSync() with a zero
block time before calling again with a max delay - the first call should * block time before calling again with a max delay - the first call should
return before the rendezvous completes, the second only after the * return before the rendezvous completes, the second only after the
rendezvous is complete. */ * rendezvous is complete. */
uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */
uxSynchronisationBit, /* The bit to set in the event group to indicate this task is at the sync point. */ uxSynchronisationBit, /* The bit to set in the event group to indicate this task is at the sync point. */
ebALL_SYNC_BITS, /* The bits to wait for - these bits are set by the other tasks taking part in the sync. */ ebALL_SYNC_BITS, /* The bits to wait for - these bits are set by the other tasks taking part in the sync. */
ebDONT_BLOCK ); /* The maximum time to wait for the sync condition to be met before giving up. */ ebDONT_BLOCK ); /* The maximum time to wait for the sync condition to be met before giving up. */
/* No block time was specified, so as per the comments above, the /* No block time was specified, so as per the comments above, the
rendezvous is not expected to have completed yet. */ * rendezvous is not expected to have completed yet. */
configASSERT( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ); configASSERT( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS );
uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */ uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the synchronisation. */
@ -308,8 +310,8 @@ EventBits_t uxSynchronisationBit, uxReturned;
portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met before giving up. */ portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met before giving up. */
/* A max delay was used, so this task should only exit the above /* A max delay was used, so this task should only exit the above
function call when the sync condition is met. Check this is the * function call when the sync condition is met. Check this is the
case. */ * case. */
configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS ); configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS );
/* Remove compiler warning if configASSERT() is not defined. */ /* Remove compiler warning if configASSERT() is not defined. */
@ -319,18 +321,18 @@ EventBits_t uxSynchronisationBit, uxReturned;
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* Set the bit that indicates this task is at the synchronisation /* Set the bit that indicates this task is at the synchronisation
point again. This time the 'test master' task has a higher priority * point again. This time the 'test master' task has a higher priority
than this task so will get to the sync point before this task. */ * than this task so will get to the sync point before this task. */
uxReturned = xEventGroupSync( xEventGroup, uxSynchronisationBit, ebALL_SYNC_BITS, portMAX_DELAY ); uxReturned = xEventGroupSync( xEventGroup, uxSynchronisationBit, ebALL_SYNC_BITS, portMAX_DELAY );
/* Again a max delay was used, so this task should only exit the above /* Again a max delay was used, so this task should only exit the above
function call when the sync condition is met. Check this is the * function call when the sync condition is met. Check this is the
case. */ * case. */
configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS ); configASSERT( ( uxReturned & ebALL_SYNC_BITS ) == ebALL_SYNC_BITS );
/* Block on the event group again. This time the event group is going /* Block on the event group again. This time the event group is going
to be deleted while this task is blocked on it so it is expected that 0 * to be deleted while this task is blocked on it so it is expected that 0
be returned. */ * be returned. */
uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY );
configASSERT( uxReturned == 0 ); configASSERT( uxReturned == 0 );
} }
@ -352,14 +354,14 @@ BaseType_t xError = pdFALSE;
* prvBitCombinationTestMasterFunction() function which is called by the * prvBitCombinationTestMasterFunction() function which is called by the
* test master task. * test master task.
*********************************************************************** ***********************************************************************
*
This task is controller by the 'test master' task (which is * This task is controller by the 'test master' task (which is
implemented by prvTestMasterTask()). Suspend until resumed by the * implemented by prvTestMasterTask()). Suspend until resumed by the
'test master' task. */ * 'test master' task. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* Wait indefinitely for one of the bits in ebCOMBINED_BITS to get /* Wait indefinitely for one of the bits in ebCOMBINED_BITS to get
set. Clear the bit on exit. */ * set. Clear the bit on exit. */
uxReturned = xEventGroupWaitBits( xEventGroup, /* The event group that contains the event bits being queried. */ uxReturned = xEventGroupWaitBits( xEventGroup, /* The event group that contains the event bits being queried. */
ebBIT_1, /* The bit to wait for. */ ebBIT_1, /* The bit to wait for. */
pdTRUE, /* Clear the bit on exit. */ pdTRUE, /* Clear the bit on exit. */
@ -367,19 +369,19 @@ BaseType_t xError = pdFALSE;
portMAX_DELAY ); /* Block indefinitely to wait for the condition to be met. */ portMAX_DELAY ); /* Block indefinitely to wait for the condition to be met. */
/* The 'test master' task set all the bits defined by ebCOMBINED_BITS, /* The 'test master' task set all the bits defined by ebCOMBINED_BITS,
only one of which was being waited for by this task. The return value * only one of which was being waited for by this task. The return value
shows the state of the event bits when the task was unblocked, however * shows the state of the event bits when the task was unblocked, however
because the task was waiting for ebBIT_1 and 'clear on exit' was set to * because the task was waiting for ebBIT_1 and 'clear on exit' was set to
the current state of the event bits will have ebBIT_1 clear. */ * the current state of the event bits will have ebBIT_1 clear. */
if( uxReturned != ebCOMBINED_BITS ) if( uxReturned != ebCOMBINED_BITS )
{ {
xError = pdTRUE; xError = pdTRUE;
} }
/* Now call xEventGroupWaitBits() again, this time waiting for all the /* Now call xEventGroupWaitBits() again, this time waiting for all the
bits in ebCOMBINED_BITS to be set. This call should block until the * bits in ebCOMBINED_BITS to be set. This call should block until the
'test master' task sets ebBIT_1 - which was the bit cleared in the call * 'test master' task sets ebBIT_1 - which was the bit cleared in the call
to xEventGroupWaitBits() above. */ * to xEventGroupWaitBits() above. */
uxReturned = xEventGroupWaitBits( xEventGroup, uxReturned = xEventGroupWaitBits( xEventGroup,
ebCOMBINED_BITS, /* The bits being waited on. */ ebCOMBINED_BITS, /* The bits being waited on. */
pdFALSE, /* Don't clear the bits on exit. */ pdFALSE, /* Don't clear the bits on exit. */
@ -396,8 +398,8 @@ BaseType_t xError = pdFALSE;
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* Now call xEventGroupWaitBits() again, again waiting for all the bits /* Now call xEventGroupWaitBits() again, again waiting for all the bits
in ebCOMBINED_BITS to be set, but this time clearing the bits when the * in ebCOMBINED_BITS to be set, but this time clearing the bits when the
task is unblocked. */ * task is unblocked. */
uxReturned = xEventGroupWaitBits( xEventGroup, uxReturned = xEventGroupWaitBits( xEventGroup,
ebCOMBINED_BITS, /* The bits being waited on. */ ebCOMBINED_BITS, /* The bits being waited on. */
pdTRUE, /* Clear the bits on exit. */ pdTRUE, /* Clear the bits on exit. */
@ -405,48 +407,44 @@ BaseType_t xError = pdFALSE;
portMAX_DELAY ); portMAX_DELAY );
/* The 'test master' task set all the bits in the event group, so that /* The 'test master' task set all the bits in the event group, so that
is the value that should have been returned. The bits defined by * is the value that should have been returned. The bits defined by
ebCOMBINED_BITS will have been clear again in the current value though * ebCOMBINED_BITS will have been clear again in the current value though
as 'clear on exit' was set to pdTRUE. */ * as 'clear on exit' was set to pdTRUE. */
if( uxReturned != ebALL_BITS ) if( uxReturned != ebALL_BITS )
{ {
xError = pdTRUE; xError = pdTRUE;
} }
/********************************************************************** /**********************************************************************
* Part 2: This section is the counterpart to the * Part 2: This section is the counterpart to the
* prvPerformTaskSyncTests() function which is called by the * prvPerformTaskSyncTests() function which is called by the
* test master task. * test master task.
*********************************************************************** ***********************************************************************
*
*
Once again wait for the 'test master' task to unsuspend this task * Once again wait for the 'test master' task to unsuspend this task
when it is time for the next test. */ * when it is time for the next test. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* Now peform a synchronisation with all the other tasks. At this point /* Now peform a synchronisation with all the other tasks. At this point
the 'test master' task has the lowest priority so will get to the sync * the 'test master' task has the lowest priority so will get to the sync
point after all the other synchronising tasks. */ * point after all the other synchronising tasks. */
uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the sync. */ uxReturned = xEventGroupSync( xEventGroup, /* The event group used for the sync. */
ebWAIT_BIT_TASK_SYNC_BIT, /* The bit in the event group used to indicate this task is at the sync point. */ ebWAIT_BIT_TASK_SYNC_BIT, /* The bit in the event group used to indicate this task is at the sync point. */
ebALL_SYNC_BITS, /* The bits to wait for. These bits are set by the other tasks taking part in the sync. */ ebALL_SYNC_BITS, /* The bits to wait for. These bits are set by the other tasks taking part in the sync. */
portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met before giving up. */ portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met before giving up. */
/* A sync with a max delay should only exit when all the synchronisation /* A sync with a max delay should only exit when all the synchronisation
bits are set... */ * bits are set... */
if( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) if( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS )
{ {
xError = pdTRUE; xError = pdTRUE;
} }
/* ...but now the synchronisation bits should be clear again. Read back /* ...but now the synchronisation bits should be clear again. Read back
the current value of the bits within the event group to check that is * the current value of the bits within the event group to check that is
the case. Setting the bits to zero will return the bits previous value * the case. Setting the bits to zero will return the bits previous value
then leave all the bits clear. */ * then leave all the bits clear. */
if( xEventGroupSetBits( xEventGroup, 0x00 ) != 0 ) if( xEventGroupSetBits( xEventGroup, 0x00 ) != 0 )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -467,12 +465,12 @@ BaseType_t xError = pdFALSE;
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* This time sync when the 'test master' task has the highest priority /* This time sync when the 'test master' task has the highest priority
at the point where it sets its sync bit - so this time the 'test master' * at the point where it sets its sync bit - so this time the 'test master'
task will get to the sync point before this task. */ * task will get to the sync point before this task. */
uxReturned = xEventGroupSync( xEventGroup, ebWAIT_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); uxReturned = xEventGroupSync( xEventGroup, ebWAIT_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY );
/* A sync with a max delay should only exit when all the synchronisation /* A sync with a max delay should only exit when all the synchronisation
bits are set... */ * bits are set... */
if( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) if( ( uxReturned & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -485,8 +483,8 @@ BaseType_t xError = pdFALSE;
} }
/* Block on the event group again. This time the event group is going /* Block on the event group again. This time the event group is going
to be deleted while this task is blocked on it, so it is expected that 0 * to be deleted while this task is blocked on it, so it is expected that 0
will be returned. */ * will be returned. */
uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY ); uxReturned = xEventGroupWaitBits( xEventGroup, ebALL_SYNC_BITS, pdFALSE, pdTRUE, portMAX_DELAY );
if( uxReturned != 0 ) if( uxReturned != 0 )
@ -505,12 +503,13 @@ BaseType_t xError = pdFALSE;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static BaseType_t prvPerformTaskSyncTests( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ) static BaseType_t prvPerformTaskSyncTests( BaseType_t xError,
TaskHandle_t xTestSlaveTaskHandle )
{ {
EventBits_t uxBits; EventBits_t uxBits;
/* The three tasks that take part in the synchronisation (rendezvous) are /* The three tasks that take part in the synchronisation (rendezvous) are
expected to be in the suspended state at the start of the test. */ * expected to be in the suspended state at the start of the test. */
if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -527,7 +526,7 @@ EventBits_t uxBits;
} }
/* Try a synch with no other tasks involved. First set all the bits other /* Try a synch with no other tasks involved. First set all the bits other
than this task's bit. */ * than this task's bit. */
xEventGroupSetBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ); xEventGroupSetBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) );
/* Then wait on just one bit - the bit that is being set. */ /* Then wait on just one bit - the bit that is being set. */
@ -537,15 +536,15 @@ EventBits_t uxBits;
portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met. */ portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met. */
/* A sync with a max delay should only exit when all the synchronise /* A sync with a max delay should only exit when all the synchronise
bits are set...check that is the case. In this case there is only one * bits are set...check that is the case. In this case there is only one
sync bit anyway. */ * sync bit anyway. */
if( ( uxBits & ebSET_BIT_TASK_SYNC_BIT ) != ebSET_BIT_TASK_SYNC_BIT ) if( ( uxBits & ebSET_BIT_TASK_SYNC_BIT ) != ebSET_BIT_TASK_SYNC_BIT )
{ {
xError = pdTRUE; xError = pdTRUE;
} }
/* ...but now the sync bits should be clear again, leaving all the other /* ...but now the sync bits should be clear again, leaving all the other
bits set (as only one bit was being waited for). */ * bits set (as only one bit was being waited for). */
if( xEventGroupGetBits( xEventGroup ) != ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ) if( xEventGroupGetBits( xEventGroup ) != ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -553,13 +552,14 @@ EventBits_t uxBits;
/* Clear all the bits to zero again. */ /* Clear all the bits to zero again. */
xEventGroupClearBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) ); xEventGroupClearBits( xEventGroup, ( ebALL_SYNC_BITS & ~ebSET_BIT_TASK_SYNC_BIT ) );
if( xEventGroupGetBits( xEventGroup ) != 0 ) if( xEventGroupGetBits( xEventGroup ) != 0 )
{ {
xError = pdTRUE; xError = pdTRUE;
} }
/* Unsuspend the other tasks then check they have executed up to the /* Unsuspend the other tasks then check they have executed up to the
synchronisation point. */ * synchronisation point. */
vTaskResume( xTestSlaveTaskHandle ); vTaskResume( xTestSlaveTaskHandle );
vTaskResume( xSyncTask1 ); vTaskResume( xSyncTask1 );
vTaskResume( xSyncTask2 ); vTaskResume( xSyncTask2 );
@ -586,7 +586,7 @@ EventBits_t uxBits;
portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met. */ portMAX_DELAY ); /* The maximum time to wait for the sync condition to be met. */
/* A sync with a max delay should only exit when all the synchronise /* A sync with a max delay should only exit when all the synchronise
bits are set...check that is the case. */ * bits are set...check that is the case. */
if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -598,9 +598,8 @@ EventBits_t uxBits;
xError = pdTRUE; xError = pdTRUE;
} }
/* The other tasks should now all be suspended again, ready for the next /* The other tasks should now all be suspended again, ready for the next
synchronisation. */ * synchronisation. */
if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended ) if( eTaskGetState( xTestSlaveTaskHandle ) != eSuspended )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -616,11 +615,10 @@ EventBits_t uxBits;
xError = pdTRUE; xError = pdTRUE;
} }
/* Sync again - but this time set the last necessary bit as the /* Sync again - but this time set the last necessary bit as the
highest priority task, rather than the lowest priority task. Unsuspend * highest priority task, rather than the lowest priority task. Unsuspend
the other tasks then check they have executed up to the synchronisation * the other tasks then check they have executed up to the synchronisation
point. */ * point. */
vTaskResume( xTestSlaveTaskHandle ); vTaskResume( xTestSlaveTaskHandle );
vTaskResume( xSyncTask1 ); vTaskResume( xSyncTask1 );
vTaskResume( xSyncTask2 ); vTaskResume( xSyncTask2 );
@ -647,7 +645,7 @@ EventBits_t uxBits;
uxBits = xEventGroupSync( xEventGroup, ebSET_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY ); uxBits = xEventGroupSync( xEventGroup, ebSET_BIT_TASK_SYNC_BIT, ebALL_SYNC_BITS, portMAX_DELAY );
/* A sync with a max delay should only exit when all the synchronisation /* A sync with a max delay should only exit when all the synchronisation
bits are set... */ * bits are set... */
if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS ) if( ( uxBits & ebALL_SYNC_BITS ) != ebALL_SYNC_BITS )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -659,9 +657,8 @@ EventBits_t uxBits;
xError = pdTRUE; xError = pdTRUE;
} }
/* The other tasks should now all be in the ready state again, but not /* The other tasks should now all be in the ready state again, but not
executed yet as this task still has a higher relative priority. */ * executed yet as this task still has a higher relative priority. */
if( eTaskGetState( xTestSlaveTaskHandle ) != eReady ) if( eTaskGetState( xTestSlaveTaskHandle ) != eReady )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -677,12 +674,11 @@ EventBits_t uxBits;
xError = pdTRUE; xError = pdTRUE;
} }
/* Reset the priority of this task back to its original value. */ /* Reset the priority of this task back to its original value. */
vTaskPrioritySet( NULL, ebSET_BIT_TASK_PRIORITY ); vTaskPrioritySet( NULL, ebSET_BIT_TASK_PRIORITY );
/* Now all the other tasks should have reblocked on the event bits /* Now all the other tasks should have reblocked on the event bits
to test the behaviour when the event bits are deleted. */ * to test the behaviour when the event bits are deleted. */
if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked ) if( eTaskGetState( xTestSlaveTaskHandle ) != eBlocked )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -702,12 +698,13 @@ EventBits_t uxBits;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError, TaskHandle_t xTestSlaveTaskHandle ) static BaseType_t prvBitCombinationTestMasterFunction( BaseType_t xError,
TaskHandle_t xTestSlaveTaskHandle )
{ {
EventBits_t uxBits; EventBits_t uxBits;
/* Resume the other task. It will block, pending a single bit from /* Resume the other task. It will block, pending a single bit from
within ebCOMBINED_BITS. */ * within ebCOMBINED_BITS. */
vTaskResume( xTestSlaveTaskHandle ); vTaskResume( xTestSlaveTaskHandle );
/* Ensure the other task is blocked on the task. */ /* Ensure the other task is blocked on the task. */
@ -717,13 +714,13 @@ EventBits_t uxBits;
} }
/* Set all the bits in ebCOMBINED_BITS - the 'test slave' task is only /* Set all the bits in ebCOMBINED_BITS - the 'test slave' task is only
blocked waiting for one of them. */ * blocked waiting for one of them. */
xEventGroupSetBits( xEventGroup, ebCOMBINED_BITS ); xEventGroupSetBits( xEventGroup, ebCOMBINED_BITS );
/* The 'test slave' task should now have executed, clearing ebBIT_1 (the /* The 'test slave' task should now have executed, clearing ebBIT_1 (the
bit it was blocked on), then re-entered the Blocked state to wait for * bit it was blocked on), then re-entered the Blocked state to wait for
all the other bits in ebCOMBINED_BITS to be set again. First check * all the other bits in ebCOMBINED_BITS to be set again. First check
ebBIT_1 is clear. */ * ebBIT_1 is clear. */
uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK );
if( uxBits != ( ebCOMBINED_BITS & ~ebBIT_1 ) ) if( uxBits != ( ebCOMBINED_BITS & ~ebBIT_1 ) )
@ -738,7 +735,7 @@ EventBits_t uxBits;
} }
/* Set all the bits other than ebBIT_1 - which is the bit that must be /* Set all the bits other than ebBIT_1 - which is the bit that must be
set before the other task unblocks. */ * set before the other task unblocks. */
xEventGroupSetBits( xEventGroup, ebALL_BITS & ~ebBIT_1 ); xEventGroupSetBits( xEventGroup, ebALL_BITS & ~ebBIT_1 );
/* Ensure all the expected bits are still set. */ /* Ensure all the expected bits are still set. */
@ -756,7 +753,7 @@ EventBits_t uxBits;
} }
/* Now also set ebBIT_1, which should unblock the other task, which will /* Now also set ebBIT_1, which should unblock the other task, which will
then suspend itself. */ * then suspend itself. */
xEventGroupSetBits( xEventGroup, ebBIT_1 ); xEventGroupSetBits( xEventGroup, ebBIT_1 );
/* Ensure the other task is suspended. */ /* Ensure the other task is suspended. */
@ -766,7 +763,7 @@ EventBits_t uxBits;
} }
/* The other task should not have cleared the bits - so all the bits /* The other task should not have cleared the bits - so all the bits
should still be set. */ * should still be set. */
if( xEventGroupSetBits( xEventGroup, 0x00 ) != ebALL_BITS ) if( xEventGroupSetBits( xEventGroup, 0x00 ) != ebALL_BITS )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -779,7 +776,7 @@ EventBits_t uxBits;
} }
/* Resume the other task - which will wait on all the ebCOMBINED_BITS /* Resume the other task - which will wait on all the ebCOMBINED_BITS
again - this time clearing the bits when it is unblocked. */ * again - this time clearing the bits when it is unblocked. */
vTaskResume( xTestSlaveTaskHandle ); vTaskResume( xTestSlaveTaskHandle );
/* Ensure the other task is blocked once again. */ /* Ensure the other task is blocked once again. */
@ -798,7 +795,7 @@ EventBits_t uxBits;
} }
/* The other task should have cleared the bits in ebCOMBINED_BITS. /* The other task should have cleared the bits in ebCOMBINED_BITS.
Clear the remaining bits. */ * Clear the remaining bits. */
uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK ); uxBits = xEventGroupWaitBits( xEventGroup, ebALL_BITS, pdFALSE, pdFALSE, ebDONT_BLOCK );
if( uxBits != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) if( uxBits != ( ebALL_BITS & ~ebCOMBINED_BITS ) )
@ -807,7 +804,7 @@ EventBits_t uxBits;
} }
/* Clear all bits ready for the sync with the other three tasks. The /* Clear all bits ready for the sync with the other three tasks. The
value returned is the value prior to the bits being cleared. */ * value returned is the value prior to the bits being cleared. */
if( xEventGroupClearBits( xEventGroup, ebALL_BITS ) != ( ebALL_BITS & ~ebCOMBINED_BITS ) ) if( xEventGroupClearBits( xEventGroup, ebALL_BITS ) != ( ebALL_BITS & ~ebCOMBINED_BITS ) )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -828,12 +825,12 @@ static void prvSelectiveBitsTestSlaveFunction( void )
EventBits_t uxPendBits, uxReturned; EventBits_t uxPendBits, uxReturned;
/* Used in a test that blocks two tasks on various different bits within an /* Used in a test that blocks two tasks on various different bits within an
event group - then sets each bit in turn and checks that the correct tasks * event group - then sets each bit in turn and checks that the correct tasks
unblock at the correct times. * unblock at the correct times.
*
This function is called by two different tasks - each of which will use a * This function is called by two different tasks - each of which will use a
different bit. Check the task handle to see which task the function was * different bit. Check the task handle to see which task the function was
called by. */ * called by. */
if( xTaskGetCurrentTaskHandle() == xSyncTask1 ) if( xTaskGetCurrentTaskHandle() == xSyncTask1 )
{ {
uxPendBits = ebSELECTIVE_BITS_1; uxPendBits = ebSELECTIVE_BITS_1;
@ -846,8 +843,8 @@ EventBits_t uxPendBits, uxReturned;
for( ; ; ) for( ; ; )
{ {
/* Wait until it is time to perform the next cycle of the test. The /* Wait until it is time to perform the next cycle of the test. The
task is unsuspended by the tests implemented in the * task is unsuspended by the tests implemented in the
prvSelectiveBitsTestMasterFunction() function. */ * prvSelectiveBitsTestMasterFunction() function. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
uxReturned = xEventGroupWaitBits( xEventGroup, uxPendBits, pdTRUE, pdFALSE, portMAX_DELAY ); uxReturned = xEventGroupWaitBits( xEventGroup, uxPendBits, pdTRUE, pdFALSE, portMAX_DELAY );
@ -865,12 +862,12 @@ BaseType_t xError = pdFALSE;
EventBits_t uxBit; EventBits_t uxBit;
/* Used in a test that blocks two tasks on various different bits within an /* Used in a test that blocks two tasks on various different bits within an
event group - then sets each bit in turn and checks that the correct tasks * event group - then sets each bit in turn and checks that the correct tasks
unblock at the correct times. The two other tasks (xSyncTask1 and * unblock at the correct times. The two other tasks (xSyncTask1 and
xSyncTask2) call prvSelectiveBitsTestSlaveFunction() to perform their parts in * xSyncTask2) call prvSelectiveBitsTestSlaveFunction() to perform their parts in
this test. * this test.
*
Both other tasks should start in the suspended state. */ * Both other tasks should start in the suspended state. */
if( eTaskGetState( xSyncTask1 ) != eSuspended ) if( eTaskGetState( xSyncTask1 ) != eSuspended )
{ {
xError = pdTRUE; xError = pdTRUE;
@ -903,7 +900,7 @@ EventBits_t uxBit;
xEventGroupSetBits( xEventGroup, uxBit ); xEventGroupSetBits( xEventGroup, uxBit );
/* Is the bit set in the first set of selective bits? If so the first /* Is the bit set in the first set of selective bits? If so the first
sync task should have unblocked and returned to the suspended state. */ * sync task should have unblocked and returned to the suspended state. */
if( ( uxBit & ebSELECTIVE_BITS_1 ) == 0 ) if( ( uxBit & ebSELECTIVE_BITS_1 ) == 0 )
{ {
/* Task should not have unblocked. */ /* Task should not have unblocked. */
@ -941,13 +938,13 @@ EventBits_t uxBit;
} }
/* Ensure both tasks are blocked on the event group again, then delete the /* Ensure both tasks are blocked on the event group again, then delete the
event group so the other tasks leave this portion of the test. */ * event group so the other tasks leave this portion of the test. */
vTaskResume( xSyncTask1 ); vTaskResume( xSyncTask1 );
vTaskResume( xSyncTask2 ); vTaskResume( xSyncTask2 );
/* Deleting the event group is the signal that the two other tasks should /* Deleting the event group is the signal that the two other tasks should
leave the prvSelectiveBitsTestSlaveFunction() function and continue to the main * leave the prvSelectiveBitsTestSlaveFunction() function and continue to the main
part of their functionality. */ * part of their functionality. */
vEventGroupDelete( xEventGroup ); vEventGroupDelete( xEventGroup );
return xError; return xError;
@ -963,7 +960,7 @@ EventBits_t uxReturned;
BaseType_t xMessagePosted; BaseType_t xMessagePosted;
/* Called periodically from the tick hook to exercise the "FromISR" /* Called periodically from the tick hook to exercise the "FromISR"
functions. */ * functions. */
/* Check the even group tasks were actually created. */ /* Check the even group tasks were actually created. */
configASSERT( xISREventGroup ); configASSERT( xISREventGroup );
@ -974,6 +971,7 @@ BaseType_t xMessagePosted;
{ {
/* All the event bits should start clear. */ /* All the event bits should start clear. */
uxReturned = xEventGroupGetBitsFromISR( xISREventGroup ); uxReturned = xEventGroupGetBitsFromISR( xISREventGroup );
if( uxReturned != 0x00 ) if( uxReturned != 0x00 )
{ {
xISRTestError = pdTRUE; xISRTestError = pdTRUE;
@ -981,9 +979,10 @@ BaseType_t xMessagePosted;
else else
{ {
/* Set the bits. This is called from the tick hook so it is not /* Set the bits. This is called from the tick hook so it is not
necessary to use the last parameter to ensure a context switch * necessary to use the last parameter to ensure a context switch
occurs immediately. */ * occurs immediately. */
xMessagePosted = xEventGroupSetBitsFromISR( xISREventGroup, uxBitsToSet, NULL ); xMessagePosted = xEventGroupSetBitsFromISR( xISREventGroup, uxBitsToSet, NULL );
if( xMessagePosted != pdPASS ) if( xMessagePosted != pdPASS )
{ {
xISRTestError = pdTRUE; xISRTestError = pdTRUE;
@ -994,6 +993,7 @@ BaseType_t xMessagePosted;
{ {
/* Check the bits were set as expected. */ /* Check the bits were set as expected. */
uxReturned = xEventGroupGetBitsFromISR( xISREventGroup ); uxReturned = xEventGroupGetBitsFromISR( xISREventGroup );
if( uxReturned != uxBitsToSet ) if( uxReturned != uxBitsToSet )
{ {
xISRTestError = pdTRUE; xISRTestError = pdTRUE;
@ -1014,7 +1014,7 @@ BaseType_t xMessagePosted;
xCallCount = 0; xCallCount = 0;
/* If no errors have been detected then increment the count of test /* If no errors have been detected then increment the count of test
cycles. */ * cycles. */
if( xISRTestError == pdFALSE ) if( xISRTestError == pdFALSE )
{ {
ulISRCycles++; ulISRCycles++;
@ -1038,22 +1038,22 @@ BaseType_t xStatus = pdPASS;
{ {
xStatus = pdFAIL; xStatus = pdFAIL;
} }
ulPreviousSetBitCycles = ulTestMasterCycles; ulPreviousSetBitCycles = ulTestMasterCycles;
if( ulPreviousWaitBitCycles == ulTestSlaveCycles ) if( ulPreviousWaitBitCycles == ulTestSlaveCycles )
{ {
xStatus = pdFAIL; xStatus = pdFAIL;
} }
ulPreviousWaitBitCycles = ulTestSlaveCycles; ulPreviousWaitBitCycles = ulTestSlaveCycles;
if( ulPreviousISRCycles == ulISRCycles ) if( ulPreviousISRCycles == ulISRCycles )
{ {
xStatus = pdFAIL; xStatus = pdFAIL;
} }
ulPreviousISRCycles = ulISRCycles; ulPreviousISRCycles = ulISRCycles;
return xStatus; return xStatus;
} }

View file

@ -96,8 +96,10 @@ static void prvHighPriorityMutexTask( void *pvParameters );
* first the same order as the two mutexes were obtained, and second the * first the same order as the two mutexes were obtained, and second the
* opposite order as the two mutexes were obtained. * opposite order as the two mutexes were obtained.
*/ */
static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ); static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex,
static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ); SemaphoreHandle_t xLocalMutex );
static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex,
SemaphoreHandle_t xLocalMutex );
#if ( INCLUDE_xTaskAbortDelay == 1 ) #if ( INCLUDE_xTaskAbortDelay == 1 )
@ -106,19 +108,19 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
#endif #endif
/* Tests the behaviour when a low priority task inherits the priority of a /* Tests the behaviour when a low priority task inherits the priority of a
high priority task only for the high priority task to timeout before * high priority task only for the high priority task to timeout before
obtaining the mutex. */ * obtaining the mutex. */
static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex ); static void prvHighPriorityTimeout( SemaphoreHandle_t xMutex );
#endif #endif
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Flag that will be latched to pdTRUE should any unexpected behaviour be /* Flag that will be latched to pdTRUE should any unexpected behaviour be
detected in any of the tasks. */ * detected in any of the tasks. */
static volatile BaseType_t xErrorDetected = pdFALSE; static volatile BaseType_t xErrorDetected = pdFALSE;
/* Counters that are incremented on each cycle of a test. This is used to /* Counters that are incremented on each cycle of a test. This is used to
detect a stalled task - a test that is no longer running. */ * detect a stalled task - a test that is no longer running. */
static volatile uint32_t ulLoopCounter = 0; static volatile uint32_t ulLoopCounter = 0;
static volatile uint32_t ulLoopCounter2 = 0; static volatile uint32_t ulLoopCounter2 = 0;
@ -126,18 +128,18 @@ static volatile uint32_t ulLoopCounter2 = 0;
static volatile uint32_t ulGuardedVariable = 0; static volatile uint32_t ulGuardedVariable = 0;
/* Handles used in the mutex test to suspend and resume the high and medium /* Handles used in the mutex test to suspend and resume the high and medium
priority mutex test tasks. */ * priority mutex test tasks. */
static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask; static TaskHandle_t xHighPriorityMutexTask, xMediumPriorityMutexTask;
/* If INCLUDE_xTaskAbortDelay is 1 additional tests are performed, requiring an /* If INCLUDE_xTaskAbortDelay is 1 additional tests are performed, requiring an
additional task. */ * additional task. */
#if ( INCLUDE_xTaskAbortDelay == 1 ) #if ( INCLUDE_xTaskAbortDelay == 1 )
static TaskHandle_t xSecondMediumPriorityMutexTask; static TaskHandle_t xSecondMediumPriorityMutexTask;
#endif #endif
/* Lets the high priority semaphore task know that its wait for the semaphore /* Lets the high priority semaphore task know that its wait for the semaphore
was aborted, in which case not being able to obtain the semaphore is not to be * was aborted, in which case not being able to obtain the semaphore is not to be
considered an error. */ * considered an error. */
static volatile BaseType_t xBlockWasAborted = pdFALSE; static volatile BaseType_t xBlockWasAborted = pdFALSE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -148,22 +150,22 @@ QueueHandle_t xQueue;
SemaphoreHandle_t xMutex; SemaphoreHandle_t xMutex;
/* Create the queue that we are going to use for the /* Create the queue that we are going to use for the
prvSendFrontAndBackTest demo. */ * prvSendFrontAndBackTest demo. */
xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) ); xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( uint32_t ) );
if( xQueue != NULL ) if( xQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one /* vQueueAddToRegistry() adds the queue to the queue registry, if one
is in use. The queue registry is provided as a means for kernel aware * is in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware debugger * debuggers to locate queues and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( xQueue, "Gen_Queue_Test" ); vQueueAddToRegistry( xQueue, "Gen_Queue_Test" );
/* Create the demo task and pass it the queue just created. We are /* Create the demo task and pass it the queue just created. We are
passing the queue handle by value so it does not matter that it is * passing the queue handle by value so it does not matter that it is
declared on the stack here. */ * declared on the stack here. */
xTaskCreate( prvSendFrontAndBackTest, "GenQ", genqGENERIC_QUEUE_TEST_TASK_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL ); xTaskCreate( prvSendFrontAndBackTest, "GenQ", genqGENERIC_QUEUE_TEST_TASK_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
} }
@ -173,22 +175,22 @@ SemaphoreHandle_t xMutex;
if( xMutex != NULL ) if( xMutex != NULL )
{ {
/* vQueueAddToRegistry() adds the mutex to the registry, if one is /* vQueueAddToRegistry() adds the mutex to the registry, if one is
in use. The registry is provided as a means for kernel aware * in use. The registry is provided as a means for kernel aware
debuggers to locate mutexes and has no purpose if a kernel aware * debuggers to locate mutexes and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will be * debugger is not being used. The call to vQueueAddToRegistry() will be
removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
defined or is defined to be less than 1. */ * defined or is defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Gen_Queue_Mutex" ); vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Gen_Queue_Mutex" );
/* Create the mutex demo tasks and pass it the mutex just created. We /* Create the mutex demo tasks and pass it the mutex just created. We
are passing the mutex handle by value so it does not matter that it is * are passing the mutex handle by value so it does not matter that it is
declared on the stack here. */ * declared on the stack here. */
xTaskCreate( prvLowPriorityMutexTask, "MuLow", genqMUTEX_TEST_TASK_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL ); xTaskCreate( prvLowPriorityMutexTask, "MuLow", genqMUTEX_TEST_TASK_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask ); xTaskCreate( prvMediumPriorityMutexTask, "MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
xTaskCreate( prvHighPriorityMutexTask, "MuHigh", genqMUTEX_TEST_TASK_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask ); xTaskCreate( prvHighPriorityMutexTask, "MuHigh", genqMUTEX_TEST_TASK_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
/* If INCLUDE_xTaskAbortDelay is set then additional tests are performed, /* If INCLUDE_xTaskAbortDelay is set then additional tests are performed,
requiring two instances of prvHighPriorityMutexTask(). */ * requiring two instances of prvHighPriorityMutexTask(). */
#if ( INCLUDE_xTaskAbortDelay == 1 ) #if ( INCLUDE_xTaskAbortDelay == 1 )
{ {
xTaskCreate( prvHighPriorityMutexTask, "MuHigh2", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_MEDIUM_PRIORITY, &xSecondMediumPriorityMutexTask ); xTaskCreate( prvHighPriorityMutexTask, "MuHigh2", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_MEDIUM_PRIORITY, &xSecondMediumPriorityMutexTask );
@ -217,9 +219,9 @@ QueueHandle_t xQueue;
for( ; ; ) for( ; ; )
{ {
/* The queue is empty, so sending an item to the back of the queue /* The queue is empty, so sending an item to the back of the queue
should have the same effect as sending it to the front of the queue. * should have the same effect as sending it to the front of the queue.
*
First send to the front and check everything is as expected. */ * First send to the front and check everything is as expected. */
ulLoopCounterSnapshot = ulLoopCounter; ulLoopCounterSnapshot = ulLoopCounter;
xQueueSendToFront( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK ); xQueueSendToFront( xQueue, ( void * ) &ulLoopCounterSnapshot, intsemNO_BLOCK );
@ -234,14 +236,14 @@ QueueHandle_t xQueue;
} }
/* The data we sent to the queue should equal the data we just received /* The data we sent to the queue should equal the data we just received
from the queue. */ * from the queue. */
if( ulLoopCounter != ulData ) if( ulLoopCounter != ulData )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Then do the same, sending the data to the back, checking everything /* Then do the same, sending the data to the back, checking everything
is as expected. */ * is as expected. */
if( uxQueueMessagesWaiting( xQueue ) != 0 ) if( uxQueueMessagesWaiting( xQueue ) != 0 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -266,7 +268,7 @@ QueueHandle_t xQueue;
} }
/* The data sent to the queue should equal the data just received from /* The data sent to the queue should equal the data just received from
the queue. */ * the queue. */
if( ulLoopCounter != ulData ) if( ulLoopCounter != ulData )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -276,8 +278,6 @@ QueueHandle_t xQueue;
taskYIELD(); taskYIELD();
#endif #endif
/* Place 2, 3, 4 into the queue, adding items to the back of the queue. */ /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
for( ulData = 2; ulData < 5; ulData++ ) for( ulData = 2; ulData < 5; ulData++ )
{ {
@ -285,18 +285,19 @@ QueueHandle_t xQueue;
} }
/* Now the order in the queue should be 2, 3, 4, with 2 being the first /* Now the order in the queue should be 2, 3, 4, with 2 being the first
thing to be read out. Now add 1 then 0 to the front of the queue. */ * thing to be read out. Now add 1 then 0 to the front of the queue. */
if( uxQueueMessagesWaiting( xQueue ) != 3 ) if( uxQueueMessagesWaiting( xQueue ) != 3 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
ulData = 1; ulData = 1;
xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ); xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
ulData = 0; ulData = 0;
xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ); xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK );
/* Now the queue should be full, and when we read the data out we /* Now the queue should be full, and when we read the data out we
should receive 0, 1, 2, 3, 4. */ * should receive 0, 1, 2, 3, 4. */
if( uxQueueMessagesWaiting( xQueue ) != 5 ) if( uxQueueMessagesWaiting( xQueue ) != 5 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -330,10 +331,10 @@ QueueHandle_t xQueue;
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now try receiving the data for real. The value should be the /* Now try receiving the data for real. The value should be the
same. Clobber the value first so we know we really received it. */ * same. Clobber the value first so we know we really received it. */
ulData2 = ~ulData2; ulData2 = ~ulData2;
if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS ) if( xQueueReceive( xQueue, &ulData2, intsemNO_BLOCK ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -358,11 +359,14 @@ QueueHandle_t xQueue;
/* Our queue is empty once more, add 10, 11 to the back. */ /* Our queue is empty once more, add 10, 11 to the back. */
ulData = 10; ulData = 10;
if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS ) if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
ulData = 11; ulData = 11;
if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS ) if( xQueueSend( xQueue, &ulData, intsemNO_BLOCK ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -374,7 +378,7 @@ QueueHandle_t xQueue;
} }
/* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
front. */ * front. */
for( ulData = 9; ulData >= 7; ulData-- ) for( ulData = 9; ulData >= 7; ulData-- )
{ {
if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS ) if( xQueueSendToFront( xQueue, ( void * ) &ulData, intsemNO_BLOCK ) != pdPASS )
@ -384,7 +388,7 @@ QueueHandle_t xQueue;
} }
/* Now check that the queue is full, and that receiving data provides /* Now check that the queue is full, and that receiving data provides
the expected sequence of 7, 8, 9, 10, 11. */ * the expected sequence of 7, 8, 9, 10, 11. */
if( uxQueueMessagesWaiting( xQueue ) != 5 ) if( uxQueueMessagesWaiting( xQueue ) != 5 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -424,7 +428,7 @@ QueueHandle_t xQueue;
} }
/* Increment the loop counter to indicate these tasks are still /* Increment the loop counter to indicate these tasks are still
executing. */ * executing. */
ulLoopCounter++; ulLoopCounter++;
} }
} }
@ -437,115 +441,121 @@ QueueHandle_t xQueue;
static UBaseType_t uxLoopCount = 0; static UBaseType_t uxLoopCount = 0;
/* The tests in this function are very similar, the slight variations /* The tests in this function are very similar, the slight variations
are for code coverage purposes. */ * are for code coverage purposes. */
/* Take the mutex. It should be available now. Check before and after /* Take the mutex. It should be available now. Check before and after
taking that the holder is reported correctly. */ * taking that the holder is reported correctly. */
if( xSemaphoreGetMutexHolder( xMutex ) != NULL ) if( xSemaphoreGetMutexHolder( xMutex ) != NULL )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS ) if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
if( xSemaphoreGetMutexHolder( xMutex ) != xTaskGetCurrentTaskHandle() ) if( xSemaphoreGetMutexHolder( xMutex ) != xTaskGetCurrentTaskHandle() )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* This task's priority should be as per that assigned when the task was /* This task's priority should be as per that assigned when the task was
created. */ * created. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now unsuspend the high priority task. This will attempt to take the /* Now unsuspend the high priority task. This will attempt to take the
mutex, and block when it finds it cannot obtain it. */ * mutex, and block when it finds it cannot obtain it. */
vTaskResume( xHighPriorityMutexTask ); vTaskResume( xHighPriorityMutexTask );
/* This task should now have inherited the priority of the high priority /* This task should now have inherited the priority of the high priority
task as by now the high priority task will have attempted to obtain the * task as by now the high priority task will have attempted to obtain the
mutex. */ * mutex. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Unblock a second medium priority task. It too will attempt to take /* Unblock a second medium priority task. It too will attempt to take
the mutex and enter the Blocked state - it won't run yet though as this * the mutex and enter the Blocked state - it won't run yet though as this
task has inherited a priority above it. */ * task has inherited a priority above it. */
vTaskResume( xSecondMediumPriorityMutexTask ); vTaskResume( xSecondMediumPriorityMutexTask );
/* This task should still have the priority of the high priority task as /* This task should still have the priority of the high priority task as
that had already been inherited as is the highest priority of the three * that had already been inherited as is the highest priority of the three
tasks using the mutex. */ * tasks using the mutex. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* On some loops, block for a short while to provide additional /* On some loops, block for a short while to provide additional
code coverage. Blocking here will allow the medium priority task to * code coverage. Blocking here will allow the medium priority task to
execute and so also block on the mutex so when the high priority task * execute and so also block on the mutex so when the high priority task
causes this task to disinherit the high priority it is inherited down to * causes this task to disinherit the high priority it is inherited down to
the priority of the medium priority task. When there is no delay the * the priority of the medium priority task. When there is no delay the
medium priority task will not run until after the disinheritance, so * medium priority task will not run until after the disinheritance, so
this task will disinherit back to its base priority, then only up to the * this task will disinherit back to its base priority, then only up to the
medium priority after the medium priority has executed. */ * medium priority after the medium priority has executed. */
vTaskDelay( uxLoopCount & ( UBaseType_t ) 0x07 ); vTaskDelay( uxLoopCount & ( UBaseType_t ) 0x07 );
/* Now force the high priority task to unblock. It will fail to obtain /* Now force the high priority task to unblock. It will fail to obtain
the mutex and go back to the suspended state - allowing this task to * the mutex and go back to the suspended state - allowing this task to
execute again. xBlockWasAborted is set to pdTRUE so the higher priority * execute again. xBlockWasAborted is set to pdTRUE so the higher priority
task knows that its failure to obtain the semaphore is not an error. */ * task knows that its failure to obtain the semaphore is not an error. */
xBlockWasAborted = pdTRUE; xBlockWasAborted = pdTRUE;
if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS ) if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* This task has inherited the priority of xHighPriorityMutexTask so /* This task has inherited the priority of xHighPriorityMutexTask so
could still be running even though xHighPriorityMutexTask is no longer * could still be running even though xHighPriorityMutexTask is no longer
blocked. Delay for a short while to ensure xHighPriorityMutexTask gets * blocked. Delay for a short while to ensure xHighPriorityMutexTask gets
a chance to run - indicated by this task changing priority. It should * a chance to run - indicated by this task changing priority. It should
disinherit the high priority task, but then inherit the priority of the * disinherit the high priority task, but then inherit the priority of the
medium priority task that is waiting for the same mutex. */ * medium priority task that is waiting for the same mutex. */
while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY ) while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
{ {
/* If this task gets stuck here then the check variables will stop /* If this task gets stuck here then the check variables will stop
incrementing and the check task will detect the error. */ * incrementing and the check task will detect the error. */
vTaskDelay( genqSHORT_BLOCK ); vTaskDelay( genqSHORT_BLOCK );
} }
/* Now force the medium priority task to unblock. xBlockWasAborted is /* Now force the medium priority task to unblock. xBlockWasAborted is
set to pdTRUE so the medium priority task knows that its failure to * set to pdTRUE so the medium priority task knows that its failure to
obtain the semaphore is not an error. */ * obtain the semaphore is not an error. */
xBlockWasAborted = pdTRUE; xBlockWasAborted = pdTRUE;
if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS ) if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* This time no other tasks are waiting for the mutex, so this task /* This time no other tasks are waiting for the mutex, so this task
should return to its base priority. This might not happen straight * should return to its base priority. This might not happen straight
away as it is running at the same priority as the task it just * away as it is running at the same priority as the task it just
unblocked. */ * unblocked. */
while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
{ {
/* If this task gets stuck here then the check variables will stop /* If this task gets stuck here then the check variables will stop
incrementing and the check task will detect the error. */ * incrementing and the check task will detect the error. */
vTaskDelay( genqSHORT_BLOCK ); vTaskDelay( genqSHORT_BLOCK );
} }
/* Give the semaphore back ready for the next test. Check the mutex /* Give the semaphore back ready for the next test. Check the mutex
holder before and after using the "FromISR" version for code coverage. */ * holder before and after using the "FromISR" version for code coverage. */
if( xSemaphoreGetMutexHolderFromISR( xMutex ) != xTaskGetCurrentTaskHandle() ) if( xSemaphoreGetMutexHolderFromISR( xMutex ) != xTaskGetCurrentTaskHandle() )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
xSemaphoreGive( xMutex ); xSemaphoreGive( xMutex );
if( xSemaphoreGetMutexHolderFromISR( xMutex ) != NULL ) if( xSemaphoreGetMutexHolderFromISR( xMutex ) != NULL )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -553,15 +563,13 @@ QueueHandle_t xQueue;
configASSERT( xErrorDetected == pdFALSE ); configASSERT( xErrorDetected == pdFALSE );
/* Now do the same again, but this time unsuspend the tasks in the /* Now do the same again, but this time unsuspend the tasks in the
opposite order. This takes a different path though the code because * opposite order. This takes a different path though the code because
when the high priority task has its block aborted there is already * when the high priority task has its block aborted there is already
another task in the list of tasks waiting for the mutex, and the * another task in the list of tasks waiting for the mutex, and the
low priority task drops down to that priority, rather than dropping * low priority task drops down to that priority, rather than dropping
down to its base priority before inheriting the priority of the medium * down to its base priority before inheriting the priority of the medium
priority task. */ * priority task. */
if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS ) if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -573,11 +581,11 @@ QueueHandle_t xQueue;
} }
/* This time unsuspend the medium priority task first. This will /* This time unsuspend the medium priority task first. This will
attempt to take the mutex, and block when it finds it cannot obtain it. */ * attempt to take the mutex, and block when it finds it cannot obtain it. */
vTaskResume( xSecondMediumPriorityMutexTask ); vTaskResume( xSecondMediumPriorityMutexTask );
/* This time this task should now have inherited the priority of the /* This time this task should now have inherited the priority of the
medium task. */ * medium task. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -587,17 +595,18 @@ QueueHandle_t xQueue;
vTaskResume( xHighPriorityMutexTask ); vTaskResume( xHighPriorityMutexTask );
/* The high priority task should already have run, causing this task to /* The high priority task should already have run, causing this task to
inherit a priority for the second time. */ * inherit a priority for the second time. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* This time, when the high priority task has its delay aborted and it /* This time, when the high priority task has its delay aborted and it
fails to obtain the mutex this task will immediately have its priority * fails to obtain the mutex this task will immediately have its priority
lowered down to that of the highest priority task waiting on the mutex, * lowered down to that of the highest priority task waiting on the mutex,
which is the medium priority task. */ * which is the medium priority task. */
xBlockWasAborted = pdTRUE; xBlockWasAborted = pdTRUE;
if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS ) if( xTaskAbortDelay( xHighPriorityMutexTask ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -606,14 +615,15 @@ QueueHandle_t xQueue;
while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY ) while( uxTaskPriorityGet( NULL ) != genqMUTEX_MEDIUM_PRIORITY )
{ {
/* If this task gets stuck here then the check variables will stop /* If this task gets stuck here then the check variables will stop
incrementing and the check task will detect the error. */ * incrementing and the check task will detect the error. */
vTaskDelay( genqSHORT_BLOCK ); vTaskDelay( genqSHORT_BLOCK );
} }
/* And finally, when the medium priority task also have its delay /* And finally, when the medium priority task also have its delay
aborted there are no other tasks waiting for the mutex so this task * aborted there are no other tasks waiting for the mutex so this task
returns to its base priority. */ * returns to its base priority. */
xBlockWasAborted = pdTRUE; xBlockWasAborted = pdTRUE;
if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS ) if( xTaskAbortDelay( xSecondMediumPriorityMutexTask ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -622,7 +632,7 @@ QueueHandle_t xQueue;
while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) while( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
{ {
/* If this task gets stuck here then the check variables will stop /* If this task gets stuck here then the check variables will stop
incrementing and the check task will detect the error. */ * incrementing and the check task will detect the error. */
vTaskDelay( genqSHORT_BLOCK ); vTaskDelay( genqSHORT_BLOCK );
} }
@ -632,14 +642,15 @@ QueueHandle_t xQueue;
configASSERT( xErrorDetected == pdFALSE ); configASSERT( xErrorDetected == pdFALSE );
/* uxLoopCount is used to add a variable delay, and in-so-doing provide /* uxLoopCount is used to add a variable delay, and in-so-doing provide
additional code coverage. */ * additional code coverage. */
uxLoopCount++; uxLoopCount++;
} }
#endif /* INCLUDE_xTaskAbortDelay == 1 */ #endif /* INCLUDE_xTaskAbortDelay == 1 */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ) static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex,
SemaphoreHandle_t xLocalMutex )
{ {
/* Take the mutex. It should be available now. */ /* Take the mutex. It should be available now. */
if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS ) if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
@ -651,14 +662,14 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
ulGuardedVariable = 0; ulGuardedVariable = 0;
/* This task's priority should be as per that assigned when the task was /* This task's priority should be as per that assigned when the task was
created. */ * created. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now unsuspend the high priority task. This will attempt to take the /* Now unsuspend the high priority task. This will attempt to take the
mutex, and block when it finds it cannot obtain it. */ * mutex, and block when it finds it cannot obtain it. */
vTaskResume( xHighPriorityMutexTask ); vTaskResume( xHighPriorityMutexTask );
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
@ -666,7 +677,7 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
#endif #endif
/* Ensure the task is reporting its priority as blocked and not /* Ensure the task is reporting its priority as blocked and not
suspended (as it would have done in versions up to V7.5.3). */ * suspended (as it would have done in versions up to V7.5.3). */
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked ); configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
@ -674,29 +685,30 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* This task should now have inherited the priority of the high priority /* This task should now have inherited the priority of the high priority
task as by now the high priority task will have attempted to obtain the * task as by now the high priority task will have attempted to obtain the
mutex. */ * mutex. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Attempt to set the priority of this task to the test priority - /* Attempt to set the priority of this task to the test priority -
between the idle priority and the medium/high test priorities, but the * between the idle priority and the medium/high test priorities, but the
actual priority should remain at the high priority. */ * actual priority should remain at the high priority. */
vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY ); vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now unsuspend the medium priority task. This should not run as the /* Now unsuspend the medium priority task. This should not run as the
inherited priority of this task is above that of the medium priority * inherited priority of this task is above that of the medium priority
task. */ * task. */
vTaskResume( xMediumPriorityMutexTask ); vTaskResume( xMediumPriorityMutexTask );
/* If the medium priority task did run then it will have incremented the /* If the medium priority task did run then it will have incremented the
guarded variable. */ * guarded variable. */
if( ulGuardedVariable != 0 ) if( ulGuardedVariable != 0 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -709,11 +721,11 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
} }
/* When the semaphore is given back the priority of this task should not /* When the semaphore is given back the priority of this task should not
yet be disinherited because the local mutex is still held. This is a * yet be disinherited because the local mutex is still held. This is a
simplification to allow FreeRTOS to be integrated with middleware that * simplification to allow FreeRTOS to be integrated with middleware that
attempts to hold multiple mutexes without bloating the code with complex * attempts to hold multiple mutexes without bloating the code with complex
algorithms. It is possible that the high priority mutex task will * algorithms. It is possible that the high priority mutex task will
execute as it shares a priority with this task. */ * execute as it shares a priority with this task. */
if( xSemaphoreGive( xMutex ) != pdPASS ) if( xSemaphoreGive( xMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -724,8 +736,8 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
#endif #endif
/* The guarded variable is only incremented by the medium priority task, /* The guarded variable is only incremented by the medium priority task,
which still should not have executed as this task should remain at the * which still should not have executed as this task should remain at the
higher priority, ensure this is the case. */ * higher priority, ensure this is the case. */
if( ulGuardedVariable != 0 ) if( ulGuardedVariable != 0 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -737,11 +749,11 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
} }
/* Now also give back the local mutex, taking the held count back to 0. /* Now also give back the local mutex, taking the held count back to 0.
This time the priority of this task should be disinherited back to the * This time the priority of this task should be disinherited back to the
priority to which it was set while the mutex was held. This means * priority to which it was set while the mutex was held. This means
the medium priority task should execute and increment the guarded * the medium priority task should execute and increment the guarded
variable. When this task next runs both the high and medium priority * variable. When this task next runs both the high and medium priority
tasks will have been suspended again. */ * tasks will have been suspended again. */
if( xSemaphoreGive( xLocalMutex ) != pdPASS ) if( xSemaphoreGive( xLocalMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -758,19 +770,20 @@ static void prvTakeTwoMutexesReturnInDifferentOrder( SemaphoreHandle_t xMutex, S
} }
/* ... and that the priority of this task has been disinherited to /* ... and that the priority of this task has been disinherited to
genqMUTEX_TEST_PRIORITY. */ * genqMUTEX_TEST_PRIORITY. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Set the priority of this task back to its original value, ready for /* Set the priority of this task back to its original value, ready for
the next loop around this test. */ * the next loop around this test. */
vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY ); vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, SemaphoreHandle_t xLocalMutex ) static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex,
SemaphoreHandle_t xLocalMutex )
{ {
/* Take the mutex. It should be available now. */ /* Take the mutex. It should be available now. */
if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS ) if( xSemaphoreTake( xMutex, intsemNO_BLOCK ) != pdPASS )
@ -782,14 +795,14 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
ulGuardedVariable = 0; ulGuardedVariable = 0;
/* This task's priority should be as per that assigned when the task was /* This task's priority should be as per that assigned when the task was
created. */ * created. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now unsuspend the high priority task. This will attempt to take the /* Now unsuspend the high priority task. This will attempt to take the
mutex, and block when it finds it cannot obtain it. */ * mutex, and block when it finds it cannot obtain it. */
vTaskResume( xHighPriorityMutexTask ); vTaskResume( xHighPriorityMutexTask );
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
@ -797,7 +810,7 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
#endif #endif
/* Ensure the task is reporting its priority as blocked and not /* Ensure the task is reporting its priority as blocked and not
suspended (as it would have done in versions up to V7.5.3). */ * suspended (as it would have done in versions up to V7.5.3). */
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked ); configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
@ -805,20 +818,20 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* This task should now have inherited the priority of the high priority /* This task should now have inherited the priority of the high priority
task as by now the high priority task will have attempted to obtain the * task as by now the high priority task will have attempted to obtain the
mutex. */ * mutex. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now unsuspend the medium priority task. This should not run as the /* Now unsuspend the medium priority task. This should not run as the
inherited priority of this task is above that of the medium priority * inherited priority of this task is above that of the medium priority
task. */ * task. */
vTaskResume( xMediumPriorityMutexTask ); vTaskResume( xMediumPriorityMutexTask );
/* If the medium priority task did run then it will have incremented the /* If the medium priority task did run then it will have incremented the
guarded variable. */ * guarded variable. */
if( ulGuardedVariable != 0 ) if( ulGuardedVariable != 0 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -831,11 +844,11 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
} }
/* When the local semaphore is given back the priority of this task should /* When the local semaphore is given back the priority of this task should
not yet be disinherited because the shared mutex is still held. This is a * not yet be disinherited because the shared mutex is still held. This is a
simplification to allow FreeRTOS to be integrated with middleware that * simplification to allow FreeRTOS to be integrated with middleware that
attempts to hold multiple mutexes without bloating the code with complex * attempts to hold multiple mutexes without bloating the code with complex
algorithms. It is possible that the high priority mutex task will * algorithms. It is possible that the high priority mutex task will
execute as it shares a priority with this task. */ * execute as it shares a priority with this task. */
if( xSemaphoreGive( xLocalMutex ) != pdPASS ) if( xSemaphoreGive( xLocalMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -846,8 +859,8 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
#endif #endif
/* The guarded variable is only incremented by the medium priority task, /* The guarded variable is only incremented by the medium priority task,
which still should not have executed as this task should remain at the * which still should not have executed as this task should remain at the
higher priority, ensure this is the case. */ * higher priority, ensure this is the case. */
if( ulGuardedVariable != 0 ) if( ulGuardedVariable != 0 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -859,10 +872,10 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
} }
/* Now also give back the shared mutex, taking the held count back to 0. /* Now also give back the shared mutex, taking the held count back to 0.
This time the priority of this task should be disinherited back to the * This time the priority of this task should be disinherited back to the
priority at which it was created. This means the medium priority task * priority at which it was created. This means the medium priority task
should execute and increment the guarded variable. When this task next runs * should execute and increment the guarded variable. When this task next runs
both the high and medium priority tasks will have been suspended again. */ * both the high and medium priority tasks will have been suspended again. */
if( xSemaphoreGive( xMutex ) != pdPASS ) if( xSemaphoreGive( xMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -879,7 +892,7 @@ static void prvTakeTwoMutexesReturnInSameOrder( SemaphoreHandle_t xMutex, Semaph
} }
/* ... and that the priority of this task has been disinherited to /* ... and that the priority of this task has been disinherited to
genqMUTEX_LOW_PRIORITY. */ * genqMUTEX_LOW_PRIORITY. */
if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY ) if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -907,8 +920,8 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
for( ; ; ) for( ; ; )
{ {
/* The first tests exercise the priority inheritance when two mutexes /* The first tests exercise the priority inheritance when two mutexes
are taken then returned in a different order to which they were * are taken then returned in a different order to which they were
taken. */ * taken. */
prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex ); prvTakeTwoMutexesReturnInDifferentOrder( xMutex, xLocalMutex );
/* Just to show this task is still running. */ /* Just to show this task is still running. */
@ -919,7 +932,7 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
#endif #endif
/* The second tests exercise the priority inheritance when two mutexes /* The second tests exercise the priority inheritance when two mutexes
are taken then returned in the same order in which they were taken. */ * are taken then returned in the same order in which they were taken. */
prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex ); prvTakeTwoMutexesReturnInSameOrder( xMutex, xLocalMutex );
/* Just to show this task is still running. */ /* Just to show this task is still running. */
@ -932,8 +945,8 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters, xLocalMutex;
#if ( INCLUDE_xTaskAbortDelay == 1 ) #if ( INCLUDE_xTaskAbortDelay == 1 )
{ {
/* Tests the behaviour when a low priority task inherits the /* Tests the behaviour when a low priority task inherits the
priority of a high priority task only for the high priority task to * priority of a high priority task only for the high priority task to
timeout before obtaining the mutex. */ * timeout before obtaining the mutex. */
prvHighPriorityTimeout( xMutex ); prvHighPriorityTimeout( xMutex );
} }
#endif #endif
@ -948,12 +961,12 @@ static void prvMediumPriorityMutexTask( void *pvParameters )
for( ; ; ) for( ; ; )
{ {
/* The medium priority task starts by suspending itself. The low /* The medium priority task starts by suspending itself. The low
priority task will unsuspend this task when required. */ * priority task will unsuspend this task when required. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* When this task unsuspends all it does is increment the guarded /* When this task unsuspends all it does is increment the guarded
variable, this is so the low priority task knows that it has * variable, this is so the low priority task knows that it has
executed. */ * executed. */
ulGuardedVariable++; ulGuardedVariable++;
} }
} }
@ -966,16 +979,16 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
for( ; ; ) for( ; ; )
{ {
/* The high priority task starts by suspending itself. The low /* The high priority task starts by suspending itself. The low
priority task will unsuspend this task when required. */ * priority task will unsuspend this task when required. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* When this task unsuspends all it does is attempt to obtain the /* When this task unsuspends all it does is attempt to obtain the
mutex. It should find the mutex is not available so a block time is * mutex. It should find the mutex is not available so a block time is
specified. */ * specified. */
if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS ) if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
{ {
/* This task would expect to obtain the mutex unless its wait for /* This task would expect to obtain the mutex unless its wait for
the mutex was aborted. */ * the mutex was aborted. */
if( xBlockWasAborted == pdFALSE ) if( xBlockWasAborted == pdFALSE )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -988,7 +1001,7 @@ SemaphoreHandle_t xMutex = ( SemaphoreHandle_t ) pvParameters;
else else
{ {
/* When the mutex is eventually obtained it is just given back before /* When the mutex is eventually obtained it is just given back before
returning to suspend ready for the next cycle. */ * returning to suspend ready for the next cycle. */
if( xSemaphoreGive( xMutex ) != pdPASS ) if( xSemaphoreGive( xMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -1005,7 +1018,7 @@ BaseType_t xAreGenericQueueTasksStillRunning( void )
static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0; static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
/* If the demo task is still running then we expect the loop counters to /* If the demo task is still running then we expect the loop counters to
have incremented since this function was last called. */ * have incremented since this function was last called. */
if( ulLastLoopCounter == ulLoopCounter ) if( ulLastLoopCounter == ulLoopCounter )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -1020,9 +1033,7 @@ static uint32_t ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
ulLastLoopCounter2 = ulLoopCounter2; ulLastLoopCounter2 = ulLoopCounter2;
/* Errors detected in the task itself will have latched xErrorDetected /* Errors detected in the task itself will have latched xErrorDetected
to true. */ * to true. */
return ( BaseType_t ) !xErrorDetected; return ( BaseType_t ) !xErrorDetected;
} }

View file

@ -63,24 +63,24 @@
#define intqLOWER_PRIORITY ( tskIDLE_PRIORITY ) #define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
/* The number of values to send/receive before checking that all values were /* The number of values to send/receive before checking that all values were
processed as expected. */ * processed as expected. */
#define intqNUM_VALUES_TO_LOG ( 200 ) #define intqNUM_VALUES_TO_LOG ( 200 )
#define intqSHORT_DELAY ( 140 ) #define intqSHORT_DELAY ( 140 )
/* The value by which the value being sent to or received from a queue should /* The value by which the value being sent to or received from a queue should
increment past intqNUM_VALUES_TO_LOG before we check that all values have been * increment past intqNUM_VALUES_TO_LOG before we check that all values have been
sent/received correctly. This is done to ensure that all tasks and interrupts * sent/received correctly. This is done to ensure that all tasks and interrupts
accessing the queue have completed their accesses with the * accessing the queue have completed their accesses with the
intqNUM_VALUES_TO_LOG range. */ * intqNUM_VALUES_TO_LOG range. */
#define intqVALUE_OVERRUN ( 50 ) #define intqVALUE_OVERRUN ( 50 )
/* The delay used by the polling task. A short delay is used for code /* The delay used by the polling task. A short delay is used for code
coverage. */ * coverage. */
#define intqONE_TICK_DELAY ( 1 ) #define intqONE_TICK_DELAY ( 1 )
/* Each task and interrupt is given a unique identifier. This value is used to /* Each task and interrupt is given a unique identifier. This value is used to
identify which task sent or received each value. The identifier is also used * identify which task sent or received each value. The identifier is also used
to distinguish between two tasks that are running the same task function. */ * to distinguish between two tasks that are running the same task function. */
#define intqHIGH_PRIORITY_TASK1 ( ( UBaseType_t ) 1 ) #define intqHIGH_PRIORITY_TASK1 ( ( UBaseType_t ) 1 )
#define intqHIGH_PRIORITY_TASK2 ( ( UBaseType_t ) 2 ) #define intqHIGH_PRIORITY_TASK2 ( ( UBaseType_t ) 2 )
#define intqLOW_PRIORITY_TASK ( ( UBaseType_t ) 3 ) #define intqLOW_PRIORITY_TASK ( ( UBaseType_t ) 3 )
@ -89,11 +89,11 @@ to distinguish between two tasks that are running the same task function. */
#define intqQUEUE_LENGTH ( ( UBaseType_t ) 10 ) #define intqQUEUE_LENGTH ( ( UBaseType_t ) 10 )
/* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
from each queue by each task, otherwise an error is detected. */ * from each queue by each task, otherwise an error is detected. */
#define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 ) #define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
/* Send the next value to the queue that is normally empty. This is called /* Send the next value to the queue that is normally empty. This is called
from within the interrupts. */ * from within the interrupts. */
#define timerNORMALLY_EMPTY_TX() \ #define timerNORMALLY_EMPTY_TX() \
if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \ if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
{ \ { \
@ -109,8 +109,9 @@ from within the interrupts. */
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
} \ } \
/* Send the next value to the queue that is normally full. This is called /* Send the next value to the queue that is normally full. This is called
from within the interrupts. */ * from within the interrupts. */
#define timerNORMALLY_FULL_TX() \ #define timerNORMALLY_FULL_TX() \
if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \ if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
{ \ { \
@ -126,8 +127,9 @@ from within the interrupts. */
portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
} \ } \
/* Receive a value from the normally empty queue. This is called from within /* Receive a value from the normally empty queue. This is called from within
an interrupt. */ * an interrupt. */
#define timerNORMALLY_EMPTY_RX() \ #define timerNORMALLY_EMPTY_RX() \
if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \ if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
{ \ { \
@ -139,7 +141,7 @@ an interrupt. */
} }
/* Receive a value from the normally full queue. This is called from within /* Receive a value from the normally full queue. This is called from within
an interrupt. */ * an interrupt. */
#define timerNORMALLY_FULL_RX() \ #define timerNORMALLY_FULL_RX() \
if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \ if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
{ \ { \
@ -156,7 +158,7 @@ static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue;
static volatile UBaseType_t uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0; static volatile UBaseType_t uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
/* Any unexpected behaviour sets xErrorStatus to fail and log the line that /* Any unexpected behaviour sets xErrorStatus to fail and log the line that
caused the error in xErrorLine. */ * caused the error in xErrorLine. */
static BaseType_t xErrorStatus = pdPASS; static BaseType_t xErrorStatus = pdPASS;
static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0; static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0;
@ -164,16 +166,16 @@ static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0;
static BaseType_t xWasSuspended = pdFALSE; static BaseType_t xWasSuspended = pdFALSE;
/* The values that are sent to the queues. An incremented value is sent each /* The values that are sent to the queues. An incremented value is sent each
time to each queue. */ * time to each queue. */
static volatile UBaseType_t uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0; static volatile UBaseType_t uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
/* A handle to some of the tasks is required so they can be suspended/resumed. */ /* A handle to some of the tasks is required so they can be suspended/resumed. */
TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2; TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
/* When a value is received in a queue the value is ticked off in the array /* When a value is received in a queue the value is ticked off in the array
the array position of the value is set to a the identifier of the task or * the array position of the value is set to a the identifier of the task or
interrupt that accessed the queue. This way missing or duplicate values can be * interrupt that accessed the queue. This way missing or duplicate values can be
detected. */ * detected. */
static uint8_t ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 }; static uint8_t ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
static uint8_t ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 }; static uint8_t ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
@ -185,9 +187,11 @@ static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
static void prv2ndHigherPriorityNormallyFullTask( void * pvParameters ); static void prv2ndHigherPriorityNormallyFullTask( void * pvParameters );
/* Used to mark the positions within the ucNormallyEmptyReceivedValues and /* Used to mark the positions within the ucNormallyEmptyReceivedValues and
ucNormallyFullReceivedValues arrays, while checking for duplicates. */ * ucNormallyFullReceivedValues arrays, while checking for duplicates. */
static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource ); static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue,
static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource ); UBaseType_t uxSource );
static void prvRecordValue_NormallyFull( UBaseType_t uxValue,
UBaseType_t uxSource );
/* Logs the line on which an error occurred. */ /* Logs the line on which an error occurred. */
static void prvQueueAccessLogError( UBaseType_t uxLine ); static void prvQueueAccessLogError( UBaseType_t uxLine );
@ -205,27 +209,28 @@ void vStartInterruptQueueTasks( void )
xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL ); xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
/* Create the queues that are accessed by multiple tasks and multiple /* Create the queues that are accessed by multiple tasks and multiple
interrupts. */ * interrupts. */
xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) ); xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) ); xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
in use. The queue registry is provided as a means for kernel aware * in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware debugger * debuggers to locate queues and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" ); vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" );
vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" ); vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource ) static void prvRecordValue_NormallyFull( UBaseType_t uxValue,
UBaseType_t uxSource )
{ {
if( uxValue < intqNUM_VALUES_TO_LOG ) if( uxValue < intqNUM_VALUES_TO_LOG )
{ {
/* We don't expect to receive the same value twice, so if the value /* We don't expect to receive the same value twice, so if the value
has already been marked as received an error has occurred. */ * has already been marked as received an error has occurred. */
if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 ) if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
{ {
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
@ -237,12 +242,13 @@ static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSour
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource ) static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue,
UBaseType_t uxSource )
{ {
if( uxValue < intqNUM_VALUES_TO_LOG ) if( uxValue < intqNUM_VALUES_TO_LOG )
{ {
/* We don't expect to receive the same value twice, so if the value /* We don't expect to receive the same value twice, so if the value
has already been marked as received an error has occurred. */ * has already been marked as received an error has occurred. */
if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 ) if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
{ {
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
@ -267,8 +273,8 @@ static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0; UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
/* The timer should not be started until after the scheduler has started. /* The timer should not be started until after the scheduler has started.
More than one task is running this code so we check the parameter value * More than one task is running this code so we check the parameter value
to determine which task should start the timer. */ * to determine which task should start the timer. */
if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 ) if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
{ {
vInitialiseTimerForIntQueueTest(); vInitialiseTimerForIntQueueTest();
@ -277,7 +283,7 @@ UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErr
for( ; ; ) for( ; ; )
{ {
/* Block waiting to receive a value from the normally empty queue. /* Block waiting to receive a value from the normally empty queue.
Interrupts will write to the queue so we should receive a value. */ * Interrupts will write to the queue so we should receive a value. */
if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS ) if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
{ {
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
@ -285,7 +291,7 @@ UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErr
else else
{ {
/* Note which value was received so we can check all expected /* Note which value was received so we can check all expected
values are received and no values are duplicated. */ * values are received and no values are duplicated. */
prvRecordValue_NormallyEmpty( uxRxed, ( UBaseType_t ) pvParameters ); prvRecordValue_NormallyEmpty( uxRxed, ( UBaseType_t ) pvParameters );
} }
@ -304,8 +310,8 @@ UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErr
uxInterrupts = 0; uxInterrupts = 0;
/* Loop through the array, checking that both tasks have /* Loop through the array, checking that both tasks have
placed values into the array, and that no values are missing. * placed values into the array, and that no values are missing.
Start at 1 as we expect position 0 to be unused. */ * Start at 1 as we expect position 0 to be unused. */
for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ ) for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
{ {
if( ucNormallyEmptyReceivedValues[ ux ] == 0 ) if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
@ -336,6 +342,7 @@ UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErr
{ {
/* Only task 2 seemed to log any values. */ /* Only task 2 seemed to log any values. */
uxErrorCount1++; uxErrorCount1++;
if( uxErrorCount1 > 2 ) if( uxErrorCount1 > 2 )
{ {
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
@ -350,6 +357,7 @@ UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErr
{ {
/* Only task 1 seemed to log any values. */ /* Only task 1 seemed to log any values. */
uxErrorCount2++; uxErrorCount2++;
if( uxErrorCount2 > 2 ) if( uxErrorCount2 > 2 )
{ {
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
@ -372,11 +380,11 @@ UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErr
uxValueForNormallyEmptyQueue = 0; uxValueForNormallyEmptyQueue = 0;
/* Suspend ourselves, allowing the lower priority task to /* Suspend ourselves, allowing the lower priority task to
actually receive something from the queue. Until now it * actually receive something from the queue. Until now it
will have been prevented from doing so by the higher * will have been prevented from doing so by the higher
priority tasks. The lower priority task will resume us * priority tasks. The lower priority task will resume us
if it receives something. We will then resume the other * if it receives something. We will then resume the other
higher priority task. */ * higher priority task. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
vTaskResume( xHighPriorityNormallyEmptyTask2 ); vTaskResume( xHighPriorityNormallyEmptyTask2 );
} }
@ -397,7 +405,7 @@ UBaseType_t uxValue, uxRxed;
if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY ) if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
{ {
/* A value should only be obtained when the high priority task is /* A value should only be obtained when the high priority task is
suspended. */ * suspended. */
if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended ) if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended )
{ {
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
@ -412,7 +420,7 @@ UBaseType_t uxValue, uxRxed;
else else
{ {
/* Raise our priority while we send so we can preempt the higher /* Raise our priority while we send so we can preempt the higher
priority task, and ensure we get the Tx value into the queue. */ * priority task, and ensure we get the Tx value into the queue. */
vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 ); vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
portENTER_CRITICAL(); portENTER_CRITICAL();
@ -441,7 +449,7 @@ UBaseType_t uxValueToTx, ux, uxInterrupts;
( void ) pvParameters; ( void ) pvParameters;
/* Make sure the queue starts full or near full. >> 1 as there are two /* Make sure the queue starts full or near full. >> 1 as there are two
high priority tasks. */ * high priority tasks. */
for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ ) for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
{ {
portENTER_CRITICAL(); portENTER_CRITICAL();
@ -466,7 +474,7 @@ UBaseType_t uxValueToTx, ux, uxInterrupts;
if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS ) if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
{ {
/* intqHIGH_PRIORITY_TASK2 is never suspended so we would not /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
expect it to ever time out. */ * expect it to ever time out. */
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
} }
@ -477,7 +485,7 @@ UBaseType_t uxValueToTx, ux, uxInterrupts;
if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) ) if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
{ {
/* Make sure the other high priority task completes its send of /* Make sure the other high priority task completes its send of
any values below intqNUM_VALUE_TO_LOG. */ * any values below intqNUM_VALUE_TO_LOG. */
vTaskDelay( intqSHORT_DELAY ); vTaskDelay( intqSHORT_DELAY );
vTaskSuspend( xHighPriorityNormallyFullTask2 ); vTaskSuspend( xHighPriorityNormallyFullTask2 );
@ -485,12 +493,12 @@ UBaseType_t uxValueToTx, ux, uxInterrupts;
if( xWasSuspended == pdTRUE ) if( xWasSuspended == pdTRUE )
{ {
/* We would have expected the other high priority task to have /* We would have expected the other high priority task to have
set this back to false by now. */ * set this back to false by now. */
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
} }
/* Set the suspended flag so an error is not logged if the other /* Set the suspended flag so an error is not logged if the other
task recognises a time out when it is unsuspended. */ * task recognises a time out when it is unsuspended. */
xWasSuspended = pdTRUE; xWasSuspended = pdTRUE;
/* Check interrupts are also sending. */ /* Check interrupts are also sending. */
@ -513,7 +521,7 @@ UBaseType_t uxValueToTx, ux, uxInterrupts;
if( uxInterrupts == 0 ) if( uxInterrupts == 0 )
{ {
/* No writes from interrupts were found. Are interrupts /* No writes from interrupts were found. Are interrupts
actually running? */ * actually running? */
prvQueueAccessLogError( __LINE__ ); prvQueueAccessLogError( __LINE__ );
} }
@ -524,11 +532,11 @@ UBaseType_t uxValueToTx, ux, uxInterrupts;
uxValueForNormallyFullQueue = 0; uxValueForNormallyFullQueue = 0;
/* Suspend ourselves, allowing the lower priority task to /* Suspend ourselves, allowing the lower priority task to
actually receive something from the queue. Until now it * actually receive something from the queue. Until now it
will have been prevented from doing so by the higher * will have been prevented from doing so by the higher
priority tasks. The lower priority task will resume us * priority tasks. The lower priority task will resume us
if it receives something. We will then resume the other * if it receives something. We will then resume the other
higher priority task. */ * higher priority task. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
vTaskResume( xHighPriorityNormallyFullTask2 ); vTaskResume( xHighPriorityNormallyFullTask2 );
} }
@ -544,7 +552,7 @@ UBaseType_t uxValueToTx, ux;
( void ) pvParameters; ( void ) pvParameters;
/* Make sure the queue starts full or near full. >> 1 as there are two /* Make sure the queue starts full or near full. >> 1 as there are two
high priority tasks. */ * high priority tasks. */
for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ ) for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
{ {
portENTER_CRITICAL(); portENTER_CRITICAL();
@ -605,7 +613,7 @@ UBaseType_t uxValue, uxTxed = 9999;
else else
{ {
/* Raise our priority while we receive so we can preempt the higher /* Raise our priority while we receive so we can preempt the higher
priority task, and ensure we get the value from the queue. */ * priority task, and ensure we get the value from the queue. */
vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 ); vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS ) if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
@ -630,7 +638,7 @@ UBaseType_t uxRxedValue;
static UBaseType_t uxNextOperation = 0; static UBaseType_t uxNextOperation = 0;
/* Called from a timer interrupt. Perform various read and write /* Called from a timer interrupt. Perform various read and write
accesses on the queues. */ * accesses on the queues. */
uxNextOperation++; uxNextOperation++;
@ -658,7 +666,7 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
static UBaseType_t uxNextOperation = 0; static UBaseType_t uxNextOperation = 0;
/* Called from a timer interrupt. Perform various read and write /* Called from a timer interrupt. Perform various read and write
accesses on the queues. */ * accesses on the queues. */
uxNextOperation++; uxNextOperation++;
@ -688,7 +696,7 @@ BaseType_t xAreIntQueueTasksStillRunning( void )
static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0; static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
/* xErrorStatus can be set outside of this function. This function just /* xErrorStatus can be set outside of this function. This function just
checks that all the tasks are still cycling. */ * checks that all the tasks are still cycling. */
if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 ) if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
{ {
@ -724,4 +732,3 @@ static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, u
return xErrorStatus; return xErrorStatus;
} }

View file

@ -54,7 +54,7 @@
#define intsemNO_BLOCK 0 #define intsemNO_BLOCK 0
/* The maximum count value for the counting semaphore given from an /* The maximum count value for the counting semaphore given from an
interrupt. */ * interrupt. */
#define intsemMAX_COUNT 3 #define intsemMAX_COUNT 3
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -95,32 +95,32 @@ static void vInterruptCountingSemaphoreTask( void *pvParameters );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Flag that will be latched to pdTRUE should any unexpected behaviour be /* Flag that will be latched to pdTRUE should any unexpected behaviour be
detected in any of the tasks. */ * detected in any of the tasks. */
static volatile BaseType_t xErrorDetected = pdFALSE; static volatile BaseType_t xErrorDetected = pdFALSE;
/* Counters that are incremented on each cycle of a test. This is used to /* Counters that are incremented on each cycle of a test. This is used to
detect a stalled task - a test that is no longer running. */ * detect a stalled task - a test that is no longer running. */
static volatile uint32_t ulMasterLoops = 0, ulCountingSemaphoreLoops = 0; static volatile uint32_t ulMasterLoops = 0, ulCountingSemaphoreLoops = 0;
/* Handles of the test tasks that must be accessed from other test tasks. */ /* Handles of the test tasks that must be accessed from other test tasks. */
static TaskHandle_t xSlaveHandle; static TaskHandle_t xSlaveHandle;
/* A mutex which is given from an interrupt - although generally mutexes should /* A mutex which is given from an interrupt - although generally mutexes should
not be used given in interrupts (and definitely never taken in an interrupt) * not be used given in interrupts (and definitely never taken in an interrupt)
there are some circumstances when it may be desirable. */ * there are some circumstances when it may be desirable. */
static SemaphoreHandle_t xISRMutex = NULL; static SemaphoreHandle_t xISRMutex = NULL;
/* A counting semaphore which is given from an interrupt. */ /* A counting semaphore which is given from an interrupt. */
static SemaphoreHandle_t xISRCountingSemaphore = NULL; static SemaphoreHandle_t xISRCountingSemaphore = NULL;
/* A mutex which is shared between the master and slave tasks - the master /* A mutex which is shared between the master and slave tasks - the master
does both sharing of this mutex with the slave and receiving a mutex from the * does both sharing of this mutex with the slave and receiving a mutex from the
interrupt. */ * interrupt. */
static SemaphoreHandle_t xMasterSlaveMutex = NULL; static SemaphoreHandle_t xMasterSlaveMutex = NULL;
/* Flag that allows the master task to control when the interrupt gives or does /* Flag that allows the master task to control when the interrupt gives or does
not give the mutex. There is no mutual exclusion on this variable, but this is * not give the mutex. There is no mutual exclusion on this variable, but this is
only test code and it should be fine in the 32=bit test environment. */ * only test code and it should be fine in the 32=bit test environment. */
static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE; static BaseType_t xOkToGiveMutex = pdFALSE, xOkToGiveCountingSemaphore = pdFALSE;
/* Used to coordinate timing between tasks and the interrupt. */ /* Used to coordinate timing between tasks and the interrupt. */
@ -137,8 +137,8 @@ void vStartInterruptSemaphoreTasks( void )
configASSERT( xISRCountingSemaphore ); configASSERT( xISRCountingSemaphore );
/* Create the mutex that is shared between the master and slave tasks (the /* Create the mutex that is shared between the master and slave tasks (the
master receives a mutex from an interrupt and shares a mutex with the * master receives a mutex from an interrupt and shares a mutex with the
slave. */ * slave. */
xMasterSlaveMutex = xSemaphoreCreateMutex(); xMasterSlaveMutex = xSemaphoreCreateMutex();
configASSERT( xMasterSlaveMutex ); configASSERT( xMasterSlaveMutex );
@ -176,7 +176,7 @@ static void vInterruptMutexMasterTask( void *pvParameters )
static void prvTakeAndGiveInTheSameOrder( void ) static void prvTakeAndGiveInTheSameOrder( void )
{ {
/* Ensure the slave is suspended, and that this task is running at the /* Ensure the slave is suspended, and that this task is running at the
lower priority as expected as the start conditions. */ * lower priority as expected as the start conditions. */
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended ); configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
@ -195,11 +195,11 @@ static void prvTakeAndGiveInTheSameOrder( void )
} }
/* This task now has the mutex. Unsuspend the slave so it too /* This task now has the mutex. Unsuspend the slave so it too
attempts to take the mutex. */ * attempts to take the mutex. */
vTaskResume( xSlaveHandle ); vTaskResume( xSlaveHandle );
/* The slave has the higher priority so should now have executed and /* The slave has the higher priority so should now have executed and
blocked on the semaphore. */ * blocked on the semaphore. */
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked ); configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked );
@ -207,23 +207,25 @@ static void prvTakeAndGiveInTheSameOrder( void )
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* This task should now have inherited the priority of the slave /* This task should now have inherited the priority of the slave
task. */ * task. */
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now wait a little longer than the time between ISR gives to also /* Now wait a little longer than the time between ISR gives to also
obtain the ISR mutex. */ * obtain the ISR mutex. */
xOkToGiveMutex = pdTRUE; xOkToGiveMutex = pdTRUE;
if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS ) if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
xOkToGiveMutex = pdFALSE; xOkToGiveMutex = pdFALSE;
/* Attempting to take again immediately should fail as the mutex is /* Attempting to take again immediately should fail as the mutex is
already held. */ * already held. */
if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL ) if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -236,8 +238,8 @@ static void prvTakeAndGiveInTheSameOrder( void )
} }
/* Give back the ISR semaphore to ensure the priority is not /* Give back the ISR semaphore to ensure the priority is not
disinherited as the shared mutex (which the higher priority task is * disinherited as the shared mutex (which the higher priority task is
attempting to obtain) is still held. */ * attempting to obtain) is still held. */
if( xSemaphoreGive( xISRMutex ) != pdPASS ) if( xSemaphoreGive( xISRMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -249,9 +251,9 @@ static void prvTakeAndGiveInTheSameOrder( void )
} }
/* Finally give back the shared mutex. This time the higher priority /* Finally give back the shared mutex. This time the higher priority
task should run before this task runs again - so this task should have * task should run before this task runs again - so this task should have
disinherited the priority and the higher priority task should be in the * disinherited the priority and the higher priority task should be in the
suspended state again. */ * suspended state again. */
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS ) if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -276,7 +278,7 @@ static void prvTakeAndGiveInTheSameOrder( void )
static void prvTakeAndGiveInTheOppositeOrder( void ) static void prvTakeAndGiveInTheOppositeOrder( void )
{ {
/* Ensure the slave is suspended, and that this task is running at the /* Ensure the slave is suspended, and that this task is running at the
lower priority as expected as the start conditions. */ * lower priority as expected as the start conditions. */
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended ); configASSERT( eTaskGetState( xSlaveHandle ) == eSuspended );
@ -295,11 +297,11 @@ static void prvTakeAndGiveInTheOppositeOrder( void )
} }
/* This task now has the mutex. Unsuspend the slave so it too /* This task now has the mutex. Unsuspend the slave so it too
attempts to take the mutex. */ * attempts to take the mutex. */
vTaskResume( xSlaveHandle ); vTaskResume( xSlaveHandle );
/* The slave has the higher priority so should now have executed and /* The slave has the higher priority so should now have executed and
blocked on the semaphore. */ * blocked on the semaphore. */
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked ); configASSERT( eTaskGetState( xSlaveHandle ) == eBlocked );
@ -307,23 +309,25 @@ static void prvTakeAndGiveInTheOppositeOrder( void )
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* This task should now have inherited the priority of the slave /* This task should now have inherited the priority of the slave
task. */ * task. */
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now wait a little longer than the time between ISR gives to also /* Now wait a little longer than the time between ISR gives to also
obtain the ISR mutex. */ * obtain the ISR mutex. */
xOkToGiveMutex = pdTRUE; xOkToGiveMutex = pdTRUE;
if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS ) if( xSemaphoreTake( xISRMutex, ( xInterruptGivePeriod * 2 ) ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
xOkToGiveMutex = pdFALSE; xOkToGiveMutex = pdFALSE;
/* Attempting to take again immediately should fail as the mutex is /* Attempting to take again immediately should fail as the mutex is
already held. */ * already held. */
if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL ) if( xSemaphoreTake( xISRMutex, intsemNO_BLOCK ) != pdFAIL )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -336,23 +340,23 @@ static void prvTakeAndGiveInTheOppositeOrder( void )
} }
/* Give back the shared semaphore to ensure the priority is not disinherited /* Give back the shared semaphore to ensure the priority is not disinherited
as the ISR mutex is still held. The higher priority slave task should run * as the ISR mutex is still held. The higher priority slave task should run
before this task runs again. */ * before this task runs again. */
if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS ) if( xSemaphoreGive( xMasterSlaveMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Should still be at the priority of the slave task as this task still /* Should still be at the priority of the slave task as this task still
holds one semaphore (this is a simplification in the priority inheritance * holds one semaphore (this is a simplification in the priority inheritance
mechanism. */ * mechanism. */
if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY ) if( uxTaskPriorityGet( NULL ) != intsemSLAVE_PRIORITY )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Give back the ISR semaphore, which should result in the priority being /* Give back the ISR semaphore, which should result in the priority being
disinherited as it was the last mutex held. */ * disinherited as it was the last mutex held. */
if( xSemaphoreGive( xISRMutex ) != pdPASS ) if( xSemaphoreGive( xISRMutex ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -376,12 +380,12 @@ static void vInterruptMutexSlaveTask( void *pvParameters )
for( ; ; ) for( ; ; )
{ {
/* This task starts by suspending itself so when it executes can be /* This task starts by suspending itself so when it executes can be
controlled by the master task. */ * controlled by the master task. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* This task will execute when the master task already holds the mutex. /* This task will execute when the master task already holds the mutex.
Attempting to take the mutex will place this task in the Blocked * Attempting to take the mutex will place this task in the Blocked
state. */ * state. */
if( xSemaphoreTake( xMasterSlaveMutex, portMAX_DELAY ) != pdPASS ) if( xSemaphoreTake( xMasterSlaveMutex, portMAX_DELAY ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -411,7 +415,7 @@ const TickType_t xDelay = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS )
} }
/* Wait until it is expected that the interrupt will have filled the /* Wait until it is expected that the interrupt will have filled the
counting semaphore. */ * counting semaphore. */
xOkToGiveCountingSemaphore = pdTRUE; xOkToGiveCountingSemaphore = pdTRUE;
vTaskDelay( xDelay ); vTaskDelay( xDelay );
xOkToGiveCountingSemaphore = pdFALSE; xOkToGiveCountingSemaphore = pdFALSE;
@ -430,9 +434,10 @@ const TickType_t xDelay = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS )
ulCountingSemaphoreLoops++; ulCountingSemaphoreLoops++;
/* Expect to be able to take the counting semaphore intsemMAX_COUNT /* Expect to be able to take the counting semaphore intsemMAX_COUNT
times. A block time of 0 is used as the semaphore should already be * times. A block time of 0 is used as the semaphore should already be
there. */ * there. */
xCount = 0; xCount = 0;
while( xSemaphoreTake( xISRCountingSemaphore, 0 ) == pdPASS ) while( xSemaphoreTake( xISRCountingSemaphore, 0 ) == pdPASS )
{ {
xCount++; xCount++;
@ -444,7 +449,7 @@ const TickType_t xDelay = pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS )
} }
/* Now raise the priority of this task so it runs immediately that the /* Now raise the priority of this task so it runs immediately that the
semaphore is given from the interrupt. */ * semaphore is given from the interrupt. */
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
/* Block to wait for the semaphore to be given from the interrupt. */ /* Block to wait for the semaphore to be given from the interrupt. */
@ -468,15 +473,17 @@ BaseType_t xHigherPriorityTaskWoken = pdFALSE;
TickType_t xTimeNow; TickType_t xTimeNow;
/* No mutual exclusion on xOkToGiveMutex, but this is only test code (and /* No mutual exclusion on xOkToGiveMutex, but this is only test code (and
only executed on a 32-bit architecture) so ignore that in this case. */ * only executed on a 32-bit architecture) so ignore that in this case. */
xTimeNow = xTaskGetTickCountFromISR(); xTimeNow = xTaskGetTickCountFromISR();
if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) ) if( ( ( TickType_t ) ( xTimeNow - xLastGiveTime ) ) >= pdMS_TO_TICKS( intsemINTERRUPT_MUTEX_GIVE_PERIOD_MS ) )
{ {
configASSERT( xISRMutex ); configASSERT( xISRMutex );
if( xOkToGiveMutex != pdFALSE ) if( xOkToGiveMutex != pdFALSE )
{ {
/* Null is used as the second parameter in this give, and non-NULL /* Null is used as the second parameter in this give, and non-NULL
in the other gives for code coverage reasons. */ * in the other gives for code coverage reasons. */
xSemaphoreGiveFromISR( xISRMutex, NULL ); xSemaphoreGiveFromISR( xISRMutex, NULL );
/* Second give attempt should fail. */ /* Second give attempt should fail. */
@ -487,6 +494,7 @@ TickType_t xTimeNow;
{ {
xSemaphoreGiveFromISR( xISRCountingSemaphore, &xHigherPriorityTaskWoken ); xSemaphoreGiveFromISR( xISRCountingSemaphore, &xHigherPriorityTaskWoken );
} }
xLastGiveTime = xTimeNow; xLastGiveTime = xTimeNow;
} }
@ -501,7 +509,7 @@ BaseType_t xAreInterruptSemaphoreTasksStillRunning( void )
static uint32_t ulLastMasterLoopCounter = 0, ulLastCountingSemaphoreLoops = 0; static uint32_t ulLastMasterLoopCounter = 0, ulLastCountingSemaphoreLoops = 0;
/* If the demo tasks are running then it is expected that the loop counters /* If the demo tasks are running then it is expected that the loop counters
will have changed since this function was last called. */ * will have changed since this function was last called. */
if( ulLastMasterLoopCounter == ulMasterLoops ) if( ulLastMasterLoopCounter == ulMasterLoops )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -517,9 +525,7 @@ static uint32_t ulLastMasterLoopCounter = 0, ulLastCountingSemaphoreLoops = 0;
ulLastCountingSemaphoreLoops = ulCountingSemaphoreLoops++; ulLastCountingSemaphoreLoops = ulCountingSemaphoreLoops++;
/* Errors detected in the task itself will have latched xErrorDetected /* Errors detected in the task itself will have latched xErrorDetected
to true. */ * to true. */
return ( BaseType_t ) !xErrorDetected; return ( BaseType_t ) !xErrorDetected;
} }

View file

@ -68,11 +68,11 @@
#include "MessageBufferAMP.h" #include "MessageBufferAMP.h"
/* Enough for 3 4 byte pointers, including the additional 4 bytes per message /* Enough for 3 4 byte pointers, including the additional 4 bytes per message
overhead of message buffers. */ * overhead of message buffers. */
#define mbaCONTROL_MESSAGE_BUFFER_SIZE ( 24 ) #define mbaCONTROL_MESSAGE_BUFFER_SIZE ( 24 )
/* Enough four 4 8 byte strings, plus the additional 4 bytes per message /* Enough four 4 8 byte strings, plus the additional 4 bytes per message
overhead of message buffers. */ * overhead of message buffers. */
#define mbaTASK_MESSAGE_BUFFER_SIZE ( 60 ) #define mbaTASK_MESSAGE_BUFFER_SIZE ( 60 )
/* The number of instances of prvCoreBTasks that are created. */ /* The number of instances of prvCoreBTasks that are created. */
@ -82,7 +82,7 @@ overhead of message buffers. */
#define mbaDONT_BLOCK 0 #define mbaDONT_BLOCK 0
/* Macro that mimics an interrupt service routine executing by simply calling /* Macro that mimics an interrupt service routine executing by simply calling
the routine inline. */ * the routine inline. */
#define mbaGENERATE_CORE_B_INTERRUPT() prvCoreBInterruptHandler() #define mbaGENERATE_CORE_B_INTERRUPT() prvCoreBInterruptHandler()
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -112,15 +112,15 @@ static void prvCoreBInterruptHandler( void );
static MessageBufferHandle_t xCoreBMessageBuffers[ mbaNUMBER_OF_CORE_B_TASKS ]; static MessageBufferHandle_t xCoreBMessageBuffers[ mbaNUMBER_OF_CORE_B_TASKS ];
/* The control message buffer. This is used to pass the handle of the message /* The control message buffer. This is used to pass the handle of the message
message buffer that holds application data into the core to core interrupt * message buffer that holds application data into the core to core interrupt
service routine. */ * service routine. */
static MessageBufferHandle_t xControlMessageBuffer; static MessageBufferHandle_t xControlMessageBuffer;
/* Counters used to indicate to the check that the tasks are still executing. */ /* Counters used to indicate to the check that the tasks are still executing. */
static uint32_t ulCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ]; static uint32_t ulCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ];
/* Set to pdFALSE if any errors are detected. Used to inform the check task /* Set to pdFALSE if any errors are detected. Used to inform the check task
that something might be wrong. */ * that something might be wrong. */
BaseType_t xDemoStatus = pdPASS; BaseType_t xDemoStatus = pdPASS;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -144,8 +144,8 @@ BaseType_t x;
configASSERT( xCoreBMessageBuffers[ x ] ); configASSERT( xCoreBMessageBuffers[ x ] );
/* Pass the loop counter into the created task using the task's /* Pass the loop counter into the created task using the task's
parameter. The task then uses the value as an index into the * parameter. The task then uses the value as an index into the
ulCycleCounters and xCoreBMessageBuffers arrays. */ * ulCycleCounters and xCoreBMessageBuffers arrays. */
xTaskCreate( prvCoreBTasks, xTaskCreate( prvCoreBTasks,
"AMPCoreB1", "AMPCoreB1",
xStackSize, xStackSize,
@ -169,15 +169,15 @@ char cString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff)
for( ; ; ) for( ; ; )
{ {
/* Create the next string to send. The value is incremented on each /* Create the next string to send. The value is incremented on each
loop iteration, and the length of the string changes as the number of * loop iteration, and the length of the string changes as the number of
digits in the value increases. */ * digits in the value increases. */
sprintf( cString, "%lu", ( unsigned long ) ulNextValue ); sprintf( cString, "%lu", ( unsigned long ) ulNextValue );
/* Send the value from this (pseudo) Core A to the tasks on the (pseudo) /* Send the value from this (pseudo) Core A to the tasks on the (pseudo)
Core B via the message buffers. This will result in sbSEND_COMPLETED() * Core B via the message buffers. This will result in sbSEND_COMPLETED()
being executed, which in turn will write the handle of the message * being executed, which in turn will write the handle of the message
buffer written to into xControlMessageBuffer then generate an interrupt * buffer written to into xControlMessageBuffer then generate an interrupt
in core B. */ * in core B. */
for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ ) for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
{ {
xMessageBufferSend( /* The message buffer to write to. */ xMessageBufferSend( /* The message buffer to write to. */
@ -191,7 +191,7 @@ char cString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xffffffff)
} }
/* Delay before repeating with a different and potentially different /* Delay before repeating with a different and potentially different
length string. */ * length string. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
ulNextValue++; ulNextValue++;
} }
@ -207,7 +207,7 @@ char cExpectedString[ 15 ]; /* At least large enough to hold "4294967295\0" (0xf
char cReceivedString[ 15 ]; char cReceivedString[ 15 ];
/* The index into the xCoreBMessageBuffers and ulLoopCounter arrays is /* The index into the xCoreBMessageBuffers and ulLoopCounter arrays is
passed into this task using the task's parameter. */ * passed into this task using the task's parameter. */
x = ( BaseType_t ) pvParameters; x = ( BaseType_t ) pvParameters;
configASSERT( x < mbaNUMBER_OF_CORE_B_TASKS ); configASSERT( x < mbaNUMBER_OF_CORE_B_TASKS );
@ -232,7 +232,7 @@ char cReceivedString[ 15 ];
( void ) xReceivedBytes; /* Incase configASSERT() is not defined. */ ( void ) xReceivedBytes; /* Incase configASSERT() is not defined. */
/* If the received string matches that expected then increment the loop /* If the received string matches that expected then increment the loop
counter so the check task knows this task is still running. */ * counter so the check task knows this task is still running. */
if( strcmp( cReceivedString, cExpectedString ) == 0 ) if( strcmp( cReceivedString, cExpectedString ) == 0 )
{ {
( ulCycleCounters[ x ] )++; ( ulCycleCounters[ x ] )++;
@ -249,7 +249,7 @@ char cReceivedString[ 15 ];
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Called by the reimplementation of sbSEND_COMPLETED(), which can be defined /* Called by the reimplementation of sbSEND_COMPLETED(), which can be defined
as follows in FreeRTOSConfig.h: * as follows in FreeRTOSConfig.h:
#define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer ) #define sbSEND_COMPLETED( pxStreamBuffer ) vGenerateCoreBInterrupt( pxStreamBuffer )
*/ */
void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer ) void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer )
@ -257,50 +257,50 @@ void vGenerateCoreBInterrupt( void * xUpdatedMessageBuffer )
MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer; MessageBufferHandle_t xUpdatedBuffer = ( MessageBufferHandle_t ) xUpdatedMessageBuffer;
/* If sbSEND_COMPLETED() has been implemented as above, then this function /* If sbSEND_COMPLETED() has been implemented as above, then this function
is called from within xMessageBufferSend(). As this function also calls * is called from within xMessageBufferSend(). As this function also calls
xMessageBufferSend() itself it is necessary to guard against a recursive * xMessageBufferSend() itself it is necessary to guard against a recursive
call. If the message buffer just updated is the message buffer written to * call. If the message buffer just updated is the message buffer written to
by this function, then this is a recursive call, and the function can just * by this function, then this is a recursive call, and the function can just
exit without taking further action. */ * exit without taking further action. */
if( xUpdatedBuffer != xControlMessageBuffer ) if( xUpdatedBuffer != xControlMessageBuffer )
{ {
/* Use xControlMessageBuffer to pass the handle of the message buffer /* Use xControlMessageBuffer to pass the handle of the message buffer
written to by core A to the interrupt handler about to be generated in * written to by core A to the interrupt handler about to be generated in
core B. */ * core B. */
xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK ); xMessageBufferSend( xControlMessageBuffer, &xUpdatedBuffer, sizeof( xUpdatedBuffer ), mbaDONT_BLOCK );
/* This is where the interrupt would be generated. In this case it is /* This is where the interrupt would be generated. In this case it is
not a genuine interrupt handler that executes, just a standard function * not a genuine interrupt handler that executes, just a standard function
call. */ * call. */
mbaGENERATE_CORE_B_INTERRUPT(); mbaGENERATE_CORE_B_INTERRUPT();
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Handler for the interrupts that are triggered on core A but execute on core /* Handler for the interrupts that are triggered on core A but execute on core
B. */ * B. */
static void prvCoreBInterruptHandler( void ) static void prvCoreBInterruptHandler( void )
{ {
MessageBufferHandle_t xUpdatedMessageBuffer; MessageBufferHandle_t xUpdatedMessageBuffer;
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* xControlMessageBuffer contains the handle of the message buffer that /* xControlMessageBuffer contains the handle of the message buffer that
contains data. */ * contains data. */
if( xMessageBufferReceive( xControlMessageBuffer, if( xMessageBufferReceive( xControlMessageBuffer,
&xUpdatedMessageBuffer, &xUpdatedMessageBuffer,
sizeof( xUpdatedMessageBuffer ), sizeof( xUpdatedMessageBuffer ),
mbaDONT_BLOCK ) == sizeof( xUpdatedMessageBuffer ) ) mbaDONT_BLOCK ) == sizeof( xUpdatedMessageBuffer ) )
{ {
/* Call the API function that sends a notification to any task that is /* Call the API function that sends a notification to any task that is
blocked on the xUpdatedMessageBuffer message buffer waiting for data to * blocked on the xUpdatedMessageBuffer message buffer waiting for data to
arrive. */ * arrive. */
xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken ); xMessageBufferSendCompletedFromISR( xUpdatedMessageBuffer, &xHigherPriorityTaskWoken );
} }
/* Normal FreeRTOS yield from interrupt semantics, where /* Normal FreeRTOS yield from interrupt semantics, where
xHigherPriorityTaskWoken is initialized to pdFALSE and will then get set to * xHigherPriorityTaskWoken is initialized to pdFALSE and will then get set to
pdTRUE if the interrupt safe API unblocks a task that has a priority above * pdTRUE if the interrupt safe API unblocks a task that has a priority above
that of the currently executing task. */ * that of the currently executing task. */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -311,7 +311,7 @@ static uint32_t ulLastCycleCounters[ mbaNUMBER_OF_CORE_B_TASKS ] = { 0 };
BaseType_t x; BaseType_t x;
/* Called by the check task to determine the health status of the tasks /* Called by the check task to determine the health status of the tasks
implemented in this demo. */ * implemented in this demo. */
for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ ) for( x = 0; x < mbaNUMBER_OF_CORE_B_TASKS; x++ )
{ {
if( ulLastCycleCounters[ x ] == ulCycleCounters[ x ] ) if( ulLastCycleCounters[ x ] == ulCycleCounters[ x ] )
@ -326,4 +326,3 @@ BaseType_t x;
return xDemoStatus; return xDemoStatus;
} }

View file

@ -52,7 +52,7 @@
#define mbNUMBER_OF_SENDER_TASKS ( 2 ) #define mbNUMBER_OF_SENDER_TASKS ( 2 )
/* Priority of the test tasks. The send and receive go from low to high /* Priority of the test tasks. The send and receive go from low to high
priority tasks, and from high to low priority tasks. */ * priority tasks, and from high to low priority tasks. */
#define mbLOWER_PRIORITY ( tskIDLE_PRIORITY ) #define mbLOWER_PRIORITY ( tskIDLE_PRIORITY )
#define mbHIGHER_PRIORITY ( tskIDLE_PRIORITY + 1 ) #define mbHIGHER_PRIORITY ( tskIDLE_PRIORITY + 1 )
@ -87,9 +87,10 @@ static void prvNonBlockingReceiverTask( void *pvParameters );
static void prvNonBlockingSenderTask( void * pvParameters ); static void prvNonBlockingSenderTask( void * pvParameters );
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
/* This file tests both statically and dynamically allocated message buffers. /* This file tests both statically and dynamically allocated message buffers.
Allocate the structures and buffers to be used by the statically allocated * Allocate the structures and buffers to be used by the statically allocated
objects, which get used in the echo tests. */ * objects, which get used in the echo tests. */
static void prvReceiverTask( void * pvParameters ); static void prvReceiverTask( void * pvParameters );
static void prvSenderTask( void * pvParameters ); static void prvSenderTask( void * pvParameters );
@ -110,7 +111,7 @@ static void prvNonBlockingSenderTask( void *pvParameters );
static MessageBufferHandle_t xCoherenceTestMessageBuffer = NULL; static MessageBufferHandle_t xCoherenceTestMessageBuffer = NULL;
static uint32_t ulSizeCoherencyTestCycles = 0UL; static uint32_t ulSizeCoherencyTestCycles = 0UL;
#endif #endif /* if ( configRUN_ADDITIONAL_TESTS == 1 ) */
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -124,17 +125,17 @@ typedef struct ECHO_MESSAGE_BUFFERS
static uint32_t ulEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 }; static uint32_t ulEchoLoopCounters[ mbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
/* The non-blocking tasks monitor their operation, and if no errors have been /* The non-blocking tasks monitor their operation, and if no errors have been
found, increment ulNonBlockingRxCounter. xAreMessageBufferTasksStillRunning() * found, increment ulNonBlockingRxCounter. xAreMessageBufferTasksStillRunning()
then checks ulNonBlockingRxCounter and only returns pdPASS if * then checks ulNonBlockingRxCounter and only returns pdPASS if
ulNonBlockingRxCounter is still incrementing. */ * ulNonBlockingRxCounter is still incrementing. */
static uint32_t ulNonBlockingRxCounter = 0; static uint32_t ulNonBlockingRxCounter = 0;
/* A message that is longer than the buffer, parts of which are written to the /* A message that is longer than the buffer, parts of which are written to the
message buffer to test writing different lengths at different offsets. */ * message buffer to test writing different lengths at different offsets. */
static const char * pc55ByteString = "One two three four five six seven eight nine ten eleve"; static const char * pc55ByteString = "One two three four five six seven eight nine ten eleve";
/* Remember the required stack size so tasks can be created at run time (after /* Remember the required stack size so tasks can be created at run time (after
initialisation time. */ * initialisation time. */
static configSTACK_DEPTH_TYPE xBlockingStackSize = 0; static configSTACK_DEPTH_TYPE xBlockingStackSize = 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -150,14 +151,14 @@ MessageBufferHandle_t xMessageBuffer;
#endif #endif
/* The echo servers sets up the message buffers before creating the echo /* The echo servers sets up the message buffers before creating the echo
client tasks. One set of tasks has the server as the higher priority, and * client tasks. One set of tasks has the server as the higher priority, and
the other has the client as the higher priority. */ * the other has the client as the higher priority. */
xTaskCreate( prvEchoServer, "1EchoServer", xBlockingStackSize, NULL, mbHIGHER_PRIORITY, NULL ); xTaskCreate( prvEchoServer, "1EchoServer", xBlockingStackSize, NULL, mbHIGHER_PRIORITY, NULL );
xTaskCreate( prvEchoServer, "2EchoServer", xBlockingStackSize, NULL, mbLOWER_PRIORITY, NULL ); xTaskCreate( prvEchoServer, "2EchoServer", xBlockingStackSize, NULL, mbLOWER_PRIORITY, NULL );
/* The non blocking tasks run continuously and will interleave with each /* The non blocking tasks run continuously and will interleave with each
other, so must be created at the lowest priority. The message buffer they * other, so must be created at the lowest priority. The message buffer they
use is created and passed in using the task's parameter. */ * use is created and passed in using the task's parameter. */
xMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES ); xMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
xTaskCreate( prvNonBlockingReceiverTask, "NonBlkRx", xStackSize, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvNonBlockingReceiverTask, "NonBlkRx", xStackSize, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );
xTaskCreate( prvNonBlockingSenderTask, "NonBlkTx", xStackSize, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvNonBlockingSenderTask, "NonBlkTx", xStackSize, ( void * ) xMessageBuffer, tskIDLE_PRIORITY, NULL );
@ -165,8 +166,8 @@ MessageBufferHandle_t xMessageBuffer;
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{ {
/* The sender tasks set up the message buffers before creating the /* The sender tasks set up the message buffers before creating the
receiver tasks. Priorities must be 0 and 1 as the priority is used to * receiver tasks. Priorities must be 0 and 1 as the priority is used to
index into the xStaticMessageBuffers and ucBufferStorage arrays. */ * index into the xStaticMessageBuffers and ucBufferStorage arrays. */
xTaskCreate( prvSenderTask, "1Sender", xBlockingStackSize, NULL, mbHIGHER_PRIORITY, NULL ); xTaskCreate( prvSenderTask, "1Sender", xBlockingStackSize, NULL, mbHIGHER_PRIORITY, NULL );
xTaskCreate( prvSenderTask, "2Sender", xBlockingStackSize, NULL, mbLOWER_PRIORITY, NULL ); xTaskCreate( prvSenderTask, "2Sender", xBlockingStackSize, NULL, mbLOWER_PRIORITY, NULL );
} }
@ -198,8 +199,8 @@ UBaseType_t uxOriginalPriority;
( void ) xAllowableMargin; ( void ) xAllowableMargin;
/* To minimise stack and heap usage a full size buffer is allocated from /* To minimise stack and heap usage a full size buffer is allocated from
the heap, then buffers which hold smaller amounts of data are overlayed * the heap, then buffers which hold smaller amounts of data are overlayed
with the larger buffer - just make sure not to use both at once!. */ * with the larger buffer - just make sure not to use both at once!. */
pucFullBuffer = pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES ); pucFullBuffer = pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
configASSERT( pucFullBuffer ); configASSERT( pucFullBuffer );
@ -207,7 +208,7 @@ UBaseType_t uxOriginalPriority;
pucReadData = pucData + x17ByteLength; pucReadData = pucData + x17ByteLength;
/* Nothing has been added or removed yet, so expect the free space to be /* Nothing has been added or removed yet, so expect the free space to be
exactly as created and the length of the next message to be 0. */ * exactly as created and the length of the next message to be 0. */
xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer ); xExpectedSpace = xMessageBufferSpaceAvailable( xMessageBuffer );
configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES ); configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE ); configASSERT( xMessageBufferIsEmpty( xMessageBuffer ) == pdTRUE );
@ -218,7 +219,7 @@ UBaseType_t uxOriginalPriority;
( void ) xNextLength; ( void ) xNextLength;
/* Try sending more bytes than possible, first using the FromISR version, then /* Try sending more bytes than possible, first using the FromISR version, then
with an infinite block time to ensure this task does not lock up. */ * with an infinite block time to ensure this task does not lock up. */
xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, mbMESSAGE_BUFFER_LENGTH_BYTES + sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ), NULL ); xReturned = xMessageBufferSendFromISR( xMessageBuffer, ( void * ) pucData, mbMESSAGE_BUFFER_LENGTH_BYTES + sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ), NULL );
configASSERT( xReturned == ( size_t ) 0 ); configASSERT( xReturned == ( size_t ) 0 );
/* In case configASSERT() is not defined. */ /* In case configASSERT() is not defined. */
@ -229,22 +230,22 @@ UBaseType_t uxOriginalPriority;
( void ) xReturned; ( void ) xReturned;
/* The buffer is 50 bytes long. When an item is added to the buffer an /* The buffer is 50 bytes long. When an item is added to the buffer an
additional 4 bytes are added to hold the item's size. That means adding * additional 4 bytes are added to hold the item's size. That means adding
6 bytes to the buffer will actually add 10 bytes to the buffer. Therefore, * 6 bytes to the buffer will actually add 10 bytes to the buffer. Therefore,
with a 50 byte buffer, a maximum of 5 6 bytes items can be added before the * with a 50 byte buffer, a maximum of 5 6 bytes items can be added before the
buffer is completely full. NOTE: The numbers in this paragraph assume * buffer is completely full. NOTE: The numbers in this paragraph assume
sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) == 4. */ * sizeof( configMESSAGE_BUFFER_LENGTH_TYPE ) == 4. */
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ ) for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
{ {
configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdFALSE ); configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdFALSE );
/* Generate recognisable data to write to the buffer. This is just /* Generate recognisable data to write to the buffer. This is just
ascii characters that shows which loop iteration the data was written * ascii characters that shows which loop iteration the data was written
in. The 'FromISR' version is used to give it some exercise as a block * in. The 'FromISR' version is used to give it some exercise as a block
time is not used. That requires the call to be in a critical section * time is not used. That requires the call to be in a critical section
so this code can also run on FreeRTOS ports that do not support * so this code can also run on FreeRTOS ports that do not support
interrupt nesting (and so don't have interrupt safe critical * interrupt nesting (and so don't have interrupt safe critical
sections).*/ * sections).*/
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength ); memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
@ -255,8 +256,8 @@ UBaseType_t uxOriginalPriority;
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
/* The space in the buffer will have reduced by the amount of user data /* The space in the buffer will have reduced by the amount of user data
written into the buffer and the amount of space used to store the length * written into the buffer and the amount of space used to store the length
of the data written into the buffer. */ * of the data written into the buffer. */
xExpectedSpace -= ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH ); xExpectedSpace -= ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer ); xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
configASSERT( xReturned == xExpectedSpace ); configASSERT( xReturned == xExpectedSpace );
@ -269,15 +270,15 @@ UBaseType_t uxOriginalPriority;
} }
/* Now the buffer should be full, and attempting to add anything will should /* Now the buffer should be full, and attempting to add anything will should
fail. */ * fail. */
configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdTRUE ); configASSERT( xMessageBufferIsFull( xMessageBuffer ) == pdTRUE );
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), mbDONT_BLOCK ); xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, sizeof( pucData[ 0 ] ), mbDONT_BLOCK );
configASSERT( xReturned == 0 ); configASSERT( xReturned == 0 );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
/* Adding with a timeout should also fail after the appropriate time. The /* Adding with a timeout should also fail after the appropriate time. The
priority is temporarily boosted in this part of the test to keep the * priority is temporarily boosted in this part of the test to keep the
allowable margin to a minimum. */ * allowable margin to a minimum. */
uxOriginalPriority = uxTaskPriorityGet( NULL ); uxOriginalPriority = uxTaskPriorityGet( NULL );
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
xTimeBeforeCall = xTaskGetTickCount(); xTimeBeforeCall = xTaskGetTickCount();
@ -291,17 +292,16 @@ UBaseType_t uxOriginalPriority;
( void ) xTimeBeforeCall; ( void ) xTimeBeforeCall;
( void ) xTimeAfterCall; ( void ) xTimeAfterCall;
/* The buffer is now full of data in the form "000000", "111111", etc. Make /* The buffer is now full of data in the form "000000", "111111", etc. Make
sure the data is read out as expected. */ * sure the data is read out as expected. */
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ ) for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
{ {
/* Generate the data that is expected to be read out for this loop /* Generate the data that is expected to be read out for this loop
iteration. */ * iteration. */
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength ); memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
/* Try reading the message into a buffer that is too small. The message /* Try reading the message into a buffer that is too small. The message
should remain in the buffer. */ * should remain in the buffer. */
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength - 1, mbDONT_BLOCK ); xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength - 1, mbDONT_BLOCK );
configASSERT( xReturned == 0 ); configASSERT( xReturned == 0 );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -312,10 +312,10 @@ UBaseType_t uxOriginalPriority;
( void ) xNextLength; /* In case configASSERT() is not defined. */ ( void ) xNextLength; /* In case configASSERT() is not defined. */
/* Read the next 6 bytes out. The 'FromISR' version is used to give it /* Read the next 6 bytes out. The 'FromISR' version is used to give it
some exercise as a block time is not used. THa requires the code to be * some exercise as a block time is not used. THa requires the code to be
in a critical section so this test can be run with FreeRTOS ports that * in a critical section so this test can be run with FreeRTOS ports that
do not support interrupt nesting (and therefore don't have interrupt * do not support interrupt nesting (and therefore don't have interrupt
safe critical sections). */ * safe critical sections). */
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
xReturned = xMessageBufferReceiveFromISR( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, NULL ); xReturned = xMessageBufferReceiveFromISR( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, NULL );
@ -328,8 +328,8 @@ UBaseType_t uxOriginalPriority;
configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 ); configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );
/* The space in the buffer will have increased by the amount of user /* The space in the buffer will have increased by the amount of user
data read from into the buffer and the amount of space used to store the * data read from into the buffer and the amount of space used to store the
length of the data read into the buffer. */ * length of the data read into the buffer. */
xExpectedSpace += ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH ); xExpectedSpace += ( x6ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer ); xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
configASSERT( xReturned == xExpectedSpace ); configASSERT( xReturned == xExpectedSpace );
@ -347,8 +347,8 @@ UBaseType_t uxOriginalPriority;
/* Reading with a timeout should also fail after the appropriate time. The /* Reading with a timeout should also fail after the appropriate time. The
priority is temporarily boosted in this part of the test to keep the * priority is temporarily boosted in this part of the test to keep the
allowable margin to a minimum. */ * allowable margin to a minimum. */
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
xTimeBeforeCall = xTaskGetTickCount(); xTimeBeforeCall = xTaskGetTickCount();
xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime ); xReturned = xMessageBufferReceive( xMessageBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime );
@ -363,19 +363,19 @@ UBaseType_t uxOriginalPriority;
/* In the next loop 17 bytes are written to then read out on each iteration. /* In the next loop 17 bytes are written to then read out on each iteration.
The expected length variable is always used after 17 bytes have been written * The expected length variable is always used after 17 bytes have been written
into the buffer - the length of the message is also written, making a total * into the buffer - the length of the message is also written, making a total
of 21 bytes consumed for each 17 byte message. */ * of 21 bytes consumed for each 17 byte message. */
xExpectedSpace = mbMESSAGE_BUFFER_LENGTH_BYTES - ( x17ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH ); xExpectedSpace = mbMESSAGE_BUFFER_LENGTH_BYTES - ( x17ByteLength + mbBYTES_TO_STORE_MESSAGE_LENGTH );
/* Reading and writing 17 bytes at a time will result in 21 bytes being /* Reading and writing 17 bytes at a time will result in 21 bytes being
written into the buffer, and as 50 is not divisible by 21, writing multiple * written into the buffer, and as 50 is not divisible by 21, writing multiple
times will cause the data to wrap in the buffer.*/ * times will cause the data to wrap in the buffer.*/
for( xItem = 0; xItem < 100; xItem++ ) for( xItem = 0; xItem < 100; xItem++ )
{ {
/* Generate recognisable data to write to the queue. This is just /* Generate recognisable data to write to the queue. This is just
ascii characters that shows which loop iteration the data was written * ascii characters that shows which loop iteration the data was written
in. */ * in. */
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength ); memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength );
xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, x17ByteLength, mbDONT_BLOCK ); xReturned = xMessageBufferSend( xMessageBuffer, ( void * ) pucData, x17ByteLength, mbDONT_BLOCK );
configASSERT( xReturned == x17ByteLength ); configASSERT( xReturned == x17ByteLength );
@ -387,8 +387,8 @@ UBaseType_t uxOriginalPriority;
( void ) xNextLength; /* In case configASSERT() is not defined. */ ( void ) xNextLength; /* In case configASSERT() is not defined. */
/* The space in the buffer will have reduced by the amount of user data /* The space in the buffer will have reduced by the amount of user data
written into the buffer and the amount of space used to store the length * written into the buffer and the amount of space used to store the length
of the data written into the buffer. */ * of the data written into the buffer. */
xReturned = xMessageBufferSpaceAvailable( xMessageBuffer ); xReturned = xMessageBufferSpaceAvailable( xMessageBuffer );
configASSERT( xReturned == xExpectedSpace ); configASSERT( xReturned == xExpectedSpace );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -402,7 +402,7 @@ UBaseType_t uxOriginalPriority;
configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 ); configASSERT( memcmp( ( void * ) pucData, ( void * ) pucReadData, x17ByteLength ) == 0 );
/* Don't expect any messages to be available as the data was read out /* Don't expect any messages to be available as the data was read out
again. */ * again. */
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer ); xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
configASSERT( xNextLength == 0 ); configASSERT( xNextLength == 0 );
( void ) xNextLength; /* In case configASSERT() is not defined. */ ( void ) xNextLength; /* In case configASSERT() is not defined. */
@ -414,15 +414,15 @@ UBaseType_t uxOriginalPriority;
configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES ); configASSERT( xExpectedSpace == mbMESSAGE_BUFFER_LENGTH_BYTES );
/* Cannot write within sizeof( size_t ) (assumed to be 4 bytes in this test) /* Cannot write within sizeof( size_t ) (assumed to be 4 bytes in this test)
bytes of the full 50 bytes, as that would not leave space for the four bytes * bytes of the full 50 bytes, as that would not leave space for the four bytes
taken by the data length. */ * taken by the data length. */
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES, mbDONT_BLOCK ); xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES, mbDONT_BLOCK );
configASSERT( xReturned == 0 ); configASSERT( xReturned == 0 );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
#ifndef configMESSAGE_BUFFER_LENGTH_TYPE #ifndef configMESSAGE_BUFFER_LENGTH_TYPE
{ {
/* The following will fail if configMESSAGE_BUFFER_LENGTH_TYPE is set /* The following will fail if configMESSAGE_BUFFER_LENGTH_TYPE is set
to a non 32-bit type. */ * to a non 32-bit type. */
xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 1, mbDONT_BLOCK ); xReturned = xMessageBufferSend( xMessageBuffer, ( const void * ) pc55ByteString, mbMESSAGE_BUFFER_LENGTH_BYTES - 1, mbDONT_BLOCK );
configASSERT( xReturned == 0 ); configASSERT( xReturned == 0 );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -433,10 +433,10 @@ UBaseType_t uxOriginalPriority;
configASSERT( xReturned == 0 ); configASSERT( xReturned == 0 );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
} }
#endif #endif /* ifndef configMESSAGE_BUFFER_LENGTH_TYPE */
/* Don't expect any messages to be available as the above were too large to /* Don't expect any messages to be available as the above were too large to
get written. */ * get written. */
xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer ); xNextLength = xMessageBufferNextLengthBytes( xMessageBuffer );
configASSERT( xNextLength == 0 ); configASSERT( xNextLength == 0 );
( void ) xNextLength; /* In case configASSERT() is not defined. */ ( void ) xNextLength; /* In case configASSERT() is not defined. */
@ -468,12 +468,13 @@ const int32_t iMaxValue = 1500;
char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */ char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
/* In this case the message buffer has already been created and is passed /* In this case the message buffer has already been created and is passed
into the task using the task's parameter. */ * into the task using the task's parameter. */
xMessageBuffer = ( MessageBufferHandle_t ) pvParameters; xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
/* Create a string from an incrementing number. The length of the /* Create a string from an incrementing number. The length of the
string will increase and decrease as the value of the number increases * string will increase and decrease as the value of the number increases
then overflows. */ * then overflows. */
memset( cTxString, 0x00, sizeof( cTxString ) ); memset( cTxString, 0x00, sizeof( cTxString ) );
sprintf( cTxString, "%d", ( int ) iDataToSend ); sprintf( cTxString, "%d", ( int ) iDataToSend );
xStringLength = strlen( cTxString ); xStringLength = strlen( cTxString );
@ -481,7 +482,7 @@ char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
for( ; ; ) for( ; ; )
{ {
/* Doesn't block so calls can interleave with the non-blocking /* Doesn't block so calls can interleave with the non-blocking
receives performed by prvNonBlockingReceiverTask(). */ * receives performed by prvNonBlockingReceiverTask(). */
if( xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), mbDONT_BLOCK ) == xStringLength ) if( xMessageBufferSend( xMessageBuffer, ( void * ) cTxString, strlen( cTxString ), mbDONT_BLOCK ) == xStringLength )
{ {
iDataToSend++; iDataToSend++;
@ -489,7 +490,7 @@ char cTxString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
if( iDataToSend > iMaxValue ) if( iDataToSend > iMaxValue )
{ {
/* The value sent is reset back to 0 to ensure the string being sent /* The value sent is reset back to 0 to ensure the string being sent
does not remain at the same length for too long. */ * does not remain at the same length for too long. */
iDataToSend = 0; iDataToSend = 0;
} }
@ -513,13 +514,13 @@ char cExpectedString[ 12 ]; /* Large enough to hold a 32 number in ASCII. */
char cRxString[ 12 ]; char cRxString[ 12 ];
/* In this case the message buffer has already been created and is passed /* In this case the message buffer has already been created and is passed
into the task using the task's parameter. */ * into the task using the task's parameter. */
xMessageBuffer = ( MessageBufferHandle_t ) pvParameters; xMessageBuffer = ( MessageBufferHandle_t ) pvParameters;
/* Create a string from an incrementing number. The length of the /* Create a string from an incrementing number. The length of the
string will increase and decrease as the value of the number increases * string will increase and decrease as the value of the number increases
then overflows. This should always match the string sent to the buffer by * then overflows. This should always match the string sent to the buffer by
the non blocking sender task. */ * the non blocking sender task. */
memset( cExpectedString, 0x00, sizeof( cExpectedString ) ); memset( cExpectedString, 0x00, sizeof( cExpectedString ) );
memset( cRxString, 0x00, sizeof( cRxString ) ); memset( cRxString, 0x00, sizeof( cRxString ) );
sprintf( cExpectedString, "%d", ( int ) iDataToSend ); sprintf( cExpectedString, "%d", ( int ) iDataToSend );
@ -528,11 +529,11 @@ char cRxString[ 12 ];
for( ; ; ) for( ; ; )
{ {
/* Doesn't block so calls can interleave with the non-blocking /* Doesn't block so calls can interleave with the non-blocking
receives performed by prvNonBlockingReceiverTask(). */ * receives performed by prvNonBlockingReceiverTask(). */
xReceiveLength = xMessageBufferReceive( xMessageBuffer, ( void * ) cRxString, sizeof( cRxString ), mbDONT_BLOCK ); xReceiveLength = xMessageBufferReceive( xMessageBuffer, ( void * ) cRxString, sizeof( cRxString ), mbDONT_BLOCK );
/* Should only ever receive no data is available, or the expected /* Should only ever receive no data is available, or the expected
length of data is available. */ * length of data is available. */
if( ( xReceiveLength != 0 ) && ( xReceiveLength != xStringLength ) ) if( ( xReceiveLength != 0 ) && ( xReceiveLength != xStringLength ) )
{ {
xNonBlockingReceiveError = pdTRUE; xNonBlockingReceiveError = pdTRUE;
@ -541,7 +542,7 @@ char cRxString[ 12 ];
if( xReceiveLength == xStringLength ) if( xReceiveLength == xStringLength )
{ {
/* Ensure the received data was that expected, then generate the /* Ensure the received data was that expected, then generate the
next expected string. */ * next expected string. */
if( strcmp( cRxString, cExpectedString ) != 0 ) if( strcmp( cRxString, cExpectedString ) != 0 )
{ {
xNonBlockingReceiveError = pdTRUE; xNonBlockingReceiveError = pdTRUE;
@ -552,7 +553,7 @@ char cRxString[ 12 ];
if( iDataToSend > iMaxValue ) if( iDataToSend > iMaxValue )
{ {
/* The value sent is reset back to 0 to ensure the string being sent /* The value sent is reset back to 0 to ensure the string being sent
does not remain at the same length for too long. */ * does not remain at the same length for too long. */
iDataToSend = 0; iDataToSend = 0;
} }
@ -564,7 +565,7 @@ char cRxString[ 12 ];
if( xNonBlockingReceiveError == pdFALSE ) if( xNonBlockingReceiveError == pdFALSE )
{ {
/* No errors detected so increment the counter that lets the /* No errors detected so increment the counter that lets the
check task know this test is still functioning correctly. */ * check task know this test is still functioning correctly. */
ulNonBlockingRxCounter++; ulNonBlockingRxCounter++;
} }
} }
@ -586,11 +587,11 @@ char cRxString[ 12 ];
/* The task's priority is used as an index into the loop counters used to /* The task's priority is used as an index into the loop counters used to
indicate this task is still running. */ * indicate this task is still running. */
UBaseType_t uxIndex = uxTaskPriorityGet( NULL ); UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
/* Make sure a change in priority does not inadvertently result in an /* Make sure a change in priority does not inadvertently result in an
invalid array index. */ * invalid array index. */
configASSERT( uxIndex < mbNUMBER_OF_ECHO_CLIENTS ); configASSERT( uxIndex < mbNUMBER_OF_ECHO_CLIENTS );
/* Avoid compiler warnings about unused parameters. */ /* Avoid compiler warnings about unused parameters. */
@ -601,13 +602,13 @@ char cRxString[ 12 ];
&( xStaticMessageBuffers[ uxIndex ] ) ); /* The static message buffer structure to use within the array. */ &( xStaticMessageBuffers[ uxIndex ] ) ); /* The static message buffer structure to use within the array. */
/* Now the message buffer has been created the receiver task can be created. /* Now the message buffer has been created the receiver task can be created.
If this sender task has the higher priority then the receiver task is * If this sender task has the higher priority then the receiver task is
created at the lower priority - if this sender task has the lower priority * created at the lower priority - if this sender task has the lower priority
then the receiver task is created at the higher priority. */ * then the receiver task is created at the higher priority. */
if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY ) if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )
{ {
/* Here prvSingleTaskTests() performs various tests on a message buffer /* Here prvSingleTaskTests() performs various tests on a message buffer
that was created statically. */ * that was created statically. */
prvSingleTaskTests( xMessageBuffer ); prvSingleTaskTests( xMessageBuffer );
xTaskCreate( prvReceiverTask, "MsgReceiver", xBlockingStackSize, ( void * ) xMessageBuffer, mbHIGHER_PRIORITY, NULL ); xTaskCreate( prvReceiverTask, "MsgReceiver", xBlockingStackSize, ( void * ) xMessageBuffer, mbHIGHER_PRIORITY, NULL );
} }
@ -619,8 +620,8 @@ char cRxString[ 12 ];
for( ; ; ) for( ; ; )
{ {
/* Create a string from an incrementing number. The length of the /* Create a string from an incrementing number. The length of the
string will increase and decrease as the value of the number increases * string will increase and decrease as the value of the number increases
then overflows. */ * then overflows. */
memset( cTxString, 0x00, sizeof( cTxString ) ); memset( cTxString, 0x00, sizeof( cTxString ) );
sprintf( cTxString, "%d", ( int ) iDataToSend ); sprintf( cTxString, "%d", ( int ) iDataToSend );
@ -634,7 +635,7 @@ char cRxString[ 12 ];
if( ( iDataToSend % iSendsBetweenIncrements ) == 0 ) if( ( iDataToSend % iSendsBetweenIncrements ) == 0 )
{ {
/* Increment a loop counter so a check task can tell this task is /* Increment a loop counter so a check task can tell this task is
still running as expected. */ * still running as expected. */
ulSenderLoopCounters[ uxIndex ]++; ulSenderLoopCounters[ uxIndex ]++;
if( uxTaskPriorityGet( NULL ) == mbHIGHER_PRIORITY ) if( uxTaskPriorityGet( NULL ) == mbHIGHER_PRIORITY )
@ -644,10 +645,10 @@ char cRxString[ 12 ];
} }
/* This message buffer is just created and deleted to ensure no /* This message buffer is just created and deleted to ensure no
issues when attempting to delete a message buffer that was * issues when attempting to delete a message buffer that was
created using statically allocated memory. To save stack space * created using statically allocated memory. To save stack space
the buffer is set to point to the cTxString array - this is * the buffer is set to point to the cTxString array - this is
ok because nothing is actually written to the memory. */ * ok because nothing is actually written to the memory. */
xTempMessageBuffer = xMessageBufferCreateStatic( sizeof( cTxString ), ( uint8_t * ) cTxString, &xStaticMessageBuffer ); xTempMessageBuffer = xMessageBufferCreateStatic( sizeof( cTxString ), ( uint8_t * ) cTxString, &xStaticMessageBuffer );
vMessageBufferDelete( xTempMessageBuffer ); vMessageBufferDelete( xTempMessageBuffer );
} }
@ -680,7 +681,6 @@ char cRxString[ 12 ];
do do
{ {
xReceivedBytes = xMessageBufferReceive( pxMessageBuffer, ( void * ) cReceivedString, sizeof( cExpectedString ), xTicksToWait ); xReceivedBytes = xMessageBufferReceive( pxMessageBuffer, ( void * ) cReceivedString, sizeof( cExpectedString ), xTicksToWait );
} while( xReceivedBytes == 0 ); } while( xReceivedBytes == 0 );
/* Ensure the received string matches the expected string. */ /* Ensure the received string matches the expected string. */
@ -700,19 +700,19 @@ char *pcStringToSend, *pcStringReceived, cNextChar = mbASCII_SPACE;
const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 ); const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 );
/* The task's priority is used as an index into the loop counters used to /* The task's priority is used as an index into the loop counters used to
indicate this task is still running. */ * indicate this task is still running. */
UBaseType_t uxIndex = uxTaskPriorityGet( NULL ); UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
/* Pointers to the client and server message buffers are passed into this task /* Pointers to the client and server message buffers are passed into this task
using the task's parameter. */ * using the task's parameter. */
EchoMessageBuffers_t * pxMessageBuffers = ( EchoMessageBuffers_t * ) pvParameters; EchoMessageBuffers_t * pxMessageBuffers = ( EchoMessageBuffers_t * ) pvParameters;
/* Prevent compiler warnings. */ /* Prevent compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
/* Create the buffer into which strings to send to the server will be /* Create the buffer into which strings to send to the server will be
created, and the buffer into which strings echoed back from the server will * created, and the buffer into which strings echoed back from the server will
be copied. */ * be copied. */
pcStringToSend = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES ); pcStringToSend = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
pcStringReceived = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES ); pcStringReceived = ( char * ) pvPortMalloc( mbMESSAGE_BUFFER_LENGTH_BYTES );
@ -725,18 +725,18 @@ EchoMessageBuffers_t *pxMessageBuffers = ( EchoMessageBuffers_t * ) pvParameters
xSendLength++; xSendLength++;
/* The message buffer is being used to hold variable length data, so /* The message buffer is being used to hold variable length data, so
each data item requires sizeof( size_t ) bytes to hold the data's * each data item requires sizeof( size_t ) bytes to hold the data's
length, hence the sizeof() in the if() condition below. */ * length, hence the sizeof() in the if() condition below. */
if( xSendLength > ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) ) if( xSendLength > ( mbMESSAGE_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) )
{ {
/* Back to a string length of 1. */ /* Back to a string length of 1. */
xSendLength = sizeof( char ); xSendLength = sizeof( char );
/* Maintain a count of the number of times this code executes so a /* Maintain a count of the number of times this code executes so a
check task can determine if this task is still functioning as * check task can determine if this task is still functioning as
expected or not. As there are two client tasks, and the priorities * expected or not. As there are two client tasks, and the priorities
used are 0 and 1, the task's priority is used as an index into the * used are 0 and 1, the task's priority is used as an index into the
loop count array. */ * loop count array. */
ulEchoLoopCounters[ uxIndex ]++; ulEchoLoopCounters[ uxIndex ]++;
} }
@ -763,7 +763,6 @@ EchoMessageBuffers_t *pxMessageBuffers = ( EchoMessageBuffers_t * ) pvParameters
{ {
mtCOVERAGE_TEST_MARKER(); mtCOVERAGE_TEST_MARKER();
} }
} while( ux == 0 ); } while( ux == 0 );
/* Wait for the string to be echoed back. */ /* Wait for the string to be echoed back. */
@ -788,8 +787,8 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
( void ) pvParameters; ( void ) pvParameters;
/* Create the message buffer used to send data from the client to the server, /* Create the message buffer used to send data from the client to the server,
and the message buffer used to echo the data from the server back to the * and the message buffer used to echo the data from the server back to the
client. */ * client. */
xMessageBuffers.xEchoClientBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES ); xMessageBuffers.xEchoClientBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
xMessageBuffers.xEchoServerBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES ); xMessageBuffers.xEchoServerBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
configASSERT( xMessageBuffers.xEchoClientBuffer ); configASSERT( xMessageBuffers.xEchoClientBuffer );
@ -807,9 +806,9 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
( void ) xTimeOnEntering; /* In case configASSERT() is not defined. */ ( void ) xTimeOnEntering; /* In case configASSERT() is not defined. */
/* Now the message buffers have been created the echo client task can be /* Now the message buffers have been created the echo client task can be
created. If this server task has the higher priority then the client task * created. If this server task has the higher priority then the client task
is created at the lower priority - if this server task has the lower * is created at the lower priority - if this server task has the lower
priority then the client task is created at the higher priority. */ * priority then the client task is created at the higher priority. */
if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY ) if( uxTaskPriorityGet( NULL ) == mbLOWER_PRIORITY )
{ {
xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbHIGHER_PRIORITY, NULL ); xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbHIGHER_PRIORITY, NULL );
@ -817,7 +816,7 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
else else
{ {
/* Here prvSingleTaskTests() performs various tests on a message buffer /* Here prvSingleTaskTests() performs various tests on a message buffer
that was created dynamically. */ * that was created dynamically. */
prvSingleTaskTests( xMessageBuffers.xEchoClientBuffer ); prvSingleTaskTests( xMessageBuffers.xEchoClientBuffer );
xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbLOWER_PRIORITY, NULL ); xTaskCreate( prvEchoClient, "EchoClient", configMINIMAL_STACK_SIZE, ( void * ) &xMessageBuffers, mbLOWER_PRIORITY, NULL );
} }
@ -836,7 +835,7 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
xMessageBufferSend( xMessageBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY ); xMessageBufferSend( xMessageBuffers.xEchoServerBuffer, ( void * ) pcReceivedString, xReceivedLength, portMAX_DELAY );
/* This message buffer is just created and deleted to ensure no memory /* This message buffer is just created and deleted to ensure no memory
leaks. */ * leaks. */
xTempMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES ); xTempMessageBuffer = xMessageBufferCreate( mbMESSAGE_BUFFER_LENGTH_BYTES );
vMessageBufferDelete( xTempMessageBuffer ); vMessageBufferDelete( xTempMessageBuffer );
} }
@ -859,12 +858,12 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
for( ; ; ) for( ; ; )
{ {
/* Add bytes to the buffer so the other task should see /* Add bytes to the buffer so the other task should see
mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING bytes free. */ * mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING bytes free. */
xMessageBufferSend( xCoherenceTestMessageBuffer, ( void * ) cTxString, strlen( cTxString ), 0 ); xMessageBufferSend( xCoherenceTestMessageBuffer, ( void * ) cTxString, strlen( cTxString ), 0 );
configASSERT( xMessageBufferSpacesAvailable( xCoherenceTestMessageBuffer ) == mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING ); configASSERT( xMessageBufferSpacesAvailable( xCoherenceTestMessageBuffer ) == mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING );
/* Read out message again so the other task should read the full /* Read out message again so the other task should read the full
mbCOHERENCE_TEST_BUFFER_SIZE bytes free again. */ * mbCOHERENCE_TEST_BUFFER_SIZE bytes free again. */
memset( ( void * ) cRxString, 0x00, sizeof( cRxString ) ); memset( ( void * ) cRxString, 0x00, sizeof( cRxString ) );
xMessageBufferReceive( xCoherenceTestMessageBuffer, ( void * ) cRxString, mbCOHERENCE_TEST_BYTES_WRITTEN, 0 ); xMessageBufferReceive( xCoherenceTestMessageBuffer, ( void * ) cRxString, mbCOHERENCE_TEST_BYTES_WRITTEN, 0 );
configASSERT( strcmp( cTxString, cRxString ) == 0 ); configASSERT( strcmp( cTxString, cRxString ) == 0 );
@ -882,15 +881,15 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 250UL );
for( ; ; ) for( ; ; )
{ {
/* This message buffer is only ever empty or contains 5 bytes. So all /* This message buffer is only ever empty or contains 5 bytes. So all
queries of its free space should result in one of the two values tested * queries of its free space should result in one of the two values tested
below. */ * below. */
xSpaceAvailable = xMessageBufferSpacesAvailable( xCoherenceTestMessageBuffer ); xSpaceAvailable = xMessageBufferSpacesAvailable( xCoherenceTestMessageBuffer );
if( ( xSpaceAvailable == mbCOHERENCE_TEST_BUFFER_SIZE ) || if( ( xSpaceAvailable == mbCOHERENCE_TEST_BUFFER_SIZE ) ||
( xSpaceAvailable == mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING ) ) ( xSpaceAvailable == mbEXPECTED_FREE_BYTES_AFTER_WRITING_STRING ) )
{ {
/* Only continue to increment the variable that shows this task /* Only continue to increment the variable that shows this task
is still executing if no errors have been found. */ * is still executing if no errors have been found. */
if( xErrorFound == pdFALSE ) if( xErrorFound == pdFALSE )
{ {
ulSizeCoherencyTestCycles++; ulSizeCoherencyTestCycles++;
@ -966,10 +965,8 @@ BaseType_t xReturn = pdPASS, x;
ullastSizeCoherencyTestCycles = ulSizeCoherencyTestCycles; ullastSizeCoherencyTestCycles = ulSizeCoherencyTestCycles;
} }
} }
#endif #endif /* if ( configRUN_ADDITIONAL_TESTS == 1 ) */
return xReturn; return xReturn;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -49,10 +49,10 @@
*/ */
/* /*
Changes from V2.0.0 * Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of + Delay periods are now specified using variables and constants of
TickType_t rather than uint32_t. + TickType_t rather than uint32_t.
*/ */
#include <stdlib.h> #include <stdlib.h>
@ -80,7 +80,7 @@ static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters ); static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );
/* Variables that are used to check that the tasks are still running with no /* Variables that are used to check that the tasks are still running with no
errors. */ * errors. */
static volatile BaseType_t xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE; static volatile BaseType_t xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -95,11 +95,11 @@ static QueueHandle_t xPolledQueue;
if( xPolledQueue != NULL ) if( xPolledQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
in use. The queue registry is provided as a means for kernel aware * in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware debugger * debuggers to locate queues and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( xPolledQueue, "Poll_Test_Queue" ); vQueueAddToRegistry( xPolledQueue, "Poll_Test_Queue" );
/* Spawn the producer and consumer. */ /* Spawn the producer and consumer. */
@ -122,7 +122,7 @@ BaseType_t xError = pdFALSE, xLoop;
if( xQueueSend( *( ( QueueHandle_t * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS ) if( xQueueSend( *( ( QueueHandle_t * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )
{ {
/* We should never find the queue full so if we get here there /* We should never find the queue full so if we get here there
has been an error. */ * has been an error. */
xError = pdTRUE; xError = pdTRUE;
} }
else else
@ -130,7 +130,7 @@ BaseType_t xError = pdFALSE, xLoop;
if( xError == pdFALSE ) if( xError == pdFALSE )
{ {
/* If an error has ever been recorded we stop incrementing the /* If an error has ever been recorded we stop incrementing the
check variable. */ * check variable. */
portENTER_CRITICAL(); portENTER_CRITICAL();
xPollingProducerCount++; xPollingProducerCount++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
@ -142,7 +142,7 @@ BaseType_t xError = pdFALSE, xLoop;
} }
/* Wait before we start posting again to ensure the consumer runs and /* Wait before we start posting again to ensure the consumer runs and
empties the queue. */ * empties the queue. */
vTaskDelay( pollqPRODUCER_DELAY ); vTaskDelay( pollqPRODUCER_DELAY );
} }
} /*lint !e818 Function prototype must conform to API. */ } /*lint !e818 Function prototype must conform to API. */
@ -163,11 +163,11 @@ BaseType_t xError = pdFALSE;
if( usData != usExpectedValue ) if( usData != usExpectedValue )
{ {
/* This is not what we expected to receive so an error has /* This is not what we expected to receive so an error has
occurred. */ * occurred. */
xError = pdTRUE; xError = pdTRUE;
/* Catch-up to the value we received so our next expected /* Catch-up to the value we received so our next expected
value should again be correct. */ * value should again be correct. */
usExpectedValue = usData; usExpectedValue = usData;
} }
else else
@ -175,7 +175,7 @@ BaseType_t xError = pdFALSE;
if( xError == pdFALSE ) if( xError == pdFALSE )
{ {
/* Only increment the check variable if no errors have /* Only increment the check variable if no errors have
occurred. */ * occurred. */
portENTER_CRITICAL(); portENTER_CRITICAL();
xPollingConsumerCount++; xPollingConsumerCount++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
@ -188,7 +188,7 @@ BaseType_t xError = pdFALSE;
} }
/* Now the queue is empty we block, allowing the producer to place more /* Now the queue is empty we block, allowing the producer to place more
items in the queue. */ * items in the queue. */
vTaskDelay( pollqCONSUMER_DELAY ); vTaskDelay( pollqCONSUMER_DELAY );
} }
} /*lint !e818 Function prototype must conform to API. */ } /*lint !e818 Function prototype must conform to API. */
@ -200,9 +200,9 @@ BaseType_t xArePollingQueuesStillRunning( void )
BaseType_t xReturn; BaseType_t xReturn;
/* Check both the consumer and producer poll count to check they have both /* Check both the consumer and producer poll count to check they have both
been changed since out last trip round. We do not need a critical section * been changed since out last trip round. We do not need a critical section
around the check variables as this is called from a higher priority than * around the check variables as this is called from a higher priority than
the other tasks that access the same variables. */ * the other tasks that access the same variables. */
if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) || if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||
( xPollingProducerCount == pollqINITIAL_VALUE ) ( xPollingProducerCount == pollqINITIAL_VALUE )
) )
@ -215,7 +215,7 @@ BaseType_t xReturn;
} }
/* Set the check variables back down so we know if they have been /* Set the check variables back down so we know if they have been
incremented the next time around. */ * incremented the next time around. */
xPollingConsumerCount = pollqINITIAL_VALUE; xPollingConsumerCount = pollqINITIAL_VALUE;
xPollingProducerCount = pollqINITIAL_VALUE; xPollingProducerCount = pollqINITIAL_VALUE;

View file

@ -67,11 +67,11 @@ static void prvHighestPriorityPeekTask( void *pvParameters );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Flag that will be latched to pdTRUE should any unexpected behaviour be /* Flag that will be latched to pdTRUE should any unexpected behaviour be
detected in any of the tasks. */ * detected in any of the tasks. */
static volatile BaseType_t xErrorDetected = pdFALSE; static volatile BaseType_t xErrorDetected = pdFALSE;
/* Counter that is incremented on each cycle of a test. This is used to /* Counter that is incremented on each cycle of a test. This is used to
detect a stalled task - a test that is no longer running. */ * detect a stalled task - a test that is no longer running. */
static volatile uint32_t ulLoopCounter = 0; static volatile uint32_t ulLoopCounter = 0;
/* Handles to the test tasks. */ /* Handles to the test tasks. */
@ -88,16 +88,16 @@ QueueHandle_t xQueue;
if( xQueue != NULL ) if( xQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
in use. The queue registry is provided as a means for kernel aware * in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware debugger * debuggers to locate queues and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( xQueue, "QPeek_Test_Queue" ); vQueueAddToRegistry( xQueue, "QPeek_Test_Queue" );
/* Create the demo tasks and pass it the queue just created. We are /* Create the demo tasks and pass it the queue just created. We are
passing the queue handle by value so it does not matter that it is declared * passing the queue handle by value so it does not matter that it is declared
on the stack here. */ * on the stack here. */
xTaskCreate( prvLowPriorityPeekTask, "PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL ); xTaskCreate( prvLowPriorityPeekTask, "PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );
xTaskCreate( prvMediumPriorityPeekTask, "PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask ); xTaskCreate( prvMediumPriorityPeekTask, "PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );
xTaskCreate( prvHighPriorityPeekTask, "PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask ); xTaskCreate( prvHighPriorityPeekTask, "PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );
@ -125,7 +125,7 @@ uint32_t ulValue;
for( ; ; ) for( ; ; )
{ {
/* Try peeking from the queue. The queue should be empty so we will /* Try peeking from the queue. The queue should be empty so we will
block, allowing the high priority task to execute. */ * block, allowing the high priority task to execute. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
/* We expected to have received something by the time we unblock. */ /* We expected to have received something by the time we unblock. */
@ -133,11 +133,11 @@ uint32_t ulValue;
} }
/* When we reach here the high and medium priority tasks should still /* When we reach here the high and medium priority tasks should still
be blocked on the queue. We unblocked because the low priority task * be blocked on the queue. We unblocked because the low priority task
wrote a value to the queue, which we should have peeked. Peeking the * wrote a value to the queue, which we should have peeked. Peeking the
data (rather than receiving it) will leave the data on the queue, so * data (rather than receiving it) will leave the data on the queue, so
the high priority task should then have also been unblocked, but not * the high priority task should then have also been unblocked, but not
yet executed. */ * yet executed. */
if( ulValue != 0x11223344 ) if( ulValue != 0x11223344 )
{ {
/* We did not receive the expected value. */ /* We did not receive the expected value. */
@ -151,9 +151,10 @@ uint32_t ulValue;
} }
/* Now we are going to actually receive the data, so when the high /* Now we are going to actually receive the data, so when the high
priority task runs it will find the queue empty and return to the * priority task runs it will find the queue empty and return to the
blocked state. */ * blocked state. */
ulValue = 0; ulValue = 0;
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
{ {
/* We expected to receive the value. */ /* We expected to receive the value. */
@ -163,12 +164,12 @@ uint32_t ulValue;
if( ulValue != 0x11223344 ) if( ulValue != 0x11223344 )
{ {
/* We did not receive the expected value - which should have been /* We did not receive the expected value - which should have been
the same value as was peeked. */ * the same value as was peeked. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Now we will block again as the queue is once more empty. The low /* Now we will block again as the queue is once more empty. The low
priority task can then execute again. */ * priority task can then execute again. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
/* We expected to have received something by the time we unblock. */ /* We expected to have received something by the time we unblock. */
@ -176,7 +177,7 @@ uint32_t ulValue;
} }
/* When we get here the low priority task should have again written to the /* When we get here the low priority task should have again written to the
queue. */ * queue. */
if( ulValue != 0x01234567 ) if( ulValue != 0x01234567 )
{ {
/* We did not receive the expected value. */ /* We did not receive the expected value. */
@ -190,16 +191,14 @@ uint32_t ulValue;
} }
/* We only peeked the data, so suspending ourselves now should enable /* We only peeked the data, so suspending ourselves now should enable
the high priority task to also peek the data. The high priority task * the high priority task to also peek the data. The high priority task
will have been unblocked when we peeked the data as we left the data * will have been unblocked when we peeked the data as we left the data
in the queue. */ * in the queue. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* This time we are going to do the same as the above test, but the /* This time we are going to do the same as the above test, but the
high priority task is going to receive the data, rather than peek it. * high priority task is going to receive the data, rather than peek it.
This means that the medium priority task should never peek the value. */ * This means that the medium priority task should never peek the value. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -223,8 +222,8 @@ uint32_t ulValue;
for( ; ; ) for( ; ; )
{ {
/* Try peeking from the queue. The queue should be empty so we will /* Try peeking from the queue. The queue should be empty so we will
block, allowing the medium priority task to execute. Both the high * block, allowing the medium priority task to execute. Both the high
and highest priority tasks will then be blocked on the queue. */ * and highest priority tasks will then be blocked on the queue. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
/* We expected to have received something by the time we unblock. */ /* We expected to have received something by the time we unblock. */
@ -232,8 +231,8 @@ uint32_t ulValue;
} }
/* When we get here the highest priority task should have peeked the data /* When we get here the highest priority task should have peeked the data
(unblocking this task) then suspended (allowing this task to also peek * (unblocking this task) then suspended (allowing this task to also peek
the data). */ * the data). */
if( ulValue != 0x01234567 ) if( ulValue != 0x01234567 )
{ {
/* We did not receive the expected value. */ /* We did not receive the expected value. */
@ -247,14 +246,13 @@ uint32_t ulValue;
} }
/* We only peeked the data, so suspending ourselves now should enable /* We only peeked the data, so suspending ourselves now should enable
the medium priority task to also peek the data. The medium priority task * the medium priority task to also peek the data. The medium priority task
will have been unblocked when we peeked the data as we left the data * will have been unblocked when we peeked the data as we left the data
in the queue. */ * in the queue. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/* This time we are going actually receive the value, so the medium /* This time we are going actually receive the value, so the medium
priority task will never peek the data - we removed it from the queue. */ * priority task will never peek the data - we removed it from the queue. */
if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -278,8 +276,8 @@ uint32_t ulValue;
for( ; ; ) for( ; ; )
{ {
/* Try peeking from the queue. The queue should be empty so we will /* Try peeking from the queue. The queue should be empty so we will
block, allowing the low priority task to execute. The highest, high * block, allowing the low priority task to execute. The highest, high
and medium priority tasks will then all be blocked on the queue. */ * and medium priority tasks will then all be blocked on the queue. */
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
{ {
/* We expected to have received something by the time we unblock. */ /* We expected to have received something by the time we unblock. */
@ -287,8 +285,8 @@ uint32_t ulValue;
} }
/* When we get here the high priority task should have peeked the data /* When we get here the high priority task should have peeked the data
(unblocking this task) then suspended (allowing this task to also peek * (unblocking this task) then suspended (allowing this task to also peek
the data). */ * the data). */
if( ulValue != 0x01234567 ) if( ulValue != 0x01234567 )
{ {
/* We did not receive the expected value. */ /* We did not receive the expected value. */
@ -305,7 +303,7 @@ uint32_t ulValue;
ulLoopCounter++; ulLoopCounter++;
/* Now we can suspend ourselves so the low priority task can execute /* Now we can suspend ourselves so the low priority task can execute
again. */ * again. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
} }
} }
@ -319,12 +317,13 @@ uint32_t ulValue;
for( ; ; ) for( ; ; )
{ {
/* Write some data to the queue. This should unblock the highest /* Write some data to the queue. This should unblock the highest
priority task that is waiting to peek data from the queue. */ * priority task that is waiting to peek data from the queue. */
ulValue = 0x11223344; ulValue = 0x11223344;
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
{ {
/* We were expecting the queue to be empty so we should not of /* We were expecting the queue to be empty so we should not of
had a problem writing to the queue. */ * had a problem writing to the queue. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
@ -333,19 +332,20 @@ uint32_t ulValue;
#endif #endif
/* By the time we get here the data should have been removed from /* By the time we get here the data should have been removed from
the queue. */ * the queue. */
if( uxQueueMessagesWaiting( xQueue ) != 0 ) if( uxQueueMessagesWaiting( xQueue ) != 0 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
/* Write another value to the queue, again waking the highest priority /* Write another value to the queue, again waking the highest priority
task that is blocked on the queue. */ * task that is blocked on the queue. */
ulValue = 0x01234567; ulValue = 0x01234567;
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
{ {
/* We were expecting the queue to be empty so we should not of /* We were expecting the queue to be empty so we should not of
had a problem writing to the queue. */ * had a problem writing to the queue. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
@ -354,8 +354,9 @@ uint32_t ulValue;
#endif #endif
/* All the other tasks should now have successfully peeked the data. /* All the other tasks should now have successfully peeked the data.
The data is still in the queue so we should be able to receive it. */ * The data is still in the queue so we should be able to receive it. */
ulValue = 0; ulValue = 0;
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
{ {
/* We expected to receive the data. */ /* We expected to receive the data. */
@ -369,14 +370,14 @@ uint32_t ulValue;
} }
/* Lets just delay a while as this is an intensive test as we don't /* Lets just delay a while as this is an intensive test as we don't
want to starve other tests of processing time. */ * want to starve other tests of processing time. */
vTaskDelay( qpeekSHORT_DELAY ); vTaskDelay( qpeekSHORT_DELAY );
/* Unsuspend the other tasks so we can repeat the test - this time /* Unsuspend the other tasks so we can repeat the test - this time
however not all the other tasks will peek the data as the high * however not all the other tasks will peek the data as the high
priority task is actually going to remove it from the queue. Send * priority task is actually going to remove it from the queue. Send
to front is used just to be different. As the queue is empty it * to front is used just to be different. As the queue is empty it
makes no difference to the result. */ * makes no difference to the result. */
vTaskResume( xMediumPriorityTask ); vTaskResume( xMediumPriorityTask );
vTaskResume( xHighPriorityTask ); vTaskResume( xHighPriorityTask );
vTaskResume( xHighestPriorityTask ); vTaskResume( xHighestPriorityTask );
@ -386,10 +387,11 @@ uint32_t ulValue;
#endif #endif
ulValue = 0xaabbaabb; ulValue = 0xaabbaabb;
if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
{ {
/* We were expecting the queue to be empty so we should not of /* We were expecting the queue to be empty so we should not of
had a problem writing to the queue. */ * had a problem writing to the queue. */
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
} }
@ -398,7 +400,7 @@ uint32_t ulValue;
#endif #endif
/* This time we should find that the queue is empty. The high priority /* This time we should find that the queue is empty. The high priority
task actually removed the data rather than just peeking it. */ * task actually removed the data rather than just peeking it. */
if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY ) if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )
{ {
/* We expected to receive the data. */ /* We expected to receive the data. */
@ -406,13 +408,13 @@ uint32_t ulValue;
} }
/* Unsuspend the highest and high priority tasks so we can go back /* Unsuspend the highest and high priority tasks so we can go back
and repeat the whole thing. The medium priority task should not be * and repeat the whole thing. The medium priority task should not be
suspended as it was not able to peek the data in this last case. */ * suspended as it was not able to peek the data in this last case. */
vTaskResume( xHighPriorityTask ); vTaskResume( xHighPriorityTask );
vTaskResume( xHighestPriorityTask ); vTaskResume( xHighestPriorityTask );
/* Lets just delay a while as this is an intensive test as we don't /* Lets just delay a while as this is an intensive test as we don't
want to starve other tests of processing time. */ * want to starve other tests of processing time. */
vTaskDelay( qpeekSHORT_DELAY ); vTaskDelay( qpeekSHORT_DELAY );
} }
} }
@ -424,7 +426,7 @@ BaseType_t xAreQueuePeekTasksStillRunning( void )
static uint32_t ulLastLoopCounter = 0; static uint32_t ulLastLoopCounter = 0;
/* If the demo task is still running then we expect the loopcounter to /* If the demo task is still running then we expect the loopcounter to
have incremented since this function was last called. */ * have incremented since this function was last called. */
if( ulLastLoopCounter == ulLoopCounter ) if( ulLastLoopCounter == ulLoopCounter )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -433,8 +435,7 @@ static uint32_t ulLastLoopCounter = 0;
ulLastLoopCounter = ulLoopCounter; ulLastLoopCounter = ulLoopCounter;
/* Errors detected in the task itself will have latched xErrorDetected /* Errors detected in the task itself will have latched xErrorDetected
to true. */ * to true. */
return ( BaseType_t ) !xErrorDetected; return ( BaseType_t ) !xErrorDetected;
} }

View file

@ -48,15 +48,15 @@
static void prvQueueOverwriteTask( void * pvParameters ); static void prvQueueOverwriteTask( void * pvParameters );
/* Variable that is incremented on each loop of prvQueueOverwriteTask() provided /* Variable that is incremented on each loop of prvQueueOverwriteTask() provided
prvQueueOverwriteTask() has not found any errors. */ * prvQueueOverwriteTask() has not found any errors. */
static uint32_t ulLoopCounter = 0; static uint32_t ulLoopCounter = 0;
/* Set to pdFALSE if an error is discovered by the /* Set to pdFALSE if an error is discovered by the
vQueueOverwritePeriodicISRDemo() function. */ * vQueueOverwritePeriodicISRDemo() function. */
static BaseType_t xISRTestStatus = pdPASS; static BaseType_t xISRTestStatus = pdPASS;
/* The queue that is accessed from the ISR. The queue accessed by the task is /* The queue that is accessed from the ISR. The queue accessed by the task is
created inside the task itself. */ * created inside the task itself. */
static QueueHandle_t xISRQueue = NULL; static QueueHandle_t xISRQueue = NULL;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -66,11 +66,11 @@ void vStartQueueOverwriteTask( UBaseType_t uxPriority )
const UBaseType_t uxQueueLength = 1; const UBaseType_t uxQueueLength = 1;
/* Create the queue used by the ISR. xQueueOverwriteFromISR() should only /* Create the queue used by the ISR. xQueueOverwriteFromISR() should only
be used on queues that have a length of 1. */ * be used on queues that have a length of 1. */
xISRQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) ); xISRQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) );
/* Create the test task. The queue used by the test task is created inside /* Create the test task. The queue used by the test task is created inside
the task itself. */ * the task itself. */
xTaskCreate( prvQueueOverwriteTask, "QOver", configMINIMAL_STACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( prvQueueOverwriteTask, "QOver", configMINIMAL_STACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -85,14 +85,14 @@ uint32_t ulValue, ulStatus = pdPASS, x;
( void ) pvParameters; ( void ) pvParameters;
/* Create the queue. xQueueOverwrite() should only be used on queues that /* Create the queue. xQueueOverwrite() should only be used on queues that
have a length of 1. */ * have a length of 1. */
xTaskQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) ); xTaskQueue = xQueueCreate( uxQueueLength, ( UBaseType_t ) sizeof( uint32_t ) );
configASSERT( xTaskQueue ); configASSERT( xTaskQueue );
for( ; ; ) for( ; ; )
{ {
/* The queue is empty. Writing to the queue then reading from the queue /* The queue is empty. Writing to the queue then reading from the queue
should return the item written. */ * should return the item written. */
ulValue = 10; ulValue = 10;
xQueueOverwrite( xTaskQueue, &ulValue ); xQueueOverwrite( xTaskQueue, &ulValue );
@ -105,15 +105,16 @@ uint32_t ulValue, ulStatus = pdPASS, x;
} }
/* Now try writing to the queue several times. Each time the value /* Now try writing to the queue several times. Each time the value
in the queue should get overwritten. */ * in the queue should get overwritten. */
for( x = 0; x < qoLOOPS; x++ ) for( x = 0; x < qoLOOPS; x++ )
{ {
/* Write to the queue. */ /* Write to the queue. */
xQueueOverwrite( xTaskQueue, &x ); xQueueOverwrite( xTaskQueue, &x );
/* Check the value in the queue is that written, even though the /* Check the value in the queue is that written, even though the
queue was not necessarily empty. */ * queue was not necessarily empty. */
xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK ); xQueuePeek( xTaskQueue, &ulValue, qoDONT_BLOCK );
if( ulValue != x ) if( ulValue != x )
{ {
ulStatus = pdFAIL; ulStatus = pdFAIL;
@ -137,7 +138,7 @@ uint32_t ulValue, ulStatus = pdPASS, x;
if( ulStatus != pdFAIL ) if( ulStatus != pdFAIL )
{ {
/* Increment a counter to show this task is still running without /* Increment a counter to show this task is still running without
error. */ * error. */
ulLoopCounter++; ulLoopCounter++;
} }
@ -179,46 +180,52 @@ const uint32_t ulTx1 = 10UL, ulTx2 = 20UL, ulNumberOfSwitchCases = 3UL;
uint32_t ulRx; uint32_t ulRx;
/* This function should be called from an interrupt, such as the tick hook /* This function should be called from an interrupt, such as the tick hook
function vApplicationTickHook(). */ * function vApplicationTickHook(). */
configASSERT( xISRQueue ); configASSERT( xISRQueue );
switch( ulCallCount ) switch( ulCallCount )
{ {
case 0: case 0:
/* The queue is empty. Write ulTx1 to the queue. In this demo the /* The queue is empty. Write ulTx1 to the queue. In this demo the
last parameter is not used because there are no tasks blocked on * last parameter is not used because there are no tasks blocked on
this queue. */ * this queue. */
xQueueOverwriteFromISR( xISRQueue, &ulTx1, NULL ); xQueueOverwriteFromISR( xISRQueue, &ulTx1, NULL );
/* Peek the queue to check it holds the expected value. */ /* Peek the queue to check it holds the expected value. */
xQueuePeekFromISR( xISRQueue, &ulRx ); xQueuePeekFromISR( xISRQueue, &ulRx );
if( ulRx != ulTx1 ) if( ulRx != ulTx1 )
{ {
xISRTestStatus = pdFAIL; xISRTestStatus = pdFAIL;
} }
break; break;
case 1: case 1:
/* The queue already holds ulTx1. Overwrite the value in the queue /* The queue already holds ulTx1. Overwrite the value in the queue
with ulTx2. */ * with ulTx2. */
xQueueOverwriteFromISR( xISRQueue, &ulTx2, NULL ); xQueueOverwriteFromISR( xISRQueue, &ulTx2, NULL );
break; break;
case 2: case 2:
/* Read from the queue to empty the queue again. The value read /* Read from the queue to empty the queue again. The value read
should be ulTx2. */ * should be ulTx2. */
xQueueReceiveFromISR( xISRQueue, &ulRx, NULL ); xQueueReceiveFromISR( xISRQueue, &ulRx, NULL );
if( ulRx != ulTx2 ) if( ulRx != ulTx2 )
{ {
xISRTestStatus = pdFAIL; xISRTestStatus = pdFAIL;
} }
break; break;
} }
/* Run the next case in the switch statement above next time this function /* Run the next case in the switch statement above next time this function
is called. */ * is called. */
ulCallCount++; ulCallCount++;
if( ulCallCount >= ulNumberOfSwitchCases ) if( ulCallCount >= ulNumberOfSwitchCases )
@ -227,4 +234,3 @@ uint32_t ulRx;
ulCallCount = 0; ulCallCount = 0;
} }
} }

View file

@ -66,8 +66,8 @@
#define queuesetDONT_BLOCK 0 #define queuesetDONT_BLOCK 0
/* Messages are sent in incrementing order from both a task and an interrupt. /* Messages are sent in incrementing order from both a task and an interrupt.
The task sends values in the range 0 to 0xfffe, and the interrupt sends values * The task sends values in the range 0 to 0xfffe, and the interrupt sends values
in the range of 0xffff to ULONG_MAX. */ * in the range of 0xffff to ULONG_MAX. */
#define queuesetINITIAL_ISR_TX_VALUE 0xffffUL #define queuesetINITIAL_ISR_TX_VALUE 0xffffUL
/* The priorities used in this demo. */ /* The priorities used in this demo. */
@ -75,25 +75,25 @@ in the range of 0xffff to ULONG_MAX. */
#define queuesetMEDIUM_PRIORITY ( queuesetLOW_PRIORITY + 1 ) #define queuesetMEDIUM_PRIORITY ( queuesetLOW_PRIORITY + 1 )
/* For test purposes the priority of the sending task is changed after every /* For test purposes the priority of the sending task is changed after every
queuesetPRIORITY_CHANGE_LOOPS number of values are sent to a queue. */ * queuesetPRIORITY_CHANGE_LOOPS number of values are sent to a queue. */
#define queuesetPRIORITY_CHANGE_LOOPS ( ( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ) * 2 ) #define queuesetPRIORITY_CHANGE_LOOPS ( ( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ) * 2 )
/* The ISR sends to the queue every queuesetISR_TX_PERIOD ticks. */ /* The ISR sends to the queue every queuesetISR_TX_PERIOD ticks. */
#define queuesetISR_TX_PERIOD ( 100UL ) #define queuesetISR_TX_PERIOD ( 100UL )
/* A delay inserted when the Tx task changes its priority to be above the idle /* A delay inserted when the Tx task changes its priority to be above the idle
task priority to ensure the idle priority tasks get some CPU time before the * task priority to ensure the idle priority tasks get some CPU time before the
next iteration of the queue set Tx task. */ * next iteration of the queue set Tx task. */
#define queuesetTX_LOOP_DELAY pdMS_TO_TICKS( ( TickType_t ) 200 ) #define queuesetTX_LOOP_DELAY pdMS_TO_TICKS( ( TickType_t ) 200 )
/* The allowable maximum deviation between a received value and the expected /* The allowable maximum deviation between a received value and the expected
received value. A deviation will occur when data is received from a queue * received value. A deviation will occur when data is received from a queue
inside an ISR in between a task receiving from a queue and the task checking * inside an ISR in between a task receiving from a queue and the task checking
the received value. */ * the received value. */
#define queuesetALLOWABLE_RX_DEVIATION 3 #define queuesetALLOWABLE_RX_DEVIATION 3
/* Ignore values that are at the boundaries of allowable values to make the /* Ignore values that are at the boundaries of allowable values to make the
testing of limits easier (don't have to deal with wrapping values). */ * testing of limits easier (don't have to deal with wrapping values). */
#define queuesetIGNORED_BOUNDARY ( queuesetALLOWABLE_RX_DEVIATION * 2 ) #define queuesetIGNORED_BOUNDARY ( queuesetALLOWABLE_RX_DEVIATION * 2 )
typedef enum typedef enum
@ -138,7 +138,8 @@ static void prvSetupTest( void );
* Checks a value received from a queue falls within the range of expected * Checks a value received from a queue falls within the range of expected
* values. * values.
*/ */
static BaseType_t prvCheckReceivedValueWithinExpectedRange( uint32_t ulReceived, uint32_t ulExpectedReceived ); static BaseType_t prvCheckReceivedValueWithinExpectedRange( uint32_t ulReceived,
uint32_t ulExpectedReceived );
/* /*
* Increase test coverage by occasionally change the priorities of the two tasks * Increase test coverage by occasionally change the priorities of the two tasks
@ -173,30 +174,30 @@ static void prvSRand( size_t uxSeed );
static QueueHandle_t xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 }; static QueueHandle_t xQueues[ queuesetNUM_QUEUES_IN_SET ] = { 0 };
/* Counts how many times each queue in the set is used to ensure all the /* Counts how many times each queue in the set is used to ensure all the
queues are used. */ * queues are used. */
static uint32_t ulQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 }; static uint32_t ulQueueUsedCounter[ queuesetNUM_QUEUES_IN_SET ] = { 0 };
/* The handle of the queue set to which the queues are added. */ /* The handle of the queue set to which the queues are added. */
static QueueSetHandle_t xQueueSet; static QueueSetHandle_t xQueueSet;
/* If the prvQueueSetReceivingTask() task has not detected any errors then /* If the prvQueueSetReceivingTask() task has not detected any errors then
it increments ulCycleCounter on each iteration. * it increments ulCycleCounter on each iteration.
xAreQueueSetTasksStillRunning() returns pdPASS if the value of * xAreQueueSetTasksStillRunning() returns pdPASS if the value of
ulCycleCounter has changed between consecutive calls, and pdFALSE if * ulCycleCounter has changed between consecutive calls, and pdFALSE if
ulCycleCounter has stopped incrementing (indicating an error condition). */ * ulCycleCounter has stopped incrementing (indicating an error condition). */
static volatile uint32_t ulCycleCounter = 0UL; static volatile uint32_t ulCycleCounter = 0UL;
/* Set to pdFAIL if an error is detected by any queue set task. /* Set to pdFAIL if an error is detected by any queue set task.
ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */ * ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */
static volatile BaseType_t xQueueSetTasksStatus = pdPASS; static volatile BaseType_t xQueueSetTasksStatus = pdPASS;
/* Just a flag to let the function that writes to a queue from an ISR know that /* Just a flag to let the function that writes to a queue from an ISR know that
the queues are setup and can be used. */ * the queues are setup and can be used. */
static volatile BaseType_t xSetupComplete = pdFALSE; static volatile BaseType_t xSetupComplete = pdFALSE;
/* The value sent to the queue from the ISR is file scope so the /* The value sent to the queue from the ISR is file scope so the
xAreQueeuSetTasksStillRunning() function can check it is incrementing as * xAreQueeuSetTasksStillRunning() function can check it is incrementing as
expected. */ * expected. */
static volatile uint32_t ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE; static volatile uint32_t ulISRTxValue = queuesetINITIAL_ISR_TX_VALUE;
/* Used by the pseudo random number generator. */ /* Used by the pseudo random number generator. */
@ -217,10 +218,10 @@ void vStartQueueSetTasks( void )
xTaskCreate( prvQueueSetReceivingTask, "SetRx", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, &xQueueSetReceivingTask ); xTaskCreate( prvQueueSetReceivingTask, "SetRx", configMINIMAL_STACK_SIZE, ( void * ) xQueueSetSendingTask, queuesetMEDIUM_PRIORITY, &xQueueSetReceivingTask );
/* It is important that the sending task does not attempt to write to a /* It is important that the sending task does not attempt to write to a
queue before the queue has been created. It is therefore placed into * queue before the queue has been created. It is therefore placed into
the suspended state before the scheduler has started. It is resumed by * the suspended state before the scheduler has started. It is resumed by
the receiving task after the receiving task has created the queues and * the receiving task after the receiving task has created the queues and
added the queues to the queue set. */ * added the queues to the queue set. */
vTaskSuspend( xQueueSetSendingTask ); vTaskSuspend( xQueueSetSendingTask );
} }
} }
@ -235,15 +236,15 @@ BaseType_t xReturn = pdPASS, x;
if( ulLastCycleCounter == ulCycleCounter ) if( ulLastCycleCounter == ulCycleCounter )
{ {
/* The cycle counter is no longer being incremented. Either one of the /* The cycle counter is no longer being incremented. Either one of the
tasks is stalled or an error has been detected. */ * tasks is stalled or an error has been detected. */
xReturn = pdFAIL; xReturn = pdFAIL;
} }
ulLastCycleCounter = ulCycleCounter; ulLastCycleCounter = ulCycleCounter;
/* Ensure that all the queues in the set have been used. This ensures the /* Ensure that all the queues in the set have been used. This ensures the
test is working as intended and guards against the rand() in the Tx task * test is working as intended and guards against the rand() in the Tx task
missing some values. */ * missing some values. */
for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )
{ {
if( ulLastQueueUsedCounter[ x ] == ulQueueUsedCounter[ x ] ) if( ulLastQueueUsedCounter[ x ] == ulQueueUsedCounter[ x ] )
@ -293,15 +294,15 @@ QueueHandle_t xQueueInUse;
xQueueInUse = xQueues[ uxQueueToWriteTo ]; xQueueInUse = xQueues[ uxQueueToWriteTo ];
/* Note which index is being written to to ensure all the queues are /* Note which index is being written to to ensure all the queues are
used. */ * used. */
( ulQueueUsedCounter[ uxQueueToWriteTo ] )++; ( ulQueueUsedCounter[ uxQueueToWriteTo ] )++;
/* Send to the queue to unblock the task that is waiting for data to /* Send to the queue to unblock the task that is waiting for data to
arrive on a queue within the queue set to which this queue belongs. */ * arrive on a queue within the queue set to which this queue belongs. */
if( xQueueSendToBack( xQueueInUse, &ulTaskTxValue, portMAX_DELAY ) != pdPASS ) if( xQueueSendToBack( xQueueInUse, &ulTaskTxValue, portMAX_DELAY ) != pdPASS )
{ {
/* The send should always pass as an infinite block time was /* The send should always pass as an infinite block time was
used. */ * used. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
@ -312,14 +313,14 @@ QueueHandle_t xQueueInUse;
ulTaskTxValue++; ulTaskTxValue++;
/* If the Tx value has reached the range used by the ISR then set it /* If the Tx value has reached the range used by the ISR then set it
back to 0. */ * back to 0. */
if( ulTaskTxValue == queuesetINITIAL_ISR_TX_VALUE ) if( ulTaskTxValue == queuesetINITIAL_ISR_TX_VALUE )
{ {
ulTaskTxValue = 0; ulTaskTxValue = 0;
} }
/* Increase test coverage by occasionally change the priorities of the /* Increase test coverage by occasionally change the priorities of the
two tasks relative to each other. */ * two tasks relative to each other. */
prvChangeRelativePriorities(); prvChangeRelativePriorities();
} }
} }
@ -331,8 +332,9 @@ static UBaseType_t ulLoops = 0;
static eRelativePriorities ePriorities = eEqualPriority; static eRelativePriorities ePriorities = eEqualPriority;
/* Occasionally change the task priority relative to the priority of /* Occasionally change the task priority relative to the priority of
the receiving task. */ * the receiving task. */
ulLoops++; ulLoops++;
if( ulLoops >= queuesetPRIORITY_CHANGE_LOOPS ) if( ulLoops >= queuesetPRIORITY_CHANGE_LOOPS )
{ {
ulLoops = 0; ulLoops = 0;
@ -340,31 +342,34 @@ static eRelativePriorities ePriorities = eEqualPriority;
switch( ePriorities ) switch( ePriorities )
{ {
case eEqualPriority: case eEqualPriority:
/* Both tasks are running with medium priority. Now lower the /* Both tasks are running with medium priority. Now lower the
priority of the receiving task so the Tx task has the higher * priority of the receiving task so the Tx task has the higher
relative priority. */ * relative priority. */
vTaskPrioritySet( xQueueSetReceivingTask, queuesetLOW_PRIORITY ); vTaskPrioritySet( xQueueSetReceivingTask, queuesetLOW_PRIORITY );
ePriorities = eTxHigherPriority; ePriorities = eTxHigherPriority;
break; break;
case eTxHigherPriority: case eTxHigherPriority:
/* The Tx task is running with a higher priority than the Rx /* The Tx task is running with a higher priority than the Rx
task. Switch the priorities around so the Rx task has the * task. Switch the priorities around so the Rx task has the
higher relative priority. */ * higher relative priority. */
vTaskPrioritySet( xQueueSetReceivingTask, queuesetMEDIUM_PRIORITY ); vTaskPrioritySet( xQueueSetReceivingTask, queuesetMEDIUM_PRIORITY );
vTaskPrioritySet( xQueueSetSendingTask, queuesetLOW_PRIORITY ); vTaskPrioritySet( xQueueSetSendingTask, queuesetLOW_PRIORITY );
ePriorities = eTxLowerPriority; ePriorities = eTxLowerPriority;
break; break;
case eTxLowerPriority: case eTxLowerPriority:
/* The Tx task is running with a lower priority than the Rx /* The Tx task is running with a lower priority than the Rx
task. Make the priorities equal again. */ * task. Make the priorities equal again. */
vTaskPrioritySet( xQueueSetSendingTask, queuesetMEDIUM_PRIORITY ); vTaskPrioritySet( xQueueSetSendingTask, queuesetMEDIUM_PRIORITY );
ePriorities = eEqualPriority; ePriorities = eEqualPriority;
/* When both tasks are using a non-idle priority the queue set /* When both tasks are using a non-idle priority the queue set
tasks will starve idle priority tasks of execution time - so * tasks will starve idle priority tasks of execution time - so
relax a bit before the next iteration to minimise the impact. */ * relax a bit before the next iteration to minimise the impact. */
vTaskDelay( queuesetTX_LOOP_DELAY ); vTaskDelay( queuesetTX_LOOP_DELAY );
break; break;
@ -383,14 +388,14 @@ TickType_t xBlockTime;
( void ) pvParameters; ( void ) pvParameters;
/* Create the queues and add them to the queue set before resuming the Tx /* Create the queues and add them to the queue set before resuming the Tx
task. */ * task. */
prvSetupTest(); prvSetupTest();
for( ; ; ) for( ; ; )
{ {
/* For test coverage reasons, the block time is dependent on the /* For test coverage reasons, the block time is dependent on the
priority of this task - which changes during the test. When the task * priority of this task - which changes during the test. When the task
is at the idle priority it polls the queue set. */ * is at the idle priority it polls the queue set. */
if( uxTaskPriorityGet( NULL ) == tskIDLE_PRIORITY ) if( uxTaskPriorityGet( NULL ) == tskIDLE_PRIORITY )
{ {
xBlockTime = 0; xBlockTime = 0;
@ -414,16 +419,16 @@ TickType_t xBlockTime;
else else
{ {
/* Reading from the queue should pass with a zero block time as /* Reading from the queue should pass with a zero block time as
this task will only run when something has been posted to a task * this task will only run when something has been posted to a task
in the queue set. */ * in the queue set. */
if( xQueueReceive( xActivatedQueue, &ulReceived, queuesetDONT_BLOCK ) != pdPASS ) if( xQueueReceive( xActivatedQueue, &ulReceived, queuesetDONT_BLOCK ) != pdPASS )
{ {
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Ensure the value received was the value expected. This function /* Ensure the value received was the value expected. This function
manipulates file scope data and is also called from an ISR, hence * manipulates file scope data and is also called from an ISR, hence
the critical section. */ * the critical section. */
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
prvCheckReceivedValue( ulReceived ); prvCheckReceivedValue( ulReceived );
@ -444,12 +449,13 @@ void vQueueSetAccessQueueSetFromISR( void )
static uint32_t ulCallCount = 0; static uint32_t ulCallCount = 0;
/* xSetupComplete is set to pdTRUE when the queues have been created and /* xSetupComplete is set to pdTRUE when the queues have been created and
are available for use. */ * are available for use. */
if( xSetupComplete == pdTRUE ) if( xSetupComplete == pdTRUE )
{ {
/* It is intended that this function is called from the tick hook /* It is intended that this function is called from the tick hook
function, so each call is one tick period apart. */ * function, so each call is one tick period apart. */
ulCallCount++; ulCallCount++;
if( ulCallCount > queuesetISR_TX_PERIOD ) if( ulCallCount > queuesetISR_TX_PERIOD )
{ {
ulCallCount = 0; ulCallCount = 0;
@ -469,28 +475,28 @@ static void prvCheckReceivedValue( uint32_t ulReceived )
static uint32_t ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; static uint32_t ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;
/* Values are received in tasks and interrupts. It is likely that the /* Values are received in tasks and interrupts. It is likely that the
receiving task will sometimes get preempted by the receiving interrupt * receiving task will sometimes get preempted by the receiving interrupt
between reading a value from the queue and calling this function. When * between reading a value from the queue and calling this function. When
that happens, if the receiving interrupt calls this function the values * that happens, if the receiving interrupt calls this function the values
will get passed into this function slightly out of order. For that * will get passed into this function slightly out of order. For that
reason the value passed in is tested against a small range of expected * reason the value passed in is tested against a small range of expected
values, rather than a single absolute value. To make the range testing * values, rather than a single absolute value. To make the range testing
easier values in the range limits are ignored. */ * easier values in the range limits are ignored. */
/* If the received value is equal to or greater than /* If the received value is equal to or greater than
queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */ * queuesetINITIAL_ISR_TX_VALUE then it was sent by an ISR. */
if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE ) if( ulReceived >= queuesetINITIAL_ISR_TX_VALUE )
{ {
/* The value was sent from the ISR. */ /* The value was sent from the ISR. */
if( ( ulReceived - queuesetINITIAL_ISR_TX_VALUE ) < queuesetIGNORED_BOUNDARY ) if( ( ulReceived - queuesetINITIAL_ISR_TX_VALUE ) < queuesetIGNORED_BOUNDARY )
{ {
/* The value received is at the lower limit of the expected range. /* The value received is at the lower limit of the expected range.
Don't test it and expect to receive one higher next time. */ * Don't test it and expect to receive one higher next time. */
} }
else if( ( ULONG_MAX - ulReceived ) <= queuesetIGNORED_BOUNDARY ) else if( ( ULONG_MAX - ulReceived ) <= queuesetIGNORED_BOUNDARY )
{ {
/* The value received is at the higher limit of the expected range. /* The value received is at the higher limit of the expected range.
Don't test it and expect to wrap soon. */ * Don't test it and expect to wrap soon. */
} }
else else
{ {
@ -505,6 +511,7 @@ static uint32_t ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queu
/* It is expected to receive an incrementing number. */ /* It is expected to receive an incrementing number. */
ulExpectedReceivedFromISR++; ulExpectedReceivedFromISR++;
if( ulExpectedReceivedFromISR == 0 ) if( ulExpectedReceivedFromISR == 0 )
{ {
ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE; ulExpectedReceivedFromISR = queuesetINITIAL_ISR_TX_VALUE;
@ -516,12 +523,12 @@ static uint32_t ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queu
if( ulReceived < queuesetIGNORED_BOUNDARY ) if( ulReceived < queuesetIGNORED_BOUNDARY )
{ {
/* The value received is at the lower limit of the expected range. /* The value received is at the lower limit of the expected range.
Don't test it, and expect to receive one higher next time. */ * Don't test it, and expect to receive one higher next time. */
} }
else if( ( ( queuesetINITIAL_ISR_TX_VALUE - 1 ) - ulReceived ) <= queuesetIGNORED_BOUNDARY ) else if( ( ( queuesetINITIAL_ISR_TX_VALUE - 1 ) - ulReceived ) <= queuesetIGNORED_BOUNDARY )
{ {
/* The value received is at the higher limit of the expected range. /* The value received is at the higher limit of the expected range.
Don't test it and expect to wrap soon. */ * Don't test it and expect to wrap soon. */
} }
else else
{ {
@ -536,6 +543,7 @@ static uint32_t ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queu
/* It is expected to receive an incrementing number. */ /* It is expected to receive an incrementing number. */
ulExpectedReceivedFromTask++; ulExpectedReceivedFromTask++;
if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE ) if( ulExpectedReceivedFromTask >= queuesetINITIAL_ISR_TX_VALUE )
{ {
ulExpectedReceivedFromTask = 0; ulExpectedReceivedFromTask = 0;
@ -544,13 +552,15 @@ static uint32_t ulExpectedReceivedFromTask = 0, ulExpectedReceivedFromISR = queu
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static BaseType_t prvCheckReceivedValueWithinExpectedRange( uint32_t ulReceived, uint32_t ulExpectedReceived ) static BaseType_t prvCheckReceivedValueWithinExpectedRange( uint32_t ulReceived,
uint32_t ulExpectedReceived )
{ {
BaseType_t xReturn = pdPASS; BaseType_t xReturn = pdPASS;
if( ulReceived > ulExpectedReceived ) if( ulReceived > ulExpectedReceived )
{ {
configASSERT( ( ulReceived - ulExpectedReceived ) <= queuesetALLOWABLE_RX_DEVIATION ); configASSERT( ( ulReceived - ulExpectedReceived ) <= queuesetALLOWABLE_RX_DEVIATION );
if( ( ulReceived - ulExpectedReceived ) > queuesetALLOWABLE_RX_DEVIATION ) if( ( ulReceived - ulExpectedReceived ) > queuesetALLOWABLE_RX_DEVIATION )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
@ -559,6 +569,7 @@ BaseType_t xReturn = pdPASS;
else else
{ {
configASSERT( ( ulExpectedReceived - ulReceived ) <= queuesetALLOWABLE_RX_DEVIATION ); configASSERT( ( ulExpectedReceived - ulReceived ) <= queuesetALLOWABLE_RX_DEVIATION );
if( ( ulExpectedReceived - ulReceived ) > queuesetALLOWABLE_RX_DEVIATION ) if( ( ulExpectedReceived - ulReceived ) > queuesetALLOWABLE_RX_DEVIATION )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
@ -583,7 +594,7 @@ uint32_t ulReceived;
if( xQueueReceiveFromISR( xActivatedQueue, &ulReceived, NULL ) != pdPASS ) if( xQueueReceiveFromISR( xActivatedQueue, &ulReceived, NULL ) != pdPASS )
{ {
/* Data should have been available as the handle was returned from /* Data should have been available as the handle was returned from
xQueueSelectFromSetFromISR(). */ * xQueueSelectFromSetFromISR(). */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
@ -610,6 +621,7 @@ uint32_t ulTxValueSnapshot = ulISRTxValue;
/* Use a different queue next time. */ /* Use a different queue next time. */
xQueueToWriteTo++; xQueueToWriteTo++;
if( xQueueToWriteTo >= queuesetNUM_QUEUES_IN_SET ) if( xQueueToWriteTo >= queuesetNUM_QUEUES_IN_SET )
{ {
xQueueToWriteTo = 0; xQueueToWriteTo = 0;
@ -625,7 +637,7 @@ QueueHandle_t xQueueHandle = NULL, xReceivedHandle = NULL;
const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1; const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
/* Create a queue that has a length of one - a requirement in order to call /* Create a queue that has a length of one - a requirement in order to call
xQueueOverwrite. This will get deleted again when this test completes. */ * xQueueOverwrite. This will get deleted again when this test completes. */
xQueueHandle = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) ); xQueueHandle = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) );
configASSERT( xQueueHandle ); configASSERT( xQueueHandle );
@ -634,43 +646,50 @@ const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
xQueueAddToSet( xQueueHandle, xQueueSet ); xQueueAddToSet( xQueueHandle, xQueueSet );
/* Add an item to the queue then ensure the queue set correctly /* Add an item to the queue then ensure the queue set correctly
indicates that one item is available, and that item is indeed the * indicates that one item is available, and that item is indeed the
queue written to. */ * queue written to. */
xQueueOverwrite( xQueueHandle, ( void * ) &ulValueToSend ); xQueueOverwrite( xQueueHandle, ( void * ) &ulValueToSend );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 )
{ {
/* Expected one item in the queue set. */ /* Expected one item in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK ); xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle ) if( xReceivedHandle != xQueueHandle )
{ {
/* Wrote to xQueueHandle so expected xQueueHandle to be the handle /* Wrote to xQueueHandle so expected xQueueHandle to be the handle
held in the queue set. */ * held in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Now overwrite the value in the queue and ensure the queue set state /* Now overwrite the value in the queue and ensure the queue set state
doesn't change as the number of items in the queues within the set have * doesn't change as the number of items in the queues within the set have
not changed. */ * not changed. */
ulValueToSend++; ulValueToSend++;
xQueueOverwrite( xQueueHandle, ( void * ) &ulValueToSend ); xQueueOverwrite( xQueueHandle, ( void * ) &ulValueToSend );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 )
{ {
/* Still expected one item in the queue set. */ /* Still expected one item in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK ); xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle ) if( xReceivedHandle != xQueueHandle )
{ {
/* Wrote to xQueueHandle so expected xQueueHandle to be the handle /* Wrote to xQueueHandle so expected xQueueHandle to be the handle
held in the queue set. */ * held in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Also ensure the value received from the queue is the overwritten /* Also ensure the value received from the queue is the overwritten
value, not the value originally written. */ * value, not the value originally written. */
xQueueReceive( xQueueHandle, &ulValueReceived, queuesetDONT_BLOCK ); xQueueReceive( xQueueHandle, &ulValueReceived, queuesetDONT_BLOCK );
if( ulValueReceived != ulValueToSend ) if( ulValueReceived != ulValueToSend )
{ {
/* Unexpected value received from the queue. */ /* Unexpected value received from the queue. */
@ -682,7 +701,9 @@ const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
{ {
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK ); xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK );
if( xReceivedHandle != NULL ) if( xReceivedHandle != NULL )
{ {
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
@ -702,7 +723,7 @@ QueueHandle_t xQueueHandle1 = NULL, xQueueHandle2 = NULL, xReceivedHandle = NULL
const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1; const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
/* Create two queues that have a length of one - a requirement in order to call /* Create two queues that have a length of one - a requirement in order to call
xQueueOverwrite. These will get deleted again when this test completes. */ * xQueueOverwrite. These will get deleted again when this test completes. */
xQueueHandle1 = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) ); xQueueHandle1 = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) );
configASSERT( xQueueHandle1 ); configASSERT( xQueueHandle1 );
xQueueHandle2 = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) ); xQueueHandle2 = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) );
@ -716,6 +737,7 @@ const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
/* Add an item using the first queue. */ /* Add an item using the first queue. */
xQueueOverwrite( xQueueHandle1, ( void * ) &ulValueToSend1 ); xQueueOverwrite( xQueueHandle1, ( void * ) &ulValueToSend1 );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 )
{ {
/* Expected one item in the queue set. */ /* Expected one item in the queue set. */
@ -723,16 +745,17 @@ const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
} }
xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK ); xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle1 ) if( xReceivedHandle != xQueueHandle1 )
{ {
/* Wrote to xQueueHandle so expected xQueueHandle to be the handle /* Wrote to xQueueHandle so expected xQueueHandle to be the handle
held in the queue set. */ * held in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Next add an item to the second queue. */ /* Next add an item to the second queue. */
xQueueOverwrite( xQueueHandle2, ( void * ) &ulValueToSend2 ); xQueueOverwrite( xQueueHandle2, ( void * ) &ulValueToSend2 );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{ {
/* Expected two items in the queue set. */ /* Expected two items in the queue set. */
@ -741,100 +764,108 @@ const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
/* The head of the queue set should not have changed though. */ /* The head of the queue set should not have changed though. */
xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK ); xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle1 ) if( xReceivedHandle != xQueueHandle1 )
{ {
/* Wrote to xQueueHandle so expected xQueueHandle to be the handle /* Wrote to xQueueHandle so expected xQueueHandle to be the handle
held in the queue set. */ * held in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Now overwrite the value in the queue and ensure the queue set state /* Now overwrite the value in the queue and ensure the queue set state
doesn't change as the number of items in the queues within the set have * doesn't change as the number of items in the queues within the set have
not changed. NOTE: after this queue 1 should hold ulValueToSend2 and queue * not changed. NOTE: after this queue 1 should hold ulValueToSend2 and queue
2 should hold the value ulValueToSend1. */ * 2 should hold the value ulValueToSend1. */
xQueueOverwrite( xQueueHandle1, ( void * ) &ulValueToSend2 ); xQueueOverwrite( xQueueHandle1, ( void * ) &ulValueToSend2 );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{
/* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL;
}
xQueueOverwrite( xQueueHandle2, ( void * ) &ulValueToSend1 );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{ {
/* Still expected two items in the queue set. */ /* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueueOverwrite( xQueueHandle2, ( void * ) &ulValueToSend1 );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{
/* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL;
}
/* Repeat the above to ensure the queue set state doesn't change. */ /* Repeat the above to ensure the queue set state doesn't change. */
xQueueOverwrite( xQueueHandle1, ( void * ) &ulValueToSend2 ); xQueueOverwrite( xQueueHandle1, ( void * ) &ulValueToSend2 );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{
/* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL;
}
xQueueOverwrite( xQueueHandle2, ( void * ) &ulValueToSend1 );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{ {
/* Still expected two items in the queue set. */ /* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueueOverwrite( xQueueHandle2, ( void * ) &ulValueToSend1 );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{
/* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL;
}
/* Now when reading from the queue set we expect the handle to the first /* Now when reading from the queue set we expect the handle to the first
queue to be received first, and for that queue to hold ulValueToSend2 as the * queue to be received first, and for that queue to hold ulValueToSend2 as the
originally written value was overwritten. Likewise the second handle received * originally written value was overwritten. Likewise the second handle received
from the set should be that of the second queue, and that queue should hold * from the set should be that of the second queue, and that queue should hold
ulValueToSend1 as the originally written value was overwritten. */ * ulValueToSend1 as the originally written value was overwritten. */
xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK ); xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle1 ) if( xReceivedHandle != xQueueHandle1 )
{ {
/* Wrote to xQueueHandle1 first so expected that handle to be read from /* Wrote to xQueueHandle1 first so expected that handle to be read from
the set first. */ * the set first. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 )
{ {
/* One value was read from the set, so now only expect a single value /* One value was read from the set, so now only expect a single value
in the set. */ * in the set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueueReceive( xReceivedHandle, &ulValueReceived, queuesetDONT_BLOCK ); xQueueReceive( xReceivedHandle, &ulValueReceived, queuesetDONT_BLOCK );
if( ulValueReceived != ulValueToSend2 ) if( ulValueReceived != ulValueToSend2 )
{ {
/* Unexpected value received from the queue. ulValueToSend1 was written /* Unexpected value received from the queue. ulValueToSend1 was written
first, but then overwritten with ulValueToSend2; */ * first, but then overwritten with ulValueToSend2; */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK ); xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle2 ) if( xReceivedHandle != xQueueHandle2 )
{ {
/* xQueueHandle1 has already been removed from the set so expect only /* xQueueHandle1 has already been removed from the set so expect only
xQueueHandle2 to be left. */ * xQueueHandle2 to be left. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 0 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 0 )
{ {
/* The last value was read from the set so don't expect any more. */ /* The last value was read from the set so don't expect any more. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueueReceive( xReceivedHandle, &ulValueReceived, queuesetDONT_BLOCK ); xQueueReceive( xReceivedHandle, &ulValueReceived, queuesetDONT_BLOCK );
if( ulValueReceived != ulValueToSend1 ) if( ulValueReceived != ulValueToSend1 )
{ {
/* Unexpected value received from the queue. ulValueToSend2 was written /* Unexpected value received from the queue. ulValueToSend2 was written
first, but then overwritten with ulValueToSend1. */ * first, but then overwritten with ulValueToSend1. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Should be anything in the queue set now. */ /* Should be anything in the queue set now. */
xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK ); xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK );
if( xReceivedHandle != NULL ) if( xReceivedHandle != NULL )
{ {
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
@ -856,7 +887,7 @@ QueueHandle_t xQueueHandle1 = NULL, xQueueHandle2 = NULL, xReceivedHandle = NULL
const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1; const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
/* Create two queues that have a length of one - a requirement in order to call /* Create two queues that have a length of one - a requirement in order to call
xQueueOverwrite. These will get deleted again when this test completes. */ * xQueueOverwrite. These will get deleted again when this test completes. */
xQueueHandle1 = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) ); xQueueHandle1 = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) );
configASSERT( xQueueHandle1 ); configASSERT( xQueueHandle1 );
xQueueHandle2 = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) ); xQueueHandle2 = xQueueCreate( xLengthOfOne, sizeof( uint32_t ) );
@ -869,8 +900,9 @@ const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
xQueueAddToSet( xQueueHandle2, xQueueSet ); xQueueAddToSet( xQueueHandle2, xQueueSet );
/* Add an item using the first queue using the 'FromISR' version of the /* Add an item using the first queue using the 'FromISR' version of the
overwrite function. */ * overwrite function. */
xQueueOverwriteFromISR( xQueueHandle1, ( void * ) &ulValueToSend1, NULL ); xQueueOverwriteFromISR( xQueueHandle1, ( void * ) &ulValueToSend1, NULL );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 )
{ {
/* Expected one item in the queue set. */ /* Expected one item in the queue set. */
@ -878,17 +910,18 @@ const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
} }
xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK ); xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle1 ) if( xReceivedHandle != xQueueHandle1 )
{ {
/* Wrote to xQueueHandle so expected xQueueHandle to be the handle /* Wrote to xQueueHandle so expected xQueueHandle to be the handle
held in the queue set. */ * held in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Next add an item to the second queue using the 'FromISR' version of the /* Next add an item to the second queue using the 'FromISR' version of the
overwrite function. */ * overwrite function. */
xQueueOverwriteFromISR( xQueueHandle2, ( void * ) &ulValueToSend2, NULL ); xQueueOverwriteFromISR( xQueueHandle2, ( void * ) &ulValueToSend2, NULL );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{ {
/* Expected two items in the queue set. */ /* Expected two items in the queue set. */
@ -897,100 +930,108 @@ const UBaseType_t xLengthOfOne = ( UBaseType_t ) 1;
/* The head of the queue set should not have changed though. */ /* The head of the queue set should not have changed though. */
xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK ); xQueuePeek( xQueueSet, &xReceivedHandle, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle1 ) if( xReceivedHandle != xQueueHandle1 )
{ {
/* Wrote to xQueueHandle so expected xQueueHandle to be the handle /* Wrote to xQueueHandle so expected xQueueHandle to be the handle
held in the queue set. */ * held in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Now overwrite the value in the queue and ensure the queue set state /* Now overwrite the value in the queue and ensure the queue set state
doesn't change as the number of items in the queues within the set have * doesn't change as the number of items in the queues within the set have
not changed. NOTE: after this queue 1 should hold ulValueToSend2 and queue * not changed. NOTE: after this queue 1 should hold ulValueToSend2 and queue
2 should hold the value ulValueToSend1. */ * 2 should hold the value ulValueToSend1. */
xQueueOverwriteFromISR( xQueueHandle1, ( void * ) &ulValueToSend2, NULL ); xQueueOverwriteFromISR( xQueueHandle1, ( void * ) &ulValueToSend2, NULL );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{
/* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL;
}
xQueueOverwriteFromISR( xQueueHandle2, ( void * ) &ulValueToSend1, NULL );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{ {
/* Still expected two items in the queue set. */ /* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueueOverwriteFromISR( xQueueHandle2, ( void * ) &ulValueToSend1, NULL );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{
/* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL;
}
/* Repeat the above to ensure the queue set state doesn't change. */ /* Repeat the above to ensure the queue set state doesn't change. */
xQueueOverwriteFromISR( xQueueHandle1, ( void * ) &ulValueToSend2, NULL ); xQueueOverwriteFromISR( xQueueHandle1, ( void * ) &ulValueToSend2, NULL );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{
/* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL;
}
xQueueOverwriteFromISR( xQueueHandle2, ( void * ) &ulValueToSend1, NULL );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{ {
/* Still expected two items in the queue set. */ /* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueueOverwriteFromISR( xQueueHandle2, ( void * ) &ulValueToSend1, NULL );
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 2 )
{
/* Still expected two items in the queue set. */
xQueueSetTasksStatus = pdFAIL;
}
/* Now when reading from the queue set we expect the handle to the first /* Now when reading from the queue set we expect the handle to the first
queue to be received first, and for that queue to hold ulValueToSend2 as the * queue to be received first, and for that queue to hold ulValueToSend2 as the
originally written value was overwritten. Likewise the second handle received * originally written value was overwritten. Likewise the second handle received
from the set should be that of the second queue, and that queue should hold * from the set should be that of the second queue, and that queue should hold
ulValueToSend1 as the originally written value was overwritten. */ * ulValueToSend1 as the originally written value was overwritten. */
xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK ); xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle1 ) if( xReceivedHandle != xQueueHandle1 )
{ {
/* Wrote to xQueueHandle1 first so expected that handle to be read from /* Wrote to xQueueHandle1 first so expected that handle to be read from
the set first. */ * the set first. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 1 )
{ {
/* One value was read from the set, so now only expect a single value /* One value was read from the set, so now only expect a single value
in the set. */ * in the set. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueueReceive( xReceivedHandle, &ulValueReceived, queuesetDONT_BLOCK ); xQueueReceive( xReceivedHandle, &ulValueReceived, queuesetDONT_BLOCK );
if( ulValueReceived != ulValueToSend2 ) if( ulValueReceived != ulValueToSend2 )
{ {
/* Unexpected value received from the queue. ulValueToSend1 was written /* Unexpected value received from the queue. ulValueToSend1 was written
first, but then overwritten with ulValueToSend2; */ * first, but then overwritten with ulValueToSend2; */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK ); xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK );
if( xReceivedHandle != xQueueHandle2 ) if( xReceivedHandle != xQueueHandle2 )
{ {
/* xQueueHandle1 has already been removed from the set so expect only /* xQueueHandle1 has already been removed from the set so expect only
xQueueHandle2 to be left. */ * xQueueHandle2 to be left. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 0 ) if( uxQueueMessagesWaiting( xQueueSet ) != ( UBaseType_t ) 0 )
{ {
/* The last value was read from the set so don't expect any more. */ /* The last value was read from the set so don't expect any more. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
xQueueReceive( xReceivedHandle, &ulValueReceived, queuesetDONT_BLOCK ); xQueueReceive( xReceivedHandle, &ulValueReceived, queuesetDONT_BLOCK );
if( ulValueReceived != ulValueToSend1 ) if( ulValueReceived != ulValueToSend1 )
{ {
/* Unexpected value received from the queue. ulValueToSend2 was written /* Unexpected value received from the queue. ulValueToSend2 was written
first, but then overwritten with ulValueToSend1. */ * first, but then overwritten with ulValueToSend1. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Should be anything in the queue set now. */ /* Should be anything in the queue set now. */
xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK ); xReceivedHandle = xQueueSelectFromSet( xQueueSet, queuesetDONT_BLOCK );
if( xReceivedHandle != NULL ) if( xReceivedHandle != NULL )
{ {
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
@ -1011,18 +1052,19 @@ BaseType_t x;
uint32_t ulValueToSend = 0; uint32_t ulValueToSend = 0;
/* Ensure the queues are created and the queue set configured before the /* Ensure the queues are created and the queue set configured before the
sending task is unsuspended. * sending task is unsuspended.
*
First Create the queue set such that it will be able to hold a message for * First Create the queue set such that it will be able to hold a message for
every space in every queue in the set. */ * every space in every queue in the set. */
xQueueSet = xQueueCreateSet( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH ); xQueueSet = xQueueCreateSet( queuesetNUM_QUEUES_IN_SET * queuesetQUEUE_LENGTH );
for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ ) for( x = 0; x < queuesetNUM_QUEUES_IN_SET; x++ )
{ {
/* Create the queue and add it to the set. The queue is just holding /* Create the queue and add it to the set. The queue is just holding
uint32_t value. */ * uint32_t value. */
xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( uint32_t ) ); xQueues[ x ] = xQueueCreate( queuesetQUEUE_LENGTH, sizeof( uint32_t ) );
configASSERT( xQueues[ x ] ); configASSERT( xQueues[ x ] );
if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdPASS ) if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdPASS )
{ {
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
@ -1030,7 +1072,7 @@ uint32_t ulValueToSend = 0;
else else
{ {
/* The queue has now been added to the queue set and cannot be added to /* The queue has now been added to the queue set and cannot be added to
another. */ * another. */
if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdFAIL ) if( xQueueAddToSet( xQueues[ x ], xQueueSet ) != pdFAIL )
{ {
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
@ -1039,11 +1081,11 @@ uint32_t ulValueToSend = 0;
} }
/* Attempt to remove a queue from a queue set it does not belong /* Attempt to remove a queue from a queue set it does not belong
to (NULL being passed as the queue set in this case). */ * to (NULL being passed as the queue set in this case). */
if( xQueueRemoveFromSet( xQueues[ 0 ], NULL ) != pdFAIL ) if( xQueueRemoveFromSet( xQueues[ 0 ], NULL ) != pdFAIL )
{ {
/* It is not possible to successfully remove a queue from a queue /* It is not possible to successfully remove a queue from a queue
set it does not belong to. */ * set it does not belong to. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
@ -1051,13 +1093,14 @@ uint32_t ulValueToSend = 0;
if( xQueueRemoveFromSet( xQueues[ 0 ], xQueueSet ) != pdPASS ) if( xQueueRemoveFromSet( xQueues[ 0 ], xQueueSet ) != pdPASS )
{ {
/* It should be possible to remove the queue from the queue set it /* It should be possible to remove the queue from the queue set it
does belong to. */ * does belong to. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Add an item to the queue before attempting to add it back into the /* Add an item to the queue before attempting to add it back into the
set. */ * set. */
xQueueSend( xQueues[ 0 ], ( void * ) &ulValueToSend, 0 ); xQueueSend( xQueues[ 0 ], ( void * ) &ulValueToSend, 0 );
if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdFAIL ) if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdFAIL )
{ {
/* Should not be able to add a non-empty queue to a set. */ /* Should not be able to add a non-empty queue to a set. */
@ -1065,29 +1108,30 @@ uint32_t ulValueToSend = 0;
} }
/* Remove the item from the queue before adding the queue back into the /* Remove the item from the queue before adding the queue back into the
set so the dynamic tests can begin. */ * set so the dynamic tests can begin. */
xQueueReceive( xQueues[ 0 ], &ulValueToSend, 0 ); xQueueReceive( xQueues[ 0 ], &ulValueToSend, 0 );
if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdPASS ) if( xQueueAddToSet( xQueues[ 0 ], xQueueSet ) != pdPASS )
{ {
/* If the queue was successfully removed from the queue set then it /* If the queue was successfully removed from the queue set then it
should be possible to add it back in again. */ * should be possible to add it back in again. */
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* The task that sends to the queues is not running yet, so attempting to /* The task that sends to the queues is not running yet, so attempting to
read from the queue set should fail. */ * read from the queue set should fail. */
if( xQueueSelectFromSet( xQueueSet, queuesetSHORT_DELAY ) != NULL ) if( xQueueSelectFromSet( xQueueSet, queuesetSHORT_DELAY ) != NULL )
{ {
xQueueSetTasksStatus = pdFAIL; xQueueSetTasksStatus = pdFAIL;
} }
/* Testing the behaviour of queue sets when a queue overwrite operation is /* Testing the behaviour of queue sets when a queue overwrite operation is
performed on a set member requires a special test as overwrites can only * performed on a set member requires a special test as overwrites can only
be performed on queues that have a length of 1. */ * be performed on queues that have a length of 1. */
prvTestQueueOverwriteWithQueueSet(); prvTestQueueOverwriteWithQueueSet();
/* Test the case where two queues within a set are written to with /* Test the case where two queues within a set are written to with
xQueueOverwrite(). */ * xQueueOverwrite(). */
prvTestQueueOverwriteOnTwoQueusInQueueSet(); prvTestQueueOverwriteOnTwoQueusInQueueSet();
prvTestQueueOverwriteFromISROnTwoQueusInQueueSet(); prvTestQueueOverwriteFromISROnTwoQueusInQueueSet();

View file

@ -76,7 +76,7 @@ static QueueHandle_t xQueue = NULL;
static QueueSetHandle_t xQueueSet = NULL; static QueueSetHandle_t xQueueSet = NULL;
/* Set to pdFAIL if an error is detected by any queue set task. /* Set to pdFAIL if an error is detected by any queue set task.
ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */ * ulCycleCounter will only be incremented if xQueueSetTasksSatus equals pdPASS. */
static volatile BaseType_t xQueueSetPollStatus = pdPASS; static volatile BaseType_t xQueueSetPollStatus = pdPASS;
/* Counter used to ensure the task is still running. */ /* Counter used to ensure the task is still running. */
@ -87,7 +87,7 @@ static uint32_t ulCycleCounter = 0;
void vStartQueueSetPollingTask( void ) void vStartQueueSetPollingTask( void )
{ {
/* Create the queue that is added to the set, the set, and add the queue to /* Create the queue that is added to the set, the set, and add the queue to
the set. */ * the set. */
xQueue = xQueueCreate( setpollQUEUE_LENGTH, sizeof( uint32_t ) ); xQueue = xQueueCreate( setpollQUEUE_LENGTH, sizeof( uint32_t ) );
xQueueSet = xQueueCreateSet( setpollQUEUE_LENGTH ); xQueueSet = xQueueCreateSet( setpollQUEUE_LENGTH );
@ -112,14 +112,14 @@ QueueHandle_t xActivatedQueue;
for( ; ; ) for( ; ; )
{ {
/* Is a message waiting? A block time is not used to ensure the queue /* Is a message waiting? A block time is not used to ensure the queue
set is polled while it is being written to from an interrupt. */ * set is polled while it is being written to from an interrupt. */
xActivatedQueue = xQueueSelectFromSet( xQueueSet, setpollDONT_BLOCK ); xActivatedQueue = xQueueSelectFromSet( xQueueSet, setpollDONT_BLOCK );
if( xActivatedQueue != NULL ) if( xActivatedQueue != NULL )
{ {
/* Reading from the queue should pass with a zero block time as /* Reading from the queue should pass with a zero block time as
this task will only run when something has been posted to a task * this task will only run when something has been posted to a task
in the queue set. */ * in the queue set. */
if( xQueueReceive( xActivatedQueue, &ulReceived, setpollDONT_BLOCK ) != pdPASS ) if( xQueueReceive( xActivatedQueue, &ulReceived, setpollDONT_BLOCK ) != pdPASS )
{ {
xQueueSetPollStatus = pdFAIL; xQueueSetPollStatus = pdFAIL;
@ -148,8 +148,9 @@ void vQueueSetPollingInterruptAccess( void )
static uint32_t ulCallCount = 0, ulValueToSend = 0; static uint32_t ulCallCount = 0, ulValueToSend = 0;
/* It is intended that this function is called from the tick hook /* It is intended that this function is called from the tick hook
function, so each call is one tick period apart. */ * function, so each call is one tick period apart. */
ulCallCount++; ulCallCount++;
if( ulCallCount > queuesetISR_TX_PERIOD ) if( ulCallCount > queuesetISR_TX_PERIOD )
{ {
ulCallCount = 0; ulCallCount = 0;

View file

@ -53,7 +53,7 @@
#define staticTASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define staticTASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
/* The length of the queue, in items, not bytes, used in the queue static /* The length of the queue, in items, not bytes, used in the queue static
allocation tests. */ * allocation tests. */
#define staticQUEUE_LENGTH_IN_ITEMS ( 5 ) #define staticQUEUE_LENGTH_IN_ITEMS ( 5 )
/* A block time of 0 simply means "don't block". */ /* A block time of 0 simply means "don't block". */
@ -164,7 +164,8 @@ static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore );
/* /*
* Checks the basic operation of a binary semaphore after it has been created. * Checks the basic operation of a binary semaphore after it has been created.
*/ */
static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount ); static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore,
UBaseType_t uxMaxCount );
/* /*
* Checks the basic operation of an event group after it has been created. * Checks the basic operation of an event group after it has been created.
@ -174,25 +175,25 @@ static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* StaticTask_t is a publicly accessible structure that has the same size and /* StaticTask_t is a publicly accessible structure that has the same size and
alignment requirements as the real TCB structure. It is provided as a mechanism * alignment requirements as the real TCB structure. It is provided as a mechanism
for applications to know the size of the TCB (which is dependent on the * for applications to know the size of the TCB (which is dependent on the
architecture and configuration file settings) without breaking the strict data * architecture and configuration file settings) without breaking the strict data
hiding policy by exposing the real TCB. This StaticTask_t variable is passed * hiding policy by exposing the real TCB. This StaticTask_t variable is passed
into the xTaskCreateStatic() function that creates the * into the xTaskCreateStatic() function that creates the
prvStaticallyAllocatedCreator() task, and will hold the TCB of the created * prvStaticallyAllocatedCreator() task, and will hold the TCB of the created
tasks. */ * tasks. */
static StaticTask_t xCreatorTaskTCBBuffer; static StaticTask_t xCreatorTaskTCBBuffer;
/* This is the stack that will be used by the prvStaticallyAllocatedCreator() /* This is the stack that will be used by the prvStaticallyAllocatedCreator()
task, which is itself created using statically allocated buffers (so without any * task, which is itself created using statically allocated buffers (so without any
dynamic memory allocation). */ * dynamic memory allocation). */
static StackType_t uxCreatorTaskStackBuffer[ staticCREATOR_TASK_STACK_SIZE ]; static StackType_t uxCreatorTaskStackBuffer[ staticCREATOR_TASK_STACK_SIZE ];
/* Used by the pseudo random number generating function. */ /* Used by the pseudo random number generating function. */
static uint32_t ulNextRand = 0; static uint32_t ulNextRand = 0;
/* Used so a check task can ensure this test is still executing, and not /* Used so a check task can ensure this test is still executing, and not
stalled. */ * stalled. */
static volatile UBaseType_t uxCycleCounter = 0; static volatile UBaseType_t uxCycleCounter = 0;
/* A variable that gets set to pdTRUE if an error is detected. */ /* A variable that gets set to pdTRUE if an error is detected. */
@ -203,7 +204,7 @@ static volatile BaseType_t xErrorOccurred = pdFALSE;
void vStartStaticallyAllocatedTasks( void ) void vStartStaticallyAllocatedTasks( void )
{ {
/* Create a single task, which then repeatedly creates and deletes the other /* Create a single task, which then repeatedly creates and deletes the other
RTOS objects using both statically and dynamically allocated RAM. */ * RTOS objects using both statically and dynamically allocated RAM. */
xTaskCreateStatic( prvStaticallyAllocatedCreator, /* The function that implements the task being created. */ xTaskCreateStatic( prvStaticallyAllocatedCreator, /* The function that implements the task being created. */
"StatCreate", /* Text name for the task - not used by the RTOS, its just to assist debugging. */ "StatCreate", /* Text name for the task - not used by the RTOS, its just to assist debugging. */
staticCREATOR_TASK_STACK_SIZE, /* Size of the buffer passed in as the stack - in words, not bytes! */ staticCREATOR_TASK_STACK_SIZE, /* Size of the buffer passed in as the stack - in words, not bytes! */
@ -222,14 +223,14 @@ static void prvStaticallyAllocatedCreator( void *pvParameters )
for( ; ; ) for( ; ; )
{ {
/* Loop, running functions that create and delete the various RTOS /* Loop, running functions that create and delete the various RTOS
objects that can be optionally created using either static or dynamic * objects that can be optionally created using either static or dynamic
memory allocation. */ * memory allocation. */
prvCreateAndDeleteStaticallyAllocatedTasks(); prvCreateAndDeleteStaticallyAllocatedTasks();
prvCreateAndDeleteStaticallyAllocatedQueues(); prvCreateAndDeleteStaticallyAllocatedQueues();
/* Delay to ensure lower priority tasks get CPU time, and increment the /* Delay to ensure lower priority tasks get CPU time, and increment the
cycle counter so a 'check' task can determine that this task is still * cycle counter so a 'check' task can determine that this task is still
executing. */ * executing. */
vTaskDelay( prvGetNextDelayTime() ); vTaskDelay( prvGetNextDelayTime() );
uxCycleCounter++; uxCycleCounter++;
@ -257,26 +258,26 @@ SemaphoreHandle_t xSemaphore;
const UBaseType_t uxMaxCount = ( UBaseType_t ) 10; const UBaseType_t uxMaxCount = ( UBaseType_t ) 10;
/* StaticSemaphore_t is a publicly accessible structure that has the same size /* StaticSemaphore_t is a publicly accessible structure that has the same size
and alignment requirements as the real semaphore structure. It is provided as a * and alignment requirements as the real semaphore structure. It is provided as a
mechanism for applications to know the size of the semaphore (which is dependent * mechanism for applications to know the size of the semaphore (which is dependent
on the architecture and configuration file settings) without breaking the strict * on the architecture and configuration file settings) without breaking the strict
data hiding policy by exposing the real semaphore internals. This * data hiding policy by exposing the real semaphore internals. This
StaticSemaphore_t variable is passed into the xSemaphoreCreateCountingStatic() * StaticSemaphore_t variable is passed into the xSemaphoreCreateCountingStatic()
function calls within this function. NOTE: In most usage scenarios now it is * function calls within this function. NOTE: In most usage scenarios now it is
faster and more memory efficient to use a direct to task notification instead of * faster and more memory efficient to use a direct to task notification instead of
a counting semaphore. http://www.freertos.org/RTOS-task-notifications.html */ * a counting semaphore. http://www.freertos.org/RTOS-task-notifications.html */
StaticSemaphore_t xSemaphoreBuffer; StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. xSemaphoreCreateCountingStatic() has one more /* Create the semaphore. xSemaphoreCreateCountingStatic() has one more
parameter than the usual xSemaphoreCreateCounting() function. The parameter * parameter than the usual xSemaphoreCreateCounting() function. The parameter
is a pointer to the pre-allocated StaticSemaphore_t structure, which will * is a pointer to the pre-allocated StaticSemaphore_t structure, which will
hold information on the semaphore in an anonymous way. If the pointer is * hold information on the semaphore in an anonymous way. If the pointer is
passed as NULL then the structure will be allocated dynamically, just as * passed as NULL then the structure will be allocated dynamically, just as
when xSemaphoreCreateCounting() is called. */ * when xSemaphoreCreateCounting() is called. */
xSemaphore = xSemaphoreCreateCountingStatic( uxMaxCount, 0, &xSemaphoreBuffer ); xSemaphore = xSemaphoreCreateCountingStatic( uxMaxCount, 0, &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed /* The semaphore handle should equal the static semaphore structure passed
into the xSemaphoreCreateBinaryStatic() function. */ * into the xSemaphoreCreateBinaryStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer ); configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
@ -288,8 +289,8 @@ StaticSemaphore_t xSemaphoreBuffer;
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
/* Now do the same but using dynamically allocated buffers to ensure the /* Now do the same but using dynamically allocated buffers to ensure the
delete functions are working correctly in both the static and dynamic * delete functions are working correctly in both the static and dynamic
allocation cases. */ * allocation cases. */
xSemaphore = xSemaphoreCreateCounting( uxMaxCount, 0 ); xSemaphore = xSemaphoreCreateCounting( uxMaxCount, 0 );
configASSERT( xSemaphore != NULL ); configASSERT( xSemaphore != NULL );
prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount ); prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount );
@ -304,36 +305,36 @@ static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void )
SemaphoreHandle_t xSemaphore; SemaphoreHandle_t xSemaphore;
/* StaticSemaphore_t is a publicly accessible structure that has the same size /* StaticSemaphore_t is a publicly accessible structure that has the same size
and alignment requirements as the real semaphore structure. It is provided as a * and alignment requirements as the real semaphore structure. It is provided as a
mechanism for applications to know the size of the semaphore (which is dependent * mechanism for applications to know the size of the semaphore (which is dependent
on the architecture and configuration file settings) without breaking the strict * on the architecture and configuration file settings) without breaking the strict
data hiding policy by exposing the real semaphore internals. This * data hiding policy by exposing the real semaphore internals. This
StaticSemaphore_t variable is passed into the * StaticSemaphore_t variable is passed into the
xSemaphoreCreateRecursiveMutexStatic() function calls within this function. */ * xSemaphoreCreateRecursiveMutexStatic() function calls within this function. */
StaticSemaphore_t xSemaphoreBuffer; StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. xSemaphoreCreateRecursiveMutexStatic() has one /* Create the semaphore. xSemaphoreCreateRecursiveMutexStatic() has one
more parameter than the usual xSemaphoreCreateRecursiveMutex() function. * more parameter than the usual xSemaphoreCreateRecursiveMutex() function.
The parameter is a pointer to the pre-allocated StaticSemaphore_t structure, * The parameter is a pointer to the pre-allocated StaticSemaphore_t structure,
which will hold information on the semaphore in an anonymous way. If the * which will hold information on the semaphore in an anonymous way. If the
pointer is passed as NULL then the structure will be allocated dynamically, * pointer is passed as NULL then the structure will be allocated dynamically,
just as when xSemaphoreCreateRecursiveMutex() is called. */ * just as when xSemaphoreCreateRecursiveMutex() is called. */
xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xSemaphoreBuffer ); xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed /* The semaphore handle should equal the static semaphore structure passed
into the xSemaphoreCreateBinaryStatic() function. */ * into the xSemaphoreCreateBinaryStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer ); configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Ensure the semaphore passes a few sanity checks as a valid /* Ensure the semaphore passes a few sanity checks as a valid
recursive semaphore. */ * recursive semaphore. */
prvSanityCheckCreatedRecursiveMutex( xSemaphore ); prvSanityCheckCreatedRecursiveMutex( xSemaphore );
/* Delete the semaphore again so the buffers can be reused. */ /* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore ); vSemaphoreDelete( xSemaphore );
/* Now do the same using dynamically allocated buffers to ensure the delete /* Now do the same using dynamically allocated buffers to ensure the delete
functions are working correctly in both the static and dynamic memory * functions are working correctly in both the static and dynamic memory
allocation cases. */ * allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
xSemaphore = xSemaphoreCreateRecursiveMutex(); xSemaphore = xSemaphoreCreateRecursiveMutex();
@ -350,34 +351,34 @@ static void prvCreateAndDeleteStaticallyAllocatedQueues( void )
QueueHandle_t xQueue; QueueHandle_t xQueue;
/* StaticQueue_t is a publicly accessible structure that has the same size and /* StaticQueue_t is a publicly accessible structure that has the same size and
alignment requirements as the real queue structure. It is provided as a * alignment requirements as the real queue structure. It is provided as a
mechanism for applications to know the size of the queue (which is dependent on * mechanism for applications to know the size of the queue (which is dependent on
the architecture and configuration file settings) without breaking the strict * the architecture and configuration file settings) without breaking the strict
data hiding policy by exposing the real queue internals. This StaticQueue_t * data hiding policy by exposing the real queue internals. This StaticQueue_t
variable is passed into the xQueueCreateStatic() function calls within this * variable is passed into the xQueueCreateStatic() function calls within this
function. */ * function. */
static StaticQueue_t xStaticQueue; static StaticQueue_t xStaticQueue;
/* The queue storage area must be large enough to hold the maximum number of /* The queue storage area must be large enough to hold the maximum number of
items it is possible for the queue to hold at any one time, which equals the * items it is possible for the queue to hold at any one time, which equals the
queue length (in items, not bytes) multiplied by the size of each item. In this * queue length (in items, not bytes) multiplied by the size of each item. In this
case the queue will hold staticQUEUE_LENGTH_IN_ITEMS 64-bit items. See * case the queue will hold staticQUEUE_LENGTH_IN_ITEMS 64-bit items. See
http://www.freertos.org/Embedded-RTOS-Queues.html */ * http://www.freertos.org/Embedded-RTOS-Queues.html */
static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_t ) ]; static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_t ) ];
/* Create the queue. xQueueCreateStatic() has two more parameters than the /* Create the queue. xQueueCreateStatic() has two more parameters than the
usual xQueueCreate() function. The first new parameter is a pointer to the * usual xQueueCreate() function. The first new parameter is a pointer to the
pre-allocated queue storage area. The second new parameter is a pointer to * pre-allocated queue storage area. The second new parameter is a pointer to
the StaticQueue_t structure that will hold the queue state information in * the StaticQueue_t structure that will hold the queue state information in
an anonymous way. If the two pointers are passed as NULL then the data * an anonymous way. If the two pointers are passed as NULL then the data
will be allocated dynamically as if xQueueCreate() had been called. */ * will be allocated dynamically as if xQueueCreate() had been called. */
xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */ xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
sizeof( uint64_t ), /* The size of each item. */ sizeof( uint64_t ), /* The size of each item. */
ucQueueStorageArea, /* The buffer used to hold items within the queue. */ ucQueueStorageArea, /* The buffer used to hold items within the queue. */
&xStaticQueue ); /* The static queue structure that will hold the state of the queue. */ &xStaticQueue ); /* The static queue structure that will hold the state of the queue. */
/* The queue handle should equal the static queue structure passed into the /* The queue handle should equal the static queue structure passed into the
xQueueCreateStatic() function. */ * xQueueCreateStatic() function. */
configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue ); configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue );
/* Ensure the queue passes a few sanity checks as a valid queue. */ /* Ensure the queue passes a few sanity checks as a valid queue. */
@ -387,15 +388,15 @@ static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_
vQueueDelete( xQueue ); vQueueDelete( xQueue );
/* Now do the same using a dynamically allocated queue to ensure the delete /* Now do the same using a dynamically allocated queue to ensure the delete
function is working correctly in both the static and dynamic memory * function is working correctly in both the static and dynamic memory
allocation cases. */ * allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
xQueue = xQueueCreate( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */ xQueue = xQueueCreate( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
sizeof( uint64_t ) ); /* The size of each item. */ sizeof( uint64_t ) ); /* The size of each item. */
/* The queue handle should equal the static queue structure passed into the /* The queue handle should equal the static queue structure passed into the
xQueueCreateStatic() function. */ * xQueueCreateStatic() function. */
configASSERT( xQueue != NULL ); configASSERT( xQueue != NULL );
/* Ensure the queue passes a few sanity checks as a valid queue. */ /* Ensure the queue passes a few sanity checks as a valid queue. */
@ -404,7 +405,7 @@ static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_
/* Delete the queue again so the buffers can be reused. */ /* Delete the queue again so the buffers can be reused. */
vQueueDelete( xQueue ); vQueueDelete( xQueue );
} }
#endif #endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -414,28 +415,28 @@ SemaphoreHandle_t xSemaphore;
BaseType_t xReturned; BaseType_t xReturned;
/* StaticSemaphore_t is a publicly accessible structure that has the same size /* StaticSemaphore_t is a publicly accessible structure that has the same size
and alignment requirements as the real semaphore structure. It is provided as a * and alignment requirements as the real semaphore structure. It is provided as a
mechanism for applications to know the size of the semaphore (which is dependent * mechanism for applications to know the size of the semaphore (which is dependent
on the architecture and configuration file settings) without breaking the strict * on the architecture and configuration file settings) without breaking the strict
data hiding policy by exposing the real semaphore internals. This * data hiding policy by exposing the real semaphore internals. This
StaticSemaphore_t variable is passed into the xSemaphoreCreateMutexStatic() * StaticSemaphore_t variable is passed into the xSemaphoreCreateMutexStatic()
function calls within this function. */ * function calls within this function. */
StaticSemaphore_t xSemaphoreBuffer; StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. xSemaphoreCreateMutexStatic() has one more /* Create the semaphore. xSemaphoreCreateMutexStatic() has one more
parameter than the usual xSemaphoreCreateMutex() function. The parameter * parameter than the usual xSemaphoreCreateMutex() function. The parameter
is a pointer to the pre-allocated StaticSemaphore_t structure, which will * is a pointer to the pre-allocated StaticSemaphore_t structure, which will
hold information on the semaphore in an anonymous way. If the pointer is * hold information on the semaphore in an anonymous way. If the pointer is
passed as NULL then the structure will be allocated dynamically, just as * passed as NULL then the structure will be allocated dynamically, just as
when xSemaphoreCreateMutex() is called. */ * when xSemaphoreCreateMutex() is called. */
xSemaphore = xSemaphoreCreateMutexStatic( &xSemaphoreBuffer ); xSemaphore = xSemaphoreCreateMutexStatic( &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed /* The semaphore handle should equal the static semaphore structure passed
into the xSemaphoreCreateMutexStatic() function. */ * into the xSemaphoreCreateMutexStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer ); configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Take the mutex so the mutex is in the state expected by the /* Take the mutex so the mutex is in the state expected by the
prvSanityCheckCreatedSemaphore() function. */ * prvSanityCheckCreatedSemaphore() function. */
xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK ); xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
if( xReturned != pdPASS ) if( xReturned != pdPASS )
@ -450,18 +451,18 @@ StaticSemaphore_t xSemaphoreBuffer;
vSemaphoreDelete( xSemaphore ); vSemaphoreDelete( xSemaphore );
/* Now do the same using a dynamically allocated mutex to ensure the delete /* Now do the same using a dynamically allocated mutex to ensure the delete
function is working correctly in both the static and dynamic allocation * function is working correctly in both the static and dynamic allocation
cases. */ * cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
xSemaphore = xSemaphoreCreateMutex(); xSemaphore = xSemaphoreCreateMutex();
/* The semaphore handle should equal the static semaphore structure /* The semaphore handle should equal the static semaphore structure
passed into the xSemaphoreCreateMutexStatic() function. */ * passed into the xSemaphoreCreateMutexStatic() function. */
configASSERT( xSemaphore != NULL ); configASSERT( xSemaphore != NULL );
/* Take the mutex so the mutex is in the state expected by the /* Take the mutex so the mutex is in the state expected by the
prvSanityCheckCreatedSemaphore() function. */ * prvSanityCheckCreatedSemaphore() function. */
xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK ); xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
if( xReturned != pdPASS ) if( xReturned != pdPASS )
@ -475,7 +476,7 @@ StaticSemaphore_t xSemaphoreBuffer;
/* Delete the semaphore again so the buffers can be reused. */ /* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore ); vSemaphoreDelete( xSemaphore );
} }
#endif #endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -484,26 +485,26 @@ static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void )
SemaphoreHandle_t xSemaphore; SemaphoreHandle_t xSemaphore;
/* StaticSemaphore_t is a publicly accessible structure that has the same size /* StaticSemaphore_t is a publicly accessible structure that has the same size
and alignment requirements as the real semaphore structure. It is provided as a * and alignment requirements as the real semaphore structure. It is provided as a
mechanism for applications to know the size of the semaphore (which is dependent * mechanism for applications to know the size of the semaphore (which is dependent
on the architecture and configuration file settings) without breaking the strict * on the architecture and configuration file settings) without breaking the strict
data hiding policy by exposing the real semaphore internals. This * data hiding policy by exposing the real semaphore internals. This
StaticSemaphore_t variable is passed into the xSemaphoreCreateBinaryStatic() * StaticSemaphore_t variable is passed into the xSemaphoreCreateBinaryStatic()
function calls within this function. NOTE: In most usage scenarios now it is * function calls within this function. NOTE: In most usage scenarios now it is
faster and more memory efficient to use a direct to task notification instead of * faster and more memory efficient to use a direct to task notification instead of
a binary semaphore. http://www.freertos.org/RTOS-task-notifications.html */ * a binary semaphore. http://www.freertos.org/RTOS-task-notifications.html */
StaticSemaphore_t xSemaphoreBuffer; StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. xSemaphoreCreateBinaryStatic() has one more /* Create the semaphore. xSemaphoreCreateBinaryStatic() has one more
parameter than the usual xSemaphoreCreateBinary() function. The parameter * parameter than the usual xSemaphoreCreateBinary() function. The parameter
is a pointer to the pre-allocated StaticSemaphore_t structure, which will * is a pointer to the pre-allocated StaticSemaphore_t structure, which will
hold information on the semaphore in an anonymous way. If the pointer is * hold information on the semaphore in an anonymous way. If the pointer is
passed as NULL then the structure will be allocated dynamically, just as * passed as NULL then the structure will be allocated dynamically, just as
when xSemaphoreCreateBinary() is called. */ * when xSemaphoreCreateBinary() is called. */
xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer ); xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed /* The semaphore handle should equal the static semaphore structure passed
into the xSemaphoreCreateBinaryStatic() function. */ * into the xSemaphoreCreateBinaryStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer ); configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Ensure the semaphore passes a few sanity checks as a valid semaphore. */ /* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
@ -513,8 +514,8 @@ StaticSemaphore_t xSemaphoreBuffer;
vSemaphoreDelete( xSemaphore ); vSemaphoreDelete( xSemaphore );
/* Now do the same using a dynamically allocated semaphore to check the /* Now do the same using a dynamically allocated semaphore to check the
delete function is working correctly in both the static and dynamic * delete function is working correctly in both the static and dynamic
allocation cases. */ * allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
xSemaphore = xSemaphoreCreateBinary(); xSemaphore = xSemaphoreCreateBinary();
@ -525,14 +526,14 @@ StaticSemaphore_t xSemaphoreBuffer;
#endif #endif
/* There isn't a static version of the old and deprecated /* There isn't a static version of the old and deprecated
vSemaphoreCreateBinary() macro (because its deprecated!), but check it is * vSemaphoreCreateBinary() macro (because its deprecated!), but check it is
still functioning correctly. */ * still functioning correctly. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
vSemaphoreCreateBinary( xSemaphore ); vSemaphoreCreateBinary( xSemaphore );
/* The macro starts with the binary semaphore available, but the test /* The macro starts with the binary semaphore available, but the test
function expects it to be unavailable. */ * function expects it to be unavailable. */
if( xSemaphoreTake( xSemaphore, staticDONT_BLOCK ) == pdFAIL ) if( xSemaphoreTake( xSemaphore, staticDONT_BLOCK ) == pdFAIL )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -541,7 +542,7 @@ StaticSemaphore_t xSemaphoreBuffer;
prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT ); prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
vSemaphoreDelete( xSemaphore ); vSemaphoreDelete( xSemaphore );
} }
#endif #endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -551,19 +552,19 @@ UBaseType_t *puxVariableToIncrement;
BaseType_t xReturned; BaseType_t xReturned;
/* The timer callback just demonstrates it is executing by incrementing a /* The timer callback just demonstrates it is executing by incrementing a
variable - the address of which is passed into the timer as its ID. Obtain * variable - the address of which is passed into the timer as its ID. Obtain
the address of the variable to increment. */ * the address of the variable to increment. */
puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer ); puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer );
/* Increment the variable to show the timer callback has executed. */ /* Increment the variable to show the timer callback has executed. */
( *puxVariableToIncrement )++; ( *puxVariableToIncrement )++;
/* If this callback has executed the required number of times, stop the /* If this callback has executed the required number of times, stop the
timer. */ * timer. */
if( *puxVariableToIncrement == staticMAX_TIMER_CALLBACK_EXECUTIONS ) if( *puxVariableToIncrement == staticMAX_TIMER_CALLBACK_EXECUTIONS )
{ {
/* This is called from a timer callback so must not block. See /* This is called from a timer callback so must not block. See
http://www.FreeRTOS.org/FreeRTOS-timers-xTimerStop.html */ * http://www.FreeRTOS.org/FreeRTOS-timers-xTimerStop.html */
xReturned = xTimerStop( xExpiredTimer, staticDONT_BLOCK ); xReturned = xTimerStop( xExpiredTimer, staticDONT_BLOCK );
if( xReturned != pdPASS ) if( xReturned != pdPASS )
@ -582,19 +583,19 @@ const TickType_t xTimerPeriod = pdMS_TO_TICKS( 20 );
BaseType_t xReturned; BaseType_t xReturned;
/* StaticTimer_t is a publicly accessible structure that has the same size /* StaticTimer_t is a publicly accessible structure that has the same size
and alignment requirements as the real timer structure. It is provided as a * and alignment requirements as the real timer structure. It is provided as a
mechanism for applications to know the size of the timer structure (which is * mechanism for applications to know the size of the timer structure (which is
dependent on the architecture and configuration file settings) without breaking * dependent on the architecture and configuration file settings) without breaking
the strict data hiding policy by exposing the real timer internals. This * the strict data hiding policy by exposing the real timer internals. This
StaticTimer_t variable is passed into the xTimerCreateStatic() function calls * StaticTimer_t variable is passed into the xTimerCreateStatic() function calls
within this function. */ * within this function. */
StaticTimer_t xTimerBuffer; StaticTimer_t xTimerBuffer;
/* Create the software time. xTimerCreateStatic() has an extra parameter /* Create the software time. xTimerCreateStatic() has an extra parameter
than the normal xTimerCreate() API function. The parameter is a pointer to * than the normal xTimerCreate() API function. The parameter is a pointer to
the StaticTimer_t structure that will hold the software timer structure. If * the StaticTimer_t structure that will hold the software timer structure. If
the parameter is passed as NULL then the structure will be allocated * the parameter is passed as NULL then the structure will be allocated
dynamically, just as if xTimerCreate() had been called. */ * dynamically, just as if xTimerCreate() had been called. */
xTimer = xTimerCreateStatic( "T1", /* Text name for the task. Helps debugging only. Not used by FreeRTOS. */ xTimer = xTimerCreateStatic( "T1", /* Text name for the task. Helps debugging only. Not used by FreeRTOS. */
xTimerPeriod, /* The period of the timer in ticks. */ xTimerPeriod, /* The period of the timer in ticks. */
pdTRUE, /* This is an auto-reload timer. */ pdTRUE, /* This is an auto-reload timer. */
@ -603,11 +604,11 @@ StaticTimer_t xTimerBuffer;
&xTimerBuffer ); /* The buffer that will hold the software timer structure. */ &xTimerBuffer ); /* The buffer that will hold the software timer structure. */
/* The timer handle should equal the static timer structure passed into the /* The timer handle should equal the static timer structure passed into the
xTimerCreateStatic() function. */ * xTimerCreateStatic() function. */
configASSERT( xTimer == ( TimerHandle_t ) &xTimerBuffer ); configASSERT( xTimer == ( TimerHandle_t ) &xTimerBuffer );
/* Set the variable to 0, wait for a few timer periods to expire, then check /* Set the variable to 0, wait for a few timer periods to expire, then check
the timer callback has incremented the variable to the expected value. */ * the timer callback has incremented the variable to the expected value. */
uxVariableToIncrement = 0; uxVariableToIncrement = 0;
/* This is a low priority so a block time should not be needed. */ /* This is a low priority so a block time should not be needed. */
@ -621,7 +622,7 @@ StaticTimer_t xTimerBuffer;
vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS ); vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS );
/* By now the timer should have expired staticMAX_TIMER_CALLBACK_EXECUTIONS /* By now the timer should have expired staticMAX_TIMER_CALLBACK_EXECUTIONS
times, and then stopped itself. */ * times, and then stopped itself. */
if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS ) if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -631,7 +632,7 @@ StaticTimer_t xTimerBuffer;
xReturned = xTimerDelete( xTimer, staticDONT_BLOCK ); xReturned = xTimerDelete( xTimer, staticDONT_BLOCK );
/* Again, as this is a low priority task it is expected that the timer /* Again, as this is a low priority task it is expected that the timer
command will have been sent even without a block time being used. */ * command will have been sent even without a block time being used. */
if( xReturned != pdPASS ) if( xReturned != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -641,8 +642,8 @@ StaticTimer_t xTimerBuffer;
uxCycleCounter++; uxCycleCounter++;
/* Now do the same using a dynamically allocated software timer to ensure /* Now do the same using a dynamically allocated software timer to ensure
the delete function is working correctly in both the static and dynamic * the delete function is working correctly in both the static and dynamic
allocation cases. */ * allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
xTimer = xTimerCreate( "T1", /* Text name for the task. Helps debugging only. Not used by FreeRTOS. */ xTimer = xTimerCreate( "T1", /* Text name for the task. Helps debugging only. Not used by FreeRTOS. */
@ -675,7 +676,7 @@ StaticTimer_t xTimerBuffer;
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
} }
#endif #endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -684,34 +685,34 @@ static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void )
EventGroupHandle_t xEventGroup; EventGroupHandle_t xEventGroup;
/* StaticEventGroup_t is a publicly accessible structure that has the same size /* StaticEventGroup_t is a publicly accessible structure that has the same size
and alignment requirements as the real event group structure. It is provided as * and alignment requirements as the real event group structure. It is provided as
a mechanism for applications to know the size of the event group (which is * a mechanism for applications to know the size of the event group (which is
dependent on the architecture and configuration file settings) without breaking * dependent on the architecture and configuration file settings) without breaking
the strict data hiding policy by exposing the real event group internals. This * the strict data hiding policy by exposing the real event group internals. This
StaticEventGroup_t variable is passed into the xSemaphoreCreateEventGroupStatic() * StaticEventGroup_t variable is passed into the xSemaphoreCreateEventGroupStatic()
function calls within this function. */ * function calls within this function. */
StaticEventGroup_t xEventGroupBuffer; StaticEventGroup_t xEventGroupBuffer;
/* Create the event group. xEventGroupCreateStatic() has an extra parameter /* Create the event group. xEventGroupCreateStatic() has an extra parameter
than the normal xEventGroupCreate() API function. The parameter is a * than the normal xEventGroupCreate() API function. The parameter is a
pointer to the StaticEventGroup_t structure that will hold the event group * pointer to the StaticEventGroup_t structure that will hold the event group
structure. */ * structure. */
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer ); xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
/* The event group handle should equal the static event group structure /* The event group handle should equal the static event group structure
passed into the xEventGroupCreateStatic() function. */ * passed into the xEventGroupCreateStatic() function. */
configASSERT( xEventGroup == ( EventGroupHandle_t ) &xEventGroupBuffer ); configASSERT( xEventGroup == ( EventGroupHandle_t ) &xEventGroupBuffer );
/* Ensure the event group passes a few sanity checks as a valid event /* Ensure the event group passes a few sanity checks as a valid event
group. */ * group. */
prvSanityCheckCreatedEventGroup( xEventGroup ); prvSanityCheckCreatedEventGroup( xEventGroup );
/* Delete the event group again so the buffers can be reused. */ /* Delete the event group again so the buffers can be reused. */
vEventGroupDelete( xEventGroup ); vEventGroupDelete( xEventGroup );
/* Now do the same using a dynamically allocated event group to ensure the /* Now do the same using a dynamically allocated event group to ensure the
delete function is working correctly in both the static and dynamic * delete function is working correctly in both the static and dynamic
allocation cases. */ * allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
xEventGroup = xEventGroupCreate(); xEventGroup = xEventGroupCreate();
@ -728,23 +729,23 @@ static void prvCreateAndDeleteStaticallyAllocatedTasks( void )
TaskHandle_t xCreatedTask; TaskHandle_t xCreatedTask;
/* The variable that will hold the TCB of tasks created by this function. See /* The variable that will hold the TCB of tasks created by this function. See
the comments above the declaration of the xCreatorTaskTCBBuffer variable for * the comments above the declaration of the xCreatorTaskTCBBuffer variable for
more information. NOTE: This is not static so relies on the tasks that use it * more information. NOTE: This is not static so relies on the tasks that use it
being deleted before this function returns and deallocates its stack. That will * being deleted before this function returns and deallocates its stack. That will
only be the case if configUSE_PREEMPTION is set to 1. */ * only be the case if configUSE_PREEMPTION is set to 1. */
StaticTask_t xTCBBuffer; StaticTask_t xTCBBuffer;
/* This buffer that will be used as the stack of tasks created by this function. /* This buffer that will be used as the stack of tasks created by this function.
See the comments above the declaration of the uxCreatorTaskStackBuffer[] array * See the comments above the declaration of the uxCreatorTaskStackBuffer[] array
above for more information. */ * above for more information. */
static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ]; static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
/* Create the task. xTaskCreateStatic() has two more parameters than /* Create the task. xTaskCreateStatic() has two more parameters than
the usual xTaskCreate() function. The first new parameter is a pointer to * the usual xTaskCreate() function. The first new parameter is a pointer to
the pre-allocated stack. The second new parameter is a pointer to the * the pre-allocated stack. The second new parameter is a pointer to the
StaticTask_t structure that will hold the task's TCB. If both pointers are * StaticTask_t structure that will hold the task's TCB. If both pointers are
passed as NULL then the respective object will be allocated dynamically as * passed as NULL then the respective object will be allocated dynamically as
if xTaskCreate() had been called. */ * if xTaskCreate() had been called. */
xCreatedTask = xTaskCreateStatic( xCreatedTask = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */ prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */ "Static", /* Human readable name for the task. */
@ -762,7 +763,7 @@ static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
else if( eTaskGetState( xCreatedTask ) != eSuspended ) else if( eTaskGetState( xCreatedTask ) != eSuspended )
{ {
/* The created task had a higher priority so should have executed and /* The created task had a higher priority so should have executed and
suspended itself by now. */ * suspended itself by now. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
else else
@ -771,8 +772,8 @@ static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
} }
/* Now do the same using a dynamically allocated task to ensure the delete /* Now do the same using a dynamically allocated task to ensure the delete
function is working correctly in both the static and dynamic allocation * function is working correctly in both the static and dynamic allocation
cases. */ * cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{ {
BaseType_t xReturned; BaseType_t xReturned;
@ -791,13 +792,15 @@ static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
} }
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
if( xReturned != pdPASS ) if( xReturned != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
vTaskDelete( xCreatedTask ); vTaskDelete( xCreatedTask );
} }
#endif #endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -806,8 +809,8 @@ static void prvStaticallyAllocatedTask( void *pvParameters )
( void ) pvParameters; ( void ) pvParameters;
/* The created task just suspends itself to wait to get deleted. The task /* The created task just suspends itself to wait to get deleted. The task
that creates this task checks this task is in the expected Suspended state * that creates this task checks this task is in the expected Suspended state
before deleting it. */ * before deleting it. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -830,15 +833,14 @@ const TickType_t xMinDelay = pdMS_TO_TICKS( ( TickType_t ) 75 );
const TickType_t xTinyDelay = pdMS_TO_TICKS( ( TickType_t ) 2 ); const TickType_t xTinyDelay = pdMS_TO_TICKS( ( TickType_t ) 2 );
/* Generate the next delay time. This is kept within a narrow band so as /* Generate the next delay time. This is kept within a narrow band so as
not to disturb the timing of other tests - but does add in some pseudo * not to disturb the timing of other tests - but does add in some pseudo
randomisation into the tests. */ * randomisation into the tests. */
do do
{ {
xNextDelay = prvRand() % xMaxDelay; xNextDelay = prvRand() % xMaxDelay;
/* Just in case this loop is executed lots of times. */ /* Just in case this loop is executed lots of times. */
vTaskDelay( xTinyDelay ); vTaskDelay( xTinyDelay );
} while( xNextDelay < xMinDelay ); } while( xNextDelay < xMinDelay );
return xNextDelay; return xNextDelay;
@ -878,7 +880,7 @@ const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( Eve
} }
/* Finally try clearing some bits too and check that operation proceeds as /* Finally try clearing some bits too and check that operation proceeds as
expected. */ * expected. */
xEventGroupClearBits( xEventGroup, xFirstTestBits ); xEventGroupClearBits( xEventGroup, xFirstTestBits );
xEventBits = xEventGroupGetBits( xEventGroup ); xEventBits = xEventGroupGetBits( xEventGroup );
@ -890,7 +892,8 @@ const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( Eve
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore, UBaseType_t uxMaxCount ) static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore,
UBaseType_t uxMaxCount )
{ {
BaseType_t xReturned; BaseType_t xReturned;
UBaseType_t x; UBaseType_t x;
@ -898,7 +901,7 @@ const TickType_t xShortBlockTime = pdMS_TO_TICKS( 10 );
TickType_t xTickCount; TickType_t xTickCount;
/* The binary semaphore should start 'empty', so a call to xSemaphoreTake() /* The binary semaphore should start 'empty', so a call to xSemaphoreTake()
should fail. */ * should fail. */
xTickCount = xTaskGetTickCount(); xTickCount = xTaskGetTickCount();
xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime ); xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
@ -914,7 +917,7 @@ TickType_t xTickCount;
} }
/* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount /* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount
times. */ * times. */
for( x = 0; x < uxMaxCount; x++ ) for( x = 0; x < uxMaxCount; x++ )
{ {
xReturned = xSemaphoreGive( xSemaphore ); xReturned = xSemaphoreGive( xSemaphore );
@ -936,7 +939,7 @@ TickType_t xTickCount;
configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount ); configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount );
/* Should now be possible to 'take' the semaphore up to a maximum of /* Should now be possible to 'take' the semaphore up to a maximum of
uxMaxCount times without blocking. */ * uxMaxCount times without blocking. */
for( x = 0; x < uxMaxCount; x++ ) for( x = 0; x < uxMaxCount; x++ )
{ {
xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK ); xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
@ -948,7 +951,7 @@ TickType_t xTickCount;
} }
/* Back to the starting condition, where the semaphore should not be /* Back to the starting condition, where the semaphore should not be
available. */ * available. */
xTickCount = xTaskGetTickCount(); xTickCount = xTaskGetTickCount();
xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime ); xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
@ -976,18 +979,20 @@ BaseType_t xReturned, xLoop;
for( xLoop = 0; xLoop < 2; xLoop++ ) for( xLoop = 0; xLoop < 2; xLoop++ )
{ {
/* A very basic test that the queue can be written to and read from as /* A very basic test that the queue can be written to and read from as
expected. First the queue should be empty. */ * expected. First the queue should be empty. */
xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK ); xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_EMPTY ) if( xReturned != errQUEUE_EMPTY )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS /* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS
times. */ * times. */
for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ ) for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
{ {
xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK ); xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != pdPASS ) if( xReturned != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -996,13 +1001,14 @@ BaseType_t xReturned, xLoop;
/* Should not now be possible to write to the queue again. */ /* Should not now be possible to write to the queue again. */
xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK ); xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_FULL ) if( xReturned != errQUEUE_FULL )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Now read back from the queue to ensure the data read back matches that /* Now read back from the queue to ensure the data read back matches that
written. */ * written. */
for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ ) for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
{ {
xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK ); xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK );
@ -1020,6 +1026,7 @@ BaseType_t xReturned, xLoop;
/* The queue should be empty again. */ /* The queue should be empty again. */
xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK ); xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_EMPTY ) if( xReturned != errQUEUE_EMPTY )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -1034,8 +1041,8 @@ const BaseType_t xLoops = 5;
BaseType_t x, xReturned; BaseType_t x, xReturned;
/* A very basic test that the recursive semaphore behaved like a recursive /* A very basic test that the recursive semaphore behaved like a recursive
semaphore. First the semaphore should not be able to be given, as it has not * semaphore. First the semaphore should not be able to be given, as it has not
yet been taken. */ * yet been taken. */
xReturned = xSemaphoreGiveRecursive( xSemaphore ); xReturned = xSemaphoreGiveRecursive( xSemaphore );
if( xReturned != pdFAIL ) if( xReturned != pdFAIL )
@ -1055,7 +1062,7 @@ BaseType_t x, xReturned;
} }
/* Should be possible to give the semaphore the same number of times as it /* Should be possible to give the semaphore the same number of times as it
was given in the loop above. */ * was given in the loop above. */
for( x = 0; x < xLoops; x++ ) for( x = 0; x < xLoops; x++ )
{ {
xReturned = xSemaphoreGiveRecursive( xSemaphore ); xReturned = xSemaphoreGiveRecursive( xSemaphore );

View file

@ -51,7 +51,7 @@
#define sbNUMBER_OF_SENDER_TASKS ( 2 ) #define sbNUMBER_OF_SENDER_TASKS ( 2 )
/* Priority of the test tasks. The send and receive go from low to high /* Priority of the test tasks. The send and receive go from low to high
priority tasks, and from high to low priority tasks. */ * priority tasks, and from high to low priority tasks. */
#define sbLOWER_PRIORITY ( tskIDLE_PRIORITY ) #define sbLOWER_PRIORITY ( tskIDLE_PRIORITY )
#define sbHIGHER_PRIORITY ( tskIDLE_PRIORITY + 1 ) #define sbHIGHER_PRIORITY ( tskIDLE_PRIORITY + 1 )
@ -62,12 +62,12 @@ priority tasks, and from high to low priority tasks. */
#define sbDONT_BLOCK ( 0 ) #define sbDONT_BLOCK ( 0 )
/* The trigger level sets the number of bytes that must be present in the /* The trigger level sets the number of bytes that must be present in the
stream buffer before a task that is blocked on the stream buffer is moved out of * stream buffer before a task that is blocked on the stream buffer is moved out of
the Blocked state so it can read the bytes. */ * the Blocked state so it can read the bytes. */
#define sbTRIGGER_LEVEL_1 ( 1 ) #define sbTRIGGER_LEVEL_1 ( 1 )
/* The size of the stack allocated to the tasks that run as part of this demo/ /* The size of the stack allocated to the tasks that run as part of this demo/
test. The stack size is over generous in most cases. */ * test. The stack size is over generous in most cases. */
#ifndef configSTREAM_BUFFER_SENDER_TASK_STACK_SIZE #ifndef configSTREAM_BUFFER_SENDER_TASK_STACK_SIZE
#define sbSTACK_SIZE ( configMINIMAL_STACK_SIZE + ( configMINIMAL_STACK_SIZE >> 1 ) ) #define sbSTACK_SIZE ( configMINIMAL_STACK_SIZE + ( configMINIMAL_STACK_SIZE >> 1 ) )
#else #else
@ -105,7 +105,7 @@ static void prvNonBlockingReceiverTask( void *pvParameters );
static void prvNonBlockingSenderTask( void * pvParameters ); static void prvNonBlockingSenderTask( void * pvParameters );
/* Performs an assert() like check in a way that won't get removed when /* Performs an assert() like check in a way that won't get removed when
performing a code coverage analysis. */ * performing a code coverage analysis. */
static void prvCheckExpectedState( BaseType_t xState ); static void prvCheckExpectedState( BaseType_t xState );
/* /*
@ -116,9 +116,10 @@ static void prvCheckExpectedState( BaseType_t xState );
static void prvInterruptTriggerLevelTest( void * pvParameters ); static void prvInterruptTriggerLevelTest( void * pvParameters );
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
/* This file tests both statically and dynamically allocated stream buffers. /* This file tests both statically and dynamically allocated stream buffers.
Allocate the structures and buffers to be used by the statically allocated * Allocate the structures and buffers to be used by the statically allocated
objects, which get used in the echo tests. */ * objects, which get used in the echo tests. */
static void prvReceiverTask( void * pvParameters ); static void prvReceiverTask( void * pvParameters );
static void prvSenderTask( void * pvParameters ); static void prvSenderTask( void * pvParameters );
@ -127,10 +128,10 @@ static void prvInterruptTriggerLevelTest( void *pvParameters );
#endif /* configSUPPORT_STATIC_ALLOCATION */ #endif /* configSUPPORT_STATIC_ALLOCATION */
/* The +1 is to make the test logic easier as the function that calculates the /* The +1 is to make the test logic easier as the function that calculates the
free space will return one less than the actual free space - adding a 1 to the * free space will return one less than the actual free space - adding a 1 to the
actual length makes it appear to the tests as if the free space is returned as * actual length makes it appear to the tests as if the free space is returned as
it might logically be expected. Returning 1 less than the actual free space is * it might logically be expected. Returning 1 less than the actual free space is
fine as it can never result in an overrun. */ * fine as it can never result in an overrun. */
static uint8_t ucBufferStorage[ sbNUMBER_OF_SENDER_TASKS ][ sbSTREAM_BUFFER_LENGTH_BYTES + 1 ]; static uint8_t ucBufferStorage[ sbNUMBER_OF_SENDER_TASKS ][ sbSTREAM_BUFFER_LENGTH_BYTES + 1 ];
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -145,36 +146,36 @@ typedef struct ECHO_STREAM_BUFFERS
static volatile uint32_t ulEchoLoopCounters[ sbNUMBER_OF_ECHO_CLIENTS ] = { 0 }; static volatile uint32_t ulEchoLoopCounters[ sbNUMBER_OF_ECHO_CLIENTS ] = { 0 };
/* The non-blocking tasks monitor their operation, and if no errors have been /* The non-blocking tasks monitor their operation, and if no errors have been
found, increment ulNonBlockingRxCounter. xAreStreamBufferTasksStillRunning() * found, increment ulNonBlockingRxCounter. xAreStreamBufferTasksStillRunning()
then checks ulNonBlockingRxCounter and only returns pdPASS if * then checks ulNonBlockingRxCounter and only returns pdPASS if
ulNonBlockingRxCounter is still incrementing. */ * ulNonBlockingRxCounter is still incrementing. */
static volatile uint32_t ulNonBlockingRxCounter = 0; static volatile uint32_t ulNonBlockingRxCounter = 0;
/* The task that receives characters from the tick interrupt in order to test /* The task that receives characters from the tick interrupt in order to test
different trigger levels monitors its own behaviour. If it has not detected any * different trigger levels monitors its own behaviour. If it has not detected any
error then it increments ulInterruptTriggerCounter to indicate to the check task * error then it increments ulInterruptTriggerCounter to indicate to the check task
that it is still operating correctly. */ * that it is still operating correctly. */
static volatile uint32_t ulInterruptTriggerCounter = 0UL; static volatile uint32_t ulInterruptTriggerCounter = 0UL;
/* The stream buffer used from the tick interrupt. This sends one byte at a time /* The stream buffer used from the tick interrupt. This sends one byte at a time
to a test task to test the trigger level operation. The variable is set to NULL * to a test task to test the trigger level operation. The variable is set to NULL
in between test runs. */ * in between test runs. */
static volatile StreamBufferHandle_t xInterruptStreamBuffer = NULL; static volatile StreamBufferHandle_t xInterruptStreamBuffer = NULL;
/* The data sent from the tick interrupt to the task that tests the trigger /* The data sent from the tick interrupt to the task that tests the trigger
level functionality. */ * level functionality. */
static const char * pcDataSentFromInterrupt = "0123456789"; static const char * pcDataSentFromInterrupt = "0123456789";
/* Data that is longer than the buffer that is sent to the buffers as a stream /* Data that is longer than the buffer that is sent to the buffers as a stream
of bytes. Parts of which are written to the stream buffer to test writing * of bytes. Parts of which are written to the stream buffer to test writing
different lengths at different offsets, to many bytes, part streams, streams * different lengths at different offsets, to many bytes, part streams, streams
that wrap, etc.. Two messages are defined to ensure left over data is not * that wrap, etc.. Two messages are defined to ensure left over data is not
accidentally read out of the buffer. */ * accidentally read out of the buffer. */
static const char * pc55ByteString = "One two three four five six seven eight nine ten eleven"; static const char * pc55ByteString = "One two three four five six seven eight nine ten eleven";
static const char * pc54ByteString = "01234567891abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ"; static const char * pc54ByteString = "01234567891abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQ";
/* Used to log the status of the tests contained within this file for reporting /* Used to log the status of the tests contained within this file for reporting
to a monitoring task ('check' task). */ * to a monitoring task ('check' task). */
static BaseType_t xErrorStatus = pdPASS; static BaseType_t xErrorStatus = pdPASS;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -184,29 +185,29 @@ void vStartStreamBufferTasks( void )
StreamBufferHandle_t xStreamBuffer; StreamBufferHandle_t xStreamBuffer;
/* The echo servers sets up the stream buffers before creating the echo /* The echo servers sets up the stream buffers before creating the echo
client tasks. One set of tasks has the server as the higher priority, and * client tasks. One set of tasks has the server as the higher priority, and
the other has the client as the higher priority. */ * the other has the client as the higher priority. */
xTaskCreate( prvEchoServer, "1StrEchoServer", sbSMALLER_STACK_SIZE, NULL, sbHIGHER_PRIORITY, NULL ); xTaskCreate( prvEchoServer, "1StrEchoServer", sbSMALLER_STACK_SIZE, NULL, sbHIGHER_PRIORITY, NULL );
xTaskCreate( prvEchoServer, "2StrEchoServer", sbSMALLER_STACK_SIZE, NULL, sbLOWER_PRIORITY, NULL ); xTaskCreate( prvEchoServer, "2StrEchoServer", sbSMALLER_STACK_SIZE, NULL, sbLOWER_PRIORITY, NULL );
/* The non blocking tasks run continuously and will interleave with each /* The non blocking tasks run continuously and will interleave with each
other, so must be created at the lowest priority. The stream buffer they * other, so must be created at the lowest priority. The stream buffer they
use is created and passed in using the task's parameter. */ * use is created and passed in using the task's parameter. */
xStreamBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 ); xStreamBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );
xTaskCreate( prvNonBlockingReceiverTask, "StrNonBlkRx", configMINIMAL_STACK_SIZE, ( void * ) xStreamBuffer, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvNonBlockingReceiverTask, "StrNonBlkRx", configMINIMAL_STACK_SIZE, ( void * ) xStreamBuffer, tskIDLE_PRIORITY, NULL );
xTaskCreate( prvNonBlockingSenderTask, "StrNonBlkTx", configMINIMAL_STACK_SIZE, ( void * ) xStreamBuffer, tskIDLE_PRIORITY, NULL ); xTaskCreate( prvNonBlockingSenderTask, "StrNonBlkTx", configMINIMAL_STACK_SIZE, ( void * ) xStreamBuffer, tskIDLE_PRIORITY, NULL );
/* The task that receives bytes from an interrupt to test that it unblocks /* The task that receives bytes from an interrupt to test that it unblocks
at a specific trigger level must run at a high priority to minimise the risk * at a specific trigger level must run at a high priority to minimise the risk
of it receiving more characters before it can execute again after being * of it receiving more characters before it can execute again after being
unblocked. */ * unblocked. */
xTaskCreate( prvInterruptTriggerLevelTest, "StrTrig", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL ); xTaskCreate( prvInterruptTriggerLevelTest, "StrTrig", configMINIMAL_STACK_SIZE, NULL, configMAX_PRIORITIES - 1, NULL );
#if ( configSUPPORT_STATIC_ALLOCATION == 1 ) #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
{ {
/* The sender tasks set up the stream buffers before creating the /* The sender tasks set up the stream buffers before creating the
receiver tasks. Priorities must be 0 and 1 as the priority is used to * receiver tasks. Priorities must be 0 and 1 as the priority is used to
index into the xStaticStreamBuffers and ucBufferStorage arrays. */ * index into the xStaticStreamBuffers and ucBufferStorage arrays. */
xTaskCreate( prvSenderTask, "Str1Sender", sbSMALLER_STACK_SIZE, NULL, sbHIGHER_PRIORITY, NULL ); xTaskCreate( prvSenderTask, "Str1Sender", sbSMALLER_STACK_SIZE, NULL, sbHIGHER_PRIORITY, NULL );
xTaskCreate( prvSenderTask, "Str2Sender", sbSMALLER_STACK_SIZE, NULL, sbLOWER_PRIORITY, NULL ); xTaskCreate( prvSenderTask, "Str2Sender", sbSMALLER_STACK_SIZE, NULL, sbLOWER_PRIORITY, NULL );
} }
@ -217,6 +218,7 @@ StreamBufferHandle_t xStreamBuffer;
static void prvCheckExpectedState( BaseType_t xState ) static void prvCheckExpectedState( BaseType_t xState )
{ {
configASSERT( xState ); configASSERT( xState );
if( xState == pdFAIL ) if( xState == pdFAIL )
{ {
xErrorStatus = pdFAIL; xErrorStatus = pdFAIL;
@ -239,8 +241,8 @@ UBaseType_t uxOriginalPriority;
( void ) xAllowableMargin; ( void ) xAllowableMargin;
/* To minimise stack and heap usage a full size buffer is allocated from the /* To minimise stack and heap usage a full size buffer is allocated from the
heap, then buffers which hold smaller amounts of data are overlayed with the * heap, then buffers which hold smaller amounts of data are overlayed with the
larger buffer - just make sure not to use both at once! */ * larger buffer - just make sure not to use both at once! */
pucFullBuffer = pvPortMalloc( xFullBufferSize ); pucFullBuffer = pvPortMalloc( xFullBufferSize );
configASSERT( pucFullBuffer ); configASSERT( pucFullBuffer );
@ -248,7 +250,7 @@ UBaseType_t uxOriginalPriority;
pucReadData = pucData + x17ByteLength; pucReadData = pucData + x17ByteLength;
/* Nothing has been added or removed yet, so expect the free space to be /* Nothing has been added or removed yet, so expect the free space to be
exactly as created. Head and tail are both at 0. */ * exactly as created. Head and tail are both at 0. */
xExpectedSpaces = sbSTREAM_BUFFER_LENGTH_BYTES; xExpectedSpaces = sbSTREAM_BUFFER_LENGTH_BYTES;
xExpectedBytes = 0; xExpectedBytes = 0;
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer ); xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
@ -259,7 +261,7 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );
/* Add a single item - number of bytes available should go up by one and spaces /* Add a single item - number of bytes available should go up by one and spaces
available down by one. Head is in front of tail. */ * available down by one. Head is in front of tail. */
xExpectedSpaces--; xExpectedSpaces--;
xExpectedBytes++; xExpectedBytes++;
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 ); xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 );
@ -288,7 +290,7 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xReturned == ( size_t ) 0 ); prvCheckExpectedState( xReturned == ( size_t ) 0 );
/* Remove a byte so the tail pointer moves off 0. Head pointer remains at the /* Remove a byte so the tail pointer moves off 0. Head pointer remains at the
end of the buffer. */ * end of the buffer. */
xExpectedSpaces += 1; xExpectedSpaces += 1;
xExpectedBytes -= 1; xExpectedBytes -= 1;
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 ); xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 );
@ -313,7 +315,7 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );
/* Now the head pointer is behind the tail pointer. Read another 29 bytes so /* Now the head pointer is behind the tail pointer. Read another 29 bytes so
the tail pointer moves to the end of the buffer. */ * the tail pointer moves to the end of the buffer. */
xExpectedSpaces += 29; xExpectedSpaces += 29;
xExpectedBytes -= 29; xExpectedBytes -= 29;
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, ( size_t ) 29, ( TickType_t ) 0 ); xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, ( size_t ) 29, ( TickType_t ) 0 );
@ -326,7 +328,7 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );
/* Read out one more byte to wrap the tail back around to the start, to get back /* Read out one more byte to wrap the tail back around to the start, to get back
to where we started. */ * to where we started. */
xExpectedSpaces += 1; xExpectedSpaces += 1;
xExpectedBytes -= 1; xExpectedBytes -= 1;
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 ); xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, sizeof( *pucData ), ( TickType_t ) 0 );
@ -339,7 +341,7 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );
/* Try filling the message buffer in one write, blocking indefinitely. Expect to /* Try filling the message buffer in one write, blocking indefinitely. Expect to
have written one byte less. */ * have written one byte less. */
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, xTrueSize, portMAX_DELAY ); xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, xTrueSize, portMAX_DELAY );
xExpectedSpaces = ( size_t ) 0; xExpectedSpaces = ( size_t ) 0;
prvCheckExpectedState( xReturned == ( xTrueSize - ( size_t ) 1 ) ); prvCheckExpectedState( xReturned == ( xTrueSize - ( size_t ) 1 ) );
@ -349,8 +351,8 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );
/* Empty the buffer again ready for the rest of the tests. Again block /* Empty the buffer again ready for the rest of the tests. Again block
indefinitely to ensure reading more than there can possible be won't lock this * indefinitely to ensure reading more than there can possible be won't lock this
task up, so expect to actually receive one byte less than requested. */ * task up, so expect to actually receive one byte less than requested. */
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, xTrueSize, portMAX_DELAY ); xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucData, xTrueSize, portMAX_DELAY );
prvCheckExpectedState( xReturned == ( xTrueSize - ( size_t ) 1 ) ); prvCheckExpectedState( xReturned == ( xTrueSize - ( size_t ) 1 ) );
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer ); xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
@ -362,18 +364,19 @@ UBaseType_t uxOriginalPriority;
/* The buffer is 30 bytes long. 6 5 byte messages should fit before the /* The buffer is 30 bytes long. 6 5 byte messages should fit before the
buffer is completely full. */ * buffer is completely full. */
xExpected = xStreamBufferSpacesAvailable( xStreamBuffer ); xExpected = xStreamBufferSpacesAvailable( xStreamBuffer );
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ ) for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
{ {
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );
/* Generate recognisable data to write to the buffer. This is just /* Generate recognisable data to write to the buffer. This is just
ascii characters that shows which loop iteration the data was written * ascii characters that shows which loop iteration the data was written
in. The 'FromISR' version is used to give it some exercise as a block * in. The 'FromISR' version is used to give it some exercise as a block
time is not used, so the call must be inside a critical section so it * time is not used, so the call must be inside a critical section so it
runs with ports that don't support interrupt nesting (and therefore * runs with ports that don't support interrupt nesting (and therefore
don't have interrupt safe critical sections). */ * don't have interrupt safe critical sections). */
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength ); memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
@ -383,7 +386,7 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xReturned == x6ByteLength ); prvCheckExpectedState( xReturned == x6ByteLength );
/* The space in the buffer will have reduced by the amount of user data /* The space in the buffer will have reduced by the amount of user data
written into the buffer. */ * written into the buffer. */
xExpected -= x6ByteLength; xExpected -= x6ByteLength;
xReturned = xStreamBufferSpacesAvailable( xStreamBuffer ); xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xReturned == xExpected ); prvCheckExpectedState( xReturned == xExpected );
@ -398,8 +401,8 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xReturned == 0 ); prvCheckExpectedState( xReturned == 0 );
/* Adding with a timeout should also fail after the appropriate time. The /* Adding with a timeout should also fail after the appropriate time. The
priority is temporarily boosted in this part of the test to keep the * priority is temporarily boosted in this part of the test to keep the
allowable margin to a minimum. */ * allowable margin to a minimum. */
uxOriginalPriority = uxTaskPriorityGet( NULL ); uxOriginalPriority = uxTaskPriorityGet( NULL );
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
xTimeBeforeCall = xTaskGetTickCount(); xTimeBeforeCall = xTaskGetTickCount();
@ -411,17 +414,17 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xReturned == 0 ); prvCheckExpectedState( xReturned == 0 );
/* The buffer is now full of data in the form "000000", "111111", etc. Make /* The buffer is now full of data in the form "000000", "111111", etc. Make
sure the data is read out as expected. */ * sure the data is read out as expected. */
for( xItem = 0; xItem < xMax6ByteMessages; xItem++ ) for( xItem = 0; xItem < xMax6ByteMessages; xItem++ )
{ {
/* Generate the data that is expected to be read out for this loop /* Generate the data that is expected to be read out for this loop
iteration. */ * iteration. */
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength ); memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x6ByteLength );
/* Read the next 6 bytes out. The 'FromISR' version is used to give it /* Read the next 6 bytes out. The 'FromISR' version is used to give it
some exercise as a block time is not used, so a it must be called from * some exercise as a block time is not used, so a it must be called from
a critical section so this will work on ports that don't support * a critical section so this will work on ports that don't support
interrupt nesting (so don't have interrupt safe critical sections). */ * interrupt nesting (so don't have interrupt safe critical sections). */
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
xReturned = xStreamBufferReceiveFromISR( xStreamBuffer, ( void * ) pucReadData, x6ByteLength, NULL ); xReturned = xStreamBufferReceiveFromISR( xStreamBuffer, ( void * ) pucReadData, x6ByteLength, NULL );
@ -433,7 +436,7 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 ); prvCheckExpectedState( memcmp( ( void * ) pucData, ( void * ) pucReadData, x6ByteLength ) == 0 );
/* The space in the buffer will have increased by the amount of user /* The space in the buffer will have increased by the amount of user
data removed from the buffer. */ * data removed from the buffer. */
xExpected += x6ByteLength; xExpected += x6ByteLength;
xReturned = xStreamBufferSpacesAvailable( xStreamBuffer ); xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xReturned == xExpected ); prvCheckExpectedState( xReturned == xExpected );
@ -447,8 +450,8 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xExpected == sbSTREAM_BUFFER_LENGTH_BYTES ); prvCheckExpectedState( xExpected == sbSTREAM_BUFFER_LENGTH_BYTES );
/* Reading with a timeout should also fail after the appropriate time. The /* Reading with a timeout should also fail after the appropriate time. The
priority is temporarily boosted in this part of the test to keep the * priority is temporarily boosted in this part of the test to keep the
allowable margin to a minimum. */ * allowable margin to a minimum. */
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
xTimeBeforeCall = xTaskGetTickCount(); xTimeBeforeCall = xTaskGetTickCount();
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime ); xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucReadData, x6ByteLength, xBlockTime );
@ -460,20 +463,20 @@ UBaseType_t uxOriginalPriority;
/* In the next loop 17 bytes are written to then read out on each /* In the next loop 17 bytes are written to then read out on each
iteration. As 30 is not divisible by 17 the data will wrap around. */ * iteration. As 30 is not divisible by 17 the data will wrap around. */
xExpected = sbSTREAM_BUFFER_LENGTH_BYTES - x17ByteLength; xExpected = sbSTREAM_BUFFER_LENGTH_BYTES - x17ByteLength;
for( xItem = 0; xItem < 100; xItem++ ) for( xItem = 0; xItem < 100; xItem++ )
{ {
/* Generate recognisable data to write to the queue. This is just /* Generate recognisable data to write to the queue. This is just
ascii characters that shows which loop iteration the data was written * ascii characters that shows which loop iteration the data was written
in. */ * in. */
memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength ); memset( ( void * ) pucData, ( ( int ) '0' ) + ( int ) xItem, x17ByteLength );
xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, x17ByteLength, sbDONT_BLOCK ); xReturned = xStreamBufferSend( xStreamBuffer, ( void * ) pucData, x17ByteLength, sbDONT_BLOCK );
prvCheckExpectedState( xReturned == x17ByteLength ); prvCheckExpectedState( xReturned == x17ByteLength );
/* The space in the buffer will have reduced by the amount of user data /* The space in the buffer will have reduced by the amount of user data
written into the buffer. */ * written into the buffer. */
xReturned = xStreamBufferSpacesAvailable( xStreamBuffer ); xReturned = xStreamBufferSpacesAvailable( xStreamBuffer );
prvCheckExpectedState( xReturned == xExpected ); prvCheckExpectedState( xReturned == xExpected );
xReturned = xStreamBufferBytesAvailable( xStreamBuffer ); xReturned = xStreamBufferBytesAvailable( xStreamBuffer );
@ -498,7 +501,7 @@ UBaseType_t uxOriginalPriority;
} }
/* Fill the buffer with one message, check it is full, then read it back /* Fill the buffer with one message, check it is full, then read it back
again and check the correct data is received. */ * again and check the correct data is received. */
xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES, sbDONT_BLOCK ); xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES, sbDONT_BLOCK );
xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES, sbDONT_BLOCK ); xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES, sbDONT_BLOCK );
prvCheckExpectedState( memcmp( pc55ByteString, pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 ); prvCheckExpectedState( memcmp( pc55ByteString, pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );
@ -507,7 +510,7 @@ UBaseType_t uxOriginalPriority;
for( xItem = 0; xItem < sbSTREAM_BUFFER_LENGTH_BYTES; xItem++ ) for( xItem = 0; xItem < sbSTREAM_BUFFER_LENGTH_BYTES; xItem++ )
{ {
/* Block time is only for test coverage, the task should never actually /* Block time is only for test coverage, the task should never actually
block here. */ * block here. */
xStreamBufferSend( xStreamBuffer, ( const void * ) &( pc54ByteString[ xItem ] ), sizeof( char ), sbRX_TX_BLOCK_TIME ); xStreamBufferSend( xStreamBuffer, ( const void * ) &( pc54ByteString[ xItem ] ), sizeof( char ), sbRX_TX_BLOCK_TIME );
} }
@ -515,9 +518,9 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdTRUE );
/* Read the message out in one go, even though it was written in individual /* Read the message out in one go, even though it was written in individual
bytes. Try reading much more data than is actually available to ensure only * bytes. Try reading much more data than is actually available to ensure only
the available bytes are returned (otherwise this read will write outside of * the available bytes are returned (otherwise this read will write outside of
the memory allocated anyway!). */ * the memory allocated anyway!). */
xReturned = xStreamBufferReceive( xStreamBuffer, pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, sbRX_TX_BLOCK_TIME ); xReturned = xStreamBufferReceive( xStreamBuffer, pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES * ( size_t ) 2, sbRX_TX_BLOCK_TIME );
prvCheckExpectedState( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES ); prvCheckExpectedState( xReturned == sbSTREAM_BUFFER_LENGTH_BYTES );
prvCheckExpectedState( memcmp( ( const void * ) pc54ByteString, ( const void * ) pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 ); prvCheckExpectedState( memcmp( ( const void * ) pc54ByteString, ( const void * ) pucFullBuffer, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );
@ -534,10 +537,11 @@ UBaseType_t uxOriginalPriority;
for( xItem = 0; xItem < sbSTREAM_BUFFER_LENGTH_BYTES; xItem++ ) for( xItem = 0; xItem < sbSTREAM_BUFFER_LENGTH_BYTES; xItem++ )
{ {
/* Block time is only for test coverage, the task should never actually /* Block time is only for test coverage, the task should never actually
block here. */ * block here. */
xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, sizeof( char ), sbRX_TX_BLOCK_TIME ); xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, sizeof( char ), sbRX_TX_BLOCK_TIME );
prvCheckExpectedState( pc55ByteString[ xItem ] == pucFullBuffer[ 0 ] ); prvCheckExpectedState( pc55ByteString[ xItem ] == pucFullBuffer[ 0 ] );
} }
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE ); prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );
@ -554,15 +558,15 @@ UBaseType_t uxOriginalPriority;
prvCheckExpectedState( xReturned == 0 ); prvCheckExpectedState( xReturned == 0 );
/* Ensure data was written as expected even when there was an attempt to /* Ensure data was written as expected even when there was an attempt to
write more than was available. This also tries to read more bytes than are * write more than was available. This also tries to read more bytes than are
available. */ * available. */
xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, xFullBufferSize, xMinimalBlockTime ); xReturned = xStreamBufferReceive( xStreamBuffer, ( void * ) pucFullBuffer, xFullBufferSize, xMinimalBlockTime );
prvCheckExpectedState( memcmp( ( const void * ) pucFullBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 ); prvCheckExpectedState( memcmp( ( const void * ) pucFullBuffer, ( const void * ) pc54ByteString, sbSTREAM_BUFFER_LENGTH_BYTES ) == 0 );
prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE ); prvCheckExpectedState( xStreamBufferIsFull( xStreamBuffer ) == pdFALSE );
prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE ); prvCheckExpectedState( xStreamBufferIsEmpty( xStreamBuffer ) == pdTRUE );
/* Clean up with data in the buffer to ensure the tests that follow don't /* Clean up with data in the buffer to ensure the tests that follow don't
see the data (the data should be discarded). */ * see the data (the data should be discarded). */
( void ) xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES / ( size_t ) 2, sbDONT_BLOCK ); ( void ) xStreamBufferSend( xStreamBuffer, ( const void * ) pc55ByteString, sbSTREAM_BUFFER_LENGTH_BYTES / ( size_t ) 2, sbDONT_BLOCK );
vPortFree( pucFullBuffer ); vPortFree( pucFullBuffer );
xStreamBufferReset( xStreamBuffer ); xStreamBufferReset( xStreamBuffer );
@ -576,17 +580,17 @@ size_t xNextChar = 0, xBytesToSend, xBytesActuallySent;
const size_t xStringLength = strlen( pc54ByteString ); const size_t xStringLength = strlen( pc54ByteString );
/* In this case the stream buffer has already been created and is passed /* In this case the stream buffer has already been created and is passed
into the task using the task's parameter. */ * into the task using the task's parameter. */
xStreamBuffer = ( StreamBufferHandle_t ) pvParameters; xStreamBuffer = ( StreamBufferHandle_t ) pvParameters;
/* Keep sending the string to the stream buffer as many bytes as possible in /* Keep sending the string to the stream buffer as many bytes as possible in
each go. Doesn't block so calls can interleave with the non-blocking * each go. Doesn't block so calls can interleave with the non-blocking
receives performed by prvNonBlockingReceiverTask(). */ * receives performed by prvNonBlockingReceiverTask(). */
for( ; ; ) for( ; ; )
{ {
/* The whole string cannot be sent at once, so xNextChar is an index to /* The whole string cannot be sent at once, so xNextChar is an index to
the position within the string that has been sent so far. How many * the position within the string that has been sent so far. How many
bytes are there left to send before the end of the string? */ * bytes are there left to send before the end of the string? */
xBytesToSend = xStringLength - xNextChar; xBytesToSend = xStringLength - xNextChar;
/* Attempt to send right up to the end of the string. */ /* Attempt to send right up to the end of the string. */
@ -594,7 +598,7 @@ const size_t xStringLength = strlen( pc54ByteString );
prvCheckExpectedState( xBytesActuallySent <= xBytesToSend ); prvCheckExpectedState( xBytesActuallySent <= xBytesToSend );
/* Move the index up the string to the next character to be sent, /* Move the index up the string to the next character to be sent,
wrapping if the end of the string has been reached. */ * wrapping if the end of the string has been reached. */
xNextChar += xBytesActuallySent; xNextChar += xBytesActuallySent;
prvCheckExpectedState( xNextChar <= xStringLength ); prvCheckExpectedState( xNextChar <= xStringLength );
@ -615,25 +619,26 @@ char cRxString[ 12 ]; /* Holds received characters. */
BaseType_t xNonBlockingReceiveError = pdFALSE; BaseType_t xNonBlockingReceiveError = pdFALSE;
/* In this case the stream buffer has already been created and is passed /* In this case the stream buffer has already been created and is passed
into the task using the task's parameter. */ * into the task using the task's parameter. */
xStreamBuffer = ( StreamBufferHandle_t ) pvParameters; xStreamBuffer = ( StreamBufferHandle_t ) pvParameters;
/* Expects to receive the pc54ByteString over and over again. Sends and /* Expects to receive the pc54ByteString over and over again. Sends and
receives are not blocking so will interleave. */ * receives are not blocking so will interleave. */
for( ; ; ) for( ; ; )
{ {
/* Attempt to receive as many bytes as possible, up to the limit of the /* Attempt to receive as many bytes as possible, up to the limit of the
Rx buffer size. */ * Rx buffer size. */
xReceiveLength = xStreamBufferReceive( xStreamBuffer, ( void * ) cRxString, sizeof( cRxString ), sbDONT_BLOCK ); xReceiveLength = xStreamBufferReceive( xStreamBuffer, ( void * ) cRxString, sizeof( cRxString ), sbDONT_BLOCK );
if( xReceiveLength > 0 ) if( xReceiveLength > 0 )
{ {
/* xNextChar is the index into pc54ByteString that has been received /* xNextChar is the index into pc54ByteString that has been received
already. If xReceiveLength bytes are added to that, will it go off * already. If xReceiveLength bytes are added to that, will it go off
the end of the string? If so, then first test up to the end of the * the end of the string? If so, then first test up to the end of the
string, then go back to the start of pc54ByteString to test the * string, then go back to the start of pc54ByteString to test the
remains of the received data. */ * remains of the received data. */
xBytesToTest = xReceiveLength; xBytesToTest = xReceiveLength;
if( ( xNextChar + xBytesToTest ) > xStringLength ) if( ( xNextChar + xBytesToTest ) > xStringLength )
{ {
/* Cap to test the received data to the end of the string. */ /* Cap to test the received data to the end of the string. */
@ -645,7 +650,7 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
} }
/* Then move back to the start of the string to test the /* Then move back to the start of the string to test the
remaining received bytes. */ * remaining received bytes. */
xNextChar = 0; xNextChar = 0;
xStartIndex = xBytesToTest; xStartIndex = xBytesToTest;
xBytesToTest = xReceiveLength - xBytesToTest; xBytesToTest = xReceiveLength - xBytesToTest;
@ -653,12 +658,12 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
else else
{ {
/* The string didn't wrap in the buffer, so start comparing from /* The string didn't wrap in the buffer, so start comparing from
the start of the received data. */ * the start of the received data. */
xStartIndex = 0; xStartIndex = 0;
} }
/* Test the received bytes are as expected, then move the index /* Test the received bytes are as expected, then move the index
along the string to the next expected char to receive. */ * along the string to the next expected char to receive. */
if( memcmp( ( const void * ) &( pc54ByteString[ xNextChar ] ), ( const void * ) &( cRxString[ xStartIndex ] ), xBytesToTest ) != 0 ) if( memcmp( ( const void * ) &( pc54ByteString[ xNextChar ] ), ( const void * ) &( cRxString[ xStartIndex ] ), xBytesToTest ) != 0 )
{ {
xNonBlockingReceiveError = pdTRUE; xNonBlockingReceiveError = pdTRUE;
@ -667,11 +672,12 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
if( xNonBlockingReceiveError == pdFALSE ) if( xNonBlockingReceiveError == pdFALSE )
{ {
/* No errors detected so increment the counter that lets the /* No errors detected so increment the counter that lets the
check task know this test is still functioning correctly. */ * check task know this test is still functioning correctly. */
ulNonBlockingRxCounter++; ulNonBlockingRxCounter++;
} }
xNextChar += xBytesToTest; xNextChar += xBytesToTest;
if( xNextChar >= xStringLength ) if( xNextChar >= xStringLength )
{ {
xNextChar = 0; xNextChar = 0;
@ -693,11 +699,11 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
const size_t xStringLength = strlen( pc55ByteString ); const size_t xStringLength = strlen( pc55ByteString );
/* The task's priority is used as an index into the loop counters used to /* The task's priority is used as an index into the loop counters used to
indicate this task is still running. */ * indicate this task is still running. */
UBaseType_t uxIndex = uxTaskPriorityGet( NULL ); UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
/* Make sure a change in priority does not inadvertently result in an /* Make sure a change in priority does not inadvertently result in an
invalid array index. */ * invalid array index. */
prvCheckExpectedState( uxIndex < sbNUMBER_OF_ECHO_CLIENTS ); prvCheckExpectedState( uxIndex < sbNUMBER_OF_ECHO_CLIENTS );
/* Avoid compiler warnings about unused parameters. */ /* Avoid compiler warnings about unused parameters. */
@ -709,14 +715,14 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
&( xStaticStreamBuffers[ uxIndex ] ) ); /* The static stream buffer structure to use within the array. */ &( xStaticStreamBuffers[ uxIndex ] ) ); /* The static stream buffer structure to use within the array. */
/* Now the stream buffer has been created the receiver task can be /* Now the stream buffer has been created the receiver task can be
created. If this sender task has the higher priority then the receiver * created. If this sender task has the higher priority then the receiver
task is created at the lower priority - if this sender task has the * task is created at the lower priority - if this sender task has the
lower priority then the receiver task is created at the higher * lower priority then the receiver task is created at the higher
priority. */ * priority. */
if( uxTaskPriorityGet( NULL ) == sbLOWER_PRIORITY ) if( uxTaskPriorityGet( NULL ) == sbLOWER_PRIORITY )
{ {
/* Here prvSingleTaskTests() performs various tests on a stream buffer /* Here prvSingleTaskTests() performs various tests on a stream buffer
that was created statically. */ * that was created statically. */
prvSingleTaskTests( xStreamBuffer ); prvSingleTaskTests( xStreamBuffer );
xTaskCreate( prvReceiverTask, "StrReceiver", sbSMALLER_STACK_SIZE, ( void * ) xStreamBuffer, sbHIGHER_PRIORITY, NULL ); xTaskCreate( prvReceiverTask, "StrReceiver", sbSMALLER_STACK_SIZE, ( void * ) xStreamBuffer, sbHIGHER_PRIORITY, NULL );
} }
@ -728,8 +734,8 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
for( ; ; ) for( ; ; )
{ {
/* The whole string cannot be sent at once, so xNextChar is an index /* The whole string cannot be sent at once, so xNextChar is an index
to the position within the string that has been sent so far. How * to the position within the string that has been sent so far. How
many bytes are there left to send before the end of the string? */ * many bytes are there left to send before the end of the string? */
xBytesToSend = xStringLength - xNextChar; xBytesToSend = xStringLength - xNextChar;
/* Attempt to send right up to the end of the string. */ /* Attempt to send right up to the end of the string. */
@ -737,7 +743,7 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
prvCheckExpectedState( xBytesActuallySent <= xBytesToSend ); prvCheckExpectedState( xBytesActuallySent <= xBytesToSend );
/* Move the index up the string to the next character to be sent, /* Move the index up the string to the next character to be sent,
wrapping if the end of the string has been reached. */ * wrapping if the end of the string has been reached. */
xNextChar += xBytesActuallySent; xNextChar += xBytesActuallySent;
prvCheckExpectedState( xNextChar <= xStringLength ); prvCheckExpectedState( xNextChar <= xStringLength );
@ -747,7 +753,7 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
} }
/* Increment a loop counter so a check task can tell this task is /* Increment a loop counter so a check task can tell this task is
still running as expected. */ * still running as expected. */
ulSenderLoopCounters[ uxIndex ]++; ulSenderLoopCounters[ uxIndex ]++;
if( uxTaskPriorityGet( NULL ) == sbHIGHER_PRIORITY ) if( uxTaskPriorityGet( NULL ) == sbHIGHER_PRIORITY )
@ -757,11 +763,11 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
} }
/* This stream buffer is just created and deleted to ensure no /* This stream buffer is just created and deleted to ensure no
issues when attempting to delete a stream buffer that was * issues when attempting to delete a stream buffer that was
created using statically allocated memory. To save stack space * created using statically allocated memory. To save stack space
the buffer is set to point to the pc55ByteString, which is a const * the buffer is set to point to the pc55ByteString, which is a const
string, but no data is written into the buffer so any valid address * string, but no data is written into the buffer so any valid address
will do. */ * will do. */
xTempStreamBuffer = xStreamBufferCreateStatic( sizeof( ucTempBuffer ), sbTRIGGER_LEVEL_1, ucTempBuffer, &xStaticStreamBuffer ); xTempStreamBuffer = xStreamBufferCreateStatic( sizeof( ucTempBuffer ), sbTRIGGER_LEVEL_1, ucTempBuffer, &xStaticStreamBuffer );
xStreamBufferReset( xTempStreamBuffer ); xStreamBufferReset( xTempStreamBuffer );
vStreamBufferDelete( xTempStreamBuffer ); vStreamBufferDelete( xTempStreamBuffer );
@ -784,23 +790,23 @@ BaseType_t xNonBlockingReceiveError = pdFALSE;
for( ; ; ) for( ; ; )
{ {
/* Attempt to receive the number of bytes to the end of the string, /* Attempt to receive the number of bytes to the end of the string,
or the number of byte that can be placed into the rx buffer, * or the number of byte that can be placed into the rx buffer,
whichever is smallest. */ * whichever is smallest. */
xBytesToReceive = configMIN( ( xStringLength - xNextChar ), sizeof( cRxString ) ); xBytesToReceive = configMIN( ( xStringLength - xNextChar ), sizeof( cRxString ) );
do do
{ {
xReceivedLength = xStreamBufferReceive( pxStreamBuffer, ( void * ) cRxString, xBytesToReceive, xTicksToWait ); xReceivedLength = xStreamBufferReceive( pxStreamBuffer, ( void * ) cRxString, xBytesToReceive, xTicksToWait );
} while( xReceivedLength == 0 ); } while( xReceivedLength == 0 );
/* Ensure the received string matches the expected string. */ /* Ensure the received string matches the expected string. */
prvCheckExpectedState( memcmp( ( void * ) cRxString, ( const void * ) &( pc55ByteString[ xNextChar ] ), xReceivedLength ) == 0 ); prvCheckExpectedState( memcmp( ( void * ) cRxString, ( const void * ) &( pc55ByteString[ xNextChar ] ), xReceivedLength ) == 0 );
/* Move the index into the string up to the end of the bytes /* Move the index into the string up to the end of the bytes
received so far - wrapping if the end of the string has been * received so far - wrapping if the end of the string has been
reached. */ * reached. */
xNextChar += xReceivedLength; xNextChar += xReceivedLength;
if( xNextChar >= xStringLength ) if( xNextChar >= xStringLength )
{ {
xNextChar = 0; xNextChar = 0;
@ -819,19 +825,19 @@ const TickType_t xTicksToWait = pdMS_TO_TICKS( 50 );
StreamBufferHandle_t xTempStreamBuffer; StreamBufferHandle_t xTempStreamBuffer;
/* The task's priority is used as an index into the loop counters used to /* The task's priority is used as an index into the loop counters used to
indicate this task is still running. */ * indicate this task is still running. */
UBaseType_t uxIndex = uxTaskPriorityGet( NULL ); UBaseType_t uxIndex = uxTaskPriorityGet( NULL );
/* Pointers to the client and server stream buffers are passed into this task /* Pointers to the client and server stream buffers are passed into this task
using the task's parameter. */ * using the task's parameter. */
EchoStreamBuffers_t * pxStreamBuffers = ( EchoStreamBuffers_t * ) pvParameters; EchoStreamBuffers_t * pxStreamBuffers = ( EchoStreamBuffers_t * ) pvParameters;
/* Prevent compiler warnings. */ /* Prevent compiler warnings. */
( void ) pvParameters; ( void ) pvParameters;
/* Create the buffer into which strings to send to the server will be /* Create the buffer into which strings to send to the server will be
created, and the buffer into which strings echoed back from the server will * created, and the buffer into which strings echoed back from the server will
be copied. */ * be copied. */
pcStringToSend = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES ); pcStringToSend = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES );
pcStringReceived = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES ); pcStringReceived = ( char * ) pvPortMalloc( sbSTREAM_BUFFER_LENGTH_BYTES );
@ -844,8 +850,8 @@ EchoStreamBuffers_t *pxStreamBuffers = ( EchoStreamBuffers_t * ) pvParameters;
xSendLength++; xSendLength++;
/* The stream buffer is being used to hold variable length data, so /* The stream buffer is being used to hold variable length data, so
each data item requires sizeof( size_t ) bytes to hold the data's * each data item requires sizeof( size_t ) bytes to hold the data's
length, hence the sizeof() in the if() condition below. */ * length, hence the sizeof() in the if() condition below. */
if( xSendLength > ( sbSTREAM_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) ) if( xSendLength > ( sbSTREAM_BUFFER_LENGTH_BYTES - sizeof( size_t ) ) )
{ {
/* Back to a string length of 1. */ /* Back to a string length of 1. */
@ -870,7 +876,6 @@ EchoStreamBuffers_t *pxStreamBuffers = ( EchoStreamBuffers_t * ) pvParameters;
do do
{ {
ux = xStreamBufferSend( pxStreamBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait ); ux = xStreamBufferSend( pxStreamBuffers->xEchoClientBuffer, ( void * ) pcStringToSend, xSendLength, xTicksToWait );
} while( ux == 0 ); } while( ux == 0 );
/* Wait for the string to be echoed back. */ /* Wait for the string to be echoed back. */
@ -880,14 +885,14 @@ EchoStreamBuffers_t *pxStreamBuffers = ( EchoStreamBuffers_t * ) pvParameters;
prvCheckExpectedState( strcmp( pcStringToSend, pcStringReceived ) == 0 ); prvCheckExpectedState( strcmp( pcStringToSend, pcStringReceived ) == 0 );
/* Maintain a count of the number of times this code executes so a /* Maintain a count of the number of times this code executes so a
check task can determine if this task is still functioning as * check task can determine if this task is still functioning as
expected or not. As there are two client tasks, and the priorities * expected or not. As there are two client tasks, and the priorities
used are 0 and 1, the task's priority is used as an index into the * used are 0 and 1, the task's priority is used as an index into the
loop count array. */ * loop count array. */
ulEchoLoopCounters[ uxIndex ]++; ulEchoLoopCounters[ uxIndex ]++;
/* This stream buffer is just created and deleted to ensure no memory /* This stream buffer is just created and deleted to ensure no memory
leaks. */ * leaks. */
xTempStreamBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 ); xTempStreamBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );
vStreamBufferDelete( xTempStreamBuffer ); vStreamBufferDelete( xTempStreamBuffer );
@ -951,8 +956,8 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 350UL );
( void ) pvParameters; ( void ) pvParameters;
/* Create the stream buffer used to send data from the client to the server, /* Create the stream buffer used to send data from the client to the server,
and the stream buffer used to echo the data from the server back to the * and the stream buffer used to echo the data from the server back to the
client. */ * client. */
xStreamBuffers.xEchoClientBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 ); xStreamBuffers.xEchoClientBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );
xStreamBuffers.xEchoServerBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 ); xStreamBuffers.xEchoServerBuffer = xStreamBufferCreate( sbSTREAM_BUFFER_LENGTH_BYTES, sbTRIGGER_LEVEL_1 );
configASSERT( xStreamBuffers.xEchoClientBuffer ); configASSERT( xStreamBuffers.xEchoClientBuffer );
@ -969,9 +974,9 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 350UL );
prvCheckExpectedState( xReceivedLength == 0 ); prvCheckExpectedState( xReceivedLength == 0 );
/* Now the stream buffers have been created the echo client task can be /* Now the stream buffers have been created the echo client task can be
created. If this server task has the higher priority then the client task * created. If this server task has the higher priority then the client task
is created at the lower priority - if this server task has the lower * is created at the lower priority - if this server task has the lower
priority then the client task is created at the higher priority. */ * priority then the client task is created at the higher priority. */
if( uxTaskPriorityGet( NULL ) == sbLOWER_PRIORITY ) if( uxTaskPriorityGet( NULL ) == sbLOWER_PRIORITY )
{ {
xTaskCreate( prvEchoClient, "EchoClient", sbSMALLER_STACK_SIZE, ( void * ) &xStreamBuffers, sbHIGHER_PRIORITY, NULL ); xTaskCreate( prvEchoClient, "EchoClient", sbSMALLER_STACK_SIZE, ( void * ) &xStreamBuffers, sbHIGHER_PRIORITY, NULL );
@ -979,7 +984,7 @@ const TickType_t xTicksToBlock = pdMS_TO_TICKS( 350UL );
else else
{ {
/* Here prvSingleTaskTests() performs various tests on a stream buffer /* Here prvSingleTaskTests() performs various tests on a stream buffer
that was created dynamically. */ * that was created dynamically. */
prvSingleTaskTests( xStreamBuffers.xEchoClientBuffer ); prvSingleTaskTests( xStreamBuffers.xEchoClientBuffer );
xTaskCreate( prvEchoClient, "EchoClient", sbSMALLER_STACK_SIZE, ( void * ) &xStreamBuffers, sbLOWER_PRIORITY, NULL ); xTaskCreate( prvEchoClient, "EchoClient", sbSMALLER_STACK_SIZE, ( void * ) &xStreamBuffers, sbLOWER_PRIORITY, NULL );
} }
@ -1006,13 +1011,13 @@ static size_t xNextChar = 0;
BaseType_t xHigherPriorityTaskWoken = pdFALSE; BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* Called from the tick interrupt hook. If the global stream buffer /* Called from the tick interrupt hook. If the global stream buffer
variable is not NULL then the prvInterruptTriggerTest() task expects a byte * variable is not NULL then the prvInterruptTriggerTest() task expects a byte
to be sent to the stream buffer on each tick interrupt. */ * to be sent to the stream buffer on each tick interrupt. */
if( xInterruptStreamBuffer != NULL ) if( xInterruptStreamBuffer != NULL )
{ {
/* One character from the pcDataSentFromInterrupt string is sent on each /* One character from the pcDataSentFromInterrupt string is sent on each
interrupt. The task blocked on the stream buffer should not be * interrupt. The task blocked on the stream buffer should not be
unblocked until the defined trigger level is hit. */ * unblocked until the defined trigger level is hit. */
xStreamBufferSendFromISR( xInterruptStreamBuffer, ( const void * ) &( pcDataSentFromInterrupt[ xNextChar ] ), sizeof( char ), &xHigherPriorityTaskWoken ); xStreamBufferSendFromISR( xInterruptStreamBuffer, ( const void * ) &( pcDataSentFromInterrupt[ xNextChar ] ), sizeof( char ), &xHigherPriorityTaskWoken );
if( xNextChar < strlen( pcDataSentFromInterrupt ) ) if( xNextChar < strlen( pcDataSentFromInterrupt ) )
@ -1036,6 +1041,7 @@ const size_t xStreamBufferSizeBytes = ( size_t ) 9, xMaxTriggerLevel = ( size_t
const TickType_t xReadBlockTime = 5, xCycleBlockTime = pdMS_TO_TICKS( 100 ); const TickType_t xReadBlockTime = 5, xCycleBlockTime = pdMS_TO_TICKS( 100 );
uint8_t ucRxData[ 9 ]; uint8_t ucRxData[ 9 ];
BaseType_t xErrorDetected = pdFALSE; BaseType_t xErrorDetected = pdFALSE;
#ifndef configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN #ifndef configSTREAM_BUFFER_TRIGGER_LEVEL_TEST_MARGIN
const size_t xAllowableMargin = ( size_t ) 0; const size_t xAllowableMargin = ( size_t ) 0;
#else #else
@ -1050,20 +1056,20 @@ BaseType_t xErrorDetected = pdFALSE;
for( xTriggerLevel = xMinTriggerLevel; xTriggerLevel < xMaxTriggerLevel; xTriggerLevel++ ) for( xTriggerLevel = xMinTriggerLevel; xTriggerLevel < xMaxTriggerLevel; xTriggerLevel++ )
{ {
/* This test is very time sensitive so delay at the beginning to ensure /* This test is very time sensitive so delay at the beginning to ensure
the rest of the system is up and running before starting. Delay between * the rest of the system is up and running before starting. Delay between
each loop to ensure the interrupt that sends to the stream buffer * each loop to ensure the interrupt that sends to the stream buffer
detects it needs to start sending from the start of the strin again.. */ * detects it needs to start sending from the start of the strin again.. */
vTaskDelay( xCycleBlockTime ); vTaskDelay( xCycleBlockTime );
/* Create the stream buffer that will be used from inside the tick /* Create the stream buffer that will be used from inside the tick
interrupt. */ * interrupt. */
memset( ucRxData, 0x00, sizeof( ucRxData ) ); memset( ucRxData, 0x00, sizeof( ucRxData ) );
xStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel ); xStreamBuffer = xStreamBufferCreate( xStreamBufferSizeBytes, xTriggerLevel );
configASSERT( xStreamBuffer ); configASSERT( xStreamBuffer );
/* Now the stream buffer has been created it can be assigned to the /* Now the stream buffer has been created it can be assigned to the
file scope variable, which will allow the tick interrupt to start * file scope variable, which will allow the tick interrupt to start
using it. */ * using it. */
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
xInterruptStreamBuffer = xStreamBuffer; xInterruptStreamBuffer = xStreamBuffer;
@ -1073,7 +1079,7 @@ BaseType_t xErrorDetected = pdFALSE;
xBytesReceived = xStreamBufferReceive( xStreamBuffer, ( void * ) ucRxData, sizeof( ucRxData ), xReadBlockTime ); xBytesReceived = xStreamBufferReceive( xStreamBuffer, ( void * ) ucRxData, sizeof( ucRxData ), xReadBlockTime );
/* Set the file scope variable back to NULL so the interrupt doesn't /* Set the file scope variable back to NULL so the interrupt doesn't
try to use it again. */ * try to use it again. */
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
xInterruptStreamBuffer = NULL; xInterruptStreamBuffer = NULL;
@ -1081,18 +1087,18 @@ BaseType_t xErrorDetected = pdFALSE;
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
/* Now check the number of bytes received equals the trigger level, /* Now check the number of bytes received equals the trigger level,
except in the case that the read timed out before the trigger level * except in the case that the read timed out before the trigger level
was reached. */ * was reached. */
if( xTriggerLevel > xReadBlockTime ) if( xTriggerLevel > xReadBlockTime )
{ {
/* Trigger level was greater than the block time so expect to /* Trigger level was greater than the block time so expect to
time out having received xReadBlockTime bytes. */ * time out having received xReadBlockTime bytes. */
if( xBytesReceived > xReadBlockTime ) if( xBytesReceived > xReadBlockTime )
{ {
/* Received more bytes than expected. That could happen if /* Received more bytes than expected. That could happen if
this task unblocked at the right time, but an interrupt * this task unblocked at the right time, but an interrupt
added another byte to the stream buffer before this task was * added another byte to the stream buffer before this task was
able to run. */ * able to run. */
if( ( xBytesReceived - xReadBlockTime ) > xAllowableMargin ) if( ( xBytesReceived - xReadBlockTime ) > xAllowableMargin )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -1101,9 +1107,9 @@ BaseType_t xErrorDetected = pdFALSE;
else if( xReadBlockTime != xBytesReceived ) else if( xReadBlockTime != xBytesReceived )
{ {
/* It is possible the interrupt placed an item in the stream /* It is possible the interrupt placed an item in the stream
buffer before this task called xStreamBufferReceive(), but * buffer before this task called xStreamBufferReceive(), but
if that is the case then xBytesReceived will only every be * if that is the case then xBytesReceived will only every be
0 as the interrupt will only have executed once. */ * 0 as the interrupt will only have executed once. */
if( xBytesReceived != 1 ) if( xBytesReceived != 1 )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -1113,15 +1119,15 @@ BaseType_t xErrorDetected = pdFALSE;
else if( xTriggerLevel < xReadBlockTime ) else if( xTriggerLevel < xReadBlockTime )
{ {
/* Trigger level was less than the block time so we expect to /* Trigger level was less than the block time so we expect to
have received the trigger level number of bytes - could be more * have received the trigger level number of bytes - could be more
though depending on other activity between the task being * though depending on other activity between the task being
unblocked and the task reading the number of bytes received. It * unblocked and the task reading the number of bytes received. It
could also be less if the interrupt already put something in the * could also be less if the interrupt already put something in the
stream buffer before this task attempted to read it - in which * stream buffer before this task attempted to read it - in which
case the task would have returned the available bytes immediately * case the task would have returned the available bytes immediately
without ever blocking - in that case the bytes received will * without ever blocking - in that case the bytes received will
only ever be 1 as the interrupt would not have executed more * only ever be 1 as the interrupt would not have executed more
than one in that time unless this task has too low a priority. */ * than one in that time unless this task has too low a priority. */
if( xBytesReceived < xTriggerLevel ) if( xBytesReceived < xTriggerLevel )
{ {
if( xBytesReceived != 1 ) if( xBytesReceived != 1 )
@ -1137,13 +1143,13 @@ BaseType_t xErrorDetected = pdFALSE;
else else
{ {
/* The trigger level equalled the block time, so expect to /* The trigger level equalled the block time, so expect to
receive no greater than the block time. It could also be less * receive no greater than the block time. It could also be less
if the interrupt already put something in the stream buffer * if the interrupt already put something in the stream buffer
before this task attempted to read it - in which case the task * before this task attempted to read it - in which case the task
would have returned the available bytes immediately without ever * would have returned the available bytes immediately without ever
blocking - in that case the bytes received would only ever be 1 * blocking - in that case the bytes received would only ever be 1
because the interrupt is not going to execute twice in that time * because the interrupt is not going to execute twice in that time
unless this task is running a too low a priority. */ * unless this task is running a too low a priority. */
if( xBytesReceived < xReadBlockTime ) if( xBytesReceived < xReadBlockTime )
{ {
if( xBytesReceived != 1 ) if( xBytesReceived != 1 )
@ -1170,7 +1176,7 @@ BaseType_t xErrorDetected = pdFALSE;
if( xErrorDetected == pdFALSE ) if( xErrorDetected == pdFALSE )
{ {
/* Increment the cycle counter so the 'check' task knows this test /* Increment the cycle counter so the 'check' task knows this test
is still running without error. */ * is still running without error. */
ulInterruptTriggerCounter++; ulInterruptTriggerCounter++;
} }

View file

@ -62,19 +62,19 @@ static void prvReceivingTask( void *pvParameters );
static StreamBufferHandle_t xStreamBuffer = NULL; static StreamBufferHandle_t xStreamBuffer = NULL;
/* The string that is sent from the interrupt to the task four bytes at a /* The string that is sent from the interrupt to the task four bytes at a
time. Must be multiple of 4 bytes long as the ISR sends 4 bytes at a time*/ * time. Must be multiple of 4 bytes long as the ISR sends 4 bytes at a time*/
static const char * pcStringToSend = "_____Hello FreeRTOS_____"; static const char * pcStringToSend = "_____Hello FreeRTOS_____";
/* The string to task is looking for, which must be a substring of /* The string to task is looking for, which must be a substring of
pcStringToSend. */ * pcStringToSend. */
static const char * pcStringToReceive = "Hello FreeRTOS"; static const char * pcStringToReceive = "Hello FreeRTOS";
/* Set to pdFAIL if anything unexpected happens. */ /* Set to pdFAIL if anything unexpected happens. */
static BaseType_t xDemoStatus = pdPASS; static BaseType_t xDemoStatus = pdPASS;
/* Incremented each time pcStringToReceive is correctly received, provided no /* Incremented each time pcStringToReceive is correctly received, provided no
errors have occurred. Used so the check task can check this task is still * errors have occurred. Used so the check task can check this task is still
running as expected. */ * running as expected. */
static uint32_t ulCycleCount = 0; static uint32_t ulCycleCount = 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -82,7 +82,7 @@ static uint32_t ulCycleCount = 0;
void vStartStreamBufferInterruptDemo( void ) void vStartStreamBufferInterruptDemo( void )
{ {
/* Create the stream buffer that sends data from the interrupt to the /* Create the stream buffer that sends data from the interrupt to the
task, and create the task. */ * task, and create the task. */
xStreamBuffer = xStreamBufferCreate( /* The buffer length in bytes. */ xStreamBuffer = xStreamBufferCreate( /* The buffer length in bytes. */
sbiSTREAM_BUFFER_LENGTH_BYTES, sbiSTREAM_BUFFER_LENGTH_BYTES,
/* The stream buffer's trigger level. */ /* The stream buffer's trigger level. */
@ -106,7 +106,7 @@ BaseType_t xNextByte = 0;
( void ) pvParameters; ( void ) pvParameters;
/* Make sure the string will fit in the Rx buffer, including the NULL /* Make sure the string will fit in the Rx buffer, including the NULL
terminator. */ * terminator. */
configASSERT( sizeof( cRxBuffer ) > strlen( pcStringToReceive ) ); configASSERT( sizeof( cRxBuffer ) > strlen( pcStringToReceive ) );
/* Make sure the stream buffer has been created. */ /* Make sure the stream buffer has been created. */
@ -118,34 +118,35 @@ BaseType_t xNextByte = 0;
for( ; ; ) for( ; ; )
{ {
/* Keep receiving characters until the end of the string is received. /* Keep receiving characters until the end of the string is received.
Note: An infinite block time is used to simplify the example. Infinite * Note: An infinite block time is used to simplify the example. Infinite
block times are not recommended in production code as they do not allow * block times are not recommended in production code as they do not allow
for error recovery. */ * for error recovery. */
xStreamBufferReceive( /* The stream buffer data is being received from. */ xStreamBufferReceive( /* The stream buffer data is being received from. */
xStreamBuffer, xStreamBuffer,
/* Where to place received data. */ /* Where to place received data. */
( void * ) &( cRxBuffer[ xNextByte ] ), ( void * ) &( cRxBuffer[ xNextByte ] ),
/* The number of bytes to receive. */ /* The number of bytes to receive. */
sizeof( char ), sizeof( char ),
/* The time to wait for the next data if the buffer /* The time to wait for the next data if the buffer
is empty. */ * is empty. */
portMAX_DELAY ); portMAX_DELAY );
/* If xNextByte is 0 then this task is looking for the start of the /* If xNextByte is 0 then this task is looking for the start of the
string, which is 'H'. */ * string, which is 'H'. */
if( xNextByte == 0 ) if( xNextByte == 0 )
{ {
if( cRxBuffer[ xNextByte ] == 'H' ) if( cRxBuffer[ xNextByte ] == 'H' )
{ {
/* The start of the string has been found. Now receive /* The start of the string has been found. Now receive
characters until the end of the string is found. */ * characters until the end of the string is found. */
xNextByte++; xNextByte++;
} }
} }
else else
{ {
/* Receiving characters while looking for the end of the string, /* Receiving characters while looking for the end of the string,
which is an 'S'. */ * which is an 'S'. */
if( cRxBuffer[ xNextByte ] == 'S' ) if( cRxBuffer[ xNextByte ] == 'S' )
{ {
/* The string has now been received. Check its validity. */ /* The string has now been received. Check its validity. */
@ -155,12 +156,12 @@ BaseType_t xNextByte = 0;
} }
/* Return to start looking for the beginning of the string /* Return to start looking for the beginning of the string
again. */ * again. */
memset( cRxBuffer, 0x00, sizeof( cRxBuffer ) ); memset( cRxBuffer, 0x00, sizeof( cRxBuffer ) );
xNextByte = 0; xNextByte = 0;
/* Increment the cycle count as an indication to the check task /* Increment the cycle count as an indication to the check task
that this demo is still running. */ * that this demo is still running. */
if( xDemoStatus == pdPASS ) if( xDemoStatus == pdPASS )
{ {
ulCycleCount++; ulCycleCount++;
@ -169,7 +170,7 @@ BaseType_t xNextByte = 0;
else else
{ {
/* Receive the next character the next time around, while /* Receive the next character the next time around, while
continuing to look for the end of the string. */ * continuing to look for the end of the string. */
xNextByte++; xNextByte++;
configASSERT( ( size_t ) xNextByte < sizeof( cRxBuffer ) ); configASSERT( ( size_t ) xNextByte < sizeof( cRxBuffer ) );
@ -187,6 +188,7 @@ static BaseType_t xCallCount = 0;
/* Is it time to write to the stream buffer again? */ /* Is it time to write to the stream buffer again? */
xCallCount++; xCallCount++;
if( xCallCount > xCallsBetweenSends ) if( xCallCount > xCallsBetweenSends )
{ {
xCallCount = 0; xCallCount = 0;
@ -198,7 +200,7 @@ static BaseType_t xCallCount = 0;
NULL ); NULL );
/* Send the next four bytes the next time around, wrapping to the start /* Send the next four bytes the next time around, wrapping to the start
of the string if necessary. */ * of the string if necessary. */
xNextByteToSend += xBytesToSend; xNextByteToSend += xBytesToSend;
if( xNextByteToSend >= strlen( pcStringToSend ) ) if( xNextByteToSend >= strlen( pcStringToSend ) )
@ -225,4 +227,3 @@ uint32_t ulLastCycleCount = 0;
return xDemoStatus; return xDemoStatus;
} }

View file

@ -98,8 +98,8 @@ static volatile uint32_t ulNotifyCycleCount = 0;
static TaskHandle_t xTaskToNotify = NULL; static TaskHandle_t xTaskToNotify = NULL;
/* Used to count the notifications sent to the task from a software timer and /* 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 * the number of notifications received by the task from the software timer. The
two should stay synchronised. */ * two should stay synchronised. */
static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL; static uint32_t ulTimerNotificationsReceived = 0UL, ulTimerNotificationsSent = 0UL;
/* The timer used to notify the task. */ /* The timer used to notify the task. */
@ -113,7 +113,7 @@ static size_t uxNextRand = 0;
void vStartTaskNotifyTask( void ) void vStartTaskNotifyTask( void )
{ {
/* Create the task that performs some tests by itself, then loops around /* Create the task that performs some tests by itself, then loops around
being notified by both a software timer and an interrupt. */ * being notified by both a software timer and an interrupt. */
xTaskCreate( prvNotifiedTask, /* Function that implements the task. */ xTaskCreate( prvNotifiedTask, /* Function that implements the task. */
"Notified", /* Text name for the task - for debugging only - not used by the kernel. */ "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!. */ notifyNOTIFIED_TASK_STACK_SIZE, /* Task's stack size in words, not bytes!. */
@ -138,7 +138,7 @@ TimerHandle_t xSingleTaskTimer;
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
Check blocking when there are no notifications. */ * Check blocking when there are no notifications. */
xTimeOnEntering = xTaskGetTickCount(); xTimeOnEntering = xTaskGetTickCount();
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait ); xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -148,6 +148,7 @@ TimerHandle_t xSingleTaskTimer;
{ {
xErrorStatus = pdFAIL; xErrorStatus = pdFAIL;
} }
configASSERT( xReturned == pdFAIL ); configASSERT( xReturned == pdFAIL );
configASSERT( ulNotifiedValue == 0UL ); configASSERT( ulNotifiedValue == 0UL );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -155,15 +156,14 @@ TimerHandle_t xSingleTaskTimer;
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
Check no blocking when notifications are pending. First notify itself - * 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 * this would not be a normal thing to do and is done here for test purposes
only. */ * only. */
xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue ); xReturned = xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
/* Even through the 'without overwrite' action was used the update should /* Even through the 'without overwrite' action was used the update should
have been successful. */ * have been successful. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -181,7 +181,7 @@ TimerHandle_t xSingleTaskTimer;
} }
/* The task should have been notified, and the notified value should /* The task should have been notified, and the notified value should
be equal to ulFirstNotifiedConst. */ * be equal to ulFirstNotifiedConst. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -192,13 +192,11 @@ TimerHandle_t xSingleTaskTimer;
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Check the non-overwriting functionality. The notification is done twice * Check the non-overwriting functionality. The notification is done twice
using two different notification values. The action says don't overwrite so * 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 * only the first notification should pass and the value read back should also
be that used with the first notification. */ * be that used with the first notification. */
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite ); xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -208,7 +206,7 @@ TimerHandle_t xSingleTaskTimer;
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
/* Waiting for the notification should now return immediately so a block /* Waiting for the notification should now return immediately so a block
time of zero is used. */ * time of zero is used. */
xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
@ -218,13 +216,11 @@ TimerHandle_t xSingleTaskTimer;
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Do the same again, only this time use the overwriting version. This time * 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 * 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 * overwrite the value written the first time, and so be the value that is read
back. */ * back. */
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite ); xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithOverwrite );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -239,11 +235,10 @@ TimerHandle_t xSingleTaskTimer;
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Check notifications with no action pass without updating the value. Even * Check notifications with no action pass without updating the value. Even
though ulFirstNotifiedConst is used as the value the value read back should * though ulFirstNotifiedConst is used as the value the value read back should
remain at ulSecondNotifiedConst. */ * remain at ulSecondNotifiedConst. */
xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction ); xReturned = xTaskNotify( xTaskToNotify, ulFirstNotifiedConst, eNoAction );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -251,13 +246,10 @@ TimerHandle_t xSingleTaskTimer;
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst ); configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
( void ) ulNotifiedValue; /* In case configASSERT() is not defined. */ ( void ) ulNotifiedValue; /* In case configASSERT() is not defined. */
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Check incrementing values. Send ulMaxLoop increment notifications, then * Check incrementing values. Send ulMaxLoop increment notifications, then
ensure the received value is as expected - which should be * ensure the received value is as expected - which should be
ulSecondNotificationValueConst plus how ever many times to loop iterated. */ * ulSecondNotificationValueConst plus how ever many times to loop iterated. */
for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ ) for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
{ {
xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement ); xReturned = xTaskNotify( xTaskToNotify, 0, eIncrement );
@ -279,12 +271,11 @@ TimerHandle_t xSingleTaskTimer;
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Check all bits can be set by notifying the task with one additional bit set * 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 * 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 * set. As there are 32-bits the loop should execute 32 times before all the
bits are found to be set. */ * bits are found to be set. */
ulNotifyingValue = 0x01; ulNotifyingValue = 0x01;
ulLoop = 0; ulLoop = 0;
@ -297,8 +288,8 @@ TimerHandle_t xSingleTaskTimer;
xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits ); xTaskNotify( xTaskToNotify, ulNotifyingValue, eSetBits );
/* Wait for the notified value - which of course will already be /* 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 * available. Don't clear the bits on entry or exit as this loop is exited
when all the bits are set. */ * when all the bits are set. */
xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWait( 0, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
@ -307,34 +298,32 @@ TimerHandle_t xSingleTaskTimer;
/* Use the next bit on the next iteration around this loop. */ /* Use the next bit on the next iteration around this loop. */
ulNotifyingValue <<= 1UL; ulNotifyingValue <<= 1UL;
} while( ulNotifiedValue != notifyUINT32_MAX ); } while( ulNotifiedValue != notifyUINT32_MAX );
/* As a 32-bit value was used the loop should have executed 32 times before /* As a 32-bit value was used the loop should have executed 32 times before
all the bits were set. */ * all the bits were set. */
configASSERT( ulLoop == 32 ); configASSERT( ulLoop == 32 );
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Check bits are cleared on entry but not on exit when a notification fails * 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 * 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 * 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 * 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 * bit one on exit. As no notification was received only the bit cleared on
entry should actually get cleared. */ * entry should actually get cleared. */
xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait ); xReturned = xTaskNotifyWait( ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
configASSERT( xReturned == pdFAIL ); configASSERT( xReturned == pdFAIL );
( void ) xReturned; /* In case configASSERT() is not defined. */ ( void ) xReturned; /* In case configASSERT() is not defined. */
/* Notify the task with no action so as not to update the bits even though /* Notify the task with no action so as not to update the bits even though
notifyUINT32_MAX is used as the notification value. */ * notifyUINT32_MAX is used as the notification value. */
xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eNoAction ); xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eNoAction );
/* Reading back the value should should find bit 0 is clear, as this was /* 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 * cleared on entry, but bit 1 is not clear as it will not have been cleared on
exit as no notification was received. */ * exit as no notification was received. */
xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWait( 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) ); configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
@ -342,22 +331,20 @@ TimerHandle_t xSingleTaskTimer;
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Now try clearing the bit on exit. For that to happen a notification must be * Now try clearing the bit on exit. For that to happen a notification must be
received, so the task is notified first. */ * received, so the task is notified first. */
xTaskNotify( xTaskToNotify, 0, eNoAction ); xTaskNotify( xTaskToNotify, 0, eNoAction );
xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 ); xTaskNotifyWait( 0x00, ulBit1, &ulNotifiedValue, 0 );
/* However as the bit is cleared on exit, after the returned notification /* However as the bit is cleared on exit, after the returned notification
value is set, the returned notification value should not have the bit * value is set, the returned notification value should not have the bit
cleared... */ * cleared... */
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) ); configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
/* ...but reading the value back again should find that the bit was indeed /* ...but reading the value back again should find that the bit was indeed
cleared internally. The returned value should be pdFAIL however as nothing * cleared internally. The returned value should be pdFAIL however as nothing
has notified the task in the mean time. */ * has notified the task in the mean time. */
xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWait( 0x00, 0x00, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdFAIL ); configASSERT( xReturned == pdFAIL );
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) ); configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
@ -365,9 +352,8 @@ TimerHandle_t xSingleTaskTimer;
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Now try querying the previous value while notifying a task. */ * Now try querying the previous value while notifying a task. */
xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue ); xTaskNotifyAndQuery( xTaskToNotify, 0x00, eSetBits, &ulPreviousValue );
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) ); configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
@ -377,54 +363,53 @@ TimerHandle_t xSingleTaskTimer;
configASSERT( ulPreviousValue == 0 ); configASSERT( ulPreviousValue == 0 );
ulExpectedValue = 0; ulExpectedValue = 0;
for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL ) for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )
{ {
/* Set the next bit up, and expect to receive the last bits set (so /* 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 * the previous value will not yet have the bit being set this time
around). */ * around). */
xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue ); xTaskNotifyAndQuery( xTaskToNotify, ulLoop, eSetBits, &ulPreviousValue );
configASSERT( ulExpectedValue == ulPreviousValue ); configASSERT( ulExpectedValue == ulPreviousValue );
ulExpectedValue |= ulLoop; ulExpectedValue |= ulLoop;
} }
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
Clear the previous notifications. */ * Clear the previous notifications. */
xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 ); xTaskNotifyWait( notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
/* The task should not have any notifications pending, so an attempt to clear /* The task should not have any notifications pending, so an attempt to clear
the notification state should fail. */ * the notification state should fail. */
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE ); configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
/* Get the task to notify itself. This is not a normal thing to do, and is /* Get the task to notify itself. This is not a normal thing to do, and is
only done here for test purposes. */ * only done here for test purposes. */
xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue ); xTaskNotifyAndQuery( xTaskToNotify, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
/* Now the notification state should be eNotified, so it should now be /* Now the notification state should be eNotified, so it should now be
possible to clear the notification state. */ * possible to clear the notification state. */
configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE ); configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE ); configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
Clear bits in the notification value. */ * Clear bits in the notification value. */
/* Get the task to set all bits its own notification value. This is not a /* 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. */ * normal thing to do, and is only done here for test purposes. */
xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eSetBits ); xTaskNotify( xTaskToNotify, notifyUINT32_MAX, eSetBits );
/* Now clear the top bytes - the returned value from the first call should /* Now clear the top bytes - the returned value from the first call should
indicate that previously all bits were set. */ * indicate that previously all bits were set. */
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_HIGH_BYTE ) == notifyUINT32_MAX ); configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_HIGH_BYTE ) == notifyUINT32_MAX );
/* Next clear the bottom bytes - the returned value this time should indicate /* Next clear the bottom bytes - the returned value this time should indicate
that the top byte was clear (before the bottom byte was cleared. */ * that the top byte was clear (before the bottom byte was cleared. */
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_LOW_BYTE ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE ) ); configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_LOW_BYTE ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE ) );
/* Next clear all bytes - the returned value should indicate that previously the /* Next clear all bytes - the returned value should indicate that previously the
high and low bytes were clear. */ * high and low bytes were clear. */
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) ); configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) );
/* Now all bits should be clear. */ /* Now all bits should be clear. */
@ -433,14 +418,14 @@ TimerHandle_t xSingleTaskTimer;
configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == 0 ); configASSERT( ulTaskNotifyValueClear( xTaskToNotify, notifyUINT32_MAX ) == 0 );
/* Now the notification state should be eNotified, so it should now be /* Now the notification state should be eNotified, so it should now be
possible to clear the notification state. */ * possible to clear the notification state. */
configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE ); configASSERT( xTaskNotifyStateClear( NULL ) == pdTRUE );
configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE ); configASSERT( xTaskNotifyStateClear( NULL ) == pdFALSE );
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
Create a timer that will try notifying this task while it is suspended. */ * Create a timer that will try notifying this task while it is suspended. */
xSingleTaskTimer = xTimerCreate( "SingleNotify", notifySUSPENDED_TEST_TIMER_PERIOD, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback ); xSingleTaskTimer = xTimerCreate( "SingleNotify", notifySUSPENDED_TEST_TIMER_PERIOD, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback );
configASSERT( xSingleTaskTimer ); configASSERT( xSingleTaskTimer );
@ -451,13 +436,13 @@ TimerHandle_t xSingleTaskTimer;
xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 ); xTaskNotifyWait( notifyUINT32_MAX, 0, NULL, 0 );
/* Raise the task's priority so it can suspend itself before the timer /* Raise the task's priority so it can suspend itself before the timer
expires. */ * expires. */
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
/* Start the timer that will try notifying this task while it is /* Start the timer that will try notifying this task while it is
suspended, then wait for a notification. The first time the callback * suspended, then wait for a notification. The first time the callback
executes the timer will suspend the task, then resume the task, without * executes the timer will suspend the task, then resume the task, without
ever sending a notification to the task. */ * ever sending a notification to the task. */
ulNotifiedValue = 0; ulNotifiedValue = 0;
xTimerStart( xSingleTaskTimer, portMAX_DELAY ); xTimerStart( xSingleTaskTimer, portMAX_DELAY );
@ -471,9 +456,9 @@ TimerHandle_t xSingleTaskTimer;
ulNotifyCycleCount++; ulNotifyCycleCount++;
/* Start the timer that will try notifying this task while it is /* Start the timer that will try notifying this task while it is
suspended, then wait for a notification. The second time the callback * suspended, then wait for a notification. The second time the callback
executes the timer will suspend the task, notify the task, then resume the * executes the timer will suspend the task, notify the task, then resume the
task (previously it was suspended and resumed without being notified). */ * task (previously it was suspended and resumed without being notified). */
xTimerStart( xSingleTaskTimer, portMAX_DELAY ); xTimerStart( xSingleTaskTimer, portMAX_DELAY );
/* Check a notification is received. */ /* Check a notification is received. */
@ -483,7 +468,7 @@ TimerHandle_t xSingleTaskTimer;
configASSERT( ulNotifiedValue != 0 ); configASSERT( ulNotifiedValue != 0 );
/* Return the task to its proper priority and delete the timer as it is /* Return the task to its proper priority and delete the timer as it is
not used again. */ * not used again. */
vTaskPrioritySet( NULL, notifyTASK_PRIORITY ); vTaskPrioritySet( NULL, notifyTASK_PRIORITY );
xTimerDelete( xSingleTaskTimer, portMAX_DELAY ); xTimerDelete( xSingleTaskTimer, portMAX_DELAY );
@ -503,9 +488,9 @@ static uint32_t ulCallCount = 0;
( void ) xExpiredTimer; ( void ) xExpiredTimer;
/* Callback for a timer that is used during preliminary testing. The timer /* 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 * 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 * and then resumed without ever receiving a notification, and 2: when a task
waiting for a notification receives a notification while it is suspended. */ * waiting for a notification receives a notification while it is suspended. */
if( ulCallCount == 0 ) if( ulCallCount == 0 )
{ {
@ -518,8 +503,8 @@ static uint32_t ulCallCount = 0;
vTaskSuspend( xTaskToNotify ); vTaskSuspend( xTaskToNotify );
/* Sending a notification while the task is suspended should pass, but /* Sending a notification while the task is suspended should pass, but
not cause the task to resume. ulCallCount is just used as a convenient * not cause the task to resume. ulCallCount is just used as a convenient
non-zero value. */ * non-zero value. */
xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite ); xTaskNotify( xTaskToNotify, ulCallCount, eSetValueWithOverwrite );
/* Make sure giving the notification didn't resume the task. */ /* Make sure giving the notification didn't resume the task. */
@ -557,19 +542,20 @@ const uint32_t ulCyclesToRaisePriority = 50UL;
( void ) pvParameters; ( void ) pvParameters;
/* Run a few tests that can be done from a single task before entering the /* Run a few tests that can be done from a single task before entering the
main loop. */ * main loop. */
prvSingleTaskTests(); prvSingleTaskTests();
/* Create the software timer that is used to send notifications to this /* Create the software timer that is used to send notifications to this
task. Notifications are also received from an interrupt. */ * task. Notifications are also received from an interrupt. */
xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer ); xTimer = xTimerCreate( "Notifier", xMaxPeriod, pdFALSE, NULL, prvNotifyingTimer );
for( ; ; ) for( ; ; )
{ {
/* Start the timer again with a different period. Sometimes the period /* 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 * will be higher than the task's block time, sometimes it will be lower
than the task's block time. */ * than the task's block time. */
xPeriod = prvRand() % xMaxPeriod; xPeriod = prvRand() % xMaxPeriod;
if( xPeriod < xMinPeriod ) if( xPeriod < xMinPeriod )
{ {
xPeriod = xMinPeriod; xPeriod = xMinPeriod;
@ -579,47 +565,47 @@ const uint32_t ulCyclesToRaisePriority = 50UL;
xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY ); xTimerChangePeriod( xTimer, xPeriod, portMAX_DELAY );
/* Block waiting for the notification again with a different period. /* Block waiting for the notification again with a different period.
Sometimes the period will be higher than the task's block time, * Sometimes the period will be higher than the task's block time,
sometimes it will be lower than the task's block time. */ * sometimes it will be lower than the task's block time. */
xPeriod = prvRand() % xMaxPeriod; xPeriod = prvRand() % xMaxPeriod;
if( xPeriod < xMinPeriod ) if( xPeriod < xMinPeriod )
{ {
xPeriod = xMinPeriod; xPeriod = xMinPeriod;
} }
/* Block to wait for a notification but without clearing the /* Block to wait for a notification but without clearing the
notification count, so only add one to the count of received * notification count, so only add one to the count of received
notifications as any other notifications will remain pending. */ * notifications as any other notifications will remain pending. */
if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 ) if( ulTaskNotifyTake( pdFALSE, xPeriod ) != 0 )
{ {
ulTimerNotificationsReceived++; ulTimerNotificationsReceived++;
} }
/* Take a notification without clearing again, but this time without a /* Take a notification without clearing again, but this time without a
block time specified. */ * block time specified. */
if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 ) if( ulTaskNotifyTake( pdFALSE, xDontBlock ) != 0 )
{ {
ulTimerNotificationsReceived++; ulTimerNotificationsReceived++;
} }
/* Wait for the next notification from the timer, clearing all /* Wait for the next notification from the timer, clearing all
notifications if one is received, so this time adding the total number * notifications if one is received, so this time adding the total number
of notifications that were pending as none will be left pending after * of notifications that were pending as none will be left pending after
the function call. */ * the function call. */
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod ); ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, xPeriod );
/* Occasionally raise the priority of the task being notified to test /* 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 * the path where the task is notified from an ISR and becomes the highest
priority ready state task, but the pxHigherPriorityTaskWoken parameter * priority ready state task, but the pxHigherPriorityTaskWoken parameter
is NULL (which it is in the tick hook that sends notifications to this * is NULL (which it is in the tick hook that sends notifications to this
task). */ * task). */
if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 ) if( ( ulNotifyCycleCount % ulCyclesToRaisePriority ) == 0 )
{ {
vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 ); vTaskPrioritySet( xTaskToNotify, configMAX_PRIORITIES - 1 );
/* Wait for the next notification again, clearing all notifications /* Wait for the next notification again, clearing all notifications
if one is received, but this time blocking indefinitely. */ * if one is received, but this time blocking indefinitely. */
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
/* Reset the priority. */ /* Reset the priority. */
@ -628,7 +614,7 @@ const uint32_t ulCyclesToRaisePriority = 50UL;
else else
{ {
/* Wait for the next notification again, clearing all notifications /* Wait for the next notification again, clearing all notifications
if one is received, but this time blocking indefinitely. */ * if one is received, but this time blocking indefinitely. */
ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY ); ulTimerNotificationsReceived += ulTaskNotifyTake( pdTRUE, portMAX_DELAY );
} }
@ -649,9 +635,9 @@ const uint32_t ulUnexpectedValue = 0xff;
configASSERT( xTaskToNotify ); configASSERT( xTaskToNotify );
/* The task performs some tests before starting the timer that gives the /* The task performs some tests before starting the timer that gives the
notification from this interrupt. If the timer has not been created yet * notification from this interrupt. If the timer has not been created yet
then the initial tests have not yet completed and the notification should * then the initial tests have not yet completed and the notification should
not be sent. */ * not be sent. */
if( xTimer != NULL ) if( xTimer != NULL )
{ {
xCallCount++; xCallCount++;
@ -662,18 +648,21 @@ const uint32_t ulUnexpectedValue = 0xff;
xCallCount = 0; xCallCount = 0;
/* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR() /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
and xTaskNotifyAndQueryFromISR(). */ * and xTaskNotifyAndQueryFromISR(). */
switch( xAPIToUse ) switch( xAPIToUse )
{ {
case 0: vTaskNotifyGiveFromISR( xTaskToNotify, NULL ); case 0:
vTaskNotifyGiveFromISR( xTaskToNotify, NULL );
xAPIToUse++; xAPIToUse++;
break; break;
case 1: xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL ); case 1:
xTaskNotifyFromISR( xTaskToNotify, 0, eIncrement, NULL );
xAPIToUse++; xAPIToUse++;
break; break;
case 2: ulPreviousValue = ulUnexpectedValue; case 2:
ulPreviousValue = ulUnexpectedValue;
xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL ); xTaskNotifyAndQueryFromISR( xTaskToNotify, 0, eIncrement, &ulPreviousValue, NULL );
configASSERT( ulPreviousValue != ulUnexpectedValue ); configASSERT( ulPreviousValue != ulUnexpectedValue );
xAPIToUse = 0; xAPIToUse = 0;
@ -690,14 +679,14 @@ const uint32_t ulUnexpectedValue = 0xff;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check the created tasks are still running and have not /* This is called to check the created tasks are still running and have not
detected any errors. */ * detected any errors. */
BaseType_t xAreTaskNotificationTasksStillRunning( void ) BaseType_t xAreTaskNotificationTasksStillRunning( void )
{ {
static uint32_t ulLastNotifyCycleCount = 0; static uint32_t ulLastNotifyCycleCount = 0;
const uint32_t ulMaxSendReceiveDeviation = 5UL; const uint32_t ulMaxSendReceiveDeviation = 5UL;
/* Check the cycle count is still incrementing to ensure the task is still /* Check the cycle count is still incrementing to ensure the task is still
actually running. */ * actually running. */
if( ulLastNotifyCycleCount == ulNotifyCycleCount ) if( ulLastNotifyCycleCount == ulNotifyCycleCount )
{ {
xErrorStatus = pdFAIL; xErrorStatus = pdFAIL;
@ -708,7 +697,7 @@ const uint32_t ulMaxSendReceiveDeviation = 5UL;
} }
/* Check the count of 'takes' from the software timer is keeping track with /* Check the count of 'takes' from the software timer is keeping track with
the amount of 'gives'. */ * the amount of 'gives'. */
if( ulTimerNotificationsSent > ulTimerNotificationsReceived ) if( ulTimerNotificationsSent > ulTimerNotificationsReceived )
{ {
if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation ) if( ( ulTimerNotificationsSent - ulTimerNotificationsReceived ) > ulMaxSendReceiveDeviation )

View file

@ -122,14 +122,14 @@ static UBaseType_t prvRand( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Counters used to check the task has not stalled. ulFineCycleCount is /* Counters used to check the task has not stalled. ulFineCycleCount is
incremented within each test. ulCourseCycleCounter is incremented one every * incremented within each test. ulCourseCycleCounter is incremented one every
loop of all the tests to ensure each test is actually executing. The check task * loop of all the tests to ensure each test is actually executing. The check task
calls xAreTaskNotificationArrayTasksStillRunning() (implemented within this * calls xAreTaskNotificationArrayTasksStillRunning() (implemented within this
file) to check both counters are changing. */ * file) to check both counters are changing. */
static volatile uint32_t ulFineCycleCount = 0, ulCourseCycleCounter = 0; static volatile uint32_t ulFineCycleCount = 0, ulCourseCycleCounter = 0;
/* The handle of the task that runs the tests and receives the notifications /* The handle of the task that runs the tests and receives the notifications
from the software timers and interrupts. */ * from the software timers and interrupts. */
static TaskHandle_t xTaskToNotify = NULL; static TaskHandle_t xTaskToNotify = NULL;
/* The software timers used to send notifications to the main test task. */ /* The software timers used to send notifications to the main test task. */
@ -150,14 +150,14 @@ const TickType_t xIncrementingIndexTimerPeriod = pdMS_TO_TICKS( 100 );
const TickType_t xSuspendTimerPeriod = pdMS_TO_TICKS( 50 ); const TickType_t xSuspendTimerPeriod = pdMS_TO_TICKS( 50 );
/* Create the software timers used for these tests. The timer callbacks send /* Create the software timers used for these tests. The timer callbacks send
notifications to this task. */ * notifications to this task. */
xNotifyWhileSuspendedTimer = xTimerCreate( "SingleNotify", xSuspendTimerPeriod, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback ); xNotifyWhileSuspendedTimer = xTimerCreate( "SingleNotify", xSuspendTimerPeriod, pdFALSE, NULL, prvSuspendedTaskTimerTestCallback );
xIncrementingIndexTimer = xTimerCreate( "Notifier", xIncrementingIndexTimerPeriod, pdFALSE, NULL, prvNotifyingTimerCallback ); xIncrementingIndexTimer = xTimerCreate( "Notifier", xIncrementingIndexTimerPeriod, pdFALSE, NULL, prvNotifyingTimerCallback );
configASSERT( xNotifyWhileSuspendedTimer ); configASSERT( xNotifyWhileSuspendedTimer );
configASSERT( xIncrementingIndexTimer ); configASSERT( xIncrementingIndexTimer );
/* Create the task that performs some tests by itself, then loops around /* Create the task that performs some tests by itself, then loops around
being notified by both a software timer and an interrupt. */ * being notified by both a software timer and an interrupt. */
xTaskCreate( prvNotifiedTask, /* Function that implements the task. */ xTaskCreate( prvNotifiedTask, /* Function that implements the task. */
"ArrayNotifed", /* Text name for the task - for debugging only - not used by the kernel. */ "ArrayNotifed", /* 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!. */ notifyNOTIFY_ARRAY_TASK_STACK_SIZE, /* Task's stack size in words, not bytes!. */
@ -176,7 +176,7 @@ static void prvNotifiedTask( void *pvParameters )
( void ) pvParameters; ( void ) pvParameters;
/* Loop through each set of test functions in turn. See the comments above /* Loop through each set of test functions in turn. See the comments above
the respective function prototypes above for more details. */ * the respective function prototypes above for more details. */
for( ; ; ) for( ; ; )
{ {
prvSingleTaskTests(); prvSingleTaskTests();
@ -201,12 +201,12 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
Check blocking when there are no notifications. */ * Check blocking when there are no notifications. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* Send notifications to the task notification in each index of the /* Send notifications to the task notification in each index of the
task notification array other than the one on which this task will * task notification array other than the one on which this task will
block. */ * block. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
if( uxOtherIndexes != uxIndexToTest ) if( uxOtherIndexes != uxIndexToTest )
@ -229,7 +229,7 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
( void ) ulNotifiedValue; ( void ) ulNotifiedValue;
/* Clear all the other notifications within the array of task /* Clear all the other notifications within the array of task
notifications again ready for the next round. */ * notifications again ready for the next round. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
if( uxOtherIndexes != uxIndexToTest ) if( uxOtherIndexes != uxIndexToTest )
@ -237,26 +237,24 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
xReturned = xTaskNotifyStateClearIndexed( xTaskToNotify, uxOtherIndexes ); xReturned = xTaskNotifyStateClearIndexed( xTaskToNotify, uxOtherIndexes );
/* The notification state was set above so expect it to still be /* The notification state was set above so expect it to still be
set. */ * set. */
configASSERT( xReturned == pdTRUE ); configASSERT( xReturned == pdTRUE );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
} }
} }
} }
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
Check no blocking when notifications are pending. */ * Check no blocking when notifications are pending. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* First notify the task notification at index uxIndexToTest within this /* First notify the task notification at index uxIndexToTest within this
task's own array of task notifications - this would not be a normal * task's own array of task notifications - this would not be a normal
thing to do and is done here for test purposes only. */ * thing to do and is done here for test purposes only. */
xReturned = xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue ); xReturned = xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
/* Even through the 'without overwrite' action was used the update should /* Even through the 'without overwrite' action was used the update should
have been successful. */ * have been successful. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
@ -265,8 +263,8 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
( void ) ulPreviousValue; ( void ) ulPreviousValue;
/* The task should now have a notification pending in the task /* The task should now have a notification pending in the task
notification at index uxIndexToTest within the task notification array, * notification at index uxIndexToTest within the task notification array,
and so not time out. */ * and so not time out. */
xTimeOnEntering = xTaskGetTickCount(); xTimeOnEntering = xTaskGetTickCount();
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait ); xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, xTicksToWait );
xTimeNow = xTaskGetTickCount(); xTimeNow = xTaskGetTickCount();
@ -274,22 +272,19 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
configASSERT( xTimeDifference < xTicksToWait ); configASSERT( xTimeDifference < xTicksToWait );
/* The task should have been notified, and the notified value should /* The task should have been notified, and the notified value should
be equal to ulFirstNotifiedConst. */ * be equal to ulFirstNotifiedConst. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
( void ) ulNotifiedValue; ( void ) ulNotifiedValue;
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Check the non-overwriting functionality. */ * Check the non-overwriting functionality. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* Send notifications to all indexes with the array of task /* Send notifications to all indexes with the array of task
notifications other than the one on which this task will block. */ * notifications other than the one on which this task will block. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
if( uxOtherIndexes != uxIndexToTest ) if( uxOtherIndexes != uxIndexToTest )
@ -301,10 +296,10 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
} }
/* The notification is performed twice using two different notification /* The notification is performed twice using two different notification
values. The action says don't overwrite so only the first 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 * 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 * first notification. The notification is sent to the task notification at
index uxIndexToTest within the array of task notifications. */ * index uxIndexToTest within the array of task notifications. */
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite ); xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
@ -314,7 +309,7 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
/* Waiting for the notification should now return immediately so a block /* Waiting for the notification should now return immediately so a block
time of zero is used. */ * time of zero is used. */
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, notifyUINT32_MAX, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
@ -323,7 +318,7 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
( void ) ulNotifiedValue; ( void ) ulNotifiedValue;
/* Clear all the other task notifications within the array of task /* Clear all the other task notifications within the array of task
notifications again ready for the next round. */ * notifications again ready for the next round. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
if( uxOtherIndexes != uxIndexToTest ) if( uxOtherIndexes != uxIndexToTest )
@ -335,21 +330,18 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
ulNotifiedValue = ulTaskNotifyValueClearIndexed( xTaskToNotify, uxOtherIndexes, notifyUINT32_MAX ); ulNotifiedValue = ulTaskNotifyValueClearIndexed( xTaskToNotify, uxOtherIndexes, notifyUINT32_MAX );
/* The notification value was set to ulFirstNotifiedConst in all /* The notification value was set to ulFirstNotifiedConst in all
the other indexes, so expect it to still have that value. */ * the other indexes, so expect it to still have that value. */
configASSERT( ulNotifiedValue == ulFirstNotifiedConst ); configASSERT( ulNotifiedValue == ulFirstNotifiedConst );
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
} }
} }
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Do the same again, only this time use the overwriting version. This time * 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 * 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 * overwrite the value written the first time, and so be the value that is read
back. */ * back. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
@ -386,43 +378,40 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
} }
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
For each task notification within the array of task notifications, check * For each task notification within the array of task notifications, check
notifications with no action pass without updating the value. */ * notifications with no action pass without updating the value. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* First set the notification values of the task notification at index /* First set the notification values of the task notification at index
uxIndexToTest of the array of task notification to * uxIndexToTest of the array of task notification to
ulSecondNotifiedValueConst. */ * ulSecondNotifiedValueConst. */
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulSecondNotifiedValueConst, eSetValueWithOverwrite ); xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulSecondNotifiedValueConst, eSetValueWithOverwrite );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
/* Even though ulFirstNotifiedConst is used as the value next, the value /* Even though ulFirstNotifiedConst is used as the value next, the value
read back should remain at ulSecondNotifiedConst as the action is set * read back should remain at ulSecondNotifiedConst as the action is set
to eNoAction. */ * to eNoAction. */
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eNoAction ); xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eNoAction );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
/* All task notifications in the array of task notifications up to and /* All task notifications in the array of task notifications up to and
including index uxIndexToTest should still contain the same value. */ * including index uxIndexToTest should still contain the same value. */
for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ )
{ {
/* First zero is bits to clear on entry, the second is bits to clear on /* First zero is bits to clear on entry, the second is bits to clear on
exist, the last 0 is the block time. */ * exist, the last 0 is the block time. */
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst ); configASSERT( ulNotifiedValue == ulSecondNotifiedValueConst );
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
} }
/* All array indexes in the array of task notifications after index /* All array indexes in the array of task notifications after index
uxIndexToTest should still contain 0 as they have not been set in this * uxIndexToTest should still contain 0 as they have not been set in this
loop yet. This time use ulTaskNotifyValueClearIndexed() instead of * loop yet. This time use ulTaskNotifyValueClearIndexed() instead of
xTaskNotifyWaitIndexed(), just for test coverage. */ * xTaskNotifyWaitIndexed(), just for test coverage. */
for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
/* This time 0 is the bits to clear parameter - so clearing no bits. */ /* This time 0 is the bits to clear parameter - so clearing no bits. */
@ -432,31 +421,28 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
} }
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Check incrementing values. For each task notification in the array of task * Check incrementing values. For each task notification in the array of task
notifications in turn, send ulMaxLoop increment notifications, then ensure * notifications in turn, send ulMaxLoop increment notifications, then ensure
the received value is as expected - which should be * the received value is as expected - which should be
ulSecondNotificationValueConst plus how ever many times to loop iterated. */ * ulSecondNotificationValueConst plus how ever many times to loop iterated. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ ) for( ulLoop = 0; ulLoop < ulMaxLoops; ulLoop++ )
{ {
/* Increment the value of the task notification at index /* Increment the value of the task notification at index
uxIndexToTest within the array of task notifications. */ * uxIndexToTest within the array of task notifications. */
xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, 0, eIncrement ); xReturned = xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, 0, eIncrement );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
} }
/* All array indexes up to and including uxIndexToTest should still /* All array indexes up to and including uxIndexToTest should still
contain the updated value. */ * contain the updated value. */
for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ )
{ {
/* First zero is bits to clear on entry, the second is bits to clear on /* First zero is bits to clear on entry, the second is bits to clear on
exist, the last 0 is the block time. */ * exist, the last 0 is the block time. */
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) ); configASSERT( ulNotifiedValue == ( ulSecondNotifiedValueConst + ulMaxLoops ) );
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
@ -469,10 +455,10 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
( void ) ulNotifiedValue; ( void ) ulNotifiedValue;
/* All notifications values in the array of task notifications after /* All notifications values in the array of task notifications after
index uxIndexToTest should still contain the un-incremented * index uxIndexToTest should still contain the un-incremented
ulSecondNotifiedValueConst as they have not been set in this loop yet. * ulSecondNotifiedValueConst as they have not been set in this loop yet.
This time use ulTaskNotifyValueClearIndexed() instead of xTaskNotifyWaitIndexed(), * This time use ulTaskNotifyValueClearIndexed() instead of xTaskNotifyWaitIndexed(),
just for test coverage. */ * just for test coverage. */
for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
/* This time 0 is the bits to clear parameter - so clearing no bits. */ /* This time 0 is the bits to clear parameter - so clearing no bits. */
@ -489,14 +475,12 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
ulTaskNotifyValueClearIndexed( NULL, uxIndexToTest, notifyUINT32_MAX ); ulTaskNotifyValueClearIndexed( NULL, uxIndexToTest, notifyUINT32_MAX );
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
For each task notification in the array of task notifications in turn, check * 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 * 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 * 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 * 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. */ * 32 times before all the bits are found to be set. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
ulNotifyingValue = 0x01; ulNotifyingValue = 0x01;
@ -505,12 +489,12 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
do do
{ {
/* Set the next bit in the value of the task notification at index /* Set the next bit in the value of the task notification at index
uxIndexToTest within the array of task notifications. */ * uxIndexToTest within the array of task notifications. */
xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulNotifyingValue, eSetBits ); xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, ulNotifyingValue, eSetBits );
/* Wait for the notified value - which of course will already be /* 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 * available. Don't clear the bits on entry or exit as this loop is
exited when all the bits are set. */ * exited when all the bits are set. */
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
@ -519,29 +503,28 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
/* Use the next bit on the next iteration around this loop. */ /* Use the next bit on the next iteration around this loop. */
ulNotifyingValue <<= 1UL; ulNotifyingValue <<= 1UL;
} while( ulNotifiedValue != notifyUINT32_MAX ); } while( ulNotifiedValue != notifyUINT32_MAX );
/* As a 32-bit value was used the loop should have executed 32 times before /* As a 32-bit value was used the loop should have executed 32 times before
all the bits were set. */ * all the bits were set. */
configASSERT( ulLoop == 32 ); configASSERT( ulLoop == 32 );
/* The value of each task notification within the array of task /* The value of each task notification within the array of task
notifications up to and including index uxIndexToTest should still have * notifications up to and including index uxIndexToTest should still have
all bits set. */ * all bits set. */
for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ )
{ {
/* First zero is bits to clear on entry, the second is bits to clear on /* First zero is bits to clear on entry, the second is bits to clear on
exist, the last 0 is the block time. */ * exist, the last 0 is the block time. */
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
configASSERT( ulNotifiedValue == notifyUINT32_MAX ); configASSERT( ulNotifiedValue == notifyUINT32_MAX );
( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) ulNotifiedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
} }
/* The value of each task notification within the array of task /* The value of each task notification within the array of task
notifications after index uxIndexToTest should still contain 0 as they * notifications after index uxIndexToTest should still contain 0 as they
have not been set in this loop yet. This time use ulTaskNotifyValueClearIndexed() * have not been set in this loop yet. This time use ulTaskNotifyValueClearIndexed()
instead of xTaskNotifyWaitIndexed(), just for test coverage. */ * instead of xTaskNotifyWaitIndexed(), just for test coverage. */
for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
/* This time 0 is the bits to clear parameter - so clearing no bits. */ /* This time 0 is the bits to clear parameter - so clearing no bits. */
@ -551,40 +534,39 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
} }
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
For each task notification within the array of task notifications in turn, * 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 * 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. */ * to arrive before timing out - both with and without a timeout value. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* Wait for the notification - but this time it is not given by anything /* 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 * 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 * entry and bit one on exit. As no notification was received only the bit
cleared on entry should actually get cleared. */ * cleared on entry should actually get cleared. */
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait ); xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, ulBit0, ulBit1, &ulNotifiedValue, xTicksToWait );
configASSERT( xReturned == pdFAIL ); configASSERT( xReturned == pdFAIL );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
/* Send a notification with no action to the task notification at index /* Send a notification with no action to the task notification at index
uxIndexToTest within the array of task notifications. This should not * uxIndexToTest within the array of task notifications. This should not
update the bits even though notifyUINT32_MAX is used as the notification * update the bits even though notifyUINT32_MAX is used as the notification
value. */ * value. */
xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX, eNoAction ); xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX, eNoAction );
/* All array indexes up to and including uxIndexToTest within the array /* All array indexes up to and including uxIndexToTest within the array
of task notifications should have the modified value. */ * of task notifications should have the modified value. */
for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes <= uxIndexToTest; uxOtherIndexes++ )
{ {
/* Reading back the value should find bit 0 is clear, as this was cleared /* 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 * on entry, but bit 1 is not clear as it will not have been cleared on exit
as no notification was received. */ * as no notification was received. */
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0x00UL, 0x00UL, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0x00UL, 0x00UL, &ulNotifiedValue, 0 );
if( uxOtherIndexes == uxIndexToTest ) if( uxOtherIndexes == uxIndexToTest )
{ {
/* This is the index being used this time round the loop and its /* This is the index being used this time round the loop and its
notification state was set immediately above. */ * notification state was set immediately above. */
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
} }
else else
@ -598,8 +580,8 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
} }
/* All array indexes after uxIndexToTest should still contain notifyUINT32_MAX /* All array indexes after uxIndexToTest should still contain notifyUINT32_MAX
left over from the previous test. This time use xTaskNotifyValueClear() * left over from the previous test. This time use xTaskNotifyValueClear()
instead of xTaskNotifyWaitIndexed(), just for test coverage. */ * instead of xTaskNotifyWaitIndexed(), just for test coverage. */
for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = uxIndexToTest + 1; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
/* This time 0 is the bits to clear parameter - so clearing no bits. */ /* This time 0 is the bits to clear parameter - so clearing no bits. */
@ -609,26 +591,23 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
} }
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
Now try clearing the bit on exit. */ * Now try clearing the bit on exit. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* The task is notified first using the task notification at index /* The task is notified first using the task notification at index
uxIndexToTest within the array of task notifications. */ * uxIndexToTest within the array of task notifications. */
xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, 0, eNoAction ); xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, 0, eNoAction );
xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, ulBit1, &ulNotifiedValue, 0 ); xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, ulBit1, &ulNotifiedValue, 0 );
/* However as the bit is cleared on exit, after the returned notification /* However as the bit is cleared on exit, after the returned notification
value is set, the returned notification value should not have the bit * value is set, the returned notification value should not have the bit
cleared... */ * cleared... */
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) ); configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~ulBit0 ) );
/* ...but reading the value back again should find that the bit was indeed /* ...but reading the value back again should find that the bit was indeed
cleared internally. The returned value should be pdFAIL however as nothing * cleared internally. The returned value should be pdFAIL however as nothing
has notified the task in the mean time. */ * has notified the task in the mean time. */
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, 0x00, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0x00, 0x00, &ulNotifiedValue, 0 );
configASSERT( xReturned == pdFAIL ); configASSERT( xReturned == pdFAIL );
configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) ); configASSERT( ulNotifiedValue == ( notifyUINT32_MAX & ~( ulBit0 | ulBit1 ) ) );
@ -646,11 +625,9 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
} }
} }
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
For each task notification within the array of task notifications, try * For each task notification within the array of task notifications, try
querying the previous value while notifying a task. */ * querying the previous value while notifying a task. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, 0x00, eSetBits, &ulPreviousValue ); xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, 0x00, eSetBits, &ulPreviousValue );
@ -662,18 +639,18 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
configASSERT( ulPreviousValue == 0 ); configASSERT( ulPreviousValue == 0 );
ulExpectedValue = 0; ulExpectedValue = 0;
for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL ) for( ulLoop = 0x01; ulLoop < 0x80UL; ulLoop <<= 1UL )
{ {
/* Set the next bit up, and expect to receive the last bits set (so /* 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 * the previous value will not yet have the bit being set this time
around). */ * around). */
xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulLoop, eSetBits, &ulPreviousValue ); xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulLoop, eSetBits, &ulPreviousValue );
configASSERT( ulExpectedValue == ulPreviousValue ); configASSERT( ulExpectedValue == ulPreviousValue );
ulExpectedValue |= ulLoop; ulExpectedValue |= ulLoop;
} }
} }
/* ---------------------------------------------------------------------- */ /* ---------------------------------------------------------------------- */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
@ -684,22 +661,22 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* No task notification within the array of task notifications should /* No task notification within the array of task notifications should
have any notification pending, so an attempt to clear the notification * have any notification pending, so an attempt to clear the notification
state should fail. */ * state should fail. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
configASSERT( xTaskNotifyStateClearIndexed( NULL, uxOtherIndexes ) == pdFALSE ); configASSERT( xTaskNotifyStateClearIndexed( NULL, uxOtherIndexes ) == pdFALSE );
} }
/* Get the task to notify itself using the task notification at index /* Get the task to notify itself using the task notification at index
uxIndexToTest within the array of task notifications. This is not a * uxIndexToTest within the array of task notifications. This is not a
normal thing to do, and is only done here for test purposes. */ * normal thing to do, and is only done here for test purposes. */
xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue ); xTaskNotifyAndQueryIndexed( xTaskToNotify, uxIndexToTest, ulFirstNotifiedConst, eSetValueWithoutOverwrite, &ulPreviousValue );
/* Now the notification state should be eNotified, so it should now be /* Now the notification state should be eNotified, so it should now be
possible to clear the notification state. Other indexes should still * possible to clear the notification state. Other indexes should still
not have a notification pending - likewise uxIndexToTest should not have * not have a notification pending - likewise uxIndexToTest should not have
a notification pending once it has been cleared. */ * a notification pending once it has been cleared. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
if( uxOtherIndexes == uxIndexToTest ) if( uxOtherIndexes == uxIndexToTest )
@ -711,28 +688,27 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
} }
} }
/* ------------------------------------------------------------------------ /* ------------------------------------------------------------------------
For each task notification within the array of task notifications, clear * For each task notification within the array of task notifications, clear
bits in the notification value. */ * bits in the notification value. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* Get the task to set all bits in its task notification at index /* Get the task to set all bits in its task notification at index
uxIndexToTest within its array of task notifications. This is not a * uxIndexToTest within its array of task notifications. This is not a
normal thing to do, and is only done here for test purposes. */ * normal thing to do, and is only done here for test purposes. */
xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX, eSetBits ); xTaskNotifyIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX, eSetBits );
/* Now clear the top bytes - the returned value from the first call /* Now clear the top bytes - the returned value from the first call
should indicate that previously all bits were set. */ * should indicate that previously all bits were set. */
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_HIGH_BYTE ) == notifyUINT32_MAX ); configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_HIGH_BYTE ) == notifyUINT32_MAX );
/* Next clear the bottom bytes - the returned value this time should /* Next clear the bottom bytes - the returned value this time should
indicate that the top byte was clear (before the bottom byte was * indicate that the top byte was clear (before the bottom byte was
cleared. */ * cleared. */
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_LOW_BYTE ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE ) ); configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_LOW_BYTE ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE ) );
/* Next clear all bytes - the returned value should indicate that previously the /* Next clear all bytes - the returned value should indicate that previously the
high and low bytes were clear. */ * high and low bytes were clear. */
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) ); configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == ( notifyUINT32_MAX & ~notifyUINT32_HIGH_BYTE & ~notifyUINT32_LOW_BYTE ) );
/* Now all bits should be clear. */ /* Now all bits should be clear. */
@ -741,14 +717,11 @@ UBaseType_t uxIndexToTest, uxOtherIndexes;
configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == 0 ); configASSERT( ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToTest, notifyUINT32_MAX ) == 0 );
/* Now the notification state should be eNotified, so it should now be /* Now the notification state should be eNotified, so it should now be
possible to clear the notification state. */ * possible to clear the notification state. */
configASSERT( xTaskNotifyStateClearIndexed( NULL, uxIndexToTest ) == pdTRUE ); configASSERT( xTaskNotifyStateClearIndexed( NULL, uxIndexToTest ) == pdTRUE );
configASSERT( xTaskNotifyStateClearIndexed( NULL, uxIndexToTest ) == pdFALSE ); configASSERT( xTaskNotifyStateClearIndexed( NULL, uxIndexToTest ) == pdFALSE );
} }
/* Incremented to show the task is still running. */ /* Incremented to show the task is still running. */
ulFineCycleCount++; ulFineCycleCount++;
@ -769,12 +742,12 @@ static UBaseType_t uxIndexToNotify = 0;
( void ) xExpiredTimer; ( void ) xExpiredTimer;
/* Callback for a timer that is used to send notifications to a task while /* 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 * 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 is suspended and then resumed without ever receiving a
notification, and 2: when a task waiting for a notification receives 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 * notification while it is suspended. Run one of two tests on every other
invocation of this callback. The notification is sent to the task * invocation of this callback. The notification is sent to the task
notification at index uxIndexToNotify. */ * notification at index uxIndexToNotify. */
if( ( ulCallCount & 0x01 ) == 0 ) if( ( ulCallCount & 0x01 ) == 0 )
{ {
vTaskSuspend( xTaskToNotify ); vTaskSuspend( xTaskToNotify );
@ -786,12 +759,13 @@ static UBaseType_t uxIndexToNotify = 0;
vTaskSuspend( xTaskToNotify ); vTaskSuspend( xTaskToNotify );
/* Sending a notification while the task is suspended should pass, but /* Sending a notification while the task is suspended should pass, but
not cause the task to resume. */ * not cause the task to resume. */
xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, 1, eSetValueWithOverwrite ); xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, 1, eSetValueWithOverwrite );
/* Use the next task notification within the array of task notifications /* Use the next task notification within the array of task notifications
the next time around. */ * the next time around. */
uxIndexToNotify++; uxIndexToNotify++;
if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES ) if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES )
{ {
uxIndexToNotify = 0; uxIndexToNotify = 0;
@ -814,13 +788,14 @@ static BaseType_t uxIndexToNotify = 0;
( void ) xNotUsed; ( void ) xNotUsed;
/* "Give" the task notification (which increments the target task /* "Give" the task notification (which increments the target task
notification value) at index uxIndexToNotify within the array of task * notification value) at index uxIndexToNotify within the array of task
notifications. */ * notifications. */
xTaskNotifyGiveIndexed( xTaskToNotify, uxIndexToNotify ); xTaskNotifyGiveIndexed( xTaskToNotify, uxIndexToNotify );
/* Use the next task notification within the array of task notifications the /* Use the next task notification within the array of task notifications the
next time around. */ * next time around. */
uxIndexToNotify++; uxIndexToNotify++;
if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES ) if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES )
{ {
uxIndexToNotify = 0; uxIndexToNotify = 0;
@ -835,15 +810,15 @@ BaseType_t xReturned;
uint32_t ulNotifiedValue; uint32_t ulNotifiedValue;
/* Raise the task's priority so it can suspend itself before the timer /* Raise the task's priority so it can suspend itself before the timer
expires. */ * expires. */
vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 ); vTaskPrioritySet( NULL, configMAX_PRIORITIES - 1 );
/* Perform the test on each task notification within the array or task /* Perform the test on each task notification within the array or task
notifications. */ * notifications. */
for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ ) for( uxIndexToTest = 0; uxIndexToTest < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToTest++ )
{ {
/* Ensure no notifications within the array of task notifications are /* Ensure no notifications within the array of task notifications are
pending. */ * pending. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, NULL, 0 ); xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, NULL, 0 );
@ -852,21 +827,21 @@ uint32_t ulNotifiedValue;
} }
/* Start the timer that will try notifying this task while it is /* Start the timer that will try notifying this task while it is
suspended, then wait for a notification. The first time the callback * suspended, then wait for a notification. The first time the callback
executes the timer will suspend the task, then resume the task, without * executes the timer will suspend the task, then resume the task, without
ever sending a notification to the task. */ * ever sending a notification to the task. */
ulNotifiedValue = 0; ulNotifiedValue = 0;
xTimerStart( xNotifyWhileSuspendedTimer, portMAX_DELAY ); xTimerStart( xNotifyWhileSuspendedTimer, portMAX_DELAY );
/* Check a notification is not received on the task notification at /* Check a notification is not received on the task notification at
index uxIndexToTest within the array of task notifications. */ * index uxIndexToTest within the array of task notifications. */
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, portMAX_DELAY ); xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, portMAX_DELAY );
configASSERT( xReturned == pdFALSE ); configASSERT( xReturned == pdFALSE );
configASSERT( ulNotifiedValue == 0 ); configASSERT( ulNotifiedValue == 0 );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
/* Check none of the task notifications within the array of task /* Check none of the task notifications within the array of task
notifications as been notified. */ * notifications as been notified. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
@ -875,23 +850,23 @@ uint32_t ulNotifiedValue;
} }
/* Start the timer that will try notifying this task while it is /* Start the timer that will try notifying this task while it is
suspended, then wait for a notification at index uxIndexToTest within * suspended, then wait for a notification at index uxIndexToTest within
the array of task notifications. The second time the callback executes * the array of task notifications. The second time the callback executes
the timer will suspend the task, notify the task, then resume the task * the timer will suspend the task, notify the task, then resume the task
(previously it was suspended and resumed without being notified). */ * (previously it was suspended and resumed without being notified). */
xTimerStart( xNotifyWhileSuspendedTimer, portMAX_DELAY ); xTimerStart( xNotifyWhileSuspendedTimer, portMAX_DELAY );
/* Check a notification is only received in the index within the array /* Check a notification is only received in the index within the array
of task notifications under test. */ * of task notifications under test. */
xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, portMAX_DELAY ); xReturned = xTaskNotifyWaitIndexed( uxIndexToTest, 0, 0, &ulNotifiedValue, portMAX_DELAY );
configASSERT( xReturned == pdPASS ); configASSERT( xReturned == pdPASS );
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
configASSERT( ulNotifiedValue != 0 ); configASSERT( ulNotifiedValue != 0 );
/* Check a notification is not received in any index within the array /* 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 * 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 * value, and that indexes above the index being tested to not have
notification values. */ * notification values. */
for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ ) for( uxOtherIndexes = 0; uxOtherIndexes < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxOtherIndexes++ )
{ {
xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 ); xReturned = xTaskNotifyWaitIndexed( uxOtherIndexes, 0, 0, &ulNotifiedValue, 0 );
@ -905,6 +880,7 @@ uint32_t ulNotifiedValue;
{ {
configASSERT( ulNotifiedValue == 0 ); configASSERT( ulNotifiedValue == 0 );
} }
( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) xReturned; /* Remove compiler warnings in case configASSERT() is not defined. */
( void ) ulNotifiedValue; ( void ) ulNotifiedValue;
} }
@ -932,9 +908,9 @@ uint32_t ulReceivedValue;
BaseType_t xReturned; BaseType_t xReturned;
/* Set the value of each notification in the array of task notifications to /* 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 * 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 * state, then clear the notification state ready for the next test. Plus 1 is
used because the index under test will use 0. */ * used because the index under test will use 0. */
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
{ {
xTaskNotifyIndexed( xTaskToNotify, uxIndex, uxIndex + 1, eSetValueWithOverwrite ); xTaskNotifyIndexed( xTaskToNotify, uxIndex, uxIndex + 1, eSetValueWithOverwrite );
@ -942,30 +918,30 @@ BaseType_t xReturned;
} }
/* Peform the test on each task notification within the array of task /* Peform the test on each task notification within the array of task
notifications. */ * notifications. */
for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ ) for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ )
{ {
/* Set the notification value of the index being tested to 0 so the /* Set the notification value of the index being tested to 0 so the
notification value increment/decrement functions can be tested. */ * notification value increment/decrement functions can be tested. */
xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, 0, eSetValueWithOverwrite ); xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, 0, eSetValueWithOverwrite );
xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndexToNotify ); xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndexToNotify );
/* Start the software timer then wait for it to notify this task. Block /* 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 * on the notification index we expect to receive the notification on. The
margin is to ensure the task blocks longer than the timer period. */ * margin is to ensure the task blocks longer than the timer period. */
xTimerStart( xIncrementingIndexTimer, portMAX_DELAY ); xTimerStart( xIncrementingIndexTimer, portMAX_DELAY );
ulReceivedValue = ulTaskNotifyTakeIndexed( uxIndexToNotify, pdFALSE, xTimerPeriod + xMargin ); ulReceivedValue = ulTaskNotifyTakeIndexed( uxIndexToNotify, pdFALSE, xTimerPeriod + xMargin );
/* The notification value was initially zero, and should have been /* The notification value was initially zero, and should have been
incremented by the software timer, so now one. It will also 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 * decremented again by the call to ulTaskNotifyTakeIndexed() so gone back
to 0. */ * to 0. */
configASSERT( ulReceivedValue == 1UL ); configASSERT( ulReceivedValue == 1UL );
( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
/* No other notification indexes should have changed, and therefore should /* No other notification indexes should have changed, and therefore should
still have their value set to their index plus 1 within the array of * still have their value set to their index plus 1 within the array of
notifications. */ * notifications. */
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
{ {
if( uxIndex != uxIndexToNotify ) if( uxIndex != uxIndexToNotify )
@ -979,7 +955,7 @@ BaseType_t xReturned;
} }
/* Reset the notification value for the index just tested back to the /* Reset the notification value for the index just tested back to the
index value plus 1 ready for the next iteration around this loop. */ * index value plus 1 ready for the next iteration around this loop. */
xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, uxIndexToNotify + 1, eSetValueWithOverwrite ); xTaskNotifyIndexed( xTaskToNotify, uxIndexToNotify, uxIndexToNotify + 1, eSetValueWithOverwrite );
xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndexToNotify ); xTaskNotifyStateClearIndexed( xTaskToNotify, uxIndexToNotify );
@ -998,42 +974,41 @@ BaseType_t xReturned;
TickType_t xTimeBeforeBlocking, xTimeNow, xTimeDifference; TickType_t xTimeBeforeBlocking, xTimeNow, xTimeDifference;
/* Set all notify values within the array of tasks notifications to zero /* Set all notify values within the array of tasks notifications to zero
ready for the next test. */ * ready for the next test. */
for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ ) for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ )
{ {
ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToNotify, notifyUINT32_MAX ); ulTaskNotifyValueClearIndexed( xTaskToNotify, uxIndexToNotify, notifyUINT32_MAX );
} }
/* Perform the test for each notification within the array of task /* Perform the test for each notification within the array of task
notifications. */ * notifications. */
for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ ) for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ )
{ {
/* Start the software timer then wait for it to notify this task. Block /* 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 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. */ * on. The margin is to ensure the task blocks longer than the timer period. */
xTimerStart( xIncrementingIndexTimer, portMAX_DELAY ); xTimerStart( xIncrementingIndexTimer, portMAX_DELAY );
xTimeBeforeBlocking = xTaskGetTickCount(); xTimeBeforeBlocking = xTaskGetTickCount();
if( uxIndexToNotify == ( configTASK_NOTIFICATION_ARRAY_ENTRIES - 1 ) ) if( uxIndexToNotify == ( configTASK_NOTIFICATION_ARRAY_ENTRIES - 1 ) )
{ {
/* configTASK_NOTIFICATION_ARRAY_ENTRIES - 1 is to be notified, so /* configTASK_NOTIFICATION_ARRAY_ENTRIES - 1 is to be notified, so
block on index 0. */ * block on index 0. */
uxIndex = 0; uxIndex = 0;
} }
else else
{ {
/* The next index to get notified will be uxIndexToNotify, so block /* The next index to get notified will be uxIndexToNotify, so block
on uxIndexToNotify + 1 */ * on uxIndexToNotify + 1 */
uxIndex = uxIndexToNotify + 1; uxIndex = uxIndexToNotify + 1;
} }
xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xTimerPeriod + xMargin ); xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xTimerPeriod + xMargin );
/* The notification will have been sent to task notification at index /* The notification will have been sent to task notification at index
uxIndexToNotify in this task by the timer callback after xTimerPeriodTicks. * uxIndexToNotify in this task by the timer callback after xTimerPeriodTicks.
The notification should not have woken this task, so xReturned should * The notification should not have woken this task, so xReturned should
be false and at least xTimerPeriod + xMargin ticks should have passed. */ * be false and at least xTimerPeriod + xMargin ticks should have passed. */
configASSERT( xReturned == pdFALSE ); configASSERT( xReturned == pdFALSE );
xTimeNow = xTaskGetTickCount(); xTimeNow = xTaskGetTickCount();
xTimeDifference = xTimeNow - xTimeBeforeBlocking; xTimeDifference = xTimeNow - xTimeBeforeBlocking;
@ -1043,7 +1018,7 @@ TickType_t xTimeBeforeBlocking, xTimeNow, xTimeDifference;
( void ) xTimeDifference; ( void ) xTimeDifference;
/* Only the notification at index position uxIndexToNotify should be /* Only the notification at index position uxIndexToNotify should be
set. Calling this function will clear it again. */ * set. Calling this function will clear it again. */
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
{ {
xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xDontBlock ); xReturned = xTaskNotifyWaitIndexed( uxIndex, 0, 0, &ulReceivedValue, xDontBlock );
@ -1051,7 +1026,7 @@ TickType_t xTimeBeforeBlocking, xTimeNow, xTimeDifference;
if( uxIndex == uxIndexToNotify ) if( uxIndex == uxIndexToNotify )
{ {
/* Expect the notification state to be set and the notification /* Expect the notification state to be set and the notification
value to have been incremented. */ * value to have been incremented. */
configASSERT( xReturned == pdTRUE ); configASSERT( xReturned == pdTRUE );
configASSERT( ulReceivedValue == 1 ); configASSERT( ulReceivedValue == 1 );
@ -1061,7 +1036,7 @@ TickType_t xTimeBeforeBlocking, xTimeNow, xTimeDifference;
else else
{ {
/* Expect the notification state to be clear and the notification /* Expect the notification state to be clear and the notification
value to remain at zer0. */ * value to remain at zer0. */
configASSERT( xReturned == pdFALSE ); configASSERT( xReturned == pdFALSE );
configASSERT( ulReceivedValue == 0 ); configASSERT( ulReceivedValue == 0 );
} }
@ -1081,7 +1056,7 @@ BaseType_t xReturned;
const TickType_t xDontBlock = 0; const TickType_t xDontBlock = 0;
/* Set the value of each notification within the array of task notifications /* Set the value of each notification within the array of task notifications
to zero so the task can block on xTaskNotifyTake(). */ * to zero so the task can block on xTaskNotifyTake(). */
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
{ {
xTaskNotifyIndexed( xTaskToNotify, uxIndex, 0, eSetValueWithOverwrite ); xTaskNotifyIndexed( xTaskToNotify, uxIndex, 0, eSetValueWithOverwrite );
@ -1089,37 +1064,37 @@ const TickType_t xDontBlock = 0;
} }
/* Perform the test on each task notification within the array of task /* Perform the test on each task notification within the array of task
notifications. */ * notifications. */
for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ ) for( uxIndexToNotify = 0; uxIndexToNotify < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndexToNotify++ )
{ {
/* Tell the interrupt to send the next notification. */ /* Tell the interrupt to send the next notification. */
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
/* Don't expect to find xSendNotificationFromISR set at this time as /* Don't expect to find xSendNotificationFromISR set at this time as
the interrupt should have cleared it back to pdFALSE last time it * the interrupt should have cleared it back to pdFALSE last time it
executed. */ * executed. */
configASSERT( xSendNotificationFromISR == pdFALSE ); configASSERT( xSendNotificationFromISR == pdFALSE );
xSendNotificationFromISR = pdTRUE; xSendNotificationFromISR = pdTRUE;
} }
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
/* Wait for a notification on the task notification at index /* Wait for a notification on the task notification at index
uxIndexToNotify within the array of task notifications. */ * uxIndexToNotify within the array of task notifications. */
ulReceivedValue = ulTaskNotifyTakeIndexed( uxIndexToNotify, pdTRUE, portMAX_DELAY ); ulReceivedValue = ulTaskNotifyTakeIndexed( uxIndexToNotify, pdTRUE, portMAX_DELAY );
/* Interrupt should have reset xSendNotificationFromISR after it sent /* Interrupt should have reset xSendNotificationFromISR after it sent
the notification. */ * the notification. */
configASSERT( xSendNotificationFromISR == pdFALSE ); configASSERT( xSendNotificationFromISR == pdFALSE );
/* The notification value was initially zero, and should have been /* The notification value was initially zero, and should have been
incremented by the interrupt, so now one. */ * incremented by the interrupt, so now one. */
configASSERT( ulReceivedValue == 1UL ); configASSERT( ulReceivedValue == 1UL );
( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */ ( void ) ulReceivedValue; /* Remove compiler warnings in case configASSERT() is not defined. */
/* No other notification indexes should have changed, and therefore should /* No other notification indexes should have changed, and therefore should
still have their value set to 0. The value in array index uxIndexToNotify * 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 * should also have been decremented back to zero by the call to
ulTaskNotifyTakeIndexed(). */ * ulTaskNotifyTakeIndexed(). */
for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ ) for( uxIndex = 0; uxIndex < configTASK_NOTIFICATION_ARRAY_ENTRIES; uxIndex++ )
{ {
xReturned = xTaskNotifyWaitIndexed( uxIndexToNotify, 0, 0, &ulReceivedValue, xDontBlock ); xReturned = xTaskNotifyWaitIndexed( uxIndexToNotify, 0, 0, &ulReceivedValue, xDontBlock );
@ -1146,27 +1121,30 @@ static UBaseType_t uxIndexToNotify = 0;
configASSERT( xTaskToNotify ); configASSERT( xTaskToNotify );
/* The task sets xSendNotificationFromISR to pdTRUE each time it wants this /* The task sets xSendNotificationFromISR to pdTRUE each time it wants this
interrupt (this function runs in the RTOS tick hook) to send the next * interrupt (this function runs in the RTOS tick hook) to send the next
notification. */ * notification. */
if( xSendNotificationFromISR == pdTRUE ) if( xSendNotificationFromISR == pdTRUE )
{ {
xSendNotificationFromISR = pdFALSE; xSendNotificationFromISR = pdFALSE;
/* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR() /* Test using both vTaskNotifyGiveFromISR(), xTaskNotifyFromISR()
and xTaskNotifyAndQueryFromISR(). The notification is set to the task * and xTaskNotifyAndQueryFromISR(). The notification is set to the task
notification at index uxIndexToNotify within the array of task * notification at index uxIndexToNotify within the array of task
notifications. */ * notifications. */
switch( xAPIToUse ) switch( xAPIToUse )
{ {
case 0: vTaskNotifyGiveIndexedFromISR( xTaskToNotify, uxIndexToNotify, NULL ); case 0:
vTaskNotifyGiveIndexedFromISR( xTaskToNotify, uxIndexToNotify, NULL );
xAPIToUse++; xAPIToUse++;
break; break;
case 1: xTaskNotifyIndexedFromISR( xTaskToNotify, uxIndexToNotify, 0, eIncrement, NULL ); case 1:
xTaskNotifyIndexedFromISR( xTaskToNotify, uxIndexToNotify, 0, eIncrement, NULL );
xAPIToUse++; xAPIToUse++;
break; break;
case 2: ulPreviousValue = ulUnexpectedValue; case 2:
ulPreviousValue = ulUnexpectedValue;
xTaskNotifyAndQueryIndexedFromISR( xTaskToNotify, uxIndexToNotify, 0, eIncrement, &ulPreviousValue, NULL ); xTaskNotifyAndQueryIndexedFromISR( xTaskToNotify, uxIndexToNotify, 0, eIncrement, &ulPreviousValue, NULL );
configASSERT( ulPreviousValue == 0 ); configASSERT( ulPreviousValue == 0 );
xAPIToUse = 0; xAPIToUse = 0;
@ -1177,8 +1155,9 @@ static UBaseType_t uxIndexToNotify = 0;
} }
/* Use the next index in the array of task notifications the next time /* Use the next index in the array of task notifications the next time
around. */ * around. */
uxIndexToNotify++; uxIndexToNotify++;
if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES ) if( uxIndexToNotify >= configTASK_NOTIFICATION_ARRAY_ENTRIES )
{ {
uxIndexToNotify = 0; uxIndexToNotify = 0;
@ -1188,7 +1167,7 @@ static UBaseType_t uxIndexToNotify = 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check the created tasks are still running and have not /* This is called to check the created tasks are still running and have not
detected any errors. */ * detected any errors. */
BaseType_t xAreTaskNotificationArrayTasksStillRunning( void ) BaseType_t xAreTaskNotificationArrayTasksStillRunning( void )
{ {
static uint32_t ulLastFineCycleCount = 0, ulLastCourseCycleCount = 0, ulCallCount = 0; static uint32_t ulLastFineCycleCount = 0, ulLastCourseCycleCount = 0, ulCallCount = 0;
@ -1196,9 +1175,9 @@ const uint32_t ulCallsBetweenCourseCycleCountChecks = 3UL;
static BaseType_t xErrorStatus = pdPASS; static BaseType_t xErrorStatus = pdPASS;
/* Check the cycle count is still incrementing to ensure the task is still /* Check the cycle count is still incrementing to ensure the task is still
actually running. The fine counter is incremented within individual test * actually running. The fine counter is incremented within individual test
functions. The course counter is incremented one each time all the test * functions. The course counter is incremented one each time all the test
functions have been executed to ensure all the tests are running. */ * functions have been executed to ensure all the tests are running. */
if( ulLastFineCycleCount == ulFineCycleCount ) if( ulLastFineCycleCount == ulFineCycleCount )
{ {
xErrorStatus = pdFAIL; xErrorStatus = pdFAIL;
@ -1209,9 +1188,11 @@ static BaseType_t xErrorStatus = pdPASS;
} }
ulCallCount++; ulCallCount++;
if( ulCallCount >= ulCallsBetweenCourseCycleCountChecks ) if( ulCallCount >= ulCallsBetweenCourseCycleCountChecks )
{ {
ulCallCount = 0; ulCallCount = 0;
if( ulLastCourseCycleCount == ulCourseCycleCounter ) if( ulLastCourseCycleCount == ulCourseCycleCounter )
{ {
xErrorStatus = pdFAIL; xErrorStatus = pdFAIL;

View file

@ -56,12 +56,12 @@
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* The callback functions used by the timers. These each increment a counter /* The callback functions used by the timers. These each increment a counter
to indicate which timer has expired. The auto-reload timers that are used by * to indicate which timer has expired. The auto-reload timers that are used by
the test task (as opposed to being used from an ISR) all share the same * the test task (as opposed to being used from an ISR) all share the same
prvAutoReloadTimerCallback() callback function, and use the ID of the * prvAutoReloadTimerCallback() callback function, and use the ID of the
pxExpiredTimer parameter passed into that function to know which counter to * pxExpiredTimer parameter passed into that function to know which counter to
increment. The other timers all have their own unique callback function and * increment. The other timers all have their own unique callback function and
simply increment their counters without using the callback function parameter. */ * simply increment their counters without using the callback function parameter. */
static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer ); static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer );
static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer ); static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer );
static void prvTimerTestTask( void * pvParameters ); static void prvTimerTestTask( void * pvParameters );
@ -69,8 +69,8 @@ static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer );
static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer ); static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer );
/* The test functions used by the timer test task. These manipulate the auto /* The test functions used by the timer test task. These manipulate the auto
reload and one-shot timers in various ways, then delay, then inspect the timers * reload and one-shot timers in various ways, then delay, then inspect the timers
to ensure they have behaved as expected. */ * to ensure they have behaved as expected. */
static void prvTest1_CreateTimersWithoutSchedulerRunning( void ); static void prvTest1_CreateTimersWithoutSchedulerRunning( void );
static void prvTest2_CheckTaskAndTimersInitialState( void ); static void prvTest2_CheckTaskAndTimersInitialState( void );
static void prvTest3_CheckAutoReloadExpireRates( void ); static void prvTest3_CheckAutoReloadExpireRates( void );
@ -83,47 +83,47 @@ static void prvResetStartConditionsForNextIteration( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Flag that will be latched to pdFAIL should any unexpected behaviour be /* Flag that will be latched to pdFAIL should any unexpected behaviour be
detected in any of the demo tests. */ * detected in any of the demo tests. */
static volatile BaseType_t xTestStatus = pdPASS; static volatile BaseType_t xTestStatus = pdPASS;
/* Flag indicating whether the testing includes the backlog demo. The backlog /* Flag indicating whether the testing includes the backlog demo. The backlog
demo can be disruptive to other demos because the timer backlog is created by * demo can be disruptive to other demos because the timer backlog is created by
calling xTaskCatchUpTicks(). */ * calling xTaskCatchUpTicks(). */
static uint8_t ucIsBacklogDemoEnabled = ( uint8_t ) pdFALSE; static uint8_t ucIsBacklogDemoEnabled = ( uint8_t ) pdFALSE;
/* Counter that is incremented on each cycle of a test. This is used to /* Counter that is incremented on each cycle of a test. This is used to
detect a stalled task - a test that is no longer running. */ * detect a stalled task - a test that is no longer running. */
static volatile uint32_t ulLoopCounter = 0; static volatile uint32_t ulLoopCounter = 0;
/* A set of auto-reload timers - each of which use the same callback function. /* A set of auto-reload timers - each of which use the same callback function.
The callback function uses the timer ID to index into, and then increment, a * The callback function uses the timer ID to index into, and then increment, a
counter in the ucAutoReloadTimerCounters[] array. The callback function stops * counter in the ucAutoReloadTimerCounters[] array. The callback function stops
xAutoReloadTimers[0] during its callback if ucIsStopNeededInTimerZeroCallback is * xAutoReloadTimers[0] during its callback if ucIsStopNeededInTimerZeroCallback is
pdTRUE. The auto-reload timers referenced from xAutoReloadTimers[] are used by * pdTRUE. The auto-reload timers referenced from xAutoReloadTimers[] are used by
the prvTimerTestTask task. */ * the prvTimerTestTask task. */
static TimerHandle_t xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 }; static TimerHandle_t xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
static uint8_t ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 }; static uint8_t ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
static uint8_t ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdFALSE; static uint8_t ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdFALSE;
/* The one-shot timer is configured to use a callback function that increments /* The one-shot timer is configured to use a callback function that increments
ucOneShotTimerCounter each time it gets called. */ * ucOneShotTimerCounter each time it gets called. */
static TimerHandle_t xOneShotTimer = NULL; static TimerHandle_t xOneShotTimer = NULL;
static uint8_t ucOneShotTimerCounter = ( uint8_t ) 0; static uint8_t ucOneShotTimerCounter = ( uint8_t ) 0;
/* The ISR reload timer is controlled from the tick hook to exercise the timer /* The ISR reload timer is controlled from the tick hook to exercise the timer
API functions that can be used from an ISR. It is configured to increment * API functions that can be used from an ISR. It is configured to increment
ucISRReloadTimerCounter each time its callback function is executed. */ * ucISRReloadTimerCounter each time its callback function is executed. */
static TimerHandle_t xISRAutoReloadTimer = NULL; static TimerHandle_t xISRAutoReloadTimer = NULL;
static uint8_t ucISRAutoReloadTimerCounter = ( uint8_t ) 0; static uint8_t ucISRAutoReloadTimerCounter = ( uint8_t ) 0;
/* The ISR one-shot timer is controlled from the tick hook to exercise the timer /* The ISR one-shot timer is controlled from the tick hook to exercise the timer
API functions that can be used from an ISR. It is configured to increment * API functions that can be used from an ISR. It is configured to increment
ucISRReloadTimerCounter each time its callback function is executed. */ * ucISRReloadTimerCounter each time its callback function is executed. */
static TimerHandle_t xISROneShotTimer = NULL; static TimerHandle_t xISROneShotTimer = NULL;
static uint8_t ucISROneShotTimerCounter = ( uint8_t ) 0; static uint8_t ucISROneShotTimerCounter = ( uint8_t ) 0;
/* The period of all the timers are a multiple of the base period. The base /* The period of all the timers are a multiple of the base period. The base
period is configured by the parameter to vStartTimerDemoTask(). */ * period is configured by the parameter to vStartTimerDemoTask(). */
static TickType_t xBasePeriod = 0; static TickType_t xBasePeriod = 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -131,22 +131,22 @@ static TickType_t xBasePeriod = 0;
void vStartTimerDemoTask( TickType_t xBasePeriodIn ) void vStartTimerDemoTask( TickType_t xBasePeriodIn )
{ {
/* Start with the timer and counter arrays clear - this is only necessary /* Start with the timer and counter arrays clear - this is only necessary
where the compiler does not clear them automatically on start up. */ * where the compiler does not clear them automatically on start up. */
memset( ucAutoReloadTimerCounters, 0x00, sizeof( ucAutoReloadTimerCounters ) ); memset( ucAutoReloadTimerCounters, 0x00, sizeof( ucAutoReloadTimerCounters ) );
memset( xAutoReloadTimers, 0x00, sizeof( xAutoReloadTimers ) ); memset( xAutoReloadTimers, 0x00, sizeof( xAutoReloadTimers ) );
/* Store the period from which all the timer periods will be generated from /* Store the period from which all the timer periods will be generated from
(multiples of). */ * (multiples of). */
xBasePeriod = xBasePeriodIn; xBasePeriod = xBasePeriodIn;
/* Create a set of timers for use by this demo/test. */ /* Create a set of timers for use by this demo/test. */
prvTest1_CreateTimersWithoutSchedulerRunning(); prvTest1_CreateTimersWithoutSchedulerRunning();
/* Create the task that will control and monitor the timers. This is /* Create the task that will control and monitor the timers. This is
created at a lower priority than the timer service task to ensure, as * created at a lower priority than the timer service task to ensure, as
far as it is concerned, commands on timers are acted on immediately * far as it is concerned, commands on timers are acted on immediately
(sending a command to the timer service task will unblock the timer service * (sending a command to the timer service task will unblock the timer service
task, which will then preempt this task). */ * task, which will then preempt this task). */
if( xTestStatus != pdFAIL ) if( xTestStatus != pdFAIL )
{ {
xTaskCreate( prvTimerTestTask, "Tmr Tst", tmrTIMER_TEST_TASK_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL ); xTaskCreate( prvTimerTestTask, "Tmr Tst", tmrTIMER_TEST_TASK_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL );
@ -165,7 +165,7 @@ static void prvTimerTestTask( void *pvParameters )
( void ) pvParameters; ( void ) pvParameters;
/* Create a one-shot timer for use later on in this test. For test purposes it /* Create a one-shot timer for use later on in this test. For test purposes it
is created as an auto-reload timer then converted to a one-shot timer. */ * is created as an auto-reload timer then converted to a one-shot timer. */
xOneShotTimer = xTimerCreate( "Oneshot Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */ xOneShotTimer = xTimerCreate( "Oneshot Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
tmrdemoONE_SHOT_TIMER_PERIOD, /* The period for the timer. */ tmrdemoONE_SHOT_TIMER_PERIOD, /* The period for the timer. */
pdFALSE, /* Autoreload is false, so created as a one-shot timer. */ pdFALSE, /* Autoreload is false, so created as a one-shot timer. */
@ -179,7 +179,7 @@ static void prvTimerTestTask( void *pvParameters )
} }
/* Purely for test coverage purposes - change and query the reload mode to /* Purely for test coverage purposes - change and query the reload mode to
auto-reload then back to one-shot. */ * auto-reload then back to one-shot. */
/* Change timer to auto-reload. */ /* Change timer to auto-reload. */
vTimerSetReloadMode( xOneShotTimer, pdTRUE ); vTimerSetReloadMode( xOneShotTimer, pdTRUE );
@ -194,7 +194,7 @@ static void prvTimerTestTask( void *pvParameters )
configASSERT( uxTimerGetReloadMode( xOneShotTimer ) == pdFALSE ); configASSERT( uxTimerGetReloadMode( xOneShotTimer ) == pdFALSE );
/* Ensure all the timers are in their expected initial state. This /* Ensure all the timers are in their expected initial state. This
depends on the timer service task having a higher priority than this task. */ * depends on the timer service task having a higher priority than this task. */
prvTest2_CheckTaskAndTimersInitialState(); prvTest2_CheckTaskAndTimersInitialState();
for( ; ; ) for( ; ; )
@ -203,11 +203,11 @@ static void prvTimerTestTask( void *pvParameters )
prvTest3_CheckAutoReloadExpireRates(); prvTest3_CheckAutoReloadExpireRates();
/* Check the auto-reload timers can be stopped correctly, and correctly /* Check the auto-reload timers can be stopped correctly, and correctly
report their state. */ * report their state. */
prvTest4_CheckAutoReloadTimersCanBeStopped(); prvTest4_CheckAutoReloadTimersCanBeStopped();
/* Check the one-shot timer only calls its callback once after it has been /* Check the one-shot timer only calls its callback once after it has been
started, and that it reports its state correctly. */ * started, and that it reports its state correctly. */
prvTest5_CheckBasicOneShotTimerBehaviour(); prvTest5_CheckBasicOneShotTimerBehaviour();
/* Check timer reset behaviour. */ /* Check timer reset behaviour. */
@ -226,7 +226,7 @@ static void prvTimerTestTask( void *pvParameters )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that the created task is still running and has not /* This is called to check that the created task is still running and has not
detected any errors. */ * detected any errors. */
BaseType_t xAreTimerDemoTasksStillRunning( TickType_t xCycleFrequency ) BaseType_t xAreTimerDemoTasksStillRunning( TickType_t xCycleFrequency )
{ {
static uint32_t ulLastLoopCounter = 0UL; static uint32_t ulLastLoopCounter = 0UL;
@ -236,23 +236,24 @@ static TickType_t xIterationsWithoutCounterIncrement = ( TickType_t ) 0, xLastCy
if( xLastCycleFrequency != xCycleFrequency ) if( xLastCycleFrequency != xCycleFrequency )
{ {
/* The cycle frequency has probably become much faster due to an error /* The cycle frequency has probably become much faster due to an error
elsewhere. Start counting Iterations again. */ * elsewhere. Start counting Iterations again. */
xIterationsWithoutCounterIncrement = ( TickType_t ) 0; xIterationsWithoutCounterIncrement = ( TickType_t ) 0;
xLastCycleFrequency = xCycleFrequency; xLastCycleFrequency = xCycleFrequency;
} }
/* Calculate the maximum number of times that it is permissible for this /* Calculate the maximum number of times that it is permissible for this
function to be called without ulLoopCounter being incremented. This is * function to be called without ulLoopCounter being incremented. This is
necessary because the tests in this file block for extended periods, and the * necessary because the tests in this file block for extended periods, and the
block period might be longer than the time between calls to this function. */ * block period might be longer than the time between calls to this function. */
xMaxBlockTimeUsedByTheseTests = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod; xMaxBlockTimeUsedByTheseTests = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
xLoopCounterIncrementTimeMax = ( xMaxBlockTimeUsedByTheseTests / xCycleFrequency ) + 1; xLoopCounterIncrementTimeMax = ( xMaxBlockTimeUsedByTheseTests / xCycleFrequency ) + 1;
/* If the demo task is still running then the loop counter is expected to /* If the demo task is still running then the loop counter is expected to
have incremented every xLoopCounterIncrementTimeMax calls. */ * have incremented every xLoopCounterIncrementTimeMax calls. */
if( ulLastLoopCounter == ulLoopCounter ) if( ulLastLoopCounter == ulLoopCounter )
{ {
xIterationsWithoutCounterIncrement++; xIterationsWithoutCounterIncrement++;
if( xIterationsWithoutCounterIncrement > xLoopCounterIncrementTimeMax ) if( xIterationsWithoutCounterIncrement > xLoopCounterIncrementTimeMax )
{ {
/* The tests appear to be no longer running (stalled). */ /* The tests appear to be no longer running (stalled). */
@ -262,14 +263,14 @@ static TickType_t xIterationsWithoutCounterIncrement = ( TickType_t ) 0, xLastCy
else else
{ {
/* ulLoopCounter changed, so the count of times this function was called /* ulLoopCounter changed, so the count of times this function was called
without a change can be reset to zero. */ * without a change can be reset to zero. */
xIterationsWithoutCounterIncrement = ( TickType_t ) 0; xIterationsWithoutCounterIncrement = ( TickType_t ) 0;
} }
ulLastLoopCounter = ulLoopCounter; ulLastLoopCounter = ulLoopCounter;
/* Errors detected in the task itself will have latched xTestStatus /* Errors detected in the task itself will have latched xTestStatus
to pdFAIL. */ * to pdFAIL. */
return xTestStatus; return xTestStatus;
} }
@ -282,9 +283,9 @@ TickType_t xTimer;
for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ ) for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ )
{ {
/* As the timer queue is not yet full, it should be possible to both /* As the timer queue is not yet full, it should be possible to both
create and start a timer. These timers are being started before the * create and start a timer. These timers are being started before the
scheduler has been started, so their block times should get set to zero * scheduler has been started, so their block times should get set to zero
within the timer API itself. */ * within the timer API itself. */
xAutoReloadTimers[ xTimer ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */ xAutoReloadTimers[ xTimer ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
( ( xTimer + ( TickType_t ) 1 ) * xBasePeriod ), /* The period for the timer. The plus 1 ensures a period of zero is not specified. */ ( ( xTimer + ( TickType_t ) 1 ) * xBasePeriod ), /* The period for the timer. The plus 1 ensures a period of zero is not specified. */
pdTRUE, /* Auto-reload is set to true. */ pdTRUE, /* Auto-reload is set to true. */
@ -301,9 +302,9 @@ TickType_t xTimer;
configASSERT( strcmp( pcTimerGetName( xAutoReloadTimers[ xTimer ] ), "FR Timer" ) == 0 ); configASSERT( strcmp( pcTimerGetName( xAutoReloadTimers[ xTimer ] ), "FR Timer" ) == 0 );
/* The scheduler has not yet started, so the block period of /* The scheduler has not yet started, so the block period of
portMAX_DELAY should just get set to zero in xTimerStart(). Also, * portMAX_DELAY should just get set to zero in xTimerStart(). Also,
the timer queue is not yet full so xTimerStart() should return * the timer queue is not yet full so xTimerStart() should return
pdPASS. */ * pdPASS. */
if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) != pdPASS ) if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) != pdPASS )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -313,8 +314,8 @@ TickType_t xTimer;
} }
/* The timers queue should now be full, so it should be possible to create /* The timers queue should now be full, so it should be possible to create
another timer, but not possible to start it (the timer queue will not get * another timer, but not possible to start it (the timer queue will not get
drained until the scheduler has been started. */ * drained until the scheduler has been started. */
xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */ xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
( configTIMER_QUEUE_LENGTH * xBasePeriod ), /* The period for the timer. */ ( configTIMER_QUEUE_LENGTH * xBasePeriod ), /* The period for the timer. */
pdTRUE, /* Auto-reload is set to true. */ pdTRUE, /* Auto-reload is set to true. */
@ -331,14 +332,14 @@ TickType_t xTimer;
if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) == pdPASS ) if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) == pdPASS )
{ {
/* This time it would not be expected that the timer could be /* This time it would not be expected that the timer could be
started at this point. */ * started at this point. */
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
configASSERT( xTestStatus ); configASSERT( xTestStatus );
} }
} }
/* Create the timers that are used from the tick interrupt to test the timer /* Create the timers that are used from the tick interrupt to test the timer
API functions that can be called from an ISR. */ * API functions that can be called from an ISR. */
xISRAutoReloadTimer = xTimerCreate( "ISR AR", /* The text name given to the timer. */ xISRAutoReloadTimer = xTimerCreate( "ISR AR", /* The text name given to the timer. */
0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */ 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
pdTRUE, /* This is an auto-reload timer. */ pdTRUE, /* This is an auto-reload timer. */
@ -364,12 +365,12 @@ static void prvTest2_CheckTaskAndTimersInitialState( void )
uint8_t ucTimer; uint8_t ucTimer;
/* Ensure all the timers are in their expected initial state. This depends /* Ensure all the timers are in their expected initial state. This depends
on the timer service task having a higher priority than this task. * on the timer service task having a higher priority than this task.
*
auto-reload timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now be active, * auto-reload timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now be active,
and auto-reload timer configTIMER_QUEUE_LENGTH should not yet be active (it * and auto-reload timer configTIMER_QUEUE_LENGTH should not yet be active (it
could not be started prior to the scheduler being started when it was * could not be started prior to the scheduler being started when it was
created). */ * created). */
for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ ) for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
{ {
if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE ) if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
@ -394,22 +395,22 @@ TickType_t xBlockPeriod, xTimerPeriod, xExpectedNumber;
UBaseType_t uxOriginalPriority; UBaseType_t uxOriginalPriority;
/* Check the auto-reload timers expire at the expected rates. Do this at a /* Check the auto-reload timers expire at the expected rates. Do this at a
high priority for maximum accuracy. This is ok as most of the time is spent * high priority for maximum accuracy. This is ok as most of the time is spent
in the Blocked state. */ * in the Blocked state. */
uxOriginalPriority = uxTaskPriorityGet( NULL ); uxOriginalPriority = uxTaskPriorityGet( NULL );
vTaskPrioritySet( NULL, ( configMAX_PRIORITIES - 1 ) ); vTaskPrioritySet( NULL, ( configMAX_PRIORITIES - 1 ) );
/* Delaying for configTIMER_QUEUE_LENGTH * xBasePeriod ticks should allow /* Delaying for configTIMER_QUEUE_LENGTH * xBasePeriod ticks should allow
all the auto-reload timers to expire at least once. */ * all the auto-reload timers to expire at least once. */
xBlockPeriod = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod; xBlockPeriod = ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
vTaskDelay( xBlockPeriod ); vTaskDelay( xBlockPeriod );
/* Check that all the auto-reload timers have called their callback /* Check that all the auto-reload timers have called their callback
function the expected number of times. */ * function the expected number of times. */
for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ ) for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
{ {
/* The expected number of expires is equal to the block period divided /* The expected number of expires is equal to the block period divided
by the timer period. */ * by the timer period. */
xTimerPeriod = ( ( ( TickType_t ) ucTimer + ( TickType_t ) 1 ) * xBasePeriod ); xTimerPeriod = ( ( ( TickType_t ) ucTimer + ( TickType_t ) 1 ) * xBasePeriod );
xExpectedNumber = xBlockPeriod / xTimerPeriod; xExpectedNumber = xBlockPeriod / xTimerPeriod;
@ -431,7 +432,7 @@ UBaseType_t uxOriginalPriority;
if( xTestStatus == pdPASS ) if( xTestStatus == pdPASS )
{ {
/* No errors have been reported so increment the loop counter so the /* No errors have been reported so increment the loop counter so the
check task knows this task is still running. */ * check task knows this task is still running. */
ulLoopCounter++; ulLoopCounter++;
} }
} }
@ -442,7 +443,7 @@ static void prvTest4_CheckAutoReloadTimersCanBeStopped( void )
uint8_t ucTimer; uint8_t ucTimer;
/* Check the auto-reload timers can be stopped correctly, and correctly /* Check the auto-reload timers can be stopped correctly, and correctly
report their state. */ * report their state. */
/* Stop all the active timers. */ /* Stop all the active timers. */
for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ ) for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
@ -455,8 +456,8 @@ uint8_t ucTimer;
} }
/* Now stop the timer. This will appear to happen immediately to /* Now stop the timer. This will appear to happen immediately to
this task because this task is running at a priority below the * this task because this task is running at a priority below the
timer service task. */ * timer service task. */
xTimerStop( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK ); xTimerStop( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
/* The timer should now be inactive. */ /* The timer should now be inactive. */
@ -470,9 +471,9 @@ uint8_t ucTimer;
taskENTER_CRITICAL(); taskENTER_CRITICAL();
{ {
/* The timer in array position configTIMER_QUEUE_LENGTH should not /* The timer in array position configTIMER_QUEUE_LENGTH should not
be active. The critical section is used to ensure the timer does * be active. The critical section is used to ensure the timer does
not call its callback between the next line running and the array * not call its callback between the next line running and the array
being cleared back to zero, as that would mask an error condition. */ * being cleared back to zero, as that would mask an error condition. */
if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( uint8_t ) 0 ) if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( uint8_t ) 0 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -485,8 +486,9 @@ uint8_t ucTimer;
taskEXIT_CRITICAL(); taskEXIT_CRITICAL();
/* The timers are now all inactive, so this time, after delaying, none /* The timers are now all inactive, so this time, after delaying, none
of the callback counters should have incremented. */ * of the callback counters should have incremented. */
vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod ); vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ ) for( ucTimer = 0; ucTimer < ( uint8_t ) configTIMER_QUEUE_LENGTH; ucTimer++ )
{ {
if( ucAutoReloadTimerCounters[ ucTimer ] != ( uint8_t ) 0 ) if( ucAutoReloadTimerCounters[ ucTimer ] != ( uint8_t ) 0 )
@ -499,7 +501,7 @@ uint8_t ucTimer;
if( xTestStatus == pdPASS ) if( xTestStatus == pdPASS )
{ {
/* No errors have been reported so increment the loop counter so /* No errors have been reported so increment the loop counter so
the check task knows this task is still running. */ * the check task knows this task is still running. */
ulLoopCounter++; ulLoopCounter++;
} }
} }
@ -508,7 +510,7 @@ uint8_t ucTimer;
static void prvTest5_CheckBasicOneShotTimerBehaviour( void ) static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
{ {
/* Check the one-shot timer only calls its callback once after it has been /* Check the one-shot timer only calls its callback once after it has been
started, and that it reports its state correctly. */ * started, and that it reports its state correctly. */
/* The one-shot timer should not be active yet. */ /* The one-shot timer should not be active yet. */
if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE ) if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
@ -525,6 +527,7 @@ static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
/* Start the one-shot timer and check that it reports its state correctly. */ /* Start the one-shot timer and check that it reports its state correctly. */
xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK ); xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE ) if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -532,8 +535,8 @@ static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
} }
/* Delay for three times as long as the one-shot timer period, then check /* Delay for three times as long as the one-shot timer period, then check
to ensure it has only called its callback once, and is now not in the * to ensure it has only called its callback once, and is now not in the
active state. */ * active state. */
vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD * ( TickType_t ) 3 ); vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD * ( TickType_t ) 3 );
if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE ) if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
@ -556,7 +559,7 @@ static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
if( xTestStatus == pdPASS ) if( xTestStatus == pdPASS )
{ {
/* No errors have been reported so increment the loop counter so the /* No errors have been reported so increment the loop counter so the
check task knows this task is still running. */ * check task knows this task is still running. */
ulLoopCounter++; ulLoopCounter++;
} }
} }
@ -570,6 +573,7 @@ uint8_t ucTimer;
/* Restart the one-shot timer and check it reports its status correctly. */ /* Restart the one-shot timer and check it reports its status correctly. */
xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK ); xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE ) if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -577,8 +581,9 @@ uint8_t ucTimer;
} }
/* Restart one of the auto-reload timers and check that it reports its /* Restart one of the auto-reload timers and check that it reports its
status correctly. */ * status correctly. */
xTimerStart( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK ); xTimerStart( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE ) if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -588,12 +593,12 @@ uint8_t ucTimer;
for( ucTimer = 0; ucTimer < tmrdemoNUM_TIMER_RESETS; ucTimer++ ) for( ucTimer = 0; ucTimer < tmrdemoNUM_TIMER_RESETS; ucTimer++ )
{ {
/* Delay for half as long as the one-shot timer period, then reset it. /* Delay for half as long as the one-shot timer period, then reset it.
It should never expire while this is done, so its callback count should * It should never expire while this is done, so its callback count should
never increment. */ * never increment. */
vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD / 2 ); vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD / 2 );
/* Check both running timers are still active, but have not called their /* Check both running timers are still active, but have not called their
callback functions. */ * callback functions. */
if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE ) if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -625,7 +630,7 @@ uint8_t ucTimer;
if( xTestStatus == pdPASS ) if( xTestStatus == pdPASS )
{ {
/* No errors have been reported so increment the loop counter so /* No errors have been reported so increment the loop counter so
the check task knows this task is still running. */ * the check task knows this task is still running. */
ulLoopCounter++; ulLoopCounter++;
} }
} }
@ -634,7 +639,7 @@ uint8_t ucTimer;
vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod ); vTaskDelay( ( ( TickType_t ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
/* The timers were not reset during the above delay period so should now /* The timers were not reset during the above delay period so should now
both have called their callback functions. */ * both have called their callback functions. */
if( ucOneShotTimerCounter != ( uint8_t ) 1 ) if( ucOneShotTimerCounter != ( uint8_t ) 1 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -648,7 +653,7 @@ uint8_t ucTimer;
} }
/* The one-shot timer should no longer be active, while the auto-reload /* The one-shot timer should no longer be active, while the auto-reload
timer should still be active. */ * timer should still be active. */
if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE ) if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -671,14 +676,14 @@ uint8_t ucTimer;
} }
/* Clear the timer callback counts, ready for another iteration of these /* Clear the timer callback counts, ready for another iteration of these
tests. */ * tests. */
ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( uint8_t ) 0; ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( uint8_t ) 0;
ucOneShotTimerCounter = ( uint8_t ) 0; ucOneShotTimerCounter = ( uint8_t ) 0;
if( xTestStatus == pdPASS ) if( xTestStatus == pdPASS )
{ {
/* No errors have been reported so increment the loop counter so the check /* No errors have been reported so increment the loop counter so the check
task knows this task is still running. */ * task knows this task is still running. */
ulLoopCounter++; ulLoopCounter++;
} }
} }
@ -687,7 +692,7 @@ uint8_t ucTimer;
static void prvTest7_CheckBacklogBehaviour( void ) static void prvTest7_CheckBacklogBehaviour( void )
{ {
/* Use the first auto-reload timer to test stopping a timer from a /* Use the first auto-reload timer to test stopping a timer from a
backlogged callback. */ * backlogged callback. */
/* The timer has not been started yet! */ /* The timer has not been started yet! */
if( xTimerIsTimerActive( xAutoReloadTimers[ 0 ] ) != pdFALSE ) if( xTimerIsTimerActive( xAutoReloadTimers[ 0 ] ) != pdFALSE )
@ -700,10 +705,10 @@ static void prvTest7_CheckBacklogBehaviour( void )
ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdTRUE; ucIsStopNeededInTimerZeroCallback = ( uint8_t ) pdTRUE;
/* Now start the timer. This will appear to happen immediately to /* Now start the timer. This will appear to happen immediately to
this task because this task is running at a priority below the timer * this task because this task is running at a priority below the timer
service task. Use a timer period of one tick so the call to * service task. Use a timer period of one tick so the call to
xTaskCatchUpTicks() below has minimal impact on other tests that might * xTaskCatchUpTicks() below has minimal impact on other tests that might
be running. */ * be running. */
#define tmrdemoBACKLOG_TIMER_PERIOD ( ( TickType_t ) 1 ) #define tmrdemoBACKLOG_TIMER_PERIOD ( ( TickType_t ) 1 )
xTimerChangePeriod( xAutoReloadTimers[ 0 ], tmrdemoBACKLOG_TIMER_PERIOD, tmrdemoDONT_BLOCK ); xTimerChangePeriod( xAutoReloadTimers[ 0 ], tmrdemoBACKLOG_TIMER_PERIOD, tmrdemoDONT_BLOCK );
@ -715,8 +720,8 @@ static void prvTest7_CheckBacklogBehaviour( void )
} }
/* Arrange for the callback to execute late enough that it will execute /* Arrange for the callback to execute late enough that it will execute
twice, back-to-back. The timer must handle the stop request properly * twice, back-to-back. The timer must handle the stop request properly
in spite of the backlog of callbacks. */ * in spite of the backlog of callbacks. */
#define tmrdemoEXPECTED_BACKLOG_EXPIRES ( ( TickType_t ) 2 ) #define tmrdemoEXPECTED_BACKLOG_EXPIRES ( ( TickType_t ) 2 )
xTaskCatchUpTicks( tmrdemoBACKLOG_TIMER_PERIOD * tmrdemoEXPECTED_BACKLOG_EXPIRES ); xTaskCatchUpTicks( tmrdemoBACKLOG_TIMER_PERIOD * tmrdemoEXPECTED_BACKLOG_EXPIRES );
@ -737,7 +742,7 @@ static void prvTest7_CheckBacklogBehaviour( void )
if( xTestStatus == pdPASS ) if( xTestStatus == pdPASS )
{ {
/* No errors have been reported so increment the loop counter so the check /* No errors have been reported so increment the loop counter so the check
task knows this task is still running. */ * task knows this task is still running. */
ulLoopCounter++; ulLoopCounter++;
} }
} }
@ -760,8 +765,8 @@ uint8_t ucTimer;
} }
/* Now start the timer. This will appear to happen immediately to /* Now start the timer. This will appear to happen immediately to
this task because this task is running at a priority below the timer * this task because this task is running at a priority below the timer
service task. */ * service task. */
xTimerStart( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK ); xTimerStart( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
/* The timer should now be active. */ /* The timer should now be active. */
@ -775,7 +780,7 @@ uint8_t ucTimer;
if( xTestStatus == pdPASS ) if( xTestStatus == pdPASS )
{ {
/* No errors have been reported so increment the loop counter so the /* No errors have been reported so increment the loop counter so the
check task knows this task is still running. */ * check task knows this task is still running. */
ulLoopCounter++; ulLoopCounter++;
} }
} }
@ -786,25 +791,26 @@ void vTimerPeriodicISRTests( void )
static TickType_t uxTick = ( TickType_t ) -1; static TickType_t uxTick = ( TickType_t ) -1;
#if ( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) ) #if ( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) )
/* The timer service task is not the highest priority task, so it cannot
be assumed that timings will be exact. Timers should never call their
callback before their expiry time, but a margin is permissible for calling
their callback after their expiry time. If exact timing is required then
configTIMER_TASK_PRIORITY must be set to ensure the timer service task
is the highest priority task in the system.
This function is called from the tick hook. The tick hook is called /* The timer service task is not the highest priority task, so it cannot
even when the scheduler is suspended. Therefore it is possible that the * be assumed that timings will be exact. Timers should never call their
uxTick count maintained in this function is temporarily ahead of the tick * callback before their expiry time, but a margin is permissible for calling
count maintained by the kernel. When this is the case a message posted from * their callback after their expiry time. If exact timing is required then
this function will assume a time stamp in advance of the real time stamp, * configTIMER_TASK_PRIORITY must be set to ensure the timer service task
which can result in a timer being processed before this function expects it * is the highest priority task in the system.
to. For example, if the kernel's tick count was 100, and uxTick was 102, *
then this function will not expect the timer to have expired until the * This function is called from the tick hook. The tick hook is called
kernel's tick count is (102 + xBasePeriod), whereas in reality the timer * even when the scheduler is suspended. Therefore it is possible that the
will expire when the kernel's tick count is (100 + xBasePeriod). For this * uxTick count maintained in this function is temporarily ahead of the tick
reason xMargin is used as an allowable margin for premature timer expires * count maintained by the kernel. When this is the case a message posted from
as well as late timer expires. */ * this function will assume a time stamp in advance of the real time stamp,
* which can result in a timer being processed before this function expects it
* to. For example, if the kernel's tick count was 100, and uxTick was 102,
* then this function will not expect the timer to have expired until the
* kernel's tick count is (102 + xBasePeriod), whereas in reality the timer
* will expire when the kernel's tick count is (100 + xBasePeriod). For this
* reason xMargin is used as an allowable margin for premature timer expires
* as well as late timer expires. */
#ifdef _WINDOWS_ #ifdef _WINDOWS_
/* Windows is not real real time. */ /* Windows is not real real time. */
const TickType_t xMargin = 20; const TickType_t xMargin = 20;
@ -818,7 +824,7 @@ static TickType_t uxTick = ( TickType_t ) -1;
#else #else
const TickType_t xMargin = 4; const TickType_t xMargin = 4;
#endif /* _WINDOWS_ */ #endif /* _WINDOWS_ */
#endif #endif /* if ( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) ) */
uxTick++; uxTick++;
@ -826,13 +832,13 @@ static TickType_t uxTick = ( TickType_t ) -1;
if( uxTick == 0 ) if( uxTick == 0 )
{ {
/* The timers will have been created, but not started. Start them now /* The timers will have been created, but not started. Start them now
by setting their period. */ * by setting their period. */
ucISRAutoReloadTimerCounter = 0; ucISRAutoReloadTimerCounter = 0;
ucISROneShotTimerCounter = 0; ucISROneShotTimerCounter = 0;
/* It is possible that the timer task has not yet made room in the /* It is possible that the timer task has not yet made room in the
timer queue. If the timers cannot be started then reset uxTick so * timer queue. If the timers cannot be started then reset uxTick so
another attempt is made later. */ * another attempt is made later. */
uxTick = ( TickType_t ) -1; uxTick = ( TickType_t ) -1;
/* Try starting first timer. */ /* Try starting first timer. */
@ -842,13 +848,13 @@ static TickType_t uxTick = ( TickType_t ) -1;
if( xTimerChangePeriodFromISR( xISROneShotTimer, xBasePeriod, NULL ) == pdPASS ) if( xTimerChangePeriodFromISR( xISROneShotTimer, xBasePeriod, NULL ) == pdPASS )
{ {
/* Both timers were started, so set the uxTick back to its /* Both timers were started, so set the uxTick back to its
proper value. */ * proper value. */
uxTick = 0; uxTick = 0;
} }
else else
{ {
/* Second timer could not be started, so stop the first one /* Second timer could not be started, so stop the first one
again. */ * again. */
xTimerStopFromISR( xISRAutoReloadTimer, NULL ); xTimerStopFromISR( xISRAutoReloadTimer, NULL );
} }
} }
@ -865,7 +871,7 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( xBasePeriod + xMargin ) ) else if( uxTick == ( xBasePeriod + xMargin ) )
{ {
/* Both timers should now have expired once. The auto-reload timer will /* Both timers should now have expired once. The auto-reload timer will
still be active, but the one-shot timer should now have stopped. */ * still be active, but the one-shot timer should now have stopped. */
if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) ) if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -875,8 +881,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 2 * xBasePeriod ) - xMargin ) ) else if( uxTick == ( ( 2 * xBasePeriod ) - xMargin ) )
{ {
/* The auto-reload timer will still be active, but the one-shot timer /* The auto-reload timer will still be active, but the one-shot timer
should now have stopped - however, at this time neither of the timers * should now have stopped - however, at this time neither of the timers
should have expired again since the last test. */ * should have expired again since the last test. */
if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) ) if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -886,8 +892,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 2 * xBasePeriod ) + xMargin ) ) else if( uxTick == ( ( 2 * xBasePeriod ) + xMargin ) )
{ {
/* The auto-reload timer will still be active, but the one-shot timer /* The auto-reload timer will still be active, but the one-shot timer
should now have stopped. At this time the auto-reload timer should have * should now have stopped. At this time the auto-reload timer should have
expired again, but the one-shot timer count should not have changed. */ * expired again, but the one-shot timer count should not have changed. */
if( ucISRAutoReloadTimerCounter != 2 ) if( ucISRAutoReloadTimerCounter != 2 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -903,8 +909,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 2 * xBasePeriod ) + ( xBasePeriod >> ( TickType_t ) 2U ) ) ) else if( uxTick == ( ( 2 * xBasePeriod ) + ( xBasePeriod >> ( TickType_t ) 2U ) ) )
{ {
/* The auto-reload timer will still be active, but the one-shot timer /* The auto-reload timer will still be active, but the one-shot timer
should now have stopped. Again though, at this time, neither timer call * should now have stopped. Again though, at this time, neither timer call
back should have been called since the last test. */ * back should have been called since the last test. */
if( ucISRAutoReloadTimerCounter != 2 ) if( ucISRAutoReloadTimerCounter != 2 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -925,8 +931,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 3 * xBasePeriod ) + xMargin ) ) else if( uxTick == ( ( 3 * xBasePeriod ) + xMargin ) )
{ {
/* The auto-reload timer and one-shot timer will be active. At /* The auto-reload timer and one-shot timer will be active. At
this time the auto-reload timer should have expired again, but the one * this time the auto-reload timer should have expired again, but the one
shot timer count should not have changed yet. */ * shot timer count should not have changed yet. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -940,14 +946,14 @@ static TickType_t uxTick = ( TickType_t ) -1;
} }
/* Now stop the auto-reload timer. The one-shot timer was started /* Now stop the auto-reload timer. The one-shot timer was started
a few ticks ago. */ * a few ticks ago. */
xTimerStopFromISR( xISRAutoReloadTimer, NULL ); xTimerStopFromISR( xISRAutoReloadTimer, NULL );
} }
else if( uxTick == ( 4 * ( xBasePeriod - xMargin ) ) ) else if( uxTick == ( 4 * ( xBasePeriod - xMargin ) ) )
{ {
/* The auto-reload timer is now stopped, and the one-shot timer is /* The auto-reload timer is now stopped, and the one-shot timer is
active, but at this time neither timer should have expired since the * active, but at this time neither timer should have expired since the
last test. */ * last test. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -963,8 +969,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 4 * xBasePeriod ) + xMargin ) ) else if( uxTick == ( ( 4 * xBasePeriod ) + xMargin ) )
{ {
/* The auto-reload timer is now stopped, and the one-shot timer is /* The auto-reload timer is now stopped, and the one-shot timer is
active. The one-shot timer should have expired again, but the auto * active. The one-shot timer should have expired again, but the auto
reload timer should not have executed its callback. */ * reload timer should not have executed its callback. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -980,8 +986,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( 8 * xBasePeriod ) ) else if( uxTick == ( 8 * xBasePeriod ) )
{ {
/* The auto-reload timer is now stopped, and the one-shot timer has /* The auto-reload timer is now stopped, and the one-shot timer has
already expired and then stopped itself. Both callback counters should * already expired and then stopped itself. Both callback counters should
not have incremented since the last test. */ * not have incremented since the last test. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -1000,8 +1006,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 9 * xBasePeriod ) - xMargin ) ) else if( uxTick == ( ( 9 * xBasePeriod ) - xMargin ) )
{ {
/* Only the one-shot timer should be running, but it should not have /* Only the one-shot timer should be running, but it should not have
expired since the last test. Check the callback counters have not * expired since the last test. Check the callback counters have not
incremented, then reset the one-shot timer again. */ * incremented, then reset the one-shot timer again. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -1019,8 +1025,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 10 * xBasePeriod ) - ( 2 * xMargin ) ) ) else if( uxTick == ( ( 10 * xBasePeriod ) - ( 2 * xMargin ) ) )
{ {
/* Only the one-shot timer should be running, but it should not have /* Only the one-shot timer should be running, but it should not have
expired since the last test. Check the callback counters have not * expired since the last test. Check the callback counters have not
incremented, then reset the one-shot timer again. */ * incremented, then reset the one-shot timer again. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -1038,8 +1044,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 11 * xBasePeriod ) - ( 3 * xMargin ) ) ) else if( uxTick == ( ( 11 * xBasePeriod ) - ( 3 * xMargin ) ) )
{ {
/* Only the one-shot timer should be running, but it should not have /* Only the one-shot timer should be running, but it should not have
expired since the last test. Check the callback counters have not * expired since the last test. Check the callback counters have not
incremented, then reset the one-shot timer once again. */ * incremented, then reset the one-shot timer once again. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -1057,10 +1063,10 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( ( 12 * xBasePeriod ) - ( 2 * xMargin ) ) ) else if( uxTick == ( ( 12 * xBasePeriod ) - ( 2 * xMargin ) ) )
{ {
/* Only the one-shot timer should have been running and this time it /* Only the one-shot timer should have been running and this time it
should have expired. Check its callback count has been incremented. * should have expired. Check its callback count has been incremented.
The auto-reload timer is still not running so should still have the same * The auto-reload timer is still not running so should still have the same
count value. This time the one-shot timer is not reset so should not * count value. This time the one-shot timer is not reset so should not
restart from its expiry period again. */ * restart from its expiry period again. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -1076,8 +1082,8 @@ static TickType_t uxTick = ( TickType_t ) -1;
else if( uxTick == ( 15 * xBasePeriod ) ) else if( uxTick == ( 15 * xBasePeriod ) )
{ {
/* Neither timer should be running now. Check neither callback count /* Neither timer should be running now. Check neither callback count
has incremented, then go back to the start to run these tests all * has incremented, then go back to the start to run these tests all
over again. */ * over again. */
if( ucISRAutoReloadTimerCounter != 3 ) if( ucISRAutoReloadTimerCounter != 3 )
{ {
xTestStatus = pdFAIL; xTestStatus = pdFAIL;
@ -1102,6 +1108,7 @@ static void prvAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
size_t uxTimerID; size_t uxTimerID;
uxTimerID = ( size_t ) pvTimerGetTimerID( pxExpiredTimer ); uxTimerID = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );
if( uxTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) ) if( uxTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )
{ {
( ucAutoReloadTimerCounters[ uxTimerID ] )++; ( ucAutoReloadTimerCounters[ uxTimerID ] )++;
@ -1125,18 +1132,18 @@ size_t uxTimerID;
static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer ) static void prvOneShotTimerCallback( TimerHandle_t pxExpiredTimer )
{ {
/* A count is kept of the number of times this callback function is executed. /* A count is kept of the number of times this callback function is executed.
The count is stored as the timer's ID. This is only done to test the * The count is stored as the timer's ID. This is only done to test the
vTimerSetTimerID() function. */ * vTimerSetTimerID() function. */
static size_t uxCallCount = 0; static size_t uxCallCount = 0;
size_t uxLastCallCount; size_t uxLastCallCount;
/* Obtain the timer's ID, which should be a count of the number of times /* Obtain the timer's ID, which should be a count of the number of times
this callback function has been executed. */ * this callback function has been executed. */
uxLastCallCount = ( size_t ) pvTimerGetTimerID( pxExpiredTimer ); uxLastCallCount = ( size_t ) pvTimerGetTimerID( pxExpiredTimer );
configASSERT( uxLastCallCount == uxCallCount ); configASSERT( uxLastCallCount == uxCallCount );
/* Increment the call count, then save it back as the timer's ID. This is /* Increment the call count, then save it back as the timer's ID. This is
only done to test the vTimerSetTimerID() API function. */ * only done to test the vTimerSetTimerID() API function. */
uxLastCallCount++; uxLastCallCount++;
vTimerSetTimerID( pxExpiredTimer, ( void * ) uxLastCallCount ); vTimerSetTimerID( pxExpiredTimer, ( void * ) uxLastCallCount );
uxCallCount++; uxCallCount++;
@ -1148,7 +1155,7 @@ size_t uxLastCallCount;
static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer ) static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
{ {
/* The parameter is not used in this case as only one timer uses this /* The parameter is not used in this case as only one timer uses this
callback function. */ * callback function. */
( void ) pxExpiredTimer; ( void ) pxExpiredTimer;
ucISRAutoReloadTimerCounter++; ucISRAutoReloadTimerCounter++;
@ -1158,13 +1165,9 @@ static void prvISRAutoReloadTimerCallback( TimerHandle_t pxExpiredTimer )
static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer ) static void prvISROneShotTimerCallback( TimerHandle_t pxExpiredTimer )
{ {
/* The parameter is not used in this case as only one timer uses this /* The parameter is not used in this case as only one timer uses this
callback function. */ * callback function. */
( void ) pxExpiredTimer; ( void ) pxExpiredTimer;
ucISROneShotTimerCounter++; ucISROneShotTimerCounter++;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/

View file

@ -62,7 +62,7 @@
#define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 ) #define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 )
/* In case the demo does not have software timers enabled, as this file uses /* In case the demo does not have software timers enabled, as this file uses
the configTIMER_TASK_PRIORITY setting. */ * the configTIMER_TASK_PRIORITY setting. */
#ifndef configTIMER_TASK_PRIORITY #ifndef configTIMER_TASK_PRIORITY
#define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 ) #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
#endif #endif
@ -86,7 +86,7 @@ static void prvBasicDelayTests( void );
static QueueHandle_t xTestQueue; static QueueHandle_t xTestQueue;
/* Handle to the secondary task is required by the primary task for calls /* Handle to the secondary task is required by the primary task for calls
to vTaskSuspend/Resume(). */ * to vTaskSuspend/Resume(). */
static TaskHandle_t xSecondary; static TaskHandle_t xSecondary;
/* Used to ensure that tasks are still executing without error. */ /* Used to ensure that tasks are still executing without error. */
@ -94,7 +94,7 @@ static volatile BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;
static volatile BaseType_t xErrorOccurred = pdFALSE; static volatile BaseType_t xErrorOccurred = pdFALSE;
/* Provides a simple mechanism for the primary task to know when the /* Provides a simple mechanism for the primary task to know when the
secondary task has executed. */ * secondary task has executed. */
static volatile UBaseType_t xRunIndicator; static volatile UBaseType_t xRunIndicator;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -107,11 +107,11 @@ void vCreateBlockTimeTasks( void )
if( xTestQueue != NULL ) if( xTestQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one /* vQueueAddToRegistry() adds the queue to the queue registry, if one
is in use. The queue registry is provided as a means for kernel aware * is in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware * debuggers to locate queues and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will be * debugger is not being used. The call to vQueueAddToRegistry() will be
removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
defined or is defined to be less than 1. */ * defined or is defined to be less than 1. */
vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" ); vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" );
/* Create the two test tasks. */ /* Create the two test tasks. */
@ -132,26 +132,25 @@ TickType_t xTimeToBlock, xBlockedTime;
for( ; ; ) for( ; ; )
{ {
/********************************************************************* /*********************************************************************
Test 0 * Test 0
*
Basic vTaskDelay() and vTaskDelayUntil() tests. */ * Basic vTaskDelay() and vTaskDelayUntil() tests. */
prvBasicDelayTests(); prvBasicDelayTests();
/********************************************************************* /*********************************************************************
Test 1 * Test 1
*
Simple block time wakeup test on queue receives. */ * Simple block time wakeup test on queue receives. */
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{ {
/* The queue is empty. Attempt to read from the queue using a block /* The queue is empty. Attempt to read from the queue using a block
time. When we wake, ensure the delta in time is as expected. */ * time. When we wake, ensure the delta in time is as expected. */
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem ); xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
xTimeWhenBlocking = xTaskGetTickCount(); xTimeWhenBlocking = xTaskGetTickCount();
/* We should unblock after xTimeToBlock having not received /* We should unblock after xTimeToBlock having not received
anything on the queue. */ * anything on the queue. */
if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY ) if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -169,18 +168,18 @@ TickType_t xTimeToBlock, xBlockedTime;
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) ) if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
{ {
/* Should not have blocked for longer than we requested, /* Should not have blocked for longer than we requested,
although we would not necessarily run as soon as we were * although we would not necessarily run as soon as we were
unblocked so a margin is allowed. */ * unblocked so a margin is allowed. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
} }
/********************************************************************* /*********************************************************************
Test 2 * Test 2
*
Simple block time wakeup test on queue sends. * Simple block time wakeup test on queue sends.
*
First fill the queue. It should be empty so all sends should pass. */ * First fill the queue. It should be empty so all sends should pass. */
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{ {
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
@ -196,13 +195,13 @@ TickType_t xTimeToBlock, xBlockedTime;
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{ {
/* The queue is full. Attempt to write to the queue using a block /* The queue is full. Attempt to write to the queue using a block
time. When we wake, ensure the delta in time is as expected. */ * time. When we wake, ensure the delta in time is as expected. */
xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem ); xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
xTimeWhenBlocking = xTaskGetTickCount(); xTimeWhenBlocking = xTaskGetTickCount();
/* We should unblock after xTimeToBlock having not received /* We should unblock after xTimeToBlock having not received
anything on the queue. */ * anything on the queue. */
if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL ) if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -220,24 +219,24 @@ TickType_t xTimeToBlock, xBlockedTime;
if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) ) if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
{ {
/* Should not have blocked for longer than we requested, /* Should not have blocked for longer than we requested,
although we would not necessarily run as soon as we were * although we would not necessarily run as soon as we were
unblocked so a margin is allowed. */ * unblocked so a margin is allowed. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
} }
/********************************************************************* /*********************************************************************
Test 3 * Test 3
*
Wake the other task, it will block attempting to post to the queue. * Wake the other task, it will block attempting to post to the queue.
When we read from the queue the other task will wake, but before it * When we read from the queue the other task will wake, but before it
can run we will post to the queue again. When the other task runs it * can run we will post to the queue again. When the other task runs it
will find the queue still full, even though it was woken. It should * will find the queue still full, even though it was woken. It should
recognise that its block time has not expired and return to block for * recognise that its block time has not expired and return to block for
the remains of its block time. * the remains of its block time.
*
Wake the other task so it blocks attempting to post to the already * Wake the other task so it blocks attempting to post to the already
full queue. */ * full queue. */
xRunIndicator = 0; xRunIndicator = 0;
vTaskResume( xSecondary ); vTaskResume( xSecondary );
@ -247,6 +246,7 @@ TickType_t xTimeToBlock, xBlockedTime;
/* The other task has not yet executed. */ /* The other task has not yet executed. */
vTaskDelay( bktSHORT_WAIT ); vTaskDelay( bktSHORT_WAIT );
} }
/* Make sure the other task is blocked on the queue. */ /* Make sure the other task is blocked on the queue. */
vTaskDelay( bktSHORT_WAIT ); vTaskDelay( bktSHORT_WAIT );
xRunIndicator = 0; xRunIndicator = 0;
@ -254,15 +254,15 @@ TickType_t xTimeToBlock, xBlockedTime;
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{ {
/* Now when we make space on the queue the other task should wake /* Now when we make space on the queue the other task should wake
but not execute as this task has higher priority. */ * but not execute as this task has higher priority. */
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Now fill the queue again before the other task gets a chance to /* Now fill the queue again before the other task gets a chance to
execute. If the other task had executed we would find the queue * execute. If the other task had executed we would find the queue
full ourselves, and the other task have set xRunIndicator. */ * full ourselves, and the other task have set xRunIndicator. */
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -275,15 +275,15 @@ TickType_t xTimeToBlock, xBlockedTime;
} }
/* Raise the priority of the other task so it executes and blocks /* Raise the priority of the other task so it executes and blocks
on the queue again. */ * on the queue again. */
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 ); vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
/* The other task should now have re-blocked without exiting the /* The other task should now have re-blocked without exiting the
queue function. */ * queue function. */
if( xRunIndicator == bktRUN_INDICATOR ) if( xRunIndicator == bktRUN_INDICATOR )
{ {
/* The other task should not have executed outside of the /* The other task should not have executed outside of the
queue function. */ * queue function. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
@ -292,22 +292,22 @@ TickType_t xTimeToBlock, xBlockedTime;
} }
/* Let the other task timeout. When it unblockes it will check that it /* Let the other task timeout. When it unblockes it will check that it
unblocked at the correct time, then suspend itself. */ * unblocked at the correct time, then suspend itself. */
while( xRunIndicator != bktRUN_INDICATOR ) while( xRunIndicator != bktRUN_INDICATOR )
{ {
vTaskDelay( bktSHORT_WAIT ); vTaskDelay( bktSHORT_WAIT );
} }
vTaskDelay( bktSHORT_WAIT ); vTaskDelay( bktSHORT_WAIT );
xRunIndicator = 0; xRunIndicator = 0;
/********************************************************************* /*********************************************************************
Test 4 * Test 4
*
As per test 3 - but with the send and receive the other way around. * As per test 3 - but with the send and receive the other way around.
The other task blocks attempting to read from the queue. * The other task blocks attempting to read from the queue.
*
Empty the queue. We should find that it is full. */ * Empty the queue. We should find that it is full. */
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{ {
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
@ -317,7 +317,7 @@ TickType_t xTimeToBlock, xBlockedTime;
} }
/* Wake the other task so it blocks attempting to read from the /* Wake the other task so it blocks attempting to read from the
already empty queue. */ * already empty queue. */
vTaskResume( xSecondary ); vTaskResume( xSecondary );
/* We need to wait a little to ensure the other task executes. */ /* We need to wait a little to ensure the other task executes. */
@ -325,21 +325,22 @@ TickType_t xTimeToBlock, xBlockedTime;
{ {
vTaskDelay( bktSHORT_WAIT ); vTaskDelay( bktSHORT_WAIT );
} }
vTaskDelay( bktSHORT_WAIT ); vTaskDelay( bktSHORT_WAIT );
xRunIndicator = 0; xRunIndicator = 0;
for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ ) for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
{ {
/* Now when we place an item on the queue the other task should /* Now when we place an item on the queue the other task should
wake but not execute as this task has higher priority. */ * wake but not execute as this task has higher priority. */
if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS ) if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Now empty the queue again before the other task gets a chance to /* Now empty the queue again before the other task gets a chance to
execute. If the other task had executed we would find the queue * execute. If the other task had executed we would find the queue
empty ourselves, and the other task would be suspended. */ * empty ourselves, and the other task would be suspended. */
if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS ) if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -352,26 +353,28 @@ TickType_t xTimeToBlock, xBlockedTime;
} }
/* Raise the priority of the other task so it executes and blocks /* Raise the priority of the other task so it executes and blocks
on the queue again. */ * on the queue again. */
vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 ); vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
/* The other task should now have re-blocked without exiting the /* The other task should now have re-blocked without exiting the
queue function. */ * queue function. */
if( xRunIndicator == bktRUN_INDICATOR ) if( xRunIndicator == bktRUN_INDICATOR )
{ {
/* The other task should not have executed outside of the /* The other task should not have executed outside of the
queue function. */ * queue function. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY ); vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
} }
/* Let the other task timeout. When it unblockes it will check that it /* Let the other task timeout. When it unblockes it will check that it
unblocked at the correct time, then suspend itself. */ * unblocked at the correct time, then suspend itself. */
while( xRunIndicator != bktRUN_INDICATOR ) while( xRunIndicator != bktRUN_INDICATOR )
{ {
vTaskDelay( bktSHORT_WAIT ); vTaskDelay( bktSHORT_WAIT );
} }
vTaskDelay( bktSHORT_WAIT ); vTaskDelay( bktSHORT_WAIT );
xPrimaryCycles++; xPrimaryCycles++;
@ -389,23 +392,24 @@ BaseType_t xData;
for( ; ; ) for( ; ; )
{ {
/********************************************************************* /*********************************************************************
Test 0, 1 and 2 * Test 0, 1 and 2
*
This task does not participate in these tests. */ * This task does not participate in these tests. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/********************************************************************* /*********************************************************************
Test 3 * Test 3
*
The first thing we do is attempt to read from the queue. It should be * The first thing we do is attempt to read from the queue. It should be
full so we block. Note the time before we block so we can check the * full so we block. Note the time before we block so we can check the
wake time is as per that expected. */ * wake time is as per that expected. */
xTimeWhenBlocking = xTaskGetTickCount(); xTimeWhenBlocking = xTaskGetTickCount();
/* We should unblock after bktTIME_TO_BLOCK having not sent anything to /* We should unblock after bktTIME_TO_BLOCK having not sent anything to
the queue. */ * the queue. */
xData = 0; xData = 0;
xRunIndicator = bktRUN_INDICATOR; xRunIndicator = bktRUN_INDICATOR;
if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL ) if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -421,8 +425,8 @@ BaseType_t xData;
} }
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
either. A margin is permitted as we would not necessarily run as * either. A margin is permitted as we would not necessarily run as
soon as we unblocked. */ * soon as we unblocked. */
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) ) if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -433,14 +437,15 @@ BaseType_t xData;
vTaskSuspend( NULL ); vTaskSuspend( NULL );
/********************************************************************* /*********************************************************************
Test 4 * Test 4
*
As per test three, but with the send and receive reversed. */ * As per test three, but with the send and receive reversed. */
xTimeWhenBlocking = xTaskGetTickCount(); xTimeWhenBlocking = xTaskGetTickCount();
/* We should unblock after bktTIME_TO_BLOCK having not received /* We should unblock after bktTIME_TO_BLOCK having not received
anything on the queue. */ * anything on the queue. */
xRunIndicator = bktRUN_INDICATOR; xRunIndicator = bktRUN_INDICATOR;
if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY ) if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -455,8 +460,8 @@ BaseType_t xData;
} }
/* We should of not blocked for much longer than bktALLOWABLE_MARGIN /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
either. A margin is permitted as we would not necessarily run as soon * either. A margin is permitted as we would not necessarily run as soon
as we unblocked. */ * as we unblocked. */
if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) ) if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -476,17 +481,17 @@ const TickType_t xPeriod = 75, xCycles = 5, xAllowableMargin = ( bktALLOWABLE_MA
BaseType_t xDidBlock; BaseType_t xDidBlock;
/* Temporarily increase priority so the timing is more accurate, but not so /* Temporarily increase priority so the timing is more accurate, but not so
high as to disrupt the timer tests. */ * high as to disrupt the timer tests. */
vTaskPrioritySet( NULL, configTIMER_TASK_PRIORITY - 1 ); vTaskPrioritySet( NULL, configTIMER_TASK_PRIORITY - 1 );
/* Crude check to too see that vTaskDelay() blocks for the expected /* Crude check to too see that vTaskDelay() blocks for the expected
period. */ * period. */
xPreTime = xTaskGetTickCount(); xPreTime = xTaskGetTickCount();
vTaskDelay( bktTIME_TO_BLOCK ); vTaskDelay( bktTIME_TO_BLOCK );
xPostTime = xTaskGetTickCount(); xPostTime = xTaskGetTickCount();
/* The priority is higher, so the allowable margin is halved when compared /* The priority is higher, so the allowable margin is halved when compared
to the other tests in this file. */ * to the other tests in this file. */
if( ( xPostTime - xPreTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) ) if( ( xPostTime - xPreTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -499,7 +504,7 @@ BaseType_t xDidBlock;
for( x = 0; x < xCycles; x++ ) for( x = 0; x < xCycles; x++ )
{ {
/* Calculate the next expected unblock time from the time taken before /* Calculate the next expected unblock time from the time taken before
this loop was entered. */ * this loop was entered. */
xExpectedUnblockTime = xPostTime + ( x * xPeriod ); xExpectedUnblockTime = xPostTime + ( x * xPeriod );
vTaskDelayUntil( &xLastUnblockTime, xPeriod ); vTaskDelayUntil( &xLastUnblockTime, xPeriod );
@ -513,26 +518,29 @@ BaseType_t xDidBlock;
} }
/* Crude tests for return value of xTaskDelayUntil(). First a standard block /* Crude tests for return value of xTaskDelayUntil(). First a standard block
should return that the task does block. */ * should return that the task does block. */
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdTRUE ) if( xDidBlock != pdTRUE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Now delay a few ticks so repeating the above block period will not block for /* Now delay a few ticks so repeating the above block period will not block for
the full amount of time, but will still block. */ * the full amount of time, but will still block. */
vTaskDelay( xHalfPeriod ); vTaskDelay( xHalfPeriod );
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdTRUE ) if( xDidBlock != pdTRUE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* This time block for longer than xPeriod before calling xTaskDelayUntil() so /* This time block for longer than xPeriod before calling xTaskDelayUntil() so
the call to xTaskDelayUntil() should not block. */ * the call to xTaskDelayUntil() should not block. */
vTaskDelay( xPeriod ); vTaskDelay( xPeriod );
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdFALSE ) if( xDidBlock != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -540,15 +548,17 @@ BaseType_t xDidBlock;
/* Catch up. */ /* Catch up. */
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdTRUE ) if( xDidBlock != pdTRUE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Again block for slightly longer than a period so ensure the time is in the /* Again block for slightly longer than a period so ensure the time is in the
past next time xTaskDelayUntil() gets called. */ * past next time xTaskDelayUntil() gets called. */
vTaskDelay( xPeriod + xAllowableMargin ); vTaskDelay( xPeriod + xAllowableMargin );
xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod ); xDidBlock = xTaskDelayUntil( &xLastUnblockTime, xPeriod );
if( xDidBlock != pdFALSE ) if( xDidBlock != pdFALSE )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -565,7 +575,7 @@ static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
BaseType_t xReturn = pdPASS; BaseType_t xReturn = pdPASS;
/* Have both tasks performed at least one cycle since this function was /* Have both tasks performed at least one cycle since this function was
last called? */ * last called? */
if( xPrimaryCycles == xLastPrimaryCycleCount ) if( xPrimaryCycles == xLastPrimaryCycleCount )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;

View file

@ -73,13 +73,13 @@
#define comTOTAL_PERMISSIBLE_ERRORS ( 2 ) #define comTOTAL_PERMISSIBLE_ERRORS ( 2 )
/* The Tx task will transmit the sequence of characters at a pseudo random /* The Tx task will transmit the sequence of characters at a pseudo random
interval. This is the maximum and minimum block time between sends. */ * interval. This is the maximum and minimum block time between sends. */
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 ) #define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 )
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 ) #define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 )
#define comOFFSET_TIME ( ( TickType_t ) 3 ) #define comOFFSET_TIME ( ( TickType_t ) 3 )
/* We should find that each character can be queued for Tx immediately and we /* We should find that each character can be queued for Tx immediately and we
don't have to block to send. */ * don't have to block to send. */
#define comNO_BLOCK ( ( TickType_t ) 0 ) #define comNO_BLOCK ( ( TickType_t ) 0 )
/* The Rx task will block on the Rx queue for a long period. */ /* The Rx task will block on the Rx queue for a long period. */
@ -102,18 +102,20 @@ static portTASK_FUNCTION_PROTO( vComTxTask, pvParameters );
static portTASK_FUNCTION_PROTO( vComRxTask, pvParameters ); static portTASK_FUNCTION_PROTO( vComRxTask, pvParameters );
/* The LED that should be toggled by the Rx and Tx tasks. The Rx task will /* The LED that should be toggled by the Rx and Tx tasks. The Rx task will
toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task will toggle LED * toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task will toggle LED
( uxBaseLED + comTX_LED_OFFSET ). */ * ( uxBaseLED + comTX_LED_OFFSET ). */
static UBaseType_t uxBaseLED = 0; static UBaseType_t uxBaseLED = 0;
/* Check variable used to ensure no error have occurred. The Rx task will /* Check variable used to ensure no error have occurred. The Rx task will
increment this variable after every successfully received sequence. If at any * increment this variable after every successfully received sequence. If at any
time the sequence is incorrect the the variable will stop being incremented. */ * time the sequence is incorrect the the variable will stop being incremented. */
static volatile UBaseType_t uxRxLoops = comINITIAL_RX_COUNT_VALUE; static volatile UBaseType_t uxRxLoops = comINITIAL_RX_COUNT_VALUE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vAltStartComTestTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ) void vAltStartComTestTasks( UBaseType_t uxPriority,
uint32_t ulBaudRate,
UBaseType_t uxLED )
{ {
/* Initialise the com port then spawn the Rx and Tx tasks. */ /* Initialise the com port then spawn the Rx and Tx tasks. */
uxBaseLED = uxLED; uxBaseLED = uxLED;
@ -136,7 +138,7 @@ TickType_t xTimeToWait;
for( ; ; ) for( ; ; )
{ {
/* Simply transmit a sequence of characters from comFIRST_BYTE to /* Simply transmit a sequence of characters from comFIRST_BYTE to
comLAST_BYTE. */ * comLAST_BYTE. */
for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ ) for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ )
{ {
if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS ) if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS )
@ -149,8 +151,8 @@ TickType_t xTimeToWait;
vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE ); vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE );
/* We have posted all the characters in the string - wait before /* We have posted all the characters in the string - wait before
re-sending. Wait a pseudo-random time as this will provide a better * re-sending. Wait a pseudo-random time as this will provide a better
test. */ * test. */
xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME; xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
/* Make sure we don't wait too long... */ /* Make sure we don't wait too long... */
@ -178,16 +180,16 @@ BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
for( ; ; ) for( ; ; )
{ {
/* We expect to receive the characters from comFIRST_BYTE to /* We expect to receive the characters from comFIRST_BYTE to
comLAST_BYTE in an incrementing order. Loop to receive each byte. */ * comLAST_BYTE in an incrementing order. Loop to receive each byte. */
for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ ) for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ )
{ {
/* Block on the queue that contains received bytes until a byte is /* Block on the queue that contains received bytes until a byte is
available. */ * available. */
if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) ) if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) )
{ {
/* Was this the byte we were expecting? If so, toggle the LED, /* Was this the byte we were expecting? If so, toggle the LED,
otherwise we are out on sync and should break out of the loop * otherwise we are out on sync and should break out of the loop
until the expected character sequence is about to restart. */ * until the expected character sequence is about to restart. */
if( cByteRxed == cExpectedByte ) if( cByteRxed == cExpectedByte )
{ {
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET ); vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
@ -204,8 +206,8 @@ BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE ); vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE );
/* Did we break out of the loop because the characters were received in /* Did we break out of the loop because the characters were received in
an unexpected order? If so wait here until the character sequence is * an unexpected order? If so wait here until the character sequence is
about to restart. */ * about to restart. */
if( xResyncRequired == pdTRUE ) if( xResyncRequired == pdTRUE )
{ {
while( cByteRxed != comLAST_BYTE ) while( cByteRxed != comLAST_BYTE )
@ -215,9 +217,9 @@ BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
} }
/* Note that an error occurred which caused us to have to resync. /* Note that an error occurred which caused us to have to resync.
We use this to stop incrementing the loop counter so * We use this to stop incrementing the loop counter so
sAreComTestTasksStillRunning() will return false - indicating an * sAreComTestTasksStillRunning() will return false - indicating an
error. */ * error. */
xErrorOccurred++; xErrorOccurred++;
/* We have now resynced with the Tx task and can continue. */ /* We have now resynced with the Tx task and can continue. */
@ -228,11 +230,11 @@ BaseType_t xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS ) if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS )
{ {
/* Increment the count of successful loops. As error /* Increment the count of successful loops. As error
occurring (i.e. an unexpected character being received) will * occurring (i.e. an unexpected character being received) will
prevent this counter being incremented for the rest of the * prevent this counter being incremented for the rest of the
execution. Don't worry about mutual exclusion on this * execution. Don't worry about mutual exclusion on this
variable - it doesn't really matter as we just want it * variable - it doesn't really matter as we just want it
to change. */ * to change. */
uxRxLoops++; uxRxLoops++;
} }
} }
@ -245,8 +247,8 @@ BaseType_t xAreComTestTasksStillRunning( void )
BaseType_t xReturn; BaseType_t xReturn;
/* If the count of successful reception loops has not changed than at /* If the count of successful reception loops has not changed than at
some time an error occurred (i.e. a character was received out of sequence) * some time an error occurred (i.e. a character was received out of sequence)
and we will return false. */ * and we will return false. */
if( uxRxLoops == comINITIAL_RX_COUNT_VALUE ) if( uxRxLoops == comINITIAL_RX_COUNT_VALUE )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
@ -257,9 +259,8 @@ BaseType_t xReturn;
} }
/* Reset the count of successful Rx loops. When this function is called /* Reset the count of successful Rx loops. When this function is called
again we expect this to have been incremented. */ * again we expect this to have been incremented. */
uxRxLoops = comINITIAL_RX_COUNT_VALUE; uxRxLoops = comINITIAL_RX_COUNT_VALUE;
return xReturn; return xReturn;
} }

View file

@ -78,8 +78,8 @@
#define comRX_LED_OFFSET ( 1 ) #define comRX_LED_OFFSET ( 1 )
/* The Tx timer transmits the sequence of characters at a pseudo random /* The Tx timer transmits the sequence of characters at a pseudo random
interval that is capped between comTX_MAX_BLOCK_TIME and * interval that is capped between comTX_MAX_BLOCK_TIME and
comTX_MIN_BLOCK_TIME. */ * comTX_MIN_BLOCK_TIME. */
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 ) #define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x96 )
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 ) #define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0x32 )
#define comOFFSET_TIME ( ( TickType_t ) 3 ) #define comOFFSET_TIME ( ( TickType_t ) 3 )
@ -89,10 +89,10 @@ comTX_MIN_BLOCK_TIME. */
#define comtstWAITING_END_OF_STRING 1 #define comtstWAITING_END_OF_STRING 1
/* A short delay in ticks - this delay is used to allow the Rx queue to fill up /* A short delay in ticks - this delay is used to allow the Rx queue to fill up
a bit so more than one character can be processed at a time. This is relative * a bit so more than one character can be processed at a time. This is relative
to comTX_MIN_BLOCK_TIME to ensure it is never longer than the shortest gap * to comTX_MIN_BLOCK_TIME to ensure it is never longer than the shortest gap
between transmissions. It could be worked out more scientifically from the * between transmissions. It could be worked out more scientifically from the
baud rate being used. */ * baud rate being used. */
#define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( TickType_t ) 2 ) #define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( TickType_t ) 2 )
/* The string that is transmitted and received. */ /* The string that is transmitted and received. */
@ -105,50 +105,52 @@ baud rate being used. */
static xComPortHandle xPort = NULL; static xComPortHandle xPort = NULL;
/* The callback function allocated to the transmit timer, as described in the /* The callback function allocated to the transmit timer, as described in the
comments at the top of this file. */ * comments at the top of this file. */
static void prvComTxTimerCallback( TimerHandle_t xTimer ); static void prvComTxTimerCallback( TimerHandle_t xTimer );
/* The receive task as described in the comments at the top of this file. */ /* The receive task as described in the comments at the top of this file. */
static void vComRxTask( void * pvParameters ); static void vComRxTask( void * pvParameters );
/* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task /* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task
will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */ * will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */
static UBaseType_t uxBaseLED = 0; static UBaseType_t uxBaseLED = 0;
/* The Rx task toggles uxRxLoops on each successful iteration of its defined /* The Rx task toggles uxRxLoops on each successful iteration of its defined
function - provided no errors have ever been latched. If this variable stops * function - provided no errors have ever been latched. If this variable stops
incrementing, then an error has occurred. */ * incrementing, then an error has occurred. */
static volatile UBaseType_t uxRxLoops = 0UL; static volatile UBaseType_t uxRxLoops = 0UL;
/* The timer used to periodically transmit the string. This is the timer that /* The timer used to periodically transmit the string. This is the timer that
has prvComTxTimerCallback allocated to it as its callback function. */ * has prvComTxTimerCallback allocated to it as its callback function. */
static TimerHandle_t xTxTimer = NULL; static TimerHandle_t xTxTimer = NULL;
/* The string length is held at file scope so the Tx timer does not need to /* The string length is held at file scope so the Tx timer does not need to
calculate it each time it executes. */ * calculate it each time it executes. */
static size_t xStringLength = 0U; static size_t xStringLength = 0U;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
void vStartComTestStringsTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ) void vStartComTestStringsTasks( UBaseType_t uxPriority,
uint32_t ulBaudRate,
UBaseType_t uxLED )
{ {
/* Store values that are used at run time. */ /* Store values that are used at run time. */
uxBaseLED = uxLED; uxBaseLED = uxLED;
/* Calculate the string length here, rather than each time the Tx timer /* Calculate the string length here, rather than each time the Tx timer
executes. */ * executes. */
xStringLength = strlen( comTRANSACTED_STRING ); xStringLength = strlen( comTRANSACTED_STRING );
/* Include the null terminator in the string length as this is used to /* Include the null terminator in the string length as this is used to
detect the end of the string in the Rx task. */ * detect the end of the string in the Rx task. */
xStringLength++; xStringLength++;
/* Initialise the com port, then spawn the Rx task and create the Tx /* Initialise the com port, then spawn the Rx task and create the Tx
timer. */ * timer. */
xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) ); xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) );
/* Create the Rx task and the Tx timer. The timer is started from the /* Create the Rx task and the Tx timer. The timer is started from the
Rx task. */ * Rx task. */
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority, ( TaskHandle_t * ) NULL );
xTxTimer = xTimerCreate( "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback ); xTxTimer = xTimerCreate( "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback );
configASSERT( xTxTimer ); configASSERT( xTxTimer );
@ -163,13 +165,13 @@ TickType_t xTimeToWait;
( void ) xTimer; ( void ) xTimer;
/* Send the string. How this is actually performed depends on the /* Send the string. How this is actually performed depends on the
sample driver provided with this demo. However - as this is a timer, * sample driver provided with this demo. However - as this is a timer,
it executes in the context of the timer task and therefore must not * it executes in the context of the timer task and therefore must not
block. */ * block. */
vSerialPutString( xPort, comTRANSACTED_STRING, xStringLength ); vSerialPutString( xPort, comTRANSACTED_STRING, xStringLength );
/* Toggle an LED to give a visible indication that another transmission /* Toggle an LED to give a visible indication that another transmission
has been performed. */ * has been performed. */
vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET ); vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
/* Wait a pseudo random time before sending the string again. */ /* Wait a pseudo random time before sending the string again. */
@ -185,8 +187,8 @@ TickType_t xTimeToWait;
} }
/* Reset the timer to run again xTimeToWait ticks from now. This function /* Reset the timer to run again xTimeToWait ticks from now. This function
is called from the context of the timer task, so the block time must not * is called from the context of the timer task, so the block time must not
be anything other than zero. */ * be anything other than zero. */
xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK ); xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK );
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -201,11 +203,11 @@ const xComPortHandle xPort = NULL;
( void ) pvParameters; ( void ) pvParameters;
/* Start the Tx timer. This only needs to be started once, as it will /* Start the Tx timer. This only needs to be started once, as it will
reset itself thereafter. */ * reset itself thereafter. */
xTimerStart( xTxTimer, portMAX_DELAY ); xTimerStart( xTxTimer, portMAX_DELAY );
/* The first expected Rx character is the first in the string that is /* The first expected Rx character is the first in the string that is
transmitted. */ * transmitted. */
pcExpectedByte = comTRANSACTED_STRING; pcExpectedByte = comTRANSACTED_STRING;
for( ; ; ) for( ; ; )
@ -214,47 +216,50 @@ const xComPortHandle xPort = NULL;
if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE ) if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE )
{ {
/* A character definitely should have been received by now. As a /* A character definitely should have been received by now. As a
character was not received an error must have occurred (which might * character was not received an error must have occurred (which might
just be that the loopback connector is not fitted). */ * just be that the loopback connector is not fitted). */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
switch( xState ) switch( xState )
{ {
case comtstWAITING_START_OF_STRING: case comtstWAITING_START_OF_STRING:
if( cRxedChar == *pcExpectedByte ) if( cRxedChar == *pcExpectedByte )
{ {
/* The received character was the first character of the /* The received character was the first character of the
string. Move to the next state to check each character * string. Move to the next state to check each character
as it comes in until the entire string has been received. */ * as it comes in until the entire string has been received. */
xState = comtstWAITING_END_OF_STRING; xState = comtstWAITING_END_OF_STRING;
pcExpectedByte++; pcExpectedByte++;
/* Block for a short period. This just allows the Rx queue /* Block for a short period. This just allows the Rx queue
to contain more than one character, and therefore prevent * to contain more than one character, and therefore prevent
thrashing reads to the queue, and repetitive context * thrashing reads to the queue, and repetitive context
switches as each character is received. */ * switches as each character is received. */
vTaskDelay( comSHORT_DELAY ); vTaskDelay( comSHORT_DELAY );
} }
break; break;
case comtstWAITING_END_OF_STRING: case comtstWAITING_END_OF_STRING:
if( cRxedChar == *pcExpectedByte ) if( cRxedChar == *pcExpectedByte )
{ {
/* The received character was the expected character. Was /* The received character was the expected character. Was
it the last character in the string - i.e. the null * it the last character in the string - i.e. the null
terminator? */ * terminator? */
if( cRxedChar == 0x00 ) if( cRxedChar == 0x00 )
{ {
/* The entire string has been received. If no errors /* The entire string has been received. If no errors
have been latched, then increment the loop counter to * have been latched, then increment the loop counter to
show this task is still healthy. */ * show this task is still healthy. */
if( xErrorOccurred == pdFALSE ) if( xErrorOccurred == pdFALSE )
{ {
uxRxLoops++; uxRxLoops++;
/* Toggle an LED to give a visible sign that a /* Toggle an LED to give a visible sign that a
complete string has been received. */ * complete string has been received. */
vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET ); vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
} }
@ -273,11 +278,13 @@ const xComPortHandle xPort = NULL;
/* The character received was not that expected. */ /* The character received was not that expected. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
break; break;
default: default:
/* Should not get here. Stop the Rx loop counter from /* Should not get here. Stop the Rx loop counter from
incrementing to latch the error. */ * incrementing to latch the error. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
break; break;
} }
@ -290,8 +297,8 @@ BaseType_t xAreComTestTasksStillRunning( void )
BaseType_t xReturn; BaseType_t xReturn;
/* If the count of successful reception loops has not changed than at /* If the count of successful reception loops has not changed than at
some time an error occurred (i.e. a character was received out of sequence) * some time an error occurred (i.e. a character was received out of sequence)
and false is returned. */ * and false is returned. */
if( uxRxLoops == 0UL ) if( uxRxLoops == 0UL )
{ {
xReturn = pdFALSE; xReturn = pdFALSE;
@ -302,9 +309,8 @@ BaseType_t xReturn;
} }
/* Reset the count of successful Rx loops. When this function is called /* Reset the count of successful Rx loops. When this function is called
again it should have been incremented again. */ * again it should have been incremented again. */
uxRxLoops = 0UL; uxRxLoops = 0UL;
return xReturn; return xReturn;
} }

View file

@ -42,21 +42,21 @@
#define countMAX_COUNT_VALUE ( 200 ) #define countMAX_COUNT_VALUE ( 200 )
/* Constants used to indicate whether or not the semaphore should have been /* Constants used to indicate whether or not the semaphore should have been
created with its maximum count value, or its minimum count value. These * created with its maximum count value, or its minimum count value. These
numbers are used to ensure that the pointers passed in as the task parameters * numbers are used to ensure that the pointers passed in as the task parameters
are valid. */ * are valid. */
#define countSTART_AT_MAX_COUNT ( 0xaa ) #define countSTART_AT_MAX_COUNT ( 0xaa )
#define countSTART_AT_ZERO ( 0x55 ) #define countSTART_AT_ZERO ( 0x55 )
/* Two tasks are created for the test. One uses a semaphore created with its /* Two tasks are created for the test. One uses a semaphore created with its
count value set to the maximum, and one with the count value set to zero. */ * count value set to the maximum, and one with the count value set to zero. */
#define countNUM_TEST_TASKS ( 2 ) #define countNUM_TEST_TASKS ( 2 )
#define countDONT_BLOCK ( 0 ) #define countDONT_BLOCK ( 0 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Flag that will be latched to pdTRUE should any unexpected behaviour be /* Flag that will be latched to pdTRUE should any unexpected behaviour be
detected in any of the tasks. */ * detected in any of the tasks. */
static volatile BaseType_t xErrorDetected = pdFALSE; static volatile BaseType_t xErrorDetected = pdFALSE;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -73,13 +73,15 @@ static void prvCountingSemaphoreTask( void *pvParameters );
* Utility function to increment the semaphore count value up from zero to * Utility function to increment the semaphore count value up from zero to
* countMAX_COUNT_VALUE. * countMAX_COUNT_VALUE.
*/ */
static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore, volatile UBaseType_t *puxLoopCounter ); static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
volatile UBaseType_t * puxLoopCounter );
/* /*
* Utility function to decrement the semaphore count value up from * Utility function to decrement the semaphore count value up from
* countMAX_COUNT_VALUE to zero. * countMAX_COUNT_VALUE to zero.
*/ */
static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore, volatile UBaseType_t *puxLoopCounter ); static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
volatile UBaseType_t * puxLoopCounter );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -90,12 +92,12 @@ typedef struct COUNT_SEM_STRUCT
SemaphoreHandle_t xSemaphore; SemaphoreHandle_t xSemaphore;
/* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with /* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with
its count value set to its max count value, or countSTART_AT_ZERO if it * its count value set to its max count value, or countSTART_AT_ZERO if it
should have been created with its count value set to 0. */ * should have been created with its count value set to 0. */
UBaseType_t uxExpectedStartCount; UBaseType_t uxExpectedStartCount;
/* Incremented on each cycle of the demo task. Used to detect a stalled /* Incremented on each cycle of the demo task. Used to detect a stalled
task. */ * task. */
volatile UBaseType_t uxLoopCounter; volatile UBaseType_t uxLoopCounter;
} xCountSemStruct; } xCountSemStruct;
@ -107,8 +109,8 @@ static xCountSemStruct xParameters[ countNUM_TEST_TASKS ];
void vStartCountingSemaphoreTasks( void ) void vStartCountingSemaphoreTasks( void )
{ {
/* Create the semaphores that we are going to use for the test/demo. The /* Create the semaphores that we are going to use for the test/demo. The
first should be created such that it starts at its maximum count value, * first should be created such that it starts at its maximum count value,
the second should be created such that it starts with a count value of zero. */ * the second should be created such that it starts with a count value of zero. */
xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE ); xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE );
xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT; xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT;
xParameters[ 0 ].uxLoopCounter = 0; xParameters[ 0 ].uxLoopCounter = 0;
@ -121,11 +123,11 @@ void vStartCountingSemaphoreTasks( void )
if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) ) if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) )
{ {
/* vQueueAddToRegistry() adds the semaphore to the registry, if one is /* vQueueAddToRegistry() adds the semaphore to the registry, if one is
in use. The registry is provided as a means for kernel aware * in use. The registry is provided as a means for kernel aware
debuggers to locate semaphores and has no purpose if a kernel aware * debuggers to locate semaphores and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will be * debugger is not being used. The call to vQueueAddToRegistry() will be
removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
defined or is defined to be less than 1. */ * defined or is defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 0 ].xSemaphore, "Counting_Sem_1" ); vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 0 ].xSemaphore, "Counting_Sem_1" );
vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 1 ].xSemaphore, "Counting_Sem_2" ); vQueueAddToRegistry( ( QueueHandle_t ) xParameters[ 1 ].xSemaphore, "Counting_Sem_2" );
@ -136,12 +138,13 @@ void vStartCountingSemaphoreTasks( void )
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore, volatile UBaseType_t *puxLoopCounter ) static void prvDecrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
volatile UBaseType_t * puxLoopCounter )
{ {
UBaseType_t ux; UBaseType_t ux;
/* If the semaphore count is at its maximum then we should not be able to /* If the semaphore count is at its maximum then we should not be able to
'give' the semaphore. */ * 'give' the semaphore. */
if( xSemaphoreGive( xSemaphore ) == pdPASS ) if( xSemaphoreGive( xSemaphore ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -166,8 +169,9 @@ UBaseType_t ux;
#endif #endif
/* If the semaphore count is zero then we should not be able to 'take' /* If the semaphore count is zero then we should not be able to 'take'
the semaphore. */ * the semaphore. */
configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 ); configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS ) if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -175,12 +179,13 @@ UBaseType_t ux;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore, volatile UBaseType_t *puxLoopCounter ) static void prvIncrementSemaphoreCount( SemaphoreHandle_t xSemaphore,
volatile UBaseType_t * puxLoopCounter )
{ {
UBaseType_t ux; UBaseType_t ux;
/* If the semaphore count is zero then we should not be able to 'take' /* If the semaphore count is zero then we should not be able to 'take'
the semaphore. */ * the semaphore. */
if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS ) if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -205,7 +210,7 @@ UBaseType_t ux;
#endif #endif
/* If the semaphore count is at its maximum then we should not be able to /* If the semaphore count is at its maximum then we should not be able to
'give' the semaphore. */ * 'give' the semaphore. */
if( xSemaphoreGive( xSemaphore ) == pdPASS ) if( xSemaphoreGive( xSemaphore ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -230,14 +235,14 @@ xCountSemStruct *pxParameter;
pxParameter = ( xCountSemStruct * ) pvParameters; pxParameter = ( xCountSemStruct * ) pvParameters;
/* Did we expect to find the semaphore already at its max count value, or /* Did we expect to find the semaphore already at its max count value, or
at zero? */ * at zero? */
if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT ) if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT )
{ {
prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) ); prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
} }
/* Now we expect the semaphore count to be 0, so this time there is an /* Now we expect the semaphore count to be 0, so this time there is an
error if we can take the semaphore. */ * error if we can take the semaphore. */
if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS ) if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS )
{ {
xErrorDetected = pdTRUE; xErrorDetected = pdTRUE;
@ -257,7 +262,7 @@ static UBaseType_t uxLastCount0 = 0, uxLastCount1 = 0;
BaseType_t xReturn = pdPASS; BaseType_t xReturn = pdPASS;
/* Return fail if any 'give' or 'take' did not result in the expected /* Return fail if any 'give' or 'take' did not result in the expected
behaviour. */ * behaviour. */
if( xErrorDetected != pdFALSE ) if( xErrorDetected != pdFALSE )
{ {
xReturn = pdFAIL; xReturn = pdFAIL;
@ -284,5 +289,3 @@ BaseType_t xReturn = pdPASS;
return xReturn; return xReturn;
} }

View file

@ -61,7 +61,7 @@
#include "crflash.h" #include "crflash.h"
/* The queue should only need to be of length 1. See the description at the /* The queue should only need to be of length 1. See the description at the
top of the file. */ * top of the file. */
#define crfQUEUE_LENGTH 1 #define crfQUEUE_LENGTH 1
#define crfFIXED_DELAY_PRIORITY 0 #define crfFIXED_DELAY_PRIORITY 0
@ -71,7 +71,7 @@ top of the file. */
#define crfFLASH_INDEX 0 #define crfFLASH_INDEX 0
/* Don't allow more than crfMAX_FLASH_TASKS 'fixed delay' co-routines to be /* Don't allow more than crfMAX_FLASH_TASKS 'fixed delay' co-routines to be
created. */ * created. */
#define crfMAX_FLASH_TASKS 8 #define crfMAX_FLASH_TASKS 8
/* We don't want to block when posting to the queue. */ /* We don't want to block when posting to the queue. */
@ -80,15 +80,17 @@ created. */
/* /*
* The 'fixed delay' co-routine as described at the top of the file. * The 'fixed delay' co-routine as described at the top of the file.
*/ */
static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ); static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex );
/* /*
* The 'flash' co-routine as described at the top of the file. * The 'flash' co-routine as described at the top of the file.
*/ */
static void prvFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ); static void prvFlashCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex );
/* The queue used to pass data between the 'fixed delay' co-routines and the /* The queue used to pass data between the 'fixed delay' co-routines and the
'flash' co-routine. */ * 'flash' co-routine. */
static QueueHandle_t xFlashQueue; static QueueHandle_t xFlashQueue;
/* This will be set to pdFALSE if we detect an error. */ /* This will be set to pdFALSE if we detect an error. */
@ -125,21 +127,26 @@ UBaseType_t uxIndex;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) static void prvFixedDelayCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex )
{ {
/* Even though this is a co-routine the xResult variable does not need to be /* Even though this is a co-routine the xResult variable does not need to be
static as we do not need it to maintain its state between blocks. */ * static as we do not need it to maintain its state between blocks. */
BaseType_t xResult; BaseType_t xResult;
/* The uxIndex parameter of the co-routine function is used as an index into /* The uxIndex parameter of the co-routine function is used as an index into
the xFlashRates array to obtain the delay period to use. */ * the xFlashRates array to obtain the delay period to use. */
static const TickType_t xFlashRates[ crfMAX_FLASH_TASKS ] = { 150 / portTICK_PERIOD_MS, static const TickType_t xFlashRates[ crfMAX_FLASH_TASKS ] =
{
150 / portTICK_PERIOD_MS,
200 / portTICK_PERIOD_MS, 200 / portTICK_PERIOD_MS,
250 / portTICK_PERIOD_MS, 250 / portTICK_PERIOD_MS,
300 / portTICK_PERIOD_MS, 300 / portTICK_PERIOD_MS,
350 / portTICK_PERIOD_MS, 350 / portTICK_PERIOD_MS,
400 / portTICK_PERIOD_MS, 400 / portTICK_PERIOD_MS,
450 / portTICK_PERIOD_MS, 450 / portTICK_PERIOD_MS,
500 / portTICK_PERIOD_MS }; 500 / portTICK_PERIOD_MS
};
/* Co-routines MUST start with a call to crSTART. */ /* Co-routines MUST start with a call to crSTART. */
crSTART( xHandle ); crSTART( xHandle );
@ -147,14 +154,14 @@ static const TickType_t xFlashRates[ crfMAX_FLASH_TASKS ] = { 150 / portTICK_PER
for( ; ; ) for( ; ; )
{ {
/* Post our uxIndex value onto the queue. This is used as the LED to /* Post our uxIndex value onto the queue. This is used as the LED to
flash. */ * flash. */
crQUEUE_SEND( xHandle, xFlashQueue, ( void * ) &uxIndex, crfPOSTING_BLOCK_TIME, &xResult ); crQUEUE_SEND( xHandle, xFlashQueue, ( void * ) &uxIndex, crfPOSTING_BLOCK_TIME, &xResult );
if( xResult != pdPASS ) if( xResult != pdPASS )
{ {
/* For the reasons stated at the top of the file we should always /* For the reasons stated at the top of the file we should always
find that we can post to the queue. If we could not then an error * find that we can post to the queue. If we could not then an error
has occurred. */ * has occurred. */
xCoRoutineFlashStatus = pdFAIL; xCoRoutineFlashStatus = pdFAIL;
} }
@ -166,10 +173,11 @@ static const TickType_t xFlashRates[ crfMAX_FLASH_TASKS ] = { 150 / portTICK_PER
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvFlashCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) static void prvFlashCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex )
{ {
/* Even though this is a co-routine the variable do not need to be /* Even though this is a co-routine the variable do not need to be
static as we do not need it to maintain their state between blocks. */ * static as we do not need it to maintain their state between blocks. */
BaseType_t xResult; BaseType_t xResult;
UBaseType_t uxLEDToFlash; UBaseType_t uxLEDToFlash;
@ -202,7 +210,6 @@ UBaseType_t uxLEDToFlash;
BaseType_t xAreFlashCoRoutinesStillRunning( void ) BaseType_t xAreFlashCoRoutinesStillRunning( void )
{ {
/* Return pdPASS or pdFAIL depending on whether an error has been detected /* Return pdPASS or pdFAIL depending on whether an error has been detected
or not. */ * or not. */
return xCoRoutineFlashStatus; return xCoRoutineFlashStatus;
} }

View file

@ -60,7 +60,7 @@
#define hookNUM_HOOK_CO_ROUTINES ( 4 ) #define hookNUM_HOOK_CO_ROUTINES ( 4 )
/* The number of times the tick hook should be called before a character is /* The number of times the tick hook should be called before a character is
posted to the 'hook' co-routines. */ * posted to the 'hook' co-routines. */
#define hookTICK_CALLS_BEFORE_POST ( 500 ) #define hookTICK_CALLS_BEFORE_POST ( 500 )
/* There should never be more than one item in any queue at any time. */ /* There should never be more than one item in any queue at any time. */
@ -70,14 +70,15 @@ posted to the 'hook' co-routines. */
#define hookNO_BLOCK_TIME ( 0 ) #define hookNO_BLOCK_TIME ( 0 )
/* The priority relative to other co-routines (rather than tasks) that the /* The priority relative to other co-routines (rather than tasks) that the
'hook' co-routines should take. */ * 'hook' co-routines should take. */
#define mainHOOK_CR_PRIORITY ( 1 ) #define mainHOOK_CR_PRIORITY ( 1 )
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
* The co-routine function itself. * The co-routine function itself.
*/ */
static void prvHookCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ); static void prvHookCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex );
/* /*
@ -90,13 +91,13 @@ void vApplicationTickHook( void );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Queues used to send data FROM a co-routine TO the tick hook function. /* Queues used to send data FROM a co-routine TO the tick hook function.
The hook functions received (Rx's) on these queues. One queue per * The hook functions received (Rx's) on these queues. One queue per
'hook' co-routine. */ * 'hook' co-routine. */
static QueueHandle_t xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ]; static QueueHandle_t xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ];
/* Queues used to send data FROM the tick hook TO a co-routine function. /* Queues used to send data FROM the tick hook TO a co-routine function.
The hood function transmits (Tx's) on these queues. One queue per * The hood function transmits (Tx's) on these queues. One queue per
'hook' co-routine. */ * 'hook' co-routine. */
static QueueHandle_t xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ]; static QueueHandle_t xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ];
/* Set to true if an error is detected at any time. */ /* Set to true if an error is detected at any time. */
@ -111,12 +112,12 @@ UBaseType_t uxIndex, uxValueToPost = 0;
for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ ) for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ )
{ {
/* Create a queue to transmit to and receive from each 'hook' /* Create a queue to transmit to and receive from each 'hook'
co-routine. */ * co-routine. */
xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) ); xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) );
xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) ); xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( UBaseType_t ) );
/* To start things off the tick hook function expects the queue it /* To start things off the tick hook function expects the queue it
uses to receive data to contain a value. */ * uses to receive data to contain a value. */
xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME ); xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME );
/* Create the 'hook' co-routine itself. */ /* Create the 'hook' co-routine itself. */
@ -133,6 +134,7 @@ BaseType_t xIndex, xCoRoutineWoken;
/* Is it time to talk to the 'hook' co-routines again? */ /* Is it time to talk to the 'hook' co-routines again? */
uxCallCounter++; uxCallCounter++;
if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST ) if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST )
{ {
uxCallCounter = 0; uxCallCounter = 0;
@ -140,16 +142,17 @@ BaseType_t xIndex, xCoRoutineWoken;
for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ ) for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
{ {
xCoRoutineWoken = pdFALSE; xCoRoutineWoken = pdFALSE;
if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS ) if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS )
{ {
/* There is no reason why we would not expect the queue to /* There is no reason why we would not expect the queue to
contain a value. */ * contain a value. */
xCoRoutineErrorDetected = pdTRUE; xCoRoutineErrorDetected = pdTRUE;
} }
else else
{ {
/* Each queue used to receive data from the 'hook' co-routines /* Each queue used to receive data from the 'hook' co-routines
should contain the number we last posted to the same co-routine. */ * should contain the number we last posted to the same co-routine. */
if( uxReceivedNumber != uxNumberToPost ) if( uxReceivedNumber != uxNumberToPost )
{ {
xCoRoutineErrorDetected = pdTRUE; xCoRoutineErrorDetected = pdTRUE;
@ -171,7 +174,7 @@ BaseType_t xIndex, xCoRoutineWoken;
if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE ) if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE )
{ {
/* Posting to the queue should have woken the co-routine that /* Posting to the queue should have woken the co-routine that
was blocked on the queue. */ * was blocked on the queue. */
xCoRoutineErrorDetected = pdTRUE; xCoRoutineErrorDetected = pdTRUE;
} }
} }
@ -179,7 +182,8 @@ BaseType_t xIndex, xCoRoutineWoken;
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
static void prvHookCoRoutine( CoRoutineHandle_t xHandle, UBaseType_t uxIndex ) static void prvHookCoRoutine( CoRoutineHandle_t xHandle,
UBaseType_t uxIndex )
{ {
static UBaseType_t uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ]; static UBaseType_t uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ];
BaseType_t xResult; BaseType_t xResult;
@ -194,7 +198,7 @@ BaseType_t xResult;
crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult ); crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult );
/* There is no reason why we should not have received something on /* There is no reason why we should not have received something on
the queue. */ * the queue. */
if( xResult != pdPASS ) if( xResult != pdPASS )
{ {
xCoRoutineErrorDetected = pdTRUE; xCoRoutineErrorDetected = pdTRUE;
@ -203,10 +207,11 @@ BaseType_t xResult;
/* Send the same number back to the idle hook so it can verify it. */ /* Send the same number back to the idle hook so it can verify it. */
xResult = pdFAIL; xResult = pdFAIL;
crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult ); crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult );
if( xResult != pdPASS ) if( xResult != pdPASS )
{ {
/* There is no reason why we should not have been able to post to /* There is no reason why we should not have been able to post to
the queue. */ * the queue. */
xCoRoutineErrorDetected = pdTRUE; xCoRoutineErrorDetected = pdTRUE;
} }
} }
@ -227,6 +232,3 @@ BaseType_t xAreHookCoRoutinesStillRunning( void )
return pdTRUE; return pdTRUE;
} }
} }

View file

@ -57,30 +57,30 @@
#define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 ) #define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 )
/* The task originally created which is responsible for periodically dynamically /* The task originally created which is responsible for periodically dynamically
creating another four tasks. */ * creating another four tasks. */
static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters ); static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters );
/* The task function of the dynamically created tasks. */ /* The task function of the dynamically created tasks. */
static portTASK_FUNCTION_PROTO( vSuicidalTask, pvParameters ); static portTASK_FUNCTION_PROTO( vSuicidalTask, pvParameters );
/* A variable which is incremented every time the dynamic tasks are created. This /* A variable which is incremented every time the dynamic tasks are created. This
is used to check that the task is still running. */ * is used to check that the task is still running. */
static volatile uint16_t usCreationCount = 0; static volatile uint16_t usCreationCount = 0;
/* Used to store the number of tasks that were originally running so the creator /* Used to store the number of tasks that were originally running so the creator
task can tell if any of the suicidal tasks have failed to die. * task can tell if any of the suicidal tasks have failed to die.
*/ */
static volatile UBaseType_t uxTasksRunningAtStart = 0; static volatile UBaseType_t uxTasksRunningAtStart = 0;
/* When a task deletes itself, it stack and TCB are cleaned up by the Idle task. /* When a task deletes itself, it stack and TCB are cleaned up by the Idle task.
Under heavy load the idle task might not get much processing time, so it would * Under heavy load the idle task might not get much processing time, so it would
be legitimate for several tasks to remain undeleted for a short period. There * be legitimate for several tasks to remain undeleted for a short period. There
may also be a few other unexpected tasks if, for example, the tasks that test * may also be a few other unexpected tasks if, for example, the tasks that test
static allocation are also being used. */ * static allocation are also being used. */
static const UBaseType_t uxMaxNumberOfExtraTasksRunning = 3; static const UBaseType_t uxMaxNumberOfExtraTasksRunning = 3;
/* Used to store a handle to the task that should be killed by a suicidal task, /* Used to store a handle to the task that should be killed by a suicidal task,
before it kills itself. */ * before it kills itself. */
TaskHandle_t xCreatedTask; TaskHandle_t xCreatedTask;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -103,8 +103,8 @@ const TickType_t xDelay = pdMS_TO_TICKS( ( TickType_t ) 200 );
if( pvParameters != NULL ) if( pvParameters != NULL )
{ {
/* This task is periodically created four times. Two created tasks are /* This task is periodically created four times. Two created tasks are
passed a handle to the other task so it can kill it before killing itself. * passed a handle to the other task so it can kill it before killing itself.
The other task is passed in null. */ * The other task is passed in null. */
xTaskToKill = *( TaskHandle_t * ) pvParameters; xTaskToKill = *( TaskHandle_t * ) pvParameters;
} }
else else
@ -144,7 +144,7 @@ UBaseType_t uxPriority;
( void ) pvParameters; ( void ) pvParameters;
/* Delay at the start to ensure tasks created by other demos have been /* Delay at the start to ensure tasks created by other demos have been
created before storing the current number of tasks. */ * created before storing the current number of tasks. */
vTaskDelay( xDelay ); vTaskDelay( xDelay );
uxTasksRunningAtStart = ( UBaseType_t ) uxTaskGetNumberOfTasks(); uxTasksRunningAtStart = ( UBaseType_t ) uxTaskGetNumberOfTasks();
@ -166,7 +166,7 @@ UBaseType_t uxPriority;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* This is called to check that the creator task is still running and that there /* This is called to check that the creator task is still running and that there
are not any more than four extra tasks. */ * are not any more than four extra tasks. */
BaseType_t xIsCreateTaskStillRunning( void ) BaseType_t xIsCreateTaskStillRunning( void )
{ {
static uint16_t usLastCreationCount = 0xfff; static uint16_t usLastCreationCount = 0xfff;
@ -199,5 +199,3 @@ static UBaseType_t uxTasksRunningNow;
return xReturn; return xReturn;
} }

View file

@ -118,17 +118,17 @@ static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* Handles to the two counter tasks. These could be passed in as parameters /* Handles to the two counter tasks. These could be passed in as parameters
to the controller task to prevent them having to be file scope. */ * to the controller task to prevent them having to be file scope. */
static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle; static TaskHandle_t xContinuousIncrementHandle, xLimitedIncrementHandle;
/* The shared counter variable. This is passed in as a parameter to the two /* The shared counter variable. This is passed in as a parameter to the two
counter variables for demonstration purposes. */ * counter variables for demonstration purposes. */
static uint32_t ulCounter; static uint32_t ulCounter;
/* Variables used to check that the tasks are still operating without error. /* Variables used to check that the tasks are still operating without error.
Each complete iteration of the controller task increments this variable * Each complete iteration of the controller task increments this variable
provided no errors have been found. The variable maintaining the same value * provided no errors have been found. The variable maintaining the same value
is therefore indication of an error. */ * is therefore indication of an error. */
static volatile uint16_t usCheckVariable = ( uint16_t ) 0; static volatile uint16_t usCheckVariable = ( uint16_t ) 0;
static volatile BaseType_t xSuspendedQueueSendError = pdFALSE; static volatile BaseType_t xSuspendedQueueSendError = pdFALSE;
static volatile BaseType_t xSuspendedQueueReceiveError = pdFALSE; static volatile BaseType_t xSuspendedQueueReceiveError = pdFALSE;
@ -137,11 +137,12 @@ static volatile BaseType_t xSuspendedQueueReceiveError = pdFALSE;
QueueHandle_t xSuspendedTestQueue; QueueHandle_t xSuspendedTestQueue;
/* The value the queue receive task expects to receive next. This is file /* The value the queue receive task expects to receive next. This is file
scope so xAreDynamicPriorityTasksStillRunning() can ensure it is still * scope so xAreDynamicPriorityTasksStillRunning() can ensure it is still
incrementing. */ * incrementing. */
static uint32_t ulExpectedValue = ( uint32_t ) 0; static uint32_t ulExpectedValue = ( uint32_t ) 0;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
/* /*
* Start the three tasks as described at the top of the file. * Start the three tasks as described at the top of the file.
* Note that the limited count task is given a higher priority. * Note that the limited count task is given a higher priority.
@ -153,11 +154,11 @@ void vStartDynamicPriorityTasks( void )
if( xSuspendedTestQueue != NULL ) if( xSuspendedTestQueue != NULL )
{ {
/* vQueueAddToRegistry() adds the queue to the queue registry, if one is /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
in use. The queue registry is provided as a means for kernel aware * in use. The queue registry is provided as a means for kernel aware
debuggers to locate queues and has no purpose if a kernel aware debugger * debuggers to locate queues and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( xSuspendedTestQueue, "Suspended_Test_Queue" ); vQueueAddToRegistry( xSuspendedTestQueue, "Suspended_Test_Queue" );
xTaskCreate( vContinuousIncrementTask, "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle ); xTaskCreate( vContinuousIncrementTask, "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
@ -178,11 +179,11 @@ static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )
volatile uint32_t * pulCounter; volatile uint32_t * pulCounter;
/* Take a pointer to the shared variable from the parameters passed into /* Take a pointer to the shared variable from the parameters passed into
the task. */ * the task. */
pulCounter = ( volatile uint32_t * ) pvParameters; pulCounter = ( volatile uint32_t * ) pvParameters;
/* This will run before the control task, so the first thing it does is /* This will run before the control task, so the first thing it does is
suspend - the control task will resume it when ready. */ * suspend - the control task will resume it when ready. */
vTaskSuspend( NULL ); vTaskSuspend( NULL );
for( ; ; ) for( ; ; )
@ -208,17 +209,17 @@ volatile uint32_t *pulCounter;
UBaseType_t uxOurPriority; UBaseType_t uxOurPriority;
/* Take a pointer to the shared variable from the parameters passed into /* Take a pointer to the shared variable from the parameters passed into
the task. */ * the task. */
pulCounter = ( volatile uint32_t * ) pvParameters; pulCounter = ( volatile uint32_t * ) pvParameters;
/* Query our priority so we can raise it when exclusive access to the /* Query our priority so we can raise it when exclusive access to the
shared variable is required. */ * shared variable is required. */
uxOurPriority = uxTaskPriorityGet( NULL ); uxOurPriority = uxTaskPriorityGet( NULL );
for( ; ; ) for( ; ; )
{ {
/* Raise the priority above the controller task to ensure a context /* Raise the priority above the controller task to ensure a context
switch does not occur while the variable is being accessed. */ * switch does not occur while the variable is being accessed. */
vTaskPrioritySet( NULL, uxOurPriority + 1 ); vTaskPrioritySet( NULL, uxOurPriority + 1 );
{ {
configASSERT( ( uxTaskPriorityGet( NULL ) == ( uxOurPriority + 1 ) ) ); configASSERT( ( uxTaskPriorityGet( NULL ) == ( uxOurPriority + 1 ) ) );
@ -258,9 +259,9 @@ short sError = pdFALSE;
for( sLoops = 0; sLoops < priLOOPS; sLoops++ ) for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
{ {
/* Suspend the continuous count task so we can take a mirror of the /* Suspend the continuous count task so we can take a mirror of the
shared variable without risk of corruption. This is not really * shared variable without risk of corruption. This is not really
needed as the other task raises its priority above this task's * needed as the other task raises its priority above this task's
priority. */ * priority. */
vTaskSuspend( xContinuousIncrementHandle ); vTaskSuspend( xContinuousIncrementHandle );
{ {
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
@ -287,14 +288,14 @@ short sError = pdFALSE;
vTaskDelay( priSLEEP_TIME ); vTaskDelay( priSLEEP_TIME );
/* Check the shared variable again. This time to ensure mutual /* Check the shared variable again. This time to ensure mutual
exclusion the whole scheduler will be locked. This is just for * exclusion the whole scheduler will be locked. This is just for
demo purposes! */ * demo purposes! */
vTaskSuspendAll(); vTaskSuspendAll();
{ {
if( ulLastCounter == ulCounter ) if( ulLastCounter == ulCounter )
{ {
/* The shared variable has not changed. There is a problem /* The shared variable has not changed. There is a problem
with the continuous count task so flag an error. */ * with the continuous count task so flag an error. */
sError = pdTRUE; sError = pdTRUE;
} }
} }
@ -304,7 +305,7 @@ short sError = pdFALSE;
/* Second section: */ /* Second section: */
/* Suspend the continuous counter task so it stops accessing the shared /* Suspend the continuous counter task so it stops accessing the shared
variable. */ * variable. */
vTaskSuspend( xContinuousIncrementHandle ); vTaskSuspend( xContinuousIncrementHandle );
/* Reset the variable. */ /* Reset the variable. */
@ -317,8 +318,8 @@ short sError = pdFALSE;
#endif /* INCLUDE_eTaskGetState */ #endif /* INCLUDE_eTaskGetState */
/* Resume the limited count task which has a higher priority than us. /* Resume the limited count task which has a higher priority than us.
We should therefore not return from this call until the limited count * We should therefore not return from this call until the limited count
task has suspended itself with a known value in the counter variable. */ * task has suspended itself with a known value in the counter variable. */
vTaskResume( xLimitedIncrementHandle ); vTaskResume( xLimitedIncrementHandle );
#if ( configUSE_PREEMPTION == 0 ) #if ( configUSE_PREEMPTION == 0 )
@ -326,7 +327,7 @@ short sError = pdFALSE;
#endif #endif
/* This task should not run again until xLimitedIncrementHandle has /* This task should not run again until xLimitedIncrementHandle has
suspended itself. */ * suspended itself. */
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
{ {
configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended ); configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
@ -396,16 +397,17 @@ BaseType_t xGotValue;
do do
{ {
/* Suspending the scheduler here is fairly pointless and /* Suspending the scheduler here is fairly pointless and
undesirable for a normal application. It is done here purely * undesirable for a normal application. It is done here purely
to test the scheduler. The inner xTaskResumeAll() should * to test the scheduler. The inner xTaskResumeAll() should
never return pdTRUE as the scheduler is still locked by the * never return pdTRUE as the scheduler is still locked by the
outer call. */ * outer call. */
vTaskSuspendAll(); vTaskSuspendAll();
{ {
vTaskSuspendAll(); vTaskSuspendAll();
{ {
xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK ); xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
} }
if( xTaskResumeAll() != pdFALSE ) if( xTaskResumeAll() != pdFALSE )
{ {
xSuspendedQueueReceiveError = pdTRUE; xSuspendedQueueReceiveError = pdTRUE;
@ -418,7 +420,6 @@ BaseType_t xGotValue;
taskYIELD(); taskYIELD();
} }
#endif #endif
} while( xGotValue == pdFALSE ); } while( xGotValue == pdFALSE );
if( ulReceivedValue != ulExpectedValue ) if( ulReceivedValue != ulExpectedValue )
@ -429,8 +430,8 @@ BaseType_t xGotValue;
if( xSuspendedQueueReceiveError != pdTRUE ) if( xSuspendedQueueReceiveError != pdTRUE )
{ {
/* Only increment the variable if an error has not occurred. This /* Only increment the variable if an error has not occurred. This
allows xAreDynamicPriorityTasksStillRunning() to check for stalled * allows xAreDynamicPriorityTasksStillRunning() to check for stalled
tasks as well as explicit errors. */ * tasks as well as explicit errors. */
++ulExpectedValue; ++ulExpectedValue;
} }
} }
@ -441,13 +442,13 @@ BaseType_t xGotValue;
BaseType_t xAreDynamicPriorityTasksStillRunning( void ) BaseType_t xAreDynamicPriorityTasksStillRunning( void )
{ {
/* Keep a history of the check variables so we know if it has been incremented /* Keep a history of the check variables so we know if it has been incremented
since the last call. */ * since the last call. */
static uint16_t usLastTaskCheck = ( uint16_t ) 0; static uint16_t usLastTaskCheck = ( uint16_t ) 0;
static uint32_t ulLastExpectedValue = ( uint32_t ) 0U; static uint32_t ulLastExpectedValue = ( uint32_t ) 0U;
BaseType_t xReturn = pdTRUE; BaseType_t xReturn = pdTRUE;
/* Check the tasks are still running by ensuring the check variable /* Check the tasks are still running by ensuring the check variable
is still incrementing. */ * is still incrementing. */
if( usCheckVariable == usLastTaskCheck ) if( usCheckVariable == usLastTaskCheck )
{ {
@ -458,7 +459,7 @@ BaseType_t xReturn = pdTRUE;
if( ulExpectedValue == ulLastExpectedValue ) if( ulExpectedValue == ulLastExpectedValue )
{ {
/* The value being received by the queue receive task has not /* The value being received by the queue receive task has not
incremented so an error exists. */ * incremented so an error exists. */
xReturn = pdFALSE; xReturn = pdFALSE;
} }

View file

@ -54,7 +54,7 @@
#define ledFLASH_RATE_BASE ( ( TickType_t ) 333 ) #define ledFLASH_RATE_BASE ( ( TickType_t ) 333 )
/* Variable used by the created tasks to calculate the LED number to use, and /* Variable used by the created tasks to calculate the LED number to use, and
the rate at which they should flash the LED. */ * the rate at which they should flash the LED. */
static volatile UBaseType_t uxFlashTaskNumber = 0; static volatile UBaseType_t uxFlashTaskNumber = 0;
/* The task that is created three times. */ /* The task that is created three times. */
@ -98,11 +98,11 @@ UBaseType_t uxLED;
xFlashRate /= portTICK_PERIOD_MS; xFlashRate /= portTICK_PERIOD_MS;
/* We will turn the LED on and off again in the delay period, so each /* We will turn the LED on and off again in the delay period, so each
delay is only half the total period. */ * delay is only half the total period. */
xFlashRate /= ( TickType_t ) 2; xFlashRate /= ( TickType_t ) 2;
/* We need to initialise xLastFlashTime prior to the first call to /* We need to initialise xLastFlashTime prior to the first call to
vTaskDelayUntil(). */ * vTaskDelayUntil(). */
xLastFlashTime = xTaskGetTickCount(); xLastFlashTime = xTaskGetTickCount();
for( ; ; ) for( ; ; )
@ -116,4 +116,3 @@ UBaseType_t uxLED;
vParTestToggleLED( uxLED ); vParTestToggleLED( uxLED );
} }
} /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */ } /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */

View file

@ -72,10 +72,10 @@ TimerHandle_t xTimer;
); );
/* If the timer was created successfully, attempt to start it. If the /* If the timer was created successfully, attempt to start it. If the
scheduler has not yet been started then the timer command queue must * scheduler has not yet been started then the timer command queue must
be long enough to hold each command sent to it until such time that the * be long enough to hold each command sent to it until such time that the
scheduler is started. The timer command queue length is set by * scheduler is started. The timer command queue length is set by
configTIMER_QUEUE_LENGTH in FreeRTOSConfig.h. */ * configTIMER_QUEUE_LENGTH in FreeRTOSConfig.h. */
if( xTimer != NULL ) if( xTimer != NULL )
{ {
xTimerStart( xTimer, ledDONT_BLOCK ); xTimerStart( xTimer, ledDONT_BLOCK );
@ -89,10 +89,8 @@ static void prvLEDTimerCallback( TimerHandle_t xTimer )
BaseType_t xTimerID; BaseType_t xTimerID;
/* The timer ID is used to identify the timer that has actually expired as /* The timer ID is used to identify the timer that has actually expired as
each timer uses the same callback. The ID is then also used as the number * each timer uses the same callback. The ID is then also used as the number
of the LED that is to be toggled. */ * of the LED that is to be toggled. */
xTimerID = ( BaseType_t ) pvTimerGetTimerID( xTimer ); xTimerID = ( BaseType_t ) pvTimerGetTimerID( xTimer );
vParTestToggleLED( xTimerID ); vParTestToggleLED( xTimerID );
} }

View file

@ -56,14 +56,14 @@
#define mathNUMBER_OF_TASKS ( 4 ) #define mathNUMBER_OF_TASKS ( 4 )
/* Four tasks, each of which performs a different floating point calculation. /* Four tasks, each of which performs a different floating point calculation.
Each of the four is created twice. */ * Each of the four is created twice. */
static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
/* These variables are used to check that all the tasks are still running. If a /* These variables are used to check that all the tasks are still running. If a
task gets a calculation wrong it will stop setting its check variable. */ * task gets a calculation wrong it will stop setting its check variable. */
static uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 }; static uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -85,8 +85,8 @@ volatile portDOUBLE dAnswer;
short sError = pdFALSE; short sError = pdFALSE;
/* Some ports require that tasks that use a hardware floating point unit /* Some ports require that tasks that use a hardware floating point unit
tell the kernel that they require a floating point context before any * tell the kernel that they require a floating point context before any
floating point instructions are executed. */ * floating point instructions are executed. */
portTASK_USES_FLOATING_POINT(); portTASK_USES_FLOATING_POINT();
d1 = 123.4567; d1 = 123.4567;
@ -96,7 +96,7 @@ short sError = pdFALSE;
dAnswer = ( d1 + d2 ) * d3; dAnswer = ( d1 + d2 ) * d3;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters; pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
@ -113,7 +113,7 @@ short sError = pdFALSE;
#endif #endif
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 ) if( fabs( d4 - dAnswer ) > 0.001 )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -122,15 +122,14 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct then set set the check /* If the calculation has always been correct then set set the check
variable. The check variable will get set to pdFALSE each time * variable. The check variable will get set to pdFALSE each time
xAreMathsTaskStillRunning() is executed. */ * xAreMathsTaskStillRunning() is executed. */
( *pusTaskCheckVariable ) = pdTRUE; ( *pusTaskCheckVariable ) = pdTRUE;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -143,8 +142,8 @@ volatile portDOUBLE dAnswer;
short sError = pdFALSE; short sError = pdFALSE;
/* Some ports require that tasks that use a hardware floating point unit /* Some ports require that tasks that use a hardware floating point unit
tell the kernel that they require a floating point context before any * tell the kernel that they require a floating point context before any
floating point instructions are executed. */ * floating point instructions are executed. */
portTASK_USES_FLOATING_POINT(); portTASK_USES_FLOATING_POINT();
d1 = -389.38; d1 = -389.38;
@ -155,7 +154,7 @@ short sError = pdFALSE;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters; pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
@ -172,7 +171,7 @@ short sError = pdFALSE;
#endif #endif
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 ) if( fabs( d4 - dAnswer ) > 0.001 )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -181,8 +180,8 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct then set set the check /* If the calculation has always been correct then set set the check
variable. The check variable will get set to pdFALSE each time * variable. The check variable will get set to pdFALSE each time
xAreMathsTaskStillRunning() is executed. */ * xAreMathsTaskStillRunning() is executed. */
( *pusTaskCheckVariable ) = pdTRUE; ( *pusTaskCheckVariable ) = pdTRUE;
} }
@ -202,19 +201,19 @@ size_t xPosition;
short sError = pdFALSE; short sError = pdFALSE;
/* Some ports require that tasks that use a hardware floating point unit /* Some ports require that tasks that use a hardware floating point unit
tell the kernel that they require a floating point context before any * tell the kernel that they require a floating point context before any
floating point instructions are executed. */ * floating point instructions are executed. */
portTASK_USES_FLOATING_POINT(); portTASK_USES_FLOATING_POINT();
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters; pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) ); pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ; ; ) for( ; ; )
{ {
dTotal1 = 0.0; dTotal1 = 0.0;
@ -236,6 +235,7 @@ short sError = pdFALSE;
} }
dDifference = dTotal1 - dTotal2; dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 ) if( fabs( dDifference ) > 0.001 )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -248,8 +248,8 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct then set set the check /* If the calculation has always been correct then set set the check
variable. The check variable will get set to pdFALSE each time * variable. The check variable will get set to pdFALSE each time
xAreMathsTaskStillRunning() is executed. */ * xAreMathsTaskStillRunning() is executed. */
( *pusTaskCheckVariable ) = pdTRUE; ( *pusTaskCheckVariable ) = pdTRUE;
} }
} }
@ -265,19 +265,19 @@ size_t xPosition;
short sError = pdFALSE; short sError = pdFALSE;
/* Some ports require that tasks that use a hardware floating point unit /* Some ports require that tasks that use a hardware floating point unit
tell the kernel that they require a floating point context before any * tell the kernel that they require a floating point context before any
floating point instructions are executed. */ * floating point instructions are executed. */
portTASK_USES_FLOATING_POINT(); portTASK_USES_FLOATING_POINT();
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters; pusTaskCheckVariable = ( volatile uint16_t * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) ); pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ; ; ) for( ; ; )
{ {
dTotal1 = 0.0; dTotal1 = 0.0;
@ -299,6 +299,7 @@ short sError = pdFALSE;
} }
dDifference = dTotal1 - dTotal2; dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 ) if( fabs( dDifference ) > 0.001 )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -311,8 +312,8 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct then set set the check /* If the calculation has always been correct then set set the check
variable. The check variable will get set to pdFALSE each time * variable. The check variable will get set to pdFALSE each time
xAreMathsTaskStillRunning() is executed. */ * xAreMathsTaskStillRunning() is executed. */
( *pusTaskCheckVariable ) = pdTRUE; ( *pusTaskCheckVariable ) = pdTRUE;
} }
} }
@ -325,25 +326,22 @@ BaseType_t xAreMathsTaskStillRunning( void )
BaseType_t xReturn = pdPASS, xTask; BaseType_t xReturn = pdPASS, xTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
have been set to pdPASS. */ * have been set to pdPASS. */
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ ) for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
{ {
if( usTaskCheck[ xTask ] != pdTRUE ) if( usTaskCheck[ xTask ] != pdTRUE )
{ {
/* The check has not been set so the associated task has either /* The check has not been set so the associated task has either
stalled or detected an error. */ * stalled or detected an error. */
xReturn = pdFAIL; xReturn = pdFAIL;
} }
else else
{ {
/* Reset the variable so it can be checked again the next time this /* Reset the variable so it can be checked again the next time this
function is executed. */ * function is executed. */
usTaskCheck[ xTask ] = pdFALSE; usTaskCheck[ xTask ] = pdFALSE;
} }
} }
return xReturn; return xReturn;
} }

View file

@ -54,14 +54,14 @@
#define intgNUMBER_OF_TASKS ( 1 ) #define intgNUMBER_OF_TASKS ( 1 )
/* The task function. Repeatedly performs a 32 bit calculation, checking the /* The task function. Repeatedly performs a 32 bit calculation, checking the
result against the expected result. If the result is incorrect then the * result against the expected result. If the result is incorrect then the
context switch must have caused some corruption. */ * context switch must have caused some corruption. */
static portTASK_FUNCTION_PROTO( vCompeteingIntMathTask, pvParameters ); static portTASK_FUNCTION_PROTO( vCompeteingIntMathTask, pvParameters );
/* Variables that are set to true within the calculation task to indicate /* Variables that are set to true within the calculation task to indicate
that the task is still executing. The check task sets the variable back to * that the task is still executing. The check task sets the variable back to
false, flagging an error if the variable is still false the next time it * false, flagging an error if the variable is still false the next time it
is called. */ * is called. */
static BaseType_t xTaskCheck[ intgNUMBER_OF_TASKS ] = { ( BaseType_t ) pdFALSE }; static BaseType_t xTaskCheck[ intgNUMBER_OF_TASKS ] = { ( BaseType_t ) pdFALSE };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -80,21 +80,21 @@ short sTask;
static portTASK_FUNCTION( vCompeteingIntMathTask, pvParameters ) static portTASK_FUNCTION( vCompeteingIntMathTask, pvParameters )
{ {
/* These variables are all effectively set to constants so they are volatile to /* These variables are all effectively set to constants so they are volatile to
ensure the compiler does not just get rid of them. */ * ensure the compiler does not just get rid of them. */
volatile long lValue; volatile long lValue;
short sError = pdFALSE; short sError = pdFALSE;
volatile BaseType_t * pxTaskHasExecuted; volatile BaseType_t * pxTaskHasExecuted;
/* Set a pointer to the variable we are going to set to true each /* Set a pointer to the variable we are going to set to true each
iteration. This is also a good test of the parameter passing mechanism * iteration. This is also a good test of the parameter passing mechanism
within each port. */ * within each port. */
pxTaskHasExecuted = ( volatile BaseType_t * ) pvParameters; pxTaskHasExecuted = ( volatile BaseType_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
for( ; ; ) for( ; ; )
{ {
/* Perform the calculation. This will store partial value in /* Perform the calculation. This will store partial value in
registers, resulting in a good test of the context switch mechanism. */ * registers, resulting in a good test of the context switch mechanism. */
lValue = intgCONST1; lValue = intgCONST1;
lValue += intgCONST2; lValue += intgCONST2;
@ -110,8 +110,8 @@ volatile BaseType_t *pxTaskHasExecuted;
lValue /= intgCONST4; lValue /= intgCONST4;
/* If the calculation is found to be incorrect we stop setting the /* If the calculation is found to be incorrect we stop setting the
TaskHasExecuted variable so the check task can see an error has * TaskHasExecuted variable so the check task can see an error has
occurred. */ * occurred. */
if( lValue != intgEXPECTED_ANSWER ) /*lint !e774 volatile used to prevent this being optimised out. */ if( lValue != intgEXPECTED_ANSWER ) /*lint !e774 volatile used to prevent this being optimised out. */
{ {
sError = pdTRUE; sError = pdTRUE;
@ -120,8 +120,8 @@ volatile BaseType_t *pxTaskHasExecuted;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* We have not encountered any errors, so set the flag that show /* We have not encountered any errors, so set the flag that show
we are still executing. This will be periodically cleared by * we are still executing. This will be periodically cleared by
the check task. */ * the check task. */
portENTER_CRITICAL(); portENTER_CRITICAL();
*pxTaskHasExecuted = pdTRUE; *pxTaskHasExecuted = pdTRUE;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
@ -144,7 +144,7 @@ BaseType_t xReturn = pdTRUE;
short sTask; short sTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
are still being set to true. */ * are still being set to true. */
for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ ) for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
{ {
if( xTaskCheck[ sTask ] == pdFALSE ) if( xTaskCheck[ sTask ] == pdFALSE )
@ -154,10 +154,9 @@ short sTask;
} }
/* Reset the check variable so we can tell if it has been set by /* Reset the check variable so we can tell if it has been set by
the next time around. */ * the next time around. */
xTaskCheck[ sTask ] = pdFALSE; xTaskCheck[ sTask ] = pdFALSE;
} }
return xReturn; return xReturn;
} }

View file

@ -26,39 +26,39 @@
*/ */
/* /*
The tasks defined on this page demonstrate the use of recursive mutexes. * The tasks defined on this page demonstrate the use of recursive mutexes.
*
For recursive mutex functionality the created mutex should be created using * For recursive mutex functionality the created mutex should be created using
xSemaphoreCreateRecursiveMutex(), then be manipulated * xSemaphoreCreateRecursiveMutex(), then be manipulated
using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API * using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API
functions. * functions.
*
This demo creates three tasks all of which access the same recursive mutex: * This demo creates three tasks all of which access the same recursive mutex:
*
prvRecursiveMutexControllingTask() has the highest priority so executes * prvRecursiveMutexControllingTask() has the highest priority so executes
first and grabs the mutex. It then performs some recursive accesses - * first and grabs the mutex. It then performs some recursive accesses -
between each of which it sleeps for a short period to let the lower * between each of which it sleeps for a short period to let the lower
priority tasks execute. When it has completed its demo functionality * priority tasks execute. When it has completed its demo functionality
it gives the mutex back before suspending itself. * it gives the mutex back before suspending itself.
*
prvRecursiveMutexBlockingTask() attempts to access the mutex by performing * prvRecursiveMutexBlockingTask() attempts to access the mutex by performing
a blocking 'take'. The blocking task has a lower priority than the * a blocking 'take'. The blocking task has a lower priority than the
controlling task so by the time it executes the mutex has already been * controlling task so by the time it executes the mutex has already been
taken by the controlling task, causing the blocking task to block. It * taken by the controlling task, causing the blocking task to block. It
does not unblock until the controlling task has given the mutex back, * does not unblock until the controlling task has given the mutex back,
and it does not actually run until the controlling task has suspended * and it does not actually run until the controlling task has suspended
itself (due to the relative priorities). When it eventually does obtain * itself (due to the relative priorities). When it eventually does obtain
the mutex all it does is give the mutex back prior to also suspending * the mutex all it does is give the mutex back prior to also suspending
itself. At this point both the controlling task and the blocking task are * itself. At this point both the controlling task and the blocking task are
suspended. * suspended.
*
prvRecursiveMutexPollingTask() runs at the idle priority. It spins round * prvRecursiveMutexPollingTask() runs at the idle priority. It spins round
a tight loop attempting to obtain the mutex with a non-blocking call. As * a tight loop attempting to obtain the mutex with a non-blocking call. As
the lowest priority task it will not successfully obtain the mutex until * the lowest priority task it will not successfully obtain the mutex until
both the controlling and blocking tasks are suspended. Once it eventually * both the controlling and blocking tasks are suspended. Once it eventually
does obtain the mutex it first unsuspends both the controlling task and * does obtain the mutex it first unsuspends both the controlling task and
blocking task prior to giving the mutex back - resulting in the polling * blocking task prior to giving the mutex back - resulting in the polling
task temporarily inheriting the controlling tasks priority. * task temporarily inheriting the controlling tasks priority.
*/ */
/* Scheduler include files. */ /* Scheduler include files. */
@ -70,7 +70,7 @@
#include "recmutex.h" #include "recmutex.h"
/* Priorities assigned to the three tasks. recmuCONTROLLING_TASK_PRIORITY can /* Priorities assigned to the three tasks. recmuCONTROLLING_TASK_PRIORITY can
be overridden by a definition in FreeRTOSConfig.h. */ * be overridden by a definition in FreeRTOSConfig.h. */
#ifndef recmuCONTROLLING_TASK_PRIORITY #ifndef recmuCONTROLLING_TASK_PRIORITY
#define recmuCONTROLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 ) #define recmuCONTROLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
#endif #endif
@ -102,7 +102,7 @@ static volatile BaseType_t xErrorOccurred = pdFALSE, xControllingIsSuspended = p
static volatile UBaseType_t uxControllingCycles = 0, uxBlockingCycles = 0, uxPollingCycles = 0; static volatile UBaseType_t uxControllingCycles = 0, uxBlockingCycles = 0, uxPollingCycles = 0;
/* Handles of the two higher priority tasks, required so they can be resumed /* Handles of the two higher priority tasks, required so they can be resumed
(unsuspended). */ * (unsuspended). */
static TaskHandle_t xControllingTaskHandle, xBlockingTaskHandle; static TaskHandle_t xControllingTaskHandle, xBlockingTaskHandle;
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -116,11 +116,11 @@ void vStartRecursiveMutexTasks( void )
if( xMutex != NULL ) if( xMutex != NULL )
{ {
/* vQueueAddToRegistry() adds the mutex to the registry, if one is /* vQueueAddToRegistry() adds the mutex to the registry, if one is
in use. The registry is provided as a means for kernel aware * in use. The registry is provided as a means for kernel aware
debuggers to locate mutex and has no purpose if a kernel aware debugger * debuggers to locate mutex and has no purpose if a kernel aware debugger
is not being used. The call to vQueueAddToRegistry() will be removed * is not being used. The call to vQueueAddToRegistry() will be removed
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is * by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
defined to be less than 1. */ * defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Recursive_Mutex" ); vQueueAddToRegistry( ( QueueHandle_t ) xMutex, "Recursive_Mutex" );
xTaskCreate( prvRecursiveMutexControllingTask, "Rec1", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle ); xTaskCreate( prvRecursiveMutexControllingTask, "Rec1", recmuRECURSIVE_MUTEX_TEST_TASK_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle );
@ -140,9 +140,9 @@ UBaseType_t ux;
for( ; ; ) for( ; ; )
{ {
/* Should not be able to 'give' the mutex, as we have not yet 'taken' /* Should not be able to 'give' the mutex, as we have not yet 'taken'
it. The first time through, the mutex will not have been used yet, * it. The first time through, the mutex will not have been used yet,
subsequent times through, at this point the mutex will be held by the * subsequent times through, at this point the mutex will be held by the
polling task. */ * polling task. */
if( xSemaphoreGiveRecursive( xMutex ) == pdPASS ) if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -151,24 +151,24 @@ UBaseType_t ux;
for( ux = 0; ux < recmuMAX_COUNT; ux++ ) for( ux = 0; ux < recmuMAX_COUNT; ux++ )
{ {
/* We should now be able to take the mutex as many times as /* We should now be able to take the mutex as many times as
we like. * we like.
*
The first time through the mutex will be immediately available, on * The first time through the mutex will be immediately available, on
subsequent times through the mutex will be held by the polling task * subsequent times through the mutex will be held by the polling task
at this point and this Take will cause the polling task to inherit * at this point and this Take will cause the polling task to inherit
the priority of this task. In this case the block time must be * the priority of this task. In this case the block time must be
long enough to ensure the polling task will execute again before the * long enough to ensure the polling task will execute again before the
block time expires. If the block time does expire then the error * block time expires. If the block time does expire then the error
flag will be set here. */ * flag will be set here. */
if( xSemaphoreTakeRecursive( xMutex, recmu15ms_DELAY ) != pdPASS ) if( xSemaphoreTakeRecursive( xMutex, recmu15ms_DELAY ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Ensure the other task attempting to access the mutex (and the /* Ensure the other task attempting to access the mutex (and the
other demo tasks) are able to execute to ensure they either block * other demo tasks) are able to execute to ensure they either block
(where a block time is specified) or return an error (where no * (where a block time is specified) or return an error (where no
block time is specified) as the mutex is held by this task. */ * block time is specified) as the mutex is held by this task. */
vTaskDelay( recmuSHORT_DELAY ); vTaskDelay( recmuSHORT_DELAY );
} }
@ -176,14 +176,14 @@ UBaseType_t ux;
for( ux = 0; ux < recmuMAX_COUNT; ux++ ) for( ux = 0; ux < recmuMAX_COUNT; ux++ )
{ {
/* Ensure the other task attempting to access the mutex (and the /* Ensure the other task attempting to access the mutex (and the
other demo tasks) are able to execute. */ * other demo tasks) are able to execute. */
vTaskDelay( recmuSHORT_DELAY ); vTaskDelay( recmuSHORT_DELAY );
/* We should now be able to give the mutex as many times as we /* We should now be able to give the mutex as many times as we
took it. When the mutex is available again the Blocking task * took it. When the mutex is available again the Blocking task
should be unblocked but not run because it has a lower priority * should be unblocked but not run because it has a lower priority
than this task. The polling task should also not run at this point * than this task. The polling task should also not run at this point
as it too has a lower priority than this task. */ * as it too has a lower priority than this task. */
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS ) if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -195,14 +195,14 @@ UBaseType_t ux;
} }
/* Having given it back the same number of times as it was taken, we /* Having given it back the same number of times as it was taken, we
should no longer be the mutex owner, so the next give should fail. */ * should no longer be the mutex owner, so the next give should fail. */
if( xSemaphoreGiveRecursive( xMutex ) == pdPASS ) if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
/* Keep count of the number of cycles this task has performed so a /* Keep count of the number of cycles this task has performed so a
stall can be detected. */ * stall can be detected. */
uxControllingCycles++; uxControllingCycles++;
/* Suspend ourselves so the blocking task can execute. */ /* Suspend ourselves so the blocking task can execute. */
@ -221,24 +221,24 @@ static void prvRecursiveMutexBlockingTask( void *pvParameters )
for( ; ; ) for( ; ; )
{ {
/* This task will run while the controlling task is blocked, and the /* This task will run while the controlling task is blocked, and the
controlling task will block only once it has the mutex - therefore * controlling task will block only once it has the mutex - therefore
this call should block until the controlling task has given up the * this call should block until the controlling task has given up the
mutex, and not actually execute past this call until the controlling * mutex, and not actually execute past this call until the controlling
task is suspended. portMAX_DELAY - 1 is used instead of portMAX_DELAY * task is suspended. portMAX_DELAY - 1 is used instead of portMAX_DELAY
to ensure the task's state is reported as Blocked and not Suspended in * to ensure the task's state is reported as Blocked and not Suspended in
a later call to configASSERT() (within the polling task). */ * a later call to configASSERT() (within the polling task). */
if( xSemaphoreTakeRecursive( xMutex, ( portMAX_DELAY - 1 ) ) == pdPASS ) if( xSemaphoreTakeRecursive( xMutex, ( portMAX_DELAY - 1 ) ) == pdPASS )
{ {
if( xControllingIsSuspended != pdTRUE ) if( xControllingIsSuspended != pdTRUE )
{ {
/* Did not expect to execute until the controlling task was /* Did not expect to execute until the controlling task was
suspended. */ * suspended. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
else else
{ {
/* Give the mutex back before suspending ourselves to allow /* Give the mutex back before suspending ourselves to allow
the polling task to obtain the mutex. */ * the polling task to obtain the mutex. */
if( xSemaphoreGiveRecursive( xMutex ) != pdPASS ) if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -252,7 +252,7 @@ static void prvRecursiveMutexBlockingTask( void *pvParameters )
else else
{ {
/* We should not leave the xSemaphoreTakeRecursive() function /* We should not leave the xSemaphoreTakeRecursive() function
until the mutex was obtained. */ * until the mutex was obtained. */
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
} }
@ -263,7 +263,7 @@ static void prvRecursiveMutexBlockingTask( void *pvParameters )
} }
/* Keep count of the number of cycles this task has performed so a /* Keep count of the number of cycles this task has performed so a
stall can be detected. */ * stall can be detected. */
uxBlockingCycles++; uxBlockingCycles++;
} }
} }
@ -277,8 +277,8 @@ static void prvRecursiveMutexPollingTask( void *pvParameters )
for( ; ; ) for( ; ; )
{ {
/* Keep attempting to obtain the mutex. It should only be obtained when /* Keep attempting to obtain the mutex. It should only be obtained when
the blocking task has suspended itself, which in turn should only * the blocking task has suspended itself, which in turn should only
happen when the controlling task is also suspended. */ * happen when the controlling task is also suspended. */
if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS ) if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )
{ {
#if ( INCLUDE_eTaskGetState == 1 ) #if ( INCLUDE_eTaskGetState == 1 )
@ -296,18 +296,18 @@ static void prvRecursiveMutexPollingTask( void *pvParameters )
else else
{ {
/* Keep count of the number of cycles this task has performed /* Keep count of the number of cycles this task has performed
so a stall can be detected. */ * so a stall can be detected. */
uxPollingCycles++; uxPollingCycles++;
/* We can resume the other tasks here even though they have a /* We can resume the other tasks here even though they have a
higher priority than the polling task. When they execute they * higher priority than the polling task. When they execute they
will attempt to obtain the mutex but fail because the polling * will attempt to obtain the mutex but fail because the polling
task is still the mutex holder. The polling task (this task) * task is still the mutex holder. The polling task (this task)
will then inherit the higher priority. The Blocking task will * will then inherit the higher priority. The Blocking task will
block indefinitely when it attempts to obtain the mutex, the * block indefinitely when it attempts to obtain the mutex, the
Controlling task will only block for a fixed period and an * Controlling task will only block for a fixed period and an
error will be latched if the polling task has not returned the * error will be latched if the polling task has not returned the
mutex by the time this fixed period has expired. */ * mutex by the time this fixed period has expired. */
vTaskResume( xBlockingTaskHandle ); vTaskResume( xBlockingTaskHandle );
#if ( configUSE_PREEMPTION == 0 ) #if ( configUSE_PREEMPTION == 0 )
taskYIELD(); taskYIELD();
@ -319,7 +319,7 @@ static void prvRecursiveMutexPollingTask( void *pvParameters )
#endif #endif
/* The other two tasks should now have executed and no longer /* The other two tasks should now have executed and no longer
be suspended. */ * be suspended. */
if( ( xBlockingIsSuspended == pdTRUE ) || ( xControllingIsSuspended == pdTRUE ) ) if( ( xBlockingIsSuspended == pdTRUE ) || ( xControllingIsSuspended == pdTRUE ) )
{ {
xErrorOccurred = pdTRUE; xErrorOccurred = pdTRUE;
@ -410,7 +410,3 @@ static UBaseType_t uxLastControllingCycles = 0, uxLastBlockingCycles = 0, uxLast
return xReturn; return xReturn;
} }

View file

@ -117,18 +117,19 @@ const TickType_t xBlockTime = ( TickType_t ) 100;
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL ); xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
/* vQueueAddToRegistry() adds the semaphore to the registry, if one /* vQueueAddToRegistry() adds the semaphore to the registry, if one
is in use. The registry is provided as a means for kernel aware * is in use. The registry is provided as a means for kernel aware
debuggers to locate semaphores and has no purpose if a kernel aware * debuggers to locate semaphores and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will * debugger is not being used. The call to vQueueAddToRegistry() will
be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
defined or is defined to be less than 1. */ * defined or is defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) pxFirstSemaphoreParameters->xSemaphore, "Counting_Sem_1" ); vQueueAddToRegistry( ( QueueHandle_t ) pxFirstSemaphoreParameters->xSemaphore, "Counting_Sem_1" );
} }
} }
/* Do exactly the same to create the second set of tasks, only this time /* Do exactly the same to create the second set of tasks, only this time
provide a block time for the semaphore calls. */ * provide a block time for the semaphore calls. */
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) ); pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxSecondSemaphoreParameters != NULL ) if( pxSecondSemaphoreParameters != NULL )
{ {
pxSecondSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary(); pxSecondSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary();
@ -145,11 +146,11 @@ const TickType_t xBlockTime = ( TickType_t ) 100;
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL ); xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
/* vQueueAddToRegistry() adds the semaphore to the registry, if one /* vQueueAddToRegistry() adds the semaphore to the registry, if one
is in use. The registry is provided as a means for kernel aware * is in use. The registry is provided as a means for kernel aware
debuggers to locate semaphores and has no purpose if a kernel aware * debuggers to locate semaphores and has no purpose if a kernel aware
debugger is not being used. The call to vQueueAddToRegistry() will * debugger is not being used. The call to vQueueAddToRegistry() will
be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not * be removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
defined or is defined to be less than 1. */ * defined or is defined to be less than 1. */
vQueueAddToRegistry( ( QueueHandle_t ) pxSecondSemaphoreParameters->xSemaphore, "Counting_Sem_2" ); vQueueAddToRegistry( ( QueueHandle_t ) pxSecondSemaphoreParameters->xSemaphore, "Counting_Sem_2" );
} }
} }
@ -164,19 +165,19 @@ uint32_t ulCounter;
short sError = pdFALSE, sCheckVariableToUse; short sError = pdFALSE, sCheckVariableToUse;
/* See which check variable to use. sNextCheckVariable is not semaphore /* See which check variable to use. sNextCheckVariable is not semaphore
protected! */ * protected! */
portENTER_CRITICAL(); portENTER_CRITICAL();
sCheckVariableToUse = sNextCheckVariable; sCheckVariableToUse = sNextCheckVariable;
sNextCheckVariable++; sNextCheckVariable++;
portEXIT_CRITICAL(); portEXIT_CRITICAL();
/* A structure is passed in as the parameter. This contains the shared /* A structure is passed in as the parameter. This contains the shared
variable being guarded. */ * variable being guarded. */
pxParameters = ( xSemaphoreParameters * ) pvParameters; pxParameters = ( xSemaphoreParameters * ) pvParameters;
pulSharedVariable = pxParameters->pulSharedVariable; pulSharedVariable = pxParameters->pulSharedVariable;
/* If we are blocking we use a much higher count to ensure loads of context /* If we are blocking we use a much higher count to ensure loads of context
switches occur during the count. */ * switches occur during the count. */
if( pxParameters->xBlockTime > ( TickType_t ) 0 ) if( pxParameters->xBlockTime > ( TickType_t ) 0 )
{ {
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE; ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
@ -192,19 +193,20 @@ short sError = pdFALSE, sCheckVariableToUse;
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS ) if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
{ {
/* We have the semaphore and so expect any other tasks using the /* We have the semaphore and so expect any other tasks using the
shared variable to have left it in the state we expect to find * shared variable to have left it in the state we expect to find
it. */ * it. */
if( *pulSharedVariable != ulExpectedValue ) if( *pulSharedVariable != ulExpectedValue )
{ {
sError = pdTRUE; sError = pdTRUE;
} }
/* Clear the variable, then count it back up to the expected value /* Clear the variable, then count it back up to the expected value
before releasing the semaphore. Would expect a context switch or * before releasing the semaphore. Would expect a context switch or
two during this time. */ * two during this time. */
for( ulCounter = ( uint32_t ) 0; ulCounter <= ulExpectedValue; ulCounter++ ) for( ulCounter = ( uint32_t ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
{ {
*pulSharedVariable = ulCounter; *pulSharedVariable = ulCounter;
if( *pulSharedVariable != ulCounter ) if( *pulSharedVariable != ulCounter )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -212,7 +214,7 @@ short sError = pdFALSE, sCheckVariableToUse;
} }
/* Release the semaphore, and if no errors have occurred increment the check /* Release the semaphore, and if no errors have occurred increment the check
variable. */ * variable. */
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE ) if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -227,23 +229,22 @@ short sError = pdFALSE, sCheckVariableToUse;
} }
/* If we have a block time then we are running at a priority higher /* If we have a block time then we are running at a priority higher
than the idle priority. This task takes a long time to complete * than the idle priority. This task takes a long time to complete
a cycle (deliberately so to test the guarding) so will be starving * a cycle (deliberately so to test the guarding) so will be starving
out lower priority tasks. Block for some time to allow give lower * out lower priority tasks. Block for some time to allow give lower
priority tasks some processor time. */ * priority tasks some processor time. */
if( pxParameters->xBlockTime != ( TickType_t ) 0 ) if( pxParameters->xBlockTime != ( TickType_t ) 0 )
{ {
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR ); vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
} }
} }
else else
{ {
if( pxParameters->xBlockTime == ( TickType_t ) 0 ) if( pxParameters->xBlockTime == ( TickType_t ) 0 )
{ {
/* We have not got the semaphore yet, so no point using the /* We have not got the semaphore yet, so no point using the
processor. We are not blocking when attempting to obtain the * processor. We are not blocking when attempting to obtain the
semaphore. */ * semaphore. */
taskYIELD(); taskYIELD();
} }
} }
@ -269,4 +270,3 @@ BaseType_t xTask, xReturn = pdTRUE;
return xReturn; return xReturn;
} }

View file

@ -52,15 +52,15 @@
#define mathNUMBER_OF_TASKS ( 8 ) #define mathNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different floating point calculation. /* Four tasks, each of which performs a different floating point calculation.
Each of the four is created twice. */ * Each of the four is created twice. */
static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters ); static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
/* These variables are used to check that all the tasks are still running. If a /* These variables are used to check that all the tasks are still running. If a
task gets a calculation wrong it will * task gets a calculation wrong it will
stop incrementing its check variable. */ * stop incrementing its check variable. */
static volatile uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 }; static volatile uint16_t usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -92,7 +92,7 @@ short sError = pdFALSE;
fAnswer = ( f1 + f2 ) * f3; fAnswer = ( f1 + f2 ) * f3;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( uint16_t * ) pvParameters; pusTaskCheckVariable = ( uint16_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
@ -109,7 +109,7 @@ short sError = pdFALSE;
#endif #endif
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( f4 - fAnswer ) > 0.001F ) if( fabs( f4 - fAnswer ) > 0.001F )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -118,14 +118,13 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
#if configUSE_PREEMPTION == 0 #if configUSE_PREEMPTION == 0
taskYIELD(); taskYIELD();
#endif #endif
} }
} }
/*-----------------------------------------------------------*/ /*-----------------------------------------------------------*/
@ -145,7 +144,7 @@ short sError = pdFALSE;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( uint16_t * ) pvParameters; pusTaskCheckVariable = ( uint16_t * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */ /* Keep performing a calculation and checking the result against a constant. */
@ -162,7 +161,7 @@ short sError = pdFALSE;
#endif #endif
/* If the calculation does not match the expected constant, stop the /* If the calculation does not match the expected constant, stop the
increment of the check variable. */ * increment of the check variable. */
if( fabs( f4 - fAnswer ) > 0.001F ) if( fabs( f4 - fAnswer ) > 0.001F )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -171,8 +170,8 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know * variable so we know
this task is still running okay. */ * this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
@ -192,14 +191,14 @@ size_t xPosition;
short sError = pdFALSE; short sError = pdFALSE;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( uint16_t * ) pvParameters; pusTaskCheckVariable = ( uint16_t * ) pvParameters;
pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) ); pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ; ; ) for( ; ; )
{ {
fTotal1 = 0.0F; fTotal1 = 0.0F;
@ -222,6 +221,7 @@ short sError = pdFALSE;
} }
fDifference = fTotal1 - fTotal2; fDifference = fTotal1 - fTotal2;
if( fabs( fDifference ) > 0.001F ) if( fabs( fDifference ) > 0.001F )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -234,7 +234,7 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
@ -250,14 +250,14 @@ size_t xPosition;
short sError = pdFALSE; short sError = pdFALSE;
/* The variable this task increments to show it is still running is passed in /* The variable this task increments to show it is still running is passed in
as the parameter. */ * as the parameter. */
pusTaskCheckVariable = ( uint16_t * ) pvParameters; pusTaskCheckVariable = ( uint16_t * ) pvParameters;
pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) ); pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );
/* Keep filling an array, keeping a running total of the values placed in the /* Keep filling an array, keeping a running total of the values placed in the
array. Then run through the array adding up all the values. If the two totals * array. Then run through the array adding up all the values. If the two totals
do not match, stop the check variable from incrementing. */ * do not match, stop the check variable from incrementing. */
for( ; ; ) for( ; ; )
{ {
fTotal1 = 0.0F; fTotal1 = 0.0F;
@ -280,6 +280,7 @@ short sError = pdFALSE;
} }
fDifference = fTotal1 - fTotal2; fDifference = fTotal1 - fTotal2;
if( fabs( fDifference ) > 0.001F ) if( fabs( fDifference ) > 0.001F )
{ {
sError = pdTRUE; sError = pdTRUE;
@ -292,7 +293,7 @@ short sError = pdFALSE;
if( sError == pdFALSE ) if( sError == pdFALSE )
{ {
/* If the calculation has always been correct, increment the check /* If the calculation has always been correct, increment the check
variable so we know this task is still running okay. */ * variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++; ( *pusTaskCheckVariable )++;
} }
} }
@ -303,12 +304,12 @@ short sError = pdFALSE;
BaseType_t xAreMathsTaskStillRunning( void ) BaseType_t xAreMathsTaskStillRunning( void )
{ {
/* Keep a history of the check variables so we know if they have been incremented /* Keep a history of the check variables so we know if they have been incremented
since the last call. */ * since the last call. */
static uint16_t usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 }; static uint16_t usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( uint16_t ) 0 };
BaseType_t xReturn = pdTRUE, xTask; BaseType_t xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables /* Check the maths tasks are still running by ensuring their check variables
are still incrementing. */ * are still incrementing. */
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ ) for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
{ {
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] ) if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
@ -322,6 +323,3 @@ BaseType_t xReturn = pdTRUE, xTask;
return xReturn; return xReturn;
} }

View file

@ -32,5 +32,3 @@ void vCreateAbortDelayTasks( void );
BaseType_t xAreAbortDelayTestTasksStillRunning( void ); BaseType_t xAreAbortDelayTestTasksStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartBlockingQueueTasks( UBaseType_t uxPriority );
BaseType_t xAreBlockingQueuesStillRunning( void ); BaseType_t xAreBlockingQueuesStillRunning( void );
#endif #endif

View file

@ -41,4 +41,3 @@ BaseType_t xAreEventGroupTasksStillRunning( void );
void vPeriodicEventGroupsProcessing( void ); void vPeriodicEventGroupsProcessing( void );
#endif /* EVENT_GROUPS_DEMO_H */ #endif /* EVENT_GROUPS_DEMO_H */

View file

@ -33,6 +33,3 @@ BaseType_t xAreGenericQueueTasksStillRunning( void );
void vMutexISRInteractionTest( void ); void vMutexISRInteractionTest( void );
#endif /* GEN_Q_TEST_H */ #endif /* GEN_Q_TEST_H */

View file

@ -34,9 +34,3 @@ BaseType_t xFirstTimerHandler( void );
BaseType_t xSecondTimerHandler( void ); BaseType_t xSecondTimerHandler( void );
#endif /* QUEUE_ACCESS_TEST */ #endif /* QUEUE_ACCESS_TEST */

View file

@ -33,6 +33,3 @@ BaseType_t xAreInterruptSemaphoreTasksStillRunning( void );
void vInterruptSemaphorePeriodicTest( void ); void vInterruptSemaphorePeriodicTest( void );
#endif /* INT_SEM_TEST_H */ #endif /* INT_SEM_TEST_H */

View file

@ -32,6 +32,3 @@ void vStartMessageBufferTasks( configSTACK_DEPTH_TYPE xStackSize );
BaseType_t xAreMessageBufferTasksStillRunning( void ); BaseType_t xAreMessageBufferTasksStillRunning( void );
#endif /* MESSAGE_BUFFER_TEST_H */ #endif /* MESSAGE_BUFFER_TEST_H */

View file

@ -32,5 +32,3 @@ void vStartPolledQueueTasks( UBaseType_t uxPriority );
BaseType_t xArePollingQueuesStillRunning( void ); BaseType_t xArePollingQueuesStillRunning( void );
#endif #endif

View file

@ -32,6 +32,3 @@ void vStartQueuePeekTasks( void );
BaseType_t xAreQueuePeekTasksStillRunning( void ); BaseType_t xAreQueuePeekTasksStillRunning( void );
#endif /* Q_PEEK_TEST_H */ #endif /* Q_PEEK_TEST_H */

View file

@ -33,5 +33,3 @@ BaseType_t xIsQueueOverwriteTaskStillRunning( void );
void vQueueOverwritePeriodicISRDemo( void ); void vQueueOverwritePeriodicISRDemo( void );
#endif /* QUEUE_OVERWRITE_H */ #endif /* QUEUE_OVERWRITE_H */

View file

@ -33,5 +33,3 @@ BaseType_t xAreQueueSetTasksStillRunning( void );
void vQueueSetAccessQueueSetFromISR( void ); void vQueueSetAccessQueueSetFromISR( void );
#endif /* QUEUE_WAIT_MULTIPLE_H */ #endif /* QUEUE_WAIT_MULTIPLE_H */

View file

@ -33,5 +33,3 @@ BaseType_t xAreQueueSetPollTasksStillRunning( void );
void vQueueSetPollingInterruptAccess( void ); void vQueueSetPollingInterruptAccess( void );
#endif /* QUEUE_SET_POLLING_H */ #endif /* QUEUE_SET_POLLING_H */

View file

@ -32,6 +32,3 @@ void vStartStaticallyAllocatedTasks( void );
BaseType_t xAreStaticAllocationTasksStillRunning( void ); BaseType_t xAreStaticAllocationTasksStillRunning( void );
#endif /* STATIC_ALLOCATION_H */ #endif /* STATIC_ALLOCATION_H */

View file

@ -33,6 +33,3 @@ BaseType_t xAreStreamBufferTasksStillRunning( void );
void vPeriodicStreamBufferProcessing( void ); void vPeriodicStreamBufferProcessing( void );
#endif /* STREAM_BUFFER_TEST_H */ #endif /* STREAM_BUFFER_TEST_H */

View file

@ -33,6 +33,3 @@ BaseType_t xAreTaskNotificationTasksStillRunning( void );
void xNotifyTaskFromISR( void ); void xNotifyTaskFromISR( void );
#endif /* TASK_NOTIFY_H */ #endif /* TASK_NOTIFY_H */

View file

@ -33,6 +33,3 @@ BaseType_t xAreTaskNotificationArrayTasksStillRunning( void );
void xNotifyArrayTaskFromISR( void ); void xNotifyArrayTaskFromISR( void );
#endif /* TASK_NOTIFY_ARRAY_H */ #endif /* TASK_NOTIFY_ARRAY_H */

View file

@ -33,6 +33,3 @@ void vTimerPeriodicISRTests( void );
void vTimerDemoIncludeBacklogTests( BaseType_t includeBacklogTests ); void vTimerDemoIncludeBacklogTests( BaseType_t includeBacklogTests );
#endif /* TIMER_DEMO_H */ #endif /* TIMER_DEMO_H */

View file

@ -32,5 +32,3 @@ void vCreateBlockTimeTasks( void );
BaseType_t xAreBlockTimeTestTasksStillRunning( void ); BaseType_t xAreBlockTimeTestTasksStillRunning( void );
#endif #endif

View file

@ -28,10 +28,13 @@
#ifndef COMTEST_H #ifndef COMTEST_H
#define COMTEST_H #define COMTEST_H
void vAltStartComTestTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ); void vAltStartComTestTasks( UBaseType_t uxPriority,
void vStartComTestTasks( UBaseType_t uxPriority, eCOMPort ePort, eBaud eBaudRate ); uint32_t ulBaudRate,
UBaseType_t uxLED );
void vStartComTestTasks( UBaseType_t uxPriority,
eCOMPort ePort,
eBaud eBaudRate );
BaseType_t xAreComTestTasksStillRunning( void ); BaseType_t xAreComTestTasksStillRunning( void );
void vComTestUnsuspendTask( void ); void vComTestUnsuspendTask( void );
#endif #endif /* ifndef COMTEST_H */

View file

@ -28,8 +28,9 @@
#ifndef COMTEST_H #ifndef COMTEST_H
#define COMTEST_H #define COMTEST_H
void vAltStartComTestTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ); void vAltStartComTestTasks( UBaseType_t uxPriority,
uint32_t ulBaudRate,
UBaseType_t uxLED );
BaseType_t xAreComTestTasksStillRunning( void ); BaseType_t xAreComTestTasksStillRunning( void );
#endif #endif

View file

@ -28,8 +28,9 @@
#ifndef COMTEST_STRINGS_H #ifndef COMTEST_STRINGS_H
#define COMTEST_STRINGS_H #define COMTEST_STRINGS_H
void vStartComTestStringsTasks( UBaseType_t uxPriority, uint32_t ulBaudRate, UBaseType_t uxLED ); void vStartComTestStringsTasks( UBaseType_t uxPriority,
uint32_t ulBaudRate,
UBaseType_t uxLED );
BaseType_t xAreComTestTasksStillRunning( void ); BaseType_t xAreComTestTasksStillRunning( void );
#endif #endif

View file

@ -32,4 +32,3 @@ void vStartCountingSemaphoreTasks( void );
BaseType_t xAreCountingSemaphoreTasksStillRunning( void ); BaseType_t xAreCountingSemaphoreTasksStillRunning( void );
#endif #endif

View file

@ -44,4 +44,3 @@ void vStartFlashCoRoutines( UBaseType_t uxPriority );
BaseType_t xAreFlashCoRoutinesStillRunning( void ); BaseType_t xAreFlashCoRoutinesStillRunning( void );
#endif #endif

View file

@ -40,4 +40,3 @@ void vStartHookCoRoutines( void );
BaseType_t xAreHookCoRoutinesStillRunning( void ); BaseType_t xAreHookCoRoutinesStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vCreateSuicidalTasks( UBaseType_t uxPriority );
BaseType_t xIsCreateTaskStillRunning( void ); BaseType_t xIsCreateTaskStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartDynamicPriorityTasks( void );
BaseType_t xAreDynamicPriorityTasksStillRunning( void ); BaseType_t xAreDynamicPriorityTasksStillRunning( void );
#endif #endif

View file

@ -30,7 +30,7 @@
void vDisplayMessage( const char * const pcMessageToPrint ); void vDisplayMessage( const char * const pcMessageToPrint );
void vWriteMessageToDisk( const char * const pcMessage ); void vWriteMessageToDisk( const char * const pcMessage );
void vWriteBufferToDisk( const char * const pcBuffer, uint32_t ulBufferLength ); void vWriteBufferToDisk( const char * const pcBuffer,
uint32_t ulBufferLength );
#endif #endif

View file

@ -31,4 +31,3 @@
void vStartLEDFlashTasks( UBaseType_t uxPriority ); void vStartLEDFlashTasks( UBaseType_t uxPriority );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartMathTasks( UBaseType_t uxPriority );
BaseType_t xAreMathsTaskStillRunning( void ); BaseType_t xAreMathsTaskStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartIntegerMathTasks( UBaseType_t uxPriority );
BaseType_t xAreIntegerMathsTaskStillRunning( void ); BaseType_t xAreIntegerMathsTaskStillRunning( void );
#endif #endif

View file

@ -32,5 +32,3 @@ void vStartMultiEventTasks( void );
BaseType_t xAreMultiEventTasksStillRunning( void ); BaseType_t xAreMultiEventTasksStillRunning( void );
#endif #endif

View file

@ -31,8 +31,8 @@
#define partstDEFAULT_PORT_ADDRESS ( ( uint16_t ) 0x378 ) #define partstDEFAULT_PORT_ADDRESS ( ( uint16_t ) 0x378 )
void vParTestInitialise( void ); void vParTestInitialise( void );
void vParTestSetLED( UBaseType_t uxLED, BaseType_t xValue ); void vParTestSetLED( UBaseType_t uxLED,
BaseType_t xValue );
void vParTestToggleLED( UBaseType_t uxLED ); void vParTestToggleLED( UBaseType_t uxLED );
#endif #endif

View file

@ -33,5 +33,3 @@ void vPrintDisplayMessage( const char * const * pcMessageToSend );
const char * pcPrintGetNextMessage( TickType_t xPrintRate ); const char * pcPrintGetNextMessage( TickType_t xPrintRate );
#endif #endif

View file

@ -32,4 +32,3 @@ void vStartRecursiveMutexTasks( void );
BaseType_t xAreRecursiveMutexTasksStillRunning( void ); BaseType_t xAreRecursiveMutexTasksStillRunning( void );
#endif #endif

View file

@ -32,4 +32,3 @@ void vStartSemaphoreTasks( UBaseType_t uxPriority );
BaseType_t xAreSemaphoreTasksStillRunning( void ); BaseType_t xAreSemaphoreTasksStillRunning( void );
#endif #endif

View file

@ -86,13 +86,24 @@ typedef enum
ser115200 ser115200
} eBaud; } eBaud;
xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud, unsigned portBASE_TYPE uxQueueLength ); xComPortHandle xSerialPortInitMinimal( unsigned long ulWantedBaud,
xComPortHandle xSerialPortInit( eCOMPort ePort, eBaud eWantedBaud, eParity eWantedParity, eDataBits eWantedDataBits, eStopBits eWantedStopBits, unsigned portBASE_TYPE uxBufferLength ); unsigned portBASE_TYPE uxQueueLength );
void vSerialPutString( xComPortHandle pxPort, const signed char * const pcString, unsigned short usStringLength ); xComPortHandle xSerialPortInit( eCOMPort ePort,
signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort, signed char *pcRxedChar, TickType_t xBlockTime ); eBaud eWantedBaud,
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort, signed char cOutChar, TickType_t xBlockTime ); eParity eWantedParity,
eDataBits eWantedDataBits,
eStopBits eWantedStopBits,
unsigned portBASE_TYPE uxBufferLength );
void vSerialPutString( xComPortHandle pxPort,
const signed char * const pcString,
unsigned short usStringLength );
signed portBASE_TYPE xSerialGetChar( xComPortHandle pxPort,
signed char * pcRxedChar,
TickType_t xBlockTime );
signed portBASE_TYPE xSerialPutChar( xComPortHandle pxPort,
signed char cOutChar,
TickType_t xBlockTime );
portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort ); portBASE_TYPE xSerialWaitForSemaphore( xComPortHandle xPort );
void vSerialClose( xComPortHandle xPort ); void vSerialClose( xComPortHandle xPort );
#endif #endif /* ifndef SERIAL_COMMS_H */

View file

@ -1,3 +1,5 @@
eFrameProcessingResult_t publicProcessIPPacket( IPPacket_t * const pxIPPacket, NetworkBufferDescriptor_t * const pxNetworkBuffer ) { eFrameProcessingResult_t publicProcessIPPacket( IPPacket_t * const pxIPPacket,
NetworkBufferDescriptor_t * const pxNetworkBuffer )
{
prvProcessIPPacket( pxIPPacket, pxNetworkBuffer ); prvProcessIPPacket( pxIPPacket, pxNetworkBuffer );
} }

View file

@ -1,12 +1,20 @@
int32_t publicTCPPrepareSend( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer, UBaseType_t uxOptionsLength ) { int32_t publicTCPPrepareSend( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t ** ppxNetworkBuffer,
UBaseType_t uxOptionsLength )
{
prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength ); prvTCPPrepareSend( pxSocket, ppxNetworkBuffer, uxOptionsLength );
} }
BaseType_t publicTCPHandleState( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t **ppxNetworkBuffer ) { BaseType_t publicTCPHandleState( FreeRTOS_Socket_t * pxSocket,
NetworkBufferDescriptor_t ** ppxNetworkBuffer )
{
prvTCPHandleState( pxSocket, ppxNetworkBuffer ); prvTCPHandleState( pxSocket, ppxNetworkBuffer );
} }
void publicTCPReturnPacket( FreeRTOS_Socket_t *pxSocket, NetworkBufferDescriptor_t *pxNetworkBuffer, void publicTCPReturnPacket( FreeRTOS_Socket_t * pxSocket,
uint32_t ulLen, BaseType_t xReleaseAfterSend ) { NetworkBufferDescriptor_t * pxNetworkBuffer,
uint32_t ulLen,
BaseType_t xReleaseAfterSend )
{
prvTCPReturnPacket( pxSocket, pxNetworkBuffer, ulLen, xReleaseAfterSend ); prvTCPReturnPacket( pxSocket, pxNetworkBuffer, ulLen, xReleaseAfterSend );
} }

View file

@ -11,28 +11,36 @@
#endif #endif
/* Using prvCopyDataToQueue together with prvNotifyQueueSetContainer /* Using prvCopyDataToQueue together with prvNotifyQueueSetContainer
leads to a problem space explosion. Therefore, we use this stub * leads to a problem space explosion. Therefore, we use this stub
and a sepearted proof on prvCopyDataToQueue to deal with it. * and a sepearted proof on prvCopyDataToQueue to deal with it.
As prvNotifyQueueSetContainer is disabled if configUSE_QUEUE_SETS != 1, * As prvNotifyQueueSetContainer is disabled if configUSE_QUEUE_SETS != 1,
in other cases the original implementation should be used. */ * in other cases the original implementation should be used. */
#if ( configUSE_QUEUE_SETS == 1 ) #if ( configUSE_QUEUE_SETS == 1 )
BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue,
const void * pvItemToQueue,
const BaseType_t xPosition )
{ {
if( pxQueue->uxItemSize > ( UBaseType_t ) 0 ) if( pxQueue->uxItemSize > ( UBaseType_t ) 0 )
{ {
__CPROVER_assert( __CPROVER_r_ok( pvItemToQueue, ( size_t ) pxQueue->uxItemSize ), "pvItemToQueue region must be readable" ); __CPROVER_assert( __CPROVER_r_ok( pvItemToQueue, ( size_t ) pxQueue->uxItemSize ), "pvItemToQueue region must be readable" );
if(xPosition == queueSEND_TO_BACK){
if( xPosition == queueSEND_TO_BACK )
{
__CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->pcWriteTo, ( size_t ) pxQueue->uxItemSize ), "pxQueue->pcWriteTo region must be writable" ); __CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->pcWriteTo, ( size_t ) pxQueue->uxItemSize ), "pxQueue->pcWriteTo region must be writable" );
}else{ }
else
{
__CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ), "pxQueue->u.xQueue.pcReadFrom region must be writable" ); __CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ), "pxQueue->u.xQueue.pcReadFrom region must be writable" );
} }
return pdFALSE; return pdFALSE;
}else }
else
{ {
return nondet_BaseType_t(); return nondet_BaseType_t();
} }
} }
#endif #endif /* if ( configUSE_QUEUE_SETS == 1 ) */
/* xQueueCreateSet is compiled out if configUSE_QUEUE_SETS != 1.*/ /* xQueueCreateSet is compiled out if configUSE_QUEUE_SETS != 1.*/
#if ( configUSE_QUEUE_SETS == 1 ) #if ( configUSE_QUEUE_SETS == 1 )
@ -40,6 +48,7 @@
{ {
UBaseType_t uxEventQueueLength = 2; UBaseType_t uxEventQueueLength = 2;
QueueSetHandle_t xSet = xQueueCreateSet( uxEventQueueLength ); QueueSetHandle_t xSet = xQueueCreateSet( uxEventQueueLength );
if( xSet ) if( xSet )
{ {
xSet->cTxLock = nondet_int8_t(); xSet->cTxLock = nondet_int8_t();
@ -47,39 +56,46 @@
xSet->cRxLock = nondet_int8_t(); xSet->cRxLock = nondet_int8_t();
xSet->uxMessagesWaiting = nondet_UBaseType_t(); xSet->uxMessagesWaiting = nondet_UBaseType_t();
xSet->xTasksWaitingToReceive.uxNumberOfItems = nondet_UBaseType_t(); xSet->xTasksWaitingToReceive.uxNumberOfItems = nondet_UBaseType_t();
/* This is an invariant checked with a couple of asserts in the code base. /* This is an invariant checked with a couple of asserts in the code base.
If it is false from the beginning, the CBMC proofs are not able to succeed*/ * If it is false from the beginning, the CBMC proofs are not able to succeed*/
__CPROVER_assume( xSet->uxMessagesWaiting < xSet->uxLength ); __CPROVER_assume( xSet->uxMessagesWaiting < xSet->uxLength );
xSet->xTasksWaitingToSend.uxNumberOfItems = nondet_UBaseType_t(); xSet->xTasksWaitingToSend.uxNumberOfItems = nondet_UBaseType_t();
} }
return xSet; return xSet;
} }
#endif #endif /* if ( configUSE_QUEUE_SETS == 1 ) */
/* Create a mostly unconstrained Queue but bound the max item size. /* Create a mostly unconstrained Queue but bound the max item size.
This is required for performance reasons in CBMC at the moment. */ * This is required for performance reasons in CBMC at the moment. */
QueueHandle_t xUnconstrainedQueueBoundedItemSize( UBaseType_t uxItemSizeBound ) { QueueHandle_t xUnconstrainedQueueBoundedItemSize( UBaseType_t uxItemSizeBound )
{
UBaseType_t uxQueueLength; UBaseType_t uxQueueLength;
UBaseType_t uxItemSize; UBaseType_t uxItemSize;
uint8_t ucQueueType; uint8_t ucQueueType;
__CPROVER_assume( uxQueueLength > 0 ); __CPROVER_assume( uxQueueLength > 0 );
__CPROVER_assume( uxItemSize < uxItemSizeBound ); __CPROVER_assume( uxItemSize < uxItemSizeBound );
// QueueGenericCreate method does not check for multiplication overflow /* QueueGenericCreate method does not check for multiplication overflow */
size_t uxQueueStorageSize; size_t uxQueueStorageSize;
__CPROVER_assume( uxQueueStorageSize < CBMC_OBJECT_MAX_SIZE ); __CPROVER_assume( uxQueueStorageSize < CBMC_OBJECT_MAX_SIZE );
__CPROVER_assume( uxItemSize < uxQueueStorageSize / uxQueueLength ); __CPROVER_assume( uxItemSize < uxQueueStorageSize / uxQueueLength );
QueueHandle_t xQueue = QueueHandle_t xQueue =
xQueueGenericCreate( uxQueueLength, uxItemSize, ucQueueType ); xQueueGenericCreate( uxQueueLength, uxItemSize, ucQueueType );
if(xQueue){
if( xQueue )
{
xQueue->cTxLock = nondet_int8_t(); xQueue->cTxLock = nondet_int8_t();
__CPROVER_assume( xQueue->cTxLock != 127 ); __CPROVER_assume( xQueue->cTxLock != 127 );
xQueue->cRxLock = nondet_int8_t(); xQueue->cRxLock = nondet_int8_t();
__CPROVER_assume( xQueue->cRxLock != 127 ); __CPROVER_assume( xQueue->cRxLock != 127 );
xQueue->uxMessagesWaiting = nondet_UBaseType_t(); xQueue->uxMessagesWaiting = nondet_UBaseType_t();
/* This is an invariant checked with a couple of asserts in the code base. /* This is an invariant checked with a couple of asserts in the code base.
If it is false from the beginning, the CBMC proofs are not able to succeed*/ * If it is false from the beginning, the CBMC proofs are not able to succeed*/
__CPROVER_assume( xQueue->uxMessagesWaiting < xQueue->uxLength ); __CPROVER_assume( xQueue->uxMessagesWaiting < xQueue->uxLength );
xQueue->xTasksWaitingToReceive.uxNumberOfItems = nondet_UBaseType_t(); xQueue->xTasksWaitingToReceive.uxNumberOfItems = nondet_UBaseType_t();
xQueue->xTasksWaitingToSend.uxNumberOfItems = nondet_UBaseType_t(); xQueue->xTasksWaitingToSend.uxNumberOfItems = nondet_UBaseType_t();
@ -87,18 +103,20 @@ QueueHandle_t xUnconstrainedQueueBoundedItemSize( UBaseType_t uxItemSizeBound )
xQueueAddToSet( xQueue, xUnconstrainedQueueSet() ); xQueueAddToSet( xQueue, xUnconstrainedQueueSet() );
#endif #endif
} }
return xQueue; return xQueue;
} }
/* Create a mostly unconstrained Queue */ /* Create a mostly unconstrained Queue */
QueueHandle_t xUnconstrainedQueue( void ) { QueueHandle_t xUnconstrainedQueue( void )
{
UBaseType_t uxQueueLength; UBaseType_t uxQueueLength;
UBaseType_t uxItemSize; UBaseType_t uxItemSize;
uint8_t ucQueueType; uint8_t ucQueueType;
__CPROVER_assume( uxQueueLength > 0 ); __CPROVER_assume( uxQueueLength > 0 );
// QueueGenericCreate method does not check for multiplication overflow /* QueueGenericCreate method does not check for multiplication overflow */
size_t uxQueueStorageSize; size_t uxQueueStorageSize;
__CPROVER_assume( uxQueueStorageSize < CBMC_OBJECT_MAX_SIZE ); __CPROVER_assume( uxQueueStorageSize < CBMC_OBJECT_MAX_SIZE );
__CPROVER_assume( uxItemSize < uxQueueStorageSize / uxQueueLength ); __CPROVER_assume( uxItemSize < uxQueueStorageSize / uxQueueLength );
@ -106,13 +124,15 @@ QueueHandle_t xUnconstrainedQueue( void ) {
QueueHandle_t xQueue = QueueHandle_t xQueue =
xQueueGenericCreate( uxQueueLength, uxItemSize, ucQueueType ); xQueueGenericCreate( uxQueueLength, uxItemSize, ucQueueType );
if(xQueue){ if( xQueue )
{
xQueue->cTxLock = nondet_int8_t(); xQueue->cTxLock = nondet_int8_t();
__CPROVER_assume( xQueue->cTxLock != 127 ); __CPROVER_assume( xQueue->cTxLock != 127 );
xQueue->cRxLock = nondet_int8_t(); xQueue->cRxLock = nondet_int8_t();
xQueue->uxMessagesWaiting = nondet_UBaseType_t(); xQueue->uxMessagesWaiting = nondet_UBaseType_t();
/* This is an invariant checked with a couple of asserts in the code base. /* This is an invariant checked with a couple of asserts in the code base.
If it is false from the beginning, the CBMC proofs are not able to succeed*/ * If it is false from the beginning, the CBMC proofs are not able to succeed*/
__CPROVER_assume( xQueue->uxMessagesWaiting < xQueue->uxLength ); __CPROVER_assume( xQueue->uxMessagesWaiting < xQueue->uxLength );
xQueue->xTasksWaitingToReceive.uxNumberOfItems = nondet_UBaseType_t(); xQueue->xTasksWaitingToReceive.uxNumberOfItems = nondet_UBaseType_t();
xQueue->xTasksWaitingToSend.uxNumberOfItems = nondet_UBaseType_t(); xQueue->xTasksWaitingToSend.uxNumberOfItems = nondet_UBaseType_t();
@ -120,21 +140,26 @@ QueueHandle_t xUnconstrainedQueue( void ) {
xQueueAddToSet( xQueue, xUnconstrainedQueueSet() ); xQueueAddToSet( xQueue, xUnconstrainedQueueSet() );
#endif #endif
} }
return xQueue; return xQueue;
} }
/* Create a mostly unconstrained Mutex */ /* Create a mostly unconstrained Mutex */
QueueHandle_t xUnconstrainedMutex( void ) { QueueHandle_t xUnconstrainedMutex( void )
{
uint8_t ucQueueType; uint8_t ucQueueType;
QueueHandle_t xQueue = QueueHandle_t xQueue =
xQueueCreateMutex( ucQueueType ); xQueueCreateMutex( ucQueueType );
if(xQueue){
if( xQueue )
{
xQueue->cTxLock = nondet_int8_t(); xQueue->cTxLock = nondet_int8_t();
__CPROVER_assume( xQueue->cTxLock != 127 ); __CPROVER_assume( xQueue->cTxLock != 127 );
xQueue->cRxLock = nondet_int8_t(); xQueue->cRxLock = nondet_int8_t();
xQueue->uxMessagesWaiting = nondet_UBaseType_t(); xQueue->uxMessagesWaiting = nondet_UBaseType_t();
/* This is an invariant checked with a couple of asserts in the code base. /* This is an invariant checked with a couple of asserts in the code base.
If it is false from the beginning, the CBMC proofs are not able to succeed*/ * If it is false from the beginning, the CBMC proofs are not able to succeed*/
__CPROVER_assume( xQueue->uxMessagesWaiting < xQueue->uxLength ); __CPROVER_assume( xQueue->uxMessagesWaiting < xQueue->uxLength );
xQueue->xTasksWaitingToReceive.uxNumberOfItems = nondet_UBaseType_t(); xQueue->xTasksWaitingToReceive.uxNumberOfItems = nondet_UBaseType_t();
xQueue->xTasksWaitingToSend.uxNumberOfItems = nondet_UBaseType_t(); xQueue->xTasksWaitingToSend.uxNumberOfItems = nondet_UBaseType_t();
@ -142,5 +167,6 @@ QueueHandle_t xUnconstrainedMutex( void ) {
xQueueAddToSet( xQueue, xUnconstrainedQueueSet() ); xQueueAddToSet( xQueue, xUnconstrainedQueueSet() );
#endif #endif
} }
return xQueue; return xQueue;
} }

View file

@ -5,6 +5,7 @@
#include "task.h" #include "task.h"
BaseType_t xState; BaseType_t xState;
void vInitTaskCheckForTimeOut(BaseType_t maxCounter, BaseType_t maxCounter_limit); void vInitTaskCheckForTimeOut( BaseType_t maxCounter,
BaseType_t maxCounter_limit );
#endif /* INC_TASK_STUBS_H */ #endif /* INC_TASK_STUBS_H */

View file

@ -1,26 +1,26 @@
/* /*
FreeRTOS V202104.00 * FreeRTOS V202104.00
Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved. * Copyright (C) 2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
Permission is hereby granted, free of charge, to any person obtaining a copy of * 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 * this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to * the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * 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, * the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions: * subject to the following conditions:
*
The above copyright notice and this permission notice shall be included in all * The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software. * copies or substantial portions of the Software.
*
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * 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 * 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 * 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. * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
http://aws.amazon.com/freertos * http://aws.amazon.com/freertos
http://www.FreeRTOS.org * http://www.FreeRTOS.org
*/ */

View file

@ -7,9 +7,9 @@
#endif #endif
/* 5 is a magic number, but we need some number here as a default value. /* 5 is a magic number, but we need some number here as a default value.
This value is used to bound any loop depending on xTaskCheckForTimeOut * This value is used to bound any loop depending on xTaskCheckForTimeOut
as a loop bound. It should be overwritten in the Makefile.json adapting * as a loop bound. It should be overwritten in the Makefile.json adapting
to the performance requirements of the harness. */ * to the performance requirements of the harness. */
#ifndef TASK_STUB_COUNTER_LIMIT #ifndef TASK_STUB_COUNTER_LIMIT
#define TASK_STUB_COUNTER_LIMIT 5; #define TASK_STUB_COUNTER_LIMIT 5;
#endif #endif
@ -24,18 +24,22 @@ BaseType_t xTaskGetSchedulerState( void )
} }
/* This function is another method apart from overwritting the defines to init the max /* This function is another method apart from overwritting the defines to init the max
loop bound. */ * loop bound. */
void vInitTaskCheckForTimeOut(BaseType_t maxCounter, BaseType_t maxCounter_limit) void vInitTaskCheckForTimeOut( BaseType_t maxCounter,
BaseType_t maxCounter_limit )
{ {
xCounter = maxCounter; xCounter = maxCounter;
xCounterLimit = maxCounter_limit; xCounterLimit = maxCounter_limit;
} }
/* This is mostly called in a loop. For CBMC, we have to bound the loop /* This is mostly called in a loop. For CBMC, we have to bound the loop
to a max limits of calls. Therefore this Stub models a nondet timeout in * to a max limits of calls. Therefore this Stub models a nondet timeout in
max TASK_STUB_COUNTER_LIMIT iterations.*/ * max TASK_STUB_COUNTER_LIMIT iterations.*/
BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut, TickType_t * const pxTicksToWait ) { BaseType_t xTaskCheckForTimeOut( TimeOut_t * const pxTimeOut,
TickType_t * const pxTicksToWait )
{
++xCounter; ++xCounter;
if( xCounter == xCounterLimit ) if( xCounter == xCounterLimit )
{ {
return pdTRUE; return pdTRUE;

View file

@ -31,7 +31,8 @@
#include "cbmc.h" #include "cbmc.h"
void harness() { void harness()
{
uint8_t ucQueueType; uint8_t ucQueueType;
xQueueCreateMutex( ucQueueType ); xQueueCreateMutex( ucQueueType );

View file

@ -42,35 +42,47 @@
#endif #endif
#if ( configUSE_QUEUE_SETS == 0 ) #if ( configUSE_QUEUE_SETS == 0 )
BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue,
const void * pvItemToQueue,
const BaseType_t xPosition )
{ {
if( pxQueue->uxItemSize > ( UBaseType_t ) 0 ) if( pxQueue->uxItemSize > ( UBaseType_t ) 0 )
{ {
__CPROVER_assert( __CPROVER_r_ok( pvItemToQueue, ( size_t ) pxQueue->uxItemSize ), "pvItemToQueue region must be readable" ); __CPROVER_assert( __CPROVER_r_ok( pvItemToQueue, ( size_t ) pxQueue->uxItemSize ), "pvItemToQueue region must be readable" );
if(xPosition == queueSEND_TO_BACK){
if( xPosition == queueSEND_TO_BACK )
{
__CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->pcWriteTo, ( size_t ) pxQueue->uxItemSize ), "pxQueue->pcWriteTo region must be writable" ); __CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->pcWriteTo, ( size_t ) pxQueue->uxItemSize ), "pxQueue->pcWriteTo region must be writable" );
}else{ }
else
{
__CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ), "pxQueue->u.xQueue.pcReadFrom region must be writable" ); __CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ), "pxQueue->u.xQueue.pcReadFrom region must be writable" );
} }
return pdFALSE; return pdFALSE;
}else }
else
{ {
return nondet_BaseType_t(); return nondet_BaseType_t();
} }
} }
#else #else /* if ( configUSE_QUEUE_SETS == 0 ) */
BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue ) BaseType_t prvNotifyQueueSetContainer( const Queue_t * const pxQueue )
{ {
Queue_t * pxQueueSetContainer = pxQueue->pxQueueSetContainer; Queue_t * pxQueueSetContainer = pxQueue->pxQueueSetContainer;
configASSERT( pxQueueSetContainer ); configASSERT( pxQueueSetContainer );
} }
void prvUnlockQueue( Queue_t * const pxQueue ) { void prvUnlockQueue( Queue_t * const pxQueue )
{
configASSERT( pxQueue ); configASSERT( pxQueue );
if( pxQueue->pxQueueSetContainer != NULL ) if( pxQueue->pxQueueSetContainer != NULL )
{ {
prvNotifyQueueSetContainer( pxQueue ); prvNotifyQueueSetContainer( pxQueue );
} }
listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ); listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) );
pxQueue->cTxLock = queueUNLOCKED; pxQueue->cTxLock = queueUNLOCKED;
@ -78,50 +90,56 @@ BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueu
pxQueue->cRxLock = queueUNLOCKED; pxQueue->cRxLock = queueUNLOCKED;
} }
#endif #endif /* if ( configUSE_QUEUE_SETS == 0 ) */
void harness(){ void harness()
//Initialise the tasksStubs {
/*Initialise the tasksStubs */
vInitTaskCheckForTimeOut( 0, QUEUE_SEND_BOUND - 1 ); vInitTaskCheckForTimeOut( 0, QUEUE_SEND_BOUND - 1 );
xState = nondet_basetype(); xState = nondet_basetype();
QueueHandle_t xQueue = QueueHandle_t xQueue =
xUnconstrainedQueueBoundedItemSize( 2 ); xUnconstrainedQueueBoundedItemSize( 2 );
TickType_t xTicksToWait; TickType_t xTicksToWait;
if(xState == taskSCHEDULER_SUSPENDED){
if( xState == taskSCHEDULER_SUSPENDED )
{
xTicksToWait = 0; xTicksToWait = 0;
} }
if(xQueue){ if( xQueue )
{
void * pvItemToQueue = pvPortMalloc( xQueue->uxItemSize ); void * pvItemToQueue = pvPortMalloc( xQueue->uxItemSize );
BaseType_t xCopyPosition; BaseType_t xCopyPosition;
if(xCopyPosition == queueOVERWRITE){ if( xCopyPosition == queueOVERWRITE )
{
xQueue->uxLength = 1; xQueue->uxLength = 1;
} }
if( xQueue->uxItemSize == 0 ) if( xQueue->uxItemSize == 0 )
{ {
/* uxQueue->xQueueType is a pointer to the head of the queue storage area. /* uxQueue->xQueueType is a pointer to the head of the queue storage area.
If an item has a sice, this pointer must not be modified after init. * If an item has a sice, this pointer must not be modified after init.
Otherwise some of the write statements will fail. */ * Otherwise some of the write statements will fail. */
xQueue->uxQueueType = nondet_int8_t(); xQueue->uxQueueType = nondet_int8_t();
pvItemToQueue = 0; pvItemToQueue = 0;
} }
/* This code checks explicitly for violations of the pxQueue->uxMessagesWaiting < pxQueue->uxLength /* This code checks explicitly for violations of the pxQueue->uxMessagesWaiting < pxQueue->uxLength
invariant. */ * invariant. */
xQueue->uxMessagesWaiting = nondet_UBaseType_t(); xQueue->uxMessagesWaiting = nondet_UBaseType_t();
/* These values are decremented during a while loop interacting with task.c. /* These values are decremented during a while loop interacting with task.c.
This interaction is currently abstracted away.*/ * This interaction is currently abstracted away.*/
xQueue->cTxLock = LOCK_BOUND - 1; xQueue->cTxLock = LOCK_BOUND - 1;
xQueue->cRxLock = LOCK_BOUND - 1; xQueue->cRxLock = LOCK_BOUND - 1;
if(!pvItemToQueue){ if( !pvItemToQueue )
{
xQueue->uxItemSize = 0; xQueue->uxItemSize = 0;
} }
xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, xCopyPosition ); xQueueGenericSend( xQueue, pvItemToQueue, xTicksToWait, xCopyPosition );
} }
} }

View file

@ -37,49 +37,66 @@
#endif #endif
#if ( configUSE_QUEUE_SETS == 0 ) #if ( configUSE_QUEUE_SETS == 0 )
BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition ) BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue,
const void * pvItemToQueue,
const BaseType_t xPosition )
{ {
if( pxQueue->uxItemSize > ( UBaseType_t ) 0 ) if( pxQueue->uxItemSize > ( UBaseType_t ) 0 )
{ {
__CPROVER_assert( __CPROVER_r_ok( pvItemToQueue, ( size_t ) pxQueue->uxItemSize ), "pvItemToQueue region must be readable" ); __CPROVER_assert( __CPROVER_r_ok( pvItemToQueue, ( size_t ) pxQueue->uxItemSize ), "pvItemToQueue region must be readable" );
if(xPosition == queueSEND_TO_BACK){
if( xPosition == queueSEND_TO_BACK )
{
__CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->pcWriteTo, ( size_t ) pxQueue->uxItemSize ), "pxQueue->pcWriteTo region must be writable" ); __CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->pcWriteTo, ( size_t ) pxQueue->uxItemSize ), "pxQueue->pcWriteTo region must be writable" );
}else{ }
else
{
__CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ), "pxQueue->u.xQueue.pcReadFrom region must be writable" ); __CPROVER_assert( __CPROVER_w_ok( ( void * ) pxQueue->u.xQueue.pcReadFrom, ( size_t ) pxQueue->uxItemSize ), "pxQueue->u.xQueue.pcReadFrom region must be writable" );
} }
return pdFALSE; return pdFALSE;
}else }
else
{ {
return nondet_BaseType_t(); return nondet_BaseType_t();
} }
} }
#endif #endif /* if ( configUSE_QUEUE_SETS == 0 ) */
void harness(){ void harness()
{
QueueHandle_t xQueue = xUnconstrainedQueueBoundedItemSize( ITEM_BOUND ); QueueHandle_t xQueue = xUnconstrainedQueueBoundedItemSize( ITEM_BOUND );
if( xQueue ){ if( xQueue )
{
void * pvItemToQueue = pvPortMalloc( xQueue->uxItemSize ); void * pvItemToQueue = pvPortMalloc( xQueue->uxItemSize );
BaseType_t * xHigherPriorityTaskWoken = pvPortMalloc( sizeof( BaseType_t ) ); BaseType_t * xHigherPriorityTaskWoken = pvPortMalloc( sizeof( BaseType_t ) );
BaseType_t xCopyPosition; BaseType_t xCopyPosition;
if( xQueue->uxItemSize == 0 ) if( xQueue->uxItemSize == 0 )
{ {
/* uxQueue->xQueueType is a pointer to the head of the queue storage area. /* uxQueue->xQueueType is a pointer to the head of the queue storage area.
If an item has a size, this pointer must not be modified after init. * If an item has a size, this pointer must not be modified after init.
Otherwise some of the write statements will fail. */ * Otherwise some of the write statements will fail. */
xQueue->uxQueueType = nondet_int8_t(); xQueue->uxQueueType = nondet_int8_t();
pvItemToQueue = 0; pvItemToQueue = 0;
} }
/* This code checks explicitly for violations of the pxQueue->uxMessagesWaiting < pxQueue->uxLength /* This code checks explicitly for violations of the pxQueue->uxMessagesWaiting < pxQueue->uxLength
invariant. */ * invariant. */
xQueue->uxMessagesWaiting = nondet_UBaseType_t(); xQueue->uxMessagesWaiting = nondet_UBaseType_t();
if(!pvItemToQueue){
if( !pvItemToQueue )
{
xQueue->uxItemSize = 0; xQueue->uxItemSize = 0;
} }
if(xCopyPosition == 2 ){
if( xCopyPosition == 2 )
{
__CPROVER_assume( xQueue->uxLength == 1 ); __CPROVER_assume( xQueue->uxLength == 1 );
} }
xQueueGenericSendFromISR( xQueue, pvItemToQueue, xHigherPriorityTaskWoken, xCopyPosition ); xQueueGenericSendFromISR( xQueue, pvItemToQueue, xHigherPriorityTaskWoken, xCopyPosition );
} }
} }

View file

@ -32,9 +32,12 @@
#include "cbmc.h" #include "cbmc.h"
void harness() { void harness()
{
QueueHandle_t xSemaphore = xUnconstrainedQueue(); QueueHandle_t xSemaphore = xUnconstrainedQueue();
if (xSemaphore) {
if( xSemaphore )
{
xSemaphore->uxQueueType = nondet_uint8_t(); xSemaphore->uxQueueType = nondet_uint8_t();
xQueueGetMutexHolder( xSemaphore ); xQueueGetMutexHolder( xSemaphore );
} }

View file

@ -32,10 +32,12 @@
#include "cbmc.h" #include "cbmc.h"
void harness(){ void harness()
{
QueueHandle_t xSemaphore = pvPortMalloc( sizeof( Queue_t ) ); QueueHandle_t xSemaphore = pvPortMalloc( sizeof( Queue_t ) );
if (xSemaphore) {
if( xSemaphore )
{
xQueueGetMutexHolderFromISR( xSemaphore ); xQueueGetMutexHolderFromISR( xSemaphore );
} }
} }

View file

@ -32,12 +32,14 @@
#include "cbmc.h" #include "cbmc.h"
void harness(){ void harness()
{
QueueHandle_t xQueue = xUnconstrainedMutex(); QueueHandle_t xQueue = xUnconstrainedMutex();
BaseType_t * xHigherPriorityTaskWoken = pvPortMalloc( sizeof( BaseType_t ) ); BaseType_t * xHigherPriorityTaskWoken = pvPortMalloc( sizeof( BaseType_t ) );
if(xQueue){
if( xQueue )
{
xQueue->uxMessagesWaiting = nondet_UBaseType_t(); xQueue->uxMessagesWaiting = nondet_UBaseType_t();
xQueueGiveFromISR( xQueue, xHigherPriorityTaskWoken ); xQueueGiveFromISR( xQueue, xHigherPriorityTaskWoken );
} }
} }

View file

@ -32,15 +32,19 @@
#include "cbmc.h" #include "cbmc.h"
void harness() { void harness()
{
uint8_t ucQueueType; uint8_t ucQueueType;
QueueHandle_t xMutex = QueueHandle_t xMutex =
xQueueCreateMutex( ucQueueType ); xQueueCreateMutex( ucQueueType );
if (xMutex) {
if( xMutex )
{
xMutex->uxQueueType = ucQueueType; xMutex->uxQueueType = ucQueueType;
UBaseType_t uxCounter; UBaseType_t uxCounter;
/* This assumption is explained in the queue.c file inside the method body /* This assumption is explained in the queue.c file inside the method body
xQueueGiveMutexRecursive and guards against an underflow error. */ * xQueueGiveMutexRecursive and guards against an underflow error. */
__CPROVER_assume( uxCounter > 0 ); __CPROVER_assume( uxCounter > 0 );
xMutex->u.xSemaphore.uxRecursiveCallCount = uxCounter; xMutex->u.xSemaphore.uxRecursiveCallCount = uxCounter;
xQueueGiveMutexRecursive( xMutex ); xQueueGiveMutexRecursive( xMutex );

View file

@ -32,10 +32,12 @@
#include "cbmc.h" #include "cbmc.h"
void harness(){ void harness()
{
QueueHandle_t xQueue = pvPortMalloc( sizeof( Queue_t ) ); QueueHandle_t xQueue = pvPortMalloc( sizeof( Queue_t ) );
if(xQueue){ if( xQueue )
{
uxQueueMessagesWaiting( xQueue ); uxQueueMessagesWaiting( xQueue );
} }
} }

View file

@ -45,32 +45,38 @@ QueueHandle_t xQueue;
/* This method is called to initialize pxTimeOut. /* This method is called to initialize pxTimeOut.
Setting up the data structure is not interesting for the proof, * Setting up the data structure is not interesting for the proof,
but the harness uses it to model a release * but the harness uses it to model a release
on the queue after first check. */ * on the queue after first check. */
void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut ){ void vTaskInternalSetTimeOutState( TimeOut_t * const pxTimeOut )
{
xQueue->uxMessagesWaiting = nondet_BaseType_t(); xQueue->uxMessagesWaiting = nondet_BaseType_t();
} }
void harness(){ void harness()
{
xQueue = xUnconstrainedQueueBoundedItemSize( 10 ); xQueue = xUnconstrainedQueueBoundedItemSize( 10 );
//Initialise the tasksStubs /*Initialise the tasksStubs */
vInitTaskCheckForTimeOut( 0, QUEUE_PEEK_BOUND - 1 ); vInitTaskCheckForTimeOut( 0, QUEUE_PEEK_BOUND - 1 );
TickType_t xTicksToWait; TickType_t xTicksToWait;
if(xState == taskSCHEDULER_SUSPENDED){
if( xState == taskSCHEDULER_SUSPENDED )
{
xTicksToWait = 0; xTicksToWait = 0;
} }
if(xQueue){ if( xQueue )
{
__CPROVER_assume( xQueue->cTxLock < LOCK_BOUND - 1 ); __CPROVER_assume( xQueue->cTxLock < LOCK_BOUND - 1 );
__CPROVER_assume( xQueue->cRxLock < LOCK_BOUND - 1 ); __CPROVER_assume( xQueue->cRxLock < LOCK_BOUND - 1 );
void * pvItemToQueue = pvPortMalloc( xQueue->uxItemSize ); void * pvItemToQueue = pvPortMalloc( xQueue->uxItemSize );
/* In case malloc fails as this is otherwise an invariant violation. */ /* In case malloc fails as this is otherwise an invariant violation. */
if(!pvItemToQueue){ if( !pvItemToQueue )
{
xQueue->uxItemSize = 0; xQueue->uxItemSize = 0;
} }

Some files were not shown because too many files have changed in this diff Show more