2 FreeRTOS V7.1.1 - Copyright (C) 2012 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 ***************************************************************************
\r
46 * Having a problem? Start by reading the FAQ "My application does *
\r
47 * not run, what could be wrong? *
\r
49 * http://www.FreeRTOS.org/FAQHelp.html *
\r
51 ***************************************************************************
\r
54 http://www.FreeRTOS.org - Documentation, training, latest information,
\r
55 license and contact details.
\r
57 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
58 including FreeRTOS+Trace - an indispensable productivity tool.
\r
60 Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell
\r
61 the code with commercial support, indemnification, and middleware, under
\r
62 the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also
\r
63 provide a safety engineered and independently SIL3 certified version under
\r
64 the SafeRTOS brand: http://www.SafeRTOS.com.
\r
68 * This file contains some test scenarios that ensure tasks do not exit queue
\r
69 * send or receive functions prematurely. A description of the tests is
\r
70 * included within the code.
\r
73 /* Kernel includes. */
\r
74 #include "FreeRTOS.h"
\r
78 /* Demo includes. */
\r
79 #include "blocktim.h"
\r
81 /* Task priorities. Allow these to be overridden. */
\r
82 #ifndef bktPRIMARY_PRIORITY
\r
83 #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
\r
86 #ifndef bktSECONDARY_PRIORITY
\r
87 #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
\r
90 /* Task behaviour. */
\r
91 #define bktQUEUE_LENGTH ( 5 )
\r
92 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
93 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
94 #define bktALLOWABLE_MARGIN ( 15 )
\r
95 #define bktTIME_TO_BLOCK ( 175 )
\r
96 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
97 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
99 /* The queue on which the tasks block. */
\r
100 static xQueueHandle xTestQueue;
\r
102 /* Handle to the secondary task is required by the primary task for calls
\r
103 to vTaskSuspend/Resume(). */
\r
104 static xTaskHandle xSecondary;
\r
106 /* Used to ensure that tasks are still executing without error. */
\r
107 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
108 static volatile portBASE_TYPE xErrorOccurred = pdFALSE;
\r
110 /* Provides a simple mechanism for the primary task to know when the
\r
111 secondary task has executed. */
\r
112 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
114 /* The two test tasks. Their behaviour is commented within the files. */
\r
115 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
116 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
118 /*-----------------------------------------------------------*/
\r
120 void vCreateBlockTimeTasks( void )
\r
122 /* Create the queue on which the two tasks block. */
\r
123 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
125 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
126 in use. The queue registry is provided as a means for kernel aware
\r
127 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
128 is not being used. The call to vQueueAddToRegistry() will be removed
\r
129 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
130 defined to be less than 1. */
\r
131 vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );
\r
133 /* Create the two test tasks. */
\r
134 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed char * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
135 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed char * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
137 /*-----------------------------------------------------------*/
\r
139 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
141 portBASE_TYPE xItem, xData;
\r
142 portTickType xTimeWhenBlocking;
\r
143 portTickType xTimeToBlock, xBlockedTime;
\r
145 ( void ) pvParameters;
\r
149 /*********************************************************************
\r
152 Simple block time wakeup test on queue receives. */
\r
153 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
155 /* The queue is empty. Attempt to read from the queue using a block
\r
156 time. When we wake, ensure the delta in time is as expected. */
\r
157 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
159 xTimeWhenBlocking = xTaskGetTickCount();
\r
161 /* We should unblock after xTimeToBlock having not received
\r
162 anything on the queue. */
\r
163 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
165 xErrorOccurred = pdTRUE;
\r
168 /* How long were we blocked for? */
\r
169 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
171 if( xBlockedTime < xTimeToBlock )
\r
173 /* Should not have blocked for less than we requested. */
\r
174 xErrorOccurred = pdTRUE;
\r
177 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
179 /* Should not have blocked for longer than we requested,
\r
180 although we would not necessarily run as soon as we were
\r
181 unblocked so a margin is allowed. */
\r
182 xErrorOccurred = pdTRUE;
\r
186 /*********************************************************************
\r
189 Simple block time wakeup test on queue sends.
\r
191 First fill the queue. It should be empty so all sends should pass. */
\r
192 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
194 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
196 xErrorOccurred = pdTRUE;
\r
199 #if configUSE_PREEMPTION == 0
\r
204 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
206 /* The queue is full. Attempt to write to the queue using a block
\r
207 time. When we wake, ensure the delta in time is as expected. */
\r
208 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
210 xTimeWhenBlocking = xTaskGetTickCount();
\r
212 /* We should unblock after xTimeToBlock having not received
\r
213 anything on the queue. */
\r
214 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
216 xErrorOccurred = pdTRUE;
\r
219 /* How long were we blocked for? */
\r
220 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
222 if( xBlockedTime < xTimeToBlock )
\r
224 /* Should not have blocked for less than we requested. */
\r
225 xErrorOccurred = pdTRUE;
\r
228 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
230 /* Should not have blocked for longer than we requested,
\r
231 although we would not necessarily run as soon as we were
\r
232 unblocked so a margin is allowed. */
\r
233 xErrorOccurred = pdTRUE;
\r
237 /*********************************************************************
\r
240 Wake the other task, it will block attempting to post to the queue.
\r
241 When we read from the queue the other task will wake, but before it
\r
242 can run we will post to the queue again. When the other task runs it
\r
243 will find the queue still full, even though it was woken. It should
\r
244 recognise that its block time has not expired and return to block for
\r
245 the remains of its block time.
\r
247 Wake the other task so it blocks attempting to post to the already
\r
250 vTaskResume( xSecondary );
\r
252 /* We need to wait a little to ensure the other task executes. */
\r
253 while( xRunIndicator != bktRUN_INDICATOR )
\r
255 /* The other task has not yet executed. */
\r
256 vTaskDelay( bktSHORT_WAIT );
\r
258 /* Make sure the other task is blocked on the queue. */
\r
259 vTaskDelay( bktSHORT_WAIT );
\r
262 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
264 /* Now when we make space on the queue the other task should wake
\r
265 but not execute as this task has higher priority. */
\r
266 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
268 xErrorOccurred = pdTRUE;
\r
271 /* Now fill the queue again before the other task gets a chance to
\r
272 execute. If the other task had executed we would find the queue
\r
273 full ourselves, and the other task have set xRunIndicator. */
\r
274 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
276 xErrorOccurred = pdTRUE;
\r
279 if( xRunIndicator == bktRUN_INDICATOR )
\r
281 /* The other task should not have executed. */
\r
282 xErrorOccurred = pdTRUE;
\r
285 /* Raise the priority of the other task so it executes and blocks
\r
286 on the queue again. */
\r
287 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
289 /* The other task should now have re-blocked without exiting the
\r
291 if( xRunIndicator == bktRUN_INDICATOR )
\r
293 /* The other task should not have executed outside of the
\r
295 xErrorOccurred = pdTRUE;
\r
298 /* Set the priority back down. */
\r
299 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
302 /* Let the other task timeout. When it unblockes it will check that it
\r
303 unblocked at the correct time, then suspend itself. */
\r
304 while( xRunIndicator != bktRUN_INDICATOR )
\r
306 vTaskDelay( bktSHORT_WAIT );
\r
308 vTaskDelay( bktSHORT_WAIT );
\r
312 /*********************************************************************
\r
315 As per test 3 - but with the send and receive the other way around.
\r
316 The other task blocks attempting to read from the queue.
\r
318 Empty the queue. We should find that it is full. */
\r
319 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
321 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
323 xErrorOccurred = pdTRUE;
\r
327 /* Wake the other task so it blocks attempting to read from the
\r
328 already empty queue. */
\r
329 vTaskResume( xSecondary );
\r
331 /* We need to wait a little to ensure the other task executes. */
\r
332 while( xRunIndicator != bktRUN_INDICATOR )
\r
334 vTaskDelay( bktSHORT_WAIT );
\r
336 vTaskDelay( bktSHORT_WAIT );
\r
339 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
341 /* Now when we place an item on the queue the other task should
\r
342 wake but not execute as this task has higher priority. */
\r
343 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
345 xErrorOccurred = pdTRUE;
\r
348 /* Now empty the queue again before the other task gets a chance to
\r
349 execute. If the other task had executed we would find the queue
\r
350 empty ourselves, and the other task would be suspended. */
\r
351 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
353 xErrorOccurred = pdTRUE;
\r
356 if( xRunIndicator == bktRUN_INDICATOR )
\r
358 /* The other task should not have executed. */
\r
359 xErrorOccurred = pdTRUE;
\r
362 /* Raise the priority of the other task so it executes and blocks
\r
363 on the queue again. */
\r
364 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
366 /* The other task should now have re-blocked without exiting the
\r
368 if( xRunIndicator == bktRUN_INDICATOR )
\r
370 /* The other task should not have executed outside of the
\r
372 xErrorOccurred = pdTRUE;
\r
374 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
377 /* Let the other task timeout. When it unblockes it will check that it
\r
378 unblocked at the correct time, then suspend itself. */
\r
379 while( xRunIndicator != bktRUN_INDICATOR )
\r
381 vTaskDelay( bktSHORT_WAIT );
\r
383 vTaskDelay( bktSHORT_WAIT );
\r
388 /*-----------------------------------------------------------*/
\r
390 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
392 portTickType xTimeWhenBlocking, xBlockedTime;
\r
393 portBASE_TYPE xData;
\r
395 ( void ) pvParameters;
\r
399 /*********************************************************************
\r
402 This task does does not participate in these tests. */
\r
403 vTaskSuspend( NULL );
\r
405 /*********************************************************************
\r
408 The first thing we do is attempt to read from the queue. It should be
\r
409 full so we block. Note the time before we block so we can check the
\r
410 wake time is as per that expected. */
\r
411 xTimeWhenBlocking = xTaskGetTickCount();
\r
413 /* We should unblock after bktTIME_TO_BLOCK having not sent
\r
414 anything to the queue. */
\r
416 xRunIndicator = bktRUN_INDICATOR;
\r
417 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
419 xErrorOccurred = pdTRUE;
\r
422 /* How long were we inside the send function? */
\r
423 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
425 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
426 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
428 xErrorOccurred = pdTRUE;
\r
431 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
432 either. A margin is permitted as we would not necessarily run as
\r
433 soon as we unblocked. */
\r
434 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
436 xErrorOccurred = pdTRUE;
\r
439 /* Suspend ready for test 3. */
\r
440 xRunIndicator = bktRUN_INDICATOR;
\r
441 vTaskSuspend( NULL );
\r
443 /*********************************************************************
\r
446 As per test three, but with the send and receive reversed. */
\r
447 xTimeWhenBlocking = xTaskGetTickCount();
\r
449 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
450 anything on the queue. */
\r
451 xRunIndicator = bktRUN_INDICATOR;
\r
452 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
454 xErrorOccurred = pdTRUE;
\r
457 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
459 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
460 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
462 xErrorOccurred = pdTRUE;
\r
465 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
466 either. A margin is permitted as we would not necessarily run as soon
\r
467 as we unblocked. */
\r
468 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
470 xErrorOccurred = pdTRUE;
\r
473 xRunIndicator = bktRUN_INDICATOR;
\r
475 xSecondaryCycles++;
\r
478 /*-----------------------------------------------------------*/
\r
480 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
\r
482 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
483 portBASE_TYPE xReturn = pdPASS;
\r
485 /* Have both tasks performed at least one cycle since this function was
\r
487 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
492 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
497 if( xErrorOccurred == pdTRUE )
\r
502 xLastSecondaryCycleCount = xSecondaryCycles;
\r
503 xLastPrimaryCycleCount = xPrimaryCycles;
\r