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