2 FreeRTOS V7.4.2 - Copyright (C) 2013 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
33 >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to
\r
34 distribute a combined work that includes FreeRTOS without being obliged to
\r
35 provide the source code for proprietary components outside of the FreeRTOS
\r
38 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
39 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
40 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
\r
41 details. You should have received a copy of the GNU General Public License
\r
42 and the FreeRTOS license exception along with FreeRTOS; if not it can be
\r
43 viewed here: http://www.freertos.org/a00114.html and also obtained by
\r
44 writing to Real Time Engineers Ltd., contact details for whom are available
\r
45 on the FreeRTOS WEB site.
\r
49 ***************************************************************************
\r
51 * Having a problem? Start by reading the FAQ "My application does *
\r
52 * not run, what could be wrong?" *
\r
54 * http://www.FreeRTOS.org/FAQHelp.html *
\r
56 ***************************************************************************
\r
59 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
60 license and Real Time Engineers Ltd. contact details.
\r
62 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
63 including FreeRTOS+Trace - an indispensable productivity tool, and our new
\r
64 fully thread aware and reentrant UDP/IP stack.
\r
66 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
67 Integrity Systems, who sell the code with commercial support,
\r
68 indemnification and middleware, under the OpenRTOS brand.
\r
70 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
71 engineered and independently SIL3 certified version for use in safety and
\r
72 mission critical applications that require provable dependability.
\r
76 * This is a version of BlockTim.c that uses the light weight API.
\r
78 * This file contains some test scenarios that ensure tasks do not exit queue
\r
79 * send or receive functions prematurely. A description of the tests is
\r
80 * included within the code.
\r
83 /* Kernel includes. */
\r
84 #include "FreeRTOS.h"
\r
88 /* Demo includes. */
\r
89 #include "AltBlock.h"
\r
91 /* Task priorities. */
\r
92 #define bktPRIMARY_PRIORITY ( 3 )
\r
93 #define bktSECONDARY_PRIORITY ( 2 )
\r
95 /* Task behaviour. */
\r
96 #define bktQUEUE_LENGTH ( 5 )
\r
97 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
98 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
99 #define bktALLOWABLE_MARGIN ( 12 )
\r
100 #define bktTIME_TO_BLOCK ( 175 )
\r
101 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
102 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
104 /* The queue on which the tasks block. */
\r
105 static xQueueHandle xTestQueue;
\r
107 /* Handle to the secondary task is required by the primary task for calls
\r
108 to vTaskSuspend/Resume(). */
\r
109 static xTaskHandle xSecondary;
\r
111 /* Used to ensure that tasks are still executing without error. */
\r
112 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
113 static portBASE_TYPE xErrorOccurred = pdFALSE;
\r
115 /* Provides a simple mechanism for the primary task to know when the
\r
116 secondary task has executed. */
\r
117 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
119 /* The two test tasks. Their behaviour is commented within the files. */
\r
120 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
121 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
123 /*-----------------------------------------------------------*/
\r
125 void vCreateAltBlockTimeTasks( void )
\r
127 /* Create the queue on which the two tasks block. */
\r
128 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
130 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
131 in use. The queue registry is provided as a means for kernel aware
\r
132 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
133 is not being used. The call to vQueueAddToRegistry() will be removed
\r
134 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
135 defined to be less than 1. */
\r
136 vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "AltBlockQueue" );
\r
139 /* Create the two test tasks. */
\r
140 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
141 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
143 /*-----------------------------------------------------------*/
\r
145 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
147 portBASE_TYPE xItem, xData;
\r
148 portTickType xTimeWhenBlocking;
\r
149 portTickType xTimeToBlock, xBlockedTime;
\r
152 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
154 const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
\r
156 /* Queue a message for printing to say the task has started. */
\r
157 vPrintDisplayMessage( &pcTaskStartMsg );
\r
160 ( void ) pvParameters;
\r
164 /*********************************************************************
\r
167 Simple block time wakeup test on queue receives. */
\r
168 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
170 /* The queue is empty. Attempt to read from the queue using a block
\r
171 time. When we wake, ensure the delta in time is as expected. */
\r
172 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
174 /* A critical section is used to minimise the jitter in the time
\r
176 portENTER_CRITICAL();
\r
178 xTimeWhenBlocking = xTaskGetTickCount();
\r
180 /* We should unblock after xTimeToBlock having not received
\r
181 anything on the queue. */
\r
182 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
184 xErrorOccurred = pdTRUE;
\r
187 /* How long were we blocked for? */
\r
188 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
190 portEXIT_CRITICAL();
\r
192 if( xBlockedTime < xTimeToBlock )
\r
194 /* Should not have blocked for less than we requested. */
\r
195 xErrorOccurred = pdTRUE;
\r
198 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
200 /* Should not have blocked for longer than we requested,
\r
201 although we would not necessarily run as soon as we were
\r
202 unblocked so a margin is allowed. */
\r
203 xErrorOccurred = pdTRUE;
\r
208 #if configUSE_PREEMPTION == 0
\r
213 /*********************************************************************
\r
216 Simple block time wakeup test on queue sends.
\r
218 First fill the queue. It should be empty so all sends should pass. */
\r
219 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
221 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
223 xErrorOccurred = pdTRUE;
\r
227 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
229 /* The queue is full. Attempt to write to the queue using a block
\r
230 time. When we wake, ensure the delta in time is as expected. */
\r
231 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
233 portENTER_CRITICAL();
\r
235 xTimeWhenBlocking = xTaskGetTickCount();
\r
237 /* We should unblock after xTimeToBlock having not received
\r
238 anything on the queue. */
\r
239 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
241 xErrorOccurred = pdTRUE;
\r
244 /* How long were we blocked for? */
\r
245 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
247 portEXIT_CRITICAL();
\r
249 if( xBlockedTime < xTimeToBlock )
\r
251 /* Should not have blocked for less than we requested. */
\r
252 xErrorOccurred = pdTRUE;
\r
255 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
257 /* Should not have blocked for longer than we requested,
\r
258 although we would not necessarily run as soon as we were
\r
259 unblocked so a margin is allowed. */
\r
260 xErrorOccurred = pdTRUE;
\r
264 #if configUSE_PREEMPTION == 0
\r
269 /*********************************************************************
\r
272 Wake the other task, it will block attempting to post to the queue.
\r
273 When we read from the queue the other task will wake, but before it
\r
274 can run we will post to the queue again. When the other task runs it
\r
275 will find the queue still full, even though it was woken. It should
\r
276 recognise that its block time has not expired and return to block for
\r
277 the remains of its block time.
\r
279 Wake the other task so it blocks attempting to post to the already
\r
282 vTaskResume( xSecondary );
\r
284 /* We need to wait a little to ensure the other task executes. */
\r
285 while( xRunIndicator != bktRUN_INDICATOR )
\r
287 /* The other task has not yet executed. */
\r
288 vTaskDelay( bktSHORT_WAIT );
\r
290 /* Make sure the other task is blocked on the queue. */
\r
291 vTaskDelay( bktSHORT_WAIT );
\r
294 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
296 /* Now when we make space on the queue the other task should wake
\r
297 but not execute as this task has higher priority. */
\r
298 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
300 xErrorOccurred = pdTRUE;
\r
303 /* Now fill the queue again before the other task gets a chance to
\r
304 execute. If the other task had executed we would find the queue
\r
305 full ourselves, and the other task have set xRunIndicator. */
\r
306 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
308 xErrorOccurred = pdTRUE;
\r
311 if( xRunIndicator == bktRUN_INDICATOR )
\r
313 /* The other task should not have executed. */
\r
314 xErrorOccurred = pdTRUE;
\r
317 /* Raise the priority of the other task so it executes and blocks
\r
318 on the queue again. */
\r
319 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
321 /* The other task should now have re-blocked without exiting the
\r
323 if( xRunIndicator == bktRUN_INDICATOR )
\r
325 /* The other task should not have executed outside of the
\r
327 xErrorOccurred = pdTRUE;
\r
330 /* Set the priority back down. */
\r
331 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
334 /* Let the other task timeout. When it unblockes it will check that it
\r
335 unblocked at the correct time, then suspend itself. */
\r
336 while( xRunIndicator != bktRUN_INDICATOR )
\r
338 vTaskDelay( bktSHORT_WAIT );
\r
340 vTaskDelay( bktSHORT_WAIT );
\r
343 #if configUSE_PREEMPTION == 0
\r
347 /*********************************************************************
\r
350 As per test 3 - but with the send and receive the other way around.
\r
351 The other task blocks attempting to read from the queue.
\r
353 Empty the queue. We should find that it is full. */
\r
354 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
356 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
358 xErrorOccurred = pdTRUE;
\r
362 /* Wake the other task so it blocks attempting to read from the
\r
363 already empty queue. */
\r
364 vTaskResume( xSecondary );
\r
366 /* We need to wait a little to ensure the other task executes. */
\r
367 while( xRunIndicator != bktRUN_INDICATOR )
\r
369 vTaskDelay( bktSHORT_WAIT );
\r
371 vTaskDelay( bktSHORT_WAIT );
\r
374 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
376 /* Now when we place an item on the queue the other task should
\r
377 wake but not execute as this task has higher priority. */
\r
378 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
380 xErrorOccurred = pdTRUE;
\r
383 /* Now empty the queue again before the other task gets a chance to
\r
384 execute. If the other task had executed we would find the queue
\r
385 empty ourselves, and the other task would be suspended. */
\r
386 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
388 xErrorOccurred = pdTRUE;
\r
391 if( xRunIndicator == bktRUN_INDICATOR )
\r
393 /* The other task should not have executed. */
\r
394 xErrorOccurred = pdTRUE;
\r
397 /* Raise the priority of the other task so it executes and blocks
\r
398 on the queue again. */
\r
399 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
401 /* The other task should now have re-blocked without exiting the
\r
403 if( xRunIndicator == bktRUN_INDICATOR )
\r
405 /* The other task should not have executed outside of the
\r
407 xErrorOccurred = pdTRUE;
\r
409 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
412 /* Let the other task timeout. When it unblockes it will check that it
\r
413 unblocked at the correct time, then suspend itself. */
\r
414 while( xRunIndicator != bktRUN_INDICATOR )
\r
416 vTaskDelay( bktSHORT_WAIT );
\r
418 vTaskDelay( bktSHORT_WAIT );
\r
423 /*-----------------------------------------------------------*/
\r
425 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
427 portTickType xTimeWhenBlocking, xBlockedTime;
\r
428 portBASE_TYPE xData;
\r
431 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
433 const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
\r
435 /* Queue a message for printing to say the task has started. */
\r
436 vPrintDisplayMessage( &pcTaskStartMsg );
\r
439 ( void ) pvParameters;
\r
443 /*********************************************************************
\r
446 This task does does not participate in these tests. */
\r
447 vTaskSuspend( NULL );
\r
449 /*********************************************************************
\r
452 The first thing we do is attempt to read from the queue. It should be
\r
453 full so we block. Note the time before we block so we can check the
\r
454 wake time is as per that expected. */
\r
455 portENTER_CRITICAL();
\r
457 xTimeWhenBlocking = xTaskGetTickCount();
\r
459 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
460 anything on the queue. */
\r
462 xRunIndicator = bktRUN_INDICATOR;
\r
463 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
465 xErrorOccurred = pdTRUE;
\r
468 /* How long were we inside the send function? */
\r
469 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
471 portEXIT_CRITICAL();
\r
473 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
474 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
476 xErrorOccurred = pdTRUE;
\r
479 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
480 either. A margin is permitted as we would not necessarily run as
\r
481 soon as we unblocked. */
\r
482 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
484 xErrorOccurred = pdTRUE;
\r
487 /* Suspend ready for test 3. */
\r
488 xRunIndicator = bktRUN_INDICATOR;
\r
489 vTaskSuspend( NULL );
\r
491 /*********************************************************************
\r
494 As per test three, but with the send and receive reversed. */
\r
495 portENTER_CRITICAL();
\r
497 xTimeWhenBlocking = xTaskGetTickCount();
\r
499 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
500 anything on the queue. */
\r
501 xRunIndicator = bktRUN_INDICATOR;
\r
502 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
504 xErrorOccurred = pdTRUE;
\r
507 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
509 portEXIT_CRITICAL();
\r
511 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
512 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
514 xErrorOccurred = pdTRUE;
\r
517 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
518 either. A margin is permitted as we would not necessarily run as soon
\r
519 as we unblocked. */
\r
520 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
522 xErrorOccurred = pdTRUE;
\r
525 xRunIndicator = bktRUN_INDICATOR;
\r
527 xSecondaryCycles++;
\r
530 /*-----------------------------------------------------------*/
\r
532 portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
\r
534 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
535 portBASE_TYPE xReturn = pdPASS;
\r
537 /* Have both tasks performed at least one cycle since this function was
\r
539 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
544 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
549 if( xErrorOccurred == pdTRUE )
\r
554 xLastSecondaryCycleCount = xSecondaryCycles;
\r
555 xLastPrimaryCycleCount = xPrimaryCycles;
\r