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