]> begriffs open source - cmsis-freertos/blob - Demo/Common/Minimal/IntQueue.c
Updated pack to FreeRTOS 10.3.1
[cmsis-freertos] / Demo / Common / Minimal / IntQueue.c
1 /*
2  * FreeRTOS Kernel V10.3.1
3  * Copyright (C) 2020 Amazon.com, Inc. or its affiliates.  All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a copy of
6  * this software and associated documentation files (the "Software"), to deal in
7  * the Software without restriction, including without limitation the rights to
8  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9  * the Software, and to permit persons to whom the Software is furnished to do so,
10  * subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included in all
13  * copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17  * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18  * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19  * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20  * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  *
22  * http://www.FreeRTOS.org
23  * http://aws.amazon.com/freertos
24  *
25  * 1 tab == 4 spaces!
26  */
27
28 /*
29  * This file defines one of the more complex set of demo/test tasks.  They are
30  * designed to stress test the queue implementation though pseudo simultaneous
31  * multiple reads and multiple writes from both tasks of varying priority and
32  * interrupts.  The interrupts are prioritised such to ensure that nesting
33  * occurs (for those ports that support it).
34  *
35  * The test ensures that, while being accessed from three tasks and two
36  * interrupts, all the data sent to the queues is also received from
37  * the same queue, and that no duplicate items are either sent or received.
38  * The tests also ensure that a low priority task is never able to successfully
39  * read from or write to a queue when a task of higher priority is attempting
40  * the same operation.
41  */
42
43 /* Standard includes. */
44 #include <string.h>
45
46 /* SafeRTOS includes. */
47 #include "FreeRTOS.h"
48 #include "queue.h"
49 #include "task.h"
50
51 /* Demo app includes. */
52 #include "IntQueue.h"
53 #include "IntQueueTimer.h"
54
55 #if( INCLUDE_eTaskGetState != 1 )
56         #error INCLUDE_eTaskGetState must be set to 1 in FreeRTOSConfig.h to use this demo file.
57 #endif
58
59 /* Priorities used by test tasks. */
60 #ifndef intqHIGHER_PRIORITY
61         #define intqHIGHER_PRIORITY             ( configMAX_PRIORITIES - 2 )
62 #endif
63 #define intqLOWER_PRIORITY              ( tskIDLE_PRIORITY )
64
65 /* The number of values to send/receive before checking that all values were
66 processed as expected. */
67 #define intqNUM_VALUES_TO_LOG   ( 200 )
68 #define intqSHORT_DELAY                 ( 140 )
69
70 /* The value by which the value being sent to or received from a queue should
71 increment past intqNUM_VALUES_TO_LOG before we check that all values have been
72 sent/received correctly.  This is done to ensure that all tasks and interrupts
73 accessing the queue have completed their accesses with the
74 intqNUM_VALUES_TO_LOG range. */
75 #define intqVALUE_OVERRUN               ( 50 )
76
77 /* The delay used by the polling task.  A short delay is used for code
78 coverage. */
79 #define intqONE_TICK_DELAY              ( 1 )
80
81 /* Each task and interrupt is given a unique identifier.  This value is used to
82 identify which task sent or received each value.  The identifier is also used
83 to distinguish between two tasks that are running the same task function. */
84 #define intqHIGH_PRIORITY_TASK1 ( ( UBaseType_t ) 1 )
85 #define intqHIGH_PRIORITY_TASK2 ( ( UBaseType_t ) 2 )
86 #define intqLOW_PRIORITY_TASK   ( ( UBaseType_t ) 3 )
87 #define intqFIRST_INTERRUPT             ( ( UBaseType_t ) 4 )
88 #define intqSECOND_INTERRUPT    ( ( UBaseType_t ) 5 )
89 #define intqQUEUE_LENGTH                ( ( UBaseType_t ) 10 )
90
91 /* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
92 from each queue by each task, otherwise an error is detected. */
93 #define intqMIN_ACCEPTABLE_TASK_COUNT           ( 5 )
94
95 /* Send the next value to the queue that is normally empty.  This is called
96 from within the interrupts. */
97 #define timerNORMALLY_EMPTY_TX()                                                                                                                                                                                        \
98         if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE )                                                                                                                 \
99         {                                                                                                                                                                                                                                               \
100         UBaseType_t uxSavedInterruptStatus;                                                                                                                                                                             \
101                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();                                                                                                                     \
102                 {                                                                                                                                                                                                                                       \
103                         uxValueForNormallyEmptyQueue++;                                                                                                                                                                 \
104                         if( xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \
105                         {                                                                                                                                                                                                                               \
106                                 uxValueForNormallyEmptyQueue--;                                                                                                                                                         \
107                         }                                                                                                                                                                                                                               \
108                 }                                                                                                                                                                                                                                       \
109                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                                                                                                            \
110         }                                                                                                                                                                                                                                               \
111
112 /* Send the next value to the queue that is normally full.  This is called
113 from within the interrupts. */
114 #define timerNORMALLY_FULL_TX()                                                                                                                                                                                         \
115         if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE )                                                                                                                  \
116         {                                                                                                                                                                                                                                               \
117         UBaseType_t uxSavedInterruptStatus;                                                                                                                                                                             \
118                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();                                                                                                                     \
119                 {                                                                                                                                                                                                                                       \
120                         uxValueForNormallyFullQueue++;                                                                                                                                                                  \
121                         if( xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \
122                         {                                                                                                                                                                                                                               \
123                                 uxValueForNormallyFullQueue--;                                                                                                                                                          \
124                         }                                                                                                                                                                                                                               \
125                 }                                                                                                                                                                                                                                       \
126                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                                                                                                            \
127         }                                                                                                                                                                                                                                               \
128
129 /* Receive a value from the normally empty queue.  This is called from within
130 an interrupt. */
131 #define timerNORMALLY_EMPTY_RX()                                                                                                                                                        \
132         if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS )    \
133         {                                                                                                                                                                                                               \
134                 prvQueueAccessLogError( __LINE__ );                                                                                                                                     \
135         }                                                                                                                                                                                                               \
136         else                                                                                                                                                                                                    \
137         {                                                                                                                                                                                                               \
138                 prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT );                                                                      \
139         }
140
141 /* Receive a value from the normally full queue.  This is called from within
142 an interrupt. */
143 #define timerNORMALLY_FULL_RX()                                                                                                                                                         \
144         if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS )             \
145         {                                                                                                                                                                                                               \
146                 prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT );                                                                       \
147         }                                                                                                                                                                                                               \
148
149
150 /*-----------------------------------------------------------*/
151
152 /* The two queues used by the test. */
153 static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue;
154
155 /* Variables used to detect a stall in one of the tasks. */
156 static volatile UBaseType_t uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
157
158 /* Any unexpected behaviour sets xErrorStatus to fail and log the line that
159 caused the error in xErrorLine. */
160 static BaseType_t xErrorStatus = pdPASS;
161 static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0;
162
163 /* Used for sequencing between tasks. */
164 static BaseType_t xWasSuspended = pdFALSE;
165
166 /* The values that are sent to the queues.  An incremented value is sent each
167 time to each queue. */
168 static volatile UBaseType_t uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
169
170 /* A handle to some of the tasks is required so they can be suspended/resumed. */
171 TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
172
173 /* When a value is received in a queue the value is ticked off in the array
174 the array position of the value is set to a the identifier of the task or
175 interrupt that accessed the queue.  This way missing or duplicate values can be
176 detected. */
177 static uint8_t ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
178 static uint8_t ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
179
180 /* The test tasks themselves. */
181 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );
182 static void prvLowerPriorityNormallyFullTask( void *pvParameters );
183 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );
184 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
185 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );
186
187 /* Used to mark the positions within the ucNormallyEmptyReceivedValues and
188 ucNormallyFullReceivedValues arrays, while checking for duplicates. */
189 static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource );
190 static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource );
191
192 /* Logs the line on which an error occurred. */
193 static void prvQueueAccessLogError( UBaseType_t uxLine );
194
195 /*-----------------------------------------------------------*/
196
197 void vStartInterruptQueueTasks( void )
198 {
199         /* Start the test tasks. */
200         xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
201         xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
202         xTaskCreate( prvLowerPriorityNormallyEmptyTask, "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
203         xTaskCreate( prv1stHigherPriorityNormallyFullTask, "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
204         xTaskCreate( prv2ndHigherPriorityNormallyFullTask, "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
205         xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
206
207         /* Create the queues that are accessed by multiple tasks and multiple
208         interrupts. */
209         xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
210         xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );
211
212         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
213         in use.  The queue registry is provided as a means for kernel aware
214         debuggers to locate queues and has no purpose if a kernel aware debugger
215         is not being used.  The call to vQueueAddToRegistry() will be removed
216         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
217         defined to be less than 1. */
218         vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" );
219         vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" );
220 }
221 /*-----------------------------------------------------------*/
222
223 static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource )
224 {
225         if( uxValue < intqNUM_VALUES_TO_LOG )
226         {
227                 /* We don't expect to receive the same value twice, so if the value
228                 has already been marked as received an error has occurred. */
229                 if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
230                 {
231                         prvQueueAccessLogError( __LINE__ );
232                 }
233
234                 /* Log that this value has been received. */
235                 ucNormallyFullReceivedValues[ uxValue ] = ( uint8_t ) uxSource;
236         }
237 }
238 /*-----------------------------------------------------------*/
239
240 static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource )
241 {
242         if( uxValue < intqNUM_VALUES_TO_LOG )
243         {
244                 /* We don't expect to receive the same value twice, so if the value
245                 has already been marked as received an error has occurred. */
246                 if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
247                 {
248                         prvQueueAccessLogError( __LINE__ );
249                 }
250
251                 /* Log that this value has been received. */
252                 ucNormallyEmptyReceivedValues[ uxValue ] = ( uint8_t ) uxSource;
253         }
254 }
255 /*-----------------------------------------------------------*/
256
257 static void prvQueueAccessLogError( UBaseType_t uxLine )
258 {
259         /* Latch the line number that caused the error. */
260         xErrorLine = uxLine;
261         xErrorStatus = pdFAIL;
262 }
263 /*-----------------------------------------------------------*/
264
265 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
266 {
267 UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
268
269         /* The timer should not be started until after the scheduler has started.
270         More than one task is running this code so we check the parameter value
271         to determine which task should start the timer. */
272         if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
273         {
274                 vInitialiseTimerForIntQueueTest();
275         }
276
277         for( ;; )
278         {
279                 /* Block waiting to receive a value from the normally empty queue.
280                 Interrupts will write to the queue so we should receive a value. */
281                 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
282                 {
283                         prvQueueAccessLogError( __LINE__ );
284                 }
285                 else
286                 {
287                         /* Note which value was received so we can check all expected
288                         values are received and no values are duplicated. */
289                         prvRecordValue_NormallyEmpty( uxRxed, ( UBaseType_t ) pvParameters );
290                 }
291
292                 /* Ensure the other task running this code gets a chance to execute. */
293                 taskYIELD();
294
295                 if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )
296                 {
297                         /* Have we received all the expected values? */
298                         if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
299                         {
300                                 vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
301
302                                 uxTask1 = 0;
303                                 uxTask2 = 0;
304                                 uxInterrupts = 0;
305
306                                 /* Loop through the array, checking that both tasks have
307                                 placed values into the array, and that no values are missing.
308                                 Start at 1 as we expect position 0 to be unused. */
309                                 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
310                                 {
311                                         if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
312                                         {
313                                                 /* A value is missing. */
314                                                 prvQueueAccessLogError( __LINE__ );
315                                         }
316                                         else
317                                         {
318                                                 if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
319                                                 {
320                                                         /* Value was placed into the array by task 1. */
321                                                         uxTask1++;
322                                                 }
323                                                 else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
324                                                 {
325                                                         /* Value was placed into the array by task 2. */
326                                                         uxTask2++;
327                                                 }
328                                                 else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )
329                                                 {
330                                                         uxInterrupts++;
331                                                 }
332                                         }
333                                 }
334
335                                 if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
336                                 {
337                                         /* Only task 2 seemed to log any values. */
338                                         uxErrorCount1++;
339                                         if( uxErrorCount1 > 2 )
340                                         {
341                                                 prvQueueAccessLogError( __LINE__ );
342                                         }
343                                 }
344                                 else
345                                 {
346                                         uxErrorCount1 = 0;
347                                 }
348
349                                 if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT  )
350                                 {
351                                         /* Only task 1 seemed to log any values. */
352                                         uxErrorCount2++;
353                                         if( uxErrorCount2 > 2 )
354                                         {
355                                                 prvQueueAccessLogError( __LINE__ );
356                                         }
357                                 }
358                                 else
359                                 {
360                                         uxErrorCount2 = 0;
361                                 }
362
363                                 if( uxInterrupts == 0 )
364                                 {
365                                         prvQueueAccessLogError( __LINE__ );
366                                 }
367
368                                 /* Clear the array again, ready to start a new cycle. */
369                                 memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
370
371                                 uxHighPriorityLoops1++;
372                                 uxValueForNormallyEmptyQueue = 0;
373
374                                 /* Suspend ourselves, allowing the lower priority task to
375                                 actually receive something from the queue.  Until now it
376                                 will have been prevented from doing so by the higher
377                                 priority tasks.  The lower priority task will resume us
378                                 if it receives something.  We will then resume the other
379                                 higher priority task. */
380                                 vTaskSuspend( NULL );
381                                 vTaskResume( xHighPriorityNormallyEmptyTask2 );
382                         }
383                 }
384         }
385 }
386 /*-----------------------------------------------------------*/
387
388 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )
389 {
390 UBaseType_t uxValue, uxRxed;
391
392         /* The parameters are not being used so avoid compiler warnings. */
393         ( void ) pvParameters;
394
395         for( ;; )
396         {
397                 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
398                 {
399                         /* A value should only be obtained when the high priority task is
400                         suspended. */
401                         if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended )
402                         {
403                                 prvQueueAccessLogError( __LINE__ );
404                         }
405
406                         prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
407
408                         /* Wake the higher priority task again. */
409                         vTaskResume( xHighPriorityNormallyEmptyTask1 );
410                         uxLowPriorityLoops1++;
411                 }
412                 else
413                 {
414                         /* Raise our priority while we send so we can preempt the higher
415                         priority task, and ensure we get the Tx value into the queue. */
416                         vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
417
418                         portENTER_CRITICAL();
419                         {
420                                 uxValueForNormallyEmptyQueue++;
421                                 uxValue = uxValueForNormallyEmptyQueue;
422                         }
423                         portEXIT_CRITICAL();
424
425                         if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
426                         {
427                                 prvQueueAccessLogError( __LINE__ );
428                         }
429
430                         vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
431                 }
432         }
433 }
434 /*-----------------------------------------------------------*/
435
436 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )
437 {
438 UBaseType_t uxValueToTx, ux, uxInterrupts;
439
440         /* The parameters are not being used so avoid compiler warnings. */
441         ( void ) pvParameters;
442
443         /* Make sure the queue starts full or near full.  >> 1 as there are two
444         high priority tasks. */
445         for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
446         {
447                 portENTER_CRITICAL();
448                 {
449                         uxValueForNormallyFullQueue++;
450                         uxValueToTx = uxValueForNormallyFullQueue;
451                 }
452                 portEXIT_CRITICAL();
453
454                 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
455         }
456
457         for( ;; )
458         {
459                 portENTER_CRITICAL();
460                 {
461                         uxValueForNormallyFullQueue++;
462                         uxValueToTx = uxValueForNormallyFullQueue;
463                 }
464                 portEXIT_CRITICAL();
465
466                 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
467                 {
468                         /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
469                         expect it to ever time out. */
470                         prvQueueAccessLogError( __LINE__ );
471                 }
472
473                 /* Allow the other task running this code to run. */
474                 taskYIELD();
475
476                 /* Have all the expected values been sent to the queue? */
477                 if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
478                 {
479                         /* Make sure the other high priority task completes its send of
480                         any values below intqNUM_VALUE_TO_LOG. */
481                         vTaskDelay( intqSHORT_DELAY );
482
483                         vTaskSuspend( xHighPriorityNormallyFullTask2 );
484
485                         if( xWasSuspended == pdTRUE )
486                         {
487                                 /* We would have expected the other high priority task to have
488                                 set this back to false by now. */
489                                 prvQueueAccessLogError( __LINE__ );
490                         }
491
492                         /* Set the suspended flag so an error is not logged if the other
493                         task recognises a time out when it is unsuspended. */
494                         xWasSuspended = pdTRUE;
495
496                         /* Check interrupts are also sending. */
497                         uxInterrupts = 0U;
498
499                         /* Start at 1 as we expect position 0 to be unused. */
500                         for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
501                         {
502                                 if( ucNormallyFullReceivedValues[ ux ] == 0 )
503                                 {
504                                         /* A value was missing. */
505                                         prvQueueAccessLogError( __LINE__ );
506                                 }
507                                 else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )
508                                 {
509                                         uxInterrupts++;
510                                 }
511                         }
512
513                         if( uxInterrupts == 0 )
514                         {
515                                 /* No writes from interrupts were found.  Are interrupts
516                                 actually running? */
517                                 prvQueueAccessLogError( __LINE__ );
518                         }
519
520                         /* Reset the array ready for the next cycle. */
521                         memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
522
523                         uxHighPriorityLoops2++;
524                         uxValueForNormallyFullQueue = 0;
525
526                         /* Suspend ourselves, allowing the lower priority task to
527                         actually receive something from the queue.  Until now it
528                         will have been prevented from doing so by the higher
529                         priority tasks.  The lower priority task will resume us
530                         if it receives something.  We will then resume the other
531                         higher priority task. */
532                         vTaskSuspend( NULL );
533                         vTaskResume( xHighPriorityNormallyFullTask2 );
534                 }
535         }
536 }
537 /*-----------------------------------------------------------*/
538
539 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )
540 {
541 UBaseType_t uxValueToTx, ux;
542
543         /* The parameters are not being used so avoid compiler warnings. */
544         ( void ) pvParameters;
545
546         /* Make sure the queue starts full or near full.  >> 1 as there are two
547         high priority tasks. */
548         for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
549         {
550                 portENTER_CRITICAL();
551                 {
552                         uxValueForNormallyFullQueue++;
553                         uxValueToTx = uxValueForNormallyFullQueue;
554                 }
555                 portEXIT_CRITICAL();
556
557                 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
558         }
559
560         for( ;; )
561         {
562                 portENTER_CRITICAL();
563                 {
564                         uxValueForNormallyFullQueue++;
565                         uxValueToTx = uxValueForNormallyFullQueue;
566                 }
567                 portEXIT_CRITICAL();
568
569                 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
570                 {
571                         if( xWasSuspended != pdTRUE )
572                         {
573                                 /* It is ok to time out if the task has been suspended. */
574                                 prvQueueAccessLogError( __LINE__ );
575                         }
576                 }
577
578                 xWasSuspended = pdFALSE;
579
580                 taskYIELD();
581         }
582 }
583 /*-----------------------------------------------------------*/
584
585 static void prvLowerPriorityNormallyFullTask( void *pvParameters )
586 {
587 UBaseType_t uxValue, uxTxed = 9999;
588
589         /* The parameters are not being used so avoid compiler warnings. */
590         ( void ) pvParameters;
591
592         for( ;; )
593         {
594                 if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )
595                 {
596                         /* Should only succeed when the higher priority task is suspended */
597                         if( eTaskGetState( xHighPriorityNormallyFullTask1 ) != eSuspended )
598                         {
599                                 prvQueueAccessLogError( __LINE__ );
600                         }
601
602                         vTaskResume( xHighPriorityNormallyFullTask1 );
603                         uxLowPriorityLoops2++;
604                 }
605                 else
606                 {
607                         /* Raise our priority while we receive so we can preempt the higher
608                         priority task, and ensure we get the value from the queue. */
609                         vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
610
611                         if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
612                         {
613                                 prvQueueAccessLogError( __LINE__ );
614                         }
615                         else
616                         {
617                                 prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
618                         }
619
620                         vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
621                 }
622         }
623 }
624 /*-----------------------------------------------------------*/
625
626 BaseType_t xFirstTimerHandler( void )
627 {
628 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
629 UBaseType_t uxRxedValue;
630 static UBaseType_t uxNextOperation = 0;
631
632         /* Called from a timer interrupt.  Perform various read and write
633         accesses on the queues. */
634
635         uxNextOperation++;
636
637         if( uxNextOperation & ( UBaseType_t ) 0x01 )
638         {
639                 timerNORMALLY_EMPTY_TX();
640                 timerNORMALLY_EMPTY_TX();
641                 timerNORMALLY_EMPTY_TX();
642         }
643         else
644         {
645                 timerNORMALLY_FULL_RX();
646                 timerNORMALLY_FULL_RX();
647                 timerNORMALLY_FULL_RX();
648         }
649
650         return xHigherPriorityTaskWoken;
651 }
652 /*-----------------------------------------------------------*/
653
654 BaseType_t xSecondTimerHandler( void )
655 {
656 UBaseType_t uxRxedValue;
657 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
658 static UBaseType_t uxNextOperation = 0;
659
660         /* Called from a timer interrupt.  Perform various read and write
661         accesses on the queues. */
662
663         uxNextOperation++;
664
665         if( uxNextOperation & ( UBaseType_t ) 0x01 )
666         {
667                 timerNORMALLY_EMPTY_TX();
668                 timerNORMALLY_EMPTY_TX();
669
670                 timerNORMALLY_EMPTY_RX();
671                 timerNORMALLY_EMPTY_RX();
672         }
673         else
674         {
675                 timerNORMALLY_FULL_RX();
676                 timerNORMALLY_FULL_TX();
677                 timerNORMALLY_FULL_TX();
678                 timerNORMALLY_FULL_TX();
679         }
680
681         return xHigherPriorityTaskWoken;
682 }
683 /*-----------------------------------------------------------*/
684
685
686 BaseType_t xAreIntQueueTasksStillRunning( void )
687 {
688 static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
689
690         /* xErrorStatus can be set outside of this function.  This function just
691         checks that all the tasks are still cycling. */
692
693         if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
694         {
695                 /* The high priority 1 task has stalled. */
696                 prvQueueAccessLogError( __LINE__ );
697         }
698
699         uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
700
701         if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
702         {
703                 /* The high priority 2 task has stalled. */
704                 prvQueueAccessLogError( __LINE__ );
705         }
706
707         uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
708
709         if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
710         {
711                 /* The low priority 1 task has stalled. */
712                 prvQueueAccessLogError( __LINE__ );
713         }
714
715         uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
716
717         if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
718         {
719                 /* The low priority 2 task has stalled. */
720                 prvQueueAccessLogError( __LINE__ );
721         }
722
723         uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
724
725         return xErrorStatus;
726 }
727