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 is a version of BlockTim.c that uses the light weight API.
\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 "AltBlock.h"
\r
83 /* Task priorities. */
\r
84 #define bktPRIMARY_PRIORITY ( 3 )
\r
85 #define bktSECONDARY_PRIORITY ( 2 )
\r
87 /* Task behaviour. */
\r
88 #define bktQUEUE_LENGTH ( 5 )
\r
89 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
90 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
91 #define bktALLOWABLE_MARGIN ( 12 )
\r
92 #define bktTIME_TO_BLOCK ( 175 )
\r
93 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
94 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
96 /* The queue on which the tasks block. */
\r
97 static xQueueHandle xTestQueue;
\r
99 /* Handle to the secondary task is required by the primary task for calls
\r
100 to vTaskSuspend/Resume(). */
\r
101 static xTaskHandle xSecondary;
\r
103 /* Used to ensure that tasks are still executing without error. */
\r
104 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
105 static portBASE_TYPE xErrorOccurred = pdFALSE;
\r
107 /* Provides a simple mechanism for the primary task to know when the
\r
108 secondary task has executed. */
\r
109 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
111 /* The two test tasks. Their behaviour is commented within the files. */
\r
112 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
113 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
115 /*-----------------------------------------------------------*/
\r
117 void vCreateAltBlockTimeTasks( void )
\r
119 /* Create the queue on which the two tasks block. */
\r
120 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
122 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
123 in use. The queue registry is provided as a means for kernel aware
\r
124 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
125 is not being used. The call to vQueueAddToRegistry() will be removed
\r
126 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
127 defined to be less than 1. */
\r
128 vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "AltBlockQueue" );
\r
131 /* Create the two test tasks. */
\r
132 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
133 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
135 /*-----------------------------------------------------------*/
\r
137 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
139 portBASE_TYPE xItem, xData;
\r
140 portTickType xTimeWhenBlocking;
\r
141 portTickType xTimeToBlock, xBlockedTime;
\r
144 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
146 const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
\r
148 /* Queue a message for printing to say the task has started. */
\r
149 vPrintDisplayMessage( &pcTaskStartMsg );
\r
152 ( void ) pvParameters;
\r
156 /*********************************************************************
\r
159 Simple block time wakeup test on queue receives. */
\r
160 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
162 /* The queue is empty. Attempt to read from the queue using a block
\r
163 time. When we wake, ensure the delta in time is as expected. */
\r
164 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
166 /* A critical section is used to minimise the jitter in the time
\r
168 portENTER_CRITICAL();
\r
170 xTimeWhenBlocking = xTaskGetTickCount();
\r
172 /* We should unblock after xTimeToBlock having not received
\r
173 anything on the queue. */
\r
174 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
176 xErrorOccurred = pdTRUE;
\r
179 /* How long were we blocked for? */
\r
180 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
182 portEXIT_CRITICAL();
\r
184 if( xBlockedTime < xTimeToBlock )
\r
186 /* Should not have blocked for less than we requested. */
\r
187 xErrorOccurred = pdTRUE;
\r
190 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
192 /* Should not have blocked for longer than we requested,
\r
193 although we would not necessarily run as soon as we were
\r
194 unblocked so a margin is allowed. */
\r
195 xErrorOccurred = pdTRUE;
\r
200 #if configUSE_PREEMPTION == 0
\r
205 /*********************************************************************
\r
208 Simple block time wakeup test on queue sends.
\r
210 First fill the queue. It should be empty so all sends should pass. */
\r
211 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
213 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
215 xErrorOccurred = pdTRUE;
\r
219 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
221 /* The queue is full. Attempt to write to the queue using a block
\r
222 time. When we wake, ensure the delta in time is as expected. */
\r
223 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
225 portENTER_CRITICAL();
\r
227 xTimeWhenBlocking = xTaskGetTickCount();
\r
229 /* We should unblock after xTimeToBlock having not received
\r
230 anything on the queue. */
\r
231 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
233 xErrorOccurred = pdTRUE;
\r
236 /* How long were we blocked for? */
\r
237 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
239 portEXIT_CRITICAL();
\r
241 if( xBlockedTime < xTimeToBlock )
\r
243 /* Should not have blocked for less than we requested. */
\r
244 xErrorOccurred = pdTRUE;
\r
247 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
249 /* Should not have blocked for longer than we requested,
\r
250 although we would not necessarily run as soon as we were
\r
251 unblocked so a margin is allowed. */
\r
252 xErrorOccurred = pdTRUE;
\r
256 #if configUSE_PREEMPTION == 0
\r
261 /*********************************************************************
\r
264 Wake the other task, it will block attempting to post to the queue.
\r
265 When we read from the queue the other task will wake, but before it
\r
266 can run we will post to the queue again. When the other task runs it
\r
267 will find the queue still full, even though it was woken. It should
\r
268 recognise that its block time has not expired and return to block for
\r
269 the remains of its block time.
\r
271 Wake the other task so it blocks attempting to post to the already
\r
274 vTaskResume( xSecondary );
\r
276 /* We need to wait a little to ensure the other task executes. */
\r
277 while( xRunIndicator != bktRUN_INDICATOR )
\r
279 /* The other task has not yet executed. */
\r
280 vTaskDelay( bktSHORT_WAIT );
\r
282 /* Make sure the other task is blocked on the queue. */
\r
283 vTaskDelay( bktSHORT_WAIT );
\r
286 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
288 /* Now when we make space on the queue the other task should wake
\r
289 but not execute as this task has higher priority. */
\r
290 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
292 xErrorOccurred = pdTRUE;
\r
295 /* Now fill the queue again before the other task gets a chance to
\r
296 execute. If the other task had executed we would find the queue
\r
297 full ourselves, and the other task have set xRunIndicator. */
\r
298 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
300 xErrorOccurred = pdTRUE;
\r
303 if( xRunIndicator == bktRUN_INDICATOR )
\r
305 /* The other task should not have executed. */
\r
306 xErrorOccurred = pdTRUE;
\r
309 /* Raise the priority of the other task so it executes and blocks
\r
310 on the queue again. */
\r
311 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
313 /* The other task should now have re-blocked without exiting the
\r
315 if( xRunIndicator == bktRUN_INDICATOR )
\r
317 /* The other task should not have executed outside of the
\r
319 xErrorOccurred = pdTRUE;
\r
322 /* Set the priority back down. */
\r
323 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
326 /* Let the other task timeout. When it unblockes it will check that it
\r
327 unblocked at the correct time, then suspend itself. */
\r
328 while( xRunIndicator != bktRUN_INDICATOR )
\r
330 vTaskDelay( bktSHORT_WAIT );
\r
332 vTaskDelay( bktSHORT_WAIT );
\r
335 #if configUSE_PREEMPTION == 0
\r
339 /*********************************************************************
\r
342 As per test 3 - but with the send and receive the other way around.
\r
343 The other task blocks attempting to read from the queue.
\r
345 Empty the queue. We should find that it is full. */
\r
346 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
348 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
350 xErrorOccurred = pdTRUE;
\r
354 /* Wake the other task so it blocks attempting to read from the
\r
355 already empty queue. */
\r
356 vTaskResume( xSecondary );
\r
358 /* We need to wait a little to ensure the other task executes. */
\r
359 while( xRunIndicator != bktRUN_INDICATOR )
\r
361 vTaskDelay( bktSHORT_WAIT );
\r
363 vTaskDelay( bktSHORT_WAIT );
\r
366 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
368 /* Now when we place an item on the queue the other task should
\r
369 wake but not execute as this task has higher priority. */
\r
370 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
372 xErrorOccurred = pdTRUE;
\r
375 /* Now empty the queue again before the other task gets a chance to
\r
376 execute. If the other task had executed we would find the queue
\r
377 empty ourselves, and the other task would be suspended. */
\r
378 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
380 xErrorOccurred = pdTRUE;
\r
383 if( xRunIndicator == bktRUN_INDICATOR )
\r
385 /* The other task should not have executed. */
\r
386 xErrorOccurred = pdTRUE;
\r
389 /* Raise the priority of the other task so it executes and blocks
\r
390 on the queue again. */
\r
391 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
393 /* The other task should now have re-blocked without exiting the
\r
395 if( xRunIndicator == bktRUN_INDICATOR )
\r
397 /* The other task should not have executed outside of the
\r
399 xErrorOccurred = pdTRUE;
\r
401 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
404 /* Let the other task timeout. When it unblockes it will check that it
\r
405 unblocked at the correct time, then suspend itself. */
\r
406 while( xRunIndicator != bktRUN_INDICATOR )
\r
408 vTaskDelay( bktSHORT_WAIT );
\r
410 vTaskDelay( bktSHORT_WAIT );
\r
415 /*-----------------------------------------------------------*/
\r
417 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
419 portTickType xTimeWhenBlocking, xBlockedTime;
\r
420 portBASE_TYPE xData;
\r
423 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
425 const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
\r
427 /* Queue a message for printing to say the task has started. */
\r
428 vPrintDisplayMessage( &pcTaskStartMsg );
\r
431 ( void ) pvParameters;
\r
435 /*********************************************************************
\r
438 This task does does not participate in these tests. */
\r
439 vTaskSuspend( NULL );
\r
441 /*********************************************************************
\r
444 The first thing we do is attempt to read from the queue. It should be
\r
445 full so we block. Note the time before we block so we can check the
\r
446 wake time is as per that expected. */
\r
447 portENTER_CRITICAL();
\r
449 xTimeWhenBlocking = xTaskGetTickCount();
\r
451 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
452 anything on the queue. */
\r
454 xRunIndicator = bktRUN_INDICATOR;
\r
455 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
457 xErrorOccurred = pdTRUE;
\r
460 /* How long were we inside the send function? */
\r
461 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
463 portEXIT_CRITICAL();
\r
465 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
466 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
468 xErrorOccurred = pdTRUE;
\r
471 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
472 either. A margin is permitted as we would not necessarily run as
\r
473 soon as we unblocked. */
\r
474 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
476 xErrorOccurred = pdTRUE;
\r
479 /* Suspend ready for test 3. */
\r
480 xRunIndicator = bktRUN_INDICATOR;
\r
481 vTaskSuspend( NULL );
\r
483 /*********************************************************************
\r
486 As per test three, but with the send and receive reversed. */
\r
487 portENTER_CRITICAL();
\r
489 xTimeWhenBlocking = xTaskGetTickCount();
\r
491 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
492 anything on the queue. */
\r
493 xRunIndicator = bktRUN_INDICATOR;
\r
494 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
496 xErrorOccurred = pdTRUE;
\r
499 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
501 portEXIT_CRITICAL();
\r
503 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
504 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
506 xErrorOccurred = pdTRUE;
\r
509 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
510 either. A margin is permitted as we would not necessarily run as soon
\r
511 as we unblocked. */
\r
512 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
514 xErrorOccurred = pdTRUE;
\r
517 xRunIndicator = bktRUN_INDICATOR;
\r
519 xSecondaryCycles++;
\r
522 /*-----------------------------------------------------------*/
\r
524 portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
\r
526 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
527 portBASE_TYPE xReturn = pdPASS;
\r
529 /* Have both tasks performed at least one cycle since this function was
\r
531 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
536 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
541 if( xErrorOccurred == pdTRUE )
\r
546 xLastSecondaryCycleCount = xSecondaryCycles;
\r
547 xLastPrimaryCycleCount = xPrimaryCycles;
\r