2 FreeRTOS V8.2.0rc1 - Copyright (C) 2014 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 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
14 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
15 >>! obliged to provide the source code for proprietary components !<<
\r
16 >>! outside of the FreeRTOS kernel. !<<
\r
18 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
19 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
20 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
21 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * Having a problem? Start by reading the FAQ "My application does *
\r
28 * not run, what could be wrong?". Have you defined configASSERT()? *
\r
30 * http://www.FreeRTOS.org/FAQHelp.html *
\r
32 ***************************************************************************
\r
34 ***************************************************************************
\r
36 * FreeRTOS provides completely free yet professionally developed, *
\r
37 * robust, strictly quality controlled, supported, and cross *
\r
38 * platform software that is more than just the market leader, it *
\r
39 * is the industry's de facto standard. *
\r
41 * Help yourself get started quickly while simultaneously helping *
\r
42 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
43 * tutorial book, reference manual, or both: *
\r
44 * http://www.FreeRTOS.org/Documentation *
\r
46 ***************************************************************************
\r
48 ***************************************************************************
\r
50 * Investing in training allows your team to be as productive as *
\r
51 * possible as early as possible, lowering your overall development *
\r
52 * cost, and enabling you to bring a more robust product to market *
\r
53 * earlier than would otherwise be possible. Richard Barry is both *
\r
54 * the architect and key author of FreeRTOS, and so also the world's *
\r
55 * leading authority on what is the world's most popular real time *
\r
56 * kernel for deeply embedded MCU designs. Obtaining your training *
\r
57 * from Richard ensures your team will gain directly from his in-depth *
\r
58 * product knowledge and years of usage experience. Contact Real Time *
\r
59 * Engineers Ltd to enquire about the FreeRTOS Masterclass, presented *
\r
60 * by Richard Barry: http://www.FreeRTOS.org/contact
\r
62 ***************************************************************************
\r
64 ***************************************************************************
\r
66 * You are receiving this top quality software for free. Please play *
\r
67 * fair and reciprocate by reporting any suspected issues and *
\r
68 * participating in the community forum: *
\r
69 * http://www.FreeRTOS.org/support *
\r
73 ***************************************************************************
\r
75 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
76 license and Real Time Engineers Ltd. contact details.
\r
78 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
79 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
80 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
82 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
83 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
85 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
86 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
87 licenses offer ticketed support, indemnification and commercial middleware.
\r
89 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
90 engineered and independently SIL3 certified version for use in safety and
\r
91 mission critical applications that require provable dependability.
\r
97 * This is a version of BlockTim.c that uses the light weight API.
\r
99 * This file contains some test scenarios that ensure tasks do not exit queue
\r
100 * send or receive functions prematurely. A description of the tests is
\r
101 * included within the code.
\r
104 /* Kernel includes. */
\r
105 #include "FreeRTOS.h"
\r
109 /* Demo includes. */
\r
110 #include "AltBlock.h"
\r
112 /* Task priorities. */
\r
113 #define bktPRIMARY_PRIORITY ( 3 )
\r
114 #define bktSECONDARY_PRIORITY ( 2 )
\r
116 /* Task behaviour. */
\r
117 #define bktQUEUE_LENGTH ( 5 )
\r
118 #define bktSHORT_WAIT ( ( ( TickType_t ) 20 ) / portTICK_PERIOD_MS )
\r
119 #define bktPRIMARY_BLOCK_TIME ( 10 )
\r
120 #define bktALLOWABLE_MARGIN ( 12 )
\r
121 #define bktTIME_TO_BLOCK ( 175 )
\r
122 #define bktDONT_BLOCK ( ( TickType_t ) 0 )
\r
123 #define bktRUN_INDICATOR ( ( UBaseType_t ) 0x55 )
\r
125 /* The queue on which the tasks block. */
\r
126 static QueueHandle_t xTestQueue;
\r
128 /* Handle to the secondary task is required by the primary task for calls
\r
129 to vTaskSuspend/Resume(). */
\r
130 static TaskHandle_t xSecondary;
\r
132 /* Used to ensure that tasks are still executing without error. */
\r
133 static BaseType_t xPrimaryCycles = 0, xSecondaryCycles = 0;
\r
134 static BaseType_t xErrorOccurred = pdFALSE;
\r
136 /* Provides a simple mechanism for the primary task to know when the
\r
137 secondary task has executed. */
\r
138 static volatile UBaseType_t xRunIndicator;
\r
140 /* The two test tasks. Their behaviour is commented within the files. */
\r
141 static void vPrimaryBlockTimeTestTask( void *pvParameters );
\r
142 static void vSecondaryBlockTimeTestTask( void *pvParameters );
\r
144 /*-----------------------------------------------------------*/
\r
146 void vCreateAltBlockTimeTasks( void )
\r
148 /* Create the queue on which the two tasks block. */
\r
149 xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( BaseType_t ) );
\r
151 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
152 in use. The queue registry is provided as a means for kernel aware
\r
153 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
154 is not being used. The call to vQueueAddToRegistry() will be removed
\r
155 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
156 defined to be less than 1. */
\r
157 vQueueAddToRegistry( xTestQueue, "AltBlockQueue" );
\r
160 /* Create the two test tasks. */
\r
161 xTaskCreate( vPrimaryBlockTimeTestTask, "FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
\r
162 xTaskCreate( vSecondaryBlockTimeTestTask, "FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
\r
164 /*-----------------------------------------------------------*/
\r
166 static void vPrimaryBlockTimeTestTask( void *pvParameters )
\r
168 BaseType_t xItem, xData;
\r
169 TickType_t xTimeWhenBlocking;
\r
170 TickType_t xTimeToBlock, xBlockedTime;
\r
173 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
175 const char * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
\r
177 /* Queue a message for printing to say the task has started. */
\r
178 vPrintDisplayMessage( &pcTaskStartMsg );
\r
181 ( void ) pvParameters;
\r
185 /*********************************************************************
\r
188 Simple block time wakeup test on queue receives. */
\r
189 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
191 /* The queue is empty. Attempt to read from the queue using a block
\r
192 time. When we wake, ensure the delta in time is as expected. */
\r
193 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
195 /* A critical section is used to minimise the jitter in the time
\r
197 portENTER_CRITICAL();
\r
199 xTimeWhenBlocking = xTaskGetTickCount();
\r
201 /* We should unblock after xTimeToBlock having not received
\r
202 anything on the queue. */
\r
203 if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
\r
205 xErrorOccurred = pdTRUE;
\r
208 /* How long were we blocked for? */
\r
209 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
211 portEXIT_CRITICAL();
\r
213 if( xBlockedTime < xTimeToBlock )
\r
215 /* Should not have blocked for less than we requested. */
\r
216 xErrorOccurred = pdTRUE;
\r
219 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
221 /* Should not have blocked for longer than we requested,
\r
222 although we would not necessarily run as soon as we were
\r
223 unblocked so a margin is allowed. */
\r
224 xErrorOccurred = pdTRUE;
\r
229 #if configUSE_PREEMPTION == 0
\r
234 /*********************************************************************
\r
237 Simple block time wakeup test on queue sends.
\r
239 First fill the queue. It should be empty so all sends should pass. */
\r
240 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
242 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
244 xErrorOccurred = pdTRUE;
\r
248 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
250 /* The queue is full. Attempt to write to the queue using a block
\r
251 time. When we wake, ensure the delta in time is as expected. */
\r
252 xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
\r
254 portENTER_CRITICAL();
\r
256 xTimeWhenBlocking = xTaskGetTickCount();
\r
258 /* We should unblock after xTimeToBlock having not received
\r
259 anything on the queue. */
\r
260 if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
\r
262 xErrorOccurred = pdTRUE;
\r
265 /* How long were we blocked for? */
\r
266 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
268 portEXIT_CRITICAL();
\r
270 if( xBlockedTime < xTimeToBlock )
\r
272 /* Should not have blocked for less than we requested. */
\r
273 xErrorOccurred = pdTRUE;
\r
276 if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
\r
278 /* Should not have blocked for longer than we requested,
\r
279 although we would not necessarily run as soon as we were
\r
280 unblocked so a margin is allowed. */
\r
281 xErrorOccurred = pdTRUE;
\r
285 #if configUSE_PREEMPTION == 0
\r
290 /*********************************************************************
\r
293 Wake the other task, it will block attempting to post to the queue.
\r
294 When we read from the queue the other task will wake, but before it
\r
295 can run we will post to the queue again. When the other task runs it
\r
296 will find the queue still full, even though it was woken. It should
\r
297 recognise that its block time has not expired and return to block for
\r
298 the remains of its block time.
\r
300 Wake the other task so it blocks attempting to post to the already
\r
303 vTaskResume( xSecondary );
\r
305 /* We need to wait a little to ensure the other task executes. */
\r
306 while( xRunIndicator != bktRUN_INDICATOR )
\r
308 /* The other task has not yet executed. */
\r
309 vTaskDelay( bktSHORT_WAIT );
\r
311 /* Make sure the other task is blocked on the queue. */
\r
312 vTaskDelay( bktSHORT_WAIT );
\r
315 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
317 /* Now when we make space on the queue the other task should wake
\r
318 but not execute as this task has higher priority. */
\r
319 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
321 xErrorOccurred = pdTRUE;
\r
324 /* Now fill the queue again before the other task gets a chance to
\r
325 execute. If the other task had executed we would find the queue
\r
326 full ourselves, and the other task have set xRunIndicator. */
\r
327 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
329 xErrorOccurred = pdTRUE;
\r
332 if( xRunIndicator == bktRUN_INDICATOR )
\r
334 /* The other task should not have executed. */
\r
335 xErrorOccurred = pdTRUE;
\r
338 /* Raise the priority of the other task so it executes and blocks
\r
339 on the queue again. */
\r
340 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
342 /* The other task should now have re-blocked without exiting the
\r
344 if( xRunIndicator == bktRUN_INDICATOR )
\r
346 /* The other task should not have executed outside of the
\r
348 xErrorOccurred = pdTRUE;
\r
351 /* Set the priority back down. */
\r
352 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
355 /* Let the other task timeout. When it unblockes it will check that it
\r
356 unblocked at the correct time, then suspend itself. */
\r
357 while( xRunIndicator != bktRUN_INDICATOR )
\r
359 vTaskDelay( bktSHORT_WAIT );
\r
361 vTaskDelay( bktSHORT_WAIT );
\r
364 #if configUSE_PREEMPTION == 0
\r
368 /*********************************************************************
\r
371 As per test 3 - but with the send and receive the other way around.
\r
372 The other task blocks attempting to read from the queue.
\r
374 Empty the queue. We should find that it is full. */
\r
375 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
377 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
379 xErrorOccurred = pdTRUE;
\r
383 /* Wake the other task so it blocks attempting to read from the
\r
384 already empty queue. */
\r
385 vTaskResume( xSecondary );
\r
387 /* We need to wait a little to ensure the other task executes. */
\r
388 while( xRunIndicator != bktRUN_INDICATOR )
\r
390 vTaskDelay( bktSHORT_WAIT );
\r
392 vTaskDelay( bktSHORT_WAIT );
\r
395 for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
\r
397 /* Now when we place an item on the queue the other task should
\r
398 wake but not execute as this task has higher priority. */
\r
399 if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
\r
401 xErrorOccurred = pdTRUE;
\r
404 /* Now empty the queue again before the other task gets a chance to
\r
405 execute. If the other task had executed we would find the queue
\r
406 empty ourselves, and the other task would be suspended. */
\r
407 if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
\r
409 xErrorOccurred = pdTRUE;
\r
412 if( xRunIndicator == bktRUN_INDICATOR )
\r
414 /* The other task should not have executed. */
\r
415 xErrorOccurred = pdTRUE;
\r
418 /* Raise the priority of the other task so it executes and blocks
\r
419 on the queue again. */
\r
420 vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
\r
422 /* The other task should now have re-blocked without exiting the
\r
424 if( xRunIndicator == bktRUN_INDICATOR )
\r
426 /* The other task should not have executed outside of the
\r
428 xErrorOccurred = pdTRUE;
\r
430 vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
\r
433 /* Let the other task timeout. When it unblockes it will check that it
\r
434 unblocked at the correct time, then suspend itself. */
\r
435 while( xRunIndicator != bktRUN_INDICATOR )
\r
437 vTaskDelay( bktSHORT_WAIT );
\r
439 vTaskDelay( bktSHORT_WAIT );
\r
444 /*-----------------------------------------------------------*/
\r
446 static void vSecondaryBlockTimeTestTask( void *pvParameters )
\r
448 TickType_t xTimeWhenBlocking, xBlockedTime;
\r
452 void vPrintDisplayMessage( const char * const * ppcMessageToSend );
\r
454 const char * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
\r
456 /* Queue a message for printing to say the task has started. */
\r
457 vPrintDisplayMessage( &pcTaskStartMsg );
\r
460 ( void ) pvParameters;
\r
464 /*********************************************************************
\r
467 This task does does not participate in these tests. */
\r
468 vTaskSuspend( NULL );
\r
470 /*********************************************************************
\r
473 The first thing we do is attempt to read from the queue. It should be
\r
474 full so we block. Note the time before we block so we can check the
\r
475 wake time is as per that expected. */
\r
476 portENTER_CRITICAL();
\r
478 xTimeWhenBlocking = xTaskGetTickCount();
\r
480 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
481 anything on the queue. */
\r
483 xRunIndicator = bktRUN_INDICATOR;
\r
484 if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
\r
486 xErrorOccurred = pdTRUE;
\r
489 /* How long were we inside the send function? */
\r
490 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
492 portEXIT_CRITICAL();
\r
494 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
495 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
497 xErrorOccurred = pdTRUE;
\r
500 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
501 either. A margin is permitted as we would not necessarily run as
\r
502 soon as we unblocked. */
\r
503 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
505 xErrorOccurred = pdTRUE;
\r
508 /* Suspend ready for test 3. */
\r
509 xRunIndicator = bktRUN_INDICATOR;
\r
510 vTaskSuspend( NULL );
\r
512 /*********************************************************************
\r
515 As per test three, but with the send and receive reversed. */
\r
516 portENTER_CRITICAL();
\r
518 xTimeWhenBlocking = xTaskGetTickCount();
\r
520 /* We should unblock after bktTIME_TO_BLOCK having not received
\r
521 anything on the queue. */
\r
522 xRunIndicator = bktRUN_INDICATOR;
\r
523 if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
\r
525 xErrorOccurred = pdTRUE;
\r
528 xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
\r
530 portEXIT_CRITICAL();
\r
532 /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
\r
533 if( xBlockedTime < bktTIME_TO_BLOCK )
\r
535 xErrorOccurred = pdTRUE;
\r
538 /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
\r
539 either. A margin is permitted as we would not necessarily run as soon
\r
540 as we unblocked. */
\r
541 if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
\r
543 xErrorOccurred = pdTRUE;
\r
546 xRunIndicator = bktRUN_INDICATOR;
\r
548 xSecondaryCycles++;
\r
551 /*-----------------------------------------------------------*/
\r
553 BaseType_t xAreAltBlockTimeTestTasksStillRunning( void )
\r
555 static BaseType_t xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
\r
556 BaseType_t xReturn = pdPASS;
\r
558 /* Have both tasks performed at least one cycle since this function was
\r
560 if( xPrimaryCycles == xLastPrimaryCycleCount )
\r
565 if( xSecondaryCycles == xLastSecondaryCycleCount )
\r
570 if( xErrorOccurred == pdTRUE )
\r
575 xLastSecondaryCycleCount = xSecondaryCycles;
\r
576 xLastPrimaryCycleCount = xPrimaryCycles;
\r