root/webserver/example/freeRTOSexample/EnergyMeters/Common/Minimal/IntQueue.c

Revision 14, 25.3 kB (checked in by phil, 15 years ago)

added unmodified FreeRTOS package V5.4.1 with only web srv demo source for LPC2368 for CrossWorks?

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