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