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