2 FreeRTOS V7.0.1 - Copyright (C) 2011 Real Time Engineers Ltd.
\r
5 ***************************************************************************
\r
7 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
8 * Complete, revised, and edited pdf reference manuals are also *
\r
11 * Purchasing FreeRTOS documentation will not only help you, by *
\r
12 * ensuring you get running as quickly as possible and with an *
\r
13 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
14 * the FreeRTOS project to continue with its mission of providing *
\r
15 * professional grade, cross platform, de facto standard solutions *
\r
16 * for microcontrollers - completely free of charge! *
\r
18 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
20 * Thank you for using FreeRTOS, and thank you for your support! *
\r
22 ***************************************************************************
\r
25 This file is part of the FreeRTOS distribution.
\r
27 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
28 the terms of the GNU General Public License (version 2) as published by the
\r
29 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
30 >>>NOTE<<< The modification to the GPL is included to allow you to
\r
31 distribute a combined work that includes FreeRTOS without being obliged to
\r
32 provide the source code for proprietary components outside of the FreeRTOS
\r
33 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
34 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
35 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
36 more details. You should have received a copy of the GNU General Public
\r
37 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
38 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
39 by writing to Richard Barry, contact details for whom are available on the
\r
44 http://www.FreeRTOS.org - Documentation, latest information, license and
\r
47 http://www.SafeRTOS.com - A version that is certified for use in safety
\r
50 http://www.OpenRTOS.com - Commercial support, development, porting,
\r
51 licensing and training services.
\r
55 * This file contains some test scenarios that ensure tasks do not exit queue
\r
56 * send or receive functions prematurely. A description of the tests is
\r
57 * included within the code.
\r
60 /* Kernel includes. */
\r
61 #include "FreeRTOS.h"
\r
65 /* Demo includes. */
\r
66 #include "blocktim.h"
\r
68 /* Task priorities. Allow these to be overridden. */
\r
69 #ifndef bktPRIMARY_PRIORITY
\r
70 #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
\r
73 #ifndef bktSECONDARY_PRIORITY
\r
74 #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
\r
77 /* Task behaviour. */
\r
78 #define bktQUEUE_LENGTH ( 5 )
\r
79 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
80 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
81 #define bktALLOWABLE_MARGIN ( 15 )
\r
82 #define bktTIME_TO_BLOCK ( 175 )
\r
83 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
84 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
86 /* The queue on which the tasks block. */
\r
87 static xQueueHandle xTestQueue;
\r
89 /* Handle to the secondary task is required by the primary task for calls
\r
90 to vTaskSuspend/Resume(). */
\r
91 static xTaskHandle xSecondary;
\r
93 /* Used to ensure that tasks are still executing without error. */
\r
94 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
95 static volatile portBASE_TYPE xErrorOccurred = pdFALSE;
\r
97 /* Provides a simple mechanism for the primary task to know when the
\r
98 secondary task has executed. */
\r
99 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
101 /* The two test tasks. Their behaviour is commented within the files. */
\r
102 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
103 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
105 /*-----------------------------------------------------------*/
\r
107 void vCreateBlockTimeTasks( void )
\r
109 /* Create the queue on which the two tasks block. */
\r
110 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
112 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
113 in use. The queue registry is provided as a means for kernel aware
\r
114 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
115 is not being used. The call to vQueueAddToRegistry() will be removed
\r
116 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
117 defined to be less than 1. */
\r
118 vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );
\r
120 /* Create the two test tasks. */
\r
121 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed char * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
122 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed char * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
124 /*-----------------------------------------------------------*/
\r
126 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
128 portBASE_TYPE xItem, xData;
\r
129 portTickType xTimeWhenBlocking;
\r
130 portTickType xTimeToBlock, xBlockedTime;
\r
132 ( void ) pvParameters;
\r
136 /*********************************************************************
\r
139 Simple block time wakeup test on queue receives. */
\r
140 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
142 /* The queue is empty. Attempt to read from the queue using a block
\r
143 time. When we wake, ensure the delta in time is as expected. */
\r
144 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
146 xTimeWhenBlocking = xTaskGetTickCount();
\r
148 /* We should unblock after xTimeToBlock having not received
\r
149 anything on the queue. */
\r
150 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
152 xErrorOccurred = pdTRUE;
\r
155 /* How long were we blocked for? */
\r
156 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
158 if( xBlockedTime < xTimeToBlock )
\r
160 /* Should not have blocked for less than we requested. */
\r
161 xErrorOccurred = pdTRUE;
\r
164 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
166 /* Should not have blocked for longer than we requested,
\r
167 although we would not necessarily run as soon as we were
\r
168 unblocked so a margin is allowed. */
\r
169 xErrorOccurred = pdTRUE;
\r
173 /*********************************************************************
\r
176 Simple block time wakeup test on queue sends.
\r
178 First fill the queue. It should be empty so all sends should pass. */
\r
179 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
181 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
183 xErrorOccurred = pdTRUE;
\r
186 #if configUSE_PREEMPTION == 0
\r
191 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
193 /* The queue is full. Attempt to write to the queue using a block
\r
194 time. When we wake, ensure the delta in time is as expected. */
\r
195 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
197 xTimeWhenBlocking = xTaskGetTickCount();
\r
199 /* We should unblock after xTimeToBlock having not received
\r
200 anything on the queue. */
\r
201 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
203 xErrorOccurred = pdTRUE;
\r
206 /* How long were we blocked for? */
\r
207 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
209 if( xBlockedTime < xTimeToBlock )
\r
211 /* Should not have blocked for less than we requested. */
\r
212 xErrorOccurred = pdTRUE;
\r
215 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
217 /* Should not have blocked for longer than we requested,
\r
218 although we would not necessarily run as soon as we were
\r
219 unblocked so a margin is allowed. */
\r
220 xErrorOccurred = pdTRUE;
\r
224 /*********************************************************************
\r
227 Wake the other task, it will block attempting to post to the queue.
\r
228 When we read from the queue the other task will wake, but before it
\r
229 can run we will post to the queue again. When the other task runs it
\r
230 will find the queue still full, even though it was woken. It should
\r
231 recognise that its block time has not expired and return to block for
\r
232 the remains of its block time.
\r
234 Wake the other task so it blocks attempting to post to the already
\r
237 vTaskResume( xSecondary );
\r
239 /* We need to wait a little to ensure the other task executes. */
\r
240 while( xRunIndicator != bktRUN_INDICATOR )
\r
242 /* The other task has not yet executed. */
\r
243 vTaskDelay( bktSHORT_WAIT );
\r
245 /* Make sure the other task is blocked on the queue. */
\r
246 vTaskDelay( bktSHORT_WAIT );
\r
249 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
251 /* Now when we make space on the queue the other task should wake
\r
252 but not execute as this task has higher priority. */
\r
253 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
255 xErrorOccurred = pdTRUE;
\r
258 /* Now fill the queue again before the other task gets a chance to
\r
259 execute. If the other task had executed we would find the queue
\r
260 full ourselves, and the other task have set xRunIndicator. */
\r
261 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
263 xErrorOccurred = pdTRUE;
\r
266 if( xRunIndicator == bktRUN_INDICATOR )
\r
268 /* The other task should not have executed. */
\r
269 xErrorOccurred = pdTRUE;
\r
272 /* Raise the priority of the other task so it executes and blocks
\r
273 on the queue again. */
\r
274 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
276 /* The other task should now have re-blocked without exiting the
\r
278 if( xRunIndicator == bktRUN_INDICATOR )
\r
280 /* The other task should not have executed outside of the
\r
282 xErrorOccurred = pdTRUE;
\r
285 /* Set the priority back down. */
\r
286 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
289 /* Let the other task timeout. When it unblockes it will check that it
\r
290 unblocked at the correct time, then suspend itself. */
\r
291 while( xRunIndicator != bktRUN_INDICATOR )
\r
293 vTaskDelay( bktSHORT_WAIT );
\r
295 vTaskDelay( bktSHORT_WAIT );
\r
299 /*********************************************************************
\r
302 As per test 3 - but with the send and receive the other way around.
\r
303 The other task blocks attempting to read from the queue.
\r
305 Empty the queue. We should find that it is full. */
\r
306 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
308 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
310 xErrorOccurred = pdTRUE;
\r
314 /* Wake the other task so it blocks attempting to read from the
\r
315 already empty queue. */
\r
316 vTaskResume( xSecondary );
\r
318 /* We need to wait a little to ensure the other task executes. */
\r
319 while( xRunIndicator != bktRUN_INDICATOR )
\r
321 vTaskDelay( bktSHORT_WAIT );
\r
323 vTaskDelay( bktSHORT_WAIT );
\r
326 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
328 /* Now when we place an item on the queue the other task should
\r
329 wake but not execute as this task has higher priority. */
\r
330 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
332 xErrorOccurred = pdTRUE;
\r
335 /* Now empty the queue again before the other task gets a chance to
\r
336 execute. If the other task had executed we would find the queue
\r
337 empty ourselves, and the other task would be suspended. */
\r
338 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
340 xErrorOccurred = pdTRUE;
\r
343 if( xRunIndicator == bktRUN_INDICATOR )
\r
345 /* The other task should not have executed. */
\r
346 xErrorOccurred = pdTRUE;
\r
349 /* Raise the priority of the other task so it executes and blocks
\r
350 on the queue again. */
\r
351 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
353 /* The other task should now have re-blocked without exiting the
\r
355 if( xRunIndicator == bktRUN_INDICATOR )
\r
357 /* The other task should not have executed outside of the
\r
359 xErrorOccurred = pdTRUE;
\r
361 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
364 /* Let the other task timeout. When it unblockes it will check that it
\r
365 unblocked at the correct time, then suspend itself. */
\r
366 while( xRunIndicator != bktRUN_INDICATOR )
\r
368 vTaskDelay( bktSHORT_WAIT );
\r
370 vTaskDelay( bktSHORT_WAIT );
\r
375 /*-----------------------------------------------------------*/
\r
377 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
379 portTickType xTimeWhenBlocking, xBlockedTime;
\r
380 portBASE_TYPE xData;
\r
382 ( void ) pvParameters;
\r
386 /*********************************************************************
\r
389 This task does does not participate in these tests. */
\r
390 vTaskSuspend( NULL );
\r
392 /*********************************************************************
\r
395 The first thing we do is attempt to read from the queue. It should be
\r
396 full so we block. Note the time before we block so we can check the
\r
397 wake time is as per that expected. */
\r
398 xTimeWhenBlocking = xTaskGetTickCount();
\r
400 /* We should unblock after bktTIME_TO_BLOCK having not sent
\r
401 anything to the queue. */
\r
403 xRunIndicator = bktRUN_INDICATOR;
\r
404 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
406 xErrorOccurred = pdTRUE;
\r
409 /* How long were we inside the send function? */
\r
410 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
412 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
413 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
415 xErrorOccurred = pdTRUE;
\r
418 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
419 either. A margin is permitted as we would not necessarily run as
\r
420 soon as we unblocked. */
\r
421 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
423 xErrorOccurred = pdTRUE;
\r
426 /* Suspend ready for test 3. */
\r
427 xRunIndicator = bktRUN_INDICATOR;
\r
428 vTaskSuspend( NULL );
\r
430 /*********************************************************************
\r
433 As per test three, but with the send and receive reversed. */
\r
434 xTimeWhenBlocking = xTaskGetTickCount();
\r
436 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
437 anything on the queue. */
\r
438 xRunIndicator = bktRUN_INDICATOR;
\r
439 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
441 xErrorOccurred = pdTRUE;
\r
444 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
446 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
447 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
449 xErrorOccurred = pdTRUE;
\r
452 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
453 either. A margin is permitted as we would not necessarily run as soon
\r
454 as we unblocked. */
\r
455 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
457 xErrorOccurred = pdTRUE;
\r
460 xRunIndicator = bktRUN_INDICATOR;
\r
462 xSecondaryCycles++;
\r
465 /*-----------------------------------------------------------*/
\r
467 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
\r
469 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
470 portBASE_TYPE xReturn = pdPASS;
\r
472 /* Have both tasks performed at least one cycle since this function was
\r
474 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
479 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
484 if( xErrorOccurred == pdTRUE )
\r
489 xLastSecondaryCycleCount = xSecondaryCycles;
\r
490 xLastPrimaryCycleCount = xPrimaryCycles;
\r