Use CI-CD-Github-Actions for spelling and formatting, add in the bot formatting action, update the CI-CD workflow files. Fix incorrect spelling and formatting on files. (#1083)

* Use new version of CI-CD Actions,  checkout@v3 instead of checkout@v2 on all jobs
* Use cSpell spell check, and use ubuntu-20.04 for formatting check
* Add in bot formatting action
* Update freertos_demo.yml and freertos_plus_demo.yml files to increase github log readability
* Add in a Qemu demo onto the workflows.
This commit is contained in:
Soren Ptak 2023-09-06 15:35:37 -04:00 committed by GitHub
parent 537007d96c
commit 3a2f6646f0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
1036 changed files with 134568 additions and 127281 deletions

View file

@ -1,307 +1,307 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Creates six tasks that operate on three queues as follows:
*
* The first two tasks send and receive an incrementing number to/from a queue.
* One task acts as a producer and the other as the consumer. The consumer is a
* higher priority than the producer and is set to block on queue reads. The queue
* only has space for one item - as soon as the producer posts a message on the
* queue the consumer will unblock, pre-empt the producer, and remove the item.
*
* The second two tasks work the other way around. Again the queue used only has
* enough space for one item. This time the consumer has a lower priority than the
* producer. The producer will try to post on the queue blocking when the queue is
* full. When the consumer wakes it will remove the item from the queue, causing
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
* queue.
*
* The last two tasks use the same queue producer and consumer functions. This time the queue has
* enough space for lots of items and the tasks operate at the same priority. The
* producer will execute, placing items into the queue. The consumer will start
* executing when either the queue becomes full (causing the producer to block) or
* a context switch occurs (tasks of the same priority will time slice).
*
* \page BlockQC blockQ.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V1.00:
*
+ Reversed the priority and block times of the second two demo tasks so
+ they operate as per the description above.
+
+ Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
+
+ Changes from V4.0.2
+
+ The second set of tasks were created the wrong way around. This has been
+ corrected.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* Demo program include files. */
#include "BlockQ.h"
#include "print.h"
#define blckqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
#define blckqNUM_TASK_SETS ( 3 )
/* Structure used to pass parameters to the blocking queue tasks. */
typedef struct BLOCKING_QUEUE_PARAMETERS
{
QueueHandle_t xQueue; /*< The queue to be used by the task. */
TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */
volatile short * psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
} xBlockingQueueParameters;
/* Task function that creates an incrementing number and posts it on a queue. */
static void vBlockingQueueProducer( void * pvParameters );
/* Task function that removes the incrementing number from a queue and checks that
* it is the expected number. */
static void vBlockingQueueConsumer( void * pvParameters );
/* Variables which are incremented each time an item is removed from a queue, and
* found to be the expected value.
* These are used to check that the tasks are still running. */
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
/* Variable which are incremented each time an item is posted on a queue. These
* are used to check that the tasks are still running. */
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
/*-----------------------------------------------------------*/
void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
{
xBlockingQueueParameters * pxQueueParameters1, * pxQueueParameters2;
xBlockingQueueParameters * pxQueueParameters3, * pxQueueParameters4;
xBlockingQueueParameters * pxQueueParameters5, * pxQueueParameters6;
const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
const TickType_t xBlockTime = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
const TickType_t xDontBlock = ( TickType_t ) 0;
/* Create the first two tasks as described at the top of the file. */
/* First create the structure used to pass parameters to the consumer tasks. */
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Create the queue used by the first two tasks to pass the incrementing number.
* Pass a pointer to the queue in the parameter structure. */
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
/* The consumer is created first so gets a block time as described above. */
pxQueueParameters1->xBlockTime = xBlockTime;
/* Pass in the variable that this task is going to increment so we can check it
* is still running. */
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
/* Create the structure used to pass parameters to the producer task. */
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Pass the queue to this task also, using the parameter structure. */
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
/* The producer is not going to block - as soon as it posts the consumer will
* wake and remove the item so the producer should always have room to post. */
pxQueueParameters2->xBlockTime = xDontBlock;
/* Pass in the variable that this task is going to increment so we can check
* it is still running. */
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
/* Note the producer has a lower priority than the consumer when the tasks are
* spawned. */
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
/* Create the second two tasks as described at the top of the file. This uses
* the same mechanism but reverses the task priorities. */
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters3->xBlockTime = xDontBlock;
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
pxQueueParameters4->xBlockTime = xBlockTime;
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueConsumer, "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
/* Create the last two tasks as described above. The mechanism is again just
* the same. This time both parameter structures are given a block time. */
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters5->xBlockTime = xBlockTime;
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
pxQueueParameters6->xBlockTime = xBlockTime;
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
}
/*-----------------------------------------------------------*/
static void vBlockingQueueProducer( void * pvParameters )
{
unsigned short usValue = 0;
xBlockingQueueParameters * pxQueueParameters;
const char * const pcTaskStartMsg = "Blocking queue producer started.\r\n";
const char * const pcTaskErrorMsg = "Could not post on blocking queue\r\n";
short sErrorEverOccurred = pdFALSE;
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
for( ; ; )
{
if( xQueueSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
{
vPrintDisplayMessage( &pcTaskErrorMsg );
sErrorEverOccurred = pdTRUE;
}
else
{
/* We have successfully posted a message, so increment the variable
* used to check we are still running. */
if( sErrorEverOccurred == pdFALSE )
{
( *pxQueueParameters->psCheckVariable )++;
}
/* Increment the variable we are going to post next time round. The
* consumer will expect the numbers to follow in numerical order. */
++usValue;
}
}
}
/*-----------------------------------------------------------*/
static void vBlockingQueueConsumer( void * pvParameters )
{
unsigned short usData, usExpectedValue = 0;
xBlockingQueueParameters * pxQueueParameters;
const char * const pcTaskStartMsg = "Blocking queue consumer started.\r\n";
const char * const pcTaskErrorMsg = "Incorrect value received on blocking queue.\r\n";
short sErrorEverOccurred = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
for( ; ; )
{
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
{
if( usData != usExpectedValue )
{
vPrintDisplayMessage( &pcTaskErrorMsg );
/* Catch-up. */
usExpectedValue = usData;
sErrorEverOccurred = pdTRUE;
}
else
{
/* We have successfully received a message, so increment the
* variable used to check we are still running. */
if( sErrorEverOccurred == pdFALSE )
{
( *pxQueueParameters->psCheckVariable )++;
}
/* Increment the value we expect to remove from the queue next time
* round. */
++usExpectedValue;
}
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreBlockingQueuesStillRunning( void )
{
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
portBASE_TYPE xReturn = pdPASS, xTasks;
/* Not too worried about mutual exclusion on these variables as they are 16
* bits and we are only reading them. We also only care to see if they have
* changed or not.
*
* Loop through each check variable and return pdFALSE if any are found not
* to have changed since the last call. */
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
{
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
{
xReturn = pdFALSE;
}
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
{
xReturn = pdFALSE;
}
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
}
return xReturn;
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Creates six tasks that operate on three queues as follows:
*
* The first two tasks send and receive an incrementing number to/from a queue.
* One task acts as a producer and the other as the consumer. The consumer is a
* higher priority than the producer and is set to block on queue reads. The queue
* only has space for one item - as soon as the producer posts a message on the
* queue the consumer will unblock, pre-empt the producer, and remove the item.
*
* The second two tasks work the other way around. Again the queue used only has
* enough space for one item. This time the consumer has a lower priority than the
* producer. The producer will try to post on the queue blocking when the queue is
* full. When the consumer wakes it will remove the item from the queue, causing
* the producer to unblock, pre-empt the consumer, and immediately re-fill the
* queue.
*
* The last two tasks use the same queue producer and consumer functions. This time the queue has
* enough space for lots of items and the tasks operate at the same priority. The
* producer will execute, placing items into the queue. The consumer will start
* executing when either the queue becomes full (causing the producer to block) or
* a context switch occurs (tasks of the same priority will time slice).
*
* \page BlockQC blockQ.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V1.00:
*
+ Reversed the priority and block times of the second two demo tasks so
+ they operate as per the description above.
+
+ Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
+
+ Changes from V4.0.2
+
+ The second set of tasks were created the wrong way around. This has been
+ corrected.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
/* Demo program include files. */
#include "BlockQ.h"
#include "print.h"
#define blckqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
#define blckqNUM_TASK_SETS ( 3 )
/* Structure used to pass parameters to the blocking queue tasks. */
typedef struct BLOCKING_QUEUE_PARAMETERS
{
QueueHandle_t xQueue; /*< The queue to be used by the task. */
TickType_t xBlockTime; /*< The block time to use on queue reads/writes. */
volatile short * psCheckVariable; /*< Incremented on each successful cycle to check the task is still running. */
} xBlockingQueueParameters;
/* Task function that creates an incrementing number and posts it on a queue. */
static void vBlockingQueueProducer( void * pvParameters );
/* Task function that removes the incrementing number from a queue and checks that
* it is the expected number. */
static void vBlockingQueueConsumer( void * pvParameters );
/* Variables which are incremented each time an item is removed from a queue, and
* found to be the expected value.
* These are used to check that the tasks are still running. */
static volatile short sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
/* Variable which are incremented each time an item is posted on a queue. These
* are used to check that the tasks are still running. */
static volatile short sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
/*-----------------------------------------------------------*/
void vStartBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
{
xBlockingQueueParameters * pxQueueParameters1, * pxQueueParameters2;
xBlockingQueueParameters * pxQueueParameters3, * pxQueueParameters4;
xBlockingQueueParameters * pxQueueParameters5, * pxQueueParameters6;
const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
const TickType_t xBlockTime = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
const TickType_t xDontBlock = ( TickType_t ) 0;
/* Create the first two tasks as described at the top of the file. */
/* First create the structure used to pass parameters to the consumer tasks. */
pxQueueParameters1 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Create the queue used by the first two tasks to pass the incrementing number.
* Pass a pointer to the queue in the parameter structure. */
pxQueueParameters1->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
/* The consumer is created first so gets a block time as described above. */
pxQueueParameters1->xBlockTime = xBlockTime;
/* Pass in the variable that this task is going to increment so we can check it
* is still running. */
pxQueueParameters1->psCheckVariable = &( sBlockingConsumerCount[ 0 ] );
/* Create the structure used to pass parameters to the producer task. */
pxQueueParameters2 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
/* Pass the queue to this task also, using the parameter structure. */
pxQueueParameters2->xQueue = pxQueueParameters1->xQueue;
/* The producer is not going to block - as soon as it posts the consumer will
* wake and remove the item so the producer should always have room to post. */
pxQueueParameters2->xBlockTime = xDontBlock;
/* Pass in the variable that this task is going to increment so we can check
* it is still running. */
pxQueueParameters2->psCheckVariable = &( sBlockingProducerCount[ 0 ] );
/* Note the producer has a lower priority than the consumer when the tasks are
* spawned. */
xTaskCreate( vBlockingQueueConsumer, "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
xTaskCreate( vBlockingQueueProducer, "QProdB2", blckqSTACK_SIZE, ( void * ) pxQueueParameters2, tskIDLE_PRIORITY, NULL );
/* Create the second two tasks as described at the top of the file. This uses
* the same mechanism but reverses the task priorities. */
pxQueueParameters3 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters3->xQueue = xQueueCreate( uxQueueSize1, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters3->xBlockTime = xDontBlock;
pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
pxQueueParameters4->xBlockTime = xBlockTime;
pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueConsumer, "QConsB4", blckqSTACK_SIZE, ( void * ) pxQueueParameters4, uxPriority, NULL );
/* Create the last two tasks as described above. The mechanism is again just
* the same. This time both parameter structures are given a block time. */
pxQueueParameters5 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters5->xQueue = xQueueCreate( uxQueueSize5, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
pxQueueParameters5->xBlockTime = xBlockTime;
pxQueueParameters5->psCheckVariable = &( sBlockingProducerCount[ 2 ] );
pxQueueParameters6 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
pxQueueParameters6->xQueue = pxQueueParameters5->xQueue;
pxQueueParameters6->xBlockTime = xBlockTime;
pxQueueParameters6->psCheckVariable = &( sBlockingConsumerCount[ 2 ] );
xTaskCreate( vBlockingQueueProducer, "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
xTaskCreate( vBlockingQueueConsumer, "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
}
/*-----------------------------------------------------------*/
static void vBlockingQueueProducer( void * pvParameters )
{
unsigned short usValue = 0;
xBlockingQueueParameters * pxQueueParameters;
const char * const pcTaskStartMsg = "Blocking queue producer started.\r\n";
const char * const pcTaskErrorMsg = "Could not post on blocking queue\r\n";
short sErrorEverOccurred = pdFALSE;
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
for( ; ; )
{
if( xQueueSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
{
vPrintDisplayMessage( &pcTaskErrorMsg );
sErrorEverOccurred = pdTRUE;
}
else
{
/* We have successfully posted a message, so increment the variable
* used to check we are still running. */
if( sErrorEverOccurred == pdFALSE )
{
( *pxQueueParameters->psCheckVariable )++;
}
/* Increment the variable we are going to post next time round. The
* consumer will expect the numbers to follow in numerical order. */
++usValue;
}
}
}
/*-----------------------------------------------------------*/
static void vBlockingQueueConsumer( void * pvParameters )
{
unsigned short usData, usExpectedValue = 0;
xBlockingQueueParameters * pxQueueParameters;
const char * const pcTaskStartMsg = "Blocking queue consumer started.\r\n";
const char * const pcTaskErrorMsg = "Incorrect value received on blocking queue.\r\n";
short sErrorEverOccurred = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
for( ; ; )
{
if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
{
if( usData != usExpectedValue )
{
vPrintDisplayMessage( &pcTaskErrorMsg );
/* Catch-up. */
usExpectedValue = usData;
sErrorEverOccurred = pdTRUE;
}
else
{
/* We have successfully received a message, so increment the
* variable used to check we are still running. */
if( sErrorEverOccurred == pdFALSE )
{
( *pxQueueParameters->psCheckVariable )++;
}
/* Increment the value we expect to remove from the queue next time
* round. */
++usExpectedValue;
}
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreBlockingQueuesStillRunning( void )
{
static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( short ) 0, ( short ) 0, ( short ) 0 };
portBASE_TYPE xReturn = pdPASS, xTasks;
/* Not too worried about mutual exclusion on these variables as they are 16
* bits and we are only reading them. We also only care to see if they have
* changed or not.
*
* Loop through each check variable and return pdFALSE if any are found not
* to have changed since the last call. */
for( xTasks = 0; xTasks < blckqNUM_TASK_SETS; xTasks++ )
{
if( sBlockingConsumerCount[ xTasks ] == sLastBlockingConsumerCount[ xTasks ] )
{
xReturn = pdFALSE;
}
sLastBlockingConsumerCount[ xTasks ] = sBlockingConsumerCount[ xTasks ];
if( sBlockingProducerCount[ xTasks ] == sLastBlockingProducerCount[ xTasks ] )
{
xReturn = pdFALSE;
}
sLastBlockingProducerCount[ xTasks ] = sBlockingProducerCount[ xTasks ];
}
return xReturn;
}

View file

@ -1,221 +1,221 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* This is a very simple queue test. See the BlockQ. c documentation for a more
* comprehensive version.
*
* Creates two tasks that communicate over a single queue. One task acts as a
* producer, the other a consumer.
*
* The producer loops for three iteration, posting an incrementing number onto the
* queue each cycle. It then delays for a fixed period before doing exactly the
* same again.
*
* The consumer loops emptying the queue. Each item removed from the queue is
* checked to ensure it contains the expected value. When the queue is empty it
* blocks for a fixed period, then does the same again.
*
* All queue access is performed without blocking. The consumer completely empties
* the queue each time it runs so the producer should never find the queue full.
*
* An error is flagged if the consumer obtains an unexpected value or the producer
* find the queue is full.
*
* \page PollQC pollQ.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "print.h"
/* Demo program include files. */
#include "PollQ.h"
#define pollqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
/* The task that posts the incrementing number onto the queue. */
static void vPolledQueueProducer( void * pvParameters );
/* The task that empties the queue. */
static void vPolledQueueConsumer( void * pvParameters );
/* Variables that are used to check that the tasks are still running with no errors. */
static volatile short sPollingConsumerCount = 0, sPollingProducerCount = 0;
/*-----------------------------------------------------------*/
void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
{
static QueueHandle_t xPolledQueue;
const unsigned portBASE_TYPE uxQueueSize = 10;
/* Create the queue used by the producer and consumer. */
xPolledQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
/* Spawn the producer and consumer. */
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
}
/*-----------------------------------------------------------*/
static void vPolledQueueProducer( void * pvParameters )
{
unsigned short usValue = 0, usLoop;
QueueHandle_t * pxQueue;
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
const unsigned short usNumToProduce = 3;
const char * const pcTaskStartMsg = "Polled queue producer started.\r\n";
const char * const pcTaskErrorMsg = "Could not post on polled queue.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The queue being used is passed in as the parameter. */
pxQueue = ( QueueHandle_t * ) pvParameters;
for( ; ; )
{
for( usLoop = 0; usLoop < usNumToProduce; ++usLoop )
{
/* Send an incrementing number on the queue without blocking. */
if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( TickType_t ) 0 ) != pdPASS )
{
/* We should never find the queue full - this is an error. */
vPrintDisplayMessage( &pcTaskErrorMsg );
sError = pdTRUE;
}
else
{
if( sError == pdFALSE )
{
/* If an error has ever been recorded we stop incrementing the
* check variable. */
++sPollingProducerCount;
}
/* Update the value we are going to post next time around. */
++usValue;
}
}
/* Wait before we start posting again to ensure the consumer runs and
* empties the queue. */
vTaskDelay( xDelay );
}
}
/*-----------------------------------------------------------*/
static void vPolledQueueConsumer( void * pvParameters )
{
unsigned short usData, usExpectedValue = 0;
QueueHandle_t * pxQueue;
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
const char * const pcTaskStartMsg = "Polled queue consumer started.\r\n";
const char * const pcTaskErrorMsg = "Incorrect value received on polled queue.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The queue being used is passed in as the parameter. */
pxQueue = ( QueueHandle_t * ) pvParameters;
for( ; ; )
{
/* Loop until the queue is empty. */
while( uxQueueMessagesWaiting( *pxQueue ) )
{
if( xQueueReceive( *pxQueue, &usData, ( TickType_t ) 0 ) == pdPASS )
{
if( usData != usExpectedValue )
{
/* This is not what we expected to receive so an error has
* occurred. */
vPrintDisplayMessage( &pcTaskErrorMsg );
sError = pdTRUE;
/* Catch-up to the value we received so our next expected value
* should again be correct. */
usExpectedValue = usData;
}
else
{
if( sError == pdFALSE )
{
/* Only increment the check variable if no errors have
* occurred. */
++sPollingConsumerCount;
}
}
++usExpectedValue;
}
}
/* Now the queue is empty we block, allowing the producer to place more
* items in the queue. */
vTaskDelay( xDelay );
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running with no errors. */
portBASE_TYPE xArePollingQueuesStillRunning( void )
{
static short sLastPollingConsumerCount = 0, sLastPollingProducerCount = 0;
portBASE_TYPE xReturn;
if( ( sLastPollingConsumerCount == sPollingConsumerCount ) ||
( sLastPollingProducerCount == sPollingProducerCount )
)
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
sLastPollingConsumerCount = sPollingConsumerCount;
sLastPollingProducerCount = sPollingProducerCount;
return xReturn;
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* This is a very simple queue test. See the BlockQ. c documentation for a more
* comprehensive version.
*
* Creates two tasks that communicate over a single queue. One task acts as a
* producer, the other a consumer.
*
* The producer loops for three iteration, posting an incrementing number onto the
* queue each cycle. It then delays for a fixed period before doing exactly the
* same again.
*
* The consumer loops emptying the queue. Each item removed from the queue is
* checked to ensure it contains the expected value. When the queue is empty it
* blocks for a fixed period, then does the same again.
*
* All queue access is performed without blocking. The consumer completely empties
* the queue each time it runs so the producer should never find the queue full.
*
* An error is flagged if the consumer obtains an unexpected value or the producer
* find the queue is full.
*
* \page PollQC pollQ.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "print.h"
/* Demo program include files. */
#include "PollQ.h"
#define pollqSTACK_SIZE ( ( unsigned short ) configMINIMAL_STACK_SIZE )
/* The task that posts the incrementing number onto the queue. */
static void vPolledQueueProducer( void * pvParameters );
/* The task that empties the queue. */
static void vPolledQueueConsumer( void * pvParameters );
/* Variables that are used to check that the tasks are still running with no errors. */
static volatile short sPollingConsumerCount = 0, sPollingProducerCount = 0;
/*-----------------------------------------------------------*/
void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
{
static QueueHandle_t xPolledQueue;
const unsigned portBASE_TYPE uxQueueSize = 10;
/* Create the queue used by the producer and consumer. */
xPolledQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
/* Spawn the producer and consumer. */
xTaskCreate( vPolledQueueConsumer, "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
xTaskCreate( vPolledQueueProducer, "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, NULL );
}
/*-----------------------------------------------------------*/
static void vPolledQueueProducer( void * pvParameters )
{
unsigned short usValue = 0, usLoop;
QueueHandle_t * pxQueue;
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
const unsigned short usNumToProduce = 3;
const char * const pcTaskStartMsg = "Polled queue producer started.\r\n";
const char * const pcTaskErrorMsg = "Could not post on polled queue.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The queue being used is passed in as the parameter. */
pxQueue = ( QueueHandle_t * ) pvParameters;
for( ; ; )
{
for( usLoop = 0; usLoop < usNumToProduce; ++usLoop )
{
/* Send an incrementing number on the queue without blocking. */
if( xQueueSendToBack( *pxQueue, ( void * ) &usValue, ( TickType_t ) 0 ) != pdPASS )
{
/* We should never find the queue full - this is an error. */
vPrintDisplayMessage( &pcTaskErrorMsg );
sError = pdTRUE;
}
else
{
if( sError == pdFALSE )
{
/* If an error has ever been recorded we stop incrementing the
* check variable. */
++sPollingProducerCount;
}
/* Update the value we are going to post next time around. */
++usValue;
}
}
/* Wait before we start posting again to ensure the consumer runs and
* empties the queue. */
vTaskDelay( xDelay );
}
}
/*-----------------------------------------------------------*/
static void vPolledQueueConsumer( void * pvParameters )
{
unsigned short usData, usExpectedValue = 0;
QueueHandle_t * pxQueue;
const TickType_t xDelay = ( TickType_t ) 200 / portTICK_PERIOD_MS;
const char * const pcTaskStartMsg = "Polled queue consumer started.\r\n";
const char * const pcTaskErrorMsg = "Incorrect value received on polled queue.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The queue being used is passed in as the parameter. */
pxQueue = ( QueueHandle_t * ) pvParameters;
for( ; ; )
{
/* Loop until the queue is empty. */
while( uxQueueMessagesWaiting( *pxQueue ) )
{
if( xQueueReceive( *pxQueue, &usData, ( TickType_t ) 0 ) == pdPASS )
{
if( usData != usExpectedValue )
{
/* This is not what we expected to receive so an error has
* occurred. */
vPrintDisplayMessage( &pcTaskErrorMsg );
sError = pdTRUE;
/* Catch-up to the value we received so our next expected value
* should again be correct. */
usExpectedValue = usData;
}
else
{
if( sError == pdFALSE )
{
/* Only increment the check variable if no errors have
* occurred. */
++sPollingConsumerCount;
}
}
++usExpectedValue;
}
}
/* Now the queue is empty we block, allowing the producer to place more
* items in the queue. */
vTaskDelay( xDelay );
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running with no errors. */
portBASE_TYPE xArePollingQueuesStillRunning( void )
{
static short sLastPollingConsumerCount = 0, sLastPollingProducerCount = 0;
portBASE_TYPE xReturn;
if( ( sLastPollingConsumerCount == sPollingConsumerCount ) ||
( sLastPollingProducerCount == sPollingProducerCount )
)
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
sLastPollingConsumerCount = sPollingConsumerCount;
sLastPollingProducerCount = sPollingProducerCount;
return xReturn;
}

View file

@ -1,350 +1,350 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Creates two tasks that operate on an interrupt driven serial port. A loopback
* connector should be used so that everything that is transmitted is also received.
* The serial port does not use any flow control. On a standard 9way 'D' connector
* pins two and three should be connected together.
*
* The first task repeatedly sends a string to a queue, character at a time. The
* serial port interrupt will empty the queue and transmit the characters. The
* task blocks for a pseudo random period before resending the string.
*
* The second task blocks on a queue waiting for a character to be received.
* Characters received by the serial port interrupt routine are posted onto the
* queue - unblocking the task making it ready to execute. If this is then the
* highest priority task ready to run it will run immediately - with a context
* switch occurring at the end of the interrupt service routine. The task
* receiving characters is spawned with a higher priority than the task
* transmitting the characters.
*
* With the loop back connector in place, one task will transmit a string and the
* other will immediately receive it. The receiving task knows the string it
* expects to receive so can detect an error.
*
* This also creates a third task. This is used to test semaphore usage from an
* ISR and does nothing interesting.
*
* \page ComTestC comtest.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V1.00:
*
+ The priority of the Rx task has been lowered. Received characters are
+ now processed (read from the queue) at the idle priority, allowing low
+ priority tasks to run evenly at times of a high communications overhead.
+
+ Changes from V1.01:
+
+ The Tx task now waits a pseudo random time between transmissions.
+ Previously a fixed period was used but this was not such a good test as
+ interrupts fired at regular intervals.
+
+ Changes From V1.2.0:
+
+ Use vSerialPutString() instead of single character puts.
+ Only stop the check variable incrementing after two consecutive errors.
+
+ Changed from V1.2.5
+
+ Made the Rx task 2 priorities higher than the Tx task. Previously it was
+ only 1. This is done to tie in better with the other demo application
+ tasks.
+
+ Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
+ Slight modification to task priorities.
+
*/
/* Scheduler include files. */
#include <stdlib.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
/* Demo program include files. */
#include "serial.h"
#include "comtest.h"
#include "print.h"
/* The Tx task will transmit the sequence of characters at a pseudo random
* interval. This is the maximum and minimum block time between sends. */
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x15e )
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0xc8 )
#define comMAX_CONSECUTIVE_ERRORS ( 2 )
#define comSTACK_SIZE ( ( unsigned short ) 256 )
#define comRX_RELATIVE_PRIORITY ( 1 )
/* Handle to the com port used by both tasks. */
static xComPortHandle xPort;
/* The transmit function as described at the top of the file. */
static void vComTxTask( void * pvParameters );
/* The receive function as described at the top of the file. */
static void vComRxTask( void * pvParameters );
/* The semaphore test function as described at the top of the file. */
static void vSemTestTask( void * pvParameters );
/* The string that is repeatedly transmitted. */
const char * const pcMessageToExchange = "Send this message over and over again to check communications interrupts. "
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
/* Variables that are incremented on each cycle of each task. These are used to
* check that both tasks are still executing. */
volatile short sTxCount = 0, sRxCount = 0, sSemCount = 0;
/* The handle to the semaphore test task. */
static TaskHandle_t xSemTestTaskHandle = NULL;
/*-----------------------------------------------------------*/
void vStartComTestTasks( unsigned portBASE_TYPE uxPriority,
eCOMPort ePort,
eBaud eBaudRate )
{
const unsigned portBASE_TYPE uxBufferLength = 255;
/* Initialise the com port then spawn both tasks. */
xPort = xSerialPortInit( ePort, eBaudRate, serNO_PARITY, serBITS_8, serSTOP_1, uxBufferLength );
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority, NULL );
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority + comRX_RELATIVE_PRIORITY, NULL );
xTaskCreate( vSemTestTask, "ISRSem", comSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xSemTestTaskHandle );
}
/*-----------------------------------------------------------*/
static void vComTxTask( void * pvParameters )
{
const char * const pcTaskStartMsg = "COM Tx task started.\r\n";
TickType_t xTimeToWait;
/* Stop warnings. */
( void ) pvParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
for( ; ; )
{
/* Send the string to the serial port. */
vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) );
/* We have posted all the characters in the string - increment the variable
* used to check that this task is still running, then wait before re-sending
* the string. */
sTxCount++;
xTimeToWait = xTaskGetTickCount();
/* Make sure we don't wait too long... */
xTimeToWait %= comTX_MAX_BLOCK_TIME;
/* ...but we do want to wait. */
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
{
xTimeToWait = comTX_MIN_BLOCK_TIME;
}
vTaskDelay( xTimeToWait );
}
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/
static void vComRxTask( void * pvParameters )
{
const char * const pcTaskStartMsg = "COM Rx task started.\r\n";
const char * const pcTaskErrorMsg = "COM read error\r\n";
const char * const pcTaskRestartMsg = "COM resynced\r\n";
const char * const pcTaskTimeoutMsg = "COM Rx timed out\r\n";
const TickType_t xBlockTime = ( TickType_t ) 0xffff / portTICK_PERIOD_MS;
const char * pcExpectedChar;
portBASE_TYPE xGotChar;
char cRxedChar;
short sResyncRequired, sConsecutiveErrors, sLatchedError;
/* Stop warnings. */
( void ) pvParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The first expected character is the first character in the string. */
pcExpectedChar = pcMessageToExchange;
sResyncRequired = pdFALSE;
sConsecutiveErrors = 0;
sLatchedError = pdFALSE;
for( ; ; )
{
/* Receive a message from the com port interrupt routine. If a message is
* not yet available the call will block the task. */
xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime );
if( xGotChar == pdTRUE )
{
if( sResyncRequired == pdTRUE )
{
/* We got out of sequence and are waiting for the start of the next
* transmission of the string. */
if( cRxedChar == '\n' )
{
/* This is the end of the message so we can start again - with
* the first character in the string being the next thing we expect
* to receive. */
pcExpectedChar = pcMessageToExchange;
sResyncRequired = pdFALSE;
/* Queue a message for printing to say that we are going to try
* again. */
vPrintDisplayMessage( &pcTaskRestartMsg );
/* Stop incrementing the check variable, if consecutive errors occur. */
sConsecutiveErrors++;
if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS )
{
sLatchedError = pdTRUE;
}
}
}
else
{
/* We have received a character, but is it the expected character? */
if( cRxedChar != *pcExpectedChar )
{
/* This was not the expected character so post a message for
* printing to say that an error has occurred. We will then wait
* to resynchronise. */
vPrintDisplayMessage( &pcTaskErrorMsg );
sResyncRequired = pdTRUE;
}
else
{
/* This was the expected character so next time we will expect
* the next character in the string. Wrap back to the beginning
* of the string when the null terminator has been reached. */
pcExpectedChar++;
if( *pcExpectedChar == '\0' )
{
pcExpectedChar = pcMessageToExchange;
/* We have got through the entire string without error. */
sConsecutiveErrors = 0;
}
}
}
/* Increment the count that is used to check that this task is still
* running. This is only done if an error has never occurred. */
if( sLatchedError == pdFALSE )
{
sRxCount++;
}
}
else
{
vPrintDisplayMessage( &pcTaskTimeoutMsg );
}
}
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/
static void vSemTestTask( void * pvParameters )
{
const char * const pcTaskStartMsg = "ISR Semaphore test started.\r\n";
portBASE_TYPE xError = pdFALSE;
/* Stop warnings. */
( void ) pvParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
for( ; ; )
{
if( xSerialWaitForSemaphore( xPort ) )
{
if( xError == pdFALSE )
{
sSemCount++;
}
}
else
{
xError = pdTRUE;
}
}
} /*lint !e715 !e830 !e818 pvParameters not used but function prototype must be standard for task function. */
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreComTestTasksStillRunning( void )
{
static short sLastTxCount = 0, sLastRxCount = 0, sLastSemCount = 0;
portBASE_TYPE xReturn;
/* Not too worried about mutual exclusion on these variables as they are 16
* bits and we are only reading them. We also only care to see if they have
* changed or not. */
if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
sLastTxCount = sTxCount;
sLastRxCount = sRxCount;
sLastSemCount = sSemCount;
return xReturn;
}
/*-----------------------------------------------------------*/
void vComTestUnsuspendTask( void )
{
/* The task that is suspended on the semaphore will be referenced from the
* Suspended list as it is blocking indefinitely. This call just checks that
* the kernel correctly detects this and does not attempt to unsuspend the
* task. */
xTaskResumeFromISR( xSemTestTaskHandle );
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Creates two tasks that operate on an interrupt driven serial port. A loopback
* connector should be used so that everything that is transmitted is also received.
* The serial port does not use any flow control. On a standard 9way 'D' connector
* pins two and three should be connected together.
*
* The first task repeatedly sends a string to a queue, character at a time. The
* serial port interrupt will empty the queue and transmit the characters. The
* task blocks for a pseudo random period before resending the string.
*
* The second task blocks on a queue waiting for a character to be received.
* Characters received by the serial port interrupt routine are posted onto the
* queue - unblocking the task making it ready to execute. If this is then the
* highest priority task ready to run it will run immediately - with a context
* switch occurring at the end of the interrupt service routine. The task
* receiving characters is spawned with a higher priority than the task
* transmitting the characters.
*
* With the loop back connector in place, one task will transmit a string and the
* other will immediately receive it. The receiving task knows the string it
* expects to receive so can detect an error.
*
* This also creates a third task. This is used to test semaphore usage from an
* ISR and does nothing interesting.
*
* \page ComTestC comtest.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V1.00:
*
+ The priority of the Rx task has been lowered. Received characters are
+ now processed (read from the queue) at the idle priority, allowing low
+ priority tasks to run evenly at times of a high communications overhead.
+
+ Changes from V1.01:
+
+ The Tx task now waits a pseudo random time between transmissions.
+ Previously a fixed period was used but this was not such a good test as
+ interrupts fired at regular intervals.
+
+ Changes From V1.2.0:
+
+ Use vSerialPutString() instead of single character puts.
+ Only stop the check variable incrementing after two consecutive errors.
+
+ Changed from V1.2.5
+
+ Made the Rx task 2 priorities higher than the Tx task. Previously it was
+ only 1. This is done to tie in better with the other demo application
+ tasks.
+
+ Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
+ Slight modification to task priorities.
+
*/
/* Scheduler include files. */
#include <stdlib.h>
#include <string.h>
#include "FreeRTOS.h"
#include "task.h"
/* Demo program include files. */
#include "serial.h"
#include "comtest.h"
#include "print.h"
/* The Tx task will transmit the sequence of characters at a pseudo random
* interval. This is the maximum and minimum block time between sends. */
#define comTX_MAX_BLOCK_TIME ( ( TickType_t ) 0x15e )
#define comTX_MIN_BLOCK_TIME ( ( TickType_t ) 0xc8 )
#define comMAX_CONSECUTIVE_ERRORS ( 2 )
#define comSTACK_SIZE ( ( unsigned short ) 256 )
#define comRX_RELATIVE_PRIORITY ( 1 )
/* Handle to the com port used by both tasks. */
static xComPortHandle xPort;
/* The transmit function as described at the top of the file. */
static void vComTxTask( void * pvParameters );
/* The receive function as described at the top of the file. */
static void vComRxTask( void * pvParameters );
/* The semaphore test function as described at the top of the file. */
static void vSemTestTask( void * pvParameters );
/* The string that is repeatedly transmitted. */
const char * const pcMessageToExchange = "Send this message over and over again to check communications interrupts. "
"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ\r\n";
/* Variables that are incremented on each cycle of each task. These are used to
* check that both tasks are still executing. */
volatile short sTxCount = 0, sRxCount = 0, sSemCount = 0;
/* The handle to the semaphore test task. */
static TaskHandle_t xSemTestTaskHandle = NULL;
/*-----------------------------------------------------------*/
void vStartComTestTasks( unsigned portBASE_TYPE uxPriority,
eCOMPort ePort,
eBaud eBaudRate )
{
const unsigned portBASE_TYPE uxBufferLength = 255;
/* Initialise the com port then spawn both tasks. */
xPort = xSerialPortInit( ePort, eBaudRate, serNO_PARITY, serBITS_8, serSTOP_1, uxBufferLength );
xTaskCreate( vComTxTask, "COMTx", comSTACK_SIZE, NULL, uxPriority, NULL );
xTaskCreate( vComRxTask, "COMRx", comSTACK_SIZE, NULL, uxPriority + comRX_RELATIVE_PRIORITY, NULL );
xTaskCreate( vSemTestTask, "ISRSem", comSTACK_SIZE, NULL, tskIDLE_PRIORITY, &xSemTestTaskHandle );
}
/*-----------------------------------------------------------*/
static void vComTxTask( void * pvParameters )
{
const char * const pcTaskStartMsg = "COM Tx task started.\r\n";
TickType_t xTimeToWait;
/* Stop warnings. */
( void ) pvParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
for( ; ; )
{
/* Send the string to the serial port. */
vSerialPutString( xPort, pcMessageToExchange, strlen( pcMessageToExchange ) );
/* We have posted all the characters in the string - increment the variable
* used to check that this task is still running, then wait before re-sending
* the string. */
sTxCount++;
xTimeToWait = xTaskGetTickCount();
/* Make sure we don't wait too long... */
xTimeToWait %= comTX_MAX_BLOCK_TIME;
/* ...but we do want to wait. */
if( xTimeToWait < comTX_MIN_BLOCK_TIME )
{
xTimeToWait = comTX_MIN_BLOCK_TIME;
}
vTaskDelay( xTimeToWait );
}
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/
static void vComRxTask( void * pvParameters )
{
const char * const pcTaskStartMsg = "COM Rx task started.\r\n";
const char * const pcTaskErrorMsg = "COM read error\r\n";
const char * const pcTaskRestartMsg = "COM resynced\r\n";
const char * const pcTaskTimeoutMsg = "COM Rx timed out\r\n";
const TickType_t xBlockTime = ( TickType_t ) 0xffff / portTICK_PERIOD_MS;
const char * pcExpectedChar;
portBASE_TYPE xGotChar;
char cRxedChar;
short sResyncRequired, sConsecutiveErrors, sLatchedError;
/* Stop warnings. */
( void ) pvParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The first expected character is the first character in the string. */
pcExpectedChar = pcMessageToExchange;
sResyncRequired = pdFALSE;
sConsecutiveErrors = 0;
sLatchedError = pdFALSE;
for( ; ; )
{
/* Receive a message from the com port interrupt routine. If a message is
* not yet available the call will block the task. */
xGotChar = xSerialGetChar( xPort, &cRxedChar, xBlockTime );
if( xGotChar == pdTRUE )
{
if( sResyncRequired == pdTRUE )
{
/* We got out of sequence and are waiting for the start of the next
* transmission of the string. */
if( cRxedChar == '\n' )
{
/* This is the end of the message so we can start again - with
* the first character in the string being the next thing we expect
* to receive. */
pcExpectedChar = pcMessageToExchange;
sResyncRequired = pdFALSE;
/* Queue a message for printing to say that we are going to try
* again. */
vPrintDisplayMessage( &pcTaskRestartMsg );
/* Stop incrementing the check variable, if consecutive errors occur. */
sConsecutiveErrors++;
if( sConsecutiveErrors >= comMAX_CONSECUTIVE_ERRORS )
{
sLatchedError = pdTRUE;
}
}
}
else
{
/* We have received a character, but is it the expected character? */
if( cRxedChar != *pcExpectedChar )
{
/* This was not the expected character so post a message for
* printing to say that an error has occurred. We will then wait
* to resynchronize. */
vPrintDisplayMessage( &pcTaskErrorMsg );
sResyncRequired = pdTRUE;
}
else
{
/* This was the expected character so next time we will expect
* the next character in the string. Wrap back to the beginning
* of the string when the null terminator has been reached. */
pcExpectedChar++;
if( *pcExpectedChar == '\0' )
{
pcExpectedChar = pcMessageToExchange;
/* We have got through the entire string without error. */
sConsecutiveErrors = 0;
}
}
}
/* Increment the count that is used to check that this task is still
* running. This is only done if an error has never occurred. */
if( sLatchedError == pdFALSE )
{
sRxCount++;
}
}
else
{
vPrintDisplayMessage( &pcTaskTimeoutMsg );
}
}
} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
/*-----------------------------------------------------------*/
static void vSemTestTask( void * pvParameters )
{
const char * const pcTaskStartMsg = "ISR Semaphore test started.\r\n";
portBASE_TYPE xError = pdFALSE;
/* Stop warnings. */
( void ) pvParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
for( ; ; )
{
if( xSerialWaitForSemaphore( xPort ) )
{
if( xError == pdFALSE )
{
sSemCount++;
}
}
else
{
xError = pdTRUE;
}
}
} /*lint !e715 !e830 !e818 pvParameters not used but function prototype must be standard for task function. */
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreComTestTasksStillRunning( void )
{
static short sLastTxCount = 0, sLastRxCount = 0, sLastSemCount = 0;
portBASE_TYPE xReturn;
/* Not too worried about mutual exclusion on these variables as they are 16
* bits and we are only reading them. We also only care to see if they have
* changed or not. */
if( ( sTxCount == sLastTxCount ) || ( sRxCount == sLastRxCount ) || ( sSemCount == sLastSemCount ) )
{
xReturn = pdFALSE;
}
else
{
xReturn = pdTRUE;
}
sLastTxCount = sTxCount;
sLastRxCount = sRxCount;
sLastSemCount = sSemCount;
return xReturn;
}
/*-----------------------------------------------------------*/
void vComTestUnsuspendTask( void )
{
/* The task that is suspended on the semaphore will be referenced from the
* Suspended list as it is blocking indefinitely. This call just checks that
* the kernel correctly detects this and does not attempt to unsuspend the
* task. */
xTaskResumeFromISR( xSemTestTaskHandle );
}

View file

@ -1,202 +1,202 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Create a single persistent task which periodically dynamically creates another
* four tasks. The original task is called the creator task, the four tasks it
* creates are called suicidal tasks.
*
* Two of the created suicidal tasks kill one other suicidal task before killing
* themselves - leaving just the original task remaining.
*
* The creator task must be spawned after all of the other demo application tasks
* as it keeps a check on the number of tasks under the scheduler control. The
* number of tasks it expects to see running should never be greater than the
* number of tasks that were in existence when the creator task was spawned, plus
* one set of four suicidal tasks. If this number is exceeded an error is flagged.
*
* \page DeathC death.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
/* Demo program include files. */
#include "death.h"
#include "print.h"
#define deathSTACK_SIZE ( ( unsigned short ) 512 )
/* The task originally created which is responsible for periodically dynamically
* creating another four tasks. */
static void vCreateTasks( void * pvParameters );
/* The task function of the dynamically created tasks. */
static void vSuicidalTask( void * pvParameters );
/* A variable which is incremented every time the dynamic tasks are created. This
* is used to check that the task is still running. */
static volatile short sCreationCount = 0;
/* Used to store the number of tasks that were originally running so the creator
* task can tell if any of the suicidal tasks have failed to die. */
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5;
/* Used to store a handle to the tasks that should be killed by a suicidal task,
* before it kills itself. */
TaskHandle_t xCreatedTask1, xCreatedTask2;
/*-----------------------------------------------------------*/
void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
{
unsigned portBASE_TYPE * puxPriority;
/* Create the Creator tasks - passing in as a parameter the priority at which
* the suicidal tasks should be created. */
puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
*puxPriority = uxPriority;
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );
/* Record the number of tasks that are running now so we know if any of the
* suicidal tasks have failed to be killed. */
uxTasksRunningAtStart = uxTaskGetNumberOfTasks();
}
/*-----------------------------------------------------------*/
static void vSuicidalTask( void * pvParameters )
{
portDOUBLE d1, d2;
TaskHandle_t xTaskToKill;
const TickType_t xDelay = ( TickType_t ) 500 / portTICK_PERIOD_MS;
if( pvParameters != NULL )
{
/* This task is periodically created four times. Tow created tasks are
* passed a handle to the other task so it can kill it before killing itself.
* The other task is passed in null. */
xTaskToKill = *( TaskHandle_t * ) pvParameters;
}
else
{
xTaskToKill = NULL;
}
for( ; ; )
{
/* Do something random just to use some stack and registers. */
d1 = 2.4;
d2 = 89.2;
d2 *= d1;
vTaskDelay( xDelay );
if( xTaskToKill != NULL )
{
/* Make sure the other task has a go before we delete it. */
vTaskDelay( ( TickType_t ) 0 );
/* Kill the other task that was created by vCreateTasks(). */
vTaskDelete( xTaskToKill );
/* Kill ourselves. */
vTaskDelete( NULL );
}
}
} /*lint !e818 !e550 Function prototype must be as per standard for task functions. */
/*-----------------------------------------------------------*/
static void vCreateTasks( void * pvParameters )
{
const TickType_t xDelay = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
unsigned portBASE_TYPE uxPriority;
const char * const pcTaskStartMsg = "Create task started.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;
vPortFree( pvParameters );
for( ; ; )
{
/* Just loop round, delaying then creating the four suicidal tasks. */
vTaskDelay( xDelay );
xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask1 );
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask1, uxPriority, NULL );
xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask2 );
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask2, uxPriority, NULL );
++sCreationCount;
}
}
/*-----------------------------------------------------------*/
/* This is called to check that the creator task is still running and that there
* are not any more than four extra tasks. */
portBASE_TYPE xIsCreateTaskStillRunning( void )
{
static short sLastCreationCount = 0;
short sReturn = pdTRUE;
unsigned portBASE_TYPE uxTasksRunningNow;
if( sLastCreationCount == sCreationCount )
{
sReturn = pdFALSE;
}
sLastCreationCount = sCreationCount;
uxTasksRunningNow = uxTaskGetNumberOfTasks();
if( uxTasksRunningNow < uxTasksRunningAtStart )
{
sReturn = pdFALSE;
}
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
{
sReturn = pdFALSE;
}
else
{
/* Everything is okay. */
}
return sReturn;
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Create a single persistent task which periodically dynamically creates another
* four tasks. The original task is called the creator task, the four tasks it
* creates are called suicidal tasks.
*
* Two of the created suicidal tasks kill one other suicidal task before killing
* themselves - leaving just the original task remaining.
*
* The creator task must be spawned after all of the other demo application tasks
* as it keeps a check on the number of tasks under the scheduler control. The
* number of tasks it expects to see running should never be greater than the
* number of tasks that were in existence when the creator task was spawned, plus
* one set of four suicidal tasks. If this number is exceeded an error is flagged.
*
* \page DeathC death.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
/* Demo program include files. */
#include "death.h"
#include "print.h"
#define deathSTACK_SIZE ( ( unsigned short ) 512 )
/* The task originally created which is responsible for periodically dynamically
* creating another four tasks. */
static void vCreateTasks( void * pvParameters );
/* The task function of the dynamically created tasks. */
static void vSuicidalTask( void * pvParameters );
/* A variable which is incremented every time the dynamic tasks are created. This
* is used to check that the task is still running. */
static volatile short sCreationCount = 0;
/* Used to store the number of tasks that were originally running so the creator
* task can tell if any of the suicidal tasks have failed to die. */
static volatile unsigned portBASE_TYPE uxTasksRunningAtStart = 0;
static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 5;
/* Used to store a handle to the tasks that should be killed by a suicidal task,
* before it kills itself. */
TaskHandle_t xCreatedTask1, xCreatedTask2;
/*-----------------------------------------------------------*/
void vCreateSuicidalTasks( unsigned portBASE_TYPE uxPriority )
{
unsigned portBASE_TYPE * puxPriority;
/* Create the Creator tasks - passing in as a parameter the priority at which
* the suicidal tasks should be created. */
puxPriority = ( unsigned portBASE_TYPE * ) pvPortMalloc( sizeof( unsigned portBASE_TYPE ) );
*puxPriority = uxPriority;
xTaskCreate( vCreateTasks, "CREATOR", deathSTACK_SIZE, ( void * ) puxPriority, uxPriority, NULL );
/* Record the number of tasks that are running now so we know if any of the
* suicidal tasks have failed to be killed. */
uxTasksRunningAtStart = uxTaskGetNumberOfTasks();
}
/*-----------------------------------------------------------*/
static void vSuicidalTask( void * pvParameters )
{
portDOUBLE d1, d2;
TaskHandle_t xTaskToKill;
const TickType_t xDelay = ( TickType_t ) 500 / portTICK_PERIOD_MS;
if( pvParameters != NULL )
{
/* This task is periodically created four times. Tow created tasks are
* passed a handle to the other task so it can kill it before killing itself.
* The other task is passed in null. */
xTaskToKill = *( TaskHandle_t * ) pvParameters;
}
else
{
xTaskToKill = NULL;
}
for( ; ; )
{
/* Do something random just to use some stack and registers. */
d1 = 2.4;
d2 = 89.2;
d2 *= d1;
vTaskDelay( xDelay );
if( xTaskToKill != NULL )
{
/* Make sure the other task has a go before we delete it. */
vTaskDelay( ( TickType_t ) 0 );
/* Kill the other task that was created by vCreateTasks(). */
vTaskDelete( xTaskToKill );
/* Kill ourselves. */
vTaskDelete( NULL );
}
}
} /*lint !e818 !e550 Function prototype must be as per standard for task functions. */
/*-----------------------------------------------------------*/
static void vCreateTasks( void * pvParameters )
{
const TickType_t xDelay = ( TickType_t ) 1000 / portTICK_PERIOD_MS;
unsigned portBASE_TYPE uxPriority;
const char * const pcTaskStartMsg = "Create task started.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;
vPortFree( pvParameters );
for( ; ; )
{
/* Just loop round, delaying then creating the four suicidal tasks. */
vTaskDelay( xDelay );
xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask1 );
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask1, uxPriority, NULL );
xTaskCreate( vSuicidalTask, "SUICIDE1", deathSTACK_SIZE, NULL, uxPriority, &xCreatedTask2 );
xTaskCreate( vSuicidalTask, "SUICIDE2", deathSTACK_SIZE, &xCreatedTask2, uxPriority, NULL );
++sCreationCount;
}
}
/*-----------------------------------------------------------*/
/* This is called to check that the creator task is still running and that there
* are not any more than four extra tasks. */
portBASE_TYPE xIsCreateTaskStillRunning( void )
{
static short sLastCreationCount = 0;
short sReturn = pdTRUE;
unsigned portBASE_TYPE uxTasksRunningNow;
if( sLastCreationCount == sCreationCount )
{
sReturn = pdFALSE;
}
sLastCreationCount = sCreationCount;
uxTasksRunningNow = uxTaskGetNumberOfTasks();
if( uxTasksRunningNow < uxTasksRunningAtStart )
{
sReturn = pdFALSE;
}
else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
{
sReturn = pdFALSE;
}
else
{
/* Everything is okay. */
}
return sReturn;
}

File diff suppressed because it is too large Load diff

View file

@ -1,368 +1,368 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* 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;
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* 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;
}

View file

@ -1,126 +1,126 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Creates eight tasks, each of which flash an LED at a different rate. The first
* LED flashes every 125ms, the second every 250ms, the third every 375ms, etc.
*
* The LED flash tasks provide instant visual feedback. They show that the scheduler
* is still operational.
*
* The PC port uses the standard parallel port for outputs, the Flashlite 186 port
* uses IO port F.
*
* \page flashC flash.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
+
+ Changes from V2.1.1
+
+ The stack size now uses configMINIMAL_STACK_SIZE.
+ String constants made file scope to decrease stack depth on 8051 port.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
/* Demo program include files. */
#include "partest.h"
#include "flash.h"
#include "print.h"
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
/* Structure used to pass parameters to the LED tasks. */
typedef struct LED_PARAMETERS
{
unsigned portBASE_TYPE uxLED; /*< The output the task should use. */
TickType_t xFlashRate; /*< The rate at which the LED should flash. */
} xLEDParameters;
/* The task that is created eight times - each time with a different xLEDParaemtes
* structure passed in as the parameter. */
static void vLEDFlashTask( void * pvParameters );
/* String to print if USE_STDIO is defined. */
const char * const pcTaskStartMsg = "LED flash task started.\r\n";
/*-----------------------------------------------------------*/
void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )
{
unsigned portBASE_TYPE uxLEDTask;
xLEDParameters * pxLEDParameters;
const unsigned portBASE_TYPE uxNumOfLEDs = 8;
const TickType_t xFlashRate = 125;
/* Create the eight tasks. */
for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask )
{
/* Create and complete the structure used to pass parameters to the next
* created task. */
pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) );
pxLEDParameters->uxLED = uxLEDTask;
pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( TickType_t ) uxLEDTask ) );
pxLEDParameters->xFlashRate /= portTICK_PERIOD_MS;
/* Spawn the task. */
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, ( void * ) pxLEDParameters, uxPriority, ( TaskHandle_t * ) NULL );
}
}
/*-----------------------------------------------------------*/
static void vLEDFlashTask( void * pvParameters )
{
xLEDParameters * pxParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
pxParameters = ( xLEDParameters * ) pvParameters;
for( ; ; )
{
/* Delay for half the flash period then turn the LED on. */
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
vParTestToggleLED( pxParameters->uxLED );
/* Delay for half the flash period then turn the LED off. */
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
vParTestToggleLED( pxParameters->uxLED );
}
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Creates eight tasks, each of which flash an LED at a different rate. The first
* LED flashes every 125ms, the second every 250ms, the third every 375ms, etc.
*
* The LED flash tasks provide instant visual feedback. They show that the scheduler
* is still operational.
*
* The PC port uses the standard parallel port for outputs, the Flashlite 186 port
* uses IO port F.
*
* \page flashC flash.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
+
+ Changes from V2.1.1
+
+ The stack size now uses configMINIMAL_STACK_SIZE.
+ String constants made file scope to decrease stack depth on 8051 port.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
/* Demo program include files. */
#include "partest.h"
#include "flash.h"
#include "print.h"
#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
/* Structure used to pass parameters to the LED tasks. */
typedef struct LED_PARAMETERS
{
unsigned portBASE_TYPE uxLED; /*< The output the task should use. */
TickType_t xFlashRate; /*< The rate at which the LED should flash. */
} xLEDParameters;
/* The task that is created eight times - each time with a different xLEDParameters
* structure passed in as the parameter. */
static void vLEDFlashTask( void * pvParameters );
/* String to print if USE_STDIO is defined. */
const char * const pcTaskStartMsg = "LED flash task started.\r\n";
/*-----------------------------------------------------------*/
void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )
{
unsigned portBASE_TYPE uxLEDTask;
xLEDParameters * pxLEDParameters;
const unsigned portBASE_TYPE uxNumOfLEDs = 8;
const TickType_t xFlashRate = 125;
/* Create the eight tasks. */
for( uxLEDTask = 0; uxLEDTask < uxNumOfLEDs; ++uxLEDTask )
{
/* Create and complete the structure used to pass parameters to the next
* created task. */
pxLEDParameters = ( xLEDParameters * ) pvPortMalloc( sizeof( xLEDParameters ) );
pxLEDParameters->uxLED = uxLEDTask;
pxLEDParameters->xFlashRate = ( xFlashRate + ( xFlashRate * ( TickType_t ) uxLEDTask ) );
pxLEDParameters->xFlashRate /= portTICK_PERIOD_MS;
/* Spawn the task. */
xTaskCreate( vLEDFlashTask, "LEDx", ledSTACK_SIZE, ( void * ) pxLEDParameters, uxPriority, ( TaskHandle_t * ) NULL );
}
}
/*-----------------------------------------------------------*/
static void vLEDFlashTask( void * pvParameters )
{
xLEDParameters * pxParameters;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
pxParameters = ( xLEDParameters * ) pvParameters;
for( ; ; )
{
/* Delay for half the flash period then turn the LED on. */
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
vParTestToggleLED( pxParameters->uxLED );
/* Delay for half the flash period then turn the LED off. */
vTaskDelay( pxParameters->xFlashRate / ( TickType_t ) 2 );
vParTestToggleLED( pxParameters->uxLED );
}
}

