2 FreeRTOS V8.2.1 - Copyright (C) 2015 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 is a version of BlockTim.c that uses the light weight API.
\r
73 * This file contains some test scenarios that ensure tasks do not exit queue
\r
74 * send or receive functions prematurely. A description of the tests is
\r
75 * included within the code.
\r
78 /* Kernel includes. */
\r
79 #include "FreeRTOS.h"
\r
83 /* Demo includes. */
\r
84 #include "AltBlock.h"
\r
86 /* Task priorities. */
\r
87 #define bktPRIMARY_PRIORITY ( 3 )
\r
88 #define bktSECONDARY_PRIORITY ( 2 )
\r
90 /* Task behaviour. */
\r
91 #define bktQUEUE_LENGTH ( 5 )
\r
92 #define bktSHORT_WAIT ( ( ( TickType_t ) 20 ) / portTICK_PERIOD_MS )
\r
93 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
94 #define bktALLOWABLE_MARGIN ( 12 )
\r
95 #define bktTIME_TO_BLOCK ( 175 )
\r
96 #define bktDONT_BLOCK ( ( TickType_t ) 0 )
\r
97 #define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 )
\r
99 /* The queue on which the tasks block. */
\r
100 static QueueHandle_t xTestQueue;
\r
102 /* Handle to the secondary task is required by the primary task for calls
\r
103 to vTaskSuspend/Resume(). */
\r
104 static TaskHandle_t xSecondary;
\r
106 /* Used to ensure that tasks are still executing without error. */
\r
107 static BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
108 static BaseType_t xErrorOccurred = pdFALSE;
\r
110 /* Provides a simple mechanism for the primary task to know when the
\r
111 secondary task has executed. */
\r
112 static volatile UBaseType_t xRunIndicator;
\r
114 /* The two test tasks. Their behaviour is commented within the files. */
\r
115 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
116 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
118 /*-----------------------------------------------------------*/
\r
120 void vCreateAltBlockTimeTasks( void )
\r
122 /* Create the queue on which the two tasks block. */
\r
123 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) );
\r
125 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
126 in use. The queue registry is provided as a means for kernel aware
\r
127 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
128 is not being used. The call to vQueueAddToRegistry() will be removed
\r
129 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
130 defined to be less than 1. */
\r
131 vQueueAddToRegistry( xTestQueue, "AltBlockQueue" );
\r
134 /* Create the two test tasks. */
\r
135 xTaskCreate( vPrimaryBlockTimeTestTask, "FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
136 xTaskCreate( vSecondaryBlockTimeTestTask, "FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
138 /*-----------------------------------------------------------*/
\r
140 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
142 BaseType_t xItem, xData;
\r
143 TickType_t xTimeWhenBlocking;
\r
144 TickType_t xTimeToBlock, xBlockedTime;
\r
147 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
149 const char * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
\r
151 /* Queue a message for printing to say the task has started. */
\r
152 vPrintDisplayMessage( &pcTaskStartMsg );
\r
155 ( void ) pvParameters;
\r
159 /*********************************************************************
\r
162 Simple block time wakeup test on queue receives. */
\r
163 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
165 /* The queue is empty. Attempt to read from the queue using a block
\r
166 time. When we wake, ensure the delta in time is as expected. */
\r
167 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
169 /* A critical section is used to minimise the jitter in the time
\r
171 portENTER_CRITICAL();
\r
173 xTimeWhenBlocking = xTaskGetTickCount();
\r
175 /* We should unblock after xTimeToBlock having not received
\r
176 anything on the queue. */
\r
177 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
179 xErrorOccurred = pdTRUE;
\r
182 /* How long were we blocked for? */
\r
183 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
185 portEXIT_CRITICAL();
\r
187 if( xBlockedTime < xTimeToBlock )
\r
189 /* Should not have blocked for less than we requested. */
\r
190 xErrorOccurred = pdTRUE;
\r
193 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
195 /* Should not have blocked for longer than we requested,
\r
196 although we would not necessarily run as soon as we were
\r
197 unblocked so a margin is allowed. */
\r
198 xErrorOccurred = pdTRUE;
\r
203 #if configUSE_PREEMPTION == 0
\r
208 /*********************************************************************
\r
211 Simple block time wakeup test on queue sends.
\r
213 First fill the queue. It should be empty so all sends should pass. */
\r
214 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
216 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
218 xErrorOccurred = pdTRUE;
\r
222 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
224 /* The queue is full. Attempt to write to the queue using a block
\r
225 time. When we wake, ensure the delta in time is as expected. */
\r
226 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
228 portENTER_CRITICAL();
\r
230 xTimeWhenBlocking = xTaskGetTickCount();
\r
232 /* We should unblock after xTimeToBlock having not received
\r
233 anything on the queue. */
\r
234 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
236 xErrorOccurred = pdTRUE;
\r
239 /* How long were we blocked for? */
\r
240 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
242 portEXIT_CRITICAL();
\r
244 if( xBlockedTime < xTimeToBlock )
\r
246 /* Should not have blocked for less than we requested. */
\r
247 xErrorOccurred = pdTRUE;
\r
250 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
252 /* Should not have blocked for longer than we requested,
\r
253 although we would not necessarily run as soon as we were
\r
254 unblocked so a margin is allowed. */
\r
255 xErrorOccurred = pdTRUE;
\r
259 #if configUSE_PREEMPTION == 0
\r
264 /*********************************************************************
\r
267 Wake the other task, it will block attempting to post to the queue.
\r
268 When we read from the queue the other task will wake, but before it
\r
269 can run we will post to the queue again. When the other task runs it
\r
270 will find the queue still full, even though it was woken. It should
\r
271 recognise that its block time has not expired and return to block for
\r
272 the remains of its block time.
\r
274 Wake the other task so it blocks attempting to post to the already
\r
277 vTaskResume( xSecondary );
\r
279 /* We need to wait a little to ensure the other task executes. */
\r
280 while( xRunIndicator != bktRUN_INDICATOR )
\r
282 /* The other task has not yet executed. */
\r
283 vTaskDelay( bktSHORT_WAIT );
\r
285 /* Make sure the other task is blocked on the queue. */
\r
286 vTaskDelay( bktSHORT_WAIT );
\r
289 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
291 /* Now when we make space on the queue the other task should wake
\r
292 but not execute as this task has higher priority. */
\r
293 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
295 xErrorOccurred = pdTRUE;
\r
298 /* Now fill the queue again before the other task gets a chance to
\r
299 execute. If the other task had executed we would find the queue
\r
300 full ourselves, and the other task have set xRunIndicator. */
\r
301 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
303 xErrorOccurred = pdTRUE;
\r
306 if( xRunIndicator == bktRUN_INDICATOR )
\r
308 /* The other task should not have executed. */
\r
309 xErrorOccurred = pdTRUE;
\r
312 /* Raise the priority of the other task so it executes and blocks
\r
313 on the queue again. */
\r
314 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
316 /* The other task should now have re-blocked without exiting the
\r
318 if( xRunIndicator == bktRUN_INDICATOR )
\r
320 /* The other task should not have executed outside of the
\r
322 xErrorOccurred = pdTRUE;
\r
325 /* Set the priority back down. */
\r
326 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
329 /* Let the other task timeout. When it unblockes it will check that it
\r
330 unblocked at the correct time, then suspend itself. */
\r
331 while( xRunIndicator != bktRUN_INDICATOR )
\r
333 vTaskDelay( bktSHORT_WAIT );
\r
335 vTaskDelay( bktSHORT_WAIT );
\r
338 #if configUSE_PREEMPTION == 0
\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( xQueueAltReceive( 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( xQueueAltSendToBack( 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( xQueueAltReceive( 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
426 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
428 const char * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
\r
430 /* Queue a message for printing to say the task has started. */
\r
431 vPrintDisplayMessage( &pcTaskStartMsg );
\r
434 ( void ) pvParameters;
\r
438 /*********************************************************************
\r
441 This task does does not participate in these tests. */
\r
442 vTaskSuspend( NULL );
\r
444 /*********************************************************************
\r
447 The first thing we do is attempt to read from the queue. It should be
\r
448 full so we block. Note the time before we block so we can check the
\r
449 wake time is as per that expected. */
\r
450 portENTER_CRITICAL();
\r
452 xTimeWhenBlocking = xTaskGetTickCount();
\r
454 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
455 anything on the queue. */
\r
457 xRunIndicator = bktRUN_INDICATOR;
\r
458 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
460 xErrorOccurred = pdTRUE;
\r
463 /* How long were we inside the send function? */
\r
464 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
466 portEXIT_CRITICAL();
\r
468 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
469 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
471 xErrorOccurred = pdTRUE;
\r
474 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
475 either. A margin is permitted as we would not necessarily run as
\r
476 soon as we unblocked. */
\r
477 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
479 xErrorOccurred = pdTRUE;
\r
482 /* Suspend ready for test 3. */
\r
483 xRunIndicator = bktRUN_INDICATOR;
\r
484 vTaskSuspend( NULL );
\r
486 /*********************************************************************
\r
489 As per test three, but with the send and receive reversed. */
\r
490 portENTER_CRITICAL();
\r
492 xTimeWhenBlocking = xTaskGetTickCount();
\r
494 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
495 anything on the queue. */
\r
496 xRunIndicator = bktRUN_INDICATOR;
\r
497 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
499 xErrorOccurred = pdTRUE;
\r
502 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
504 portEXIT_CRITICAL();
\r
506 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
507 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
509 xErrorOccurred = pdTRUE;
\r
512 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
513 either. A margin is permitted as we would not necessarily run as soon
\r
514 as we unblocked. */
\r
515 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
517 xErrorOccurred = pdTRUE;
\r
520 xRunIndicator = bktRUN_INDICATOR;
\r
522 xSecondaryCycles++;
\r
525 /*-----------------------------------------------------------*/
\r
527 BaseType_t xAreAltBlockTimeTestTasksStillRunning( void )
\r
529 static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
530 BaseType_t xReturn = pdPASS;
\r
532 /* Have both tasks performed at least one cycle since this function was
\r
534 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
539 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
544 if( xErrorOccurred == pdTRUE )
\r
549 xLastSecondaryCycleCount = xSecondaryCycles;
\r
550 xLastPrimaryCycleCount = xPrimaryCycles;
\r