]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/Common/Minimal/IntQueue.c
Kernel changes:
[freertos] / FreeRTOS / Demo / Common / Minimal / IntQueue.c
1 /*\r
2     FreeRTOS V8.1.2 - 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                         if( xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \\r
143                         {                                                                                                                                                                                                                               \\r
144                                 uxValueForNormallyEmptyQueue--;                                                                                                                                                         \\r
145                         }                                                                                                                                                                                                                               \\r
146                 }                                                                                                                                                                                                                                       \\r
147                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                                                                                                            \\r
148         }                                                                                                                                                                                                                                               \\r
149 \r
150 /* Send the next value to the queue that is normally full.  This is called\r
151 from within the interrupts. */\r
152 #define timerNORMALLY_FULL_TX()                                                                                                                                                                                         \\r
153         if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE )                                                                                                                  \\r
154         {                                                                                                                                                                                                                                               \\r
155         UBaseType_t uxSavedInterruptStatus;                                                                                                                                                                             \\r
156                 uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();                                                                                                                     \\r
157                 {                                                                                                                                                                                                                                       \\r
158                         uxValueForNormallyFullQueue++;                                                                                                                                                                  \\r
159                         if( xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ) != pdPASS ) \\r
160                         {                                                                                                                                                                                                                               \\r
161                                 uxValueForNormallyFullQueue--;                                                                                                                                                          \\r
162                         }                                                                                                                                                                                                                               \\r
163                 }                                                                                                                                                                                                                                       \\r
164                 portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );                                                                                                            \\r
165         }                                                                                                                                                                                                                                               \\r
166 \r
167 /* Receive a value from the normally empty queue.  This is called from within\r
168 an interrupt. */\r
169 #define timerNORMALLY_EMPTY_RX()                                                                                                                                                        \\r
170         if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS )    \\r
171         {                                                                                                                                                                                                               \\r
172                 prvQueueAccessLogError( __LINE__ );                                                                                                                                     \\r
173         }                                                                                                                                                                                                               \\r
174         else                                                                                                                                                                                                    \\r
175         {                                                                                                                                                                                                               \\r
176                 prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT );                                                                      \\r
177         }\r
178 \r
179 /* Receive a value from the normally full queue.  This is called from within\r
180 an interrupt. */\r
181 #define timerNORMALLY_FULL_RX()                                                                                                                                                         \\r
182         if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS )             \\r
183         {                                                                                                                                                                                                               \\r
184                 prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT );                                                                       \\r
185         }                                                                                                                                                                                                               \\r
186 \r
187 \r
188 /*-----------------------------------------------------------*/\r
189 \r
190 /* The two queues used by the test. */\r
191 static QueueHandle_t xNormallyEmptyQueue, xNormallyFullQueue;\r
192 \r
193 /* Variables used to detect a stall in one of the tasks. */\r
194 static UBaseType_t uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;\r
195 \r
196 /* Any unexpected behaviour sets xErrorStatus to fail and log the line that\r
197 caused the error in xErrorLine. */\r
198 static BaseType_t xErrorStatus = pdPASS;\r
199 static volatile UBaseType_t xErrorLine = ( UBaseType_t ) 0;\r
200 \r
201 /* Used for sequencing between tasks. */\r
202 static BaseType_t xWasSuspended = pdFALSE;\r
203 \r
204 /* The values that are sent to the queues.  An incremented value is sent each\r
205 time to each queue. */\r
206 volatile UBaseType_t uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;\r
207 \r
208 /* A handle to some of the tasks is required so they can be suspended/resumed. */\r
209 TaskHandle_t xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;\r
210 \r
211 /* When a value is received in a queue the value is ticked off in the array\r
212 the array position of the value is set to a the identifier of the task or\r
213 interrupt that accessed the queue.  This way missing or duplicate values can be\r
214 detected. */\r
215 static uint8_t ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };\r
216 static uint8_t ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };\r
217 \r
218 /* The test tasks themselves. */\r
219 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );\r
220 static void prvLowerPriorityNormallyFullTask( void *pvParameters );\r
221 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );\r
222 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );\r
223 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );\r
224 \r
225 /* Used to mark the positions within the ucNormallyEmptyReceivedValues and\r
226 ucNormallyFullReceivedValues arrays, while checking for duplicates. */\r
227 static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource );\r
228 static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource );\r
229 \r
230 /* Logs the line on which an error occurred. */\r
231 static void prvQueueAccessLogError( UBaseType_t uxLine );\r
232 \r
233 /*-----------------------------------------------------------*/\r
234 \r
235 void vStartInterruptQueueTasks( void )\r
236 {\r
237         /* Start the test tasks. */\r
238         xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );\r
239         xTaskCreate( prvHigherPriorityNormallyEmptyTask, "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );\r
240         xTaskCreate( prvLowerPriorityNormallyEmptyTask, "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );\r
241         xTaskCreate( prv1stHigherPriorityNormallyFullTask, "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );\r
242         xTaskCreate( prv2ndHigherPriorityNormallyFullTask, "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );\r
243         xTaskCreate( prvLowerPriorityNormallyFullTask, "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );\r
244 \r
245         /* Create the queues that are accessed by multiple tasks and multiple\r
246         interrupts. */\r
247         xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );\r
248         xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( UBaseType_t ) sizeof( UBaseType_t ) );\r
249 \r
250         /* vQueueAddToRegistry() adds the queue to the queue registry, if one is\r
251         in use.  The queue registry is provided as a means for kernel aware\r
252         debuggers to locate queues and has no purpose if a kernel aware debugger\r
253         is not being used.  The call to vQueueAddToRegistry() will be removed\r
254         by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is\r
255         defined to be less than 1. */\r
256         vQueueAddToRegistry( xNormallyFullQueue, "NormallyFull" );\r
257         vQueueAddToRegistry( xNormallyEmptyQueue, "NormallyEmpty" );\r
258 }\r
259 /*-----------------------------------------------------------*/\r
260 \r
261 static void prvRecordValue_NormallyFull( UBaseType_t uxValue, UBaseType_t uxSource )\r
262 {\r
263         if( uxValue < intqNUM_VALUES_TO_LOG )\r
264         {\r
265                 /* We don't expect to receive the same value twice, so if the value\r
266                 has already been marked as received an error has occurred. */\r
267                 if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )\r
268                 {\r
269                         prvQueueAccessLogError( __LINE__ );\r
270                 }\r
271 \r
272                 /* Log that this value has been received. */\r
273                 ucNormallyFullReceivedValues[ uxValue ] = ( uint8_t ) uxSource;\r
274         }\r
275 }\r
276 /*-----------------------------------------------------------*/\r
277 \r
278 static void prvRecordValue_NormallyEmpty( UBaseType_t uxValue, UBaseType_t uxSource )\r
279 {\r
280         if( uxValue < intqNUM_VALUES_TO_LOG )\r
281         {\r
282                 /* We don't expect to receive the same value twice, so if the value\r
283                 has already been marked as received an error has occurred. */\r
284                 if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )\r
285                 {\r
286                         prvQueueAccessLogError( __LINE__ );\r
287                 }\r
288 \r
289                 /* Log that this value has been received. */\r
290                 ucNormallyEmptyReceivedValues[ uxValue ] = ( uint8_t ) uxSource;\r
291         }\r
292 }\r
293 /*-----------------------------------------------------------*/\r
294 \r
295 static void prvQueueAccessLogError( UBaseType_t uxLine )\r
296 {\r
297         /* Latch the line number that caused the error. */\r
298         xErrorLine = uxLine;\r
299         xErrorStatus = pdFAIL;\r
300 }\r
301 /*-----------------------------------------------------------*/\r
302 \r
303 static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )\r
304 {\r
305 UBaseType_t uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;\r
306 \r
307         /* The timer should not be started until after the scheduler has started.\r
308         More than one task is running this code so we check the parameter value\r
309         to determine which task should start the timer. */\r
310         if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )\r
311         {\r
312                 vInitialiseTimerForIntQueueTest();\r
313         }\r
314 \r
315         for( ;; )\r
316         {\r
317                 /* Block waiting to receive a value from the normally empty queue.\r
318                 Interrupts will write to the queue so we should receive a value. */\r
319                 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )\r
320                 {\r
321                         prvQueueAccessLogError( __LINE__ );\r
322                 }\r
323                 else\r
324                 {\r
325                         /* Note which value was received so we can check all expected\r
326                         values are received and no values are duplicated. */\r
327                         prvRecordValue_NormallyEmpty( uxRxed, ( UBaseType_t ) pvParameters );\r
328                 }\r
329 \r
330                 /* Ensure the other task running this code gets a chance to execute. */\r
331                 taskYIELD();\r
332 \r
333                 if( ( UBaseType_t ) pvParameters == intqHIGH_PRIORITY_TASK1 )\r
334                 {\r
335                         /* Have we received all the expected values? */\r
336                         if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )\r
337                         {\r
338                                 vTaskSuspend( xHighPriorityNormallyEmptyTask2 );\r
339 \r
340                                 uxTask1 = 0;\r
341                                 uxTask2 = 0;\r
342                                 uxInterrupts = 0;\r
343 \r
344                                 /* Loop through the array, checking that both tasks have\r
345                                 placed values into the array, and that no values are missing.\r
346                                 Start at 1 as we expect position 0 to be unused. */\r
347                                 for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )\r
348                                 {\r
349                                         if( ucNormallyEmptyReceivedValues[ ux ] == 0 )\r
350                                         {\r
351                                                 /* A value is missing. */\r
352                                                 prvQueueAccessLogError( __LINE__ );\r
353                                         }\r
354                                         else\r
355                                         {\r
356                                                 if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )\r
357                                                 {\r
358                                                         /* Value was placed into the array by task 1. */\r
359                                                         uxTask1++;\r
360                                                 }\r
361                                                 else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )\r
362                                                 {\r
363                                                         /* Value was placed into the array by task 2. */\r
364                                                         uxTask2++;\r
365                                                 }\r
366                                                 else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )\r
367                                                 {\r
368                                                         uxInterrupts++;\r
369                                                 }\r
370                                         }\r
371                                 }\r
372 \r
373                                 if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )\r
374                                 {\r
375                                         /* Only task 2 seemed to log any values. */\r
376                                         uxErrorCount1++;\r
377                                         if( uxErrorCount1 > 2 )\r
378                                         {\r
379                                                 prvQueueAccessLogError( __LINE__ );\r
380                                         }\r
381                                 }\r
382                                 else\r
383                                 {\r
384                                         uxErrorCount1 = 0;\r
385                                 }\r
386 \r
387                                 if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT  )\r
388                                 {\r
389                                         /* Only task 1 seemed to log any values. */\r
390                                         uxErrorCount2++;\r
391                                         if( uxErrorCount2 > 2 )\r
392                                         {\r
393                                                 prvQueueAccessLogError( __LINE__ );\r
394                                         }\r
395                                 }\r
396                                 else\r
397                                 {\r
398                                         uxErrorCount2 = 0;\r
399                                 }\r
400 \r
401                                 if( uxInterrupts == 0 )\r
402                                 {\r
403                                         prvQueueAccessLogError( __LINE__ );\r
404                                 }\r
405 \r
406                                 /* Clear the array again, ready to start a new cycle. */\r
407                                 memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );\r
408 \r
409                                 uxHighPriorityLoops1++;\r
410                                 uxValueForNormallyEmptyQueue = 0;\r
411 \r
412                                 /* Suspend ourselves, allowing the lower priority task to\r
413                                 actually receive something from the queue.  Until now it\r
414                                 will have been prevented from doing so by the higher\r
415                                 priority tasks.  The lower priority task will resume us\r
416                                 if it receives something.  We will then resume the other\r
417                                 higher priority task. */\r
418                                 vTaskSuspend( NULL );\r
419                                 vTaskResume( xHighPriorityNormallyEmptyTask2 );\r
420                         }\r
421                 }\r
422         }\r
423 }\r
424 /*-----------------------------------------------------------*/\r
425 \r
426 static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )\r
427 {\r
428 UBaseType_t uxValue, uxRxed;\r
429 \r
430         /* The parameters are not being used so avoid compiler warnings. */\r
431         ( void ) pvParameters;\r
432 \r
433         for( ;; )\r
434         {\r
435                 if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )\r
436                 {\r
437                         /* A value should only be obtained when the high priority task is\r
438                         suspended. */\r
439                         if( eTaskGetState( xHighPriorityNormallyEmptyTask1 ) != eSuspended )\r
440                         {\r
441                                 prvQueueAccessLogError( __LINE__ );\r
442                         }\r
443 \r
444                         prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );\r
445 \r
446                         /* Wake the higher priority task again. */\r
447                         vTaskResume( xHighPriorityNormallyEmptyTask1 );\r
448                         uxLowPriorityLoops1++;\r
449                 }\r
450                 else\r
451                 {\r
452                         /* Raise our priority while we send so we can preempt the higher\r
453                         priority task, and ensure we get the Tx value into the queue. */\r
454                         vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );\r
455 \r
456                         portENTER_CRITICAL();\r
457                         {\r
458                                 uxValueForNormallyEmptyQueue++;\r
459                                 uxValue = uxValueForNormallyEmptyQueue;\r
460                         }\r
461                         portEXIT_CRITICAL();\r
462 \r
463                         if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )\r
464                         {\r
465                                 prvQueueAccessLogError( __LINE__ );\r
466                         }\r
467 \r
468                         vTaskPrioritySet( NULL, intqLOWER_PRIORITY );\r
469                 }\r
470         }\r
471 }\r
472 /*-----------------------------------------------------------*/\r
473 \r
474 static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )\r
475 {\r
476 UBaseType_t uxValueToTx, ux, uxInterrupts;\r
477 \r
478         /* The parameters are not being used so avoid compiler warnings. */\r
479         ( void ) pvParameters;\r
480 \r
481         /* Make sure the queue starts full or near full.  >> 1 as there are two\r
482         high priority tasks. */\r
483         for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )\r
484         {\r
485                 portENTER_CRITICAL();\r
486                 {\r
487                         uxValueForNormallyFullQueue++;\r
488                         uxValueToTx = uxValueForNormallyFullQueue;\r
489                 }\r
490                 portEXIT_CRITICAL();\r
491 \r
492                 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );\r
493         }\r
494 \r
495         for( ;; )\r
496         {\r
497                 portENTER_CRITICAL();\r
498                 {\r
499                         uxValueForNormallyFullQueue++;\r
500                         uxValueToTx = uxValueForNormallyFullQueue;\r
501                 }\r
502                 portEXIT_CRITICAL();\r
503 \r
504                 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )\r
505                 {\r
506                         /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not\r
507                         expect it to ever time out. */\r
508                         prvQueueAccessLogError( __LINE__ );\r
509                 }\r
510 \r
511                 /* Allow the other task running this code to run. */\r
512                 taskYIELD();\r
513 \r
514                 /* Have all the expected values been sent to the queue? */\r
515                 if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )\r
516                 {\r
517                         /* Make sure the other high priority task completes its send of\r
518                         any values below intqNUM_VALUE_TO_LOG. */\r
519                         vTaskDelay( intqSHORT_DELAY );\r
520 \r
521                         vTaskSuspend( xHighPriorityNormallyFullTask2 );\r
522 \r
523                         if( xWasSuspended == pdTRUE )\r
524                         {\r
525                                 /* We would have expected the other high priority task to have\r
526                                 set this back to false by now. */\r
527                                 prvQueueAccessLogError( __LINE__ );\r
528                         }\r
529 \r
530                         /* Set the suspended flag so an error is not logged if the other\r
531                         task recognises a time out when it is unsuspended. */\r
532                         xWasSuspended = pdTRUE;\r
533 \r
534                         /* Check interrupts are also sending. */\r
535                         uxInterrupts = 0U;\r
536 \r
537                         /* Start at 1 as we expect position 0 to be unused. */\r
538                         for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )\r
539                         {\r
540                                 if( ucNormallyFullReceivedValues[ ux ] == 0 )\r
541                                 {\r
542                                         /* A value was missing. */\r
543                                         prvQueueAccessLogError( __LINE__ );\r
544                                 }\r
545                                 else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )\r
546                                 {\r
547                                         uxInterrupts++;\r
548                                 }\r
549                         }\r
550 \r
551                         if( uxInterrupts == 0 )\r
552                         {\r
553                                 /* No writes from interrupts were found.  Are interrupts\r
554                                 actually running? */\r
555                                 prvQueueAccessLogError( __LINE__ );\r
556                         }\r
557 \r
558                         /* Reset the array ready for the next cycle. */\r
559                         memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );\r
560 \r
561                         uxHighPriorityLoops2++;\r
562                         uxValueForNormallyFullQueue = 0;\r
563 \r
564                         /* Suspend ourselves, allowing the lower priority task to\r
565                         actually receive something from the queue.  Until now it\r
566                         will have been prevented from doing so by the higher\r
567                         priority tasks.  The lower priority task will resume us\r
568                         if it receives something.  We will then resume the other\r
569                         higher priority task. */\r
570                         vTaskSuspend( NULL );\r
571                         vTaskResume( xHighPriorityNormallyFullTask2 );\r
572                 }\r
573         }\r
574 }\r
575 /*-----------------------------------------------------------*/\r
576 \r
577 static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )\r
578 {\r
579 UBaseType_t uxValueToTx, ux;\r
580 \r
581         /* The parameters are not being used so avoid compiler warnings. */\r
582         ( void ) pvParameters;\r
583 \r
584         /* Make sure the queue starts full or near full.  >> 1 as there are two\r
585         high priority tasks. */\r
586         for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )\r
587         {\r
588                 portENTER_CRITICAL();\r
589                 {\r
590                         uxValueForNormallyFullQueue++;\r
591                         uxValueToTx = uxValueForNormallyFullQueue;\r
592                 }\r
593                 portEXIT_CRITICAL();\r
594 \r
595                 xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );\r
596         }\r
597 \r
598         for( ;; )\r
599         {\r
600                 portENTER_CRITICAL();\r
601                 {\r
602                         uxValueForNormallyFullQueue++;\r
603                         uxValueToTx = uxValueForNormallyFullQueue;\r
604                 }\r
605                 portEXIT_CRITICAL();\r
606 \r
607                 if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )\r
608                 {\r
609                         if( xWasSuspended != pdTRUE )\r
610                         {\r
611                                 /* It is ok to time out if the task has been suspended. */\r
612                                 prvQueueAccessLogError( __LINE__ );\r
613                         }\r
614                 }\r
615 \r
616                 xWasSuspended = pdFALSE;\r
617 \r
618                 taskYIELD();\r
619         }\r
620 }\r
621 /*-----------------------------------------------------------*/\r
622 \r
623 static void prvLowerPriorityNormallyFullTask( void *pvParameters )\r
624 {\r
625 UBaseType_t uxValue, uxTxed = 9999;\r
626 \r
627         /* The parameters are not being used so avoid compiler warnings. */\r
628         ( void ) pvParameters;\r
629 \r
630         for( ;; )\r
631         {\r
632                 if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )\r
633                 {\r
634                         /* Should only succeed when the higher priority task is suspended */\r
635                         if( eTaskGetState( xHighPriorityNormallyFullTask1 ) != eSuspended )\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 BaseType_t xFirstTimerHandler( void )\r
665 {\r
666 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
667 UBaseType_t uxRxedValue;\r
668 static UBaseType_t uxNextOperation = 0;\r
669 \r
670         /* Called from a timer interrupt.  Perform various read and write\r
671         accesses on the queues. */\r
672 \r
673         uxNextOperation++;\r
674 \r
675         if( uxNextOperation & ( UBaseType_t ) 0x01 )\r
676         {\r
677                 timerNORMALLY_EMPTY_TX();\r
678                 timerNORMALLY_EMPTY_TX();\r
679                 timerNORMALLY_EMPTY_TX();\r
680         }\r
681         else\r
682         {\r
683                 timerNORMALLY_FULL_RX();\r
684                 timerNORMALLY_FULL_RX();\r
685                 timerNORMALLY_FULL_RX();\r
686         }\r
687 \r
688         return xHigherPriorityTaskWoken;\r
689 }\r
690 /*-----------------------------------------------------------*/\r
691 \r
692 BaseType_t xSecondTimerHandler( void )\r
693 {\r
694 UBaseType_t uxRxedValue;\r
695 BaseType_t xHigherPriorityTaskWoken = pdFALSE;\r
696 static UBaseType_t uxNextOperation = 0;\r
697 \r
698         /* Called from a timer interrupt.  Perform various read and write\r
699         accesses on the queues. */\r
700 \r
701         uxNextOperation++;\r
702 \r
703         if( uxNextOperation & ( UBaseType_t ) 0x01 )\r
704         {\r
705                 timerNORMALLY_EMPTY_TX();\r
706                 timerNORMALLY_EMPTY_TX();\r
707 \r
708                 timerNORMALLY_EMPTY_RX();\r
709                 timerNORMALLY_EMPTY_RX();\r
710         }\r
711         else\r
712         {\r
713                 timerNORMALLY_FULL_RX();\r
714                 timerNORMALLY_FULL_TX();\r
715                 timerNORMALLY_FULL_TX();\r
716                 timerNORMALLY_FULL_TX();\r
717                 timerNORMALLY_FULL_TX();\r
718         }\r
719 \r
720         return xHigherPriorityTaskWoken;\r
721 }\r
722 /*-----------------------------------------------------------*/\r
723 \r
724 \r
725 BaseType_t xAreIntQueueTasksStillRunning( void )\r
726 {\r
727 static UBaseType_t uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;\r
728 \r
729         /* xErrorStatus can be set outside of this function.  This function just\r
730         checks that all the tasks are still cycling. */\r
731 \r
732         if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )\r
733         {\r
734                 /* The high priority 1 task has stalled. */\r
735                 prvQueueAccessLogError( __LINE__ );\r
736         }\r
737 \r
738         uxLastHighPriorityLoops1 = uxHighPriorityLoops1;\r
739 \r
740         if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )\r
741         {\r
742                 /* The high priority 2 task has stalled. */\r
743                 prvQueueAccessLogError( __LINE__ );\r
744         }\r
745 \r
746         uxLastHighPriorityLoops2 = uxHighPriorityLoops2;\r
747 \r
748         if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )\r
749         {\r
750                 /* The low priority 1 task has stalled. */\r
751                 prvQueueAccessLogError( __LINE__ );\r
752         }\r
753 \r
754         uxLastLowPriorityLoops1 = uxLowPriorityLoops1;\r
755 \r
756         if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )\r
757         {\r
758                 /* The low priority 2 task has stalled. */\r
759                 prvQueueAccessLogError( __LINE__ );\r
760         }\r
761 \r
762         uxLastLowPriorityLoops2 = uxLowPriorityLoops2;\r
763 \r
764         return xErrorStatus;\r
765 }\r
766 \r