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