/* | |
FreeRTOS V6.0.3 - Copyright (C) 2010 Real Time Engineers Ltd. | |
*************************************************************************** | |
* * | |
* If you are: * | |
* * | |
* + New to FreeRTOS, * | |
* + Wanting to learn FreeRTOS or multitasking in general quickly * | |
* + Looking for basic training, * | |
* + Wanting to improve your FreeRTOS skills and productivity * | |
* * | |
* then take a look at the FreeRTOS eBook * | |
* * | |
* "Using the FreeRTOS Real Time Kernel - a Practical Guide" * | |
* http://www.FreeRTOS.org/Documentation * | |
* * | |
* A pdf reference manual is also available. Both are usually delivered * | |
* to your inbox within 20 minutes to two hours when purchased between 8am * | |
* and 8pm GMT (although please allow up to 24 hours in case of * | |
* exceptional circumstances). Thank you for your support! * | |
* * | |
*************************************************************************** | |
This file is part of the FreeRTOS distribution. | |
FreeRTOS is free software; you can redistribute it and/or modify it under | |
the terms of the GNU General Public License (version 2) as published by the | |
Free Software Foundation AND MODIFIED BY the FreeRTOS exception. | |
***NOTE*** The exception to the GPL is included to allow you to distribute | |
a combined work that includes FreeRTOS without being obliged to provide the | |
source code for proprietary components outside of the FreeRTOS kernel. | |
FreeRTOS is distributed in the hope that it will be useful, but WITHOUT | |
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for | |
more details. You should have received a copy of the GNU General Public | |
License and the FreeRTOS license exception along with FreeRTOS; if not it | |
can be viewed here: http://www.freertos.org/a00114.html and also obtained | |
by writing to Richard Barry, contact details for whom are available on the | |
FreeRTOS WEB site. | |
1 tab == 4 spaces! | |
http://www.FreeRTOS.org - Documentation, latest information, license and | |
contact details. | |
http://www.SafeRTOS.com - A version that is certified for use in safety | |
critical systems. | |
http://www.OpenRTOS.com - Commercial support, development, porting, | |
licensing and training services. | |
*/ | |
/* | |
* Tests the behaviour when data is peeked from a queue when there are | |
* multiple tasks blocked on the queue. | |
*/ | |
#include <stdlib.h> | |
/* Scheduler include files. */ | |
#include "FreeRTOS.h" | |
#include "task.h" | |
#include "queue.h" | |
#include "semphr.h" | |
/* Demo program include files. */ | |
#include "QPeek.h" | |
#define qpeekQUEUE_LENGTH ( 5 ) | |
#define qpeekNO_BLOCK ( 0 ) | |
#define qpeekSHORT_DELAY ( 10 ) | |
#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 ) | |
#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 ) | |
#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 ) | |
#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 ) | |
/*-----------------------------------------------------------*/ | |
/* | |
* The following three tasks are used to demonstrate the peeking behaviour. | |
* Each task is given a different priority to demonstrate the order in which | |
* tasks are woken as data is peeked from a queue. | |
*/ | |
static void prvLowPriorityPeekTask( void *pvParameters ); | |
static void prvMediumPriorityPeekTask( void *pvParameters ); | |
static void prvHighPriorityPeekTask( void *pvParameters ); | |
static void prvHighestPriorityPeekTask( void *pvParameters ); | |
/*-----------------------------------------------------------*/ | |
/* Flag that will be latched to pdTRUE should any unexpected behaviour be | |
detected in any of the tasks. */ | |
static volatile portBASE_TYPE xErrorDetected = pdFALSE; | |
/* 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. */ | |
static volatile unsigned portLONG ulLoopCounter = 0; | |
/* Handles to the test tasks. */ | |
xTaskHandle xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask; | |
/*-----------------------------------------------------------*/ | |
void vStartQueuePeekTasks( void ) | |
{ | |
xQueueHandle xQueue; | |
/* Create the queue that we are going to use for the test/demo. */ | |
xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( unsigned portLONG ) ); | |
/* vQueueAddToRegistry() adds the queue to the queue registry, if one 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 | |
is not being used. The call to vQueueAddToRegistry() will be removed | |
by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is | |
defined to be less than 1. */ | |
vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "QPeek_Test_Queue" ); | |
/* 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 | |
on the stack here. */ | |
xTaskCreate( prvLowPriorityPeekTask, ( signed portCHAR * )"PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL ); | |
xTaskCreate( prvMediumPriorityPeekTask, ( signed portCHAR * )"PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask ); | |
xTaskCreate( prvHighPriorityPeekTask, ( signed portCHAR * )"PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask ); | |
xTaskCreate( prvHighestPriorityPeekTask, ( signed portCHAR * )"PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask ); | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvHighestPriorityPeekTask( void *pvParameters ) | |
{ | |
xQueueHandle xQueue = ( xQueueHandle ) pvParameters; | |
unsigned portLONG ulValue; | |
#ifdef USE_STDIO | |
{ | |
void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend ); | |
const portCHAR * const pcTaskStartMsg = "Queue peek test started.\r\n"; | |
/* Queue a message for printing to say the task has started. */ | |
vPrintDisplayMessage( &pcTaskStartMsg ); | |
} | |
#endif | |
for( ;; ) | |
{ | |
/* Try peeking from the queue. The queue should be empty so we will | |
block, allowing the high priority task to execute. */ | |
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) | |
{ | |
/* We expected to have received something by the time we unblock. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* When we reach here the high and medium priority tasks should still | |
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 | |
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 | |
yet executed. */ | |
if( ulValue != 0x11223344 ) | |
{ | |
/* We did not receive the expected value. */ | |
xErrorDetected = pdTRUE; | |
} | |
if( uxQueueMessagesWaiting( xQueue ) != 1 ) | |
{ | |
/* The message should have been left on the queue. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* 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 | |
blocked state. */ | |
ulValue = 0; | |
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) | |
{ | |
/* We expected to receive the value. */ | |
xErrorDetected = pdTRUE; | |
} | |
if( ulValue != 0x11223344 ) | |
{ | |
/* We did not receive the expected value - which should have been | |
the same value as was peeked. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* Now we will block again as the queue is once more empty. The low | |
priority task can then execute again. */ | |
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) | |
{ | |
/* We expected to have received something by the time we unblock. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* When we get here the low priority task should have again written to the | |
queue. */ | |
if( ulValue != 0x01234567 ) | |
{ | |
/* We did not receive the expected value. */ | |
xErrorDetected = pdTRUE; | |
} | |
if( uxQueueMessagesWaiting( xQueue ) != 1 ) | |
{ | |
/* The message should have been left on the queue. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* We only peeked the data, so suspending ourselves now should enable | |
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 | |
in the queue. */ | |
vTaskSuspend( NULL ); | |
/* 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. | |
This means that the medium priority task should never peek the value. */ | |
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) | |
{ | |
xErrorDetected = pdTRUE; | |
} | |
if( ulValue != 0xaabbaabb ) | |
{ | |
xErrorDetected = pdTRUE; | |
} | |
vTaskSuspend( NULL ); | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvHighPriorityPeekTask( void *pvParameters ) | |
{ | |
xQueueHandle xQueue = ( xQueueHandle ) pvParameters; | |
unsigned portLONG ulValue; | |
for( ;; ) | |
{ | |
/* Try peeking from the queue. The queue should be empty so we will | |
block, allowing the medium priority task to execute. Both the high | |
and highest priority tasks will then be blocked on the queue. */ | |
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) | |
{ | |
/* We expected to have received something by the time we unblock. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* When we get here the highest priority task should have peeked the data | |
(unblocking this task) then suspended (allowing this task to also peek | |
the data). */ | |
if( ulValue != 0x01234567 ) | |
{ | |
/* We did not receive the expected value. */ | |
xErrorDetected = pdTRUE; | |
} | |
if( uxQueueMessagesWaiting( xQueue ) != 1 ) | |
{ | |
/* The message should have been left on the queue. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* We only peeked the data, so suspending ourselves now should enable | |
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 | |
in the queue. */ | |
vTaskSuspend( NULL ); | |
/* 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. */ | |
if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) | |
{ | |
xErrorDetected = pdTRUE; | |
} | |
if( ulValue != 0xaabbaabb ) | |
{ | |
xErrorDetected = pdTRUE; | |
} | |
vTaskSuspend( NULL ); | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvMediumPriorityPeekTask( void *pvParameters ) | |
{ | |
xQueueHandle xQueue = ( xQueueHandle ) pvParameters; | |
unsigned portLONG ulValue; | |
for( ;; ) | |
{ | |
/* Try peeking from the queue. The queue should be empty so we will | |
block, allowing the low priority task to execute. The highest, high | |
and medium priority tasks will then all be blocked on the queue. */ | |
if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS ) | |
{ | |
/* We expected to have received something by the time we unblock. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* When we get here the high priority task should have peeked the data | |
(unblocking this task) then suspended (allowing this task to also peek | |
the data). */ | |
if( ulValue != 0x01234567 ) | |
{ | |
/* We did not receive the expected value. */ | |
xErrorDetected = pdTRUE; | |
} | |
if( uxQueueMessagesWaiting( xQueue ) != 1 ) | |
{ | |
/* The message should have been left on the queue. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* Just so we know the test is still running. */ | |
ulLoopCounter++; | |
/* Now we can suspend ourselves so the low priority task can execute | |
again. */ | |
vTaskSuspend( NULL ); | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
static void prvLowPriorityPeekTask( void *pvParameters ) | |
{ | |
xQueueHandle xQueue = ( xQueueHandle ) pvParameters; | |
unsigned portLONG ulValue; | |
for( ;; ) | |
{ | |
/* Write some data to the queue. This should unblock the highest | |
priority task that is waiting to peek data from the queue. */ | |
ulValue = 0x11223344; | |
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) | |
{ | |
/* We were expecting the queue to be empty so we should not of | |
had a problem writing to the queue. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* By the time we get here the data should have been removed from | |
the queue. */ | |
if( uxQueueMessagesWaiting( xQueue ) != 0 ) | |
{ | |
xErrorDetected = pdTRUE; | |
} | |
/* Write another value to the queue, again waking the highest priority | |
task that is blocked on the queue. */ | |
ulValue = 0x01234567; | |
if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) | |
{ | |
/* We were expecting the queue to be empty so we should not of | |
had a problem writing to the queue. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* 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. */ | |
ulValue = 0; | |
if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) | |
{ | |
/* We expected to receive the data. */ | |
xErrorDetected = pdTRUE; | |
} | |
if( ulValue != 0x01234567 ) | |
{ | |
/* We did not receive the expected value. */ | |
} | |
/* Lets just delay a while as this is an intensive test as we don't | |
want to starve other tests of processing time. */ | |
vTaskDelay( qpeekSHORT_DELAY ); | |
/* 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 | |
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 | |
makes no difference to the result. */ | |
vTaskResume( xMediumPriorityTask ); | |
vTaskResume( xHighPriorityTask ); | |
vTaskResume( xHighestPriorityTask ); | |
ulValue = 0xaabbaabb; | |
if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS ) | |
{ | |
/* We were expecting the queue to be empty so we should not of | |
had a problem writing to the queue. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* This time we should find that the queue is empty. The high priority | |
task actually removed the data rather than just peeking it. */ | |
if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY ) | |
{ | |
/* We expected to receive the data. */ | |
xErrorDetected = pdTRUE; | |
} | |
/* Unsuspend the highest and high priority tasks so we can go back | |
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. */ | |
vTaskResume( xHighPriorityTask ); | |
vTaskResume( xHighestPriorityTask ); | |
/* Lets just delay a while as this is an intensive test as we don't | |
want to starve other tests of processing time. */ | |
vTaskDelay( qpeekSHORT_DELAY ); | |
} | |
} | |
/*-----------------------------------------------------------*/ | |
/* This is called to check that all the created tasks are still running. */ | |
portBASE_TYPE xAreQueuePeekTasksStillRunning( void ) | |
{ | |
static unsigned portLONG ulLastLoopCounter = 0; | |
/* If the demo task is still running then we expect the loopcounter to | |
have incremented since this function was last called. */ | |
if( ulLastLoopCounter == ulLoopCounter ) | |
{ | |
xErrorDetected = pdTRUE; | |
} | |
ulLastLoopCounter = ulLoopCounter; | |
/* Errors detected in the task itself will have latched xErrorDetected | |
to true. */ | |
return !xErrorDetected; | |
} | |