2 FreeRTOS V7.4.0 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 FEATURES AND PORTS ARE ADDED TO FREERTOS ALL THE TIME. PLEASE VISIT
\r
5 http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
7 ***************************************************************************
\r
9 * FreeRTOS tutorial books are available in pdf and paperback. *
\r
10 * Complete, revised, and edited pdf reference manuals are also *
\r
13 * Purchasing FreeRTOS documentation will not only help you, by *
\r
14 * ensuring you get running as quickly as possible and with an *
\r
15 * in-depth knowledge of how to use FreeRTOS, it will also help *
\r
16 * the FreeRTOS project to continue with its mission of providing *
\r
17 * professional grade, cross platform, de facto standard solutions *
\r
18 * for microcontrollers - completely free of charge! *
\r
20 * >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
\r
22 * Thank you for using FreeRTOS, and thank you for your support! *
\r
24 ***************************************************************************
\r
27 This file is part of the FreeRTOS distribution.
\r
29 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
30 the terms of the GNU General Public License (version 2) as published by the
\r
31 Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
\r
33 >>>>>>NOTE<<<<<< The modification to the GPL is included to allow you to
\r
34 distribute a combined work that includes FreeRTOS without being obliged to
\r
35 provide the source code for proprietary components outside of the FreeRTOS
\r
38 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
39 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
40 FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
\r
41 details. You should have received a copy of the GNU General Public License
\r
42 and the FreeRTOS license exception along with FreeRTOS; if not itcan be
\r
43 viewed here: http://www.freertos.org/a00114.html and also obtained by
\r
44 writing to Real Time Engineers Ltd., contact details for whom are available
\r
45 on the FreeRTOS WEB site.
\r
49 ***************************************************************************
\r
51 * Having a problem? Start by reading the FAQ "My application does *
\r
52 * not run, what could be wrong?" *
\r
54 * http://www.FreeRTOS.org/FAQHelp.html *
\r
56 ***************************************************************************
\r
59 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
60 license and Real Time Engineers Ltd. contact details.
\r
62 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
63 including FreeRTOS+Trace - an indispensable productivity tool, and our new
\r
64 fully thread aware and reentrant UDP/IP stack.
\r
66 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
67 Integrity Systems, who sell the code with commercial support,
\r
68 indemnification and middleware, under the OpenRTOS brand.
\r
70 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
71 engineered and independently SIL3 certified version for use in safety and
\r
72 mission critical applications that require provable dependability.
\r
76 * This file contains some test scenarios that ensure tasks do not exit queue
\r
77 * send or receive functions prematurely. A description of the tests is
\r
78 * included within the code.
\r
81 /* Kernel includes. */
\r
82 #include "FreeRTOS.h"
\r
86 /* Demo includes. */
\r
87 #include "blocktim.h"
\r
89 /* Task priorities. Allow these to be overridden. */
\r
90 #ifndef bktPRIMARY_PRIORITY
\r
91 #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
\r
94 #ifndef bktSECONDARY_PRIORITY
\r
95 #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
\r
98 /* Task behaviour. */
\r
99 #define bktQUEUE_LENGTH ( 5 )
\r
100 #define bktSHORT_WAIT ( ( ( TickType_t ) 20 ) / portTICK_PERIOD_MS )
\r
101 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
102 #define bktALLOWABLE_MARGIN ( 15 )
\r
103 #define bktTIME_TO_BLOCK ( 175 )
\r
104 #define bktDONT_BLOCK ( ( TickType_t ) 0 )
\r
105 #define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
\r
107 /* The queue on which the tasks block. */
\r
108 static QueueHandle_t xTestQueue;
\r
110 /* Handle to the secondary task is required by the primary task for calls
\r
111 to vTaskSuspend/Resume(). */
\r
112 static TaskHandle_t xSecondary;
\r
114 /* Used to ensure that tasks are still executing without error. */
\r
115 static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
116 static volatile portBASE_TYPE xErrorOccurred = pdFALSE;
\r
118 /* Provides a simple mechanism for the primary task to know when the
\r
119 secondary task has executed. */
\r
120 static volatile unsigned portBASE_TYPE xRunIndicator;
\r
122 /* The two test tasks. Their behaviour is commented within the files. */
\r
123 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
124 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
126 /*-----------------------------------------------------------*/
\r
128 void vCreateBlockTimeTasks( void )
\r
130 /* Create the queue on which the two tasks block. */
\r
131 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
\r
133 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
134 in use. The queue registry is provided as a means for kernel aware
\r
135 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
136 is not being used. The call to vQueueAddToRegistry() will be removed
\r
137 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
138 defined to be less than 1. */
\r
139 vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );
\r
141 /* Create the two test tasks. */
\r
142 xTaskCreate( vPrimaryBlockTimeTestTask, "BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
143 xTaskCreate( vSecondaryBlockTimeTestTask, "BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
145 /*-----------------------------------------------------------*/
\r
147 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
149 portBASE_TYPE xItem, xData;
\r
150 TickType_t xTimeWhenBlocking;
\r
151 TickType_t xTimeToBlock, xBlockedTime;
\r
153 ( void ) pvParameters;
\r
157 /*********************************************************************
\r
160 Simple block time wakeup test on queue receives. */
\r
161 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
163 /* The queue is empty. Attempt to read from the queue using a block
\r
164 time. When we wake, ensure the delta in time is as expected. */
\r
165 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
167 xTimeWhenBlocking = xTaskGetTickCount();
\r
169 /* We should unblock after xTimeToBlock having not received
\r
170 anything on the queue. */
\r
171 if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
173 xErrorOccurred = pdTRUE;
\r
176 /* How long were we blocked for? */
\r
177 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
179 if( xBlockedTime < xTimeToBlock )
\r
181 /* Should not have blocked for less than we requested. */
\r
182 xErrorOccurred = pdTRUE;
\r
185 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
187 /* Should not have blocked for longer than we requested,
\r
188 although we would not necessarily run as soon as we were
\r
189 unblocked so a margin is allowed. */
\r
190 xErrorOccurred = pdTRUE;
\r
194 /*********************************************************************
\r
197 Simple block time wakeup test on queue sends.
\r
199 First fill the queue. It should be empty so all sends should pass. */
\r
200 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
202 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
204 xErrorOccurred = pdTRUE;
\r
207 #if configUSE_PREEMPTION == 0
\r
212 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
214 /* The queue is full. Attempt to write to the queue using a block
\r
215 time. When we wake, ensure the delta in time is as expected. */
\r
216 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
218 xTimeWhenBlocking = xTaskGetTickCount();
\r
220 /* We should unblock after xTimeToBlock having not received
\r
221 anything on the queue. */
\r
222 if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
224 xErrorOccurred = pdTRUE;
\r
227 /* How long were we blocked for? */
\r
228 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
230 if( xBlockedTime < xTimeToBlock )
\r
232 /* Should not have blocked for less than we requested. */
\r
233 xErrorOccurred = pdTRUE;
\r
236 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
238 /* Should not have blocked for longer than we requested,
\r
239 although we would not necessarily run as soon as we were
\r
240 unblocked so a margin is allowed. */
\r
241 xErrorOccurred = pdTRUE;
\r
245 /*********************************************************************
\r
248 Wake the other task, it will block attempting to post to the queue.
\r
249 When we read from the queue the other task will wake, but before it
\r
250 can run we will post to the queue again. When the other task runs it
\r
251 will find the queue still full, even though it was woken. It should
\r
252 recognise that its block time has not expired and return to block for
\r
253 the remains of its block time.
\r
255 Wake the other task so it blocks attempting to post to the already
\r
258 vTaskResume( xSecondary );
\r
260 /* We need to wait a little to ensure the other task executes. */
\r
261 while( xRunIndicator != bktRUN_INDICATOR )
\r
263 /* The other task has not yet executed. */
\r
264 vTaskDelay( bktSHORT_WAIT );
\r
266 /* Make sure the other task is blocked on the queue. */
\r
267 vTaskDelay( bktSHORT_WAIT );
\r
270 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
272 /* Now when we make space on the queue the other task should wake
\r
273 but not execute as this task has higher priority. */
\r
274 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
276 xErrorOccurred = pdTRUE;
\r
279 /* Now fill the queue again before the other task gets a chance to
\r
280 execute. If the other task had executed we would find the queue
\r
281 full ourselves, and the other task have set xRunIndicator. */
\r
282 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
284 xErrorOccurred = pdTRUE;
\r
287 if( xRunIndicator == bktRUN_INDICATOR )
\r
289 /* The other task should not have executed. */
\r
290 xErrorOccurred = pdTRUE;
\r
293 /* Raise the priority of the other task so it executes and blocks
\r
294 on the queue again. */
\r
295 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
297 /* The other task should now have re-blocked without exiting the
\r
299 if( xRunIndicator == bktRUN_INDICATOR )
\r
301 /* The other task should not have executed outside of the
\r
303 xErrorOccurred = pdTRUE;
\r
306 /* Set the priority back down. */
\r
307 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
310 /* Let the other task timeout. When it unblockes it will check that it
\r
311 unblocked at the correct time, then suspend itself. */
\r
312 while( xRunIndicator != bktRUN_INDICATOR )
\r
314 vTaskDelay( bktSHORT_WAIT );
\r
316 vTaskDelay( bktSHORT_WAIT );
\r
320 /*********************************************************************
\r
323 As per test 3 - but with the send and receive the other way around.
\r
324 The other task blocks attempting to read from the queue.
\r
326 Empty the queue. We should find that it is full. */
\r
327 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
329 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
331 xErrorOccurred = pdTRUE;
\r
335 /* Wake the other task so it blocks attempting to read from the
\r
336 already empty queue. */
\r
337 vTaskResume( xSecondary );
\r
339 /* We need to wait a little to ensure the other task executes. */
\r
340 while( xRunIndicator != bktRUN_INDICATOR )
\r
342 vTaskDelay( bktSHORT_WAIT );
\r
344 vTaskDelay( bktSHORT_WAIT );
\r
347 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
349 /* Now when we place an item on the queue the other task should
\r
350 wake but not execute as this task has higher priority. */
\r
351 if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
353 xErrorOccurred = pdTRUE;
\r
356 /* Now empty the queue again before the other task gets a chance to
\r
357 execute. If the other task had executed we would find the queue
\r
358 empty ourselves, and the other task would be suspended. */
\r
359 if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
361 xErrorOccurred = pdTRUE;
\r
364 if( xRunIndicator == bktRUN_INDICATOR )
\r
366 /* The other task should not have executed. */
\r
367 xErrorOccurred = pdTRUE;
\r
370 /* Raise the priority of the other task so it executes and blocks
\r
371 on the queue again. */
\r
372 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
374 /* The other task should now have re-blocked without exiting the
\r
376 if( xRunIndicator == bktRUN_INDICATOR )
\r
378 /* The other task should not have executed outside of the
\r
380 xErrorOccurred = pdTRUE;
\r
382 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
385 /* Let the other task timeout. When it unblockes it will check that it
\r
386 unblocked at the correct time, then suspend itself. */
\r
387 while( xRunIndicator != bktRUN_INDICATOR )
\r
389 vTaskDelay( bktSHORT_WAIT );
\r
391 vTaskDelay( bktSHORT_WAIT );
\r
396 /*-----------------------------------------------------------*/
\r
398 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
400 TickType_t xTimeWhenBlocking, xBlockedTime;
\r
401 portBASE_TYPE xData;
\r
403 ( void ) pvParameters;
\r
407 /*********************************************************************
\r
410 This task does does not participate in these tests. */
\r
411 vTaskSuspend( NULL );
\r
413 /*********************************************************************
\r
416 The first thing we do is attempt to read from the queue. It should be
\r
417 full so we block. Note the time before we block so we can check the
\r
418 wake time is as per that expected. */
\r
419 xTimeWhenBlocking = xTaskGetTickCount();
\r
421 /* We should unblock after bktTIME_TO_BLOCK having not sent
\r
422 anything to the queue. */
\r
424 xRunIndicator = bktRUN_INDICATOR;
\r
425 if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
427 xErrorOccurred = pdTRUE;
\r
430 /* How long were we inside the send function? */
\r
431 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
433 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
434 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
436 xErrorOccurred = pdTRUE;
\r
439 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
440 either. A margin is permitted as we would not necessarily run as
\r
441 soon as we unblocked. */
\r
442 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
444 xErrorOccurred = pdTRUE;
\r
447 /* Suspend ready for test 3. */
\r
448 xRunIndicator = bktRUN_INDICATOR;
\r
449 vTaskSuspend( NULL );
\r
451 /*********************************************************************
\r
454 As per test three, but with the send and receive reversed. */
\r
455 xTimeWhenBlocking = xTaskGetTickCount();
\r
457 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
458 anything on the queue. */
\r
459 xRunIndicator = bktRUN_INDICATOR;
\r
460 if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
462 xErrorOccurred = pdTRUE;
\r
465 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
467 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
468 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
470 xErrorOccurred = pdTRUE;
\r
473 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
474 either. A margin is permitted as we would not necessarily run as soon
\r
475 as we unblocked. */
\r
476 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
478 xErrorOccurred = pdTRUE;
\r
481 xRunIndicator = bktRUN_INDICATOR;
\r
483 xSecondaryCycles++;
\r
486 /*-----------------------------------------------------------*/
\r
488 portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
\r
490 static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
491 portBASE_TYPE xReturn = pdPASS;
\r
493 /* Have both tasks performed at least one cycle since this function was
\r
495 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
500 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
505 if( xErrorOccurred == pdTRUE )
\r
510 xLastSecondaryCycleCount = xSecondaryCycles;
\r
511 xLastPrimaryCycleCount = xPrimaryCycles;
\r