2 FreeRTOS V9.0.0rc2 - Copyright (C) 2016 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 This file is part of the FreeRTOS distribution.
\r
9 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
10 the terms of the GNU General Public License (version 2) as published by the
\r
11 Free Software Foundation >>>> AND MODIFIED BY <<<< the FreeRTOS exception.
\r
13 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
71 * This file contains some test scenarios that ensure tasks do not exit queue
\r
72 * send or receive functions prematurely. A description of the tests is
\r
73 * included within the code.
\r
76 /* Kernel includes. */
\r
77 #include "FreeRTOS.h"
\r
81 /* Demo includes. */
\r
82 #include "blocktim.h"
\r
84 /* Task priorities. Allow these to be overridden. */
\r
85 #ifndef bktPRIMARY_PRIORITY
\r
86 #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
\r
89 #ifndef bktSECONDARY_PRIORITY
\r
90 #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
\r
93 /* Task behaviour. */
\r
94 #define bktQUEUE_LENGTH ( 5 )
\r
95 #define bktSHORT_WAIT pdMS_TO_TICKS( ( TickType_t ) 20 )
\r
96 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
97 #define bktALLOWABLE_MARGIN ( 15 )
\r
98 #define bktTIME_TO_BLOCK ( 175 )
\r
99 #define bktDONT_BLOCK ( ( TickType_t ) 0 )
\r
100 #define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 )
\r
102 /*-----------------------------------------------------------*/
\r
105 * The two test tasks. Their behaviour is commented within the functions.
\r
107 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
108 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
111 * Very basic tests to verify the block times are as expected.
\r
113 static void prvBasicDelayTests( void );
\r
115 /*-----------------------------------------------------------*/
\r
117 /* The queue on which the tasks block. */
\r
118 static QueueHandle_t xTestQueue;
\r
120 /* Handle to the secondary task is required by the primary task for calls
\r
121 to vTaskSuspend/Resume(). */
\r
122 static TaskHandle_t xSecondary;
\r
124 /* Used to ensure that tasks are still executing without error. */
\r
125 static volatile BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
126 static volatile BaseType_t xErrorOccurred = pdFALSE;
\r
128 /* Provides a simple mechanism for the primary task to know when the
\r
129 secondary task has executed. */
\r
130 static volatile UBaseType_t xRunIndicator;
\r
132 /*-----------------------------------------------------------*/
\r
134 void vCreateBlockTimeTasks( void )
\r
136 /* Create the queue on which the two tasks block. */
\r
137 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) );
\r
139 if( xTestQueue != NULL )
\r
141 /* vQueueAddToRegistry() adds the queue to the queue registry, if one
\r
142 is in use. The queue registry is provided as a means for kernel aware
\r
143 debuggers to locate queues and has no purpose if a kernel aware
\r
144 debugger is not being used. The call to vQueueAddToRegistry() will be
\r
145 removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
\r
146 defined or is defined to be less than 1. */
\r
147 vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" );
\r
149 /* Create the two test tasks. */
\r
150 xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
151 xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
154 /*-----------------------------------------------------------*/
\r
156 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
158 BaseType_t xItem, xData;
\r
159 TickType_t xTimeWhenBlocking;
\r
160 TickType_t xTimeToBlock, xBlockedTime;
\r
162 ( void ) pvParameters;
\r
166 /*********************************************************************
\r
169 Basic vTaskDelay() and vTaskDelayUntil() tests. */
\r
170 prvBasicDelayTests();
\r
173 /*********************************************************************
\r
176 Simple block time wakeup test on queue receives. */
\r
177 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
179 /* The queue is empty. Attempt to read from the queue using a block
\r
180 time. When we wake, ensure the delta in time is as expected. */
\r
181 xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
\r
183 xTimeWhenBlocking = xTaskGetTickCount();
\r
185 /* We should unblock after xTimeToBlock having not received
\r
186 anything on the queue. */
\r
187 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
189 xErrorOccurred = pdTRUE;
\r
192 /* How long were we blocked for? */
\r
193 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
195 if( xBlockedTime < xTimeToBlock )
\r
197 /* Should not have blocked for less than we requested. */
\r
198 xErrorOccurred = pdTRUE;
\r
201 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
203 /* Should not have blocked for longer than we requested,
\r
204 although we would not necessarily run as soon as we were
\r
205 unblocked so a margin is allowed. */
\r
206 xErrorOccurred = pdTRUE;
\r
210 /*********************************************************************
\r
213 Simple block time wakeup test on queue sends.
\r
215 First fill the queue. It should be empty so all sends should pass. */
\r
216 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
218 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
220 xErrorOccurred = pdTRUE;
\r
223 #if configUSE_PREEMPTION == 0
\r
228 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
230 /* The queue is full. Attempt to write to the queue using a block
\r
231 time. When we wake, ensure the delta in time is as expected. */
\r
232 xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
\r
234 xTimeWhenBlocking = xTaskGetTickCount();
\r
236 /* We should unblock after xTimeToBlock having not received
\r
237 anything on the queue. */
\r
238 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
240 xErrorOccurred = pdTRUE;
\r
243 /* How long were we blocked for? */
\r
244 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
246 if( xBlockedTime < xTimeToBlock )
\r
248 /* Should not have blocked for less than we requested. */
\r
249 xErrorOccurred = pdTRUE;
\r
252 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
254 /* Should not have blocked for longer than we requested,
\r
255 although we would not necessarily run as soon as we were
\r
256 unblocked so a margin is allowed. */
\r
257 xErrorOccurred = pdTRUE;
\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( xQueueReceive( 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( xQueueSend( 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
336 /*********************************************************************
\r
339 As per test 3 - but with the send and receive the other way around.
\r
340 The other task blocks attempting to read from the queue.
\r
342 Empty the queue. We should find that it is full. */
\r
343 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
345 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
347 xErrorOccurred = pdTRUE;
\r
351 /* Wake the other task so it blocks attempting to read from the
\r
352 already empty queue. */
\r
353 vTaskResume( xSecondary );
\r
355 /* We need to wait a little to ensure the other task executes. */
\r
356 while( xRunIndicator != bktRUN_INDICATOR )
\r
358 vTaskDelay( bktSHORT_WAIT );
\r
360 vTaskDelay( bktSHORT_WAIT );
\r
363 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
365 /* Now when we place an item on the queue the other task should
\r
366 wake but not execute as this task has higher priority. */
\r
367 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
369 xErrorOccurred = pdTRUE;
\r
372 /* Now empty the queue again before the other task gets a chance to
\r
373 execute. If the other task had executed we would find the queue
\r
374 empty ourselves, and the other task would be suspended. */
\r
375 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
377 xErrorOccurred = pdTRUE;
\r
380 if( xRunIndicator == bktRUN_INDICATOR )
\r
382 /* The other task should not have executed. */
\r
383 xErrorOccurred = pdTRUE;
\r
386 /* Raise the priority of the other task so it executes and blocks
\r
387 on the queue again. */
\r
388 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
390 /* The other task should now have re-blocked without exiting the
\r
392 if( xRunIndicator == bktRUN_INDICATOR )
\r
394 /* The other task should not have executed outside of the
\r
396 xErrorOccurred = pdTRUE;
\r
398 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
401 /* Let the other task timeout. When it unblockes it will check that it
\r
402 unblocked at the correct time, then suspend itself. */
\r
403 while( xRunIndicator != bktRUN_INDICATOR )
\r
405 vTaskDelay( bktSHORT_WAIT );
\r
407 vTaskDelay( bktSHORT_WAIT );
\r
412 /*-----------------------------------------------------------*/
\r
414 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
416 TickType_t xTimeWhenBlocking, xBlockedTime;
\r
419 ( void ) pvParameters;
\r
423 /*********************************************************************
\r
426 This task does not participate in these tests. */
\r
427 vTaskSuspend( NULL );
\r
429 /*********************************************************************
\r
432 The first thing we do is attempt to read from the queue. It should be
\r
433 full so we block. Note the time before we block so we can check the
\r
434 wake time is as per that expected. */
\r
435 xTimeWhenBlocking = xTaskGetTickCount();
\r
437 /* We should unblock after bktTIME_TO_BLOCK having not sent anything to
\r
440 xRunIndicator = bktRUN_INDICATOR;
\r
441 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
443 xErrorOccurred = pdTRUE;
\r
446 /* How long were we inside the send function? */
\r
447 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
449 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
450 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
452 xErrorOccurred = pdTRUE;
\r
455 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
456 either. A margin is permitted as we would not necessarily run as
\r
457 soon as we unblocked. */
\r
458 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
460 xErrorOccurred = pdTRUE;
\r
463 /* Suspend ready for test 3. */
\r
464 xRunIndicator = bktRUN_INDICATOR;
\r
465 vTaskSuspend( NULL );
\r
467 /*********************************************************************
\r
470 As per test three, but with the send and receive reversed. */
\r
471 xTimeWhenBlocking = xTaskGetTickCount();
\r
473 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
474 anything on the queue. */
\r
475 xRunIndicator = bktRUN_INDICATOR;
\r
476 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
478 xErrorOccurred = pdTRUE;
\r
481 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
483 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
484 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
486 xErrorOccurred = pdTRUE;
\r
489 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
490 either. A margin is permitted as we would not necessarily run as soon
\r
491 as we unblocked. */
\r
492 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
494 xErrorOccurred = pdTRUE;
\r
497 xRunIndicator = bktRUN_INDICATOR;
\r
499 xSecondaryCycles++;
\r
502 /*-----------------------------------------------------------*/
\r
504 static void prvBasicDelayTests( void )
\r
506 TickType_t xPreTime, xPostTime, x, xLastUnblockTime, xExpectedUnblockTime;
\r
507 const TickType_t xPeriod = 75, xCycles = 5, xAllowableMargin = ( bktALLOWABLE_MARGIN >> 1 );
\r
509 /* Temporarily increase priority so the timing is more accurate, but not so
\r
510 high as to disrupt the timer tests. */
\r
511 vTaskPrioritySet( NULL, configTIMER_TASK_PRIORITY - 1 );
\r
513 /* Crude check to too that vTaskDelay() blocks for the expected period. */
\r
514 xPreTime = xTaskGetTickCount();
\r
515 vTaskDelay( bktTIME_TO_BLOCK );
\r
516 xPostTime = xTaskGetTickCount();
\r
518 /* The priority is higher, so the allowable margin is halved when compared
\r
519 to the other tests in this file. */
\r
520 if( ( xPostTime - xPreTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
\r
522 xErrorOccurred = pdTRUE;
\r
525 /* Now crude tests to check the vTaskDelayUntil() functionality. */
\r
526 xPostTime = xTaskGetTickCount();
\r
527 xLastUnblockTime = xPostTime;
\r
529 for( x = 0; x < xCycles; x++ )
\r
531 /* Calculate the next expected unblock time from the time taken before
\r
532 this loop was entered. */
\r
533 xExpectedUnblockTime = xPostTime + ( x * xPeriod );
\r
535 vTaskDelayUntil( &xLastUnblockTime, xPeriod );
\r
537 if( ( xTaskGetTickCount() - xExpectedUnblockTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
\r
539 xErrorOccurred = pdTRUE;
\r
545 /* Reset to the original task priority ready for the other tests. */
\r
546 vTaskPrioritySet( NULL, bktPRIMARY_PRIORITY );
\r
548 /*-----------------------------------------------------------*/
\r
550 BaseType_t xAreBlockTimeTestTasksStillRunning( void )
\r
552 static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
553 BaseType_t xReturn = pdPASS;
\r
555 /* Have both tasks performed at least one cycle since this function was
\r
557 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
562 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
567 if( xErrorOccurred == pdTRUE )
\r
572 xLastSecondaryCycleCount = xSecondaryCycles;
\r
573 xLastPrimaryCycleCount = xPrimaryCycles;
\r