View file

@ -1,329 +1,329 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* Changes from V1.2.3
*
+ The created tasks now include calls to tskYIELD(), allowing them to be used
+ with the cooperative scheduler.
*/
/**
* Creates eight tasks, each of which loops continuously performing an (emulated)
* floating point calculation.
*
* All the tasks run at the idle priority and never block or yield. This causes
* all eight tasks to time slice with the idle task. Running at the idle priority
* means that these tasks will get pre-empted any time another task is ready to run
* or a time slice occurs. More often than not the pre-emption will occur mid
* calculation, creating a good test of the schedulers context switch mechanism - a
* calculation producing an unexpected result could be a symptom of a corruption in
* the context of a task.
*
* \page FlopC flop.c
* \ingroup DemoFiles
* <HR>
*/
#include <stdlib.h>
#include <math.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "print.h"
/* Demo program include files. */
#include "flop.h"
#define mathSTACK_SIZE ( ( unsigned short ) 512 )
#define mathNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different floating point calculation.
* Each of the four is created twice. */
static void vCompetingMathTask1( void * pvParameters );
static void vCompetingMathTask2( void * pvParameters );
static void vCompetingMathTask3( void * pvParameters );
static void vCompetingMathTask4( void * pvParameters );
/* These variables are used to check that all the tasks are still running. If a
* task gets a calculation wrong it will
* stop incrementing its check variable. */
static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
/*-----------------------------------------------------------*/
void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
{
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
}
/*-----------------------------------------------------------*/
static void vCompetingMathTask1( void * pvParameters )
{
portDOUBLE d1, d2, d3, d4;
volatile unsigned short * pusTaskCheckVariable;
const portDOUBLE dAnswer = ( 123.4567 + 2345.6789 ) * -918.222;
const char * const pcTaskStartMsg = "Math task 1 started.\r\n";
const char * const pcTaskFailMsg = "Math task 1 failed.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */
for( ; ; )
{
d1 = 123.4567;
d2 = 2345.6789;
d3 = -918.222;
d4 = ( d1 + d2 ) * d3;
taskYIELD();
/* If the calculation does not match the expected constant, stop the
* increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
taskYIELD();
}
}
/*-----------------------------------------------------------*/
static void vCompetingMathTask2( void * pvParameters )
{
portDOUBLE d1, d2, d3, d4;
volatile unsigned short * pusTaskCheckVariable;
const portDOUBLE dAnswer = ( -389.38 / 32498.2 ) * -2.0001;
const char * const pcTaskStartMsg = "Math task 2 started.\r\n";
const char * const pcTaskFailMsg = "Math task 2 failed.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */
for( ; ; )
{
d1 = -389.38;
d2 = 32498.2;
d3 = -2.0001;
d4 = ( d1 / d2 ) * d3;
taskYIELD();
/* If the calculation does not match the expected constant, stop the
* increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know
* this task is still running okay. */
( *pusTaskCheckVariable )++;
}
taskYIELD();
}
}
/*-----------------------------------------------------------*/
static void vCompetingMathTask3( void * pvParameters )
{
portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250;
unsigned short usPosition;
const char * const pcTaskStartMsg = "Math task 3 started.\r\n";
const char * const pcTaskFailMsg = "Math task 3 failed.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the
* array. Then run through the array adding up all the values. If the two totals
* do not match, stop the check variable from incrementing. */
for( ; ; )
{
dTotal1 = 0.0;
dTotal2 = 0.0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
pdArray[ usPosition ] = ( portDOUBLE ) usPosition + 5.5;
dTotal1 += ( portDOUBLE ) usPosition + 5.5;
}
taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
dTotal2 += pdArray[ usPosition ];
}
dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD();
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
static void vCompetingMathTask4( void * pvParameters )
{
portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250;
unsigned short usPosition;
const char * const pcTaskStartMsg = "Math task 4 started.\r\n";
const char * const pcTaskFailMsg = "Math task 4 failed.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the
* array. Then run through the array adding up all the values. If the two totals
* do not match, stop the check variable from incrementing. */
for( ; ; )
{
dTotal1 = 0.0;
dTotal2 = 0.0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
pdArray[ usPosition ] = ( portDOUBLE ) usPosition * 12.123;
dTotal1 += ( portDOUBLE ) usPosition * 12.123;
}
taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
dTotal2 += pdArray[ usPosition ];
}
dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD();
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreMathsTaskStillRunning( void )
{
/* Keep a history of the check variables so we know if they have been incremented
* since the last call. */
static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables
* are still incrementing. */
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
{
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
{
/* The check has not incremented so an error exists. */
xReturn = pdFALSE;
}
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
}
return xReturn;
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* Changes from V1.2.3
*
+ The created tasks now include calls to tskYIELD(), allowing them to be used
+ with the cooperative scheduler.
*/
/**
* Creates eight tasks, each of which loops continuously performing an (emulated)
* floating point calculation.
*
* All the tasks run at the idle priority and never block or yield. This causes
* all eight tasks to time slice with the idle task. Running at the idle priority
* means that these tasks will get pre-empted any time another task is ready to run
* or a time slice occurs. More often than not the pre-emption will occur mid
* calculation, creating a good test of the schedulers context switch mechanism - a
* calculation producing an unexpected result could be a symptom of a corruption in
* the context of a task.
*
* \page FlopC flop.c
* \ingroup DemoFiles
* <HR>
*/
#include <stdlib.h>
#include <math.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "print.h"
/* Demo program include files. */
#include "flop.h"
#define mathSTACK_SIZE ( ( unsigned short ) 512 )
#define mathNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different floating point calculation.
* Each of the four is created twice. */
static void vCompetingMathTask1( void * pvParameters );
static void vCompetingMathTask2( void * pvParameters );
static void vCompetingMathTask3( void * pvParameters );
static void vCompetingMathTask4( void * pvParameters );
/* These variables are used to check that all the tasks are still running. If a
* task gets a calculation wrong it will
* stop incrementing its check variable. */
static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
/*-----------------------------------------------------------*/
void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
{
xTaskCreate( vCompetingMathTask1, "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask1, "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask2, "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask3, "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
xTaskCreate( vCompetingMathTask4, "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
}
/*-----------------------------------------------------------*/
static void vCompetingMathTask1( void * pvParameters )
{
portDOUBLE d1, d2, d3, d4;
volatile unsigned short * pusTaskCheckVariable;
const portDOUBLE dAnswer = ( 123.4567 + 2345.6789 ) * -918.222;
const char * const pcTaskStartMsg = "Math task 1 started.\r\n";
const char * const pcTaskFailMsg = "Math task 1 failed.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */
for( ; ; )
{
d1 = 123.4567;
d2 = 2345.6789;
d3 = -918.222;
d4 = ( d1 + d2 ) * d3;
taskYIELD();
/* If the calculation does not match the expected constant, stop the
* increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
taskYIELD();
}
}
/*-----------------------------------------------------------*/
static void vCompetingMathTask2( void * pvParameters )
{
portDOUBLE d1, d2, d3, d4;
volatile unsigned short * pusTaskCheckVariable;
const portDOUBLE dAnswer = ( -389.38 / 32498.2 ) * -2.0001;
const char * const pcTaskStartMsg = "Math task 2 started.\r\n";
const char * const pcTaskFailMsg = "Math task 2 failed.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */
for( ; ; )
{
d1 = -389.38;
d2 = 32498.2;
d3 = -2.0001;
d4 = ( d1 / d2 ) * d3;
taskYIELD();
/* If the calculation does not match the expected constant, stop the
* increment of the check variable. */
if( fabs( d4 - dAnswer ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know
* this task is still running okay. */
( *pusTaskCheckVariable )++;
}
taskYIELD();
}
}
/*-----------------------------------------------------------*/
static void vCompetingMathTask3( void * pvParameters )
{
portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250;
unsigned short usPosition;
const char * const pcTaskStartMsg = "Math task 3 started.\r\n";
const char * const pcTaskFailMsg = "Math task 3 failed.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the
* array. Then run through the array adding up all the values. If the two totals
* do not match, stop the check variable from incrementing. */
for( ; ; )
{
dTotal1 = 0.0;
dTotal2 = 0.0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
pdArray[ usPosition ] = ( portDOUBLE ) usPosition + 5.5;
dTotal1 += ( portDOUBLE ) usPosition + 5.5;
}
taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
dTotal2 += pdArray[ usPosition ];
}
dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD();
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
static void vCompetingMathTask4( void * pvParameters )
{
portDOUBLE * pdArray, dTotal1, dTotal2, dDifference;
volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250;
unsigned short usPosition;
const char * const pcTaskStartMsg = "Math task 4 started.\r\n";
const char * const pcTaskFailMsg = "Math task 4 failed.\r\n";
short sError = pdFALSE;
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
pdArray = ( portDOUBLE * ) pvPortMalloc( ( size_t ) 250 * sizeof( portDOUBLE ) );
/* Keep filling an array, keeping a running total of the values placed in the
* array. Then run through the array adding up all the values. If the two totals
* do not match, stop the check variable from incrementing. */
for( ; ; )
{
dTotal1 = 0.0;
dTotal2 = 0.0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
pdArray[ usPosition ] = ( portDOUBLE ) usPosition * 12.123;
dTotal1 += ( portDOUBLE ) usPosition * 12.123;
}
taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
dTotal2 += pdArray[ usPosition ];
}
dDifference = dTotal1 - dTotal2;
if( fabs( dDifference ) > 0.001 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD();
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreMathsTaskStillRunning( void )
{
/* Keep a history of the check variables so we know if they have been incremented
* since the last call. */
static unsigned short usLastTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables
* are still incrementing. */
for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
{
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
{
/* The check has not incremented so an error exists. */
xReturn = pdFALSE;
}
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
}
return xReturn;
}

View file

@ -1,325 +1,325 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* Changes from V1.2.3
*
+ The created tasks now include calls to tskYIELD(), allowing them to be used
+ with the cooperative scheduler.
*/
/**
* This does the same as flop. c, but uses variables of type long instead of
* type double.
*
* As with flop. c, the tasks created in this file are a good test of the
* scheduler context switch mechanism. The processor has to access 32bit
* variables in two or four chunks (depending on the processor). The low
* priority of these tasks means there is a high probability that a context
* switch will occur mid calculation. See the flop. c documentation for
* more information.
*
* \page IntegerC integer.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V1.2.1
*
+ The constants used in the calculations are larger to ensure the
+ optimiser does not truncate them to 16 bits.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "print.h"
/* Demo program include files. */
#include "integer.h"
#define intgSTACK_SIZE ( ( unsigned short ) 256 )
#define intgNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different calculation on four byte
* variables. Each of the four is created twice. */
static void vCompeteingIntMathTask1( void * pvParameters );
static void vCompeteingIntMathTask2( void * pvParameters );
static void vCompeteingIntMathTask3( void * pvParameters );
static void vCompeteingIntMathTask4( void * pvParameters );
/* These variables are used to check that all the tasks are still running. If a
* task gets a calculation wrong it will stop incrementing its check variable. */
static volatile unsigned short usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
/*-----------------------------------------------------------*/
void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority )
{
xTaskCreate( vCompeteingIntMathTask1, "IntMath1", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask2, "IntMath2", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask3, "IntMath3", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask4, "IntMath4", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask1, "IntMath5", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask2, "IntMath6", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask3, "IntMath7", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask4, "IntMath8", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
}
/*-----------------------------------------------------------*/
static void vCompeteingIntMathTask1( void * pvParameters )
{
long l1, l2, l3, l4;
short sError = pdFALSE;
volatile unsigned short * pusTaskCheckVariable;
const long lAnswer = ( ( long ) 74565L + ( long ) 1234567L ) * ( long ) -918L;
const char * const pcTaskStartMsg = "Integer math task 1 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */
for( ; ; )
{
l1 = ( long ) 74565L;
l2 = ( long ) 1234567L;
l3 = ( long ) -918L;
l4 = ( l1 + l2 ) * l3;
taskYIELD();
/* If the calculation does not match the expected constant, stop the
* increment of the check variable. */
if( l4 != lAnswer )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
static void vCompeteingIntMathTask2( void * pvParameters )
{
long l1, l2, l3, l4;
short sError = pdFALSE;
volatile unsigned short * pusTaskCheckVariable;
const long lAnswer = ( ( long ) -389000L / ( long ) 329999L ) * ( long ) -89L;
const char * const pcTaskStartMsg = "Integer math task 2 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */
for( ; ; )
{
l1 = -389000L;
l2 = 329999L;
l3 = -89L;
l4 = ( l1 / l2 ) * l3;
taskYIELD();
/* If the calculation does not match the expected constant, stop the
* increment of the check variable. */
if( l4 != lAnswer )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
static void vCompeteingIntMathTask3( void * pvParameters )
{
long * plArray, lTotal1, lTotal2;
short sError = pdFALSE;
volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = ( unsigned short ) 250;
unsigned short usPosition;
const char * const pcTaskStartMsg = "Integer math task 3 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 3 failed.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Create the array we are going to use for our check calculation. */
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
/* Keep filling the array, keeping a running total of the values placed in the
* array. Then run through the array adding up all the values. If the two totals
* do not match, stop the check variable from incrementing. */
for( ; ; )
{
lTotal1 = ( long ) 0;
lTotal2 = ( long ) 0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
plArray[ usPosition ] = ( long ) usPosition + ( long ) 5;
lTotal1 += ( long ) usPosition + ( long ) 5;
}
taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
lTotal2 += plArray[ usPosition ];
}
if( lTotal1 != lTotal2 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD();
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
static void vCompeteingIntMathTask4( void * pvParameters )
{
long * plArray, lTotal1, lTotal2;
short sError = pdFALSE;
volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250;
unsigned short usPosition;
const char * const pcTaskStartMsg = "Integer math task 4 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Create the array we are going to use for our check calculation. */
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
/* Keep filling the array, keeping a running total of the values placed in the
* array. Then run through the array adding up all the values. If the two totals
* do not match, stop the check variable from incrementing. */
for( ; ; )
{
lTotal1 = ( long ) 0;
lTotal2 = ( long ) 0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
plArray[ usPosition ] = ( long ) usPosition * ( long ) 12;
lTotal1 += ( long ) usPosition * ( long ) 12;
}
taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
lTotal2 += plArray[ usPosition ];
}
if( lTotal1 != lTotal2 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD();
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
{
/* Keep a history of the check variables so we know if they have been incremented
* since the last call. */
static unsigned short usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables
* are still incrementing. */
for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ )
{
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
{
/* The check has not incremented so an error exists. */
xReturn = pdFALSE;
}
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
}
return xReturn;
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* Changes from V1.2.3
*
+ The created tasks now include calls to tskYIELD(), allowing them to be used
+ with the cooperative scheduler.
*/
/**
* This does the same as flop. c, but uses variables of type long instead of
* type double.
*
* As with flop. c, the tasks created in this file are a good test of the
* scheduler context switch mechanism. The processor has to access 32bit
* variables in two or four chunks (depending on the processor). The low
* priority of these tasks means there is a high probability that a context
* switch will occur mid calculation. See the flop. c documentation for
* more information.
*
* \page IntegerC integer.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V1.2.1
*
+ The constants used in the calculations are larger to ensure the
+ optimiser does not truncate them to 16 bits.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "print.h"
/* Demo program include files. */
#include "integer.h"
#define intgSTACK_SIZE ( ( unsigned short ) 256 )
#define intgNUMBER_OF_TASKS ( 8 )
/* Four tasks, each of which performs a different calculation on four byte
* variables. Each of the four is created twice. */
static void vCompeteingIntMathTask1( void * pvParameters );
static void vCompeteingIntMathTask2( void * pvParameters );
static void vCompeteingIntMathTask3( void * pvParameters );
static void vCompeteingIntMathTask4( void * pvParameters );
/* These variables are used to check that all the tasks are still running. If a
* task gets a calculation wrong it will stop incrementing its check variable. */
static volatile unsigned short usTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
/*-----------------------------------------------------------*/
void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority )
{
xTaskCreate( vCompeteingIntMathTask1, "IntMath1", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask2, "IntMath2", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask3, "IntMath3", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask4, "IntMath4", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask1, "IntMath5", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask2, "IntMath6", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask3, "IntMath7", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
xTaskCreate( vCompeteingIntMathTask4, "IntMath8", intgSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
}
/*-----------------------------------------------------------*/
static void vCompeteingIntMathTask1( void * pvParameters )
{
long l1, l2, l3, l4;
short sError = pdFALSE;
volatile unsigned short * pusTaskCheckVariable;
const long lAnswer = ( ( long ) 74565L + ( long ) 1234567L ) * ( long ) -918L;
const char * const pcTaskStartMsg = "Integer math task 1 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 1 failed.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */
for( ; ; )
{
l1 = ( long ) 74565L;
l2 = ( long ) 1234567L;
l3 = ( long ) -918L;
l4 = ( l1 + l2 ) * l3;
taskYIELD();
/* If the calculation does not match the expected constant, stop the
* increment of the check variable. */
if( l4 != lAnswer )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
static void vCompeteingIntMathTask2( void * pvParameters )
{
long l1, l2, l3, l4;
short sError = pdFALSE;
volatile unsigned short * pusTaskCheckVariable;
const long lAnswer = ( ( long ) -389000L / ( long ) 329999L ) * ( long ) -89L;
const char * const pcTaskStartMsg = "Integer math task 2 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 2 failed.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Keep performing a calculation and checking the result against a constant. */
for( ; ; )
{
l1 = -389000L;
l2 = 329999L;
l3 = -89L;
l4 = ( l1 / l2 ) * l3;
taskYIELD();
/* If the calculation does not match the expected constant, stop the
* increment of the check variable. */
if( l4 != lAnswer )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
static void vCompeteingIntMathTask3( void * pvParameters )
{
long * plArray, lTotal1, lTotal2;
short sError = pdFALSE;
volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = ( unsigned short ) 250;
unsigned short usPosition;
const char * const pcTaskStartMsg = "Integer math task 3 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 3 failed.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Create the array we are going to use for our check calculation. */
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
/* Keep filling the array, keeping a running total of the values placed in the
* array. Then run through the array adding up all the values. If the two totals
* do not match, stop the check variable from incrementing. */
for( ; ; )
{
lTotal1 = ( long ) 0;
lTotal2 = ( long ) 0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
plArray[ usPosition ] = ( long ) usPosition + ( long ) 5;
lTotal1 += ( long ) usPosition + ( long ) 5;
}
taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
lTotal2 += plArray[ usPosition ];
}
if( lTotal1 != lTotal2 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD();
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
static void vCompeteingIntMathTask4( void * pvParameters )
{
long * plArray, lTotal1, lTotal2;
short sError = pdFALSE;
volatile unsigned short * pusTaskCheckVariable;
const unsigned short usArraySize = 250;
unsigned short usPosition;
const char * const pcTaskStartMsg = "Integer math task 4 started.\r\n";
const char * const pcTaskFailMsg = "Integer math task 4 failed.\r\n";
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcTaskStartMsg );
/* The variable this task increments to show it is still running is passed in
* as the parameter. */
pusTaskCheckVariable = ( unsigned short * ) pvParameters;
/* Create the array we are going to use for our check calculation. */
plArray = ( long * ) pvPortMalloc( ( size_t ) 250 * sizeof( long ) );
/* Keep filling the array, keeping a running total of the values placed in the
* array. Then run through the array adding up all the values. If the two totals
* do not match, stop the check variable from incrementing. */
for( ; ; )
{
lTotal1 = ( long ) 0;
lTotal2 = ( long ) 0;
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
plArray[ usPosition ] = ( long ) usPosition * ( long ) 12;
lTotal1 += ( long ) usPosition * ( long ) 12;
}
taskYIELD();
for( usPosition = 0; usPosition < usArraySize; usPosition++ )
{
lTotal2 += plArray[ usPosition ];
}
if( lTotal1 != lTotal2 )
{
vPrintDisplayMessage( &pcTaskFailMsg );
sError = pdTRUE;
}
taskYIELD();
if( sError == pdFALSE )
{
/* If the calculation has always been correct, increment the check
* variable so we know this task is still running okay. */
( *pusTaskCheckVariable )++;
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
{
/* Keep a history of the check variables so we know if they have been incremented
* since the last call. */
static unsigned short usLastTaskCheck[ intgNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
portBASE_TYPE xReturn = pdTRUE, xTask;
/* Check the maths tasks are still running by ensuring their check variables
* are still incrementing. */
for( xTask = 0; xTask < intgNUMBER_OF_TASKS; xTask++ )
{
if( usTaskCheck[ xTask ] == usLastTaskCheck[ xTask ] )
{
/* The check has not incremented so an error exists. */
xReturn = pdFALSE;
}
usLastTaskCheck[ xTask ] = usTaskCheck[ xTask ];
}
return xReturn;
}

View file

@ -1,103 +1,103 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Manages a queue of strings that are waiting to be displayed. This is used to
* ensure mutual exclusion of console output.
*
* A task wishing to display a message will call vPrintDisplayMessage (), with a
* pointer to the string as the parameter. The pointer is posted onto the
* xPrintQueue queue.
*
* The task spawned in main. c blocks on xPrintQueue. When a message becomes
* available it calls pcPrintGetNextMessage () to obtain a pointer to the next
* string, then uses the functions defined in the portable layer FileIO. c to
* display the message.
*
* <b>NOTE:</b>
* Using console IO can disrupt real time performance - depending on the port.
* Standard C IO routines are not designed for real time applications. While
* standard IO is useful for demonstration and debugging an alternative method
* should be used if you actually require console IO as part of your application.
*
* \page PrintC print.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "queue.h"
/* Demo program include files. */
#include "print.h"
static QueueHandle_t xPrintQueue;
/*-----------------------------------------------------------*/
void vPrintInitialise( void )
{
const unsigned portBASE_TYPE uxQueueSize = 20;
/* Create the queue on which errors will be reported. */
xPrintQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( char * ) );
}
/*-----------------------------------------------------------*/
void vPrintDisplayMessage( const char * const * ppcMessageToSend )
{
#ifdef USE_STDIO
xQueueSend( xPrintQueue, ( void * ) ppcMessageToSend, ( TickType_t ) 0 );
#else
/* Stop warnings. */
( void ) ppcMessageToSend;
#endif
}
/*-----------------------------------------------------------*/
const char * pcPrintGetNextMessage( TickType_t xPrintRate )
{
char * pcMessage;
if( xQueueReceive( xPrintQueue, &pcMessage, xPrintRate ) == pdPASS )
{
return pcMessage;
}
else
{
return NULL;
}
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Manages a queue of strings that are waiting to be displayed. This is used to
* ensure mutual exclusion of console output.
*
* A task wishing to display a message will call vPrintDisplayMessage (), with a
* pointer to the string as the parameter. The pointer is posted onto the
* xPrintQueue queue.
*
* The task spawned in main. c blocks on xPrintQueue. When a message becomes
* available it calls pcPrintGetNextMessage () to obtain a pointer to the next
* string, then uses the functions defined in the portable layer FileIO. c to
* display the message.
*
* <b>NOTE:</b>
* Using console IO can disrupt real time performance - depending on the port.
* Standard C IO routines are not designed for real time applications. While
* standard IO is useful for demonstration and debugging an alternative method
* should be used if you actually require console IO as part of your application.
*
* \page PrintC print.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V2.0.0
*
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "queue.h"
/* Demo program include files. */
#include "print.h"
static QueueHandle_t xPrintQueue;
/*-----------------------------------------------------------*/
void vPrintInitialise( void )
{
const unsigned portBASE_TYPE uxQueueSize = 20;
/* Create the queue on which errors will be reported. */
xPrintQueue = xQueueCreate( uxQueueSize, ( unsigned portBASE_TYPE ) sizeof( char * ) );
}
/*-----------------------------------------------------------*/
void vPrintDisplayMessage( const char * const * ppcMessageToSend )
{
#ifdef USE_STDIO
xQueueSend( xPrintQueue, ( void * ) ppcMessageToSend, ( TickType_t ) 0 );
#else
/* Stop warnings. */
( void ) ppcMessageToSend;
#endif
}
/*-----------------------------------------------------------*/
const char * pcPrintGetNextMessage( TickType_t xPrintRate )
{
char * pcMessage;
if( xQueueReceive( xPrintQueue, &pcMessage, xPrintRate ) == pdPASS )
{
return pcMessage;
}
else
{
return NULL;
}
}

View file

@ -1,285 +1,285 @@
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Creates two sets of two tasks. The tasks within a set share a variable, access
* to which is guarded by a semaphore.
*
* Each task starts by attempting to obtain the semaphore. On obtaining a
* semaphore a task checks to ensure that the guarded variable has an expected
* value. It then clears the variable to zero before counting it back up to the
* expected value in increments of 1. After each increment the variable is checked
* to ensure it contains the value to which it was just set. When the starting
* value is again reached the task releases the semaphore giving the other task in
* the set a chance to do exactly the same thing. The starting value is high
* enough to ensure that a tick is likely to occur during the incrementing loop.
*
* An error is flagged if at any time during the process a shared variable is
* found to have a value other than that expected. Such an occurrence would
* suggest an error in the mutual exclusion mechanism by which access to the
* variable is restricted.
*
* The first set of two tasks poll their semaphore. The second set use blocking
* calls.
*
* \page SemTestC semtest.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V1.2.0:
*
+ The tasks that operate at the idle priority now use a lower expected
+ count than those running at a higher priority. This prevents the low
+ priority tasks from signaling an error because they have not been
+ scheduled enough time for each of them to count the shared variable to
+ the high value.
+
+ Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
+
+ Changes from V2.1.1
+
+ The stack size now uses configMINIMAL_STACK_SIZE.
+ String constants made file scope to decrease stack depth on 8051 port.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* Demo app include files. */
#include "semtest.h"
#include "print.h"
/* The value to which the shared variables are counted. */
#define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xfff )
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xff )
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
#define semtstNUM_TASKS ( 4 )
#define semtstDELAY_FACTOR ( ( TickType_t ) 10 )
/* The task function as described at the top of the file. */
static void prvSemaphoreTest( void * pvParameters );
/* Structure used to pass parameters to each task. */
typedef struct SEMAPHORE_PARAMETERS
{
SemaphoreHandle_t xSemaphore;
volatile unsigned long * pulSharedVariable;
TickType_t xBlockTime;
} xSemaphoreParameters;
/* Variables used to check that all the tasks are still running without errors. */
static volatile short sCheckVariables[ semtstNUM_TASKS ] = { 0 };
static volatile short sNextCheckVariable = 0;
/* Strings to print if USE_STDIO is defined. */
const char * const pcPollingSemaphoreTaskError = "Guarded shared variable in unexpected state.\r\n";
const char * const pcSemaphoreTaskStart = "Guarded shared variable task started.\r\n";
/*-----------------------------------------------------------*/
void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
{
xSemaphoreParameters * pxFirstSemaphoreParameters, * pxSecondSemaphoreParameters;
const TickType_t xBlockTime = ( TickType_t ) 100;
/* Create the structure used to pass parameters to the first two tasks. */
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxFirstSemaphoreParameters != NULL )
{
/* Create the semaphore used by the first two tasks. */
vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );
if( pxFirstSemaphoreParameters->xSemaphore != NULL )
{
/* Create the variable which is to be shared by the first two tasks. */
pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
/* Initialise the share variable to the value the tasks expect. */
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
/* The first two tasks do not block on semaphore calls. */
pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0;
/* Spawn the first two tasks. As they poll they operate at the idle priority. */
xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
}
}
/* Do exactly the same to create the second set of tasks, only this time
* provide a block time for the semaphore calls. */
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxSecondSemaphoreParameters != NULL )
{
vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
if( pxSecondSemaphoreParameters->xSemaphore != NULL )
{
pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS;
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
}
}
}
/*-----------------------------------------------------------*/
static void prvSemaphoreTest( void * pvParameters )
{
xSemaphoreParameters * pxParameters;
volatile unsigned long * pulSharedVariable, ulExpectedValue;
unsigned long ulCounter;
short sError = pdFALSE, sCheckVariableToUse;
/* See which check variable to use. sNextCheckVariable is not semaphore
* protected! */
portENTER_CRITICAL();
sCheckVariableToUse = sNextCheckVariable;
sNextCheckVariable++;
portEXIT_CRITICAL();
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcSemaphoreTaskStart );
/* A structure is passed in as the parameter. This contains the shared
* variable being guarded. */
pxParameters = ( xSemaphoreParameters * ) pvParameters;
pulSharedVariable = pxParameters->pulSharedVariable;
/* If we are blocking we use a much higher count to ensure loads of context
* switches occur during the count. */
if( pxParameters->xBlockTime > ( TickType_t ) 0 )
{
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
}
else
{
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
}
for( ; ; )
{
/* Try to obtain the semaphore. */
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
{
/* We have the semaphore and so expect any other tasks using the
* shared variable to have left it in the state we expect to find
* it. */
if( *pulSharedVariable != ulExpectedValue )
{
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
sError = pdTRUE;
}
/* Clear the variable, then count it back up to the expected value
* before releasing the semaphore. Would expect a context switch or
* two during this time. */
for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
{
*pulSharedVariable = ulCounter;
if( *pulSharedVariable != ulCounter )
{
if( sError == pdFALSE )
{
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
}
sError = pdTRUE;
}
}
/* Release the semaphore, and if no errors have occurred increment the check
* variable. */
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
{
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
if( sCheckVariableToUse < semtstNUM_TASKS )
{
( sCheckVariables[ sCheckVariableToUse ] )++;
}
}
/* If we have a block time then we are running at a priority higher
* than the idle priority. This task takes a long time to complete
* a cycle (deliberately so to test the guarding) so will be starving
* out lower priority tasks. Block for some time to allow give lower
* priority tasks some processor time. */
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
}
else
{
if( pxParameters->xBlockTime == ( TickType_t ) 0 )
{
/* We have not got the semaphore yet, so no point using the
* processor. We are not blocking when attempting to obtain the
* semaphore. */
taskYIELD();
}
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
BaseType_t xAreSemaphoreTasksStillRunning( void )
{
static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
portBASE_TYPE xTask, xReturn = pdTRUE;
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
{
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
{
xReturn = pdFALSE;
}
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
}
return xReturn;
}
/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/**
* Creates two sets of two tasks. The tasks within a set share a variable, access
* to which is guarded by a semaphore.
*
* Each task starts by attempting to obtain the semaphore. On obtaining a
* semaphore a task checks to ensure that the guarded variable has an expected
* value. It then clears the variable to zero before counting it back up to the
* expected value in increments of 1. After each increment the variable is checked
* to ensure it contains the value to which it was just set. When the starting
* value is again reached the task releases the semaphore giving the other task in
* the set a chance to do exactly the same thing. The starting value is high
* enough to ensure that a tick is likely to occur during the incrementing loop.
*
* An error is flagged if at any time during the process a shared variable is
* found to have a value other than that expected. Such an occurrence would
* suggest an error in the mutual exclusion mechanism by which access to the
* variable is restricted.
*
* The first set of two tasks poll their semaphore. The second set use blocking
* calls.
*
* \page SemTestC semtest.c
* \ingroup DemoFiles
* <HR>
*/
/*
* Changes from V1.2.0:
*
+ The tasks that operate at the idle priority now use a lower expected
+ count than those running at a higher priority. This prevents the low
+ priority tasks from signaling an error because they have not been
+ scheduled enough time for each of them to count the shared variable to
+ the high value.
+
+ Changes from V2.0.0
+
+ Delay periods are now specified using variables and constants of
+ TickType_t rather than unsigned long.
+
+ Changes from V2.1.1
+
+ The stack size now uses configMINIMAL_STACK_SIZE.
+ String constants made file scope to decrease stack depth on 8051 port.
*/
#include <stdlib.h>
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
/* Demo app include files. */
#include "semtest.h"
#include "print.h"
/* The value to which the shared variables are counted. */
#define semtstBLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xfff )
#define semtstNON_BLOCKING_EXPECTED_VALUE ( ( unsigned long ) 0xff )
#define semtstSTACK_SIZE configMINIMAL_STACK_SIZE
#define semtstNUM_TASKS ( 4 )
#define semtstDELAY_FACTOR ( ( TickType_t ) 10 )
/* The task function as described at the top of the file. */
static void prvSemaphoreTest( void * pvParameters );
/* Structure used to pass parameters to each task. */
typedef struct SEMAPHORE_PARAMETERS
{
SemaphoreHandle_t xSemaphore;
volatile unsigned long * pulSharedVariable;
TickType_t xBlockTime;
} xSemaphoreParameters;
/* Variables used to check that all the tasks are still running without errors. */
static volatile short sCheckVariables[ semtstNUM_TASKS ] = { 0 };
static volatile short sNextCheckVariable = 0;
/* Strings to print if USE_STDIO is defined. */
const char * const pcPollingSemaphoreTaskError = "Guarded shared variable in unexpected state.\r\n";
const char * const pcSemaphoreTaskStart = "Guarded shared variable task started.\r\n";
/*-----------------------------------------------------------*/
void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
{
xSemaphoreParameters * pxFirstSemaphoreParameters, * pxSecondSemaphoreParameters;
const TickType_t xBlockTime = ( TickType_t ) 100;
/* Create the structure used to pass parameters to the first two tasks. */
pxFirstSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxFirstSemaphoreParameters != NULL )
{
/* Create the semaphore used by the first two tasks. */
vSemaphoreCreateBinary( pxFirstSemaphoreParameters->xSemaphore );
if( pxFirstSemaphoreParameters->xSemaphore != NULL )
{
/* Create the variable which is to be shared by the first two tasks. */
pxFirstSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
/* Initialise the share variable to the value the tasks expect. */
*( pxFirstSemaphoreParameters->pulSharedVariable ) = semtstNON_BLOCKING_EXPECTED_VALUE;
/* The first two tasks do not block on semaphore calls. */
pxFirstSemaphoreParameters->xBlockTime = ( TickType_t ) 0;
/* Spawn the first two tasks. As they poll they operate at the idle priority. */
xTaskCreate( prvSemaphoreTest, "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
xTaskCreate( prvSemaphoreTest, "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( TaskHandle_t * ) NULL );
}
}
/* Do exactly the same to create the second set of tasks, only this time
* provide a block time for the semaphore calls. */
pxSecondSemaphoreParameters = ( xSemaphoreParameters * ) pvPortMalloc( sizeof( xSemaphoreParameters ) );
if( pxSecondSemaphoreParameters != NULL )
{
vSemaphoreCreateBinary( pxSecondSemaphoreParameters->xSemaphore );
if( pxSecondSemaphoreParameters->xSemaphore != NULL )
{
pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
*( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_PERIOD_MS;
xTaskCreate( prvSemaphoreTest, "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
xTaskCreate( prvSemaphoreTest, "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( TaskHandle_t * ) NULL );
}
}
}
/*-----------------------------------------------------------*/
static void prvSemaphoreTest( void * pvParameters )
{
xSemaphoreParameters * pxParameters;
volatile unsigned long * pulSharedVariable, ulExpectedValue;
unsigned long ulCounter;
short sError = pdFALSE, sCheckVariableToUse;
/* See which check variable to use. sNextCheckVariable is not semaphore
* protected! */
portENTER_CRITICAL();
sCheckVariableToUse = sNextCheckVariable;
sNextCheckVariable++;
portEXIT_CRITICAL();
/* Queue a message for printing to say the task has started. */
vPrintDisplayMessage( &pcSemaphoreTaskStart );
/* A structure is passed in as the parameter. This contains the shared
* variable being guarded. */
pxParameters = ( xSemaphoreParameters * ) pvParameters;
pulSharedVariable = pxParameters->pulSharedVariable;
/* If we are blocking we use a much higher count to ensure loads of context
* switches occur during the count. */
if( pxParameters->xBlockTime > ( TickType_t ) 0 )
{
ulExpectedValue = semtstBLOCKING_EXPECTED_VALUE;
}
else
{
ulExpectedValue = semtstNON_BLOCKING_EXPECTED_VALUE;
}
for( ; ; )
{
/* Try to obtain the semaphore. */
if( xSemaphoreTake( pxParameters->xSemaphore, pxParameters->xBlockTime ) == pdPASS )
{
/* We have the semaphore and so expect any other tasks using the
* shared variable to have left it in the state we expect to find
* it. */
if( *pulSharedVariable != ulExpectedValue )
{
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
sError = pdTRUE;
}
/* Clear the variable, then count it back up to the expected value
* before releasing the semaphore. Would expect a context switch or
* two during this time. */
for( ulCounter = ( unsigned long ) 0; ulCounter <= ulExpectedValue; ulCounter++ )
{
*pulSharedVariable = ulCounter;
if( *pulSharedVariable != ulCounter )
{
if( sError == pdFALSE )
{
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
}
sError = pdTRUE;
}
}
/* Release the semaphore, and if no errors have occurred increment the check
* variable. */
if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
{
vPrintDisplayMessage( &pcPollingSemaphoreTaskError );
sError = pdTRUE;
}
if( sError == pdFALSE )
{
if( sCheckVariableToUse < semtstNUM_TASKS )
{
( sCheckVariables[ sCheckVariableToUse ] )++;
}
}
/* If we have a block time then we are running at a priority higher
* than the idle priority. This task takes a long time to complete
* a cycle (deliberately so to test the guarding) so will be starving
* out lower priority tasks. Block for some time to allow give lower
* priority tasks some processor time. */
vTaskDelay( pxParameters->xBlockTime * semtstDELAY_FACTOR );
}
else
{
if( pxParameters->xBlockTime == ( TickType_t ) 0 )
{
/* We have not got the semaphore yet, so no point using the
* processor. We are not blocking when attempting to obtain the
* semaphore. */
taskYIELD();
}
}
}
}
/*-----------------------------------------------------------*/
/* This is called to check that all the created tasks are still running. */
BaseType_t xAreSemaphoreTasksStillRunning( void )
{
static short sLastCheckVariables[ semtstNUM_TASKS ] = { 0 };
portBASE_TYPE xTask, xReturn = pdTRUE;
for( xTask = 0; xTask < semtstNUM_TASKS; xTask++ )
{
if( sLastCheckVariables[ xTask ] == sCheckVariables[ xTask ] )
{
xReturn = pdFALSE;
}
sLastCheckVariables[ xTask ] = sCheckVariables[ xTask ];
}
return xReturn;
}