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 is a version of BlockTim.c that uses the light weight API.
\r
57 * This file contains some test scenarios that ensure tasks do not exit queue
\r
58 * send or receive functions prematurely. A description of the tests is
\r
59 * included within the code.
\r
62 /* Kernel includes. */
\r
63 #include "FreeRTOS.h"
\r
67 /* Demo includes. */
\r
68 #include "AltBlock.h"
\r
70 /* Task priorities. */
\r
71 #define bktPRIMARY_PRIORITY ( 3 )
\r
72 #define bktSECONDARY_PRIORITY ( 2 )
\r
74 /* Task behaviour. */
\r
75 #define bktQUEUE_LENGTH ( 5 )
\r
76 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
77 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
78 #define bktALLOWABLE_MARGIN ( 12 )
\r
79 #define bktTIME_TO_BLOCK ( 175 )
\r
80 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
81 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
83 /* The queue on which the tasks block. */
\r
84 static xQueueHandle xTestQueue;
\r
86 /* Handle to the secondary task is required by the primary task for calls
\r
87 to vTaskSuspend/Resume(). */
\r
88 static xTaskHandle xSecondary;
\r
90 /* Used to ensure that tasks are still executing without error. */
\r
91 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
92 static portBASE_TYPE xErrorOccurred = pdFALSE;
\r
94 /* Provides a simple mechanism for the primary task to know when the
\r
95 secondary task has executed. */
\r
96 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
98 /* The two test tasks. Their behaviour is commented within the files. */
\r
99 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
100 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
102 /*-----------------------------------------------------------*/
\r
104 void vCreateAltBlockTimeTasks( void )
\r
106 /* Create the queue on which the two tasks block. */
\r
107 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
109 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
110 in use. The queue registry is provided as a means for kernel aware
\r
111 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
112 is not being used. The call to vQueueAddToRegistry() will be removed
\r
113 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
114 defined to be less than 1. */
\r
115 vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "AltBlockQueue" );
\r
118 /* Create the two test tasks. */
\r
119 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
120 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
122 /*-----------------------------------------------------------*/
\r
124 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
126 portBASE_TYPE xItem, xData;
\r
127 portTickType xTimeWhenBlocking;
\r
128 portTickType xTimeToBlock, xBlockedTime;
\r
131 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
133 const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
\r
135 /* Queue a message for printing to say the task has started. */
\r
136 vPrintDisplayMessage( &pcTaskStartMsg );
\r
139 ( void ) pvParameters;
\r
143 /*********************************************************************
\r
146 Simple block time wakeup test on queue receives. */
\r
147 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
149 /* The queue is empty. Attempt to read from the queue using a block
\r
150 time. When we wake, ensure the delta in time is as expected. */
\r
151 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
153 /* A critical section is used to minimise the jitter in the time
\r
155 portENTER_CRITICAL();
\r
157 xTimeWhenBlocking = xTaskGetTickCount();
\r
159 /* We should unblock after xTimeToBlock having not received
\r
160 anything on the queue. */
\r
161 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
163 xErrorOccurred = pdTRUE;
\r
166 /* How long were we blocked for? */
\r
167 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
169 portEXIT_CRITICAL();
\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
187 #if configUSE_PREEMPTION == 0
\r
192 /*********************************************************************
\r
195 Simple block time wakeup test on queue sends.
\r
197 First fill the queue. It should be empty so all sends should pass. */
\r
198 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
200 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
202 xErrorOccurred = pdTRUE;
\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 portENTER_CRITICAL();
\r
214 xTimeWhenBlocking = xTaskGetTickCount();
\r
216 /* We should unblock after xTimeToBlock having not received
\r
217 anything on the queue. */
\r
218 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
220 xErrorOccurred = pdTRUE;
\r
223 /* How long were we blocked for? */
\r
224 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
226 portEXIT_CRITICAL();
\r
228 if( xBlockedTime < xTimeToBlock )
\r
230 /* Should not have blocked for less than we requested. */
\r
231 xErrorOccurred = pdTRUE;
\r
234 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
236 /* Should not have blocked for longer than we requested,
\r
237 although we would not necessarily run as soon as we were
\r
238 unblocked so a margin is allowed. */
\r
239 xErrorOccurred = pdTRUE;
\r
243 #if configUSE_PREEMPTION == 0
\r
248 /*********************************************************************
\r
251 Wake the other task, it will block attempting to post to the queue.
\r
252 When we read from the queue the other task will wake, but before it
\r
253 can run we will post to the queue again. When the other task runs it
\r
254 will find the queue still full, even though it was woken. It should
\r
255 recognise that its block time has not expired and return to block for
\r
256 the remains of its block time.
\r
258 Wake the other task so it blocks attempting to post to the already
\r
261 vTaskResume( xSecondary );
\r
263 /* We need to wait a little to ensure the other task executes. */
\r
264 while( xRunIndicator != bktRUN_INDICATOR )
\r
266 /* The other task has not yet executed. */
\r
267 vTaskDelay( bktSHORT_WAIT );
\r
269 /* Make sure the other task is blocked on the queue. */
\r
270 vTaskDelay( bktSHORT_WAIT );
\r
273 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
275 /* Now when we make space on the queue the other task should wake
\r
276 but not execute as this task has higher priority. */
\r
277 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
279 xErrorOccurred = pdTRUE;
\r
282 /* Now fill the queue again before the other task gets a chance to
\r
283 execute. If the other task had executed we would find the queue
\r
284 full ourselves, and the other task have set xRunIndicator. */
\r
285 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
287 xErrorOccurred = pdTRUE;
\r
290 if( xRunIndicator == bktRUN_INDICATOR )
\r
292 /* The other task should not have executed. */
\r
293 xErrorOccurred = pdTRUE;
\r
296 /* Raise the priority of the other task so it executes and blocks
\r
297 on the queue again. */
\r
298 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
300 /* The other task should now have re-blocked without exiting the
\r
302 if( xRunIndicator == bktRUN_INDICATOR )
\r
304 /* The other task should not have executed outside of the
\r
306 xErrorOccurred = pdTRUE;
\r
309 /* Set the priority back down. */
\r
310 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
313 /* Let the other task timeout. When it unblockes it will check that it
\r
314 unblocked at the correct time, then suspend itself. */
\r
315 while( xRunIndicator != bktRUN_INDICATOR )
\r
317 vTaskDelay( bktSHORT_WAIT );
\r
319 vTaskDelay( bktSHORT_WAIT );
\r
322 #if configUSE_PREEMPTION == 0
\r
326 /*********************************************************************
\r
329 As per test 3 - but with the send and receive the other way around.
\r
330 The other task blocks attempting to read from the queue.
\r
332 Empty the queue. We should find that it is full. */
\r
333 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
335 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
337 xErrorOccurred = pdTRUE;
\r
341 /* Wake the other task so it blocks attempting to read from the
\r
342 already empty queue. */
\r
343 vTaskResume( xSecondary );
\r
345 /* We need to wait a little to ensure the other task executes. */
\r
346 while( xRunIndicator != bktRUN_INDICATOR )
\r
348 vTaskDelay( bktSHORT_WAIT );
\r
350 vTaskDelay( bktSHORT_WAIT );
\r
353 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
355 /* Now when we place an item on the queue the other task should
\r
356 wake but not execute as this task has higher priority. */
\r
357 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
359 xErrorOccurred = pdTRUE;
\r
362 /* Now empty the queue again before the other task gets a chance to
\r
363 execute. If the other task had executed we would find the queue
\r
364 empty ourselves, and the other task would be suspended. */
\r
365 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
367 xErrorOccurred = pdTRUE;
\r
370 if( xRunIndicator == bktRUN_INDICATOR )
\r
372 /* The other task should not have executed. */
\r
373 xErrorOccurred = pdTRUE;
\r
376 /* Raise the priority of the other task so it executes and blocks
\r
377 on the queue again. */
\r
378 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
380 /* The other task should now have re-blocked without exiting the
\r
382 if( xRunIndicator == bktRUN_INDICATOR )
\r
384 /* The other task should not have executed outside of the
\r
386 xErrorOccurred = pdTRUE;
\r
388 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
391 /* Let the other task timeout. When it unblockes it will check that it
\r
392 unblocked at the correct time, then suspend itself. */
\r
393 while( xRunIndicator != bktRUN_INDICATOR )
\r
395 vTaskDelay( bktSHORT_WAIT );
\r
397 vTaskDelay( bktSHORT_WAIT );
\r
402 /*-----------------------------------------------------------*/
\r
404 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
406 portTickType xTimeWhenBlocking, xBlockedTime;
\r
407 portBASE_TYPE xData;
\r
410 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
412 const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
\r
414 /* Queue a message for printing to say the task has started. */
\r
415 vPrintDisplayMessage( &pcTaskStartMsg );
\r
418 ( void ) pvParameters;
\r
422 /*********************************************************************
\r
425 This task does does not participate in these tests. */
\r
426 vTaskSuspend( NULL );
\r
428 /*********************************************************************
\r
431 The first thing we do is attempt to read from the queue. It should be
\r
432 full so we block. Note the time before we block so we can check the
\r
433 wake time is as per that expected. */
\r
434 portENTER_CRITICAL();
\r
436 xTimeWhenBlocking = xTaskGetTickCount();
\r
438 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
439 anything on the queue. */
\r
441 xRunIndicator = bktRUN_INDICATOR;
\r
442 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
444 xErrorOccurred = pdTRUE;
\r
447 /* How long were we inside the send function? */
\r
448 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
450 portEXIT_CRITICAL();
\r
452 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
453 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
455 xErrorOccurred = pdTRUE;
\r
458 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
459 either. A margin is permitted as we would not necessarily run as
\r
460 soon as we unblocked. */
\r
461 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
463 xErrorOccurred = pdTRUE;
\r
466 /* Suspend ready for test 3. */
\r
467 xRunIndicator = bktRUN_INDICATOR;
\r
468 vTaskSuspend( NULL );
\r
470 /*********************************************************************
\r
473 As per test three, but with the send and receive reversed. */
\r
474 portENTER_CRITICAL();
\r
476 xTimeWhenBlocking = xTaskGetTickCount();
\r
478 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
479 anything on the queue. */
\r
480 xRunIndicator = bktRUN_INDICATOR;
\r
481 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
483 xErrorOccurred = pdTRUE;
\r
486 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
488 portEXIT_CRITICAL();
\r
490 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
491 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
493 xErrorOccurred = pdTRUE;
\r
496 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
497 either. A margin is permitted as we would not necessarily run as soon
\r
498 as we unblocked. */
\r
499 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
501 xErrorOccurred = pdTRUE;
\r
504 xRunIndicator = bktRUN_INDICATOR;
\r
506 xSecondaryCycles++;
\r
509 /*-----------------------------------------------------------*/
\r
511 portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
\r
513 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
514 portBASE_TYPE xReturn = pdPASS;
\r
516 /* Have both tasks performed at least one cycle since this function was
\r
518 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
523 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
528 if( xErrorOccurred == pdTRUE )
\r
533 xLastSecondaryCycleCount = xSecondaryCycles;
\r
534 xLastPrimaryCycleCount = xPrimaryCycles;
\r