2 FreeRTOS V7.5.0 - Copyright (C) 2013 Real Time Engineers Ltd.
\r
4 VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
\r
6 ***************************************************************************
\r
8 * FreeRTOS provides completely free yet professionally developed, *
\r
9 * robust, strictly quality controlled, supported, and cross *
\r
10 * platform software that has become a de facto standard. *
\r
12 * Help yourself get started quickly and support the FreeRTOS *
\r
13 * project by purchasing a FreeRTOS tutorial book, reference *
\r
14 * manual, or both from: http://www.FreeRTOS.org/Documentation *
\r
18 ***************************************************************************
\r
20 This file is part of the FreeRTOS distribution.
\r
22 FreeRTOS is free software; you can redistribute it and/or modify it under
\r
23 the terms of the GNU General Public License (version 2) as published by the
\r
24 Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
\r
26 >>! NOTE: The modification to the GPL is included to allow you to distribute
\r
27 >>! a combined work that includes FreeRTOS without being obliged to provide
\r
28 >>! the source code for proprietary components outside of the FreeRTOS
\r
31 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
32 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
33 FOR A PARTICULAR PURPOSE. Full license text is available from the following
\r
34 link: http://www.freertos.org/a00114.html
\r
38 ***************************************************************************
\r
40 * Having a problem? Start by reading the FAQ "My application does *
\r
41 * not run, what could be wrong?" *
\r
43 * http://www.FreeRTOS.org/FAQHelp.html *
\r
45 ***************************************************************************
\r
47 http://www.FreeRTOS.org - Documentation, books, training, latest versions,
\r
48 license and Real Time Engineers Ltd. contact details.
\r
50 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
51 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
52 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
54 http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
\r
55 Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
56 licenses offer ticketed support, indemnification and middleware.
\r
58 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
59 engineered and independently SIL3 certified version for use in safety and
\r
60 mission critical applications that require provable dependability.
\r
66 * This file defines one of the more complex set of demo/test tasks. They are
\r
67 * designed to stress test the queue implementation though pseudo simultaneous
\r
68 * multiple reads and multiple writes from both tasks of varying priority and
\r
69 * interrupts. The interrupts are prioritised such to ensure that nesting
\r
70 * occurs (for those ports that support it).
\r
72 * The test ensures that, while being accessed from three tasks and two
\r
73 * interrupts, all the data sent to the queues is also received from
\r
74 * the same queue, and that no duplicate items are either sent or received.
\r
75 * The tests also ensure that a low priority task is never able to successfully
\r
76 * read from or write to a queue when a task of higher priority is attempting
\r
77 * the same operation.
\r
80 /* Standard includes. */
\r
83 /* SafeRTOS includes. */
\r
84 #include "FreeRTOS.h"
\r
88 /* Demo app includes. */
\r
89 #include "IntQueue.h"
\r
90 #include "IntQueueTimer.h"
\r
92 /* Priorities used by test tasks. */
\r
93 #ifndef intqHIGHER_PRIORITY
\r
94 #define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )
\r
96 #define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
\r
98 /* The number of values to send/receive before checking that all values were
\r
99 processed as expected. */
\r
100 #define intqNUM_VALUES_TO_LOG ( 200 )
\r
101 #define intqSHORT_DELAY ( 140 )
\r
103 /* The value by which the value being sent to or received from a queue should
\r
104 increment past intqNUM_VALUES_TO_LOG before we check that all values have been
\r
105 sent/received correctly. This is done to ensure that all tasks and interrupts
\r
106 accessing the queue have completed their accesses with the
\r
107 intqNUM_VALUES_TO_LOG range. */
\r
108 #define intqVALUE_OVERRUN ( 50 )
\r
110 /* The delay used by the polling task. A short delay is used for code
\r
112 #define intqONE_TICK_DELAY ( 1 )
\r
114 /* Each task and interrupt is given a unique identifier. This value is used to
\r
115 identify which task sent or received each value. The identifier is also used
\r
116 to distinguish between two tasks that are running the same task function. */
\r
117 #define intqHIGH_PRIORITY_TASK1 ( ( unsigned portBASE_TYPE ) 1 )
\r
118 #define intqHIGH_PRIORITY_TASK2 ( ( unsigned portBASE_TYPE ) 2 )
\r
119 #define intqLOW_PRIORITY_TASK ( ( unsigned portBASE_TYPE ) 3 )
\r
120 #define intqFIRST_INTERRUPT ( ( unsigned portBASE_TYPE ) 4 )
\r
121 #define intqSECOND_INTERRUPT ( ( unsigned portBASE_TYPE ) 5 )
\r
122 #define intqQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 10 )
\r
124 /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
\r
125 from each queue by each task, otherwise an error is detected. */
\r
126 #define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
\r
128 /* Send the next value to the queue that is normally empty. This is called
\r
129 from within the interrupts. */
\r
130 #define timerNORMALLY_EMPTY_TX() \
\r
131 if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
\r
133 unsigned portBASE_TYPE uxSavedInterruptStatus; \
\r
134 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
136 uxValueForNormallyEmptyQueue++; \
\r
137 xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ); \
\r
139 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
142 /* Send the next value to the queue that is normally full. This is called
\r
143 from within the interrupts. */
\r
144 #define timerNORMALLY_FULL_TX() \
\r
145 if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
\r
147 unsigned portBASE_TYPE uxSavedInterruptStatus; \
\r
148 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
150 uxValueForNormallyFullQueue++; \
\r
151 xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ); \
\r
153 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
156 /* Receive a value from the normally empty queue. This is called from within
\r
158 #define timerNORMALLY_EMPTY_RX() \
\r
159 if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
\r
161 prvQueueAccessLogError( __LINE__ ); \
\r
165 prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \
\r
168 /* Receive a value from the normally full queue. This is called from within
\r
170 #define timerNORMALLY_FULL_RX() \
\r
171 if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
\r
173 prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \
\r
177 /*-----------------------------------------------------------*/
\r
179 /* The two queues used by the test. */
\r
180 static xQueueHandle xNormallyEmptyQueue, xNormallyFullQueue;
\r
182 /* Variables used to detect a stall in one of the tasks. */
\r
183 static unsigned portBASE_TYPE uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
\r
185 /* Any unexpected behaviour sets xErrorStatus to fail and log the line that
\r
186 caused the error in xErrorLine. */
\r
187 static portBASE_TYPE xErrorStatus = pdPASS;
\r
188 static volatile unsigned portBASE_TYPE xErrorLine = ( unsigned portBASE_TYPE ) 0;
\r
190 /* Used for sequencing between tasks. */
\r
191 static portBASE_TYPE xWasSuspended = pdFALSE;
\r
193 /* The values that are sent to the queues. An incremented value is sent each
\r
194 time to each queue. */
\r
195 volatile unsigned portBASE_TYPE uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
\r
197 /* A handle to some of the tasks is required so they can be suspended/resumed. */
\r
198 xTaskHandle xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
\r
200 /* When a value is received in a queue the value is ticked off in the array
\r
201 the array position of the value is set to a the identifier of the task or
\r
202 interrupt that accessed the queue. This way missing or duplicate values can be
\r
204 static unsigned portCHAR ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
\r
205 static unsigned portCHAR ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
\r
207 /* The test tasks themselves. */
\r
208 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );
\r
209 static void prvLowerPriorityNormallyFullTask( void *pvParameters );
\r
210 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );
\r
211 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
\r
212 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );
\r
214 /* Used to mark the positions within the ucNormallyEmptyReceivedValues and
\r
215 ucNormallyFullReceivedValues arrays, while checking for duplicates. */
\r
216 static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
\r
217 static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
\r
219 /* Logs the line on which an error occurred. */
\r
220 static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine );
\r
222 /*-----------------------------------------------------------*/
\r
224 void vStartInterruptQueueTasks( void )
\r
226 /* Start the test tasks. */
\r
227 xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
\r
228 xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
\r
229 xTaskCreate( prvLowerPriorityNormallyEmptyTask, ( signed portCHAR * ) "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
\r
230 xTaskCreate( prv1stHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
\r
231 xTaskCreate( prv2ndHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
\r
232 xTaskCreate( prvLowerPriorityNormallyFullTask, ( signed portCHAR * ) "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
\r
234 /* Create the queues that are accessed by multiple tasks and multiple
\r
236 xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
\r
237 xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
\r
239 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
240 in use. The queue registry is provided as a means for kernel aware
\r
241 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
242 is not being used. The call to vQueueAddToRegistry() will be removed
\r
243 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
244 defined to be less than 1. */
\r
245 vQueueAddToRegistry( xNormallyFullQueue, ( signed portCHAR * ) "NormallyFull" );
\r
246 vQueueAddToRegistry( xNormallyEmptyQueue, ( signed portCHAR * ) "NormallyEmpty" );
\r
248 /*-----------------------------------------------------------*/
\r
250 static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
\r
252 if( uxValue < intqNUM_VALUES_TO_LOG )
\r
254 /* We don't expect to receive the same value twice, so if the value
\r
255 has already been marked as received an error has occurred. */
\r
256 if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
\r
258 prvQueueAccessLogError( __LINE__ );
\r
261 /* Log that this value has been received. */
\r
262 ucNormallyFullReceivedValues[ uxValue ] = uxSource;
\r
265 /*-----------------------------------------------------------*/
\r
267 static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
\r
269 if( uxValue < intqNUM_VALUES_TO_LOG )
\r
271 /* We don't expect to receive the same value twice, so if the value
\r
272 has already been marked as received an error has occurred. */
\r
273 if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
\r
275 prvQueueAccessLogError( __LINE__ );
\r
278 /* Log that this value has been received. */
\r
279 ucNormallyEmptyReceivedValues[ uxValue ] = uxSource;
\r
282 /*-----------------------------------------------------------*/
\r
284 static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine )
\r
286 /* Latch the line number that caused the error. */
\r
287 xErrorLine = uxLine;
\r
288 xErrorStatus = pdFAIL;
\r
290 /*-----------------------------------------------------------*/
\r
292 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
\r
294 unsigned portBASE_TYPE uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
\r
296 /* The timer should not be started until after the scheduler has started.
\r
297 More than one task is running this code so we check the parameter value
\r
298 to determine which task should start the timer. */
\r
299 if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
\r
301 vInitialiseTimerForIntQueueTest();
\r
306 /* Block waiting to receive a value from the normally empty queue.
\r
307 Interrupts will write to the queue so we should receive a value. */
\r
308 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
\r
310 prvQueueAccessLogError( __LINE__ );
\r
314 /* Note which value was received so we can check all expected
\r
315 values are received and no values are duplicated. */
\r
316 prvRecordValue_NormallyEmpty( uxRxed, ( unsigned portBASE_TYPE ) pvParameters );
\r
319 /* Ensure the other task running this code gets a chance to execute. */
\r
322 if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
\r
324 /* Have we received all the expected values? */
\r
325 if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
\r
327 vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
\r
333 /* Loop through the array, checking that both tasks have
\r
334 placed values into the array, and that no values are missing.
\r
335 Start at 1 as we expect position 0 to be unused. */
\r
336 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
\r
338 if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
\r
340 /* A value is missing. */
\r
341 prvQueueAccessLogError( __LINE__ );
\r
345 if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
\r
347 /* Value was placed into the array by task 1. */
\r
350 else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
\r
352 /* Value was placed into the array by task 2. */
\r
355 else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )
\r
362 if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
\r
364 /* Only task 2 seemed to log any values. */
\r
366 if( uxErrorCount1 > 2 )
\r
368 prvQueueAccessLogError( __LINE__ );
\r
376 if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )
\r
378 /* Only task 1 seemed to log any values. */
\r
380 if( uxErrorCount2 > 2 )
\r
382 prvQueueAccessLogError( __LINE__ );
\r
390 if( uxInterrupts == 0 )
\r
392 prvQueueAccessLogError( __LINE__ );
\r
395 /* Clear the array again, ready to start a new cycle. */
\r
396 memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
\r
398 uxHighPriorityLoops1++;
\r
399 uxValueForNormallyEmptyQueue = 0;
\r
401 /* Suspend ourselves, allowing the lower priority task to
\r
402 actually receive something from the queue. Until now it
\r
403 will have been prevented from doing so by the higher
\r
404 priority tasks. The lower priority task will resume us
\r
405 if it receives something. We will then resume the other
\r
406 higher priority task. */
\r
407 vTaskSuspend( NULL );
\r
408 vTaskResume( xHighPriorityNormallyEmptyTask2 );
\r
413 /*-----------------------------------------------------------*/
\r
415 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )
\r
417 unsigned portBASE_TYPE uxValue, uxRxed;
\r
419 /* The parameters are not being used so avoid compiler warnings. */
\r
420 ( void ) pvParameters;
\r
424 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
\r
426 /* We should only obtain a value when the high priority task is
\r
428 if( xTaskIsTaskSuspended( xHighPriorityNormallyEmptyTask1 ) == pdFALSE )
\r
430 prvQueueAccessLogError( __LINE__ );
\r
433 prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
\r
435 /* Wake the higher priority task again. */
\r
436 vTaskResume( xHighPriorityNormallyEmptyTask1 );
\r
437 uxLowPriorityLoops1++;
\r
441 /* Raise our priority while we send so we can preempt the higher
\r
442 priority task, and ensure we get the Tx value into the queue. */
\r
443 vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
\r
445 portENTER_CRITICAL();
\r
447 uxValueForNormallyEmptyQueue++;
\r
448 uxValue = uxValueForNormallyEmptyQueue;
\r
450 portEXIT_CRITICAL();
\r
452 if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
\r
454 prvQueueAccessLogError( __LINE__ );
\r
457 vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
\r
461 /*-----------------------------------------------------------*/
\r
463 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )
\r
465 unsigned portBASE_TYPE uxValueToTx, ux, uxInterrupts;
\r
467 /* The parameters are not being used so avoid compiler warnings. */
\r
468 ( void ) pvParameters;
\r
470 /* Make sure the queue starts full or near full. >> 1 as there are two
\r
471 high priority tasks. */
\r
472 for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
\r
474 portENTER_CRITICAL();
\r
476 uxValueForNormallyFullQueue++;
\r
477 uxValueToTx = uxValueForNormallyFullQueue;
\r
479 portEXIT_CRITICAL();
\r
481 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
\r
486 portENTER_CRITICAL();
\r
488 uxValueForNormallyFullQueue++;
\r
489 uxValueToTx = uxValueForNormallyFullQueue;
\r
491 portEXIT_CRITICAL();
\r
493 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
\r
495 /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
\r
496 expect it to ever time out. */
\r
497 prvQueueAccessLogError( __LINE__ );
\r
500 /* Allow the other task running this code to run. */
\r
503 /* Have all the expected values been sent to the queue? */
\r
504 if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
\r
506 /* Make sure the other high priority task completes its send of
\r
507 any values below intqNUM_VALUE_TO_LOG. */
\r
508 vTaskDelay( intqSHORT_DELAY );
\r
510 vTaskSuspend( xHighPriorityNormallyFullTask2 );
\r
512 if( xWasSuspended == pdTRUE )
\r
514 /* We would have expected the other high priority task to have
\r
515 set this back to false by now. */
\r
516 prvQueueAccessLogError( __LINE__ );
\r
519 /* Set the suspended flag so an error is not logged if the other
\r
520 task recognises a time out when it is unsuspended. */
\r
521 xWasSuspended = pdTRUE;
\r
523 /* Check interrupts are also sending. */
\r
526 /* Start at 1 as we expect position 0 to be unused. */
\r
527 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
\r
529 if( ucNormallyFullReceivedValues[ ux ] == 0 )
\r
531 /* A value was missing. */
\r
532 prvQueueAccessLogError( __LINE__ );
\r
534 else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )
\r
540 if( uxInterrupts == 0 )
\r
542 /* No writes from interrupts were found. Are interrupts
\r
543 actually running? */
\r
544 prvQueueAccessLogError( __LINE__ );
\r
547 /* Reset the array ready for the next cycle. */
\r
548 memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
\r
550 uxHighPriorityLoops2++;
\r
551 uxValueForNormallyFullQueue = 0;
\r
553 /* Suspend ourselves, allowing the lower priority task to
\r
554 actually receive something from the queue. Until now it
\r
555 will have been prevented from doing so by the higher
\r
556 priority tasks. The lower priority task will resume us
\r
557 if it receives something. We will then resume the other
\r
558 higher priority task. */
\r
559 vTaskSuspend( NULL );
\r
560 vTaskResume( xHighPriorityNormallyFullTask2 );
\r
564 /*-----------------------------------------------------------*/
\r
566 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )
\r
568 unsigned portBASE_TYPE uxValueToTx, ux;
\r
570 /* The parameters are not being used so avoid compiler warnings. */
\r
571 ( void ) pvParameters;
\r
573 /* Make sure the queue starts full or near full. >> 1 as there are two
\r
574 high priority tasks. */
\r
575 for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
\r
577 portENTER_CRITICAL();
\r
579 uxValueForNormallyFullQueue++;
\r
580 uxValueToTx = uxValueForNormallyFullQueue;
\r
582 portEXIT_CRITICAL();
\r
584 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
\r
589 portENTER_CRITICAL();
\r
591 uxValueForNormallyFullQueue++;
\r
592 uxValueToTx = uxValueForNormallyFullQueue;
\r
594 portEXIT_CRITICAL();
\r
596 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
\r
598 if( xWasSuspended != pdTRUE )
\r
600 /* It is ok to time out if the task has been suspended. */
\r
601 prvQueueAccessLogError( __LINE__ );
\r
605 xWasSuspended = pdFALSE;
\r
610 /*-----------------------------------------------------------*/
\r
612 static void prvLowerPriorityNormallyFullTask( void *pvParameters )
\r
614 unsigned portBASE_TYPE uxValue, uxTxed = 9999;
\r
616 /* The parameters are not being used so avoid compiler warnings. */
\r
617 ( void ) pvParameters;
\r
621 if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )
\r
623 /* We would only expect to succeed when the higher priority task
\r
625 if( xTaskIsTaskSuspended( xHighPriorityNormallyFullTask1 ) == pdFALSE )
\r
627 prvQueueAccessLogError( __LINE__ );
\r
630 vTaskResume( xHighPriorityNormallyFullTask1 );
\r
631 uxLowPriorityLoops2++;
\r
635 /* Raise our priority while we receive so we can preempt the higher
\r
636 priority task, and ensure we get the value from the queue. */
\r
637 vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
\r
639 if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
\r
641 prvQueueAccessLogError( __LINE__ );
\r
645 prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
\r
648 vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
\r
652 /*-----------------------------------------------------------*/
\r
654 portBASE_TYPE xFirstTimerHandler( void )
\r
656 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, uxRxedValue;
\r
657 static unsigned portBASE_TYPE uxNextOperation = 0;
\r
659 /* Called from a timer interrupt. Perform various read and write
\r
660 accesses on the queues. */
\r
664 if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
\r
666 timerNORMALLY_EMPTY_TX();
\r
667 timerNORMALLY_EMPTY_TX();
\r
668 timerNORMALLY_EMPTY_TX();
\r
672 timerNORMALLY_FULL_RX();
\r
673 timerNORMALLY_FULL_RX();
\r
674 timerNORMALLY_FULL_RX();
\r
677 return xHigherPriorityTaskWoken;
\r
679 /*-----------------------------------------------------------*/
\r
681 portBASE_TYPE xSecondTimerHandler( void )
\r
683 unsigned portBASE_TYPE uxRxedValue;
\r
684 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
685 static unsigned portBASE_TYPE uxNextOperation = 0;
\r
687 /* Called from a timer interrupt. Perform various read and write
\r
688 accesses on the queues. */
\r
692 if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
\r
694 timerNORMALLY_EMPTY_TX();
\r
695 timerNORMALLY_EMPTY_TX();
\r
697 timerNORMALLY_EMPTY_RX();
\r
698 timerNORMALLY_EMPTY_RX();
\r
702 timerNORMALLY_FULL_RX();
\r
703 timerNORMALLY_FULL_TX();
\r
704 timerNORMALLY_FULL_TX();
\r
705 timerNORMALLY_FULL_TX();
\r
706 timerNORMALLY_FULL_TX();
\r
709 return xHigherPriorityTaskWoken;
\r
711 /*-----------------------------------------------------------*/
\r
714 portBASE_TYPE xAreIntQueueTasksStillRunning( void )
\r
716 static unsigned portBASE_TYPE uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
\r
718 /* xErrorStatus can be set outside of this function. This function just
\r
719 checks that all the tasks are still cycling. */
\r
721 if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
\r
723 /* The high priority 1 task has stalled. */
\r
724 prvQueueAccessLogError( __LINE__ );
\r
727 uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
\r
729 if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
\r
731 /* The high priority 2 task has stalled. */
\r
732 prvQueueAccessLogError( __LINE__ );
\r
735 uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
\r
737 if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
\r
739 /* The low priority 1 task has stalled. */
\r
740 prvQueueAccessLogError( __LINE__ );
\r
743 uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
\r
745 if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
\r
747 /* The low priority 2 task has stalled. */
\r
748 prvQueueAccessLogError( __LINE__ );
\r
751 uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
\r
753 return xErrorStatus;
\r