diff options
Diffstat (limited to 'src/FreeRTOS-Sim-master/Demo/Common/Full/events.c')
-rw-r--r-- | src/FreeRTOS-Sim-master/Demo/Common/Full/events.c | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/src/FreeRTOS-Sim-master/Demo/Common/Full/events.c b/src/FreeRTOS-Sim-master/Demo/Common/Full/events.c new file mode 100644 index 0000000..807ae53 --- /dev/null +++ b/src/FreeRTOS-Sim-master/Demo/Common/Full/events.c @@ -0,0 +1,410 @@ +/*
+ FreeRTOS V8.2.2 - Copyright (C) 2015 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ ***************************************************************************
+ >>! NOTE: The modification to the GPL is included to allow you to !<<
+ >>! distribute a combined work that includes FreeRTOS without being !<<
+ >>! obliged to provide the source code for proprietary components !<<
+ >>! outside of the FreeRTOS kernel. !<<
+ ***************************************************************************
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available on the following
+ link: http://www.freertos.org/a00114.html
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that is more than just the market leader, it *
+ * is the industry's de facto standard. *
+ * *
+ * Help yourself get started quickly while simultaneously helping *
+ * to support the FreeRTOS project by purchasing a FreeRTOS *
+ * tutorial book, reference manual, or both: *
+ * http://www.FreeRTOS.org/Documentation *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org/FAQHelp.html - Having a problem? Start by reading
+ the FAQ page "My application does not run, what could be wrong?". Have you
+ defined configASSERT()?
+
+ http://www.FreeRTOS.org/support - In return for receiving this top quality
+ embedded software for free we request you assist our global community by
+ participating in the support forum.
+
+ http://www.FreeRTOS.org/training - Investing in training allows your team to
+ be as productive as possible as early as possible. Now you can receive
+ FreeRTOS training directly from Richard Barry, CEO of Real Time Engineers
+ Ltd, and the world's leading authority on the world's leading RTOS.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.FreeRTOS.org/labs - Where new FreeRTOS products go to incubate.
+ Come and try FreeRTOS+TCP, our new open source TCP/IP stack for FreeRTOS.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd. license FreeRTOS to High
+ Integrity Systems ltd. to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and commercial middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/**
+ * This file exercises the event mechanism whereby more than one task is
+ * blocked waiting for the same event.
+ *
+ * The demo creates five tasks - four 'event' tasks, and a controlling task.
+ * The event tasks have various different priorities and all block on reading
+ * the same queue. The controlling task writes data to the queue, then checks
+ * to see which of the event tasks read the data from the queue. The
+ * controlling task has the lowest priority of all the tasks so is guaranteed
+ * to always get preempted immediately upon writing to the queue.
+ *
+ * By selectively suspending and resuming the event tasks the controlling task
+ * can check that the highest priority task that is blocked on the queue is the
+ * task that reads the posted data from the queue.
+ *
+ * Two of the event tasks share the same priority. When neither of these tasks
+ * are suspended they should alternate - one reading one message from the queue,
+ * the other the next message, etc.
+ */
+
+/* Standard includes. */
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* Demo program include files. */
+#include "mevents.h"
+#include "print.h"
+
+/* Demo specific constants. */
+#define evtSTACK_SIZE ( ( unsigned portBASE_TYPE ) configMINIMAL_STACK_SIZE )
+#define evtNUM_TASKS ( 4 )
+#define evtQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 3 )
+#define evtNO_DELAY 0
+
+/* Just indexes used to uniquely identify the tasks. Note that two tasks are
+'highest' priority. */
+#define evtHIGHEST_PRIORITY_INDEX_2 3
+#define evtHIGHEST_PRIORITY_INDEX_1 2
+#define evtMEDIUM_PRIORITY_INDEX 1
+#define evtLOWEST_PRIORITY_INDEX 0
+
+/* Each event task increments one of these counters each time it reads data
+from the queue. */
+static volatile portBASE_TYPE xTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
+
+/* Each time the controlling task posts onto the queue it increments the
+expected count of the task that it expected to read the data from the queue
+(i.e. the task with the highest priority that should be blocked on the queue).
+
+xExpectedTaskCounters are incremented from the controlling task, and
+xTaskCounters are incremented from the individual event tasks - therefore
+comparing xTaskCounters to xExpectedTaskCounters shows whether or not the
+correct task was unblocked by the post. */
+static portBASE_TYPE xExpectedTaskCounters[ evtNUM_TASKS ] = { 0, 0, 0, 0 };
+
+/* Handles to the four event tasks. These are required to suspend and resume
+the tasks. */
+static TaskHandle_t xCreatedTasks[ evtNUM_TASKS ];
+
+/* The single queue onto which the controlling task posts, and the four event
+tasks block. */
+static QueueHandle_t xQueue;
+
+/* Flag used to indicate whether or not an error has occurred at any time.
+An error is either the queue being full when not expected, or an unexpected
+task reading data from the queue. */
+static portBASE_TYPE xHealthStatus = pdPASS;
+
+/*-----------------------------------------------------------*/
+
+/* Function that implements the event task. This is created four times. */
+static void prvMultiEventTask( void *pvParameters );
+
+/* Function that implements the controlling task. */
+static void prvEventControllerTask( void *pvParameters );
+
+/* This is a utility function that posts data to the queue, then compares
+xExpectedTaskCounters with xTaskCounters to ensure everything worked as
+expected.
+
+The event tasks all have higher priorities the controlling task. Therefore
+the controlling task will always get preempted between writhing to the queue
+and checking the task counters.
+
+@param xExpectedTask The index to the task that the controlling task thinks
+ should be the highest priority task waiting for data, and
+ therefore the task that will unblock.
+
+@param xIncrement The number of items that should be written to the queue.
+*/
+static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement );
+
+/* This is just incremented each cycle of the controlling tasks function so
+the main application can ensure the test is still running. */
+static portBASE_TYPE xCheckVariable = 0;
+
+/*-----------------------------------------------------------*/
+
+void vStartMultiEventTasks( void )
+{
+ /* Create the queue to be used for all the communications. */
+ xQueue = xQueueCreate( evtQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
+
+ /* Start the controlling task. This has the idle priority to ensure it is
+ always preempted by the event tasks. */
+ xTaskCreate( prvEventControllerTask, "EvntCTRL", evtSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+
+ /* Start the four event tasks. Note that two have priority 3, one
+ priority 2 and the other priority 1. */
+ xTaskCreate( prvMultiEventTask, "Event0", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 0 ] ), 1, &( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] ) );
+ xTaskCreate( prvMultiEventTask, "Event1", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 1 ] ), 2, &( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] ) );
+ xTaskCreate( prvMultiEventTask, "Event2", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 2 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] ) );
+ xTaskCreate( prvMultiEventTask, "Event3", evtSTACK_SIZE, ( void * ) &( xTaskCounters[ 3 ] ), 3, &( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] ) );
+}
+/*-----------------------------------------------------------*/
+
+static void prvMultiEventTask( void *pvParameters )
+{
+portBASE_TYPE *pxCounter;
+unsigned portBASE_TYPE uxDummy;
+const char * const pcTaskStartMsg = "Multi event task started.\r\n";
+
+ /* The variable this task will increment is passed in as a parameter. */
+ pxCounter = ( portBASE_TYPE * ) pvParameters;
+
+ vPrintDisplayMessage( &pcTaskStartMsg );
+
+ for( ;; )
+ {
+ /* Block on the queue. */
+ if( xQueueReceive( xQueue, &uxDummy, portMAX_DELAY ) )
+ {
+ /* We unblocked by reading the queue - so simply increment
+ the counter specific to this task instance. */
+ ( *pxCounter )++;
+ }
+ else
+ {
+ xHealthStatus = pdFAIL;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvEventControllerTask( void *pvParameters )
+{
+const char * const pcTaskStartMsg = "Multi event controller task started.\r\n";
+portBASE_TYPE xDummy = 0;
+
+ /* Just to stop warnings. */
+ ( void ) pvParameters;
+
+ vPrintDisplayMessage( &pcTaskStartMsg );
+
+ for( ;; )
+ {
+ /* All tasks are blocked on the queue. When a message is posted one of
+ the two tasks that share the highest priority should unblock to read
+ the queue. The next message written should unblock the other task with
+ the same high priority, and so on in order. No other task should
+ unblock to read data as they have lower priorities. */
+
+ prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
+ prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
+ prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
+ prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_2, 1 );
+ prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
+
+ /* For the rest of these tests we don't need the second 'highest'
+ priority task - so it is suspended. */
+ vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
+
+
+
+ /* Now suspend the other highest priority task. The medium priority
+ task will then be the task with the highest priority that remains
+ blocked on the queue. */
+ vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
+
+ /* This time, when we post onto the queue we will expect the medium
+ priority task to unblock and preempt us. */
+ prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
+
+ /* Now try resuming the highest priority task while the scheduler is
+ suspended. The task should start executing as soon as the scheduler
+ is resumed - therefore when we post to the queue again, the highest
+ priority task should again preempt us. */
+ vTaskSuspendAll();
+ vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
+ xTaskResumeAll();
+ prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
+
+ /* Now we are going to suspend the high and medium priority tasks. The
+ low priority task should then preempt us. Again the task suspension is
+ done with the whole scheduler suspended just for test purposes. */
+ vTaskSuspendAll();
+ vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
+ vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
+ xTaskResumeAll();
+ prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
+
+ /* Do the same basic test another few times - selectively suspending
+ and resuming tasks and each time calling prvCheckTaskCounters() passing
+ to the function the number of the task we expected to be unblocked by
+ the post. */
+
+ vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
+ prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
+
+ vTaskSuspendAll(); /* Just for test. */
+ vTaskSuspendAll(); /* Just for test. */
+ vTaskSuspendAll(); /* Just for even more test. */
+ vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
+ xTaskResumeAll();
+ xTaskResumeAll();
+ xTaskResumeAll();
+ prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, 1 );
+
+ vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
+ prvCheckTaskCounters( evtMEDIUM_PRIORITY_INDEX, 1 );
+
+ vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
+ prvCheckTaskCounters( evtHIGHEST_PRIORITY_INDEX_1, 1 );
+
+ /* Now a slight change, first suspend all tasks. */
+ vTaskSuspend( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
+ vTaskSuspend( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
+ vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
+
+ /* Now when we resume the low priority task and write to the queue 3
+ times. We expect the low priority task to service the queue three
+ times. */
+ vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
+ prvCheckTaskCounters( evtLOWEST_PRIORITY_INDEX, evtQUEUE_LENGTH );
+
+ /* Again suspend all tasks (only the low priority task is not suspended
+ already). */
+ vTaskSuspend( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
+
+ /* This time we are going to suspend the scheduler, resume the low
+ priority task, then resume the high priority task. In this state we
+ will write to the queue three times. When the scheduler is resumed
+ we expect the high priority task to service all three messages. */
+ vTaskSuspendAll();
+ {
+ vTaskResume( xCreatedTasks[ evtLOWEST_PRIORITY_INDEX ] );
+ vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_1 ] );
+
+ for( xDummy = 0; xDummy < evtQUEUE_LENGTH; xDummy++ )
+ {
+ if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
+ {
+ xHealthStatus = pdFAIL;
+ }
+ }
+
+ /* The queue should not have been serviced yet!. The scheduler
+ is still suspended. */
+ if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
+ {
+ xHealthStatus = pdFAIL;
+ }
+ }
+ xTaskResumeAll();
+
+ /* We should have been preempted by resuming the scheduler - so by the
+ time we are running again we expect the high priority task to have
+ removed three items from the queue. */
+ xExpectedTaskCounters[ evtHIGHEST_PRIORITY_INDEX_1 ] += evtQUEUE_LENGTH;
+ if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
+ {
+ xHealthStatus = pdFAIL;
+ }
+
+ /* The medium priority and second high priority tasks are still
+ suspended. Make sure to resume them before starting again. */
+ vTaskResume( xCreatedTasks[ evtMEDIUM_PRIORITY_INDEX ] );
+ vTaskResume( xCreatedTasks[ evtHIGHEST_PRIORITY_INDEX_2 ] );
+
+ /* Just keep incrementing to show the task is still executing. */
+ xCheckVariable++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvCheckTaskCounters( portBASE_TYPE xExpectedTask, portBASE_TYPE xIncrement )
+{
+portBASE_TYPE xDummy = 0;
+
+ /* Write to the queue the requested number of times. The data written is
+ not important. */
+ for( xDummy = 0; xDummy < xIncrement; xDummy++ )
+ {
+ if( xQueueSend( xQueue, &xDummy, evtNO_DELAY ) != pdTRUE )
+ {
+ /* Did not expect to ever find the queue full. */
+ xHealthStatus = pdFAIL;
+ }
+ }
+
+ /* All the tasks blocked on the queue have a priority higher than the
+ controlling task. Writing to the queue will therefore have caused this
+ task to be preempted. By the time this line executes the event task will
+ have executed and incremented its counter. Increment the expected counter
+ to the same value. */
+ ( xExpectedTaskCounters[ xExpectedTask ] ) += xIncrement;
+
+ /* Check the actual counts and expected counts really are the same. */
+ if( memcmp( ( void * ) xExpectedTaskCounters, ( void * ) xTaskCounters, sizeof( xExpectedTaskCounters ) ) )
+ {
+ /* The counters were not the same. This means a task we did not expect
+ to unblock actually did unblock. */
+ xHealthStatus = pdFAIL;
+ }
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xAreMultiEventTasksStillRunning( void )
+{
+static portBASE_TYPE xPreviousCheckVariable = 0;
+
+ /* Called externally to periodically check that this test is still
+ operational. */
+
+ if( xPreviousCheckVariable == xCheckVariable )
+ {
+ xHealthStatus = pdFAIL;
+ }
+
+ xPreviousCheckVariable = xCheckVariable;
+
+ return xHealthStatus;
+}
+
+
|