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