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