2 FreeRTOS V7.6.0 - Copyright (C) 2013 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 file defines one of the more complex set of demo/test tasks. They are
\r
68 * designed to stress test the queue implementation though pseudo simultaneous
\r
69 * multiple reads and multiple writes from both tasks of varying priority and
\r
70 * interrupts. The interrupts are prioritised such to ensure that nesting
\r
71 * occurs (for those ports that support it).
\r
73 * The test ensures that, while being accessed from three tasks and two
\r
74 * interrupts, all the data sent to the queues is also received from
\r
75 * the same queue, and that no duplicate items are either sent or received.
\r
76 * The tests also ensure that a low priority task is never able to successfully
\r
77 * read from or write to a queue when a task of higher priority is attempting
\r
78 * the same operation.
\r
81 /* Standard includes. */
\r
84 /* SafeRTOS includes. */
\r
85 #include "FreeRTOS.h"
\r
89 /* Demo app includes. */
\r
90 #include "IntQueue.h"
\r
91 #include "IntQueueTimer.h"
\r
93 /* Priorities used by test tasks. */
\r
94 #ifndef intqHIGHER_PRIORITY
\r
95 #define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )
\r
97 #define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
\r
99 /* The number of values to send/receive before checking that all values were
\r
100 processed as expected. */
\r
101 #define intqNUM_VALUES_TO_LOG ( 200 )
\r
102 #define intqSHORT_DELAY ( 140 )
\r
104 /* The value by which the value being sent to or received from a queue should
\r
105 increment past intqNUM_VALUES_TO_LOG before we check that all values have been
\r
106 sent/received correctly. This is done to ensure that all tasks and interrupts
\r
107 accessing the queue have completed their accesses with the
\r
108 intqNUM_VALUES_TO_LOG range. */
\r
109 #define intqVALUE_OVERRUN ( 50 )
\r
111 /* The delay used by the polling task. A short delay is used for code
\r
113 #define intqONE_TICK_DELAY ( 1 )
\r
115 /* Each task and interrupt is given a unique identifier. This value is used to
\r
116 identify which task sent or received each value. The identifier is also used
\r
117 to distinguish between two tasks that are running the same task function. */
\r
118 #define intqHIGH_PRIORITY_TASK1 ( ( unsigned portBASE_TYPE ) 1 )
\r
119 #define intqHIGH_PRIORITY_TASK2 ( ( unsigned portBASE_TYPE ) 2 )
\r
120 #define intqLOW_PRIORITY_TASK ( ( unsigned portBASE_TYPE ) 3 )
\r
121 #define intqFIRST_INTERRUPT ( ( unsigned portBASE_TYPE ) 4 )
\r
122 #define intqSECOND_INTERRUPT ( ( unsigned portBASE_TYPE ) 5 )
\r
123 #define intqQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 10 )
\r
125 /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
\r
126 from each queue by each task, otherwise an error is detected. */
\r
127 #define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
\r
129 /* Send the next value to the queue that is normally empty. This is called
\r
130 from within the interrupts. */
\r
131 #define timerNORMALLY_EMPTY_TX() \
\r
132 if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
\r
134 unsigned portBASE_TYPE uxSavedInterruptStatus; \
\r
135 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
137 uxValueForNormallyEmptyQueue++; \
\r
138 xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ); \
\r
140 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
143 /* Send the next value to the queue that is normally full. This is called
\r
144 from within the interrupts. */
\r
145 #define timerNORMALLY_FULL_TX() \
\r
146 if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
\r
148 unsigned portBASE_TYPE uxSavedInterruptStatus; \
\r
149 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
151 uxValueForNormallyFullQueue++; \
\r
152 xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ); \
\r
154 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
157 /* Receive a value from the normally empty queue. This is called from within
\r
159 #define timerNORMALLY_EMPTY_RX() \
\r
160 if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
\r
162 prvQueueAccessLogError( __LINE__ ); \
\r
166 prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \
\r
169 /* Receive a value from the normally full queue. This is called from within
\r
171 #define timerNORMALLY_FULL_RX() \
\r
172 if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
\r
174 prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \
\r
178 /*-----------------------------------------------------------*/
\r
180 /* The two queues used by the test. */
\r
181 static xQueueHandle xNormallyEmptyQueue, xNormallyFullQueue;
\r
183 /* Variables used to detect a stall in one of the tasks. */
\r
184 static unsigned portBASE_TYPE uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
\r
186 /* Any unexpected behaviour sets xErrorStatus to fail and log the line that
\r
187 caused the error in xErrorLine. */
\r
188 static portBASE_TYPE xErrorStatus = pdPASS;
\r
189 static volatile unsigned portBASE_TYPE xErrorLine = ( unsigned portBASE_TYPE ) 0;
\r
191 /* Used for sequencing between tasks. */
\r
192 static portBASE_TYPE xWasSuspended = pdFALSE;
\r
194 /* The values that are sent to the queues. An incremented value is sent each
\r
195 time to each queue. */
\r
196 volatile unsigned portBASE_TYPE uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
\r
198 /* A handle to some of the tasks is required so they can be suspended/resumed. */
\r
199 xTaskHandle xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
\r
201 /* When a value is received in a queue the value is ticked off in the array
\r
202 the array position of the value is set to a the identifier of the task or
\r
203 interrupt that accessed the queue. This way missing or duplicate values can be
\r
205 static unsigned portCHAR ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
\r
206 static unsigned portCHAR ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
\r
208 /* The test tasks themselves. */
\r
209 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );
\r
210 static void prvLowerPriorityNormallyFullTask( void *pvParameters );
\r
211 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );
\r
212 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
\r
213 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );
\r
215 /* Used to mark the positions within the ucNormallyEmptyReceivedValues and
\r
216 ucNormallyFullReceivedValues arrays, while checking for duplicates. */
\r
217 static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
\r
218 static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
\r
220 /* Logs the line on which an error occurred. */
\r
221 static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine );
\r
223 /*-----------------------------------------------------------*/
\r
225 void vStartInterruptQueueTasks( void )
\r
227 /* Start the test tasks. */
\r
228 xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
\r
229 xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
\r
230 xTaskCreate( prvLowerPriorityNormallyEmptyTask, ( signed portCHAR * ) "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
\r
231 xTaskCreate( prv1stHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
\r
232 xTaskCreate( prv2ndHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
\r
233 xTaskCreate( prvLowerPriorityNormallyFullTask, ( signed portCHAR * ) "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
\r
235 /* Create the queues that are accessed by multiple tasks and multiple
\r
237 xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
\r
238 xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
\r
240 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
241 in use. The queue registry is provided as a means for kernel aware
\r
242 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
243 is not being used. The call to vQueueAddToRegistry() will be removed
\r
244 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
245 defined to be less than 1. */
\r
246 vQueueAddToRegistry( xNormallyFullQueue, ( signed portCHAR * ) "NormallyFull" );
\r
247 vQueueAddToRegistry( xNormallyEmptyQueue, ( signed portCHAR * ) "NormallyEmpty" );
\r
249 /*-----------------------------------------------------------*/
\r
251 static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
\r
253 if( uxValue < intqNUM_VALUES_TO_LOG )
\r
255 /* We don't expect to receive the same value twice, so if the value
\r
256 has already been marked as received an error has occurred. */
\r
257 if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
\r
259 prvQueueAccessLogError( __LINE__ );
\r
262 /* Log that this value has been received. */
\r
263 ucNormallyFullReceivedValues[ uxValue ] = uxSource;
\r
266 /*-----------------------------------------------------------*/
\r
268 static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
\r
270 if( uxValue < intqNUM_VALUES_TO_LOG )
\r
272 /* We don't expect to receive the same value twice, so if the value
\r
273 has already been marked as received an error has occurred. */
\r
274 if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
\r
276 prvQueueAccessLogError( __LINE__ );
\r
279 /* Log that this value has been received. */
\r
280 ucNormallyEmptyReceivedValues[ uxValue ] = uxSource;
\r
283 /*-----------------------------------------------------------*/
\r
285 static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine )
\r
287 /* Latch the line number that caused the error. */
\r
288 xErrorLine = uxLine;
\r
289 xErrorStatus = pdFAIL;
\r
291 /*-----------------------------------------------------------*/
\r
293 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
\r
295 unsigned portBASE_TYPE uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
\r
297 /* The timer should not be started until after the scheduler has started.
\r
298 More than one task is running this code so we check the parameter value
\r
299 to determine which task should start the timer. */
\r
300 if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
\r
302 vInitialiseTimerForIntQueueTest();
\r
307 /* Block waiting to receive a value from the normally empty queue.
\r
308 Interrupts will write to the queue so we should receive a value. */
\r
309 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
\r
311 prvQueueAccessLogError( __LINE__ );
\r
315 /* Note which value was received so we can check all expected
\r
316 values are received and no values are duplicated. */
\r
317 prvRecordValue_NormallyEmpty( uxRxed, ( unsigned portBASE_TYPE ) pvParameters );
\r
320 /* Ensure the other task running this code gets a chance to execute. */
\r
323 if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
\r
325 /* Have we received all the expected values? */
\r
326 if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
\r
328 vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
\r
334 /* Loop through the array, checking that both tasks have
\r
335 placed values into the array, and that no values are missing.
\r
336 Start at 1 as we expect position 0 to be unused. */
\r
337 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
\r
339 if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
\r
341 /* A value is missing. */
\r
342 prvQueueAccessLogError( __LINE__ );
\r
346 if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
\r
348 /* Value was placed into the array by task 1. */
\r
351 else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
\r
353 /* Value was placed into the array by task 2. */
\r
356 else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )
\r
363 if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
\r
365 /* Only task 2 seemed to log any values. */
\r
367 if( uxErrorCount1 > 2 )
\r
369 prvQueueAccessLogError( __LINE__ );
\r
377 if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )
\r
379 /* Only task 1 seemed to log any values. */
\r
381 if( uxErrorCount2 > 2 )
\r
383 prvQueueAccessLogError( __LINE__ );
\r
391 if( uxInterrupts == 0 )
\r
393 prvQueueAccessLogError( __LINE__ );
\r
396 /* Clear the array again, ready to start a new cycle. */
\r
397 memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
\r
399 uxHighPriorityLoops1++;
\r
400 uxValueForNormallyEmptyQueue = 0;
\r
402 /* Suspend ourselves, allowing the lower priority task to
\r
403 actually receive something from the queue. Until now it
\r
404 will have been prevented from doing so by the higher
\r
405 priority tasks. The lower priority task will resume us
\r
406 if it receives something. We will then resume the other
\r
407 higher priority task. */
\r
408 vTaskSuspend( NULL );
\r
409 vTaskResume( xHighPriorityNormallyEmptyTask2 );
\r
414 /*-----------------------------------------------------------*/
\r
416 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )
\r
418 unsigned portBASE_TYPE uxValue, uxRxed;
\r
420 /* The parameters are not being used so avoid compiler warnings. */
\r
421 ( void ) pvParameters;
\r
425 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
\r
427 /* We should only obtain a value when the high priority task is
\r
429 if( xTaskIsTaskSuspended( xHighPriorityNormallyEmptyTask1 ) == pdFALSE )
\r
431 prvQueueAccessLogError( __LINE__ );
\r
434 prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
\r
436 /* Wake the higher priority task again. */
\r
437 vTaskResume( xHighPriorityNormallyEmptyTask1 );
\r
438 uxLowPriorityLoops1++;
\r
442 /* Raise our priority while we send so we can preempt the higher
\r
443 priority task, and ensure we get the Tx value into the queue. */
\r
444 vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
\r
446 portENTER_CRITICAL();
\r
448 uxValueForNormallyEmptyQueue++;
\r
449 uxValue = uxValueForNormallyEmptyQueue;
\r
451 portEXIT_CRITICAL();
\r
453 if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
\r
455 prvQueueAccessLogError( __LINE__ );
\r
458 vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
\r
462 /*-----------------------------------------------------------*/
\r
464 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )
\r
466 unsigned portBASE_TYPE uxValueToTx, ux, uxInterrupts;
\r
468 /* The parameters are not being used so avoid compiler warnings. */
\r
469 ( void ) pvParameters;
\r
471 /* Make sure the queue starts full or near full. >> 1 as there are two
\r
472 high priority tasks. */
\r
473 for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
\r
475 portENTER_CRITICAL();
\r
477 uxValueForNormallyFullQueue++;
\r
478 uxValueToTx = uxValueForNormallyFullQueue;
\r
480 portEXIT_CRITICAL();
\r
482 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
\r
487 portENTER_CRITICAL();
\r
489 uxValueForNormallyFullQueue++;
\r
490 uxValueToTx = uxValueForNormallyFullQueue;
\r
492 portEXIT_CRITICAL();
\r
494 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
\r
496 /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
\r
497 expect it to ever time out. */
\r
498 prvQueueAccessLogError( __LINE__ );
\r
501 /* Allow the other task running this code to run. */
\r
504 /* Have all the expected values been sent to the queue? */
\r
505 if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
\r
507 /* Make sure the other high priority task completes its send of
\r
508 any values below intqNUM_VALUE_TO_LOG. */
\r
509 vTaskDelay( intqSHORT_DELAY );
\r
511 vTaskSuspend( xHighPriorityNormallyFullTask2 );
\r
513 if( xWasSuspended == pdTRUE )
\r
515 /* We would have expected the other high priority task to have
\r
516 set this back to false by now. */
\r
517 prvQueueAccessLogError( __LINE__ );
\r
520 /* Set the suspended flag so an error is not logged if the other
\r
521 task recognises a time out when it is unsuspended. */
\r
522 xWasSuspended = pdTRUE;
\r
524 /* Check interrupts are also sending. */
\r
527 /* Start at 1 as we expect position 0 to be unused. */
\r
528 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
\r
530 if( ucNormallyFullReceivedValues[ ux ] == 0 )
\r
532 /* A value was missing. */
\r
533 prvQueueAccessLogError( __LINE__ );
\r
535 else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )
\r
541 if( uxInterrupts == 0 )
\r
543 /* No writes from interrupts were found. Are interrupts
\r
544 actually running? */
\r
545 prvQueueAccessLogError( __LINE__ );
\r
548 /* Reset the array ready for the next cycle. */
\r
549 memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
\r
551 uxHighPriorityLoops2++;
\r
552 uxValueForNormallyFullQueue = 0;
\r
554 /* Suspend ourselves, allowing the lower priority task to
\r
555 actually receive something from the queue. Until now it
\r
556 will have been prevented from doing so by the higher
\r
557 priority tasks. The lower priority task will resume us
\r
558 if it receives something. We will then resume the other
\r
559 higher priority task. */
\r
560 vTaskSuspend( NULL );
\r
561 vTaskResume( xHighPriorityNormallyFullTask2 );
\r
565 /*-----------------------------------------------------------*/
\r
567 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )
\r
569 unsigned portBASE_TYPE uxValueToTx, ux;
\r
571 /* The parameters are not being used so avoid compiler warnings. */
\r
572 ( void ) pvParameters;
\r
574 /* Make sure the queue starts full or near full. >> 1 as there are two
\r
575 high priority tasks. */
\r
576 for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
\r
578 portENTER_CRITICAL();
\r
580 uxValueForNormallyFullQueue++;
\r
581 uxValueToTx = uxValueForNormallyFullQueue;
\r
583 portEXIT_CRITICAL();
\r
585 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
\r
590 portENTER_CRITICAL();
\r
592 uxValueForNormallyFullQueue++;
\r
593 uxValueToTx = uxValueForNormallyFullQueue;
\r
595 portEXIT_CRITICAL();
\r
597 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
\r
599 if( xWasSuspended != pdTRUE )
\r
601 /* It is ok to time out if the task has been suspended. */
\r
602 prvQueueAccessLogError( __LINE__ );
\r
606 xWasSuspended = pdFALSE;
\r
611 /*-----------------------------------------------------------*/
\r
613 static void prvLowerPriorityNormallyFullTask( void *pvParameters )
\r
615 unsigned portBASE_TYPE uxValue, uxTxed = 9999;
\r
617 /* The parameters are not being used so avoid compiler warnings. */
\r
618 ( void ) pvParameters;
\r
622 if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )
\r
624 /* We would only expect to succeed when the higher priority task
\r
626 if( xTaskIsTaskSuspended( xHighPriorityNormallyFullTask1 ) == pdFALSE )
\r
628 prvQueueAccessLogError( __LINE__ );
\r
631 vTaskResume( xHighPriorityNormallyFullTask1 );
\r
632 uxLowPriorityLoops2++;
\r
636 /* Raise our priority while we receive so we can preempt the higher
\r
637 priority task, and ensure we get the value from the queue. */
\r
638 vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
\r
640 if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
\r
642 prvQueueAccessLogError( __LINE__ );
\r
646 prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
\r
649 vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
\r
653 /*-----------------------------------------------------------*/
\r
655 portBASE_TYPE xFirstTimerHandler( void )
\r
657 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, uxRxedValue;
\r
658 static unsigned portBASE_TYPE uxNextOperation = 0;
\r
660 /* Called from a timer interrupt. Perform various read and write
\r
661 accesses on the queues. */
\r
665 if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
\r
667 timerNORMALLY_EMPTY_TX();
\r
668 timerNORMALLY_EMPTY_TX();
\r
669 timerNORMALLY_EMPTY_TX();
\r
673 timerNORMALLY_FULL_RX();
\r
674 timerNORMALLY_FULL_RX();
\r
675 timerNORMALLY_FULL_RX();
\r
678 return xHigherPriorityTaskWoken;
\r
680 /*-----------------------------------------------------------*/
\r
682 portBASE_TYPE xSecondTimerHandler( void )
\r
684 unsigned portBASE_TYPE uxRxedValue;
\r
685 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
686 static unsigned portBASE_TYPE uxNextOperation = 0;
\r
688 /* Called from a timer interrupt. Perform various read and write
\r
689 accesses on the queues. */
\r
693 if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
\r
695 timerNORMALLY_EMPTY_TX();
\r
696 timerNORMALLY_EMPTY_TX();
\r
698 timerNORMALLY_EMPTY_RX();
\r
699 timerNORMALLY_EMPTY_RX();
\r
703 timerNORMALLY_FULL_RX();
\r
704 timerNORMALLY_FULL_TX();
\r
705 timerNORMALLY_FULL_TX();
\r
706 timerNORMALLY_FULL_TX();
\r
707 timerNORMALLY_FULL_TX();
\r
710 return xHigherPriorityTaskWoken;
\r
712 /*-----------------------------------------------------------*/
\r
715 portBASE_TYPE xAreIntQueueTasksStillRunning( void )
\r
717 static unsigned portBASE_TYPE uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
\r
719 /* xErrorStatus can be set outside of this function. This function just
\r
720 checks that all the tasks are still cycling. */
\r
722 if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
\r
724 /* The high priority 1 task has stalled. */
\r
725 prvQueueAccessLogError( __LINE__ );
\r
728 uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
\r
730 if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
\r
732 /* The high priority 2 task has stalled. */
\r
733 prvQueueAccessLogError( __LINE__ );
\r
736 uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
\r
738 if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
\r
740 /* The low priority 1 task has stalled. */
\r
741 prvQueueAccessLogError( __LINE__ );
\r
744 uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
\r
746 if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
\r
748 /* The low priority 2 task has stalled. */
\r
749 prvQueueAccessLogError( __LINE__ );
\r
752 uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
\r
754 return xErrorStatus;
\r