2 FreeRTOS V9.0.1 - Copyright (C) 2017 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 ***************************************************************************
\r
14 >>! NOTE: The modification to the GPL is included to allow you to !<<
\r
15 >>! distribute a combined work that includes FreeRTOS without being !<<
\r
16 >>! obliged to provide the source code for proprietary components !<<
\r
17 >>! outside of the FreeRTOS kernel. !<<
\r
18 ***************************************************************************
\r
20 FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
\r
21 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
\r
22 FOR A PARTICULAR PURPOSE. Full license text is available on the following
\r
23 link: http://www.freertos.org/a00114.html
\r
25 ***************************************************************************
\r
27 * FreeRTOS provides completely free yet professionally developed, *
\r
28 * robust, strictly quality controlled, supported, and cross *
\r
29 * platform software that is more than just the market leader, it *
\r
30 * is the industry's de facto standard. *
\r
32 * Help yourself get started quickly while simultaneously helping *
\r
33 * to support the FreeRTOS project by purchasing a FreeRTOS *
\r
34 * tutorial book, reference manual, or both: *
\r
35 * http://www.FreeRTOS.org/Documentation *
\r
37 ***************************************************************************
\r
39 http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
\r
40 the FAQ page "My application does not run, what could be wrong?". Have you
\r
41 defined configASSERT()?
\r
43 http://www.FreeRTOS.org/support - In return for receiving this top quality
\r
44 embedded software for free we request you assist our global community by
\r
45 participating in the support forum.
\r
47 http://www.FreeRTOS.org/training - Investing in training allows your team to
\r
48 be as productive as possible as early as possible. Now you can receive
\r
49 FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
\r
50 Ltd, and the world's leading authority on the world's leading RTOS.
\r
52 http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
\r
53 including FreeRTOS+Trace - an indispensable productivity tool, a DOS
\r
54 compatible FAT file system, and our tiny thread aware UDP/IP stack.
\r
56 http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
\r
57 Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
\r
59 http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
\r
60 Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
\r
61 licenses offer ticketed support, indemnification and commercial middleware.
\r
63 http://www.SafeRTOS.com - High Integrity Systems also provide a safety
\r
64 engineered and independently SIL3 certified version for use in safety and
\r
65 mission critical applications that require provable dependability.
\r
71 * This file defines one of the more complex set of demo/test tasks. They are
\r
72 * designed to stress test the queue implementation though pseudo simultaneous
\r
73 * multiple reads and multiple writes from both tasks of varying priority and
\r
74 * interrupts. The interrupts are prioritised such to ensure that nesting
\r
75 * occurs (for those ports that support it).
\r
77 * The test ensures that, while being accessed from three tasks and two
\r
78 * interrupts, all the data sent to the queues is also received from
\r
79 * the same queue, and that no duplicate items are either sent or received.
\r
80 * The tests also ensure that a low priority task is never able to successfully
\r
81 * read from or write to a queue when a task of higher priority is attempting
\r
82 * the same operation.
\r
85 /* Standard includes. */
\r
88 /* SafeRTOS includes. */
\r
89 #include "FreeRTOS.h"
\r
93 /* Demo app includes. */
\r
94 #include "IntQueue.h"
\r
95 #include "IntQueueTimer.h"
\r
97 #if( INCLUDE_eTaskGetState != 1 )
\r
98 #error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file.
\r
101 /* Priorities used by test tasks. */
\r
102 #ifndef intqHIGHER_PRIORITY
\r
103 #define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )
\r
105 #define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
\r
107 /* The number of values to send/receive before checking that all values were
\r
108 processed as expected. */
\r
109 #define intqNUM_VALUES_TO_LOG ( 200 )
\r
110 #define intqSHORT_DELAY ( 140 )
\r
112 /* The value by which the value being sent to or received from a queue should
\r
113 increment past intqNUM_VALUES_TO_LOG before we check that all values have been
\r
114 sent/received correctly. This is done to ensure that all tasks and interrupts
\r
115 accessing the queue have completed their accesses with the
\r
116 intqNUM_VALUES_TO_LOG range. */
\r
117 #define intqVALUE_OVERRUN ( 50 )
\r
119 /* The delay used by the polling task. A short delay is used for code
\r
121 #define intqONE_TICK_DELAY ( 1 )
\r
123 /* Each task and interrupt is given a unique identifier. This value is used to
\r
124 identify which task sent or received each value. The identifier is also used
\r
125 to distinguish between two tasks that are running the same task function. */
\r
126 #define intqHIGH_PRIORITY_TASK1 ( ( UBaseType_t ) 1 )
\r
127 #define intqHIGH_PRIORITY_TASK2 ( ( UBaseType_t ) 2 )
\r
128 #define intqLOW_PRIORITY_TASK ( ( UBaseType_t ) 3 )
\r
129 #define intqFIRST_INTERRUPT ( ( UBaseType_t ) 4 )
\r
130 #define intqSECOND_INTERRUPT ( ( UBaseType_t ) 5 )
\r
131 #define intqQUEUE_LENGTH ( ( UBaseType_t ) 10 )
\r
133 /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
\r
134 from each queue by each task, otherwise an error is detected. */
\r
135 #define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
\r
137 /* Send the next value to the queue that is normally empty. This is called
\r
138 from within the interrupts. */
\r
139 #define timerNORMALLY_EMPTY_TX() \
\r
140 if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
\r
142 UBaseType_t uxSavedInterruptStatus; \
\r
143 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
145 uxValueForNormallyEmptyQueue++; \
\r
146 if( xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \
\r
148 uxValueForNormallyEmptyQueue--; \
\r
151 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
154 /* Send the next value to the queue that is normally full. This is called
\r
155 from within the interrupts. */
\r
156 #define timerNORMALLY_FULL_TX() \
\r
157 if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
\r
159 UBaseType_t uxSavedInterruptStatus; \
\r
160 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
\r
162 uxValueForNormallyFullQueue++; \
\r
163 if( xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \
\r
165 uxValueForNormallyFullQueue--; \
\r
168 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
\r
171 /* Receive a value from the normally empty queue. This is called from within
\r
173 #define timerNORMALLY_EMPTY_RX() \
\r
174 if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
\r
176 prvQueueAccessLogError( __LINE__ ); \
\r
180 prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \
\r
183 /* Receive a value from the normally full queue. This is called from within
\r
185 #define timerNORMALLY_FULL_RX() \
\r
186 if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
\r
188 prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \
\r
192 /*-----------------------------------------------------------*/
\r
194 /* The two queues used by the test. */
\r
195 static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue;
\r
197 /* Variables used to detect a stall in one of the tasks. */
\r
198 static volatile UBaseType_t uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
\r
200 /* Any unexpected behaviour sets xErrorStatus to fail and log the line that
\r
201 caused the error in xErrorLine. */
\r
202 static BaseType_t xErrorStatus = pdPASS;
\r
203 static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0;
\r
205 /* Used for sequencing between tasks. */
\r
206 static BaseType_t xWasSuspended = pdFALSE;
\r
208 /* The values that are sent to the queues. An incremented value is sent each
\r
209 time to each queue. */
\r
210 static volatile UBaseType_t uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
\r
212 /* A handle to some of the tasks is required so they can be suspended/resumed. */
\r
213 TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
\r
215 /* When a value is received in a queue the value is ticked off in the array
\r
216 the array position of the value is set to a the identifier of the task or
\r
217 interrupt that accessed the queue. This way missing or duplicate values can be
\r
219 static uint8_t ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
\r
220 static uint8_t ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
\r
222 /* The test tasks themselves. */
\r
223 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );
\r
224 static void prvLowerPriorityNormallyFullTask( void *pvParameters );
\r
225 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );
\r
226 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
\r
227 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );
\r
229 /* Used to mark the positions within the ucNormallyEmptyReceivedValues and
\r
230 ucNormallyFullReceivedValues arrays, while checking for duplicates. */
\r
231 static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource );
\r
232 static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource );
\r
234 /* Logs the line on which an error occurred. */
\r
235 static void prvQueueAccessLogError( UBaseType_t uxLine );
\r
237 /*-----------------------------------------------------------*/
\r
239 void vStartInterruptQueueTasks( void )
\r
241 /* Start the test tasks. */
\r
242 xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
\r
243 xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
\r
244 xTaskCreate( prvLowerPriorityNormallyEmptyTask, "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
\r
245 xTaskCreate( prv1stHigherPriorityNormallyFullTask, "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
\r
246 xTaskCreate( prv2ndHigherPriorityNormallyFullTask, "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
\r
247 xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
\r
249 /* Create the queues that are accessed by multiple tasks and multiple
\r
251 xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
\r
252 xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
\r
254 /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
\r
255 in use. The queue registry is provided as a means for kernel aware
\r
256 debuggers to locate queues and has no purpose if a kernel aware debugger
\r
257 is not being used. The call to vQueueAddToRegistry() will be removed
\r
258 by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
\r
259 defined to be less than 1. */
\r
260 vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" );
\r
261 vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" );
\r
263 /*-----------------------------------------------------------*/
\r
265 static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource )
\r
267 if( uxValue < intqNUM_VALUES_TO_LOG )
\r
269 /* We don't expect to receive the same value twice, so if the value
\r
270 has already been marked as received an error has occurred. */
\r
271 if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
\r
273 prvQueueAccessLogError( __LINE__ );
\r
276 /* Log that this value has been received. */
\r
277 ucNormallyFullReceivedValues[ uxValue ] = ( uint8_t ) uxSource;
\r
280 /*-----------------------------------------------------------*/
\r
282 static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource )
\r
284 if( uxValue < intqNUM_VALUES_TO_LOG )
\r
286 /* We don't expect to receive the same value twice, so if the value
\r
287 has already been marked as received an error has occurred. */
\r
288 if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
\r
290 prvQueueAccessLogError( __LINE__ );
\r
293 /* Log that this value has been received. */
\r
294 ucNormallyEmptyReceivedValues[ uxValue ] = ( uint8_t ) uxSource;
\r
297 /*-----------------------------------------------------------*/
\r
299 static void prvQueueAccessLogError( UBaseType_t uxLine )
\r
301 /* Latch the line number that caused the error. */
\r
302 xErrorLine = uxLine;
\r
303 xErrorStatus = pdFAIL;
\r
305 /*-----------------------------------------------------------*/
\r
307 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
\r
309 UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
\r
311 /* The timer should not be started until after the scheduler has started.
\r
312 More than one task is running this code so we check the parameter value
\r
313 to determine which task should start the timer. */
\r
314 if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
\r
316 vInitialiseTimerForIntQueueTest();
\r
321 /* Block waiting to receive a value from the normally empty queue.
\r
322 Interrupts will write to the queue so we should receive a value. */
\r
323 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
\r
325 prvQueueAccessLogError( __LINE__ );
\r
329 /* Note which value was received so we can check all expected
\r
330 values are received and no values are duplicated. */
\r
331 prvRecordValue_NormallyEmpty( uxRxed, ( UBaseType_t ) pvParameters );
\r
334 /* Ensure the other task running this code gets a chance to execute. */
\r
337 if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
\r
339 /* Have we received all the expected values? */
\r
340 if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
\r
342 vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
\r
348 /* Loop through the array, checking that both tasks have
\r
349 placed values into the array, and that no values are missing.
\r
350 Start at 1 as we expect position 0 to be unused. */
\r
351 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
\r
353 if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
\r
355 /* A value is missing. */
\r
356 prvQueueAccessLogError( __LINE__ );
\r
360 if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
\r
362 /* Value was placed into the array by task 1. */
\r
365 else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
\r
367 /* Value was placed into the array by task 2. */
\r
370 else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )
\r
377 if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
\r
379 /* Only task 2 seemed to log any values. */
\r
381 if( uxErrorCount1 > 2 )
\r
383 prvQueueAccessLogError( __LINE__ );
\r
391 if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )
\r
393 /* Only task 1 seemed to log any values. */
\r
395 if( uxErrorCount2 > 2 )
\r
397 prvQueueAccessLogError( __LINE__ );
\r
405 if( uxInterrupts == 0 )
\r
407 prvQueueAccessLogError( __LINE__ );
\r
410 /* Clear the array again, ready to start a new cycle. */
\r
411 memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
\r
413 uxHighPriorityLoops1++;
\r
414 uxValueForNormallyEmptyQueue = 0;
\r
416 /* Suspend ourselves, allowing the lower priority task to
\r
417 actually receive something from the queue. Until now it
\r
418 will have been prevented from doing so by the higher
\r
419 priority tasks. The lower priority task will resume us
\r
420 if it receives something. We will then resume the other
\r
421 higher priority task. */
\r
422 vTaskSuspend( NULL );
\r
423 vTaskResume( xHighPriorityNormallyEmptyTask2 );
\r
428 /*-----------------------------------------------------------*/
\r
430 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )
\r
432 UBaseType_t uxValue, uxRxed;
\r
434 /* The parameters are not being used so avoid compiler warnings. */
\r
435 ( void ) pvParameters;
\r
439 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
\r
441 /* A value should only be obtained when the high priority task is
\r
443 if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended )
\r
445 prvQueueAccessLogError( __LINE__ );
\r
448 prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
\r
450 /* Wake the higher priority task again. */
\r
451 vTaskResume( xHighPriorityNormallyEmptyTask1 );
\r
452 uxLowPriorityLoops1++;
\r
456 /* Raise our priority while we send so we can preempt the higher
\r
457 priority task, and ensure we get the Tx value into the queue. */
\r
458 vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
\r
460 portENTER_CRITICAL();
\r
462 uxValueForNormallyEmptyQueue++;
\r
463 uxValue = uxValueForNormallyEmptyQueue;
\r
465 portEXIT_CRITICAL();
\r
467 if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
\r
469 prvQueueAccessLogError( __LINE__ );
\r
472 vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
\r
476 /*-----------------------------------------------------------*/
\r
478 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )
\r
480 UBaseType_t uxValueToTx, ux, uxInterrupts;
\r
482 /* The parameters are not being used so avoid compiler warnings. */
\r
483 ( void ) pvParameters;
\r
485 /* Make sure the queue starts full or near full. >> 1 as there are two
\r
486 high priority tasks. */
\r
487 for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
\r
489 portENTER_CRITICAL();
\r
491 uxValueForNormallyFullQueue++;
\r
492 uxValueToTx = uxValueForNormallyFullQueue;
\r
494 portEXIT_CRITICAL();
\r
496 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
\r
501 portENTER_CRITICAL();
\r
503 uxValueForNormallyFullQueue++;
\r
504 uxValueToTx = uxValueForNormallyFullQueue;
\r
506 portEXIT_CRITICAL();
\r
508 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
\r
510 /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
\r
511 expect it to ever time out. */
\r
512 prvQueueAccessLogError( __LINE__ );
\r
515 /* Allow the other task running this code to run. */
\r
518 /* Have all the expected values been sent to the queue? */
\r
519 if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
\r
521 /* Make sure the other high priority task completes its send of
\r
522 any values below intqNUM_VALUE_TO_LOG. */
\r
523 vTaskDelay( intqSHORT_DELAY );
\r
525 vTaskSuspend( xHighPriorityNormallyFullTask2 );
\r
527 if( xWasSuspended == pdTRUE )
\r
529 /* We would have expected the other high priority task to have
\r
530 set this back to false by now. */
\r
531 prvQueueAccessLogError( __LINE__ );
\r
534 /* Set the suspended flag so an error is not logged if the other
\r
535 task recognises a time out when it is unsuspended. */
\r
536 xWasSuspended = pdTRUE;
\r
538 /* Check interrupts are also sending. */
\r
541 /* Start at 1 as we expect position 0 to be unused. */
\r
542 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
\r
544 if( ucNormallyFullReceivedValues[ ux ] == 0 )
\r
546 /* A value was missing. */
\r
547 prvQueueAccessLogError( __LINE__ );
\r
549 else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )
\r
555 if( uxInterrupts == 0 )
\r
557 /* No writes from interrupts were found. Are interrupts
\r
558 actually running? */
\r
559 prvQueueAccessLogError( __LINE__ );
\r
562 /* Reset the array ready for the next cycle. */
\r
563 memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
\r
565 uxHighPriorityLoops2++;
\r
566 uxValueForNormallyFullQueue = 0;
\r
568 /* Suspend ourselves, allowing the lower priority task to
\r
569 actually receive something from the queue. Until now it
\r
570 will have been prevented from doing so by the higher
\r
571 priority tasks. The lower priority task will resume us
\r
572 if it receives something. We will then resume the other
\r
573 higher priority task. */
\r
574 vTaskSuspend( NULL );
\r
575 vTaskResume( xHighPriorityNormallyFullTask2 );
\r
579 /*-----------------------------------------------------------*/
\r
581 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )
\r
583 UBaseType_t uxValueToTx, ux;
\r
585 /* The parameters are not being used so avoid compiler warnings. */
\r
586 ( void ) pvParameters;
\r
588 /* Make sure the queue starts full or near full. >> 1 as there are two
\r
589 high priority tasks. */
\r
590 for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
\r
592 portENTER_CRITICAL();
\r
594 uxValueForNormallyFullQueue++;
\r
595 uxValueToTx = uxValueForNormallyFullQueue;
\r
597 portEXIT_CRITICAL();
\r
599 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
\r
604 portENTER_CRITICAL();
\r
606 uxValueForNormallyFullQueue++;
\r
607 uxValueToTx = uxValueForNormallyFullQueue;
\r
609 portEXIT_CRITICAL();
\r
611 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
\r
613 if( xWasSuspended != pdTRUE )
\r
615 /* It is ok to time out if the task has been suspended. */
\r
616 prvQueueAccessLogError( __LINE__ );
\r
620 xWasSuspended = pdFALSE;
\r
625 /*-----------------------------------------------------------*/
\r
627 static void prvLowerPriorityNormallyFullTask( void *pvParameters )
\r
629 UBaseType_t uxValue, uxTxed = 9999;
\r
631 /* The parameters are not being used so avoid compiler warnings. */
\r
632 ( void ) pvParameters;
\r
636 if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )
\r
638 /* Should only succeed when the higher priority task is suspended */
\r
639 if( eTaskGetState( xHighPriorityNormallyFullTask1 ) != eSuspended )
\r
641 prvQueueAccessLogError( __LINE__ );
\r
644 vTaskResume( xHighPriorityNormallyFullTask1 );
\r
645 uxLowPriorityLoops2++;
\r
649 /* Raise our priority while we receive so we can preempt the higher
\r
650 priority task, and ensure we get the value from the queue. */
\r
651 vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
\r
653 if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
\r
655 prvQueueAccessLogError( __LINE__ );
\r
659 prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
\r
662 vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
\r
666 /*-----------------------------------------------------------*/
\r
668 BaseType_t xFirstTimerHandler( void )
\r
670 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
671 UBaseType_t uxRxedValue;
\r
672 static UBaseType_t uxNextOperation = 0;
\r
674 /* Called from a timer interrupt. Perform various read and write
\r
675 accesses on the queues. */
\r
679 if( uxNextOperation & ( UBaseType_t ) 0x01 )
\r
681 timerNORMALLY_EMPTY_TX();
\r
682 timerNORMALLY_EMPTY_TX();
\r
683 timerNORMALLY_EMPTY_TX();
\r
687 timerNORMALLY_FULL_RX();
\r
688 timerNORMALLY_FULL_RX();
\r
689 timerNORMALLY_FULL_RX();
\r
692 return xHigherPriorityTaskWoken;
\r
694 /*-----------------------------------------------------------*/
\r
696 BaseType_t xSecondTimerHandler( void )
\r
698 UBaseType_t uxRxedValue;
\r
699 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
\r
700 static UBaseType_t uxNextOperation = 0;
\r
702 /* Called from a timer interrupt. Perform various read and write
\r
703 accesses on the queues. */
\r
707 if( uxNextOperation & ( UBaseType_t ) 0x01 )
\r
709 timerNORMALLY_EMPTY_TX();
\r
710 timerNORMALLY_EMPTY_TX();
\r
712 timerNORMALLY_EMPTY_RX();
\r
713 timerNORMALLY_EMPTY_RX();
\r
717 timerNORMALLY_FULL_RX();
\r
718 timerNORMALLY_FULL_TX();
\r
719 timerNORMALLY_FULL_TX();
\r
720 timerNORMALLY_FULL_TX();
\r
723 return xHigherPriorityTaskWoken;
\r
725 /*-----------------------------------------------------------*/
\r
728 BaseType_t xAreIntQueueTasksStillRunning( void )
\r
730 static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
\r
732 /* xErrorStatus can be set outside of this function. This function just
\r
733 checks that all the tasks are still cycling. */
\r
735 if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
\r
737 /* The high priority 1 task has stalled. */
\r
738 prvQueueAccessLogError( __LINE__ );
\r
741 uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
\r
743 if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
\r
745 /* The high priority 2 task has stalled. */
\r
746 prvQueueAccessLogError( __LINE__ );
\r
749 uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
\r
751 if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
\r
753 /* The low priority 1 task has stalled. */
\r
754 prvQueueAccessLogError( __LINE__ );
\r
757 uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
\r
759 if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
\r
761 /* The low priority 2 task has stalled. */
\r
762 prvQueueAccessLogError( __LINE__ );
\r
765 uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
\r
767 return xErrorStatus;
\r