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