OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [trunk/] [rtos/] [freertos-6.1.1/] [Demo/] [Common/] [Minimal/] [IntQueue.c] - Blame information for rev 649

Go to most recent revision | Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.