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