2 FreeRTOS V8.0.1 - 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 !<<
\r
28 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
29 >>! obliged to provide the source code for proprietary components !<<
\r
30 >>! outside of the FreeRTOS kernel. !<<
\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 #if( INCLUDE_eTaskGetState != 1 )
\r
94 #error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file.
\r
97 /* Priorities used by test tasks. */
\r
98 #ifndef intqHIGHER_PRIORITY
\r
99 #define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )
\r
101 #define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
\r
103 /* The number of values to send/receive before checking that all values were
\r
104 processed as expected. */
\r
105 #define intqNUM_VALUES_TO_LOG ( 200 )
\r
106 #define intqSHORT_DELAY ( 140 )
\r
108 /* The value by which the value being sent to or received from a queue should
\r
109 increment past intqNUM_VALUES_TO_LOG before we check that all values have been
\r
110 sent/received correctly. This is done to ensure that all tasks and interrupts
\r
111 accessing the queue have completed their accesses with the
\r
112 intqNUM_VALUES_TO_LOG range. */
\r
113 #define intqVALUE_OVERRUN ( 50 )
\r
115 /* The delay used by the polling task. A short delay is used for code
\r
117 #define intqONE_TICK_DELAY ( 1 )
\r
119 /* Each task and interrupt is given a unique identifier. This value is used to
\r
120 identify which task sent or received each value. The identifier is also used
\r
121 to distinguish between two tasks that are running the same task function. */
\r
122 #define intqHIGH_PRIORITY_TASK1 ( ( unsigned portBASE_TYPE ) 1 )
\r
123 #define intqHIGH_PRIORITY_TASK2 ( ( unsigned portBASE_TYPE ) 2 )
\r
124 #define intqLOW_PRIORITY_TASK ( ( unsigned portBASE_TYPE ) 3 )
\r
125 #define intqFIRST_INTERRUPT ( ( unsigned portBASE_TYPE ) 4 )
\r
126 #define intqSECOND_INTERRUPT ( ( unsigned portBASE_TYPE ) 5 )
\r
127 #define intqQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 10 )
\r
129 /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
\r
130 from each queue by each task, otherwise an error is detected. */
\r
131 #define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
\r
133 /* Send the next value to the queue that is normally empty. This is called
\r
134 from within the interrupts. */
\r
135 #define timerNORMALLY_EMPTY_TX() \
\r
136 if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
\r
138 unsigned portBASE_TYPE uxSavedInterruptStatus; \
\r
139 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
141 uxValueForNormallyEmptyQueue++; \
\r
142 xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ); \
\r
144 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
147 /* Send the next value to the queue that is normally full. This is called
\r
148 from within the interrupts. */
\r
149 #define timerNORMALLY_FULL_TX() \
\r
150 if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
\r
152 unsigned portBASE_TYPE uxSavedInterruptStatus; \
\r
153 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
155 uxValueForNormallyFullQueue++; \
\r
156 xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ); \
\r
158 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
161 /* Receive a value from the normally empty queue. This is called from within
\r
163 #define timerNORMALLY_EMPTY_RX() \
\r
164 if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
\r
166 prvQueueAccessLogError( __LINE__ ); \
\r
170 prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \
\r
173 /* Receive a value from the normally full queue. This is called from within
\r
175 #define timerNORMALLY_FULL_RX() \
\r
176 if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
\r
178 prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \
\r
182 /*-----------------------------------------------------------*/
\r
184 /* The two queues used by the test. */
\r
185 static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue;
\r
187 /* Variables used to detect a stall in one of the tasks. */
\r
188 static unsigned portBASE_TYPE uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
\r
190 /* Any unexpected behaviour sets xErrorStatus to fail and log the line that
\r
191 caused the error in xErrorLine. */
\r
192 static portBASE_TYPE xErrorStatus = pdPASS;
\r
193 static volatile unsigned portBASE_TYPE xErrorLine = ( unsigned portBASE_TYPE ) 0;
\r
195 /* Used for sequencing between tasks. */
\r
196 static portBASE_TYPE xWasSuspended = pdFALSE;
\r
198 /* The values that are sent to the queues. An incremented value is sent each
\r
199 time to each queue. */
\r
200 volatile unsigned portBASE_TYPE uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
\r
202 /* A handle to some of the tasks is required so they can be suspended/resumed. */
\r
203 TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
\r
205 /* When a value is received in a queue the value is ticked off in the array
\r
206 the array position of the value is set to a the identifier of the task or
\r
207 interrupt that accessed the queue. This way missing or duplicate values can be
\r
209 static unsigned char ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
\r
210 static unsigned char ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
\r
212 /* The test tasks themselves. */
\r
213 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );
\r
214 static void prvLowerPriorityNormallyFullTask( void *pvParameters );
\r
215 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );
\r
216 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
\r
217 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );
\r
219 /* Used to mark the positions within the ucNormallyEmptyReceivedValues and
\r
220 ucNormallyFullReceivedValues arrays, while checking for duplicates. */
\r
221 static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
\r
222 static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
\r
224 /* Logs the line on which an error occurred. */
\r
225 static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine );
\r
227 /*-----------------------------------------------------------*/
\r
229 void vStartInterruptQueueTasks( void )
\r
231 /* Start the test tasks. */
\r
232 xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
\r
233 xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
\r
234 xTaskCreate( prvLowerPriorityNormallyEmptyTask, "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
\r
235 xTaskCreate( prv1stHigherPriorityNormallyFullTask, "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
\r
236 xTaskCreate( prv2ndHigherPriorityNormallyFullTask, "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
\r
237 xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
\r
239 /* Create the queues that are accessed by multiple tasks and multiple
\r
241 xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
\r
242 xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
\r
244 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
245 in use. The queue registry is provided as a means for kernel aware
\r
246 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
247 is not being used. The call to vQueueAddToRegistry() will be removed
\r
248 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
249 defined to be less than 1. */
\r
250 vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" );
\r
251 vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" );
\r
253 /*-----------------------------------------------------------*/
\r
255 static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
\r
257 if( uxValue < intqNUM_VALUES_TO_LOG )
\r
259 /* We don't expect to receive the same value twice, so if the value
\r
260 has already been marked as received an error has occurred. */
\r
261 if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
\r
263 prvQueueAccessLogError( __LINE__ );
\r
266 /* Log that this value has been received. */
\r
267 ucNormallyFullReceivedValues[ uxValue ] = ( unsigned char ) uxSource;
\r
270 /*-----------------------------------------------------------*/
\r
272 static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
\r
274 if( uxValue < intqNUM_VALUES_TO_LOG )
\r
276 /* We don't expect to receive the same value twice, so if the value
\r
277 has already been marked as received an error has occurred. */
\r
278 if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
\r
280 prvQueueAccessLogError( __LINE__ );
\r
283 /* Log that this value has been received. */
\r
284 ucNormallyEmptyReceivedValues[ uxValue ] = ( unsigned char ) uxSource;
\r
287 /*-----------------------------------------------------------*/
\r
289 static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine )
\r
291 /* Latch the line number that caused the error. */
\r
292 xErrorLine = uxLine;
\r
293 xErrorStatus = pdFAIL;
\r
295 /*-----------------------------------------------------------*/
\r
297 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
\r
299 unsigned portBASE_TYPE uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
\r
301 /* The timer should not be started until after the scheduler has started.
\r
302 More than one task is running this code so we check the parameter value
\r
303 to determine which task should start the timer. */
\r
304 if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
\r
306 vInitialiseTimerForIntQueueTest();
\r
311 /* Block waiting to receive a value from the normally empty queue.
\r
312 Interrupts will write to the queue so we should receive a value. */
\r
313 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
\r
315 prvQueueAccessLogError( __LINE__ );
\r
319 /* Note which value was received so we can check all expected
\r
320 values are received and no values are duplicated. */
\r
321 prvRecordValue_NormallyEmpty( uxRxed, ( unsigned portBASE_TYPE ) pvParameters );
\r
324 /* Ensure the other task running this code gets a chance to execute. */
\r
327 if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
\r
329 /* Have we received all the expected values? */
\r
330 if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
\r
332 vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
\r
338 /* Loop through the array, checking that both tasks have
\r
339 placed values into the array, and that no values are missing.
\r
340 Start at 1 as we expect position 0 to be unused. */
\r
341 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
\r
343 if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
\r
345 /* A value is missing. */
\r
346 prvQueueAccessLogError( __LINE__ );
\r
350 if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
\r
352 /* Value was placed into the array by task 1. */
\r
355 else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
\r
357 /* Value was placed into the array by task 2. */
\r
360 else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )
\r
367 if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
\r
369 /* Only task 2 seemed to log any values. */
\r
371 if( uxErrorCount1 > 2 )
\r
373 prvQueueAccessLogError( __LINE__ );
\r
381 if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )
\r
383 /* Only task 1 seemed to log any values. */
\r
385 if( uxErrorCount2 > 2 )
\r
387 prvQueueAccessLogError( __LINE__ );
\r
395 if( uxInterrupts == 0 )
\r
397 prvQueueAccessLogError( __LINE__ );
\r
400 /* Clear the array again, ready to start a new cycle. */
\r
401 memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
\r
403 uxHighPriorityLoops1++;
\r
404 uxValueForNormallyEmptyQueue = 0;
\r
406 /* Suspend ourselves, allowing the lower priority task to
\r
407 actually receive something from the queue. Until now it
\r
408 will have been prevented from doing so by the higher
\r
409 priority tasks. The lower priority task will resume us
\r
410 if it receives something. We will then resume the other
\r
411 higher priority task. */
\r
412 vTaskSuspend( NULL );
\r
413 vTaskResume( xHighPriorityNormallyEmptyTask2 );
\r
418 /*-----------------------------------------------------------*/
\r
420 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )
\r
422 unsigned portBASE_TYPE uxValue, uxRxed;
\r
424 /* The parameters are not being used so avoid compiler warnings. */
\r
425 ( void ) pvParameters;
\r
429 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
\r
431 /* A value should only be obtained when the high priority task is
\r
433 if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended )
\r
435 prvQueueAccessLogError( __LINE__ );
\r
438 prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
\r
440 /* Wake the higher priority task again. */
\r
441 vTaskResume( xHighPriorityNormallyEmptyTask1 );
\r
442 uxLowPriorityLoops1++;
\r
446 /* Raise our priority while we send so we can preempt the higher
\r
447 priority task, and ensure we get the Tx value into the queue. */
\r
448 vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
\r
450 portENTER_CRITICAL();
\r
452 uxValueForNormallyEmptyQueue++;
\r
453 uxValue = uxValueForNormallyEmptyQueue;
\r
455 portEXIT_CRITICAL();
\r
457 if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
\r
459 prvQueueAccessLogError( __LINE__ );
\r
462 vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
\r
466 /*-----------------------------------------------------------*/
\r
468 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )
\r
470 unsigned portBASE_TYPE uxValueToTx, ux, uxInterrupts;
\r
472 /* The parameters are not being used so avoid compiler warnings. */
\r
473 ( void ) pvParameters;
\r
475 /* Make sure the queue starts full or near full. >> 1 as there are two
\r
476 high priority tasks. */
\r
477 for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
\r
479 portENTER_CRITICAL();
\r
481 uxValueForNormallyFullQueue++;
\r
482 uxValueToTx = uxValueForNormallyFullQueue;
\r
484 portEXIT_CRITICAL();
\r
486 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
\r
491 portENTER_CRITICAL();
\r
493 uxValueForNormallyFullQueue++;
\r
494 uxValueToTx = uxValueForNormallyFullQueue;
\r
496 portEXIT_CRITICAL();
\r
498 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
\r
500 /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
\r
501 expect it to ever time out. */
\r
502 prvQueueAccessLogError( __LINE__ );
\r
505 /* Allow the other task running this code to run. */
\r
508 /* Have all the expected values been sent to the queue? */
\r
509 if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
\r
511 /* Make sure the other high priority task completes its send of
\r
512 any values below intqNUM_VALUE_TO_LOG. */
\r
513 vTaskDelay( intqSHORT_DELAY );
\r
515 vTaskSuspend( xHighPriorityNormallyFullTask2 );
\r
517 if( xWasSuspended == pdTRUE )
\r
519 /* We would have expected the other high priority task to have
\r
520 set this back to false by now. */
\r
521 prvQueueAccessLogError( __LINE__ );
\r
524 /* Set the suspended flag so an error is not logged if the other
\r
525 task recognises a time out when it is unsuspended. */
\r
526 xWasSuspended = pdTRUE;
\r
528 /* Check interrupts are also sending. */
\r
531 /* Start at 1 as we expect position 0 to be unused. */
\r
532 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
\r
534 if( ucNormallyFullReceivedValues[ ux ] == 0 )
\r
536 /* A value was missing. */
\r
537 prvQueueAccessLogError( __LINE__ );
\r
539 else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )
\r
545 if( uxInterrupts == 0 )
\r
547 /* No writes from interrupts were found. Are interrupts
\r
548 actually running? */
\r
549 prvQueueAccessLogError( __LINE__ );
\r
552 /* Reset the array ready for the next cycle. */
\r
553 memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
\r
555 uxHighPriorityLoops2++;
\r
556 uxValueForNormallyFullQueue = 0;
\r
558 /* Suspend ourselves, allowing the lower priority task to
\r
559 actually receive something from the queue. Until now it
\r
560 will have been prevented from doing so by the higher
\r
561 priority tasks. The lower priority task will resume us
\r
562 if it receives something. We will then resume the other
\r
563 higher priority task. */
\r
564 vTaskSuspend( NULL );
\r
565 vTaskResume( xHighPriorityNormallyFullTask2 );
\r
569 /*-----------------------------------------------------------*/
\r
571 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )
\r
573 unsigned portBASE_TYPE uxValueToTx, ux;
\r
575 /* The parameters are not being used so avoid compiler warnings. */
\r
576 ( void ) pvParameters;
\r
578 /* Make sure the queue starts full or near full. >> 1 as there are two
\r
579 high priority tasks. */
\r
580 for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
\r
582 portENTER_CRITICAL();
\r
584 uxValueForNormallyFullQueue++;
\r
585 uxValueToTx = uxValueForNormallyFullQueue;
\r
587 portEXIT_CRITICAL();
\r
589 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
\r
594 portENTER_CRITICAL();
\r
596 uxValueForNormallyFullQueue++;
\r
597 uxValueToTx = uxValueForNormallyFullQueue;
\r
599 portEXIT_CRITICAL();
\r
601 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
\r
603 if( xWasSuspended != pdTRUE )
\r
605 /* It is ok to time out if the task has been suspended. */
\r
606 prvQueueAccessLogError( __LINE__ );
\r
610 xWasSuspended = pdFALSE;
\r
615 /*-----------------------------------------------------------*/
\r
617 static void prvLowerPriorityNormallyFullTask( void *pvParameters )
\r
619 unsigned portBASE_TYPE uxValue, uxTxed = 9999;
\r
621 /* The parameters are not being used so avoid compiler warnings. */
\r
622 ( void ) pvParameters;
\r
626 if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )
\r
628 /* Should only succeed when the higher priority task is suspended */
\r
629 if( eTaskGetState( xHighPriorityNormallyFullTask1 ) != eSuspended )
\r
631 prvQueueAccessLogError( __LINE__ );
\r
634 vTaskResume( xHighPriorityNormallyFullTask1 );
\r
635 uxLowPriorityLoops2++;
\r
639 /* Raise our priority while we receive so we can preempt the higher
\r
640 priority task, and ensure we get the value from the queue. */
\r
641 vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
\r
643 if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
\r
645 prvQueueAccessLogError( __LINE__ );
\r
649 prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
\r
652 vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
\r
656 /*-----------------------------------------------------------*/
\r
658 portBASE_TYPE xFirstTimerHandler( void )
\r
660 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
661 unsigned portBASE_TYPE uxRxedValue;
\r
662 static unsigned portBASE_TYPE uxNextOperation = 0;
\r
664 /* Called from a timer interrupt. Perform various read and write
\r
665 accesses on the queues. */
\r
669 if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
\r
671 timerNORMALLY_EMPTY_TX();
\r
672 timerNORMALLY_EMPTY_TX();
\r
673 timerNORMALLY_EMPTY_TX();
\r
677 timerNORMALLY_FULL_RX();
\r
678 timerNORMALLY_FULL_RX();
\r
679 timerNORMALLY_FULL_RX();
\r
682 return xHigherPriorityTaskWoken;
\r
684 /*-----------------------------------------------------------*/
\r
686 portBASE_TYPE xSecondTimerHandler( void )
\r
688 unsigned portBASE_TYPE uxRxedValue;
\r
689 portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
\r
690 static unsigned portBASE_TYPE uxNextOperation = 0;
\r
692 /* Called from a timer interrupt. Perform various read and write
\r
693 accesses on the queues. */
\r
697 if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
\r
699 timerNORMALLY_EMPTY_TX();
\r
700 timerNORMALLY_EMPTY_TX();
\r
702 timerNORMALLY_EMPTY_RX();
\r
703 timerNORMALLY_EMPTY_RX();
\r
707 timerNORMALLY_FULL_RX();
\r
708 timerNORMALLY_FULL_TX();
\r
709 timerNORMALLY_FULL_TX();
\r
710 timerNORMALLY_FULL_TX();
\r
711 timerNORMALLY_FULL_TX();
\r
714 return xHigherPriorityTaskWoken;
\r
716 /*-----------------------------------------------------------*/
\r
719 portBASE_TYPE xAreIntQueueTasksStillRunning( void )
\r
721 static unsigned portBASE_TYPE uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
\r
723 /* xErrorStatus can be set outside of this function. This function just
\r
724 checks that all the tasks are still cycling. */
\r
726 if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
\r
728 /* The high priority 1 task has stalled. */
\r
729 prvQueueAccessLogError( __LINE__ );
\r
732 uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
\r
734 if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
\r
736 /* The high priority 2 task has stalled. */
\r
737 prvQueueAccessLogError( __LINE__ );
\r
740 uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
\r
742 if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
\r
744 /* The low priority 1 task has stalled. */
\r
745 prvQueueAccessLogError( __LINE__ );
\r
748 uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
\r
750 if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
\r
752 /* The low priority 2 task has stalled. */
\r
753 prvQueueAccessLogError( __LINE__ );
\r
756 uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
\r
758 return xErrorStatus;
\r