2 FreeRTOS V7.3.0 - Copyright (C) 2012 Real Time Engineers Ltd.
\r
4 FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT
\r
5 http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
10 * Complete, revised, and edited pdf reference manuals are also *
\r
13 * Purchasing FreeRTOS documentation will not only help you, by *
\r
14 * ensuring you get running as quickly as possible and with an *
\r
15 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
16 * the FreeRTOS project to continue with its mission of providing *
\r
17 * professional grade, cross platform, de facto standard solutions *
\r
18 * for microcontrollers - completely free of charge! *
\r
20 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
22 * Thank you for using FreeRTOS, and thank you for your support! *
\r
24 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\r
29 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
30 the terms of the GNU General Public License (version 2) as published by the
\r
31 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
32 >>>NOTE<<< The modification to the GPL is included to allow you to
\r
33 distribute a combined work that includes FreeRTOS without being obliged to
\r
34 provide the source code for proprietary components outside of the FreeRTOS
\r
35 kernel. FreeRTOS is distributed in the hope that it will be useful, but
\r
36 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
\r
37 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
\r
38 more details. You should have received a copy of the GNU General Public
\r
39 License and the FreeRTOS license exception along with FreeRTOS; if not it
\r
40 can be viewed here: http://www.freertos.org/a00114.html and also obtained
\r
41 by writing to Richard Barry, contact details for whom are available on the
\r
46 ***************************************************************************
\r
48 * Having a problem? Start by reading the FAQ "My application does *
\r
49 * not run, what could be wrong?" *
\r
51 * http://www.FreeRTOS.org/FAQHelp.html *
\r
53 ***************************************************************************
\r
56 http://www.FreeRTOS.org - Documentation, training, latest versions, license
\r
57 and contact details.
\r
59 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
60 including FreeRTOS+Trace - an indispensable productivity tool.
\r
62 Real Time Engineers ltd license FreeRTOS to High Integrity Systems, who sell
\r
63 the code with commercial support, indemnification, and middleware, under
\r
64 the OpenRTOS brand: http://www.OpenRTOS.com. High Integrity Systems also
\r
65 provide a safety engineered and independently SIL3 certified version under
\r
66 the SafeRTOS brand: http://www.SafeRTOS.com.
\r
70 * This file contains some test scenarios that ensure tasks do not exit queue
\r
71 * send or receive functions prematurely. A description of the tests is
\r
72 * included within the code.
\r
75 /* Kernel includes. */
\r
76 #include "FreeRTOS.h"
\r
80 /* Demo includes. */
\r
81 #include "blocktim.h"
\r
83 /* Task priorities. Allow these to be overridden. */
\r
84 #ifndef bktPRIMARY_PRIORITY
\r
85 #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
\r
88 #ifndef bktSECONDARY_PRIORITY
\r
89 #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
\r
92 /* Task behaviour. */
\r
93 #define bktQUEUE_LENGTH ( 5 )
\r
94 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
95 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
96 #define bktALLOWABLE_MARGIN ( 15 )
\r
97 #define bktTIME_TO_BLOCK ( 175 )
\r
98 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
99 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
101 /* The queue on which the tasks block. */
\r
102 static xQueueHandle xTestQueue;
\r
104 /* Handle to the secondary task is required by the primary task for calls
\r
105 to vTaskSuspend/Resume(). */
\r
106 static xTaskHandle xSecondary;
\r
108 /* Used to ensure that tasks are still executing without error. */
\r
109 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
110 static volatile portBASE_TYPE xErrorOccurred = pdFALSE;
\r
112 /* Provides a simple mechanism for the primary task to know when the
\r
113 secondary task has executed. */
\r
114 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
116 /* The two test tasks. Their behaviour is commented within the files. */
\r
117 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
118 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
120 /*-----------------------------------------------------------*/
\r
122 void vCreateBlockTimeTasks( void )
\r
124 /* Create the queue on which the two tasks block. */
\r
125 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
127 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
128 in use. The queue registry is provided as a means for kernel aware
\r
129 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
130 is not being used. The call to vQueueAddToRegistry() will be removed
\r
131 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
132 defined to be less than 1. */
\r
133 vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );
\r
135 /* Create the two test tasks. */
\r
136 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed char * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
137 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed char * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
139 /*-----------------------------------------------------------*/
\r
141 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
143 portBASE_TYPE xItem, xData;
\r
144 portTickType xTimeWhenBlocking;
\r
145 portTickType xTimeToBlock, xBlockedTime;
\r
147 ( void ) pvParameters;
\r
151 /*********************************************************************
\r
154 Simple block time wakeup test on queue receives. */
\r
155 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
157 /* The queue is empty. Attempt to read from the queue using a block
\r
158 time. When we wake, ensure the delta in time is as expected. */
\r
159 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
161 xTimeWhenBlocking = xTaskGetTickCount();
\r
163 /* We should unblock after xTimeToBlock having not received
\r
164 anything on the queue. */
\r
165 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
167 xErrorOccurred = pdTRUE;
\r
170 /* How long were we blocked for? */
\r
171 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
173 if( xBlockedTime < xTimeToBlock )
\r
175 /* Should not have blocked for less than we requested. */
\r
176 xErrorOccurred = pdTRUE;
\r
179 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
181 /* Should not have blocked for longer than we requested,
\r
182 although we would not necessarily run as soon as we were
\r
183 unblocked so a margin is allowed. */
\r
184 xErrorOccurred = pdTRUE;
\r
188 /*********************************************************************
\r
191 Simple block time wakeup test on queue sends.
\r
193 First fill the queue. It should be empty so all sends should pass. */
\r
194 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
196 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
198 xErrorOccurred = pdTRUE;
\r
201 #if configUSE_PREEMPTION == 0
\r
206 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
208 /* The queue is full. Attempt to write to the queue using a block
\r
209 time. When we wake, ensure the delta in time is as expected. */
\r
210 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
212 xTimeWhenBlocking = xTaskGetTickCount();
\r
214 /* We should unblock after xTimeToBlock having not received
\r
215 anything on the queue. */
\r
216 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
218 xErrorOccurred = pdTRUE;
\r
221 /* How long were we blocked for? */
\r
222 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
224 if( xBlockedTime < xTimeToBlock )
\r
226 /* Should not have blocked for less than we requested. */
\r
227 xErrorOccurred = pdTRUE;
\r
230 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
232 /* Should not have blocked for longer than we requested,
\r
233 although we would not necessarily run as soon as we were
\r
234 unblocked so a margin is allowed. */
\r
235 xErrorOccurred = pdTRUE;
\r
239 /*********************************************************************
\r
242 Wake the other task, it will block attempting to post to the queue.
\r
243 When we read from the queue the other task will wake, but before it
\r
244 can run we will post to the queue again. When the other task runs it
\r
245 will find the queue still full, even though it was woken. It should
\r
246 recognise that its block time has not expired and return to block for
\r
247 the remains of its block time.
\r
249 Wake the other task so it blocks attempting to post to the already
\r
252 vTaskResume( xSecondary );
\r
254 /* We need to wait a little to ensure the other task executes. */
\r
255 while( xRunIndicator != bktRUN_INDICATOR )
\r
257 /* The other task has not yet executed. */
\r
258 vTaskDelay( bktSHORT_WAIT );
\r
260 /* Make sure the other task is blocked on the queue. */
\r
261 vTaskDelay( bktSHORT_WAIT );
\r
264 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
266 /* Now when we make space on the queue the other task should wake
\r
267 but not execute as this task has higher priority. */
\r
268 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
270 xErrorOccurred = pdTRUE;
\r
273 /* Now fill the queue again before the other task gets a chance to
\r
274 execute. If the other task had executed we would find the queue
\r
275 full ourselves, and the other task have set xRunIndicator. */
\r
276 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
278 xErrorOccurred = pdTRUE;
\r
281 if( xRunIndicator == bktRUN_INDICATOR )
\r
283 /* The other task should not have executed. */
\r
284 xErrorOccurred = pdTRUE;
\r
287 /* Raise the priority of the other task so it executes and blocks
\r
288 on the queue again. */
\r
289 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
291 /* The other task should now have re-blocked without exiting the
\r
293 if( xRunIndicator == bktRUN_INDICATOR )
\r
295 /* The other task should not have executed outside of the
\r
297 xErrorOccurred = pdTRUE;
\r
300 /* Set the priority back down. */
\r
301 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
304 /* Let the other task timeout. When it unblockes it will check that it
\r
305 unblocked at the correct time, then suspend itself. */
\r
306 while( xRunIndicator != bktRUN_INDICATOR )
\r
308 vTaskDelay( bktSHORT_WAIT );
\r
310 vTaskDelay( bktSHORT_WAIT );
\r
314 /*********************************************************************
\r
317 As per test 3 - but with the send and receive the other way around.
\r
318 The other task blocks attempting to read from the queue.
\r
320 Empty the queue. We should find that it is full. */
\r
321 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
323 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
325 xErrorOccurred = pdTRUE;
\r
329 /* Wake the other task so it blocks attempting to read from the
\r
330 already empty queue. */
\r
331 vTaskResume( xSecondary );
\r
333 /* We need to wait a little to ensure the other task executes. */
\r
334 while( xRunIndicator != bktRUN_INDICATOR )
\r
336 vTaskDelay( bktSHORT_WAIT );
\r
338 vTaskDelay( bktSHORT_WAIT );
\r
341 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
343 /* Now when we place an item on the queue the other task should
\r
344 wake but not execute as this task has higher priority. */
\r
345 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
347 xErrorOccurred = pdTRUE;
\r
350 /* Now empty the queue again before the other task gets a chance to
\r
351 execute. If the other task had executed we would find the queue
\r
352 empty ourselves, and the other task would be suspended. */
\r
353 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
355 xErrorOccurred = pdTRUE;
\r
358 if( xRunIndicator == bktRUN_INDICATOR )
\r
360 /* The other task should not have executed. */
\r
361 xErrorOccurred = pdTRUE;
\r
364 /* Raise the priority of the other task so it executes and blocks
\r
365 on the queue again. */
\r
366 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
368 /* The other task should now have re-blocked without exiting the
\r
370 if( xRunIndicator == bktRUN_INDICATOR )
\r
372 /* The other task should not have executed outside of the
\r
374 xErrorOccurred = pdTRUE;
\r
376 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
379 /* Let the other task timeout. When it unblockes it will check that it
\r
380 unblocked at the correct time, then suspend itself. */
\r
381 while( xRunIndicator != bktRUN_INDICATOR )
\r
383 vTaskDelay( bktSHORT_WAIT );
\r
385 vTaskDelay( bktSHORT_WAIT );
\r
390 /*-----------------------------------------------------------*/
\r
392 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
394 portTickType xTimeWhenBlocking, xBlockedTime;
\r
395 portBASE_TYPE xData;
\r
397 ( void ) pvParameters;
\r
401 /*********************************************************************
\r
404 This task does does not participate in these tests. */
\r
405 vTaskSuspend( NULL );
\r
407 /*********************************************************************
\r
410 The first thing we do is attempt to read from the queue. It should be
\r
411 full so we block. Note the time before we block so we can check the
\r
412 wake time is as per that expected. */
\r
413 xTimeWhenBlocking = xTaskGetTickCount();
\r
415 /* We should unblock after bktTIME_TO_BLOCK having not sent
\r
416 anything to the queue. */
\r
418 xRunIndicator = bktRUN_INDICATOR;
\r
419 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
421 xErrorOccurred = pdTRUE;
\r
424 /* How long were we inside the send function? */
\r
425 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
427 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
428 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
430 xErrorOccurred = pdTRUE;
\r
433 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
434 either. A margin is permitted as we would not necessarily run as
\r
435 soon as we unblocked. */
\r
436 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
438 xErrorOccurred = pdTRUE;
\r
441 /* Suspend ready for test 3. */
\r
442 xRunIndicator = bktRUN_INDICATOR;
\r
443 vTaskSuspend( NULL );
\r
445 /*********************************************************************
\r
448 As per test three, but with the send and receive reversed. */
\r
449 xTimeWhenBlocking = xTaskGetTickCount();
\r
451 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
452 anything on the queue. */
\r
453 xRunIndicator = bktRUN_INDICATOR;
\r
454 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
456 xErrorOccurred = pdTRUE;
\r
459 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
461 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
462 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
464 xErrorOccurred = pdTRUE;
\r
467 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
468 either. A margin is permitted as we would not necessarily run as soon
\r
469 as we unblocked. */
\r
470 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
472 xErrorOccurred = pdTRUE;
\r
475 xRunIndicator = bktRUN_INDICATOR;
\r
477 xSecondaryCycles++;
\r
480 /*-----------------------------------------------------------*/
\r
482 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
\r
484 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
485 portBASE_TYPE xReturn = pdPASS;
\r
487 /* Have both tasks performed at least one cycle since this function was
\r
489 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
494 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
499 if( xErrorOccurred == pdTRUE )
\r
504 xLastSecondaryCycleCount = xSecondaryCycles;
\r
505 xLastPrimaryCycleCount = xPrimaryCycles;
\r