2 FreeRTOS V9.0.0 - 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 /* In case the demo does not have software timers enabled, as this file uses
\r
103 the configTIMER_TASK_PRIORITY setting. */
\r
104 #ifndef configTIMER_TASK_PRIORITY
\r
105 #define configTIMER_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
\r
108 /*-----------------------------------------------------------*/
\r
111 * The two test tasks. Their behaviour is commented within the functions.
\r
113 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
114 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
117 * Very basic tests to verify the block times are as expected.
\r
119 static void prvBasicDelayTests( void );
\r
121 /*-----------------------------------------------------------*/
\r
123 /* The queue on which the tasks block. */
\r
124 static QueueHandle_t xTestQueue;
\r
126 /* Handle to the secondary task is required by the primary task for calls
\r
127 to vTaskSuspend/Resume(). */
\r
128 static TaskHandle_t xSecondary;
\r
130 /* Used to ensure that tasks are still executing without error. */
\r
131 static volatile BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
132 static volatile BaseType_t xErrorOccurred = pdFALSE;
\r
134 /* Provides a simple mechanism for the primary task to know when the
\r
135 secondary task has executed. */
\r
136 static volatile UBaseType_t xRunIndicator;
\r
138 /*-----------------------------------------------------------*/
\r
140 void vCreateBlockTimeTasks( void )
\r
142 /* Create the queue on which the two tasks block. */
\r
143 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) );
\r
145 if( xTestQueue != NULL )
\r
147 /* vQueueAddToRegistry() adds the queue to the queue registry, if one
\r
148 is in use. The queue registry is provided as a means for kernel aware
\r
149 debuggers to locate queues and has no purpose if a kernel aware
\r
150 debugger is not being used. The call to vQueueAddToRegistry() will be
\r
151 removed by the pre-processor if configQUEUE_REGISTRY_SIZE is not
\r
152 defined or is defined to be less than 1. */
\r
153 vQueueAddToRegistry( xTestQueue, "Block_Time_Queue" );
\r
155 /* Create the two test tasks. */
\r
156 xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
157 xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
160 /*-----------------------------------------------------------*/
\r
162 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
164 BaseType_t xItem, xData;
\r
165 TickType_t xTimeWhenBlocking;
\r
166 TickType_t xTimeToBlock, xBlockedTime;
\r
168 ( void ) pvParameters;
\r
172 /*********************************************************************
\r
175 Basic vTaskDelay() and vTaskDelayUntil() tests. */
\r
176 prvBasicDelayTests();
\r
179 /*********************************************************************
\r
182 Simple block time wakeup test on queue receives. */
\r
183 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
185 /* The queue is empty. Attempt to read from the queue using a block
\r
186 time. When we wake, ensure the delta in time is as expected. */
\r
187 xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
\r
189 xTimeWhenBlocking = xTaskGetTickCount();
\r
191 /* We should unblock after xTimeToBlock having not received
\r
192 anything on the queue. */
\r
193 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
195 xErrorOccurred = pdTRUE;
\r
198 /* How long were we blocked for? */
\r
199 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
201 if( xBlockedTime < xTimeToBlock )
\r
203 /* Should not have blocked for less than we requested. */
\r
204 xErrorOccurred = pdTRUE;
\r
207 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
209 /* Should not have blocked for longer than we requested,
\r
210 although we would not necessarily run as soon as we were
\r
211 unblocked so a margin is allowed. */
\r
212 xErrorOccurred = pdTRUE;
\r
216 /*********************************************************************
\r
219 Simple block time wakeup test on queue sends.
\r
221 First fill the queue. It should be empty so all sends should pass. */
\r
222 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
224 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
226 xErrorOccurred = pdTRUE;
\r
229 #if configUSE_PREEMPTION == 0
\r
234 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
236 /* The queue is full. Attempt to write to the queue using a block
\r
237 time. When we wake, ensure the delta in time is as expected. */
\r
238 xTimeToBlock = ( TickType_t ) ( bktPRIMARY_BLOCK_TIME << xItem );
\r
240 xTimeWhenBlocking = xTaskGetTickCount();
\r
242 /* We should unblock after xTimeToBlock having not received
\r
243 anything on the queue. */
\r
244 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
246 xErrorOccurred = pdTRUE;
\r
249 /* How long were we blocked for? */
\r
250 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
252 if( xBlockedTime < xTimeToBlock )
\r
254 /* Should not have blocked for less than we requested. */
\r
255 xErrorOccurred = pdTRUE;
\r
258 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
260 /* Should not have blocked for longer than we requested,
\r
261 although we would not necessarily run as soon as we were
\r
262 unblocked so a margin is allowed. */
\r
263 xErrorOccurred = pdTRUE;
\r
267 /*********************************************************************
\r
270 Wake the other task, it will block attempting to post to the queue.
\r
271 When we read from the queue the other task will wake, but before it
\r
272 can run we will post to the queue again. When the other task runs it
\r
273 will find the queue still full, even though it was woken. It should
\r
274 recognise that its block time has not expired and return to block for
\r
275 the remains of its block time.
\r
277 Wake the other task so it blocks attempting to post to the already
\r
280 vTaskResume( xSecondary );
\r
282 /* We need to wait a little to ensure the other task executes. */
\r
283 while( xRunIndicator != bktRUN_INDICATOR )
\r
285 /* The other task has not yet executed. */
\r
286 vTaskDelay( bktSHORT_WAIT );
\r
288 /* Make sure the other task is blocked on the queue. */
\r
289 vTaskDelay( bktSHORT_WAIT );
\r
292 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
294 /* Now when we make space on the queue the other task should wake
\r
295 but not execute as this task has higher priority. */
\r
296 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
298 xErrorOccurred = pdTRUE;
\r
301 /* Now fill the queue again before the other task gets a chance to
\r
302 execute. If the other task had executed we would find the queue
\r
303 full ourselves, and the other task have set xRunIndicator. */
\r
304 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
306 xErrorOccurred = pdTRUE;
\r
309 if( xRunIndicator == bktRUN_INDICATOR )
\r
311 /* The other task should not have executed. */
\r
312 xErrorOccurred = pdTRUE;
\r
315 /* Raise the priority of the other task so it executes and blocks
\r
316 on the queue again. */
\r
317 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
319 /* The other task should now have re-blocked without exiting the
\r
321 if( xRunIndicator == bktRUN_INDICATOR )
\r
323 /* The other task should not have executed outside of the
\r
325 xErrorOccurred = pdTRUE;
\r
328 /* Set the priority back down. */
\r
329 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
332 /* Let the other task timeout. When it unblockes it will check that it
\r
333 unblocked at the correct time, then suspend itself. */
\r
334 while( xRunIndicator != bktRUN_INDICATOR )
\r
336 vTaskDelay( bktSHORT_WAIT );
\r
338 vTaskDelay( bktSHORT_WAIT );
\r
342 /*********************************************************************
\r
345 As per test 3 - but with the send and receive the other way around.
\r
346 The other task blocks attempting to read from the queue.
\r
348 Empty the queue. We should find that it is full. */
\r
349 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
351 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
353 xErrorOccurred = pdTRUE;
\r
357 /* Wake the other task so it blocks attempting to read from the
\r
358 already empty queue. */
\r
359 vTaskResume( xSecondary );
\r
361 /* We need to wait a little to ensure the other task executes. */
\r
362 while( xRunIndicator != bktRUN_INDICATOR )
\r
364 vTaskDelay( bktSHORT_WAIT );
\r
366 vTaskDelay( bktSHORT_WAIT );
\r
369 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
371 /* Now when we place an item on the queue the other task should
\r
372 wake but not execute as this task has higher priority. */
\r
373 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
375 xErrorOccurred = pdTRUE;
\r
378 /* Now empty the queue again before the other task gets a chance to
\r
379 execute. If the other task had executed we would find the queue
\r
380 empty ourselves, and the other task would be suspended. */
\r
381 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
383 xErrorOccurred = pdTRUE;
\r
386 if( xRunIndicator == bktRUN_INDICATOR )
\r
388 /* The other task should not have executed. */
\r
389 xErrorOccurred = pdTRUE;
\r
392 /* Raise the priority of the other task so it executes and blocks
\r
393 on the queue again. */
\r
394 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
396 /* The other task should now have re-blocked without exiting the
\r
398 if( xRunIndicator == bktRUN_INDICATOR )
\r
400 /* The other task should not have executed outside of the
\r
402 xErrorOccurred = pdTRUE;
\r
404 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
407 /* Let the other task timeout. When it unblockes it will check that it
\r
408 unblocked at the correct time, then suspend itself. */
\r
409 while( xRunIndicator != bktRUN_INDICATOR )
\r
411 vTaskDelay( bktSHORT_WAIT );
\r
413 vTaskDelay( bktSHORT_WAIT );
\r
418 /*-----------------------------------------------------------*/
\r
420 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
422 TickType_t xTimeWhenBlocking, xBlockedTime;
\r
425 ( void ) pvParameters;
\r
429 /*********************************************************************
\r
432 This task does not participate in these tests. */
\r
433 vTaskSuspend( NULL );
\r
435 /*********************************************************************
\r
438 The first thing we do is attempt to read from the queue. It should be
\r
439 full so we block. Note the time before we block so we can check the
\r
440 wake time is as per that expected. */
\r
441 xTimeWhenBlocking = xTaskGetTickCount();
\r
443 /* We should unblock after bktTIME_TO_BLOCK having not sent anything to
\r
446 xRunIndicator = bktRUN_INDICATOR;
\r
447 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
449 xErrorOccurred = pdTRUE;
\r
452 /* How long were we inside the send function? */
\r
453 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
455 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
456 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
458 xErrorOccurred = pdTRUE;
\r
461 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
462 either. A margin is permitted as we would not necessarily run as
\r
463 soon as we unblocked. */
\r
464 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
466 xErrorOccurred = pdTRUE;
\r
469 /* Suspend ready for test 3. */
\r
470 xRunIndicator = bktRUN_INDICATOR;
\r
471 vTaskSuspend( NULL );
\r
473 /*********************************************************************
\r
476 As per test three, but with the send and receive reversed. */
\r
477 xTimeWhenBlocking = xTaskGetTickCount();
\r
479 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
480 anything on the queue. */
\r
481 xRunIndicator = bktRUN_INDICATOR;
\r
482 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
484 xErrorOccurred = pdTRUE;
\r
487 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
489 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
490 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
492 xErrorOccurred = pdTRUE;
\r
495 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
496 either. A margin is permitted as we would not necessarily run as soon
\r
497 as we unblocked. */
\r
498 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
500 xErrorOccurred = pdTRUE;
\r
503 xRunIndicator = bktRUN_INDICATOR;
\r
505 xSecondaryCycles++;
\r
508 /*-----------------------------------------------------------*/
\r
510 static void prvBasicDelayTests( void )
\r
512 TickType_t xPreTime, xPostTime, x, xLastUnblockTime, xExpectedUnblockTime;
\r
513 const TickType_t xPeriod = 75, xCycles = 5, xAllowableMargin = ( bktALLOWABLE_MARGIN >> 1 );
\r
515 /* Temporarily increase priority so the timing is more accurate, but not so
\r
516 high as to disrupt the timer tests. */
\r
517 vTaskPrioritySet( NULL, configTIMER_TASK_PRIORITY - 1 );
\r
519 /* Crude check to too that vTaskDelay() blocks for the expected period. */
\r
520 xPreTime = xTaskGetTickCount();
\r
521 vTaskDelay( bktTIME_TO_BLOCK );
\r
522 xPostTime = xTaskGetTickCount();
\r
524 /* The priority is higher, so the allowable margin is halved when compared
\r
525 to the other tests in this file. */
\r
526 if( ( xPostTime - xPreTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
\r
528 xErrorOccurred = pdTRUE;
\r
531 /* Now crude tests to check the vTaskDelayUntil() functionality. */
\r
532 xPostTime = xTaskGetTickCount();
\r
533 xLastUnblockTime = xPostTime;
\r
535 for( x = 0; x < xCycles; x++ )
\r
537 /* Calculate the next expected unblock time from the time taken before
\r
538 this loop was entered. */
\r
539 xExpectedUnblockTime = xPostTime + ( x * xPeriod );
\r
541 vTaskDelayUntil( &xLastUnblockTime, xPeriod );
\r
543 if( ( xTaskGetTickCount() - xExpectedUnblockTime ) > ( bktTIME_TO_BLOCK + xAllowableMargin ) )
\r
545 xErrorOccurred = pdTRUE;
\r
551 /* Reset to the original task priority ready for the other tests. */
\r
552 vTaskPrioritySet( NULL, bktPRIMARY_PRIORITY );
\r
554 /*-----------------------------------------------------------*/
\r
556 BaseType_t xAreBlockTimeTestTasksStillRunning( void )
\r
558 static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
559 BaseType_t xReturn = pdPASS;
\r
561 /* Have both tasks performed at least one cycle since this function was
\r
563 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
568 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
573 if( xErrorOccurred == pdTRUE )
\r
578 xLastSecondaryCycleCount = xSecondaryCycles;
\r
579 xLastPrimaryCycleCount = xPrimaryCycles;
\r