2 FreeRTOS V7.5.1 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
6 ***************************************************************************
\r
8 * FreeRTOS provides completely free yet professionally developed, *
\r
9 * robust, strictly quality controlled, supported, and cross *
\r
10 * platform software that has become a de facto standard. *
\r
12 * Help yourself get started quickly and support the FreeRTOS *
\r
13 * project by purchasing a FreeRTOS tutorial book, reference *
\r
14 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
18 ***************************************************************************
\r
20 This file is part of the FreeRTOS distribution.
\r
22 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
23 the terms of the GNU General Public License (version 2) as published by the
\r
24 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
26 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
27 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
28 >>! the source code for proprietary components outside of the FreeRTOS
\r
31 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
32 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
33 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
34 link: http://www.freertos.org/a00114.html
\r
38 ***************************************************************************
\r
40 * Having a problem? Start by reading the FAQ "My application does *
\r
41 * not run, what could be wrong?" *
\r
43 * http://www.FreeRTOS.org/FAQHelp.html *
\r
45 ***************************************************************************
\r
47 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
48 license and Real Time Engineers Ltd. contact details.
\r
50 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
51 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
52 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
54 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
55 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
56 licenses offer ticketed support, indemnification and middleware.
\r
58 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
59 engineered and independently SIL3 certified version for use in safety and
\r
60 mission critical applications that require provable dependability.
\r
66 * This is a version of BlockTim.c that uses the light weight API.
\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 "AltBlock.h"
\r
81 /* Task priorities. */
\r
82 #define bktPRIMARY_PRIORITY ( 3 )
\r
83 #define bktSECONDARY_PRIORITY ( 2 )
\r
85 /* Task behaviour. */
\r
86 #define bktQUEUE_LENGTH ( 5 )
\r
87 #define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
\r
88 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
89 #define bktALLOWABLE_MARGIN ( 12 )
\r
90 #define bktTIME_TO_BLOCK ( 175 )
\r
91 #define bktDONT_BLOCK ( ( portTickType ) 0 )
\r
92 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
94 /* The queue on which the tasks block. */
\r
95 static xQueueHandle xTestQueue;
\r
97 /* Handle to the secondary task is required by the primary task for calls
\r
98 to vTaskSuspend/Resume(). */
\r
99 static xTaskHandle xSecondary;
\r
101 /* Used to ensure that tasks are still executing without error. */
\r
102 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
103 static portBASE_TYPE xErrorOccurred = pdFALSE;
\r
105 /* Provides a simple mechanism for the primary task to know when the
\r
106 secondary task has executed. */
\r
107 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
109 /* The two test tasks. Their behaviour is commented within the files. */
\r
110 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
111 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
113 /*-----------------------------------------------------------*/
\r
115 void vCreateAltBlockTimeTasks( void )
\r
117 /* Create the queue on which the two tasks block. */
\r
118 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
120 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
121 in use. The queue registry is provided as a means for kernel aware
\r
122 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
123 is not being used. The call to vQueueAddToRegistry() will be removed
\r
124 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
125 defined to be less than 1. */
\r
126 vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "AltBlockQueue" );
\r
129 /* Create the two test tasks. */
\r
130 xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
131 xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
133 /*-----------------------------------------------------------*/
\r
135 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
137 portBASE_TYPE xItem, xData;
\r
138 portTickType xTimeWhenBlocking;
\r
139 portTickType xTimeToBlock, xBlockedTime;
\r
142 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
144 const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
\r
146 /* Queue a message for printing to say the task has started. */
\r
147 vPrintDisplayMessage( &pcTaskStartMsg );
\r
150 ( void ) pvParameters;
\r
154 /*********************************************************************
\r
157 Simple block time wakeup test on queue receives. */
\r
158 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
160 /* The queue is empty. Attempt to read from the queue using a block
\r
161 time. When we wake, ensure the delta in time is as expected. */
\r
162 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
164 /* A critical section is used to minimise the jitter in the time
\r
166 portENTER_CRITICAL();
\r
168 xTimeWhenBlocking = xTaskGetTickCount();
\r
170 /* We should unblock after xTimeToBlock having not received
\r
171 anything on the queue. */
\r
172 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
174 xErrorOccurred = pdTRUE;
\r
177 /* How long were we blocked for? */
\r
178 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
180 portEXIT_CRITICAL();
\r
182 if( xBlockedTime < xTimeToBlock )
\r
184 /* Should not have blocked for less than we requested. */
\r
185 xErrorOccurred = pdTRUE;
\r
188 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
190 /* Should not have blocked for longer than we requested,
\r
191 although we would not necessarily run as soon as we were
\r
192 unblocked so a margin is allowed. */
\r
193 xErrorOccurred = pdTRUE;
\r
198 #if configUSE_PREEMPTION == 0
\r
203 /*********************************************************************
\r
206 Simple block time wakeup test on queue sends.
\r
208 First fill the queue. It should be empty so all sends should pass. */
\r
209 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
211 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
213 xErrorOccurred = pdTRUE;
\r
217 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
219 /* The queue is full. Attempt to write to the queue using a block
\r
220 time. When we wake, ensure the delta in time is as expected. */
\r
221 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
223 portENTER_CRITICAL();
\r
225 xTimeWhenBlocking = xTaskGetTickCount();
\r
227 /* We should unblock after xTimeToBlock having not received
\r
228 anything on the queue. */
\r
229 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
231 xErrorOccurred = pdTRUE;
\r
234 /* How long were we blocked for? */
\r
235 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
237 portEXIT_CRITICAL();
\r
239 if( xBlockedTime < xTimeToBlock )
\r
241 /* Should not have blocked for less than we requested. */
\r
242 xErrorOccurred = pdTRUE;
\r
245 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
247 /* Should not have blocked for longer than we requested,
\r
248 although we would not necessarily run as soon as we were
\r
249 unblocked so a margin is allowed. */
\r
250 xErrorOccurred = pdTRUE;
\r
254 #if configUSE_PREEMPTION == 0
\r
259 /*********************************************************************
\r
262 Wake the other task, it will block attempting to post to the queue.
\r
263 When we read from the queue the other task will wake, but before it
\r
264 can run we will post to the queue again. When the other task runs it
\r
265 will find the queue still full, even though it was woken. It should
\r
266 recognise that its block time has not expired and return to block for
\r
267 the remains of its block time.
\r
269 Wake the other task so it blocks attempting to post to the already
\r
272 vTaskResume( xSecondary );
\r
274 /* We need to wait a little to ensure the other task executes. */
\r
275 while( xRunIndicator != bktRUN_INDICATOR )
\r
277 /* The other task has not yet executed. */
\r
278 vTaskDelay( bktSHORT_WAIT );
\r
280 /* Make sure the other task is blocked on the queue. */
\r
281 vTaskDelay( bktSHORT_WAIT );
\r
284 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
286 /* Now when we make space on the queue the other task should wake
\r
287 but not execute as this task has higher priority. */
\r
288 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
290 xErrorOccurred = pdTRUE;
\r
293 /* Now fill the queue again before the other task gets a chance to
\r
294 execute. If the other task had executed we would find the queue
\r
295 full ourselves, and the other task have set xRunIndicator. */
\r
296 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
298 xErrorOccurred = pdTRUE;
\r
301 if( xRunIndicator == bktRUN_INDICATOR )
\r
303 /* The other task should not have executed. */
\r
304 xErrorOccurred = pdTRUE;
\r
307 /* Raise the priority of the other task so it executes and blocks
\r
308 on the queue again. */
\r
309 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
311 /* The other task should now have re-blocked without exiting the
\r
313 if( xRunIndicator == bktRUN_INDICATOR )
\r
315 /* The other task should not have executed outside of the
\r
317 xErrorOccurred = pdTRUE;
\r
320 /* Set the priority back down. */
\r
321 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
324 /* Let the other task timeout. When it unblockes it will check that it
\r
325 unblocked at the correct time, then suspend itself. */
\r
326 while( xRunIndicator != bktRUN_INDICATOR )
\r
328 vTaskDelay( bktSHORT_WAIT );
\r
330 vTaskDelay( bktSHORT_WAIT );
\r
333 #if configUSE_PREEMPTION == 0
\r
337 /*********************************************************************
\r
340 As per test 3 - but with the send and receive the other way around.
\r
341 The other task blocks attempting to read from the queue.
\r
343 Empty the queue. We should find that it is full. */
\r
344 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
346 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
348 xErrorOccurred = pdTRUE;
\r
352 /* Wake the other task so it blocks attempting to read from the
\r
353 already empty queue. */
\r
354 vTaskResume( xSecondary );
\r
356 /* We need to wait a little to ensure the other task executes. */
\r
357 while( xRunIndicator != bktRUN_INDICATOR )
\r
359 vTaskDelay( bktSHORT_WAIT );
\r
361 vTaskDelay( bktSHORT_WAIT );
\r
364 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
366 /* Now when we place an item on the queue the other task should
\r
367 wake but not execute as this task has higher priority. */
\r
368 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
370 xErrorOccurred = pdTRUE;
\r
373 /* Now empty the queue again before the other task gets a chance to
\r
374 execute. If the other task had executed we would find the queue
\r
375 empty ourselves, and the other task would be suspended. */
\r
376 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
378 xErrorOccurred = pdTRUE;
\r
381 if( xRunIndicator == bktRUN_INDICATOR )
\r
383 /* The other task should not have executed. */
\r
384 xErrorOccurred = pdTRUE;
\r
387 /* Raise the priority of the other task so it executes and blocks
\r
388 on the queue again. */
\r
389 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
391 /* The other task should now have re-blocked without exiting the
\r
393 if( xRunIndicator == bktRUN_INDICATOR )
\r
395 /* The other task should not have executed outside of the
\r
397 xErrorOccurred = pdTRUE;
\r
399 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
402 /* Let the other task timeout. When it unblockes it will check that it
\r
403 unblocked at the correct time, then suspend itself. */
\r
404 while( xRunIndicator != bktRUN_INDICATOR )
\r
406 vTaskDelay( bktSHORT_WAIT );
\r
408 vTaskDelay( bktSHORT_WAIT );
\r
413 /*-----------------------------------------------------------*/
\r
415 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
417 portTickType xTimeWhenBlocking, xBlockedTime;
\r
418 portBASE_TYPE xData;
\r
421 void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
\r
423 const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
\r
425 /* Queue a message for printing to say the task has started. */
\r
426 vPrintDisplayMessage( &pcTaskStartMsg );
\r
429 ( void ) pvParameters;
\r
433 /*********************************************************************
\r
436 This task does does not participate in these tests. */
\r
437 vTaskSuspend( NULL );
\r
439 /*********************************************************************
\r
442 The first thing we do is attempt to read from the queue. It should be
\r
443 full so we block. Note the time before we block so we can check the
\r
444 wake time is as per that expected. */
\r
445 portENTER_CRITICAL();
\r
447 xTimeWhenBlocking = xTaskGetTickCount();
\r
449 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
450 anything on the queue. */
\r
452 xRunIndicator = bktRUN_INDICATOR;
\r
453 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
455 xErrorOccurred = pdTRUE;
\r
458 /* How long were we inside the send function? */
\r
459 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
461 portEXIT_CRITICAL();
\r
463 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
464 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
466 xErrorOccurred = pdTRUE;
\r
469 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
470 either. A margin is permitted as we would not necessarily run as
\r
471 soon as we unblocked. */
\r
472 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
474 xErrorOccurred = pdTRUE;
\r
477 /* Suspend ready for test 3. */
\r
478 xRunIndicator = bktRUN_INDICATOR;
\r
479 vTaskSuspend( NULL );
\r
481 /*********************************************************************
\r
484 As per test three, but with the send and receive reversed. */
\r
485 portENTER_CRITICAL();
\r
487 xTimeWhenBlocking = xTaskGetTickCount();
\r
489 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
490 anything on the queue. */
\r
491 xRunIndicator = bktRUN_INDICATOR;
\r
492 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
494 xErrorOccurred = pdTRUE;
\r
497 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
499 portEXIT_CRITICAL();
\r
501 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
502 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
504 xErrorOccurred = pdTRUE;
\r
507 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
508 either. A margin is permitted as we would not necessarily run as soon
\r
509 as we unblocked. */
\r
510 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
512 xErrorOccurred = pdTRUE;
\r
515 xRunIndicator = bktRUN_INDICATOR;
\r
517 xSecondaryCycles++;
\r
520 /*-----------------------------------------------------------*/
\r
522 portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
\r
524 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
525 portBASE_TYPE xReturn = pdPASS;
\r
527 /* Have both tasks performed at least one cycle since this function was
\r
529 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
534 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
539 if( xErrorOccurred == pdTRUE )
\r
544 xLastSecondaryCycleCount = xSecondaryCycles;
\r
545 xLastPrimaryCycleCount = xPrimaryCycles;
\r