2 FreeRTOS V8.0.0:rc1 - Copyright (C) 2014 Real Time Engineers Ltd.
\r
5 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS provides completely free yet professionally developed, *
\r
10 * robust, strictly quality controlled, supported, and cross *
\r
11 * platform software that has become a de facto standard. *
\r
13 * Help yourself get started quickly and support the FreeRTOS *
\r
14 * project by purchasing a FreeRTOS tutorial book, reference *
\r
15 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
19 ***************************************************************************
\r
21 This file is part of the FreeRTOS distribution.
\r
23 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
24 the terms of the GNU General Public License (version 2) as published by the
\r
25 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
27 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
28 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
29 >>! the source code for proprietary components outside of the FreeRTOS
\r
32 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
33 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
34 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
35 link: http://www.freertos.org/a00114.html
\r
39 ***************************************************************************
\r
41 * Having a problem? Start by reading the FAQ "My application does *
\r
42 * not run, what could be wrong?" *
\r
44 * http://www.FreeRTOS.org/FAQHelp.html *
\r
46 ***************************************************************************
\r
48 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
49 license and Real Time Engineers Ltd. contact details.
\r
51 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
52 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
53 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
55 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
56 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
57 licenses offer ticketed support, indemnification and middleware.
\r
59 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
60 engineered and independently SIL3 certified version for use in safety and
\r
61 mission critical applications that require provable dependability.
\r
67 * This is a version of BlockTim.c that uses the light weight API.
\r
69 * This file contains some test scenarios that ensure tasks do not exit queue
\r
70 * send or receive functions prematurely. A description of the tests is
\r
71 * included within the code.
\r
74 /* Kernel includes. */
\r
75 #include "FreeRTOS.h"
\r
79 /* Demo includes. */
\r
80 #include "AltBlock.h"
\r
82 /* Task priorities. */
\r
83 #define bktPRIMARY_PRIORITY ( 3 )
\r
84 #define bktSECONDARY_PRIORITY ( 2 )
\r
86 /* Task behaviour. */
\r
87 #define bktQUEUE_LENGTH ( 5 )
\r
88 #define bktSHORT_WAIT ( ( ( TickType_t ) 20 ) / portTICK_PERIOD_MS )
\r
89 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
90 #define bktALLOWABLE_MARGIN ( 12 )
\r
91 #define bktTIME_TO_BLOCK ( 175 )
\r
92 #define bktDONT_BLOCK ( ( TickType_t ) 0 )
\r
93 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
95 /* The queue on which the tasks block. */
\r
96 static QueueHandle_t xTestQueue;
\r
98 /* Handle to the secondary task is required by the primary task for calls
\r
99 to vTaskSuspend/Resume(). */
\r
100 static TaskHandle_t xSecondary;
\r
102 /* Used to ensure that tasks are still executing without error. */
\r
103 static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
104 static portBASE_TYPE xErrorOccurred = pdFALSE;
\r
106 /* Provides a simple mechanism for the primary task to know when the
\r
107 secondary task has executed. */
\r
108 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
110 /* The two test tasks. Their behaviour is commented within the files. */
\r
111 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
112 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
114 /*-----------------------------------------------------------*/
\r
116 void vCreateAltBlockTimeTasks( void )
\r
118 /* Create the queue on which the two tasks block. */
\r
119 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
121 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
122 in use. The queue registry is provided as a means for kernel aware
\r
123 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
124 is not being used. The call to vQueueAddToRegistry() will be removed
\r
125 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
126 defined to be less than 1. */
\r
127 vQueueAddToRegistry( xTestQueue, "AltBlockQueue" );
\r
130 /* Create the two test tasks. */
\r
131 xTaskCreate( vPrimaryBlockTimeTestTask, "FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
132 xTaskCreate( vSecondaryBlockTimeTestTask, "FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
134 /*-----------------------------------------------------------*/
\r
136 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
138 portBASE_TYPE xItem, xData;
\r
139 TickType_t xTimeWhenBlocking;
\r
140 TickType_t xTimeToBlock, xBlockedTime;
\r
143 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
145 const char * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
\r
147 /* Queue a message for printing to say the task has started. */
\r
148 vPrintDisplayMessage( &pcTaskStartMsg );
\r
151 ( void ) pvParameters;
\r
155 /*********************************************************************
\r
158 Simple block time wakeup test on queue receives. */
\r
159 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
161 /* The queue is empty. Attempt to read from the queue using a block
\r
162 time. When we wake, ensure the delta in time is as expected. */
\r
163 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
165 /* A critical section is used to minimise the jitter in the time
\r
167 portENTER_CRITICAL();
\r
169 xTimeWhenBlocking = xTaskGetTickCount();
\r
171 /* We should unblock after xTimeToBlock having not received
\r
172 anything on the queue. */
\r
173 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
175 xErrorOccurred = pdTRUE;
\r
178 /* How long were we blocked for? */
\r
179 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
181 portEXIT_CRITICAL();
\r
183 if( xBlockedTime < xTimeToBlock )
\r
185 /* Should not have blocked for less than we requested. */
\r
186 xErrorOccurred = pdTRUE;
\r
189 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
191 /* Should not have blocked for longer than we requested,
\r
192 although we would not necessarily run as soon as we were
\r
193 unblocked so a margin is allowed. */
\r
194 xErrorOccurred = pdTRUE;
\r
199 #if configUSE_PREEMPTION == 0
\r
204 /*********************************************************************
\r
207 Simple block time wakeup test on queue sends.
\r
209 First fill the queue. It should be empty so all sends should pass. */
\r
210 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
212 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
214 xErrorOccurred = pdTRUE;
\r
218 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
220 /* The queue is full. Attempt to write to the queue using a block
\r
221 time. When we wake, ensure the delta in time is as expected. */
\r
222 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
224 portENTER_CRITICAL();
\r
226 xTimeWhenBlocking = xTaskGetTickCount();
\r
228 /* We should unblock after xTimeToBlock having not received
\r
229 anything on the queue. */
\r
230 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
232 xErrorOccurred = pdTRUE;
\r
235 /* How long were we blocked for? */
\r
236 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
238 portEXIT_CRITICAL();
\r
240 if( xBlockedTime < xTimeToBlock )
\r
242 /* Should not have blocked for less than we requested. */
\r
243 xErrorOccurred = pdTRUE;
\r
246 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
248 /* Should not have blocked for longer than we requested,
\r
249 although we would not necessarily run as soon as we were
\r
250 unblocked so a margin is allowed. */
\r
251 xErrorOccurred = pdTRUE;
\r
255 #if configUSE_PREEMPTION == 0
\r
260 /*********************************************************************
\r
263 Wake the other task, it will block attempting to post to the queue.
\r
264 When we read from the queue the other task will wake, but before it
\r
265 can run we will post to the queue again. When the other task runs it
\r
266 will find the queue still full, even though it was woken. It should
\r
267 recognise that its block time has not expired and return to block for
\r
268 the remains of its block time.
\r
270 Wake the other task so it blocks attempting to post to the already
\r
273 vTaskResume( xSecondary );
\r
275 /* We need to wait a little to ensure the other task executes. */
\r
276 while( xRunIndicator != bktRUN_INDICATOR )
\r
278 /* The other task has not yet executed. */
\r
279 vTaskDelay( bktSHORT_WAIT );
\r
281 /* Make sure the other task is blocked on the queue. */
\r
282 vTaskDelay( bktSHORT_WAIT );
\r
285 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
287 /* Now when we make space on the queue the other task should wake
\r
288 but not execute as this task has higher priority. */
\r
289 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
291 xErrorOccurred = pdTRUE;
\r
294 /* Now fill the queue again before the other task gets a chance to
\r
295 execute. If the other task had executed we would find the queue
\r
296 full ourselves, and the other task have set xRunIndicator. */
\r
297 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
299 xErrorOccurred = pdTRUE;
\r
302 if( xRunIndicator == bktRUN_INDICATOR )
\r
304 /* The other task should not have executed. */
\r
305 xErrorOccurred = pdTRUE;
\r
308 /* Raise the priority of the other task so it executes and blocks
\r
309 on the queue again. */
\r
310 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
312 /* The other task should now have re-blocked without exiting the
\r
314 if( xRunIndicator == bktRUN_INDICATOR )
\r
316 /* The other task should not have executed outside of the
\r
318 xErrorOccurred = pdTRUE;
\r
321 /* Set the priority back down. */
\r
322 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
325 /* Let the other task timeout. When it unblockes it will check that it
\r
326 unblocked at the correct time, then suspend itself. */
\r
327 while( xRunIndicator != bktRUN_INDICATOR )
\r
329 vTaskDelay( bktSHORT_WAIT );
\r
331 vTaskDelay( bktSHORT_WAIT );
\r
334 #if configUSE_PREEMPTION == 0
\r
338 /*********************************************************************
\r
341 As per test 3 - but with the send and receive the other way around.
\r
342 The other task blocks attempting to read from the queue.
\r
344 Empty the queue. We should find that it is full. */
\r
345 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
347 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
349 xErrorOccurred = pdTRUE;
\r
353 /* Wake the other task so it blocks attempting to read from the
\r
354 already empty queue. */
\r
355 vTaskResume( xSecondary );
\r
357 /* We need to wait a little to ensure the other task executes. */
\r
358 while( xRunIndicator != bktRUN_INDICATOR )
\r
360 vTaskDelay( bktSHORT_WAIT );
\r
362 vTaskDelay( bktSHORT_WAIT );
\r
365 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
367 /* Now when we place an item on the queue the other task should
\r
368 wake but not execute as this task has higher priority. */
\r
369 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
371 xErrorOccurred = pdTRUE;
\r
374 /* Now empty the queue again before the other task gets a chance to
\r
375 execute. If the other task had executed we would find the queue
\r
376 empty ourselves, and the other task would be suspended. */
\r
377 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
379 xErrorOccurred = pdTRUE;
\r
382 if( xRunIndicator == bktRUN_INDICATOR )
\r
384 /* The other task should not have executed. */
\r
385 xErrorOccurred = pdTRUE;
\r
388 /* Raise the priority of the other task so it executes and blocks
\r
389 on the queue again. */
\r
390 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
392 /* The other task should now have re-blocked without exiting the
\r
394 if( xRunIndicator == bktRUN_INDICATOR )
\r
396 /* The other task should not have executed outside of the
\r
398 xErrorOccurred = pdTRUE;
\r
400 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
403 /* Let the other task timeout. When it unblockes it will check that it
\r
404 unblocked at the correct time, then suspend itself. */
\r
405 while( xRunIndicator != bktRUN_INDICATOR )
\r
407 vTaskDelay( bktSHORT_WAIT );
\r
409 vTaskDelay( bktSHORT_WAIT );
\r
414 /*-----------------------------------------------------------*/
\r
416 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
418 TickType_t xTimeWhenBlocking, xBlockedTime;
\r
419 portBASE_TYPE xData;
\r
422 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
424 const char * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
\r
426 /* Queue a message for printing to say the task has started. */
\r
427 vPrintDisplayMessage( &pcTaskStartMsg );
\r
430 ( void ) pvParameters;
\r
434 /*********************************************************************
\r
437 This task does does not participate in these tests. */
\r
438 vTaskSuspend( NULL );
\r
440 /*********************************************************************
\r
443 The first thing we do is attempt to read from the queue. It should be
\r
444 full so we block. Note the time before we block so we can check the
\r
445 wake time is as per that expected. */
\r
446 portENTER_CRITICAL();
\r
448 xTimeWhenBlocking = xTaskGetTickCount();
\r
450 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
451 anything on the queue. */
\r
453 xRunIndicator = bktRUN_INDICATOR;
\r
454 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
456 xErrorOccurred = pdTRUE;
\r
459 /* How long were we inside the send function? */
\r
460 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
462 portEXIT_CRITICAL();
\r
464 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
465 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
467 xErrorOccurred = pdTRUE;
\r
470 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
471 either. A margin is permitted as we would not necessarily run as
\r
472 soon as we unblocked. */
\r
473 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
475 xErrorOccurred = pdTRUE;
\r
478 /* Suspend ready for test 3. */
\r
479 xRunIndicator = bktRUN_INDICATOR;
\r
480 vTaskSuspend( NULL );
\r
482 /*********************************************************************
\r
485 As per test three, but with the send and receive reversed. */
\r
486 portENTER_CRITICAL();
\r
488 xTimeWhenBlocking = xTaskGetTickCount();
\r
490 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
491 anything on the queue. */
\r
492 xRunIndicator = bktRUN_INDICATOR;
\r
493 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
495 xErrorOccurred = pdTRUE;
\r
498 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
500 portEXIT_CRITICAL();
\r
502 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
503 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
505 xErrorOccurred = pdTRUE;
\r
508 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
509 either. A margin is permitted as we would not necessarily run as soon
\r
510 as we unblocked. */
\r
511 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
513 xErrorOccurred = pdTRUE;
\r
516 xRunIndicator = bktRUN_INDICATOR;
\r
518 xSecondaryCycles++;
\r
521 /*-----------------------------------------------------------*/
\r
523 portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
\r
525 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
526 portBASE_TYPE xReturn = pdPASS;
\r
528 /* Have both tasks performed at least one cycle since this function was
\r
530 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
535 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
540 if( xErrorOccurred == pdTRUE )
\r
545 xLastSecondaryCycleCount = xSecondaryCycles;
\r
546 xLastPrimaryCycleCount = xPrimaryCycles;
\r