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