FreeRTOS Real Time Operating System, Modified from Kenji Arai's initial port. See freertos.org for full documentation.

Fork of FreeRTOS_on_mbed_v1 by Kenji Arai

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BlockQ.c Source File

BlockQ.c

00001 /*
00002     FreeRTOS V6.0.3 - Copyright (C) 2010 Real Time Engineers Ltd.
00003 
00004     ***************************************************************************
00005     *                                                                         *
00006     * If you are:                                                             *
00007     *                                                                         *
00008     *    + New to FreeRTOS,                                                   *
00009     *    + Wanting to learn FreeRTOS or multitasking in general quickly       *
00010     *    + Looking for basic training,                                        *
00011     *    + Wanting to improve your FreeRTOS skills and productivity           *
00012     *                                                                         *
00013     * then take a look at the FreeRTOS eBook                                  *
00014     *                                                                         *
00015     *        "Using the FreeRTOS Real Time Kernel - a Practical Guide"        *
00016     *                  http://www.FreeRTOS.org/Documentation                  *
00017     *                                                                         *
00018     * A pdf reference manual is also available.  Both are usually delivered   *
00019     * to your inbox within 20 minutes to two hours when purchased between 8am *
00020     * and 8pm GMT (although please allow up to 24 hours in case of            *
00021     * exceptional circumstances).  Thank you for your support!                *
00022     *                                                                         *
00023     ***************************************************************************
00024 
00025     This file is part of the FreeRTOS distribution.
00026 
00027     FreeRTOS is free software; you can redistribute it and/or modify it under
00028     the terms of the GNU General Public License (version 2) as published by the
00029     Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
00030     ***NOTE*** The exception to the GPL is included to allow you to distribute
00031     a combined work that includes FreeRTOS without being obliged to provide the
00032     source code for proprietary components outside of the FreeRTOS kernel.
00033     FreeRTOS is distributed in the hope that it will be useful, but WITHOUT
00034     ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00035     FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
00036     more details. You should have received a copy of the GNU General Public 
00037     License and the FreeRTOS license exception along with FreeRTOS; if not it 
00038     can be viewed here: http://www.freertos.org/a00114.html and also obtained 
00039     by writing to Richard Barry, contact details for whom are available on the
00040     FreeRTOS WEB site.
00041 
00042     1 tab == 4 spaces!
00043 
00044     http://www.FreeRTOS.org - Documentation, latest information, license and
00045     contact details.
00046 
00047     http://www.SafeRTOS.com - A version that is certified for use in safety
00048     critical systems.
00049 
00050     http://www.OpenRTOS.com - Commercial support, development, porting,
00051     licensing and training services.
00052 */
00053 
00054 /*
00055  * Creates six tasks that operate on three queues as follows:
00056  *
00057  * The first two tasks send and receive an incrementing number to/from a queue.
00058  * One task acts as a producer and the other as the consumer.  The consumer is a
00059  * higher priority than the producer and is set to block on queue reads.  The queue
00060  * only has space for one item - as soon as the producer posts a message on the
00061  * queue the consumer will unblock, pre-empt the producer, and remove the item.
00062  *
00063  * The second two tasks work the other way around.  Again the queue used only has
00064  * enough space for one item.  This time the consumer has a lower priority than the
00065  * producer.  The producer will try to post on the queue blocking when the queue is
00066  * full.  When the consumer wakes it will remove the item from the queue, causing
00067  * the producer to unblock, pre-empt the consumer, and immediately re-fill the
00068  * queue.
00069  *
00070  * The last two tasks use the same queue producer and consumer functions.  This time the queue has
00071  * enough space for lots of items and the tasks operate at the same priority.  The
00072  * producer will execute, placing items into the queue.  The consumer will start
00073  * executing when either the queue becomes full (causing the producer to block) or
00074  * a context switch occurs (tasks of the same priority will time slice).
00075  *
00076  */
00077 
00078 /*
00079 
00080 Changes from V4.1.1
00081 
00082     + The second set of tasks were created the wrong way around.  This has been
00083       corrected.
00084 */
00085 
00086 
00087 #include <stdlib.h>
00088 
00089 /* Scheduler include files. */
00090 #include "FreeRTOS.h"
00091 #include "task.h"
00092 #include "queue.h"
00093 
00094 /* Demo program include files. */
00095 #include "BlockQ.h"
00096 
00097 #define blckqSTACK_SIZE        configMINIMAL_STACK_SIZE
00098 #define blckqNUM_TASK_SETS    ( 3 )
00099 
00100 /* Structure used to pass parameters to the blocking queue tasks. */
00101 typedef struct BLOCKING_QUEUE_PARAMETERS
00102 {
00103     xQueueHandle xQueue;                    /*< The queue to be used by the task. */
00104     portTickType xBlockTime;                /*< The block time to use on queue reads/writes. */
00105     volatile short *psCheckVariable;    /*< Incremented on each successful cycle to check the task is still running. */
00106 } xBlockingQueueParameters;
00107 
00108 /* Task function that creates an incrementing number and posts it on a queue. */
00109 static portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
00110 
00111 /* Task function that removes the incrementing number from a queue and checks that
00112 it is the expected number. */
00113 static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, pvParameters );
00114 
00115 /* Variables which are incremented each time an item is removed from a queue, and
00116 found to be the expected value.
00117 These are used to check that the tasks are still running. */
00118 static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };
00119 
00120 /* Variable which are incremented each time an item is posted on a queue.   These
00121 are used to check that the tasks are still running. */
00122 static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };
00123 
00124 /*-----------------------------------------------------------*/
00125 
00126 void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
00127 {
00128 xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2;
00129 xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4;
00130 xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6;
00131 const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
00132 const portTickType xBlockTime = ( portTickType ) 1000 / portTICK_RATE_MS;
00133 const portTickType xDontBlock = ( portTickType ) 0;
00134 
00135     /* Create the first two tasks as described at the top of the file. */
00136     
00137     /* First create the structure used to pass parameters to the consumer tasks. */
00138     pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
00139 
00140     /* Create the queue used by the first two tasks to pass the incrementing number.
00141     Pass a pointer to the queue in the parameter structure. */
00142     pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
00143 
00144     /* The consumer is created first so gets a block time as described above. */
00145     pxQueueParameters1->xBlockTime = xBlockTime;
00146 
00147     /* Pass in the variable that this task is going to increment so we can check it
00148     is still running. */
00149     pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
00150         
00151     /* Create the structure used to pass parameters to the producer task. */
00152     pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
00153 
00154     /* Pass the queue to this task also, using the parameter structure. */
00155     pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
00156 
00157     /* The producer is not going to block - as soon as it posts the consumer will
00158     wake and remove the item so the producer should always have room to post. */
00159     pxQueueParameters2->xBlockTime = xDontBlock;
00160 
00161     /* Pass in the variable that this task is going to increment so we can check
00162     it is still running. */
00163     pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
00164 
00165 
00166     /* Note the producer has a lower priority than the consumer when the tasks are
00167     spawned. */
00168     xTaskCreate( vBlockingQueueConsumer, ( signed char * ) "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
00169     xTaskCreate( vBlockingQueueProducer, ( signed char * ) "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
00170 
00171     
00172 
00173     /* Create the second two tasks as described at the top of the file.   This uses
00174     the same mechanism but reverses the task priorities. */
00175 
00176     pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
00177     pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
00178     pxQueueParameters3->xBlockTime = xDontBlock;
00179     pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
00180 
00181     pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
00182     pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
00183     pxQueueParameters4->xBlockTime = xBlockTime;
00184     pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
00185 
00186     xTaskCreate( vBlockingQueueConsumer, ( signed char * ) "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
00187     xTaskCreate( vBlockingQueueProducer, ( signed char * ) "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
00188 
00189 
00190 
00191     /* Create the last two tasks as described above.  The mechanism is again just
00192     the same.  This time both parameter structures are given a block time. */
00193     pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
00194     pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
00195     pxQueueParameters5->xBlockTime = xBlockTime;
00196     pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
00197 
00198     pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
00199     pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
00200     pxQueueParameters6->xBlockTime = xBlockTime;
00201     pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );    
00202 
00203     xTaskCreate( vBlockingQueueProducer, ( signed char * ) "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
00204     xTaskCreate( vBlockingQueueConsumer, ( signed char * ) "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
00205 }
00206 /*-----------------------------------------------------------*/
00207 
00208 static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )
00209 {
00210 unsigned short usValue = 0;
00211 xBlockingQueueParameters *pxQueueParameters;
00212 short sErrorEverOccurred = pdFALSE;
00213 
00214     pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
00215 
00216     for( ;; )
00217     {        
00218         if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
00219         {
00220             sErrorEverOccurred = pdTRUE;
00221         }
00222         else
00223         {
00224             /* We have successfully posted a message, so increment the variable
00225             used to check we are still running. */
00226             if( sErrorEverOccurred == pdFALSE )
00227             {
00228                 ( *pxQueueParameters->psCheckVariable )++;
00229             }
00230 
00231             /* Increment the variable we are going to post next time round.  The
00232             consumer will expect the numbers to    follow in numerical order. */
00233             ++usValue;
00234         }
00235     }
00236 }
00237 /*-----------------------------------------------------------*/
00238 
00239 static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
00240 {
00241 unsigned short usData, usExpectedValue = 0;
00242 xBlockingQueueParameters *pxQueueParameters;
00243 short sErrorEverOccurred = pdFALSE;
00244 
00245     pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
00246 
00247     for( ;; )
00248     {    
00249         if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
00250         {
00251             if( usData != usExpectedValue )
00252             {
00253                 /* Catch-up. */
00254                 usExpectedValue = usData;
00255 
00256                 sErrorEverOccurred = pdTRUE;
00257             }
00258             else
00259             {
00260                 /* We have successfully received a message, so increment the
00261                 variable used to check we are still running. */    
00262                 if( sErrorEverOccurred == pdFALSE )
00263                 {
00264                     ( *pxQueueParameters->psCheckVariable )++;
00265                 }
00266                             
00267                 /* Increment the value we expect to remove from the queue next time
00268                 round. */
00269                 ++usExpectedValue;
00270             }            
00271         }        
00272     }
00273 }
00274 /*-----------------------------------------------------------*/
00275 
00276 /* This is called to check that all the created tasks are still running. */
00277 portBASE_TYPE xAreBlockingQueuesStillRunning( void )
00278 {
00279 static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };
00280 static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };
00281 portBASE_TYPE xReturn = pdPASS, xTasks;
00282 
00283     /* Not too worried about mutual exclusion on these variables as they are 16
00284     bits and we are only reading them. We also only care to see if they have
00285     changed or not.
00286     
00287     Loop through each check variable to and return pdFALSE if any are found not
00288     to have changed since the last call. */
00289 
00290     for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
00291     {
00292         if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ]  )
00293         {
00294             xReturn = pdFALSE;
00295         }
00296         sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
00297 
00298 
00299         if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ]  )
00300         {
00301             xReturn = pdFALSE;
00302         }
00303         sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
00304     }
00305 
00306     return xReturn;
00307 }
00308