diff options
| author | Yuval Adam <yuv.adm@gmail.com> | 2014-08-08 14:42:07 +0300 |
|---|---|---|
| committer | Yuval Adam <yuv.adm@gmail.com> | 2014-08-08 14:42:07 +0300 |
| commit | a6163888f3c56123b1db313743c6147ba498732c (patch) | |
| tree | ff7d15d991d1d09ba6cbc0cec80924f57445bfdd /third_party/FreeRTOS/Demo/Common/Minimal | |
| parent | c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 (diff) | |
Add third_party libs
Diffstat (limited to 'third_party/FreeRTOS/Demo/Common/Minimal')
25 files changed, 9968 insertions, 0 deletions
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/AltBlckQ.c b/third_party/FreeRTOS/Demo/Common/Minimal/AltBlckQ.c new file mode 100644 index 0000000..aff7d32 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/AltBlckQ.c @@ -0,0 +1,332 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This is a version of BlockQ.c that uses the alternative (Alt) API.
+ *
+ * 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).
+ *
+ */
+
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* Demo program include files. */
+#include "AltBlckQ.h"
+
+#define blckqSTACK_SIZE configMINIMAL_STACK_SIZE
+#define blckqNUM_TASK_SETS ( 3 )
+
+/* Structure used to pass parameters to the blocking queue tasks. */
+typedef struct BLOCKING_QUEUE_PARAMETERS
+{
+ xQueueHandle xQueue; /*< The queue to be used by the task. */
+ portTickType xBlockTime; /*< The block time to use on queue reads/writes. */
+ volatile portSHORT *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 portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
+
+/* Task function that removes the incrementing number from a queue and checks that
+it is the expected number. */
+static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, 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 portSHORT sBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 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 portSHORT sBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
+
+/*-----------------------------------------------------------*/
+
+void vStartAltBlockingQueueTasks( unsigned portBASE_TYPE uxPriority )
+{
+xBlockingQueueParameters *pxQueueParameters1, *pxQueueParameters2;
+xBlockingQueueParameters *pxQueueParameters3, *pxQueueParameters4;
+xBlockingQueueParameters *pxQueueParameters5, *pxQueueParameters6;
+const unsigned portBASE_TYPE uxQueueSize1 = 1, uxQueueSize5 = 5;
+const portTickType xBlockTime = ( portTickType ) 1000 / portTICK_RATE_MS;
+const portTickType xDontBlock = ( portTickType ) 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 portSHORT ) );
+
+ /* 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, ( signed portCHAR * ) "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
+ xTaskCreate( vBlockingQueueProducer, ( signed portCHAR * ) "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 portSHORT ) );
+ pxQueueParameters3->xBlockTime = xDontBlock;
+ pxQueueParameters3->psCheckVariable = &( sBlockingProducerCount[ 1 ] );
+
+ pxQueueParameters4 = ( xBlockingQueueParameters * ) pvPortMalloc( sizeof( xBlockingQueueParameters ) );
+ pxQueueParameters4->xQueue = pxQueueParameters3->xQueue;
+ pxQueueParameters4->xBlockTime = xBlockTime;
+ pxQueueParameters4->psCheckVariable = &( sBlockingConsumerCount[ 1 ] );
+
+ xTaskCreate( vBlockingQueueConsumer, ( signed portCHAR * ) "QProdB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
+ xTaskCreate( vBlockingQueueProducer, ( signed portCHAR * ) "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 portSHORT ) );
+ 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, ( signed portCHAR * ) "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
+ xTaskCreate( vBlockingQueueConsumer, ( signed portCHAR * ) "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )
+{
+unsigned portSHORT usValue = 0;
+xBlockingQueueParameters *pxQueueParameters;
+portSHORT sErrorEverOccurred = pdFALSE;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Alt blocking queue producer task started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
+
+ for( ;; )
+ {
+ if( xQueueAltSendToBack( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
+ {
+ 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 portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
+{
+unsigned portSHORT usData, usExpectedValue = 0;
+xBlockingQueueParameters *pxQueueParameters;
+portSHORT sErrorEverOccurred = pdFALSE;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Alt blocking queue consumer task started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
+
+ for( ;; )
+ {
+ if( xQueueAltReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
+ {
+ if( usData != usExpectedValue )
+ {
+ /* 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 xAreAltBlockingQueuesStillRunning( void )
+{
+static portSHORT sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0 };
+static portSHORT sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 0, ( unsigned portSHORT ) 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 to 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;
+}
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/AltBlock.c b/third_party/FreeRTOS/Demo/Common/Minimal/AltBlock.c new file mode 100644 index 0000000..93c8472 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/AltBlock.c @@ -0,0 +1,549 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This is a version of BlockTim.c that uses the light weight API.
+ *
+ * This file contains some test scenarios that ensure tasks do not exit queue
+ * send or receive functions prematurely. A description of the tests is
+ * included within the code.
+ */
+
+/* Kernel includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* Demo includes. */
+#include "AltBlock.h"
+
+/* Task priorities. */
+#define bktPRIMARY_PRIORITY ( 3 )
+#define bktSECONDARY_PRIORITY ( 2 )
+
+/* Task behaviour. */
+#define bktQUEUE_LENGTH ( 5 )
+#define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
+#define bktPRIMARY_BLOCK_TIME ( 10 )
+#define bktALLOWABLE_MARGIN ( 12 )
+#define bktTIME_TO_BLOCK ( 175 )
+#define bktDONT_BLOCK ( ( portTickType ) 0 )
+#define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
+
+/* The queue on which the tasks block. */
+static xQueueHandle xTestQueue;
+
+/* Handle to the secondary task is required by the primary task for calls
+to vTaskSuspend/Resume(). */
+static xTaskHandle xSecondary;
+
+/* Used to ensure that tasks are still executing without error. */
+static portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
+static portBASE_TYPE xErrorOccurred = pdFALSE;
+
+/* Provides a simple mechanism for the primary task to know when the
+secondary task has executed. */
+static volatile unsigned portBASE_TYPE xRunIndicator;
+
+/* The two test tasks. Their behaviour is commented within the files. */
+static void vPrimaryBlockTimeTestTask( void *pvParameters );
+static void vSecondaryBlockTimeTestTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+void vCreateAltBlockTimeTasks( void )
+{
+ /* Create the queue on which the two tasks block. */
+ xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xTestQueue, ( signed portCHAR * ) "AltBlockQueue" );
+
+
+ /* Create the two test tasks. */
+ xTaskCreate( vPrimaryBlockTimeTestTask, ( signed portCHAR * )"FBTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
+ xTaskCreate( vSecondaryBlockTimeTestTask, ( signed portCHAR * )"FBTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
+}
+/*-----------------------------------------------------------*/
+
+static void vPrimaryBlockTimeTestTask( void *pvParameters )
+{
+portBASE_TYPE xItem, xData;
+portTickType xTimeWhenBlocking;
+portTickType xTimeToBlock, xBlockedTime;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Alt primary block time test started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /*********************************************************************
+ Test 1
+
+ Simple block time wakeup test on queue receives. */
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ /* The queue is empty. Attempt to read from the queue using a block
+ time. When we wake, ensure the delta in time is as expected. */
+ xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
+
+ /* A critical section is used to minimise the jitter in the time
+ measurements. */
+ portENTER_CRITICAL();
+ {
+ xTimeWhenBlocking = xTaskGetTickCount();
+
+ /* We should unblock after xTimeToBlock having not received
+ anything on the queue. */
+ if( xQueueAltReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* How long were we blocked for? */
+ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
+ }
+ portEXIT_CRITICAL();
+
+ if( xBlockedTime < xTimeToBlock )
+ {
+ /* Should not have blocked for less than we requested. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
+ {
+ /* Should not have blocked for longer than we requested,
+ although we would not necessarily run as soon as we were
+ unblocked so a margin is allowed. */
+ xErrorOccurred = pdTRUE;
+ }
+ }
+
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+
+ /*********************************************************************
+ Test 2
+
+ Simple block time wakeup test on queue sends.
+
+ First fill the queue. It should be empty so all sends should pass. */
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+ }
+
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ /* The queue is full. Attempt to write to the queue using a block
+ time. When we wake, ensure the delta in time is as expected. */
+ xTimeToBlock = bktPRIMARY_BLOCK_TIME << xItem;
+
+ portENTER_CRITICAL();
+ {
+ xTimeWhenBlocking = xTaskGetTickCount();
+
+ /* We should unblock after xTimeToBlock having not received
+ anything on the queue. */
+ if( xQueueAltSendToBack( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* How long were we blocked for? */
+ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
+ }
+ portEXIT_CRITICAL();
+
+ if( xBlockedTime < xTimeToBlock )
+ {
+ /* Should not have blocked for less than we requested. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
+ {
+ /* Should not have blocked for longer than we requested,
+ although we would not necessarily run as soon as we were
+ unblocked so a margin is allowed. */
+ xErrorOccurred = pdTRUE;
+ }
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+
+ /*********************************************************************
+ Test 3
+
+ Wake the other task, it will block attempting to post to the queue.
+ When we read from the queue the other task will wake, but before it
+ can run we will post to the queue again. When the other task runs it
+ will find the queue still full, even though it was woken. It should
+ recognise that its block time has not expired and return to block for
+ the remains of its block time.
+
+ Wake the other task so it blocks attempting to post to the already
+ full queue. */
+ xRunIndicator = 0;
+ vTaskResume( xSecondary );
+
+ /* We need to wait a little to ensure the other task executes. */
+ while( xRunIndicator != bktRUN_INDICATOR )
+ {
+ /* The other task has not yet executed. */
+ vTaskDelay( bktSHORT_WAIT );
+ }
+ /* Make sure the other task is blocked on the queue. */
+ vTaskDelay( bktSHORT_WAIT );
+ xRunIndicator = 0;
+
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ /* Now when we make space on the queue the other task should wake
+ but not execute as this task has higher priority. */
+ if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Now fill the queue again before the other task gets a chance to
+ execute. If the other task had executed we would find the queue
+ full ourselves, and the other task have set xRunIndicator. */
+ if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ if( xRunIndicator == bktRUN_INDICATOR )
+ {
+ /* The other task should not have executed. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Raise the priority of the other task so it executes and blocks
+ on the queue again. */
+ vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
+
+ /* The other task should now have re-blocked without exiting the
+ queue function. */
+ if( xRunIndicator == bktRUN_INDICATOR )
+ {
+ /* The other task should not have executed outside of the
+ queue function. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Set the priority back down. */
+ vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
+ }
+
+ /* Let the other task timeout. When it unblockes it will check that it
+ unblocked at the correct time, then suspend itself. */
+ while( xRunIndicator != bktRUN_INDICATOR )
+ {
+ vTaskDelay( bktSHORT_WAIT );
+ }
+ vTaskDelay( bktSHORT_WAIT );
+ xRunIndicator = 0;
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /*********************************************************************
+ Test 4
+
+ As per test 3 - but with the send and receive the other way around.
+ The other task blocks attempting to read from the queue.
+
+ Empty the queue. We should find that it is full. */
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+ }
+
+ /* Wake the other task so it blocks attempting to read from the
+ already empty queue. */
+ vTaskResume( xSecondary );
+
+ /* We need to wait a little to ensure the other task executes. */
+ while( xRunIndicator != bktRUN_INDICATOR )
+ {
+ vTaskDelay( bktSHORT_WAIT );
+ }
+ vTaskDelay( bktSHORT_WAIT );
+ xRunIndicator = 0;
+
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ /* Now when we place an item on the queue the other task should
+ wake but not execute as this task has higher priority. */
+ if( xQueueAltSendToBack( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Now empty the queue again before the other task gets a chance to
+ execute. If the other task had executed we would find the queue
+ empty ourselves, and the other task would be suspended. */
+ if( xQueueAltReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ if( xRunIndicator == bktRUN_INDICATOR )
+ {
+ /* The other task should not have executed. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Raise the priority of the other task so it executes and blocks
+ on the queue again. */
+ vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
+
+ /* The other task should now have re-blocked without exiting the
+ queue function. */
+ if( xRunIndicator == bktRUN_INDICATOR )
+ {
+ /* The other task should not have executed outside of the
+ queue function. */
+ xErrorOccurred = pdTRUE;
+ }
+ vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
+ }
+
+ /* Let the other task timeout. When it unblockes it will check that it
+ unblocked at the correct time, then suspend itself. */
+ while( xRunIndicator != bktRUN_INDICATOR )
+ {
+ vTaskDelay( bktSHORT_WAIT );
+ }
+ vTaskDelay( bktSHORT_WAIT );
+
+ xPrimaryCycles++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void vSecondaryBlockTimeTestTask( void *pvParameters )
+{
+portTickType xTimeWhenBlocking, xBlockedTime;
+portBASE_TYPE xData;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Alt secondary block time test started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /*********************************************************************
+ Test 1 and 2
+
+ This task does does not participate in these tests. */
+ vTaskSuspend( NULL );
+
+ /*********************************************************************
+ Test 3
+
+ The first thing we do is attempt to read from the queue. It should be
+ full so we block. Note the time before we block so we can check the
+ wake time is as per that expected. */
+ portENTER_CRITICAL();
+ {
+ xTimeWhenBlocking = xTaskGetTickCount();
+
+ /* We should unblock after bktTIME_TO_BLOCK having not received
+ anything on the queue. */
+ xData = 0;
+ xRunIndicator = bktRUN_INDICATOR;
+ if( xQueueAltSendToBack( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* How long were we inside the send function? */
+ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
+ }
+ portEXIT_CRITICAL();
+
+ /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
+ if( xBlockedTime < bktTIME_TO_BLOCK )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
+ either. A margin is permitted as we would not necessarily run as
+ soon as we unblocked. */
+ if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Suspend ready for test 3. */
+ xRunIndicator = bktRUN_INDICATOR;
+ vTaskSuspend( NULL );
+
+ /*********************************************************************
+ Test 4
+
+ As per test three, but with the send and receive reversed. */
+ portENTER_CRITICAL();
+ {
+ xTimeWhenBlocking = xTaskGetTickCount();
+
+ /* We should unblock after bktTIME_TO_BLOCK having not received
+ anything on the queue. */
+ xRunIndicator = bktRUN_INDICATOR;
+ if( xQueueAltReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
+ }
+ portEXIT_CRITICAL();
+
+ /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
+ if( xBlockedTime < bktTIME_TO_BLOCK )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
+ either. A margin is permitted as we would not necessarily run as soon
+ as we unblocked. */
+ if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ xRunIndicator = bktRUN_INDICATOR;
+
+ xSecondaryCycles++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xAreAltBlockTimeTestTasksStillRunning( void )
+{
+static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
+portBASE_TYPE xReturn = pdPASS;
+
+ /* Have both tasks performed at least one cycle since this function was
+ last called? */
+ if( xPrimaryCycles == xLastPrimaryCycleCount )
+ {
+ xReturn = pdFAIL;
+ }
+
+ if( xSecondaryCycles == xLastSecondaryCycleCount )
+ {
+ xReturn = pdFAIL;
+ }
+
+ if( xErrorOccurred == pdTRUE )
+ {
+ xReturn = pdFAIL;
+ }
+
+ xLastSecondaryCycleCount = xSecondaryCycles;
+ xLastPrimaryCycleCount = xPrimaryCycles;
+
+ return xReturn;
+}
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/AltPollQ.c b/third_party/FreeRTOS/Demo/Common/Minimal/AltPollQ.c new file mode 100644 index 0000000..25949ea --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/AltPollQ.c @@ -0,0 +1,275 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This is a version of PollQ.c that uses the alternative (Alt) API.
+ *
+ * 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.
+ */
+
+/*
+Changes from V2.0.0
+
+ + Delay periods are now specified using variables and constants of
+ portTickType rather than unsigned portLONG.
+*/
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* Demo program include files. */
+#include "AltPollQ.h"
+
+#define pollqSTACK_SIZE configMINIMAL_STACK_SIZE
+#define pollqQUEUE_SIZE ( 10 )
+#define pollqPRODUCER_DELAY ( ( portTickType ) 200 / portTICK_RATE_MS )
+#define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( portTickType ) ( 20 / portTICK_RATE_MS ) )
+#define pollqNO_DELAY ( ( portTickType ) 0 )
+#define pollqVALUES_TO_PRODUCE ( ( signed portBASE_TYPE ) 3 )
+#define pollqINITIAL_VALUE ( ( signed portBASE_TYPE ) 0 )
+
+/* The task that posts the incrementing number onto the queue. */
+static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
+
+/* The task that empties the queue. */
+static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );
+
+/* Variables that are used to check that the tasks are still running with no
+errors. */
+static volatile signed portBASE_TYPE xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;
+
+/*-----------------------------------------------------------*/
+
+void vStartAltPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
+{
+static xQueueHandle xPolledQueue;
+
+ /* Create the queue used by the producer and consumer. */
+ xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( unsigned portBASE_TYPE ) sizeof( unsigned portSHORT ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xPolledQueue, ( signed portCHAR * ) "AltPollQueue" );
+
+
+ /* Spawn the producer and consumer. */
+ xTaskCreate( vPolledQueueConsumer, ( signed portCHAR * ) "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );
+ xTaskCreate( vPolledQueueProducer, ( signed portCHAR * ) "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vPolledQueueProducer, pvParameters )
+{
+unsigned portSHORT usValue = ( unsigned portSHORT ) 0;
+signed portBASE_TYPE xError = pdFALSE, xLoop;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Alt polling queue producer task started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ for( ;; )
+ {
+ for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ )
+ {
+ /* Send an incrementing number on the queue without blocking. */
+ if( xQueueAltSendToBack( *( ( xQueueHandle * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )
+ {
+ /* We should never find the queue full so if we get here there
+ has been an error. */
+ xError = pdTRUE;
+ }
+ else
+ {
+ if( xError == pdFALSE )
+ {
+ /* If an error has ever been recorded we stop incrementing the
+ check variable. */
+ portENTER_CRITICAL();
+ xPollingProducerCount++;
+ portEXIT_CRITICAL();
+ }
+
+ /* 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( pollqPRODUCER_DELAY );
+ }
+} /*lint !e818 Function prototype must conform to API. */
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters )
+{
+unsigned portSHORT usData, usExpectedValue = ( unsigned portSHORT ) 0;
+signed portBASE_TYPE xError = pdFALSE;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Alt blocking queue consumer task started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ for( ;; )
+ {
+ /* Loop until the queue is empty. */
+ while( uxQueueMessagesWaiting( *( ( xQueueHandle * ) pvParameters ) ) )
+ {
+ if( xQueueAltReceive( *( ( xQueueHandle * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS )
+ {
+ if( usData != usExpectedValue )
+ {
+ /* This is not what we expected to receive so an error has
+ occurred. */
+ xError = pdTRUE;
+
+ /* Catch-up to the value we received so our next expected
+ value should again be correct. */
+ usExpectedValue = usData;
+ }
+ else
+ {
+ if( xError == pdFALSE )
+ {
+ /* Only increment the check variable if no errors have
+ occurred. */
+ portENTER_CRITICAL();
+ xPollingConsumerCount++;
+ portEXIT_CRITICAL();
+ }
+ }
+
+ /* Next time round we would expect the number to be one higher. */
+ usExpectedValue++;
+ }
+ }
+
+ /* Now the queue is empty we block, allowing the producer to place more
+ items in the queue. */
+ vTaskDelay( pollqCONSUMER_DELAY );
+ }
+} /*lint !e818 Function prototype must conform to API. */
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running with no errors. */
+portBASE_TYPE xAreAltPollingQueuesStillRunning( void )
+{
+portBASE_TYPE xReturn;
+
+ /* Check both the consumer and producer poll count to check they have both
+ been changed since out last trip round. We do not need a critical section
+ around the check variables as this is called from a higher priority than
+ the other tasks that access the same variables. */
+ if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||
+ ( xPollingProducerCount == pollqINITIAL_VALUE )
+ )
+ {
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+
+ /* Set the check variables back down so we know if they have been
+ incremented the next time around. */
+ xPollingConsumerCount = pollqINITIAL_VALUE;
+ xPollingProducerCount = pollqINITIAL_VALUE;
+
+ return xReturn;
+}
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/AltQTest.c b/third_party/FreeRTOS/Demo/Common/Minimal/AltQTest.c new file mode 100644 index 0000000..9710336 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/AltQTest.c @@ -0,0 +1,587 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+
+/*
+ * This file implements the same demo and test as GenQTest.c, but uses the
+ * light weight API in place of the fully featured API.
+ *
+ * See the comments at the top of GenQTest.c for a description.
+ */
+
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* Demo program include files. */
+#include "AltQTest.h"
+
+#define genqQUEUE_LENGTH ( 5 )
+#define genqNO_BLOCK ( 0 )
+
+#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
+#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
+#define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
+#define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Tests the behaviour of the xQueueAltSendToFront() and xQueueAltSendToBack()
+ * macros by using both to fill a queue, then reading from the queue to
+ * check the resultant queue order is as expected. Queue data is also
+ * peeked.
+ */
+static void prvSendFrontAndBackTest( void *pvParameters );
+
+/*
+ * The following three tasks are used to demonstrate the mutex behaviour.
+ * Each task is given a different priority to demonstrate the priority
+ * inheritance mechanism.
+ *
+ * The low priority task obtains a mutex. After this a high priority task
+ * attempts to obtain the same mutex, causing its priority to be inherited
+ * by the low priority task. The task with the inherited high priority then
+ * resumes a medium priority task to ensure it is not blocked by the medium
+ * priority task while it holds the inherited high priority. Once the mutex
+ * is returned the task with the inherited priority returns to its original
+ * low priority, and is therefore immediately preempted by first the high
+ * priority task and then the medium prioroity task before it can continue.
+ */
+static void prvLowPriorityMutexTask( void *pvParameters );
+static void prvMediumPriorityMutexTask( void *pvParameters );
+static void prvHighPriorityMutexTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+/* Flag that will be latched to pdTRUE should any unexpected behaviour be
+detected in any of the tasks. */
+static portBASE_TYPE xErrorDetected = pdFALSE;
+
+/* Counters that are incremented on each cycle of a test. This is used to
+detect a stalled task - a test that is no longer running. */
+static volatile unsigned portLONG ulLoopCounter = 0;
+static volatile unsigned portLONG ulLoopCounter2 = 0;
+
+/* The variable that is guarded by the mutex in the mutex demo tasks. */
+static volatile unsigned portLONG ulGuardedVariable = 0;
+
+/* Handles used in the mutext test to suspend and resume the high and medium
+priority mutex test tasks. */
+static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
+
+/*-----------------------------------------------------------*/
+
+void vStartAltGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
+{
+xQueueHandle xQueue;
+xSemaphoreHandle xMutex;
+
+ /* Create the queue that we are going to use for the
+ prvSendFrontAndBackTest demo. */
+ xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Alt_Gen_Test_Queue" );
+
+ /* Create the demo task and pass it the queue just created. We are
+ passing the queue handle by value so it does not matter that it is
+ declared on the stack here. */
+ xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * ) "FGenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
+
+ /* Create the mutex used by the prvMutexTest task. */
+ xMutex = xSemaphoreCreateMutex();
+
+ /* vQueueAddToRegistry() adds the mutex to the registry, if one is
+ in use. The registry is provided as a means for kernel aware
+ debuggers to locate mutex and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Alt_Q_Mutex" );
+
+ /* Create the mutex demo tasks and pass it the mutex just created. We are
+ passing the mutex handle by value so it does not matter that it is declared
+ on the stack here. */
+ xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * ) "FMuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
+ xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * ) "FMuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
+ xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * ) "FMuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
+}
+/*-----------------------------------------------------------*/
+
+static void prvSendFrontAndBackTest( void *pvParameters )
+{
+unsigned portLONG ulData, ulData2;
+xQueueHandle xQueue;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Alt queue SendToFront/SendToBack/Peek test started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ xQueue = ( xQueueHandle ) pvParameters;
+
+ for( ;; )
+ {
+ /* The queue is empty, so sending an item to the back of the queue
+ should have the same efect as sending it to the front of the queue.
+
+ First send to the front and check everything is as expected. */
+ xQueueAltSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
+
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* The data we sent to the queue should equal the data we just received
+ from the queue. */
+ if( ulLoopCounter != ulData )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Then do the same, sending the data to the back, checking everything
+ is as expected. */
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ xQueueAltSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
+
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueAltReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* The data we sent to the queue should equal the data we just received
+ from the queue. */
+ if( ulLoopCounter != ulData )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+
+
+ /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
+ for( ulData = 2; ulData < 5; ulData++ )
+ {
+ xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
+ }
+
+ /* Now the order in the queue should be 2, 3, 4, with 2 being the first
+ thing to be read out. Now add 1 then 0 to the front of the queue. */
+ if( uxQueueMessagesWaiting( xQueue ) != 3 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ ulData = 1;
+ xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
+ ulData = 0;
+ xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
+
+ /* Now the queue should be full, and when we read the data out we
+ should receive 0, 1, 2, 3, 4. */
+ if( uxQueueMessagesWaiting( xQueue ) != 5 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* Check the data we read out is in the expected order. */
+ for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
+ {
+ /* Try peeking the data first. */
+ if( xQueueAltPeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulData != ulData2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+
+ /* Now try receiving the data for real. The value should be the
+ same. Clobber the value first so we know we really received it. */
+ ulData2 = ~ulData2;
+ if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulData != ulData2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ }
+
+ /* The queue should now be empty again. */
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+
+ /* Our queue is empty once more, add 10, 11 to the back. */
+ ulData = 10;
+ if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ ulData = 11;
+ if( xQueueAltSendToBack( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
+ front. */
+ for( ulData = 9; ulData >= 7; ulData-- )
+ {
+ if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ }
+
+ /* Now check that the queue is full, and that receiving data provides
+ the expected sequence of 7, 8, 9, 10, 11. */
+ if( uxQueueMessagesWaiting( xQueue ) != 5 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueAltSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueAltSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* Check the data we read out is in the expected order. */
+ for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
+ {
+ if( xQueueAltReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulData != ulData2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ ulLoopCounter++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvLowPriorityMutexTask( void *pvParameters )
+{
+xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Fast mutex with priority inheritance test started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ ( void ) pvParameters;
+
+
+ for( ;; )
+ {
+ /* Take the mutex. It should be available now. */
+ if( xSemaphoreAltTake( xMutex, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Set our guarded variable to a known start value. */
+ ulGuardedVariable = 0;
+
+ /* Our priority should be as per that assigned when the task was
+ created. */
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Now unsuspend the high priority task. This will attempt to take the
+ mutex, and block when it finds it cannot obtain it. */
+ vTaskResume( xHighPriorityMutexTask );
+
+ /* We should now have inherited the prioritoy of the high priority task,
+ as by now it will have attempted to get the mutex. */
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* We can attempt to set our priority to the test priority - between the
+ idle priority and the medium/high test priorities, but our actual
+ prioroity should remain at the high priority. */
+ vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Now unsuspend the medium priority task. This should not run as our
+ inherited priority is above that of the medium priority task. */
+ vTaskResume( xMediumPriorityMutexTask );
+
+ /* If the did run then it will have incremented our guarded variable. */
+ if( ulGuardedVariable != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* When we give back the semaphore our priority should be disinherited
+ back to the priority to which we attempted to set ourselves. This means
+ that when the high priority task next blocks, the medium priority task
+ should execute and increment the guarded variable. When we next run
+ both the high and medium priority tasks will have been suspended again. */
+ if( xSemaphoreAltGive( xMutex ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Check that the guarded variable did indeed increment... */
+ if( ulGuardedVariable != 1 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* ... and that our priority has been disinherited to
+ genqMUTEX_TEST_PRIORITY. */
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Set our priority back to our original priority ready for the next
+ loop around this test. */
+ vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
+
+ /* Just to show we are still running. */
+ ulLoopCounter2++;
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvMediumPriorityMutexTask( void *pvParameters )
+{
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* The medium priority task starts by suspending itself. The low
+ priority task will unsuspend this task when required. */
+ vTaskSuspend( NULL );
+
+ /* When this task unsuspends all it does is increment the guarded
+ variable, this is so the low priority task knows that it has
+ executed. */
+ ulGuardedVariable++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvHighPriorityMutexTask( void *pvParameters )
+{
+xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
+
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* The high priority task starts by suspending itself. The low
+ priority task will unsuspend this task when required. */
+ vTaskSuspend( NULL );
+
+ /* When this task unsuspends all it does is attempt to obtain
+ the mutex. It should find the mutex is not available so a
+ block time is specified. */
+ if( xSemaphoreAltTake( xMutex, portMAX_DELAY ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* When we eventually obtain the mutex we just give it back then
+ return to suspend ready for the next test. */
+ if( xSemaphoreAltGive( xMutex ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running. */
+portBASE_TYPE xAreAltGenericQueueTasksStillRunning( void )
+{
+static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
+
+ /* If the demo task is still running then we expect the loopcounters to
+ have incremented since this function was last called. */
+ if( ulLastLoopCounter == ulLoopCounter )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulLastLoopCounter2 == ulLoopCounter2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ ulLastLoopCounter = ulLoopCounter;
+ ulLastLoopCounter2 = ulLoopCounter2;
+
+ /* Errors detected in the task itself will have latched xErrorDetected
+ to true. */
+
+ return !xErrorDetected;
+}
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/BlockQ.c b/third_party/FreeRTOS/Demo/Common/Minimal/BlockQ.c new file mode 100644 index 0000000..be19050 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/BlockQ.c @@ -0,0 +1,324 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * 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).
+ *
+ */
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* Demo program include files. */
+#include "BlockQ.h"
+
+#define blckqSTACK_SIZE configMINIMAL_STACK_SIZE
+#define blckqNUM_TASK_SETS ( 3 )
+
+/* Structure used to pass parameters to the blocking queue tasks. */
+typedef struct BLOCKING_QUEUE_PARAMETERS
+{
+ xQueueHandle xQueue; /*< The queue to be used by the task. */
+ portTickType 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 portTASK_FUNCTION_PROTO( vBlockingQueueProducer, pvParameters );
+
+/* Task function that removes the incrementing number from a queue and checks that
+it is the expected number. */
+static portTASK_FUNCTION_PROTO( vBlockingQueueConsumer, 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 ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned 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 ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned 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 portTickType xBlockTime = ( portTickType ) 1000 / portTICK_RATE_MS;
+const portTickType xDontBlock = ( portTickType ) 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, ( signed char * ) "QConsB1", blckqSTACK_SIZE, ( void * ) pxQueueParameters1, uxPriority, NULL );
+ xTaskCreate( vBlockingQueueProducer, ( signed char * ) "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( vBlockingQueueConsumer, ( signed char * ) "QConsB3", blckqSTACK_SIZE, ( void * ) pxQueueParameters3, tskIDLE_PRIORITY, NULL );
+ xTaskCreate( vBlockingQueueProducer, ( signed char * ) "QProdB4", 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, ( signed char * ) "QProdB5", blckqSTACK_SIZE, ( void * ) pxQueueParameters5, tskIDLE_PRIORITY, NULL );
+ xTaskCreate( vBlockingQueueConsumer, ( signed char * ) "QConsB6", blckqSTACK_SIZE, ( void * ) pxQueueParameters6, tskIDLE_PRIORITY, NULL );
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vBlockingQueueProducer, pvParameters )
+{
+unsigned short usValue = 0;
+xBlockingQueueParameters *pxQueueParameters;
+short sErrorEverOccurred = pdFALSE;
+
+ pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
+
+ for( ;; )
+ {
+ if( xQueueSend( pxQueueParameters->xQueue, ( void * ) &usValue, pxQueueParameters->xBlockTime ) != pdPASS )
+ {
+ 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;
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vBlockingQueueConsumer, pvParameters )
+{
+unsigned short usData, usExpectedValue = 0;
+xBlockingQueueParameters *pxQueueParameters;
+short sErrorEverOccurred = pdFALSE;
+
+ pxQueueParameters = ( xBlockingQueueParameters * ) pvParameters;
+
+ for( ;; )
+ {
+ if( xQueueReceive( pxQueueParameters->xQueue, &usData, pxQueueParameters->xBlockTime ) == pdPASS )
+ {
+ if( usData != usExpectedValue )
+ {
+ /* 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;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ {
+ if( pxQueueParameters->xBlockTime == 0 )
+ {
+ taskYIELD();
+ }
+ }
+ #endif
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running. */
+portBASE_TYPE xAreBlockingQueuesStillRunning( void )
+{
+static short sLastBlockingConsumerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned short ) 0 };
+static short sLastBlockingProducerCount[ blckqNUM_TASK_SETS ] = { ( unsigned short ) 0, ( unsigned short ) 0, ( unsigned 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 to 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;
+}
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/GenQTest.c b/third_party/FreeRTOS/Demo/Common/Minimal/GenQTest.c new file mode 100644 index 0000000..90dac35 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/GenQTest.c @@ -0,0 +1,600 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+
+/*
+ * Tests the extra queue functionality introduced in FreeRTOS.org V4.5.0 -
+ * including xQueueSendToFront(), xQueueSendToBack(), xQueuePeek() and
+ * mutex behaviour.
+ *
+ * See the comments above the prvSendFrontAndBackTest() and
+ * prvLowPriorityMutexTask() prototypes below for more information.
+ */
+
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* Demo program include files. */
+#include "GenQTest.h"
+
+#define genqQUEUE_LENGTH ( 5 )
+#define genqNO_BLOCK ( 0 )
+
+#define genqMUTEX_LOW_PRIORITY ( tskIDLE_PRIORITY )
+#define genqMUTEX_TEST_PRIORITY ( tskIDLE_PRIORITY + 1 )
+#define genqMUTEX_MEDIUM_PRIORITY ( tskIDLE_PRIORITY + 2 )
+#define genqMUTEX_HIGH_PRIORITY ( tskIDLE_PRIORITY + 3 )
+
+/*-----------------------------------------------------------*/
+
+/*
+ * Tests the behaviour of the xQueueSendToFront() and xQueueSendToBack()
+ * macros by using both to fill a queue, then reading from the queue to
+ * check the resultant queue order is as expected. Queue data is also
+ * peeked.
+ */
+static void prvSendFrontAndBackTest( void *pvParameters );
+
+/*
+ * The following three tasks are used to demonstrate the mutex behaviour.
+ * Each task is given a different priority to demonstrate the priority
+ * inheritance mechanism.
+ *
+ * The low priority task obtains a mutex. After this a high priority task
+ * attempts to obtain the same mutex, causing its priority to be inherited
+ * by the low priority task. The task with the inherited high priority then
+ * resumes a medium priority task to ensure it is not blocked by the medium
+ * priority task while it holds the inherited high priority. Once the mutex
+ * is returned the task with the inherited priority returns to its original
+ * low priority, and is therefore immediately preempted by first the high
+ * priority task and then the medium prioroity task before it can continue.
+ */
+static void prvLowPriorityMutexTask( void *pvParameters );
+static void prvMediumPriorityMutexTask( void *pvParameters );
+static void prvHighPriorityMutexTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+/* Flag that will be latched to pdTRUE should any unexpected behaviour be
+detected in any of the tasks. */
+static volatile portBASE_TYPE xErrorDetected = pdFALSE;
+
+/* Counters that are incremented on each cycle of a test. This is used to
+detect a stalled task - a test that is no longer running. */
+static volatile unsigned portLONG ulLoopCounter = 0;
+static volatile unsigned portLONG ulLoopCounter2 = 0;
+
+/* The variable that is guarded by the mutex in the mutex demo tasks. */
+static volatile unsigned portLONG ulGuardedVariable = 0;
+
+/* Handles used in the mutext test to suspend and resume the high and medium
+priority mutex test tasks. */
+static xTaskHandle xHighPriorityMutexTask, xMediumPriorityMutexTask;
+
+/*-----------------------------------------------------------*/
+
+void vStartGenericQueueTasks( unsigned portBASE_TYPE uxPriority )
+{
+xQueueHandle xQueue;
+xSemaphoreHandle xMutex;
+
+ /* Create the queue that we are going to use for the
+ prvSendFrontAndBackTest demo. */
+ xQueue = xQueueCreate( genqQUEUE_LENGTH, sizeof( unsigned portLONG ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "Gen_Queue_Test" );
+
+ /* Create the demo task and pass it the queue just created. We are
+ passing the queue handle by value so it does not matter that it is
+ declared on the stack here. */
+ xTaskCreate( prvSendFrontAndBackTest, ( signed portCHAR * )"GenQ", configMINIMAL_STACK_SIZE, ( void * ) xQueue, uxPriority, NULL );
+
+ /* Create the mutex used by the prvMutexTest task. */
+ xMutex = xSemaphoreCreateMutex();
+
+ /* vQueueAddToRegistry() adds the mutex to the registry, if one is
+ in use. The registry is provided as a means for kernel aware
+ debuggers to locate mutexes and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Gen_Queue_Mutex" );
+
+ /* Create the mutex demo tasks and pass it the mutex just created. We are
+ passing the mutex handle by value so it does not matter that it is declared
+ on the stack here. */
+ xTaskCreate( prvLowPriorityMutexTask, ( signed portCHAR * )"MuLow", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_LOW_PRIORITY, NULL );
+ xTaskCreate( prvMediumPriorityMutexTask, ( signed portCHAR * )"MuMed", configMINIMAL_STACK_SIZE, NULL, genqMUTEX_MEDIUM_PRIORITY, &xMediumPriorityMutexTask );
+ xTaskCreate( prvHighPriorityMutexTask, ( signed portCHAR * )"MuHigh", configMINIMAL_STACK_SIZE, ( void * ) xMutex, genqMUTEX_HIGH_PRIORITY, &xHighPriorityMutexTask );
+}
+/*-----------------------------------------------------------*/
+
+static void prvSendFrontAndBackTest( void *pvParameters )
+{
+unsigned portLONG ulData, ulData2;
+xQueueHandle xQueue;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Queue SendToFront/SendToBack/Peek test started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ xQueue = ( xQueueHandle ) pvParameters;
+
+ for( ;; )
+ {
+ /* The queue is empty, so sending an item to the back of the queue
+ should have the same efect as sending it to the front of the queue.
+
+ First send to the front and check everything is as expected. */
+ xQueueSendToFront( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
+
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* The data we sent to the queue should equal the data we just received
+ from the queue. */
+ if( ulLoopCounter != ulData )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Then do the same, sending the data to the back, checking everything
+ is as expected. */
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ xQueueSendToBack( xQueue, ( void * ) &ulLoopCounter, genqNO_BLOCK );
+
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueReceive( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* The data we sent to the queue should equal the data we just received
+ from the queue. */
+ if( ulLoopCounter != ulData )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+
+
+ /* Place 2, 3, 4 into the queue, adding items to the back of the queue. */
+ for( ulData = 2; ulData < 5; ulData++ )
+ {
+ xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK );
+ }
+
+ /* Now the order in the queue should be 2, 3, 4, with 2 being the first
+ thing to be read out. Now add 1 then 0 to the front of the queue. */
+ if( uxQueueMessagesWaiting( xQueue ) != 3 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ ulData = 1;
+ xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
+ ulData = 0;
+ xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK );
+
+ /* Now the queue should be full, and when we read the data out we
+ should receive 0, 1, 2, 3, 4. */
+ if( uxQueueMessagesWaiting( xQueue ) != 5 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* Check the data we read out is in the expected order. */
+ for( ulData = 0; ulData < genqQUEUE_LENGTH; ulData++ )
+ {
+ /* Try peeking the data first. */
+ if( xQueuePeek( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulData != ulData2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+
+ /* Now try receiving the data for real. The value should be the
+ same. Clobber the value first so we know we really received it. */
+ ulData2 = ~ulData2;
+ if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulData != ulData2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ }
+
+ /* The queue should now be empty again. */
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+
+ /* Our queue is empty once more, add 10, 11 to the back. */
+ ulData = 10;
+ if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ ulData = 11;
+ if( xQueueSend( xQueue, &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Now we should have 10, 11 in the queue. Add 7, 8, 9 to the
+ front. */
+ for( ulData = 9; ulData >= 7; ulData-- )
+ {
+ if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ }
+
+ /* Now check that the queue is full, and that receiving data provides
+ the expected sequence of 7, 8, 9, 10, 11. */
+ if( uxQueueMessagesWaiting( xQueue ) != 5 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueSendToFront( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( xQueueSendToBack( xQueue, ( void * ) &ulData, genqNO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* Check the data we read out is in the expected order. */
+ for( ulData = 7; ulData < ( 7 + genqQUEUE_LENGTH ); ulData++ )
+ {
+ if( xQueueReceive( xQueue, &ulData2, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulData != ulData2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ ulLoopCounter++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvLowPriorityMutexTask( void *pvParameters )
+{
+xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Mutex with priority inheritance test started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ for( ;; )
+ {
+ /* Take the mutex. It should be available now. */
+ if( xSemaphoreTake( xMutex, genqNO_BLOCK ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Set our guarded variable to a known start value. */
+ ulGuardedVariable = 0;
+
+ /* Our priority should be as per that assigned when the task was
+ created. */
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_LOW_PRIORITY )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Now unsuspend the high priority task. This will attempt to take the
+ mutex, and block when it finds it cannot obtain it. */
+ vTaskResume( xHighPriorityMutexTask );
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* Ensure the task is reporting it priority as blocked and not
+ suspended (as it would have done in versions up to V7.5.3). */
+ #if( INCLUDE_eTaskGetState == 1 )
+ {
+ configASSERT( eTaskGetState( xHighPriorityMutexTask ) == eBlocked );
+ }
+ #endif /* INCLUDE_eTaskGetState */
+
+ /* We should now have inherited the prioritoy of the high priority task,
+ as by now it will have attempted to get the mutex. */
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* We can attempt to set our priority to the test priority - between the
+ idle priority and the medium/high test priorities, but our actual
+ prioroity should remain at the high priority. */
+ vTaskPrioritySet( NULL, genqMUTEX_TEST_PRIORITY );
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_HIGH_PRIORITY )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Now unsuspend the medium priority task. This should not run as our
+ inherited priority is above that of the medium priority task. */
+ vTaskResume( xMediumPriorityMutexTask );
+
+ /* If the did run then it will have incremented our guarded variable. */
+ if( ulGuardedVariable != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* When we give back the semaphore our priority should be disinherited
+ back to the priority to which we attempted to set ourselves. This means
+ that when the high priority task next blocks, the medium priority task
+ should execute and increment the guarded variable. When we next run
+ both the high and medium priority tasks will have been suspended again. */
+ if( xSemaphoreGive( xMutex ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* Check that the guarded variable did indeed increment... */
+ if( ulGuardedVariable != 1 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* ... and that our priority has been disinherited to
+ genqMUTEX_TEST_PRIORITY. */
+ if( uxTaskPriorityGet( NULL ) != genqMUTEX_TEST_PRIORITY )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Set our priority back to our original priority ready for the next
+ loop around this test. */
+ vTaskPrioritySet( NULL, genqMUTEX_LOW_PRIORITY );
+
+ /* Just to show we are still running. */
+ ulLoopCounter2++;
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvMediumPriorityMutexTask( void *pvParameters )
+{
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* The medium priority task starts by suspending itself. The low
+ priority task will unsuspend this task when required. */
+ vTaskSuspend( NULL );
+
+ /* When this task unsuspends all it does is increment the guarded
+ variable, this is so the low priority task knows that it has
+ executed. */
+ ulGuardedVariable++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvHighPriorityMutexTask( void *pvParameters )
+{
+xSemaphoreHandle xMutex = ( xSemaphoreHandle ) pvParameters;
+
+ for( ;; )
+ {
+ /* The high priority task starts by suspending itself. The low
+ priority task will unsuspend this task when required. */
+ vTaskSuspend( NULL );
+
+ /* When this task unsuspends all it does is attempt to obtain
+ the mutex. It should find the mutex is not available so a
+ block time is specified. */
+ if( xSemaphoreTake( xMutex, portMAX_DELAY ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* When we eventually obtain the mutex we just give it back then
+ return to suspend ready for the next test. */
+ if( xSemaphoreGive( xMutex ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running. */
+portBASE_TYPE xAreGenericQueueTasksStillRunning( void )
+{
+static unsigned portLONG ulLastLoopCounter = 0, ulLastLoopCounter2 = 0;
+
+ /* If the demo task is still running then we expect the loopcounters to
+ have incremented since this function was last called. */
+ if( ulLastLoopCounter == ulLoopCounter )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulLastLoopCounter2 == ulLoopCounter2 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ ulLastLoopCounter = ulLoopCounter;
+ ulLastLoopCounter2 = ulLoopCounter2;
+
+ /* Errors detected in the task itself will have latched xErrorDetected
+ to true. */
+
+ return ( portBASE_TYPE ) !xErrorDetected;
+}
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/IntQueue.c b/third_party/FreeRTOS/Demo/Common/Minimal/IntQueue.c new file mode 100644 index 0000000..42d2103 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/IntQueue.c @@ -0,0 +1,756 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This file defines one of the more complex set of demo/test tasks. They are
+ * designed to stress test the queue implementation though pseudo simultaneous
+ * multiple reads and multiple writes from both tasks of varying priority and
+ * interrupts. The interrupts are prioritised such to ensure that nesting
+ * occurs (for those ports that support it).
+ *
+ * The test ensures that, while being accessed from three tasks and two
+ * interrupts, all the data sent to the queues is also received from
+ * the same queue, and that no duplicate items are either sent or received.
+ * The tests also ensure that a low priority task is never able to successfully
+ * read from or write to a queue when a task of higher priority is attempting
+ * the same operation.
+ */
+
+/* Standard includes. */
+#include <string.h>
+
+/* SafeRTOS includes. */
+#include "FreeRTOS.h"
+#include "queue.h"
+#include "task.h"
+
+/* Demo app includes. */
+#include "IntQueue.h"
+#include "IntQueueTimer.h"
+
+/* Priorities used by test tasks. */
+#ifndef intqHIGHER_PRIORITY
+ #define intqHIGHER_PRIORITY ( configMAX_PRIORITIES - 2 )
+#endif
+#define intqLOWER_PRIORITY ( tskIDLE_PRIORITY )
+
+/* The number of values to send/receive before checking that all values were
+processed as expected. */
+#define intqNUM_VALUES_TO_LOG ( 200 )
+#define intqSHORT_DELAY ( 140 )
+
+/* The value by which the value being sent to or received from a queue should
+increment past intqNUM_VALUES_TO_LOG before we check that all values have been
+sent/received correctly. This is done to ensure that all tasks and interrupts
+accessing the queue have completed their accesses with the
+intqNUM_VALUES_TO_LOG range. */
+#define intqVALUE_OVERRUN ( 50 )
+
+/* The delay used by the polling task. A short delay is used for code
+coverage. */
+#define intqONE_TICK_DELAY ( 1 )
+
+/* Each task and interrupt is given a unique identifier. This value is used to
+identify which task sent or received each value. The identifier is also used
+to distinguish between two tasks that are running the same task function. */
+#define intqHIGH_PRIORITY_TASK1 ( ( unsigned portBASE_TYPE ) 1 )
+#define intqHIGH_PRIORITY_TASK2 ( ( unsigned portBASE_TYPE ) 2 )
+#define intqLOW_PRIORITY_TASK ( ( unsigned portBASE_TYPE ) 3 )
+#define intqFIRST_INTERRUPT ( ( unsigned portBASE_TYPE ) 4 )
+#define intqSECOND_INTERRUPT ( ( unsigned portBASE_TYPE ) 5 )
+#define intqQUEUE_LENGTH ( ( unsigned portBASE_TYPE ) 10 )
+
+/* At least intqMIN_ACCEPTABLE_TASK_COUNT values should be sent to/received
+from each queue by each task, otherwise an error is detected. */
+#define intqMIN_ACCEPTABLE_TASK_COUNT ( 5 )
+
+/* Send the next value to the queue that is normally empty. This is called
+from within the interrupts. */
+#define timerNORMALLY_EMPTY_TX() \
+ if( xQueueIsQueueFullFromISR( xNormallyEmptyQueue ) != pdTRUE ) \
+ { \
+ unsigned portBASE_TYPE uxSavedInterruptStatus; \
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
+ { \
+ uxValueForNormallyEmptyQueue++; \
+ xQueueSendFromISR( xNormallyEmptyQueue, ( void * ) &uxValueForNormallyEmptyQueue, &xHigherPriorityTaskWoken ); \
+ } \
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
+ } \
+
+/* Send the next value to the queue that is normally full. This is called
+from within the interrupts. */
+#define timerNORMALLY_FULL_TX() \
+ if( xQueueIsQueueFullFromISR( xNormallyFullQueue ) != pdTRUE ) \
+ { \
+ unsigned portBASE_TYPE uxSavedInterruptStatus; \
+ uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR(); \
+ { \
+ uxValueForNormallyFullQueue++; \
+ xQueueSendFromISR( xNormallyFullQueue, ( void * ) &uxValueForNormallyFullQueue, &xHigherPriorityTaskWoken ); \
+ } \
+ portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus ); \
+ } \
+
+/* Receive a value from the normally empty queue. This is called from within
+an interrupt. */
+#define timerNORMALLY_EMPTY_RX() \
+ if( xQueueReceiveFromISR( xNormallyEmptyQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) != pdPASS ) \
+ { \
+ prvQueueAccessLogError( __LINE__ ); \
+ } \
+ else \
+ { \
+ prvRecordValue_NormallyEmpty( uxRxedValue, intqSECOND_INTERRUPT ); \
+ }
+
+/* Receive a value from the normally full queue. This is called from within
+an interrupt. */
+#define timerNORMALLY_FULL_RX() \
+ if( xQueueReceiveFromISR( xNormallyFullQueue, &uxRxedValue, &xHigherPriorityTaskWoken ) == pdPASS ) \
+ { \
+ prvRecordValue_NormallyFull( uxRxedValue, intqSECOND_INTERRUPT ); \
+ } \
+
+
+/*-----------------------------------------------------------*/
+
+/* The two queues used by the test. */
+static xQueueHandle xNormallyEmptyQueue, xNormallyFullQueue;
+
+/* Variables used to detect a stall in one of the tasks. */
+static unsigned portBASE_TYPE uxHighPriorityLoops1 = 0, uxHighPriorityLoops2 = 0, uxLowPriorityLoops1 = 0, uxLowPriorityLoops2 = 0;
+
+/* Any unexpected behaviour sets xErrorStatus to fail and log the line that
+caused the error in xErrorLine. */
+static portBASE_TYPE xErrorStatus = pdPASS;
+static volatile unsigned portBASE_TYPE xErrorLine = ( unsigned portBASE_TYPE ) 0;
+
+/* Used for sequencing between tasks. */
+static portBASE_TYPE xWasSuspended = pdFALSE;
+
+/* The values that are sent to the queues. An incremented value is sent each
+time to each queue. */
+volatile unsigned portBASE_TYPE uxValueForNormallyEmptyQueue = 0, uxValueForNormallyFullQueue = 0;
+
+/* A handle to some of the tasks is required so they can be suspended/resumed. */
+xTaskHandle xHighPriorityNormallyEmptyTask1, xHighPriorityNormallyEmptyTask2, xHighPriorityNormallyFullTask1, xHighPriorityNormallyFullTask2;
+
+/* When a value is received in a queue the value is ticked off in the array
+the array position of the value is set to a the identifier of the task or
+interrupt that accessed the queue. This way missing or duplicate values can be
+detected. */
+static unsigned portCHAR ucNormallyEmptyReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
+static unsigned portCHAR ucNormallyFullReceivedValues[ intqNUM_VALUES_TO_LOG ] = { 0 };
+
+/* The test tasks themselves. */
+static void prvLowerPriorityNormallyEmptyTask( void *pvParameters );
+static void prvLowerPriorityNormallyFullTask( void *pvParameters );
+static void prvHigherPriorityNormallyEmptyTask( void *pvParameters );
+static void prv1stHigherPriorityNormallyFullTask( void *pvParameters );
+static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters );
+
+/* Used to mark the positions within the ucNormallyEmptyReceivedValues and
+ucNormallyFullReceivedValues arrays, while checking for duplicates. */
+static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
+static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource );
+
+/* Logs the line on which an error occurred. */
+static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine );
+
+/*-----------------------------------------------------------*/
+
+void vStartInterruptQueueTasks( void )
+{
+ /* Start the test tasks. */
+ xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H1QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask1 );
+ xTaskCreate( prvHigherPriorityNormallyEmptyTask, ( signed portCHAR * ) "H2QRx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyEmptyTask2 );
+ xTaskCreate( prvLowerPriorityNormallyEmptyTask, ( signed portCHAR * ) "L1QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
+ xTaskCreate( prv1stHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H1QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK1, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask1 );
+ xTaskCreate( prv2ndHigherPriorityNormallyFullTask, ( signed portCHAR * ) "H2QTx", configMINIMAL_STACK_SIZE, ( void * ) intqHIGH_PRIORITY_TASK2, intqHIGHER_PRIORITY, &xHighPriorityNormallyFullTask2 );
+ xTaskCreate( prvLowerPriorityNormallyFullTask, ( signed portCHAR * ) "L2QRx", configMINIMAL_STACK_SIZE, NULL, intqLOWER_PRIORITY, NULL );
+
+ /* Create the queues that are accessed by multiple tasks and multiple
+ interrupts. */
+ xNormallyFullQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
+ xNormallyEmptyQueue = xQueueCreate( intqQUEUE_LENGTH, ( unsigned portBASE_TYPE ) sizeof( unsigned portBASE_TYPE ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xNormallyFullQueue, ( signed portCHAR * ) "NormallyFull" );
+ vQueueAddToRegistry( xNormallyEmptyQueue, ( signed portCHAR * ) "NormallyEmpty" );
+}
+/*-----------------------------------------------------------*/
+
+static void prvRecordValue_NormallyFull( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
+{
+ if( uxValue < intqNUM_VALUES_TO_LOG )
+ {
+ /* We don't expect to receive the same value twice, so if the value
+ has already been marked as received an error has occurred. */
+ if( ucNormallyFullReceivedValues[ uxValue ] != 0x00 )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ /* Log that this value has been received. */
+ ucNormallyFullReceivedValues[ uxValue ] = uxSource;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvRecordValue_NormallyEmpty( unsigned portBASE_TYPE uxValue, unsigned portBASE_TYPE uxSource )
+{
+ if( uxValue < intqNUM_VALUES_TO_LOG )
+ {
+ /* We don't expect to receive the same value twice, so if the value
+ has already been marked as received an error has occurred. */
+ if( ucNormallyEmptyReceivedValues[ uxValue ] != 0x00 )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ /* Log that this value has been received. */
+ ucNormallyEmptyReceivedValues[ uxValue ] = uxSource;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvQueueAccessLogError( unsigned portBASE_TYPE uxLine )
+{
+ /* Latch the line number that caused the error. */
+ xErrorLine = uxLine;
+ xErrorStatus = pdFAIL;
+}
+/*-----------------------------------------------------------*/
+
+static void prvHigherPriorityNormallyEmptyTask( void *pvParameters )
+{
+unsigned portBASE_TYPE uxRxed, ux, uxTask1, uxTask2, uxInterrupts, uxErrorCount1 = 0, uxErrorCount2 = 0;
+
+ /* The timer should not be started until after the scheduler has started.
+ More than one task is running this code so we check the parameter value
+ to determine which task should start the timer. */
+ if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
+ {
+ vInitialiseTimerForIntQueueTest();
+ }
+
+ for( ;; )
+ {
+ /* Block waiting to receive a value from the normally empty queue.
+ Interrupts will write to the queue so we should receive a value. */
+ if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqSHORT_DELAY ) != pdPASS )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+ else
+ {
+ /* Note which value was received so we can check all expected
+ values are received and no values are duplicated. */
+ prvRecordValue_NormallyEmpty( uxRxed, ( unsigned portBASE_TYPE ) pvParameters );
+ }
+
+ /* Ensure the other task running this code gets a chance to execute. */
+ taskYIELD();
+
+ if( ( unsigned portBASE_TYPE ) pvParameters == intqHIGH_PRIORITY_TASK1 )
+ {
+ /* Have we received all the expected values? */
+ if( uxValueForNormallyEmptyQueue > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
+ {
+ vTaskSuspend( xHighPriorityNormallyEmptyTask2 );
+
+ uxTask1 = 0;
+ uxTask2 = 0;
+ uxInterrupts = 0;
+
+ /* Loop through the array, checking that both tasks have
+ placed values into the array, and that no values are missing.
+ Start at 1 as we expect position 0 to be unused. */
+ for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
+ {
+ if( ucNormallyEmptyReceivedValues[ ux ] == 0 )
+ {
+ /* A value is missing. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+ else
+ {
+ if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK1 )
+ {
+ /* Value was placed into the array by task 1. */
+ uxTask1++;
+ }
+ else if( ucNormallyEmptyReceivedValues[ ux ] == intqHIGH_PRIORITY_TASK2 )
+ {
+ /* Value was placed into the array by task 2. */
+ uxTask2++;
+ }
+ else if( ucNormallyEmptyReceivedValues[ ux ] == intqSECOND_INTERRUPT )
+ {
+ uxInterrupts++;
+ }
+ }
+ }
+
+ if( uxTask1 < intqMIN_ACCEPTABLE_TASK_COUNT )
+ {
+ /* Only task 2 seemed to log any values. */
+ uxErrorCount1++;
+ if( uxErrorCount1 > 2 )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+ }
+ else
+ {
+ uxErrorCount1 = 0;
+ }
+
+ if( uxTask2 < intqMIN_ACCEPTABLE_TASK_COUNT )
+ {
+ /* Only task 1 seemed to log any values. */
+ uxErrorCount2++;
+ if( uxErrorCount2 > 2 )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+ }
+ else
+ {
+ uxErrorCount2 = 0;
+ }
+
+ if( uxInterrupts == 0 )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ /* Clear the array again, ready to start a new cycle. */
+ memset( ucNormallyEmptyReceivedValues, 0x00, sizeof( ucNormallyEmptyReceivedValues ) );
+
+ uxHighPriorityLoops1++;
+ uxValueForNormallyEmptyQueue = 0;
+
+ /* Suspend ourselves, allowing the lower priority task to
+ actually receive something from the queue. Until now it
+ will have been prevented from doing so by the higher
+ priority tasks. The lower priority task will resume us
+ if it receives something. We will then resume the other
+ higher priority task. */
+ vTaskSuspend( NULL );
+ vTaskResume( xHighPriorityNormallyEmptyTask2 );
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvLowerPriorityNormallyEmptyTask( void *pvParameters )
+{
+unsigned portBASE_TYPE uxValue, uxRxed;
+
+ /* The parameters are not being used so avoid compiler warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ if( xQueueReceive( xNormallyEmptyQueue, &uxRxed, intqONE_TICK_DELAY ) != errQUEUE_EMPTY )
+ {
+ /* We should only obtain a value when the high priority task is
+ suspended. */
+ if( xTaskIsTaskSuspended( xHighPriorityNormallyEmptyTask1 ) == pdFALSE )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ prvRecordValue_NormallyEmpty( uxRxed, intqLOW_PRIORITY_TASK );
+
+ /* Wake the higher priority task again. */
+ vTaskResume( xHighPriorityNormallyEmptyTask1 );
+ uxLowPriorityLoops1++;
+ }
+ else
+ {
+ /* Raise our priority while we send so we can preempt the higher
+ priority task, and ensure we get the Tx value into the queue. */
+ vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
+
+ portENTER_CRITICAL();
+ {
+ uxValueForNormallyEmptyQueue++;
+ uxValue = uxValueForNormallyEmptyQueue;
+ }
+ portEXIT_CRITICAL();
+
+ if( xQueueSend( xNormallyEmptyQueue, &uxValue, portMAX_DELAY ) != pdPASS )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prv1stHigherPriorityNormallyFullTask( void *pvParameters )
+{
+unsigned portBASE_TYPE uxValueToTx, ux, uxInterrupts;
+
+ /* The parameters are not being used so avoid compiler warnings. */
+ ( void ) pvParameters;
+
+ /* Make sure the queue starts full or near full. >> 1 as there are two
+ high priority tasks. */
+ for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
+ {
+ portENTER_CRITICAL();
+ {
+ uxValueForNormallyFullQueue++;
+ uxValueToTx = uxValueForNormallyFullQueue;
+ }
+ portEXIT_CRITICAL();
+
+ xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
+ }
+
+ for( ;; )
+ {
+ portENTER_CRITICAL();
+ {
+ uxValueForNormallyFullQueue++;
+ uxValueToTx = uxValueForNormallyFullQueue;
+ }
+ portEXIT_CRITICAL();
+
+ if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
+ {
+ /* intqHIGH_PRIORITY_TASK2 is never suspended so we would not
+ expect it to ever time out. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ /* Allow the other task running this code to run. */
+ taskYIELD();
+
+ /* Have all the expected values been sent to the queue? */
+ if( uxValueToTx > ( intqNUM_VALUES_TO_LOG + intqVALUE_OVERRUN ) )
+ {
+ /* Make sure the other high priority task completes its send of
+ any values below intqNUM_VALUE_TO_LOG. */
+ vTaskDelay( intqSHORT_DELAY );
+
+ vTaskSuspend( xHighPriorityNormallyFullTask2 );
+
+ if( xWasSuspended == pdTRUE )
+ {
+ /* We would have expected the other high priority task to have
+ set this back to false by now. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ /* Set the suspended flag so an error is not logged if the other
+ task recognises a time out when it is unsuspended. */
+ xWasSuspended = pdTRUE;
+
+ /* Check interrupts are also sending. */
+ uxInterrupts = 0U;
+
+ /* Start at 1 as we expect position 0 to be unused. */
+ for( ux = 1; ux < intqNUM_VALUES_TO_LOG; ux++ )
+ {
+ if( ucNormallyFullReceivedValues[ ux ] == 0 )
+ {
+ /* A value was missing. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+ else if( ucNormallyFullReceivedValues[ ux ] == intqSECOND_INTERRUPT )
+ {
+ uxInterrupts++;
+ }
+ }
+
+ if( uxInterrupts == 0 )
+ {
+ /* No writes from interrupts were found. Are interrupts
+ actually running? */
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ /* Reset the array ready for the next cycle. */
+ memset( ucNormallyFullReceivedValues, 0x00, sizeof( ucNormallyFullReceivedValues ) );
+
+ uxHighPriorityLoops2++;
+ uxValueForNormallyFullQueue = 0;
+
+ /* Suspend ourselves, allowing the lower priority task to
+ actually receive something from the queue. Until now it
+ will have been prevented from doing so by the higher
+ priority tasks. The lower priority task will resume us
+ if it receives something. We will then resume the other
+ higher priority task. */
+ vTaskSuspend( NULL );
+ vTaskResume( xHighPriorityNormallyFullTask2 );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prv2ndHigherPriorityNormallyFullTask( void *pvParameters )
+{
+unsigned portBASE_TYPE uxValueToTx, ux;
+
+ /* The parameters are not being used so avoid compiler warnings. */
+ ( void ) pvParameters;
+
+ /* Make sure the queue starts full or near full. >> 1 as there are two
+ high priority tasks. */
+ for( ux = 0; ux < ( intqQUEUE_LENGTH >> 1 ); ux++ )
+ {
+ portENTER_CRITICAL();
+ {
+ uxValueForNormallyFullQueue++;
+ uxValueToTx = uxValueForNormallyFullQueue;
+ }
+ portEXIT_CRITICAL();
+
+ xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY );
+ }
+
+ for( ;; )
+ {
+ portENTER_CRITICAL();
+ {
+ uxValueForNormallyFullQueue++;
+ uxValueToTx = uxValueForNormallyFullQueue;
+ }
+ portEXIT_CRITICAL();
+
+ if( xQueueSend( xNormallyFullQueue, &uxValueToTx, intqSHORT_DELAY ) != pdPASS )
+ {
+ if( xWasSuspended != pdTRUE )
+ {
+ /* It is ok to time out if the task has been suspended. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+ }
+
+ xWasSuspended = pdFALSE;
+
+ taskYIELD();
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvLowerPriorityNormallyFullTask( void *pvParameters )
+{
+unsigned portBASE_TYPE uxValue, uxTxed = 9999;
+
+ /* The parameters are not being used so avoid compiler warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ if( xQueueSend( xNormallyFullQueue, &uxTxed, intqONE_TICK_DELAY ) != errQUEUE_FULL )
+ {
+ /* We would only expect to succeed when the higher priority task
+ is suspended. */
+ if( xTaskIsTaskSuspended( xHighPriorityNormallyFullTask1 ) == pdFALSE )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ vTaskResume( xHighPriorityNormallyFullTask1 );
+ uxLowPriorityLoops2++;
+ }
+ else
+ {
+ /* Raise our priority while we receive so we can preempt the higher
+ priority task, and ensure we get the value from the queue. */
+ vTaskPrioritySet( NULL, intqHIGHER_PRIORITY + 1 );
+
+ if( xQueueReceive( xNormallyFullQueue, &uxValue, portMAX_DELAY ) != pdPASS )
+ {
+ prvQueueAccessLogError( __LINE__ );
+ }
+ else
+ {
+ prvRecordValue_NormallyFull( uxValue, intqLOW_PRIORITY_TASK );
+ }
+
+ vTaskPrioritySet( NULL, intqLOWER_PRIORITY );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xFirstTimerHandler( void )
+{
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE, uxRxedValue;
+static unsigned portBASE_TYPE uxNextOperation = 0;
+
+ /* Called from a timer interrupt. Perform various read and write
+ accesses on the queues. */
+
+ uxNextOperation++;
+
+ if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
+ {
+ timerNORMALLY_EMPTY_TX();
+ timerNORMALLY_EMPTY_TX();
+ timerNORMALLY_EMPTY_TX();
+ }
+ else
+ {
+ timerNORMALLY_FULL_RX();
+ timerNORMALLY_FULL_RX();
+ timerNORMALLY_FULL_RX();
+ }
+
+ return xHigherPriorityTaskWoken;
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xSecondTimerHandler( void )
+{
+unsigned portBASE_TYPE uxRxedValue;
+portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+static unsigned portBASE_TYPE uxNextOperation = 0;
+
+ /* Called from a timer interrupt. Perform various read and write
+ accesses on the queues. */
+
+ uxNextOperation++;
+
+ if( uxNextOperation & ( unsigned portBASE_TYPE ) 0x01 )
+ {
+ timerNORMALLY_EMPTY_TX();
+ timerNORMALLY_EMPTY_TX();
+
+ timerNORMALLY_EMPTY_RX();
+ timerNORMALLY_EMPTY_RX();
+ }
+ else
+ {
+ timerNORMALLY_FULL_RX();
+ timerNORMALLY_FULL_TX();
+ timerNORMALLY_FULL_TX();
+ timerNORMALLY_FULL_TX();
+ timerNORMALLY_FULL_TX();
+ }
+
+ return xHigherPriorityTaskWoken;
+}
+/*-----------------------------------------------------------*/
+
+
+portBASE_TYPE xAreIntQueueTasksStillRunning( void )
+{
+static unsigned portBASE_TYPE uxLastHighPriorityLoops1 = 0, uxLastHighPriorityLoops2 = 0, uxLastLowPriorityLoops1 = 0, uxLastLowPriorityLoops2 = 0;
+
+ /* xErrorStatus can be set outside of this function. This function just
+ checks that all the tasks are still cycling. */
+
+ if( uxHighPriorityLoops1 == uxLastHighPriorityLoops1 )
+ {
+ /* The high priority 1 task has stalled. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ uxLastHighPriorityLoops1 = uxHighPriorityLoops1;
+
+ if( uxHighPriorityLoops2 == uxLastHighPriorityLoops2 )
+ {
+ /* The high priority 2 task has stalled. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ uxLastHighPriorityLoops2 = uxHighPriorityLoops2;
+
+ if( uxLowPriorityLoops1 == uxLastLowPriorityLoops1 )
+ {
+ /* The low priority 1 task has stalled. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ uxLastLowPriorityLoops1 = uxLowPriorityLoops1;
+
+ if( uxLowPriorityLoops2 == uxLastLowPriorityLoops2 )
+ {
+ /* The low priority 2 task has stalled. */
+ prvQueueAccessLogError( __LINE__ );
+ }
+
+ uxLastLowPriorityLoops2 = uxLowPriorityLoops2;
+
+ return xErrorStatus;
+}
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/PollQ.c b/third_party/FreeRTOS/Demo/Common/Minimal/PollQ.c new file mode 100644 index 0000000..e3a3cb3 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/PollQ.c @@ -0,0 +1,258 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This version of PollQ. c is for use on systems that have limited stack
+ * space and no display facilities. The complete version can be found in
+ * the Demo/Common/Full directory.
+ *
+ * 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.
+ */
+
+/*
+Changes from V2.0.0
+
+ + Delay periods are now specified using variables and constants of
+ portTickType rather than unsigned long.
+*/
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* Demo program include files. */
+#include "PollQ.h"
+
+#define pollqSTACK_SIZE configMINIMAL_STACK_SIZE
+#define pollqQUEUE_SIZE ( 10 )
+#define pollqPRODUCER_DELAY ( ( portTickType ) 200 / portTICK_RATE_MS )
+#define pollqCONSUMER_DELAY ( pollqPRODUCER_DELAY - ( portTickType ) ( 20 / portTICK_RATE_MS ) )
+#define pollqNO_DELAY ( ( portTickType ) 0 )
+#define pollqVALUES_TO_PRODUCE ( ( signed portBASE_TYPE ) 3 )
+#define pollqINITIAL_VALUE ( ( signed portBASE_TYPE ) 0 )
+
+/* The task that posts the incrementing number onto the queue. */
+static portTASK_FUNCTION_PROTO( vPolledQueueProducer, pvParameters );
+
+/* The task that empties the queue. */
+static portTASK_FUNCTION_PROTO( vPolledQueueConsumer, pvParameters );
+
+/* Variables that are used to check that the tasks are still running with no
+errors. */
+static volatile signed portBASE_TYPE xPollingConsumerCount = pollqINITIAL_VALUE, xPollingProducerCount = pollqINITIAL_VALUE;
+
+/*-----------------------------------------------------------*/
+
+void vStartPolledQueueTasks( unsigned portBASE_TYPE uxPriority )
+{
+static xQueueHandle xPolledQueue;
+
+ /* Create the queue used by the producer and consumer. */
+ xPolledQueue = xQueueCreate( pollqQUEUE_SIZE, ( unsigned portBASE_TYPE ) sizeof( unsigned short ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xPolledQueue, ( signed char * ) "Poll_Test_Queue" );
+
+ /* Spawn the producer and consumer. */
+ xTaskCreate( vPolledQueueConsumer, ( signed char * ) "QConsNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );
+ xTaskCreate( vPolledQueueProducer, ( signed char * ) "QProdNB", pollqSTACK_SIZE, ( void * ) &xPolledQueue, uxPriority, ( xTaskHandle * ) NULL );
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vPolledQueueProducer, pvParameters )
+{
+unsigned short usValue = ( unsigned short ) 0;
+signed portBASE_TYPE xError = pdFALSE, xLoop;
+
+ for( ;; )
+ {
+ for( xLoop = 0; xLoop < pollqVALUES_TO_PRODUCE; xLoop++ )
+ {
+ /* Send an incrementing number on the queue without blocking. */
+ if( xQueueSend( *( ( xQueueHandle * ) pvParameters ), ( void * ) &usValue, pollqNO_DELAY ) != pdPASS )
+ {
+ /* We should never find the queue full so if we get here there
+ has been an error. */
+ xError = pdTRUE;
+ }
+ else
+ {
+ if( xError == pdFALSE )
+ {
+ /* If an error has ever been recorded we stop incrementing the
+ check variable. */
+ portENTER_CRITICAL();
+ xPollingProducerCount++;
+ portEXIT_CRITICAL();
+ }
+
+ /* 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( pollqPRODUCER_DELAY );
+ }
+} /*lint !e818 Function prototype must conform to API. */
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vPolledQueueConsumer, pvParameters )
+{
+unsigned short usData, usExpectedValue = ( unsigned short ) 0;
+signed portBASE_TYPE xError = pdFALSE;
+
+ for( ;; )
+ {
+ /* Loop until the queue is empty. */
+ while( uxQueueMessagesWaiting( *( ( xQueueHandle * ) pvParameters ) ) )
+ {
+ if( xQueueReceive( *( ( xQueueHandle * ) pvParameters ), &usData, pollqNO_DELAY ) == pdPASS )
+ {
+ if( usData != usExpectedValue )
+ {
+ /* This is not what we expected to receive so an error has
+ occurred. */
+ xError = pdTRUE;
+
+ /* Catch-up to the value we received so our next expected
+ value should again be correct. */
+ usExpectedValue = usData;
+ }
+ else
+ {
+ if( xError == pdFALSE )
+ {
+ /* Only increment the check variable if no errors have
+ occurred. */
+ portENTER_CRITICAL();
+ xPollingConsumerCount++;
+ portEXIT_CRITICAL();
+ }
+ }
+
+ /* Next time round we would expect the number to be one higher. */
+ usExpectedValue++;
+ }
+ }
+
+ /* Now the queue is empty we block, allowing the producer to place more
+ items in the queue. */
+ vTaskDelay( pollqCONSUMER_DELAY );
+ }
+} /*lint !e818 Function prototype must conform to API. */
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running with no errors. */
+portBASE_TYPE xArePollingQueuesStillRunning( void )
+{
+portBASE_TYPE xReturn;
+
+ /* Check both the consumer and producer poll count to check they have both
+ been changed since out last trip round. We do not need a critical section
+ around the check variables as this is called from a higher priority than
+ the other tasks that access the same variables. */
+ if( ( xPollingConsumerCount == pollqINITIAL_VALUE ) ||
+ ( xPollingProducerCount == pollqINITIAL_VALUE )
+ )
+ {
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+
+ /* Set the check variables back down so we know if they have been
+ incremented the next time around. */
+ xPollingConsumerCount = pollqINITIAL_VALUE;
+ xPollingProducerCount = pollqINITIAL_VALUE;
+
+ return xReturn;
+}
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/QPeek.c b/third_party/FreeRTOS/Demo/Common/Minimal/QPeek.c new file mode 100644 index 0000000..942155c --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/QPeek.c @@ -0,0 +1,474 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+
+/*
+ * Tests the behaviour when data is peeked from a queue when there are
+ * multiple tasks blocked on the queue.
+ */
+
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+#include "semphr.h"
+
+/* Demo program include files. */
+#include "QPeek.h"
+
+#define qpeekQUEUE_LENGTH ( 5 )
+#define qpeekNO_BLOCK ( 0 )
+#define qpeekSHORT_DELAY ( 10 )
+
+#define qpeekLOW_PRIORITY ( tskIDLE_PRIORITY + 0 )
+#define qpeekMEDIUM_PRIORITY ( tskIDLE_PRIORITY + 1 )
+#define qpeekHIGH_PRIORITY ( tskIDLE_PRIORITY + 2 )
+#define qpeekHIGHEST_PRIORITY ( tskIDLE_PRIORITY + 3 )
+
+/*-----------------------------------------------------------*/
+
+/*
+ * The following three tasks are used to demonstrate the peeking behaviour.
+ * Each task is given a different priority to demonstrate the order in which
+ * tasks are woken as data is peeked from a queue.
+ */
+static void prvLowPriorityPeekTask( void *pvParameters );
+static void prvMediumPriorityPeekTask( void *pvParameters );
+static void prvHighPriorityPeekTask( void *pvParameters );
+static void prvHighestPriorityPeekTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+/* Flag that will be latched to pdTRUE should any unexpected behaviour be
+detected in any of the tasks. */
+static volatile portBASE_TYPE xErrorDetected = pdFALSE;
+
+/* Counter that is incremented on each cycle of a test. This is used to
+detect a stalled task - a test that is no longer running. */
+static volatile unsigned portLONG ulLoopCounter = 0;
+
+/* Handles to the test tasks. */
+xTaskHandle xMediumPriorityTask, xHighPriorityTask, xHighestPriorityTask;
+/*-----------------------------------------------------------*/
+
+void vStartQueuePeekTasks( void )
+{
+xQueueHandle xQueue;
+
+ /* Create the queue that we are going to use for the test/demo. */
+ xQueue = xQueueCreate( qpeekQUEUE_LENGTH, sizeof( unsigned portLONG ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xQueue, ( signed portCHAR * ) "QPeek_Test_Queue" );
+
+ /* Create the demo tasks and pass it the queue just created. We are
+ passing the queue handle by value so it does not matter that it is declared
+ on the stack here. */
+ xTaskCreate( prvLowPriorityPeekTask, ( signed portCHAR * )"PeekL", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekLOW_PRIORITY, NULL );
+ xTaskCreate( prvMediumPriorityPeekTask, ( signed portCHAR * )"PeekM", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekMEDIUM_PRIORITY, &xMediumPriorityTask );
+ xTaskCreate( prvHighPriorityPeekTask, ( signed portCHAR * )"PeekH1", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGH_PRIORITY, &xHighPriorityTask );
+ xTaskCreate( prvHighestPriorityPeekTask, ( signed portCHAR * )"PeekH2", configMINIMAL_STACK_SIZE, ( void * ) xQueue, qpeekHIGHEST_PRIORITY, &xHighestPriorityTask );
+}
+/*-----------------------------------------------------------*/
+
+static void prvHighestPriorityPeekTask( void *pvParameters )
+{
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
+unsigned portLONG ulValue;
+
+ #ifdef USE_STDIO
+ {
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Queue peek test started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ }
+ #endif
+
+ for( ;; )
+ {
+ /* Try peeking from the queue. The queue should be empty so we will
+ block, allowing the high priority task to execute. */
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
+ {
+ /* We expected to have received something by the time we unblock. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* When we reach here the high and medium priority tasks should still
+ be blocked on the queue. We unblocked because the low priority task
+ wrote a value to the queue, which we should have peeked. Peeking the
+ data (rather than receiving it) will leave the data on the queue, so
+ the high priority task should then have also been unblocked, but not
+ yet executed. */
+ if( ulValue != 0x11223344 )
+ {
+ /* We did not receive the expected value. */
+ xErrorDetected = pdTRUE;
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )
+ {
+ /* The message should have been left on the queue. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Now we are going to actually receive the data, so when the high
+ priority task runs it will find the queue empty and return to the
+ blocked state. */
+ ulValue = 0;
+ if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
+ {
+ /* We expected to receive the value. */
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulValue != 0x11223344 )
+ {
+ /* We did not receive the expected value - which should have been
+ the same value as was peeked. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Now we will block again as the queue is once more empty. The low
+ priority task can then execute again. */
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
+ {
+ /* We expected to have received something by the time we unblock. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* When we get here the low priority task should have again written to the
+ queue. */
+ if( ulValue != 0x01234567 )
+ {
+ /* We did not receive the expected value. */
+ xErrorDetected = pdTRUE;
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )
+ {
+ /* The message should have been left on the queue. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* We only peeked the data, so suspending ourselves now should enable
+ the high priority task to also peek the data. The high priority task
+ will have been unblocked when we peeked the data as we left the data
+ in the queue. */
+ vTaskSuspend( NULL );
+
+
+
+ /* This time we are going to do the same as the above test, but the
+ high priority task is going to receive the data, rather than peek it.
+ This means that the medium priority task should never peek the value. */
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulValue != 0xaabbaabb )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ vTaskSuspend( NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvHighPriorityPeekTask( void *pvParameters )
+{
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
+unsigned portLONG ulValue;
+
+ for( ;; )
+ {
+ /* Try peeking from the queue. The queue should be empty so we will
+ block, allowing the medium priority task to execute. Both the high
+ and highest priority tasks will then be blocked on the queue. */
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
+ {
+ /* We expected to have received something by the time we unblock. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* When we get here the highest priority task should have peeked the data
+ (unblocking this task) then suspended (allowing this task to also peek
+ the data). */
+ if( ulValue != 0x01234567 )
+ {
+ /* We did not receive the expected value. */
+ xErrorDetected = pdTRUE;
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )
+ {
+ /* The message should have been left on the queue. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* We only peeked the data, so suspending ourselves now should enable
+ the medium priority task to also peek the data. The medium priority task
+ will have been unblocked when we peeked the data as we left the data
+ in the queue. */
+ vTaskSuspend( NULL );
+
+
+ /* This time we are going actually receive the value, so the medium
+ priority task will never peek the data - we removed it from the queue. */
+ if( xQueueReceive( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulValue != 0xaabbaabb )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ vTaskSuspend( NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvMediumPriorityPeekTask( void *pvParameters )
+{
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
+unsigned portLONG ulValue;
+
+ for( ;; )
+ {
+ /* Try peeking from the queue. The queue should be empty so we will
+ block, allowing the low priority task to execute. The highest, high
+ and medium priority tasks will then all be blocked on the queue. */
+ if( xQueuePeek( xQueue, &ulValue, portMAX_DELAY ) != pdPASS )
+ {
+ /* We expected to have received something by the time we unblock. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* When we get here the high priority task should have peeked the data
+ (unblocking this task) then suspended (allowing this task to also peek
+ the data). */
+ if( ulValue != 0x01234567 )
+ {
+ /* We did not receive the expected value. */
+ xErrorDetected = pdTRUE;
+ }
+
+ if( uxQueueMessagesWaiting( xQueue ) != 1 )
+ {
+ /* The message should have been left on the queue. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Just so we know the test is still running. */
+ ulLoopCounter++;
+
+ /* Now we can suspend ourselves so the low priority task can execute
+ again. */
+ vTaskSuspend( NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvLowPriorityPeekTask( void *pvParameters )
+{
+xQueueHandle xQueue = ( xQueueHandle ) pvParameters;
+unsigned portLONG ulValue;
+
+ for( ;; )
+ {
+ /* Write some data to the queue. This should unblock the highest
+ priority task that is waiting to peek data from the queue. */
+ ulValue = 0x11223344;
+ if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
+ {
+ /* We were expecting the queue to be empty so we should not of
+ had a problem writing to the queue. */
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* By the time we get here the data should have been removed from
+ the queue. */
+ if( uxQueueMessagesWaiting( xQueue ) != 0 )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Write another value to the queue, again waking the highest priority
+ task that is blocked on the queue. */
+ ulValue = 0x01234567;
+ if( xQueueSendToBack( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
+ {
+ /* We were expecting the queue to be empty so we should not of
+ had a problem writing to the queue. */
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* All the other tasks should now have successfully peeked the data.
+ The data is still in the queue so we should be able to receive it. */
+ ulValue = 0;
+ if( xQueueReceive( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
+ {
+ /* We expected to receive the data. */
+ xErrorDetected = pdTRUE;
+ }
+
+ if( ulValue != 0x01234567 )
+ {
+ /* We did not receive the expected value. */
+ }
+
+ /* Lets just delay a while as this is an intensive test as we don't
+ want to starve other tests of processing time. */
+ vTaskDelay( qpeekSHORT_DELAY );
+
+ /* Unsuspend the other tasks so we can repeat the test - this time
+ however not all the other tasks will peek the data as the high
+ priority task is actually going to remove it from the queue. Send
+ to front is used just to be different. As the queue is empty it
+ makes no difference to the result. */
+ vTaskResume( xMediumPriorityTask );
+ vTaskResume( xHighPriorityTask );
+ vTaskResume( xHighestPriorityTask );
+
+ #if( configUSE_PREEMPTION == 0 )
+ taskYIELD();
+ #endif
+
+ ulValue = 0xaabbaabb;
+ if( xQueueSendToFront( xQueue, &ulValue, qpeekNO_BLOCK ) != pdPASS )
+ {
+ /* We were expecting the queue to be empty so we should not of
+ had a problem writing to the queue. */
+ xErrorDetected = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* This time we should find that the queue is empty. The high priority
+ task actually removed the data rather than just peeking it. */
+ if( xQueuePeek( xQueue, &ulValue, qpeekNO_BLOCK ) != errQUEUE_EMPTY )
+ {
+ /* We expected to receive the data. */
+ xErrorDetected = pdTRUE;
+ }
+
+ /* Unsuspend the highest and high priority tasks so we can go back
+ and repeat the whole thing. The medium priority task should not be
+ suspended as it was not able to peek the data in this last case. */
+ vTaskResume( xHighPriorityTask );
+ vTaskResume( xHighestPriorityTask );
+
+ /* Lets just delay a while as this is an intensive test as we don't
+ want to starve other tests of processing time. */
+ vTaskDelay( qpeekSHORT_DELAY );
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running. */
+portBASE_TYPE xAreQueuePeekTasksStillRunning( void )
+{
+static unsigned portLONG ulLastLoopCounter = 0;
+
+ /* If the demo task is still running then we expect the loopcounter to
+ have incremented since this function was last called. */
+ if( ulLastLoopCounter == ulLoopCounter )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ ulLastLoopCounter = ulLoopCounter;
+
+ /* Errors detected in the task itself will have latched xErrorDetected
+ to true. */
+
+ return !xErrorDetected;
+}
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/TimerDemo.c b/third_party/FreeRTOS/Demo/Common/Minimal/TimerDemo.c new file mode 100644 index 0000000..509c690 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/TimerDemo.c @@ -0,0 +1,1060 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+
+/*
+ * Tests the behaviour of timers. Some timers are created before the scheduler
+ * is started, and some after.
+ */
+
+/* Standard includes. */
+#include <string.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+
+/* Demo program include files. */
+#include "TimerDemo.h"
+
+#if ( configTIMER_TASK_PRIORITY < 1 )
+ #error configTIMER_TASK_PRIORITY must be set to at least 1 for this test/demo to function correctly.
+#endif
+
+#define tmrdemoDONT_BLOCK ( ( portTickType ) 0 )
+#define tmrdemoONE_SHOT_TIMER_PERIOD ( xBasePeriod * ( portTickType ) 3 )
+#define trmdemoNUM_TIMER_RESETS ( ( unsigned char ) 10 )
+
+/*-----------------------------------------------------------*/
+
+/* The callback functions used by the timers. These each increment a counter
+to indicate which timer has expired. The auto-reload timers that are used by
+the test task (as opposed to being used from an ISR) all share the same
+prvAutoReloadTimerCallback() callback function, and use the ID of the
+pxExpiredTimer parameter passed into that function to know which counter to
+increment. The other timers all have their own unique callback function and
+simply increment their counters without using the callback function parameter. */
+static void prvAutoReloadTimerCallback( xTimerHandle pxExpiredTimer );
+static void prvOneShotTimerCallback( xTimerHandle pxExpiredTimer );
+static void prvTimerTestTask( void *pvParameters );
+static void prvISRAutoReloadTimerCallback( xTimerHandle pxExpiredTimer );
+static void prvISROneShotTimerCallback( xTimerHandle pxExpiredTimer );
+
+/* The test functions used by the timer test task. These manipulate the auto
+reload and one shot timers in various ways, then delay, then inspect the timers
+to ensure they have behaved as expected. */
+static void prvTest1_CreateTimersWithoutSchedulerRunning( void );
+static void prvTest2_CheckTaskAndTimersInitialState( void );
+static void prvTest3_CheckAutoReloadExpireRates( void );
+static void prvTest4_CheckAutoReloadTimersCanBeStopped( void );
+static void prvTest5_CheckBasicOneShotTimerBehaviour( void );
+static void prvTest6_CheckAutoReloadResetBehaviour( void );
+static void prvResetStartConditionsForNextIteration( void );
+
+/*-----------------------------------------------------------*/
+
+/* Flag that will be latched to pdFAIL should any unexpected behaviour be
+detected in any of the demo tests. */
+static volatile portBASE_TYPE xTestStatus = pdPASS;
+
+/* Counter that is incremented on each cycle of a test. This is used to
+detect a stalled task - a test that is no longer running. */
+static volatile unsigned long ulLoopCounter = 0;
+
+/* A set of auto reload timers - each of which use the same callback function.
+The callback function uses the timer ID to index into, and then increment, a
+counter in the ucAutoReloadTimerCounters[] array. The auto reload timers
+referenced from xAutoReloadTimers[] are used by the prvTimerTestTask task. */
+static xTimerHandle xAutoReloadTimers[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
+static unsigned char ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH + 1 ] = { 0 };
+
+/* The one shot timer is configured to use a callback function that increments
+ucOneShotTimerCounter each time it gets called. */
+static xTimerHandle xOneShotTimer = NULL;
+static unsigned char ucOneShotTimerCounter = ( unsigned char ) 0;
+
+/* The ISR reload timer is controlled from the tick hook to exercise the timer
+API functions that can be used from an ISR. It is configured to increment
+ucISRReloadTimerCounter each time its callback function is executed. */
+static xTimerHandle xISRAutoReloadTimer = NULL;
+static unsigned char ucISRAutoReloadTimerCounter = ( unsigned char ) 0;
+
+/* The ISR one shot timer is controlled from the tick hook to exercise the timer
+API functions that can be used from an ISR. It is configured to increment
+ucISRReloadTimerCounter each time its callback function is executed. */
+static xTimerHandle xISROneShotTimer = NULL;
+static unsigned char ucISROneShotTimerCounter = ( unsigned char ) 0;
+
+/* The period of all the timers are a multiple of the base period. The base
+period is configured by the parameter to vStartTimerDemoTask(). */
+static portTickType xBasePeriod = 0;
+
+/*-----------------------------------------------------------*/
+
+void vStartTimerDemoTask( portTickType xBasePeriodIn )
+{
+ /* Start with the timer and counter arrays clear - this is only necessary
+ where the compiler does not clear them automatically on start up. */
+ memset( ucAutoReloadTimerCounters, 0x00, sizeof( ucAutoReloadTimerCounters ) );
+ memset( xAutoReloadTimers, 0x00, sizeof( xAutoReloadTimers ) );
+
+ /* Store the period from which all the timer periods will be generated from
+ (multiples of). */
+ xBasePeriod = xBasePeriodIn;
+
+ /* Create a set of timers for use by this demo/test. */
+ prvTest1_CreateTimersWithoutSchedulerRunning();
+
+ /* Create the task that will control and monitor the timers. This is
+ created at a lower priority than the timer service task to ensure, as
+ far as it is concerned, commands on timers are actioned immediately
+ (sending a command to the timer service task will unblock the timer service
+ task, which will then preempt this task). */
+ if( xTestStatus != pdFAIL )
+ {
+ xTaskCreate( prvTimerTestTask, ( signed portCHAR * ) "Tmr Tst", configMINIMAL_STACK_SIZE, NULL, configTIMER_TASK_PRIORITY - 1, NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTimerTestTask( void *pvParameters )
+{
+ ( void ) pvParameters;
+
+ /* Create a one-shot timer for use later on in this test. */
+ xOneShotTimer = xTimerCreate( ( const signed char * ) "Oneshot Timer",/* Text name to facilitate debugging. The kernel does not use this itself. */
+ tmrdemoONE_SHOT_TIMER_PERIOD, /* The period for the timer. */
+ pdFALSE, /* Don't auto-reload - hence a one shot timer. */
+ ( void * ) 0, /* The timer identifier. In this case this is not used as the timer has its own callback. */
+ prvOneShotTimerCallback ); /* The callback to be called when the timer expires. */
+
+ if( xOneShotTimer == NULL )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+
+ /* Ensure all the timers are in their expected initial state. This
+ depends on the timer service task having a higher priority than this task. */
+ prvTest2_CheckTaskAndTimersInitialState();
+
+ for( ;; )
+ {
+ /* Check the auto reload timers expire at the expected/correct rates. */
+ prvTest3_CheckAutoReloadExpireRates();
+
+ /* Check the auto reload timers can be stopped correctly, and correctly
+ report their state. */
+ prvTest4_CheckAutoReloadTimersCanBeStopped();
+
+ /* Check the one shot timer only calls its callback once after it has been
+ started, and that it reports its state correctly. */
+ prvTest5_CheckBasicOneShotTimerBehaviour();
+
+ /* Check timer reset behaviour. */
+ prvTest6_CheckAutoReloadResetBehaviour();
+
+ /* Start the timers again to restart all the tests over again. */
+ prvResetStartConditionsForNextIteration();
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* This is called to check that the created task is still running and has not
+detected any errors. */
+portBASE_TYPE xAreTimerDemoTasksStillRunning( portTickType xCycleFrequency )
+{
+static unsigned long ulLastLoopCounter = 0UL;
+portTickType xMaxBlockTimeUsedByTheseTests, xLoopCounterIncrementTimeMax;
+static portTickType xIterationsWithoutCounterIncrement = ( portTickType ) 0, xLastCycleFrequency;
+
+ if( xLastCycleFrequency != xCycleFrequency )
+ {
+ /* The cycle frequency has probably become much faster due to an error
+ elsewhere. Start counting Iterations again. */
+ xIterationsWithoutCounterIncrement = ( portTickType ) 0;
+ xLastCycleFrequency = xCycleFrequency;
+ }
+
+ /* Calculate the maximum number of times that it is permissible for this
+ function to be called without ulLoopCounter being incremented. This is
+ necessary because the tests in this file block for extended periods, and the
+ block period might be longer than the time between calls to this function. */
+ xMaxBlockTimeUsedByTheseTests = ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
+ xLoopCounterIncrementTimeMax = xMaxBlockTimeUsedByTheseTests / xCycleFrequency;
+
+ /* If the demo task is still running then we expect the loopcounter to
+ have incremented every xLoopCounterIncrementTimeMax calls. */
+ if( ulLastLoopCounter == ulLoopCounter )
+ {
+ xIterationsWithoutCounterIncrement++;
+ if( xIterationsWithoutCounterIncrement > xLoopCounterIncrementTimeMax )
+ {
+ /* The tests appear to be no longer running (stalled). */
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else
+ {
+ /* ulLoopCounter changed, so the count of times this function was called
+ without a change can be reset to zero. */
+ xIterationsWithoutCounterIncrement = ( portTickType ) 0;
+ }
+
+ ulLastLoopCounter = ulLoopCounter;
+
+ /* Errors detected in the task itself will have latched xTestStatus
+ to pdFAIL. */
+
+ return xTestStatus;
+}
+/*-----------------------------------------------------------*/
+
+static void prvTest1_CreateTimersWithoutSchedulerRunning( void )
+{
+unsigned portBASE_TYPE xTimer;
+
+ for( xTimer = 0; xTimer < configTIMER_QUEUE_LENGTH; xTimer++ )
+ {
+ /* As the timer queue is not yet full, it should be possible to both create
+ and start a timer. These timers are being started before the scheduler has
+ been started, so their block times should get set to zero within the timer
+ API itself. */
+ xAutoReloadTimers[ xTimer ] = xTimerCreate( ( const signed char * )"FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
+ ( ( xTimer + ( portTickType ) 1 ) * xBasePeriod ),/* The period for the timer. The plus 1 ensures a period of zero is not specified. */
+ pdTRUE, /* Auto-reload is set to true. */
+ ( void * ) xTimer, /* An identifier for the timer as all the auto reload timers use the same callback. */
+ prvAutoReloadTimerCallback ); /* The callback to be called when the timer expires. */
+
+ if( xAutoReloadTimers[ xTimer ] == NULL )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ else
+ {
+ /* The scheduler has not yet started, so the block period of
+ portMAX_DELAY should just get set to zero in xTimerStart(). Also,
+ the timer queue is not yet full so xTimerStart() should return
+ pdPASS. */
+ if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) != pdPASS )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ }
+
+ /* The timers queue should now be full, so it should be possible to create
+ another timer, but not possible to start it (the timer queue will not get
+ drained until the scheduler has been started. */
+ xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] = xTimerCreate( ( const signed char * ) "FR Timer", /* Text name to facilitate debugging. The kernel does not use this itself. */
+ ( configTIMER_QUEUE_LENGTH * xBasePeriod ), /* The period for the timer. */
+ pdTRUE, /* Auto-reload is set to true. */
+ ( void * ) xTimer, /* An identifier for the timer as all the auto reload timers use the same callback. */
+ prvAutoReloadTimerCallback ); /* The callback executed when the timer expires. */
+
+ if( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] == NULL )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ else
+ {
+ if( xTimerStart( xAutoReloadTimers[ xTimer ], portMAX_DELAY ) == pdPASS )
+ {
+ /* This time it would not be expected that the timer could be
+ started at this point. */
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+
+ /* Create the timers that are used from the tick interrupt to test the timer
+ API functions that can be called from an ISR. */
+ xISRAutoReloadTimer = xTimerCreate( ( const signed char * ) "ISR AR", /* The text name given to the timer. */
+ 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
+ pdTRUE, /* This is an auto reload timer. */
+ ( void * ) NULL, /* The identifier is not required. */
+ prvISRAutoReloadTimerCallback ); /* The callback that is executed when the timer expires. */
+
+ xISROneShotTimer = xTimerCreate( ( const signed char * ) "ISR OS", /* The text name given to the timer. */
+ 0xffff, /* The timer is not given a period yet - this will be done from the tick hook, but a period of 0 is invalid. */
+ pdFALSE, /* This is a one shot timer. */
+ ( void * ) NULL, /* The identifier is not required. */
+ prvISROneShotTimerCallback ); /* The callback that is executed when the timer expires. */
+
+ if( ( xISRAutoReloadTimer == NULL ) || ( xISROneShotTimer == NULL ) )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTest2_CheckTaskAndTimersInitialState( void )
+{
+unsigned char ucTimer;
+
+ /* Ensure all the timers are in their expected initial state. This depends
+ on the timer service task having a higher priority than this task.
+
+ auto reload timers 0 to ( configTIMER_QUEUE_LENGTH - 1 ) should now be active,
+ and auto reload timer configTIMER_QUEUE_LENGTH should not yet be active (it
+ could not be started prior to the scheduler being started when it was
+ created). */
+ for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
+ {
+ if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+
+ if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH ] ) != pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTest3_CheckAutoReloadExpireRates( void )
+{
+unsigned char ucMaxAllowableValue, ucMinAllowableValue, ucTimer;
+portTickType xBlockPeriod, xTimerPeriod, xExpectedNumber;
+
+ /* Check the auto reload timers expire at the expected rates. */
+
+
+ /* Delaying for configTIMER_QUEUE_LENGTH * xBasePeriod ticks should allow
+ all the auto reload timers to expire at least once. */
+ xBlockPeriod = ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod;
+ vTaskDelay( xBlockPeriod );
+
+ /* Check that all the auto reload timers have called their callback
+ function the expected number of times. */
+ for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
+ {
+ /* The expected number of expiries is equal to the block period divided
+ by the timer period. */
+ xTimerPeriod = ( ( ( portTickType ) ucTimer + ( portTickType ) 1 ) * xBasePeriod );
+ xExpectedNumber = xBlockPeriod / xTimerPeriod;
+
+ ucMaxAllowableValue = ( ( unsigned char ) xExpectedNumber ) ;
+ ucMinAllowableValue = ( ( unsigned char ) xExpectedNumber - ( unsigned char ) 1 );
+
+ if( ( ucAutoReloadTimerCounters[ ucTimer ] < ucMinAllowableValue ) ||
+ ( ucAutoReloadTimerCounters[ ucTimer ] > ucMaxAllowableValue )
+ )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+
+ if( xTestStatus == pdPASS )
+ {
+ /* No errors have been reported so increment the loop counter so the
+ check task knows this task is still running. */
+ ulLoopCounter++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTest4_CheckAutoReloadTimersCanBeStopped( void )
+{
+unsigned char ucTimer;
+
+ /* Check the auto reload timers can be stopped correctly, and correctly
+ report their state. */
+
+ /* Stop all the active timers. */
+ for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
+ {
+ /* The timer has not been stopped yet! */
+ if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Now stop the timer. This will appear to happen immediately to
+ this task because this task is running at a priority below the
+ timer service task. */
+ xTimerStop( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
+
+ /* The timer should now be inactive. */
+ if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+
+ taskENTER_CRITICAL();
+ {
+ /* The timer in array position configTIMER_QUEUE_LENGTH should not
+ be active. The critical section is used to ensure the timer does
+ not call its callback between the next line running and the array
+ being cleared back to zero, as that would mask an error condition. */
+ if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH ] != ( unsigned char ) 0 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Clear the timer callback count. */
+ memset( ( void * ) ucAutoReloadTimerCounters, 0, sizeof( ucAutoReloadTimerCounters ) );
+ }
+ taskEXIT_CRITICAL();
+
+ /* The timers are now all inactive, so this time, after delaying, none
+ of the callback counters should have incremented. */
+ vTaskDelay( ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
+ for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
+ {
+ if( ucAutoReloadTimerCounters[ ucTimer ] != ( unsigned char ) 0 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+
+ if( xTestStatus == pdPASS )
+ {
+ /* No errors have been reported so increment the loop counter so
+ the check task knows this task is still running. */
+ ulLoopCounter++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTest5_CheckBasicOneShotTimerBehaviour( void )
+{
+ /* Check the one shot timer only calls its callback once after it has been
+ started, and that it reports its state correctly. */
+
+ /* The one shot timer should not be active yet. */
+ if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucOneShotTimerCounter != ( unsigned char ) 0 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Start the one shot timer and check that it reports its state correctly. */
+ xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
+ if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Delay for three times as long as the one shot timer period, then check
+ to ensure it has only called its callback once, and is now not in the
+ active state. */
+ vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD * ( portTickType ) 3 );
+
+ if( xTimerIsTimerActive( xOneShotTimer ) != pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucOneShotTimerCounter != ( unsigned char ) 1 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ else
+ {
+ /* Reset the one shot timer callback count. */
+ ucOneShotTimerCounter = ( unsigned char ) 0;
+ }
+
+ if( xTestStatus == pdPASS )
+ {
+ /* No errors have been reported so increment the loop counter so the
+ check task knows this task is still running. */
+ ulLoopCounter++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvTest6_CheckAutoReloadResetBehaviour( void )
+{
+unsigned char ucTimer;
+
+ /* Check timer reset behaviour. */
+
+ /* Restart the one shot timer and check it reports its status correctly. */
+ xTimerStart( xOneShotTimer, tmrdemoDONT_BLOCK );
+ if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Restart one of the auto reload timers and check that it reports its
+ status correctly. */
+ xTimerStart( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
+ if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ for( ucTimer = 0; ucTimer < trmdemoNUM_TIMER_RESETS; ucTimer++ )
+ {
+ /* Delay for half as long as the one shot timer period, then reset it.
+ It should never expire while this is done, so its callback count should
+ never increment. */
+ vTaskDelay( tmrdemoONE_SHOT_TIMER_PERIOD / 2 );
+
+ /* Check both running timers are still active, but have not called their
+ callback functions. */
+ if( xTimerIsTimerActive( xOneShotTimer ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucOneShotTimerCounter != ( unsigned char ) 0 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] != ( unsigned char ) 0 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Reset both running timers. */
+ xTimerReset( xOneShotTimer, tmrdemoDONT_BLOCK );
+ xTimerReset( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
+
+ if( xTestStatus == pdPASS )
+ {
+ /* No errors have been reported so increment the loop counter so
+ the check task knows this task is still running. */
+ ulLoopCounter++;
+ }
+ }
+
+ /* Finally delay long enough for both running timers to expire. */
+ vTaskDelay( ( ( portTickType ) configTIMER_QUEUE_LENGTH ) * xBasePeriod );
+
+ /* The timers were not reset during the above delay period so should now
+ both have called their callback functions. */
+ if( ucOneShotTimerCounter != ( unsigned char ) 1 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] == 0 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* The one shot timer should no longer be active, while the auto reload
+ timer should still be active. */
+ if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( xTimerIsTimerActive( xOneShotTimer ) == pdTRUE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Stop the auto reload timer again. */
+ xTimerStop( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ], tmrdemoDONT_BLOCK );
+
+ if( xTimerIsTimerActive( xAutoReloadTimers[ configTIMER_QUEUE_LENGTH - 1 ] ) != pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Clear the timer callback counts, ready for another iteration of these
+ tests. */
+ ucAutoReloadTimerCounters[ configTIMER_QUEUE_LENGTH - 1 ] = ( unsigned char ) 0;
+ ucOneShotTimerCounter = ( unsigned char ) 0;
+
+ if( xTestStatus == pdPASS )
+ {
+ /* No errors have been reported so increment the loop counter so the check
+ task knows this task is still running. */
+ ulLoopCounter++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvResetStartConditionsForNextIteration( void )
+{
+unsigned char ucTimer;
+
+ /* Start the timers again to start all the tests over again. */
+
+ /* Start the timers again. */
+ for( ucTimer = 0; ucTimer < ( unsigned char ) configTIMER_QUEUE_LENGTH; ucTimer++ )
+ {
+ /* The timer has not been started yet! */
+ if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) != pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Now start the timer. This will appear to happen immediately to
+ this task because this task is running at a priority below the timer
+ service task. */
+ xTimerStart( xAutoReloadTimers[ ucTimer ], tmrdemoDONT_BLOCK );
+
+ /* The timer should now be active. */
+ if( xTimerIsTimerActive( xAutoReloadTimers[ ucTimer ] ) == pdFALSE )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+
+ if( xTestStatus == pdPASS )
+ {
+ /* No errors have been reported so increment the loop counter so the
+ check task knows this task is still running. */
+ ulLoopCounter++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+void vTimerPeriodicISRTests( void )
+{
+static portTickType uxTick = ( portTickType ) -1;
+
+/* The xHigherPriorityTaskWoken parameter is not used in this case as this
+function is called from the tick hook anyway. However the API required it
+to be present. */
+signed portBASE_TYPE xHigherPriorityTaskWoken = pdFALSE;
+portTickType xMargin;
+
+ if( configTIMER_TASK_PRIORITY != ( configMAX_PRIORITIES - 1 ) )
+ {
+ /* The timer service task is not the highest priority task, so it cannot
+ be assumed that timings will be exact. Timers should never call their
+ callback before their expiry time, but a margin is permissible for calling
+ their callback after their expiry time. If exact timing is required then
+ configTIMER_TASK_PRIORITY must be set to ensure the timer service task
+ is the highest priority task in the system. */
+ xMargin = 5;
+ }
+ else
+ {
+ xMargin = 1;
+ }
+
+ /* This test is called from the tick ISR even when the scheduler is suspended.
+ Therefore, it is possible for the xTickCount to be temporarily less than the
+ uxTicks count maintained in this function. That can result in calculated
+ unblock times being too short, as this function is not called as missed ticks
+ (ticks that occur while the scheduler is suspended) are unwound to re-instate
+ the real tick value. Therefore, if this happens, just abandon the test
+ and start again. */
+ if( xTaskGetSchedulerState() != taskSCHEDULER_RUNNING )
+ {
+ uxTick = ( portTickType ) -1;
+ }
+ else
+ {
+ uxTick++;
+ }
+
+ if( uxTick == 0 )
+ {
+ /* The timers will have been created, but not started. Start them
+ now by setting their period. */
+ ucISRAutoReloadTimerCounter = 0;
+ ucISROneShotTimerCounter = 0;
+ xTimerChangePeriodFromISR( xISRAutoReloadTimer, xBasePeriod, &xHigherPriorityTaskWoken );
+ xTimerChangePeriodFromISR( xISROneShotTimer, xBasePeriod, &xHigherPriorityTaskWoken );
+ }
+ else if( uxTick == xBasePeriod )
+ {
+ /* Neither timer should have expired yet. */
+ if( ( ucISRAutoReloadTimerCounter != 0 ) || ( ucISROneShotTimerCounter != 0 ) )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else if( uxTick == ( xBasePeriod + xMargin ) )
+ {
+ /* Both timers should now have expired once. The auto reload timer will
+ still be active, but the one shot timer should now have stopped. */
+ if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else if( uxTick == ( 2 * xBasePeriod ) )
+ {
+ /* The auto reload timer will still be active, but the one shot timer
+ should now have stopped - however, at this time neither of the timers
+ should have expired again since the last test. */
+ if( ( ucISRAutoReloadTimerCounter != 1 ) || ( ucISROneShotTimerCounter != 1 ) )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else if( uxTick == ( ( 2 * xBasePeriod ) + xMargin ) )
+ {
+ /* The auto reload timer will still be active, but the one shot timer
+ should now have stopped. At this time the auto reload timer should have
+ expired again, but the one shot timer count should not have changed. */
+ if( ucISRAutoReloadTimerCounter != 2 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 1 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else if( uxTick == ( ( 2 * xBasePeriod ) + ( xBasePeriod >> ( portTickType ) 2U ) ) )
+ {
+ /* The auto reload timer will still be active, but the one shot timer
+ should now have stopped. Again though, at this time, neither timer call
+ back should have been called since the last test. */
+ if( ucISRAutoReloadTimerCounter != 2 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 1 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else if( uxTick == ( 3 * xBasePeriod ) )
+ {
+ /* Start the one shot timer again. */
+ xTimerStartFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
+ }
+ else if( uxTick == ( ( 3 * xBasePeriod ) + xMargin ) )
+ {
+ /* The auto reload timer and one shot timer will be active. At
+ this time the auto reload timer should have expired again, but the one
+ shot timer count should not have changed yet. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 1 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Now stop the auto reload timer. The one shot timer was started
+ a few ticks ago. */
+ xTimerStopFromISR( xISRAutoReloadTimer, &xHigherPriorityTaskWoken );
+ }
+ else if( uxTick == ( 4 * xBasePeriod ) )
+ {
+ /* The auto reload timer is now stopped, and the one shot timer is
+ active, but at this time neither timer should have expired since the
+ last test. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 1 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else if( uxTick == ( ( 4 * xBasePeriod ) + xMargin ) )
+ {
+ /* The auto reload timer is now stopped, and the one shot timer is
+ active. The one shot timer should have expired again, but the auto
+ reload timer should not have executed its callback. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 2 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else if( uxTick == ( ( 8 * xBasePeriod ) + xMargin ) )
+ {
+ /* The auto reload timer is now stopped, and the one shot timer has
+ already expired and then stopped itself. Both callback counters should
+ not have incremented since the last test. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 2 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ /* Now reset the one shot timer. */
+ xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
+ }
+ else if( uxTick == ( 9 * xBasePeriod ) )
+ {
+ /* Only the one shot timer should be running, but it should not have
+ expired since the last test. Check the callback counters have not
+ incremented, then reset the one shot timer again. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 2 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
+ }
+ else if( uxTick == ( 10 * xBasePeriod ) )
+ {
+ /* Only the one shot timer should be running, but it should not have
+ expired since the last test. Check the callback counters have not
+ incremented, then reset the one shot timer again. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 2 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
+ }
+ else if( uxTick == ( 11 * xBasePeriod ) )
+ {
+ /* Only the one shot timer should be running, but it should not have
+ expired since the last test. Check the callback counters have not
+ incremented, then reset the one shot timer once again. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 2 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ xTimerResetFromISR( xISROneShotTimer, &xHigherPriorityTaskWoken );
+ }
+ else if( uxTick == ( ( 12 * xBasePeriod ) + xMargin ) )
+ {
+ /* Only the one shot timer should have been running and this time it
+ should have expired. Check its callback count has been incremented.
+ The auto reload timer is still not running so should still have the same
+ count value. This time the one shot timer is not reset so should not
+ restart from its expiry period again. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+ }
+ else if( uxTick == ( 15 * xBasePeriod ) )
+ {
+ /* Neither timer should be running now. Check neither callback count
+ has incremented, then go back to the start to run these tests all
+ over again. */
+ if( ucISRAutoReloadTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ if( ucISROneShotTimerCounter != 3 )
+ {
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+
+ uxTick = ( portTickType ) -1;
+ }
+}
+/*-----------------------------------------------------------*/
+
+/*** Timer callback functions are defined below here. ***/
+
+static void prvAutoReloadTimerCallback( xTimerHandle pxExpiredTimer )
+{
+unsigned long ulTimerID;
+
+ ulTimerID = ( unsigned long ) pvTimerGetTimerID( pxExpiredTimer );
+ if( ulTimerID <= ( configTIMER_QUEUE_LENGTH + 1 ) )
+ {
+ ( ucAutoReloadTimerCounters[ ulTimerID ] )++;
+ }
+ else
+ {
+ /* The timer ID appears to be unexpected (invalid). */
+ xTestStatus = pdFAIL;
+ configASSERT( xTestStatus );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvOneShotTimerCallback( xTimerHandle pxExpiredTimer )
+{
+ /* The parameter is not used in this case as only one timer uses this
+ callback function. */
+ ( void ) pxExpiredTimer;
+
+ ucOneShotTimerCounter++;
+}
+/*-----------------------------------------------------------*/
+
+static void prvISRAutoReloadTimerCallback( xTimerHandle pxExpiredTimer )
+{
+ /* The parameter is not used in this case as only one timer uses this
+ callback function. */
+ ( void ) pxExpiredTimer;
+
+ ucISRAutoReloadTimerCounter++;
+}
+/*-----------------------------------------------------------*/
+
+static void prvISROneShotTimerCallback( xTimerHandle pxExpiredTimer )
+{
+ /* The parameter is not used in this case as only one timer uses this
+ callback function. */
+ ( void ) pxExpiredTimer;
+
+ ucISROneShotTimerCounter++;
+}
+/*-----------------------------------------------------------*/
+
+
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/blocktim.c b/third_party/FreeRTOS/Demo/Common/Minimal/blocktim.c new file mode 100644 index 0000000..cef2ba6 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/blocktim.c @@ -0,0 +1,505 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This file contains some test scenarios that ensure tasks do not exit queue
+ * send or receive functions prematurely. A description of the tests is
+ * included within the code.
+ */
+
+/* Kernel includes. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "queue.h"
+
+/* Demo includes. */
+#include "blocktim.h"
+
+/* Task priorities. Allow these to be overridden. */
+#ifndef bktPRIMARY_PRIORITY
+ #define bktPRIMARY_PRIORITY ( configMAX_PRIORITIES - 3 )
+#endif
+
+#ifndef bktSECONDARY_PRIORITY
+ #define bktSECONDARY_PRIORITY ( configMAX_PRIORITIES - 4 )
+#endif
+
+/* Task behaviour. */
+#define bktQUEUE_LENGTH ( 5 )
+#define bktSHORT_WAIT ( ( ( portTickType ) 20 ) / portTICK_RATE_MS )
+#define bktPRIMARY_BLOCK_TIME ( 10 )
+#define bktALLOWABLE_MARGIN ( 15 )
+#define bktTIME_TO_BLOCK ( 175 )
+#define bktDONT_BLOCK ( ( portTickType ) 0 )
+#define bktRUN_INDICATOR ( ( unsigned portBASE_TYPE ) 0x55 )
+
+/* The queue on which the tasks block. */
+static xQueueHandle xTestQueue;
+
+/* Handle to the secondary task is required by the primary task for calls
+to vTaskSuspend/Resume(). */
+static xTaskHandle xSecondary;
+
+/* Used to ensure that tasks are still executing without error. */
+static volatile portBASE_TYPE xPrimaryCycles = 0, xSecondaryCycles = 0;
+static volatile portBASE_TYPE xErrorOccurred = pdFALSE;
+
+/* Provides a simple mechanism for the primary task to know when the
+secondary task has executed. */
+static volatile unsigned portBASE_TYPE xRunIndicator;
+
+/* The two test tasks. Their behaviour is commented within the files. */
+static void vPrimaryBlockTimeTestTask( void *pvParameters );
+static void vSecondaryBlockTimeTestTask( void *pvParameters );
+
+/*-----------------------------------------------------------*/
+
+void vCreateBlockTimeTasks( void )
+{
+ /* Create the queue on which the two tasks block. */
+ xTestQueue = xQueueCreate( bktQUEUE_LENGTH, sizeof( portBASE_TYPE ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xTestQueue, ( signed char * ) "Block_Time_Queue" );
+
+ /* Create the two test tasks. */
+ xTaskCreate( vPrimaryBlockTimeTestTask, ( signed char * )"BTest1", configMINIMAL_STACK_SIZE, NULL, bktPRIMARY_PRIORITY, NULL );
+ xTaskCreate( vSecondaryBlockTimeTestTask, ( signed char * )"BTest2", configMINIMAL_STACK_SIZE, NULL, bktSECONDARY_PRIORITY, &xSecondary );
+}
+/*-----------------------------------------------------------*/
+
+static void vPrimaryBlockTimeTestTask( void *pvParameters )
+{
+portBASE_TYPE xItem, xData;
+portTickType xTimeWhenBlocking;
+portTickType xTimeToBlock, xBlockedTime;
+
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /*********************************************************************
+ Test 1
+
+ Simple block time wakeup test on queue receives. */
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ /* The queue is empty. Attempt to read from the queue using a block
+ time. When we wake, ensure the delta in time is as expected. */
+ xTimeToBlock = ( portTickType ) ( bktPRIMARY_BLOCK_TIME << xItem );
+
+ xTimeWhenBlocking = xTaskGetTickCount();
+
+ /* We should unblock after xTimeToBlock having not received
+ anything on the queue. */
+ if( xQueueReceive( xTestQueue, &xData, xTimeToBlock ) != errQUEUE_EMPTY )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* How long were we blocked for? */
+ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
+
+ if( xBlockedTime < xTimeToBlock )
+ {
+ /* Should not have blocked for less than we requested. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
+ {
+ /* Should not have blocked for longer than we requested,
+ although we would not necessarily run as soon as we were
+ unblocked so a margin is allowed. */
+ xErrorOccurred = pdTRUE;
+ }
+ }
+
+ /*********************************************************************
+ Test 2
+
+ Simple block time wakeup test on queue sends.
+
+ First fill the queue. It should be empty so all sends should pass. */
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+ }
+
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ /* The queue is full. Attempt to write to the queue using a block
+ time. When we wake, ensure the delta in time is as expected. */
+ xTimeToBlock = ( portTickType ) ( bktPRIMARY_BLOCK_TIME << xItem );
+
+ xTimeWhenBlocking = xTaskGetTickCount();
+
+ /* We should unblock after xTimeToBlock having not received
+ anything on the queue. */
+ if( xQueueSend( xTestQueue, &xItem, xTimeToBlock ) != errQUEUE_FULL )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* How long were we blocked for? */
+ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
+
+ if( xBlockedTime < xTimeToBlock )
+ {
+ /* Should not have blocked for less than we requested. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ if( xBlockedTime > ( xTimeToBlock + bktALLOWABLE_MARGIN ) )
+ {
+ /* Should not have blocked for longer than we requested,
+ although we would not necessarily run as soon as we were
+ unblocked so a margin is allowed. */
+ xErrorOccurred = pdTRUE;
+ }
+ }
+
+ /*********************************************************************
+ Test 3
+
+ Wake the other task, it will block attempting to post to the queue.
+ When we read from the queue the other task will wake, but before it
+ can run we will post to the queue again. When the other task runs it
+ will find the queue still full, even though it was woken. It should
+ recognise that its block time has not expired and return to block for
+ the remains of its block time.
+
+ Wake the other task so it blocks attempting to post to the already
+ full queue. */
+ xRunIndicator = 0;
+ vTaskResume( xSecondary );
+
+ /* We need to wait a little to ensure the other task executes. */
+ while( xRunIndicator != bktRUN_INDICATOR )
+ {
+ /* The other task has not yet executed. */
+ vTaskDelay( bktSHORT_WAIT );
+ }
+ /* Make sure the other task is blocked on the queue. */
+ vTaskDelay( bktSHORT_WAIT );
+ xRunIndicator = 0;
+
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ /* Now when we make space on the queue the other task should wake
+ but not execute as this task has higher priority. */
+ if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Now fill the queue again before the other task gets a chance to
+ execute. If the other task had executed we would find the queue
+ full ourselves, and the other task have set xRunIndicator. */
+ if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ if( xRunIndicator == bktRUN_INDICATOR )
+ {
+ /* The other task should not have executed. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Raise the priority of the other task so it executes and blocks
+ on the queue again. */
+ vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
+
+ /* The other task should now have re-blocked without exiting the
+ queue function. */
+ if( xRunIndicator == bktRUN_INDICATOR )
+ {
+ /* The other task should not have executed outside of the
+ queue function. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Set the priority back down. */
+ vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
+ }
+
+ /* Let the other task timeout. When it unblockes it will check that it
+ unblocked at the correct time, then suspend itself. */
+ while( xRunIndicator != bktRUN_INDICATOR )
+ {
+ vTaskDelay( bktSHORT_WAIT );
+ }
+ vTaskDelay( bktSHORT_WAIT );
+ xRunIndicator = 0;
+
+
+ /*********************************************************************
+ Test 4
+
+ As per test 3 - but with the send and receive the other way around.
+ The other task blocks attempting to read from the queue.
+
+ Empty the queue. We should find that it is full. */
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+ }
+
+ /* Wake the other task so it blocks attempting to read from the
+ already empty queue. */
+ vTaskResume( xSecondary );
+
+ /* We need to wait a little to ensure the other task executes. */
+ while( xRunIndicator != bktRUN_INDICATOR )
+ {
+ vTaskDelay( bktSHORT_WAIT );
+ }
+ vTaskDelay( bktSHORT_WAIT );
+ xRunIndicator = 0;
+
+ for( xItem = 0; xItem < bktQUEUE_LENGTH; xItem++ )
+ {
+ /* Now when we place an item on the queue the other task should
+ wake but not execute as this task has higher priority. */
+ if( xQueueSend( xTestQueue, &xItem, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Now empty the queue again before the other task gets a chance to
+ execute. If the other task had executed we would find the queue
+ empty ourselves, and the other task would be suspended. */
+ if( xQueueReceive( xTestQueue, &xData, bktDONT_BLOCK ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ if( xRunIndicator == bktRUN_INDICATOR )
+ {
+ /* The other task should not have executed. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Raise the priority of the other task so it executes and blocks
+ on the queue again. */
+ vTaskPrioritySet( xSecondary, bktPRIMARY_PRIORITY + 2 );
+
+ /* The other task should now have re-blocked without exiting the
+ queue function. */
+ if( xRunIndicator == bktRUN_INDICATOR )
+ {
+ /* The other task should not have executed outside of the
+ queue function. */
+ xErrorOccurred = pdTRUE;
+ }
+ vTaskPrioritySet( xSecondary, bktSECONDARY_PRIORITY );
+ }
+
+ /* Let the other task timeout. When it unblockes it will check that it
+ unblocked at the correct time, then suspend itself. */
+ while( xRunIndicator != bktRUN_INDICATOR )
+ {
+ vTaskDelay( bktSHORT_WAIT );
+ }
+ vTaskDelay( bktSHORT_WAIT );
+
+ xPrimaryCycles++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void vSecondaryBlockTimeTestTask( void *pvParameters )
+{
+portTickType xTimeWhenBlocking, xBlockedTime;
+portBASE_TYPE xData;
+
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /*********************************************************************
+ Test 1 and 2
+
+ This task does does not participate in these tests. */
+ vTaskSuspend( NULL );
+
+ /*********************************************************************
+ Test 3
+
+ The first thing we do is attempt to read from the queue. It should be
+ full so we block. Note the time before we block so we can check the
+ wake time is as per that expected. */
+ xTimeWhenBlocking = xTaskGetTickCount();
+
+ /* We should unblock after bktTIME_TO_BLOCK having not sent
+ anything to the queue. */
+ xData = 0;
+ xRunIndicator = bktRUN_INDICATOR;
+ if( xQueueSend( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_FULL )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* How long were we inside the send function? */
+ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
+
+ /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
+ if( xBlockedTime < bktTIME_TO_BLOCK )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
+ either. A margin is permitted as we would not necessarily run as
+ soon as we unblocked. */
+ if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Suspend ready for test 3. */
+ xRunIndicator = bktRUN_INDICATOR;
+ vTaskSuspend( NULL );
+
+ /*********************************************************************
+ Test 4
+
+ As per test three, but with the send and receive reversed. */
+ xTimeWhenBlocking = xTaskGetTickCount();
+
+ /* We should unblock after bktTIME_TO_BLOCK having not received
+ anything on the queue. */
+ xRunIndicator = bktRUN_INDICATOR;
+ if( xQueueReceive( xTestQueue, &xData, bktTIME_TO_BLOCK ) != errQUEUE_EMPTY )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ xBlockedTime = xTaskGetTickCount() - xTimeWhenBlocking;
+
+ /* We should not have blocked for less time than bktTIME_TO_BLOCK. */
+ if( xBlockedTime < bktTIME_TO_BLOCK )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* We should of not blocked for much longer than bktALLOWABLE_MARGIN
+ either. A margin is permitted as we would not necessarily run as soon
+ as we unblocked. */
+ if( xBlockedTime > ( bktTIME_TO_BLOCK + bktALLOWABLE_MARGIN ) )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ xRunIndicator = bktRUN_INDICATOR;
+
+ xSecondaryCycles++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xAreBlockTimeTestTasksStillRunning( void )
+{
+static portBASE_TYPE xLastPrimaryCycleCount = 0, xLastSecondaryCycleCount = 0;
+portBASE_TYPE xReturn = pdPASS;
+
+ /* Have both tasks performed at least one cycle since this function was
+ last called? */
+ if( xPrimaryCycles == xLastPrimaryCycleCount )
+ {
+ xReturn = pdFAIL;
+ }
+
+ if( xSecondaryCycles == xLastSecondaryCycleCount )
+ {
+ xReturn = pdFAIL;
+ }
+
+ if( xErrorOccurred == pdTRUE )
+ {
+ xReturn = pdFAIL;
+ }
+
+ xLastSecondaryCycleCount = xSecondaryCycles;
+ xLastPrimaryCycleCount = xPrimaryCycles;
+
+ return xReturn;
+}
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/comtest.c b/third_party/FreeRTOS/Demo/Common/Minimal/comtest.c new file mode 100644 index 0000000..3295535 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/comtest.c @@ -0,0 +1,303 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+
+/*
+ * This version of comtest. c is for use on systems that have limited stack
+ * space and no display facilities. The complete version can be found in
+ * the Demo/Common/Full directory.
+ *
+ * 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 posts a sequence of characters to the Tx queue, toggling an
+ * LED on each successful post. At the end of the sequence it sleeps for a
+ * pseudo-random period before resending the same sequence.
+ *
+ * The UART Tx end interrupt is enabled whenever data is available in the Tx
+ * queue. The Tx end ISR removes a single character from the Tx queue and
+ * passes it to the UART for transmission.
+ *
+ * The second task blocks on the Rx queue waiting for a character to become
+ * available. When the UART Rx end interrupt receives a character it places
+ * it in the Rx queue, waking the second task. The second task checks that the
+ * characters removed from the Rx queue form the same sequence as those posted
+ * to the Tx queue, and toggles an LED for each correct character.
+ *
+ * The receiving task is spawned with a higher priority than the transmitting
+ * task. The receiver will therefore wake every time a character is
+ * transmitted so neither the Tx or Rx queue should ever hold more than a few
+ * characters.
+ *
+ */
+
+/* Scheduler include files. */
+#include <stdlib.h>
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Demo program include files. */
+#include "serial.h"
+#include "comtest.h"
+#include "partest.h"
+
+#define comSTACK_SIZE configMINIMAL_STACK_SIZE
+#define comTX_LED_OFFSET ( 0 )
+#define comRX_LED_OFFSET ( 1 )
+#define comTOTAL_PERMISSIBLE_ERRORS ( 2 )
+
+/* 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 ( ( portTickType ) 0x96 )
+#define comTX_MIN_BLOCK_TIME ( ( portTickType ) 0x32 )
+#define comOFFSET_TIME ( ( portTickType ) 3 )
+
+/* We should find that each character can be queued for Tx immediately and we
+don't have to block to send. */
+#define comNO_BLOCK ( ( portTickType ) 0 )
+
+/* The Rx task will block on the Rx queue for a long period. */
+#define comRX_BLOCK_TIME ( ( portTickType ) 0xffff )
+
+/* The sequence transmitted is from comFIRST_BYTE to and including comLAST_BYTE. */
+#define comFIRST_BYTE ( 'A' )
+#define comLAST_BYTE ( 'X' )
+
+#define comBUFFER_LEN ( ( unsigned portBASE_TYPE ) ( comLAST_BYTE - comFIRST_BYTE ) + ( unsigned portBASE_TYPE ) 1 )
+#define comINITIAL_RX_COUNT_VALUE ( 0 )
+
+/* Handle to the com port used by both tasks. */
+static xComPortHandle xPort = NULL;
+
+/* The transmit task as described at the top of the file. */
+static portTASK_FUNCTION_PROTO( vComTxTask, pvParameters );
+
+/* The receive task as described at the top of the file. */
+static portTASK_FUNCTION_PROTO( vComRxTask, pvParameters );
+
+/* The LED that should be toggled by the Rx and Tx tasks. The Rx task will
+toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task will toggle LED
+( uxBaseLED + comTX_LED_OFFSET ). */
+static unsigned portBASE_TYPE uxBaseLED = 0;
+
+/* Check variable used to ensure no error have occurred. The Rx task will
+increment this variable after every successfully received sequence. If at any
+time the sequence is incorrect the the variable will stop being incremented. */
+static volatile unsigned portBASE_TYPE uxRxLoops = comINITIAL_RX_COUNT_VALUE;
+
+/*-----------------------------------------------------------*/
+
+void vAltStartComTestTasks( unsigned portBASE_TYPE uxPriority, unsigned long ulBaudRate, unsigned portBASE_TYPE uxLED )
+{
+ /* Initialise the com port then spawn the Rx and Tx tasks. */
+ uxBaseLED = uxLED;
+ xSerialPortInitMinimal( ulBaudRate, comBUFFER_LEN );
+
+ /* The Tx task is spawned with a lower priority than the Rx task. */
+ xTaskCreate( vComTxTask, ( signed char * ) "COMTx", comSTACK_SIZE, NULL, uxPriority - 1, ( xTaskHandle * ) NULL );
+ xTaskCreate( vComRxTask, ( signed char * ) "COMRx", comSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vComTxTask, pvParameters )
+{
+signed char cByteToSend;
+portTickType xTimeToWait;
+
+ /* Just to stop compiler warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* Simply transmit a sequence of characters from comFIRST_BYTE to
+ comLAST_BYTE. */
+ for( cByteToSend = comFIRST_BYTE; cByteToSend <= comLAST_BYTE; cByteToSend++ )
+ {
+ if( xSerialPutChar( xPort, cByteToSend, comNO_BLOCK ) == pdPASS )
+ {
+ vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
+ }
+ }
+
+ /* Turn the LED off while we are not doing anything. */
+ vParTestSetLED( uxBaseLED + comTX_LED_OFFSET, pdFALSE );
+
+ /* We have posted all the characters in the string - wait before
+ re-sending. Wait a pseudo-random time as this will provide a better
+ test. */
+ xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
+
+ /* 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 portTASK_FUNCTION( vComRxTask, pvParameters )
+{
+signed char cExpectedByte, cByteRxed;
+portBASE_TYPE xResyncRequired = pdFALSE, xErrorOccurred = pdFALSE;
+
+ /* Just to stop compiler warnings. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* We expect to receive the characters from comFIRST_BYTE to
+ comLAST_BYTE in an incrementing order. Loop to receive each byte. */
+ for( cExpectedByte = comFIRST_BYTE; cExpectedByte <= comLAST_BYTE; cExpectedByte++ )
+ {
+ /* Block on the queue that contains received bytes until a byte is
+ available. */
+ if( xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME ) )
+ {
+ /* Was this the byte we were expecting? If so, toggle the LED,
+ otherwise we are out on sync and should break out of the loop
+ until the expected character sequence is about to restart. */
+ if( cByteRxed == cExpectedByte )
+ {
+ vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
+ }
+ else
+ {
+ xResyncRequired = pdTRUE;
+ break; /*lint !e960 Non-switch break allowed. */
+ }
+ }
+ }
+
+ /* Turn the LED off while we are not doing anything. */
+ vParTestSetLED( uxBaseLED + comRX_LED_OFFSET, pdFALSE );
+
+ /* Did we break out of the loop because the characters were received in
+ an unexpected order? If so wait here until the character sequence is
+ about to restart. */
+ if( xResyncRequired == pdTRUE )
+ {
+ while( cByteRxed != comLAST_BYTE )
+ {
+ /* Block until the next char is available. */
+ xSerialGetChar( xPort, &cByteRxed, comRX_BLOCK_TIME );
+ }
+
+ /* Note that an error occurred which caused us to have to resync.
+ We use this to stop incrementing the loop counter so
+ sAreComTestTasksStillRunning() will return false - indicating an
+ error. */
+ xErrorOccurred++;
+
+ /* We have now resynced with the Tx task and can continue. */
+ xResyncRequired = pdFALSE;
+ }
+ else
+ {
+ if( xErrorOccurred < comTOTAL_PERMISSIBLE_ERRORS )
+ {
+ /* Increment the count of successful loops. As error
+ occurring (i.e. an unexpected character being received) will
+ prevent this counter being incremented for the rest of the
+ execution. Don't worry about mutual exclusion on this
+ variable - it doesn't really matter as we just want it
+ to change. */
+ uxRxLoops++;
+ }
+ }
+ }
+} /*lint !e715 !e818 pvParameters is required for a task function even if it is not referenced. */
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xAreComTestTasksStillRunning( void )
+{
+portBASE_TYPE xReturn;
+
+ /* If the count of successful reception loops has not changed than at
+ some time an error occurred (i.e. a character was received out of sequence)
+ and we will return false. */
+ if( uxRxLoops == comINITIAL_RX_COUNT_VALUE )
+ {
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+
+ /* Reset the count of successful Rx loops. When this function is called
+ again we expect this to have been incremented. */
+ uxRxLoops = comINITIAL_RX_COUNT_VALUE;
+
+ return xReturn;
+}
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/comtest_strings.c b/third_party/FreeRTOS/Demo/Common/Minimal/comtest_strings.c new file mode 100644 index 0000000..11b80c4 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/comtest_strings.c @@ -0,0 +1,349 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+
+/*
+ * Creates a task and a timer that operate on an interrupt driven serial port.
+ * This demo assumes that the characters transmitted on a port will also be
+ * received on the same port. Therefore, the UART must either be connected to
+ * an echo server, or the uart connector must have a loopback connector fitted.
+ * See http://www.serialporttool.com/CommEcho.htm for a suitable echo server
+ * for Windows hosts.
+ *
+ * The timer sends a string to the UART, toggles an LED, then resets itself by
+ * changing its own period. The period is calculated as a pseudo random number
+ * between comTX_MAX_BLOCK_TIME and comTX_MIN_BLOCK_TIME.
+ *
+ * The task blocks on an Rx queue waiting for a character to become available.
+ * Received characters are checked to ensure they match those transmitted by the
+ * Tx timer. An error is latched if characters are missing, incorrect, or
+ * arrive too slowly.
+ *
+ * How characters are actually transmitted and received is port specific. Demos
+ * that include this test/demo file will provide example drivers. The Tx timer
+ * executes in the context of the timer service (daemon) task, and must
+ * therefore never attempt to block.
+ *
+ */
+
+/* Scheduler include files. */
+#include <stdlib.h>
+#include <string.h>
+#include "FreeRTOS.h"
+#include "task.h"
+#include "timers.h"
+
+#ifndef configUSE_TIMERS
+ #error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
+#endif
+
+#if configUSE_TIMERS != 1
+ #error This demo uses timers. configUSE_TIMERS must be set to 1 in FreeRTOSConfig.h.
+#endif
+
+
+/* Demo program include files. */
+#include "serial.h"
+#include "comtest_strings.h"
+#include "partest.h"
+
+/* The size of the stack given to the Rx task. */
+#define comSTACK_SIZE configMINIMAL_STACK_SIZE
+
+/* See the comment above the declaraction of the uxBaseLED variable. */
+#define comTX_LED_OFFSET ( 0 )
+#define comRX_LED_OFFSET ( 1 )
+
+/* The Tx timer transmits the sequence of characters at a pseudo random
+interval that is capped between comTX_MAX_BLOCK_TIME and
+comTX_MIN_BLOCK_TIME. */
+#define comTX_MAX_BLOCK_TIME ( ( portTickType ) 0x96 )
+#define comTX_MIN_BLOCK_TIME ( ( portTickType ) 0x32 )
+#define comOFFSET_TIME ( ( portTickType ) 3 )
+
+/* States for the simple state machine implemented in the Rx task. */
+#define comtstWAITING_START_OF_STRING 0
+#define comtstWAITING_END_OF_STRING 1
+
+/* A short delay in ticks - this delay is used to allow the Rx queue to fill up
+a bit so more than one character can be processed at a time. This is relative
+to comTX_MIN_BLOCK_TIME to ensure it is never longer than the shortest gap
+between transmissions. It could be worked out more scientifically from the
+baud rate being used. */
+#define comSHORT_DELAY ( comTX_MIN_BLOCK_TIME >> ( portTickType ) 2 )
+
+/* The string that is transmitted and received. */
+#define comTRANSACTED_STRING "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
+
+/* A block time of 0 simply means "don't block". */
+#define comtstDONT_BLOCK ( portTickType ) 0
+
+/* Handle to the com port used by both tasks. */
+static xComPortHandle xPort = NULL;
+
+/* The callback function allocated to the transmit timer, as described in the
+comments at the top of this file. */
+static void prvComTxTimerCallback( xTimerHandle xTimer );
+
+/* The receive task as described in the comments at the top of this file. */
+static void vComRxTask( void *pvParameters );
+
+/* The Rx task will toggle LED ( uxBaseLED + comRX_LED_OFFSET). The Tx task
+will toggle LED ( uxBaseLED + comTX_LED_OFFSET ). */
+static unsigned portBASE_TYPE uxBaseLED = 0;
+
+/* The Rx task toggles uxRxLoops on each successful iteration of its defined
+function - provided no errors have ever been latched. If this variable stops
+incrementing, then an error has occurred. */
+static volatile unsigned portBASE_TYPE uxRxLoops = 0UL;
+
+/* The timer used to periodically transmit the string. This is the timer that
+has prvComTxTimerCallback allocated to it as its callback function. */
+static xTimerHandle xTxTimer = NULL;
+
+/* The string length is held at file scope so the Tx timer does not need to
+calculate it each time it executes. */
+static size_t xStringLength = 0U;
+
+/*-----------------------------------------------------------*/
+
+void vStartComTestStringsTasks( unsigned portBASE_TYPE uxPriority, unsigned long ulBaudRate, unsigned portBASE_TYPE uxLED )
+{
+ /* Store values that are used at run time. */
+ uxBaseLED = uxLED;
+
+ /* Calculate the string length here, rather than each time the Tx timer
+ executes. */
+ xStringLength = strlen( comTRANSACTED_STRING );
+
+ /* Include the null terminator in the string length as this is used to
+ detect the end of the string in the Rx task. */
+ xStringLength++;
+
+ /* Initialise the com port, then spawn the Rx task and create the Tx
+ timer. */
+ xSerialPortInitMinimal( ulBaudRate, ( xStringLength * 2U ) );
+
+ /* Create the Rx task and the Tx timer. The timer is started from the
+ Rx task. */
+ xTaskCreate( vComRxTask, ( signed char * ) "COMRx", comSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );
+ xTxTimer = xTimerCreate( ( const signed char * ) "TxTimer", comTX_MIN_BLOCK_TIME, pdFALSE, NULL, prvComTxTimerCallback );
+ configASSERT( xTxTimer );
+}
+/*-----------------------------------------------------------*/
+
+static void prvComTxTimerCallback( xTimerHandle xTimer )
+{
+portTickType xTimeToWait;
+
+ /* The parameter is not used in this case. */
+ ( void ) xTimer;
+
+ /* Send the string. How this is actually performed depends on the
+ sample driver provided with this demo. However - as this is a timer,
+ it executes in the context of the timer task and therefore must not
+ block. */
+ vSerialPutString( xPort, ( const signed char * const ) comTRANSACTED_STRING, xStringLength );
+
+ /* Toggle an LED to give a visible indication that another transmission
+ has been performed. */
+ vParTestToggleLED( uxBaseLED + comTX_LED_OFFSET );
+
+ /* Wait a pseudo random time before sending the string again. */
+ xTimeToWait = xTaskGetTickCount() + comOFFSET_TIME;
+
+ /* Ensure the time to wait is not greater than comTX_MAX_BLOCK_TIME. */
+ xTimeToWait %= comTX_MAX_BLOCK_TIME;
+
+ /* Ensure the time to wait is not less than comTX_MIN_BLOCK_TIME. */
+ if( xTimeToWait < comTX_MIN_BLOCK_TIME )
+ {
+ xTimeToWait = comTX_MIN_BLOCK_TIME;
+ }
+
+ /* Reset the timer to run again xTimeToWait ticks from now. This function
+ is called from the context of the timer task, so the block time must not
+ be anything other than zero. */
+ xTimerChangePeriod( xTxTimer, xTimeToWait, comtstDONT_BLOCK );
+}
+/*-----------------------------------------------------------*/
+
+static void vComRxTask( void *pvParameters )
+{
+portBASE_TYPE xState = comtstWAITING_START_OF_STRING, xErrorOccurred = pdFALSE;
+signed char *pcExpectedByte, cRxedChar;
+const xComPortHandle xPort = NULL;
+
+ /* The parameter is not used in this example. */
+ ( void ) pvParameters;
+
+ /* Start the Tx timer. This only needs to be started once, as it will
+ reset itself thereafter. */
+ xTimerStart( xTxTimer, portMAX_DELAY );
+
+ /* The first expected Rx character is the first in the string that is
+ transmitted. */
+ pcExpectedByte = ( signed char * ) comTRANSACTED_STRING;
+
+ for( ;; )
+ {
+ /* Wait for the next character. */
+ if( xSerialGetChar( xPort, &cRxedChar, ( comTX_MAX_BLOCK_TIME * 2 ) ) == pdFALSE )
+ {
+ /* A character definitely should have been received by now. As a
+ character was not received an error must have occurred (which might
+ just be that the loopback connector is not fitted). */
+ xErrorOccurred = pdTRUE;
+ }
+
+ switch( xState )
+ {
+ case comtstWAITING_START_OF_STRING:
+ if( cRxedChar == *pcExpectedByte )
+ {
+ /* The received character was the first character of the
+ string. Move to the next state to check each character
+ as it comes in until the entire string has been received. */
+ xState = comtstWAITING_END_OF_STRING;
+ pcExpectedByte++;
+
+ /* Block for a short period. This just allows the Rx queue
+ to contain more than one character, and therefore prevent
+ thrashing reads to the queue, and repetitive context
+ switches as each character is received. */
+ vTaskDelay( comSHORT_DELAY );
+ }
+ break;
+
+ case comtstWAITING_END_OF_STRING:
+ if( cRxedChar == *pcExpectedByte )
+ {
+ /* The received character was the expected character. Was
+ it the last character in the string - i.e. the null
+ terminator? */
+ if( cRxedChar == 0x00 )
+ {
+ /* The entire string has been received. If no errors
+ have been latched, then increment the loop counter to
+ show this task is still healthy. */
+ if( xErrorOccurred == pdFALSE )
+ {
+ uxRxLoops++;
+
+ /* Toggle an LED to give a visible sign that a
+ complete string has been received. */
+ vParTestToggleLED( uxBaseLED + comRX_LED_OFFSET );
+ }
+
+ /* Go back to wait for the start of the next string. */
+ pcExpectedByte = ( signed char * ) comTRANSACTED_STRING;
+ xState = comtstWAITING_START_OF_STRING;
+ }
+ else
+ {
+ /* Wait for the next character in the string. */
+ pcExpectedByte++;
+ }
+ }
+ else
+ {
+ /* The character received was not that expected. */
+ xErrorOccurred = pdTRUE;
+ }
+ break;
+
+ default:
+ /* Should not get here. Stop the Rx loop counter from
+ incrementing to latch the error. */
+ xErrorOccurred = pdTRUE;
+ break;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xAreComTestTasksStillRunning( void )
+{
+portBASE_TYPE xReturn;
+
+ /* If the count of successful reception loops has not changed than at
+ some time an error occurred (i.e. a character was received out of sequence)
+ and false is returned. */
+ if( uxRxLoops == 0UL )
+ {
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+
+ /* Reset the count of successful Rx loops. When this function is called
+ again it should have been incremented again. */
+ uxRxLoops = 0UL;
+
+ return xReturn;
+}
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/countsem.c b/third_party/FreeRTOS/Demo/Common/Minimal/countsem.c new file mode 100644 index 0000000..d38e4f4 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/countsem.c @@ -0,0 +1,322 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+
+/*
+ * Simple demonstration of the usage of counting semaphore.
+ */
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* Demo program include files. */
+#include "countsem.h"
+
+/* The maximum count value that the semaphore used for the demo can hold. */
+#define countMAX_COUNT_VALUE ( 200 )
+
+/* Constants used to indicate whether or not the semaphore should have been
+created with its maximum count value, or its minimum count value. These
+numbers are used to ensure that the pointers passed in as the task parameters
+are valid. */
+#define countSTART_AT_MAX_COUNT ( 0xaa )
+#define countSTART_AT_ZERO ( 0x55 )
+
+/* Two tasks are created for the test. One uses a semaphore created with its
+count value set to the maximum, and one with the count value set to zero. */
+#define countNUM_TEST_TASKS ( 2 )
+#define countDONT_BLOCK ( 0 )
+
+/*-----------------------------------------------------------*/
+
+/* Flag that will be latched to pdTRUE should any unexpected behaviour be
+detected in any of the tasks. */
+static volatile portBASE_TYPE xErrorDetected = pdFALSE;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * The demo task. This simply counts the semaphore up to its maximum value,
+ * the counts it back down again. The result of each semaphore 'give' and
+ * 'take' is inspected, with an error being flagged if it is found not to be
+ * the expected result.
+ */
+static void prvCountingSemaphoreTask( void *pvParameters );
+
+/*
+ * Utility function to increment the semaphore count value up from zero to
+ * countMAX_COUNT_VALUE.
+ */
+static void prvIncrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter );
+
+/*
+ * Utility function to decrement the semaphore count value up from
+ * countMAX_COUNT_VALUE to zero.
+ */
+static void prvDecrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter );
+
+/*-----------------------------------------------------------*/
+
+/* The structure that is passed into the task as the task parameter. */
+typedef struct COUNT_SEM_STRUCT
+{
+ /* The semaphore to be used for the demo. */
+ xSemaphoreHandle xSemaphore;
+
+ /* Set to countSTART_AT_MAX_COUNT if the semaphore should be created with
+ its count value set to its max count value, or countSTART_AT_ZERO if it
+ should have been created with its count value set to 0. */
+ unsigned portBASE_TYPE uxExpectedStartCount;
+
+ /* Incremented on each cycle of the demo task. Used to detect a stalled
+ task. */
+ unsigned portBASE_TYPE uxLoopCounter;
+} xCountSemStruct;
+
+/* Two structures are defined, one is passed to each test task. */
+static volatile xCountSemStruct xParameters[ countNUM_TEST_TASKS ];
+
+/*-----------------------------------------------------------*/
+
+void vStartCountingSemaphoreTasks( void )
+{
+ /* Create the semaphores that we are going to use for the test/demo. The
+ first should be created such that it starts at its maximum count value,
+ the second should be created such that it starts with a count value of zero. */
+ xParameters[ 0 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, countMAX_COUNT_VALUE );
+ xParameters[ 0 ].uxExpectedStartCount = countSTART_AT_MAX_COUNT;
+ xParameters[ 0 ].uxLoopCounter = 0;
+
+ xParameters[ 1 ].xSemaphore = xSemaphoreCreateCounting( countMAX_COUNT_VALUE, 0 );
+ xParameters[ 1 ].uxExpectedStartCount = 0;
+ xParameters[ 1 ].uxLoopCounter = 0;
+
+ /* vQueueAddToRegistry() adds the semaphore to the registry, if one is
+ in use. The registry is provided as a means for kernel aware
+ debuggers to locate semaphores and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( ( xQueueHandle ) xParameters[ 0 ].xSemaphore, ( signed portCHAR * ) "Counting_Sem_1" );
+ vQueueAddToRegistry( ( xQueueHandle ) xParameters[ 1 ].xSemaphore, ( signed portCHAR * ) "Counting_Sem_2" );
+
+
+ /* Were the semaphores created? */
+ if( ( xParameters[ 0 ].xSemaphore != NULL ) || ( xParameters[ 1 ].xSemaphore != NULL ) )
+ {
+ /* Create the demo tasks, passing in the semaphore to use as the parameter. */
+ xTaskCreate( prvCountingSemaphoreTask, ( signed portCHAR * ) "CNT1", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 0 ] ), tskIDLE_PRIORITY, NULL );
+ xTaskCreate( prvCountingSemaphoreTask, ( signed portCHAR * ) "CNT2", configMINIMAL_STACK_SIZE, ( void * ) &( xParameters[ 1 ] ), tskIDLE_PRIORITY, NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvDecrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter )
+{
+unsigned portBASE_TYPE ux;
+
+ /* If the semaphore count is at its maximum then we should not be able to
+ 'give' the semaphore. */
+ if( xSemaphoreGive( xSemaphore ) == pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* We should be able to 'take' the semaphore countMAX_COUNT_VALUE times. */
+ for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
+ {
+ if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) != pdPASS )
+ {
+ /* We expected to be able to take the semaphore. */
+ xErrorDetected = pdTRUE;
+ }
+
+ ( *puxLoopCounter )++;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* If the semaphore count is zero then we should not be able to 'take'
+ the semaphore. */
+ if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvIncrementSemaphoreCount( xSemaphoreHandle xSemaphore, unsigned portBASE_TYPE *puxLoopCounter )
+{
+unsigned portBASE_TYPE ux;
+
+ /* If the semaphore count is zero then we should not be able to 'take'
+ the semaphore. */
+ if( xSemaphoreTake( xSemaphore, countDONT_BLOCK ) == pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ /* We should be able to 'give' the semaphore countMAX_COUNT_VALUE times. */
+ for( ux = 0; ux < countMAX_COUNT_VALUE; ux++ )
+ {
+ if( xSemaphoreGive( xSemaphore ) != pdPASS )
+ {
+ /* We expected to be able to take the semaphore. */
+ xErrorDetected = pdTRUE;
+ }
+
+ ( *puxLoopCounter )++;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* If the semaphore count is at its maximum then we should not be able to
+ 'give' the semaphore. */
+ if( xSemaphoreGive( xSemaphore ) == pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvCountingSemaphoreTask( void *pvParameters )
+{
+xCountSemStruct *pxParameter;
+
+ #ifdef USE_STDIO
+ void vPrintDisplayMessage( const portCHAR * const * ppcMessageToSend );
+
+ const portCHAR * const pcTaskStartMsg = "Counting semaphore demo started.\r\n";
+
+ /* Queue a message for printing to say the task has started. */
+ vPrintDisplayMessage( &pcTaskStartMsg );
+ #endif
+
+ /* The semaphore to be used was passed as the parameter. */
+ pxParameter = ( xCountSemStruct * ) pvParameters;
+
+ /* Did we expect to find the semaphore already at its max count value, or
+ at zero? */
+ if( pxParameter->uxExpectedStartCount == countSTART_AT_MAX_COUNT )
+ {
+ prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
+ }
+
+ /* Now we expect the semaphore count to be 0, so this time there is an
+ error if we can take the semaphore. */
+ if( xSemaphoreTake( pxParameter->xSemaphore, 0 ) == pdPASS )
+ {
+ xErrorDetected = pdTRUE;
+ }
+
+ for( ;; )
+ {
+ prvIncrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
+ prvDecrementSemaphoreCount( pxParameter->xSemaphore, &( pxParameter->uxLoopCounter ) );
+ }
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xAreCountingSemaphoreTasksStillRunning( void )
+{
+static unsigned portBASE_TYPE uxLastCount0 = 0, uxLastCount1 = 0;
+portBASE_TYPE xReturn = pdPASS;
+
+ /* Return fail if any 'give' or 'take' did not result in the expected
+ behaviour. */
+ if( xErrorDetected != pdFALSE )
+ {
+ xReturn = pdFAIL;
+ }
+
+ /* Return fail if either task is not still incrementing its loop counter. */
+ if( uxLastCount0 == xParameters[ 0 ].uxLoopCounter )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ uxLastCount0 = xParameters[ 0 ].uxLoopCounter;
+ }
+
+ if( uxLastCount1 == xParameters[ 1 ].uxLoopCounter )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ uxLastCount1 = xParameters[ 1 ].uxLoopCounter;
+ }
+
+ return xReturn;
+}
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/crflash.c b/third_party/FreeRTOS/Demo/Common/Minimal/crflash.c new file mode 100644 index 0000000..9f0a1a8 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/crflash.c @@ -0,0 +1,246 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This demo application file demonstrates the use of queues to pass data
+ * between co-routines.
+ *
+ * N represents the number of 'fixed delay' co-routines that are created and
+ * is set during initialisation.
+ *
+ * N 'fixed delay' co-routines are created that just block for a fixed
+ * period then post the number of an LED onto a queue. Each such co-routine
+ * uses a different block period. A single 'flash' co-routine is also created
+ * that blocks on the same queue, waiting for the number of the next LED it
+ * should flash. Upon receiving a number it simply toggle the instructed LED
+ * then blocks on the queue once more. In this manner each LED from LED 0 to
+ * LED N-1 is caused to flash at a different rate.
+ *
+ * The 'fixed delay' co-routines are created with co-routine priority 0. The
+ * flash co-routine is created with co-routine priority 1. This means that
+ * the queue should never contain more than a single item. This is because
+ * posting to the queue will unblock the 'flash' co-routine, and as this has
+ * a priority greater than the tasks posting to the queue it is guaranteed to
+ * have emptied the queue and blocked once again before the queue can contain
+ * any more date. An error is indicated if an attempt to post data to the
+ * queue fails - indicating that the queue is already full.
+ *
+ */
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "croutine.h"
+#include "queue.h"
+
+/* Demo application includes. */
+#include "partest.h"
+#include "crflash.h"
+
+/* The queue should only need to be of length 1. See the description at the
+top of the file. */
+#define crfQUEUE_LENGTH 1
+
+#define crfFIXED_DELAY_PRIORITY 0
+#define crfFLASH_PRIORITY 1
+
+/* Only one flash co-routine is created so the index is not significant. */
+#define crfFLASH_INDEX 0
+
+/* Don't allow more than crfMAX_FLASH_TASKS 'fixed delay' co-routines to be
+created. */
+#define crfMAX_FLASH_TASKS 8
+
+/* We don't want to block when posting to the queue. */
+#define crfPOSTING_BLOCK_TIME 0
+
+/*
+ * The 'fixed delay' co-routine as described at the top of the file.
+ */
+static void prvFixedDelayCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex );
+
+/*
+ * The 'flash' co-routine as described at the top of the file.
+ */
+static void prvFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex );
+
+/* The queue used to pass data between the 'fixed delay' co-routines and the
+'flash' co-routine. */
+static xQueueHandle xFlashQueue;
+
+/* This will be set to pdFALSE if we detect an error. */
+static portBASE_TYPE xCoRoutineFlashStatus = pdPASS;
+
+/*-----------------------------------------------------------*/
+
+/*
+ * See the header file for details.
+ */
+void vStartFlashCoRoutines( unsigned portBASE_TYPE uxNumberToCreate )
+{
+unsigned portBASE_TYPE uxIndex;
+
+ if( uxNumberToCreate > crfMAX_FLASH_TASKS )
+ {
+ uxNumberToCreate = crfMAX_FLASH_TASKS;
+ }
+
+ /* Create the queue used to pass data between the co-routines. */
+ xFlashQueue = xQueueCreate( crfQUEUE_LENGTH, sizeof( unsigned portBASE_TYPE ) );
+
+ if( xFlashQueue )
+ {
+ /* Create uxNumberToCreate 'fixed delay' co-routines. */
+ for( uxIndex = 0; uxIndex < uxNumberToCreate; uxIndex++ )
+ {
+ xCoRoutineCreate( prvFixedDelayCoRoutine, crfFIXED_DELAY_PRIORITY, uxIndex );
+ }
+
+ /* Create the 'flash' co-routine. */
+ xCoRoutineCreate( prvFlashCoRoutine, crfFLASH_PRIORITY, crfFLASH_INDEX );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvFixedDelayCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+{
+/* Even though this is a co-routine the xResult variable does not need to be
+static as we do not need it to maintain its state between blocks. */
+signed portBASE_TYPE xResult;
+/* The uxIndex parameter of the co-routine function is used as an index into
+the xFlashRates array to obtain the delay period to use. */
+static const portTickType xFlashRates[ crfMAX_FLASH_TASKS ] = { 150 / portTICK_RATE_MS,
+ 200 / portTICK_RATE_MS,
+ 250 / portTICK_RATE_MS,
+ 300 / portTICK_RATE_MS,
+ 350 / portTICK_RATE_MS,
+ 400 / portTICK_RATE_MS,
+ 450 / portTICK_RATE_MS,
+ 500 / portTICK_RATE_MS };
+
+ /* Co-routines MUST start with a call to crSTART. */
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ /* Post our uxIndex value onto the queue. This is used as the LED to
+ flash. */
+ crQUEUE_SEND( xHandle, xFlashQueue, ( void * ) &uxIndex, crfPOSTING_BLOCK_TIME, &xResult );
+
+ if( xResult != pdPASS )
+ {
+ /* For the reasons stated at the top of the file we should always
+ find that we can post to the queue. If we could not then an error
+ has occurred. */
+ xCoRoutineFlashStatus = pdFAIL;
+ }
+
+ crDELAY( xHandle, xFlashRates[ uxIndex ] );
+ }
+
+ /* Co-routines MUST end with a call to crEND. */
+ crEND();
+}
+/*-----------------------------------------------------------*/
+
+static void prvFlashCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+{
+/* Even though this is a co-routine the variable do not need to be
+static as we do not need it to maintain their state between blocks. */
+signed portBASE_TYPE xResult;
+unsigned portBASE_TYPE uxLEDToFlash;
+
+ /* Co-routines MUST start with a call to crSTART. */
+ crSTART( xHandle );
+ ( void ) uxIndex;
+
+ for( ;; )
+ {
+ /* Block to wait for the number of the LED to flash. */
+ crQUEUE_RECEIVE( xHandle, xFlashQueue, &uxLEDToFlash, portMAX_DELAY, &xResult );
+
+ if( xResult != pdPASS )
+ {
+ /* We would not expect to wake unless we received something. */
+ xCoRoutineFlashStatus = pdFAIL;
+ }
+ else
+ {
+ /* We received the number of an LED to flash - flash it! */
+ vParTestToggleLED( uxLEDToFlash );
+ }
+ }
+
+ /* Co-routines MUST end with a call to crEND. */
+ crEND();
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xAreFlashCoRoutinesStillRunning( void )
+{
+ /* Return pdPASS or pdFAIL depending on whether an error has been detected
+ or not. */
+ return xCoRoutineFlashStatus;
+}
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/crhook.c b/third_party/FreeRTOS/Demo/Common/Minimal/crhook.c new file mode 100644 index 0000000..0eaba7d --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/crhook.c @@ -0,0 +1,270 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * This demo file demonstrates how to send data between an ISR and a
+ * co-routine. A tick hook function is used to periodically pass data between
+ * the RTOS tick and a set of 'hook' co-routines.
+ *
+ * hookNUM_HOOK_CO_ROUTINES co-routines are created. Each co-routine blocks
+ * to wait for a character to be received on a queue from the tick ISR, checks
+ * to ensure the character received was that expected, then sends the number
+ * back to the tick ISR on a different queue.
+ *
+ * The tick ISR checks the numbers received back from the 'hook' co-routines
+ * matches the number previously sent.
+ *
+ * If at any time a queue function returns unexpectedly, or an incorrect value
+ * is received either by the tick hook or a co-routine then an error is
+ * latched.
+ *
+ * This demo relies on each 'hook' co-routine to execute between each
+ * hookTICK_CALLS_BEFORE_POST tick interrupts. This and the heavy use of
+ * queues from within an interrupt may result in an error being detected on
+ * slower targets simply due to timing.
+ */
+
+/* Scheduler includes. */
+#include "FreeRTOS.h"
+#include "croutine.h"
+#include "queue.h"
+
+/* Demo application includes. */
+#include "crhook.h"
+
+/* The number of 'hook' co-routines that are to be created. */
+#define hookNUM_HOOK_CO_ROUTINES ( 4 )
+
+/* The number of times the tick hook should be called before a character is
+posted to the 'hook' co-routines. */
+#define hookTICK_CALLS_BEFORE_POST ( 500 )
+
+/* There should never be more than one item in any queue at any time. */
+#define hookHOOK_QUEUE_LENGTH ( 1 )
+
+/* Don't block when initially posting to the queue. */
+#define hookNO_BLOCK_TIME ( 0 )
+
+/* The priority relative to other co-routines (rather than tasks) that the
+'hook' co-routines should take. */
+#define mainHOOK_CR_PRIORITY ( 1 )
+/*-----------------------------------------------------------*/
+
+/*
+ * The co-routine function itself.
+ */
+static void prvHookCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex );
+
+
+/*
+ * The tick hook function. This receives a number from each 'hook' co-routine
+ * then sends a number to each co-routine. An error is flagged if a send or
+ * receive fails, or an unexpected number is received.
+ */
+void vApplicationTickHook( void );
+
+/*-----------------------------------------------------------*/
+
+/* Queues used to send data FROM a co-routine TO the tick hook function.
+The hook functions received (Rx's) on these queues. One queue per
+'hook' co-routine. */
+static xQueueHandle xHookRxQueues[ hookNUM_HOOK_CO_ROUTINES ];
+
+/* Queues used to send data FROM the tick hook TO a co-routine function.
+The hood function transmits (Tx's) on these queues. One queue per
+'hook' co-routine. */
+static xQueueHandle xHookTxQueues[ hookNUM_HOOK_CO_ROUTINES ];
+
+/* Set to true if an error is detected at any time. */
+static portBASE_TYPE xCoRoutineErrorDetected = pdFALSE;
+
+/*-----------------------------------------------------------*/
+
+void vStartHookCoRoutines( void )
+{
+unsigned portBASE_TYPE uxIndex, uxValueToPost = 0;
+
+ for( uxIndex = 0; uxIndex < hookNUM_HOOK_CO_ROUTINES; uxIndex++ )
+ {
+ /* Create a queue to transmit to and receive from each 'hook'
+ co-routine. */
+ xHookRxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( unsigned portBASE_TYPE ) );
+ xHookTxQueues[ uxIndex ] = xQueueCreate( hookHOOK_QUEUE_LENGTH, sizeof( unsigned portBASE_TYPE ) );
+
+ /* To start things off the tick hook function expects the queue it
+ uses to receive data to contain a value. */
+ xQueueSend( xHookRxQueues[ uxIndex ], &uxValueToPost, hookNO_BLOCK_TIME );
+
+ /* Create the 'hook' co-routine itself. */
+ xCoRoutineCreate( prvHookCoRoutine, mainHOOK_CR_PRIORITY, uxIndex );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static unsigned portBASE_TYPE uxCallCounter = 0, uxNumberToPost = 0;
+void vApplicationTickHook( void )
+{
+unsigned portBASE_TYPE uxReceivedNumber;
+signed portBASE_TYPE xIndex, xCoRoutineWoken;
+
+ /* Is it time to talk to the 'hook' co-routines again? */
+ uxCallCounter++;
+ if( uxCallCounter >= hookTICK_CALLS_BEFORE_POST )
+ {
+ uxCallCounter = 0;
+
+ for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
+ {
+ xCoRoutineWoken = pdFALSE;
+ if( crQUEUE_RECEIVE_FROM_ISR( xHookRxQueues[ xIndex ], &uxReceivedNumber, &xCoRoutineWoken ) != pdPASS )
+ {
+ /* There is no reason why we would not expect the queue to
+ contain a value. */
+ xCoRoutineErrorDetected = pdTRUE;
+ }
+ else
+ {
+ /* Each queue used to receive data from the 'hook' co-routines
+ should contain the number we last posted to the same co-routine. */
+ if( uxReceivedNumber != uxNumberToPost )
+ {
+ xCoRoutineErrorDetected = pdTRUE;
+ }
+
+ /* Nothing should be blocked waiting to post to the queue. */
+ if( xCoRoutineWoken != pdFALSE )
+ {
+ xCoRoutineErrorDetected = pdTRUE;
+ }
+ }
+ }
+
+ /* Start the next cycle by posting the next number onto each Tx queue. */
+ uxNumberToPost++;
+
+ for( xIndex = 0; xIndex < hookNUM_HOOK_CO_ROUTINES; xIndex++ )
+ {
+ if( crQUEUE_SEND_FROM_ISR( xHookTxQueues[ xIndex ], &uxNumberToPost, pdFALSE ) != pdTRUE )
+ {
+ /* Posting to the queue should have woken the co-routine that
+ was blocked on the queue. */
+ xCoRoutineErrorDetected = pdTRUE;
+ }
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvHookCoRoutine( xCoRoutineHandle xHandle, unsigned portBASE_TYPE uxIndex )
+{
+static unsigned portBASE_TYPE uxReceivedValue[ hookNUM_HOOK_CO_ROUTINES ];
+portBASE_TYPE xResult;
+
+ /* Each co-routine MUST start with a call to crSTART(); */
+ crSTART( xHandle );
+
+ for( ;; )
+ {
+ /* Wait to receive a value from the tick hook. */
+ xResult = pdFAIL;
+ crQUEUE_RECEIVE( xHandle, xHookTxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), portMAX_DELAY, &xResult );
+
+ /* There is no reason why we should not have received something on
+ the queue. */
+ if( xResult != pdPASS )
+ {
+ xCoRoutineErrorDetected = pdTRUE;
+ }
+
+ /* Send the same number back to the idle hook so it can verify it. */
+ xResult = pdFAIL;
+ crQUEUE_SEND( xHandle, xHookRxQueues[ uxIndex ], &( uxReceivedValue[ uxIndex ] ), hookNO_BLOCK_TIME, &xResult );
+ if( xResult != pdPASS )
+ {
+ /* There is no reason why we should not have been able to post to
+ the queue. */
+ xCoRoutineErrorDetected = pdTRUE;
+ }
+ }
+
+ /* Each co-routine MUST end with a call to crEND(). */
+ crEND();
+}
+/*-----------------------------------------------------------*/
+
+portBASE_TYPE xAreHookCoRoutinesStillRunning( void )
+{
+ if( xCoRoutineErrorDetected )
+ {
+ return pdFALSE;
+ }
+ else
+ {
+ return pdTRUE;
+ }
+}
+
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/death.c b/third_party/FreeRTOS/Demo/Common/Minimal/death.c new file mode 100644 index 0000000..d6a9110 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/death.c @@ -0,0 +1,267 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/**
+ * Create a single persistent task which periodically dynamically creates another
+ * two tasks. The original task is called the creator task, the two tasks it
+ * creates are called suicidal tasks.
+ *
+ * One of the created suicidal tasks kill one other suicidal task before killing
+ * itself - 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 V3.0.0
+ + CreationCount sizes changed from unsigned portBASE_TYPE to
+ unsigned short to minimize the risk of overflowing.
+
+ + Reset of usLastCreationCount added
+
+Changes from V3.1.0
+ + Changed the dummy calculation to use variables of type long, rather than
+ float. This allows the file to be used with ports that do not support
+ floating point.
+
+*/
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Demo program include files. */
+#include "death.h"
+
+#define deathSTACK_SIZE ( configMINIMAL_STACK_SIZE + 60 )
+
+/* The task originally created which is responsible for periodically dynamically
+creating another four tasks. */
+static portTASK_FUNCTION_PROTO( vCreateTasks, pvParameters );
+
+/* The task function of the dynamically created tasks. */
+static portTASK_FUNCTION_PROTO( vSuicidalTask, 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 unsigned short usCreationCount = 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;
+
+/* Tasks are deleted by the idle task. Under heavy load the idle task might
+not get much processing time, so it would be legitimate for several tasks to
+remain undeleted for a short period. */
+static const unsigned portBASE_TYPE uxMaxNumberOfExtraTasksRunning = 3;
+
+/* Used to store a handle to the task that should be killed by a suicidal task,
+before it kills itself. */
+xTaskHandle xCreatedTask;
+
+/*-----------------------------------------------------------*/
+
+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, ( signed char * ) "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 = ( unsigned portBASE_TYPE ) uxTaskGetNumberOfTasks();
+
+ /* FreeRTOS.org versions before V3.0 started the idle-task as the very
+ first task. The idle task was then already included in uxTasksRunningAtStart.
+ From FreeRTOS V3.0 on, the idle task is started when the scheduler is
+ started. Therefore the idle task is not yet accounted for. We correct
+ this by increasing uxTasksRunningAtStart by 1. */
+ uxTasksRunningAtStart++;
+
+ /* From FreeRTOS version 7.0.0 can optionally create a timer service task.
+ If this is done, then uxTasksRunningAtStart needs incrementing again as that
+ too is created when the scheduler is started. */
+ #if configUSE_TIMERS == 1
+ uxTasksRunningAtStart++;
+ #endif
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vSuicidalTask, pvParameters )
+{
+volatile long l1, l2;
+xTaskHandle xTaskToKill;
+const portTickType xDelay = ( portTickType ) 200 / portTICK_RATE_MS;
+
+ if( pvParameters != NULL )
+ {
+ /* This task is periodically created four times. Two 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 = *( xTaskHandle* )pvParameters;
+ }
+ else
+ {
+ xTaskToKill = NULL;
+ }
+
+ for( ;; )
+ {
+ /* Do something random just to use some stack and registers. */
+ l1 = 2;
+ l2 = 89;
+ l2 *= l1;
+ vTaskDelay( xDelay );
+
+ if( xTaskToKill != NULL )
+ {
+ /* Make sure the other task has a go before we delete it. */
+ vTaskDelay( ( portTickType ) 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 portTASK_FUNCTION( vCreateTasks, pvParameters )
+{
+const portTickType xDelay = ( portTickType ) 1000 / portTICK_RATE_MS;
+unsigned portBASE_TYPE uxPriority;
+
+ uxPriority = *( unsigned portBASE_TYPE * ) pvParameters;
+ vPortFree( pvParameters );
+
+ for( ;; )
+ {
+ /* Just loop round, delaying then creating the four suicidal tasks. */
+ vTaskDelay( xDelay );
+
+ xCreatedTask = NULL;
+
+ xTaskCreate( vSuicidalTask, ( signed char * ) "SUICID1", configMINIMAL_STACK_SIZE, NULL, uxPriority, &xCreatedTask );
+ xTaskCreate( vSuicidalTask, ( signed char * ) "SUICID2", configMINIMAL_STACK_SIZE, &xCreatedTask, uxPriority, NULL );
+
+ ++usCreationCount;
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* 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 unsigned short usLastCreationCount = 0xfff;
+portBASE_TYPE xReturn = pdTRUE;
+static unsigned portBASE_TYPE uxTasksRunningNow;
+
+ if( usLastCreationCount == usCreationCount )
+ {
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ usLastCreationCount = usCreationCount;
+ }
+
+ uxTasksRunningNow = ( unsigned portBASE_TYPE ) uxTaskGetNumberOfTasks();
+
+ if( uxTasksRunningNow < uxTasksRunningAtStart )
+ {
+ xReturn = pdFALSE;
+ }
+ else if( ( uxTasksRunningNow - uxTasksRunningAtStart ) > uxMaxNumberOfExtraTasksRunning )
+ {
+ xReturn = pdFALSE;
+ }
+ else
+ {
+ /* Everything is okay. */
+ }
+
+ return xReturn;
+}
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/dynamic.c b/third_party/FreeRTOS/Demo/Common/Minimal/dynamic.c new file mode 100644 index 0000000..2a900af --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/dynamic.c @@ -0,0 +1,511 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * The first test creates three tasks - two counter tasks (one continuous count
+ * and one limited count) and one controller. A "count" variable is shared
+ * between all three tasks. The two counter tasks should never be in a "ready"
+ * state at the same time. The controller task runs at the same priority as
+ * the continuous count task, and at a lower priority than the limited count
+ * task.
+ *
+ * One counter task loops indefinitely, incrementing the shared count variable
+ * on each iteration. To ensure it has exclusive access to the variable it
+ * raises its priority above that of the controller task before each
+ * increment, lowering it again to its original priority before starting the
+ * next iteration.
+ *
+ * The other counter task increments the shared count variable on each
+ * iteration of its loop until the count has reached a limit of 0xff - at
+ * which point it suspends itself. It will not start a new loop until the
+ * controller task has made it "ready" again by calling vTaskResume().
+ * This second counter task operates at a higher priority than controller
+ * task so does not need to worry about mutual exclusion of the counter
+ * variable.
+ *
+ * The controller task is in two sections. The first section controls and
+ * monitors the continuous count task. When this section is operational the
+ * limited count task is suspended. Likewise, the second section controls
+ * and monitors the limited count task. When this section is operational the
+ * continuous count task is suspended.
+ *
+ * In the first section the controller task first takes a copy of the shared
+ * count variable. To ensure mutual exclusion on the count variable it
+ * suspends the continuous count task, resuming it again when the copy has been
+ * taken. The controller task then sleeps for a fixed period - during which
+ * the continuous count task will execute and increment the shared variable.
+ * When the controller task wakes it checks that the continuous count task
+ * has executed by comparing the copy of the shared variable with its current
+ * value. This time, to ensure mutual exclusion, the scheduler itself is
+ * suspended with a call to vTaskSuspendAll (). This is for demonstration
+ * purposes only and is not a recommended technique due to its inefficiency.
+ *
+ * After a fixed number of iterations the controller task suspends the
+ * continuous count task, and moves on to its second section.
+ *
+ * At the start of the second section the shared variable is cleared to zero.
+ * The limited count task is then woken from its suspension by a call to
+ * vTaskResume (). As this counter task operates at a higher priority than
+ * the controller task the controller task should not run again until the
+ * shared variable has been counted up to the limited value causing the counter
+ * task to suspend itself. The next line after vTaskResume () is therefore
+ * a check on the shared variable to ensure everything is as expected.
+ *
+ *
+ * The second test consists of a couple of very simple tasks that post onto a
+ * queue while the scheduler is suspended. This test was added to test parts
+ * of the scheduler not exercised by the first test.
+ *
+ */
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* Demo app include files. */
+#include "dynamic.h"
+
+/* Function that implements the "limited count" task as described above. */
+static portTASK_FUNCTION_PROTO( vLimitedIncrementTask, pvParameters );
+
+/* Function that implements the "continuous count" task as described above. */
+static portTASK_FUNCTION_PROTO( vContinuousIncrementTask, pvParameters );
+
+/* Function that implements the controller task as described above. */
+static portTASK_FUNCTION_PROTO( vCounterControlTask, pvParameters );
+
+static portTASK_FUNCTION_PROTO( vQueueReceiveWhenSuspendedTask, pvParameters );
+static portTASK_FUNCTION_PROTO( vQueueSendWhenSuspendedTask, pvParameters );
+
+/* Demo task specific constants. */
+#define priSTACK_SIZE ( configMINIMAL_STACK_SIZE )
+#define priSLEEP_TIME ( ( portTickType ) 128 / portTICK_RATE_MS )
+#define priLOOPS ( 5 )
+#define priMAX_COUNT ( ( unsigned long ) 0xff )
+#define priNO_BLOCK ( ( portTickType ) 0 )
+#define priSUSPENDED_QUEUE_LENGTH ( 1 )
+
+/*-----------------------------------------------------------*/
+
+/* Handles to the two counter tasks. These could be passed in as parameters
+to the controller task to prevent them having to be file scope. */
+static xTaskHandle xContinuousIncrementHandle, xLimitedIncrementHandle;
+
+/* The shared counter variable. This is passed in as a parameter to the two
+counter variables for demonstration purposes. */
+static volatile unsigned long ulCounter;
+
+/* Variables used to check that the tasks are still operating without error.
+Each complete iteration of the controller task increments this variable
+provided no errors have been found. The variable maintaining the same value
+is therefore indication of an error. */
+static volatile unsigned short usCheckVariable = ( unsigned short ) 0;
+static volatile portBASE_TYPE xSuspendedQueueSendError = pdFALSE;
+static volatile portBASE_TYPE xSuspendedQueueReceiveError = pdFALSE;
+
+/* Queue used by the second test. */
+xQueueHandle xSuspendedTestQueue;
+
+/* The value the queue receive task expects to receive next. This is file
+scope so xAreDynamicPriorityTasksStillRunning() can ensure it is still
+incrementing. */
+static unsigned long ulExpectedValue = ( unsigned long ) 0;
+
+/*-----------------------------------------------------------*/
+/*
+ * Start the three tasks as described at the top of the file.
+ * Note that the limited count task is given a higher priority.
+ */
+void vStartDynamicPriorityTasks( void )
+{
+ xSuspendedTestQueue = xQueueCreate( priSUSPENDED_QUEUE_LENGTH, sizeof( unsigned long ) );
+
+ /* vQueueAddToRegistry() adds the queue to the queue registry, if one is
+ in use. The queue registry is provided as a means for kernel aware
+ debuggers to locate queues and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( xSuspendedTestQueue, ( signed char * ) "Suspended_Test_Queue" );
+
+ xTaskCreate( vContinuousIncrementTask, ( signed char * ) "CNT_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY, &xContinuousIncrementHandle );
+ xTaskCreate( vLimitedIncrementTask, ( signed char * ) "LIM_INC", priSTACK_SIZE, ( void * ) &ulCounter, tskIDLE_PRIORITY + 1, &xLimitedIncrementHandle );
+ xTaskCreate( vCounterControlTask, ( signed char * ) "C_CTRL", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+ xTaskCreate( vQueueSendWhenSuspendedTask, ( signed char * ) "SUSP_TX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+ xTaskCreate( vQueueReceiveWhenSuspendedTask, ( signed char * ) "SUSP_RX", priSTACK_SIZE, NULL, tskIDLE_PRIORITY, NULL );
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Just loops around incrementing the shared variable until the limit has been
+ * reached. Once the limit has been reached it suspends itself.
+ */
+static portTASK_FUNCTION( vLimitedIncrementTask, pvParameters )
+{
+unsigned long *pulCounter;
+
+ /* Take a pointer to the shared variable from the parameters passed into
+ the task. */
+ pulCounter = ( unsigned long * ) pvParameters;
+
+ /* This will run before the control task, so the first thing it does is
+ suspend - the control task will resume it when ready. */
+ vTaskSuspend( NULL );
+
+ for( ;; )
+ {
+ /* Just count up to a value then suspend. */
+ ( *pulCounter )++;
+
+ if( *pulCounter >= priMAX_COUNT )
+ {
+ vTaskSuspend( NULL );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Just keep counting the shared variable up. The control task will suspend
+ * this task when it wants.
+ */
+static portTASK_FUNCTION( vContinuousIncrementTask, pvParameters )
+{
+volatile unsigned long *pulCounter;
+unsigned portBASE_TYPE uxOurPriority;
+
+ /* Take a pointer to the shared variable from the parameters passed into
+ the task. */
+ pulCounter = ( unsigned long * ) pvParameters;
+
+ /* Query our priority so we can raise it when exclusive access to the
+ shared variable is required. */
+ uxOurPriority = uxTaskPriorityGet( NULL );
+
+ for( ;; )
+ {
+ /* Raise the priority above the controller task to ensure a context
+ switch does not occur while the variable is being accessed. */
+ vTaskPrioritySet( NULL, uxOurPriority + 1 );
+ {
+ configASSERT( ( uxTaskPriorityGet( NULL ) == ( uxOurPriority + 1 ) ) );
+ ( *pulCounter )++;
+ }
+ vTaskPrioritySet( NULL, uxOurPriority );
+
+ #if( configUSE_PREEMPTION == 0 )
+ taskYIELD();
+ #endif
+
+ configASSERT( ( uxTaskPriorityGet( NULL ) == uxOurPriority ) );
+ }
+}
+/*-----------------------------------------------------------*/
+
+/*
+ * Controller task as described above.
+ */
+static portTASK_FUNCTION( vCounterControlTask, pvParameters )
+{
+unsigned long ulLastCounter;
+short sLoops;
+short sError = pdFALSE;
+
+ /* Just to stop warning messages. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* Start with the counter at zero. */
+ ulCounter = ( unsigned long ) 0;
+
+ /* First section : */
+
+ /* Check the continuous count task is running. */
+ for( sLoops = 0; sLoops < priLOOPS; sLoops++ )
+ {
+ /* Suspend the continuous count task so we can take a mirror of the
+ shared variable without risk of corruption. This is not really
+ needed as the other task raises its priority above this task's
+ priority. */
+ vTaskSuspend( xContinuousIncrementHandle );
+ {
+ #if( INCLUDE_eTaskGetState == 1 )
+ {
+ configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eSuspended );
+ }
+ #endif /* INCLUDE_eTaskGetState */
+
+ ulLastCounter = ulCounter;
+ }
+ vTaskResume( xContinuousIncrementHandle );
+
+ #if( configUSE_PREEMPTION == 0 )
+ taskYIELD();
+ #endif
+
+ #if( INCLUDE_eTaskGetState == 1 )
+ {
+ configASSERT( eTaskGetState( xContinuousIncrementHandle ) == eReady );
+ }
+ #endif /* INCLUDE_eTaskGetState */
+
+ /* Now delay to ensure the other task has processor time. */
+ vTaskDelay( priSLEEP_TIME );
+
+ /* Check the shared variable again. This time to ensure mutual
+ exclusion the whole scheduler will be locked. This is just for
+ demo purposes! */
+ vTaskSuspendAll();
+ {
+ if( ulLastCounter == ulCounter )
+ {
+ /* The shared variable has not changed. There is a problem
+ with the continuous count task so flag an error. */
+ sError = pdTRUE;
+ }
+ }
+ xTaskResumeAll();
+ }
+
+ /* Second section: */
+
+ /* Suspend the continuous counter task so it stops accessing the shared
+ variable. */
+ vTaskSuspend( xContinuousIncrementHandle );
+
+ /* Reset the variable. */
+ ulCounter = ( unsigned long ) 0;
+
+ #if( INCLUDE_eTaskGetState == 1 )
+ {
+ configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
+ }
+ #endif /* INCLUDE_eTaskGetState */
+
+ /* Resume the limited count task which has a higher priority than us.
+ We should therefore not return from this call until the limited count
+ task has suspended itself with a known value in the counter variable. */
+ vTaskResume( xLimitedIncrementHandle );
+
+ #if( configUSE_PREEMPTION == 0 )
+ taskYIELD();
+ #endif
+
+ /* This task should not run again until xLimitedIncrementHandle has
+ suspended itself. */
+ #if( INCLUDE_eTaskGetState == 1 )
+ {
+ configASSERT( eTaskGetState( xLimitedIncrementHandle ) == eSuspended );
+ }
+ #endif /* INCLUDE_eTaskGetState */
+
+ /* Does the counter variable have the expected value? */
+ if( ulCounter != priMAX_COUNT )
+ {
+ sError = pdTRUE;
+ }
+
+ if( sError == pdFALSE )
+ {
+ /* If no errors have occurred then increment the check variable. */
+ portENTER_CRITICAL();
+ usCheckVariable++;
+ portEXIT_CRITICAL();
+ }
+
+ /* Resume the continuous count task and do it all again. */
+ vTaskResume( xContinuousIncrementHandle );
+
+ #if( configUSE_PREEMPTION == 0 )
+ taskYIELD();
+ #endif
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vQueueSendWhenSuspendedTask, pvParameters )
+{
+static unsigned long ulValueToSend = ( unsigned long ) 0;
+
+ /* Just to stop warning messages. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ vTaskSuspendAll();
+ {
+ /* We must not block while the scheduler is suspended! */
+ if( xQueueSend( xSuspendedTestQueue, ( void * ) &ulValueToSend, priNO_BLOCK ) != pdTRUE )
+ {
+ xSuspendedQueueSendError = pdTRUE;
+ }
+ }
+ xTaskResumeAll();
+
+ vTaskDelay( priSLEEP_TIME );
+
+ ++ulValueToSend;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vQueueReceiveWhenSuspendedTask, pvParameters )
+{
+unsigned long ulReceivedValue;
+portBASE_TYPE xGotValue;
+
+ /* Just to stop warning messages. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ do
+ {
+ /* Suspending the scheduler here is fairly pointless and
+ undesirable for a normal application. It is done here purely
+ to test the scheduler. The inner xTaskResumeAll() should
+ never return pdTRUE as the scheduler is still locked by the
+ outer call. */
+ vTaskSuspendAll();
+ {
+ vTaskSuspendAll();
+ {
+ xGotValue = xQueueReceive( xSuspendedTestQueue, ( void * ) &ulReceivedValue, priNO_BLOCK );
+ }
+ if( xTaskResumeAll() != pdFALSE )
+ {
+ xSuspendedQueueReceiveError = pdTRUE;
+ }
+ }
+ xTaskResumeAll();
+
+ #if configUSE_PREEMPTION == 0
+ {
+ taskYIELD();
+ }
+ #endif
+
+ } while( xGotValue == pdFALSE );
+
+ if( ulReceivedValue != ulExpectedValue )
+ {
+ xSuspendedQueueReceiveError = pdTRUE;
+ }
+
+ if( xSuspendedQueueReceiveError != pdTRUE )
+ {
+ /* Only increment the variable if an error has not occurred. This
+ allows xAreDynamicPriorityTasksStillRunning() to check for stalled
+ tasks as well as explicit errors. */
+ ++ulExpectedValue;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* Called to check that all the created tasks are still running without error. */
+portBASE_TYPE xAreDynamicPriorityTasksStillRunning( void )
+{
+/* Keep a history of the check variables so we know if it has been incremented
+since the last call. */
+static unsigned short usLastTaskCheck = ( unsigned short ) 0;
+static unsigned long ulLastExpectedValue = ( unsigned long ) 0U;
+portBASE_TYPE xReturn = pdTRUE;
+
+ /* Check the tasks are still running by ensuring the check variable
+ is still incrementing. */
+
+ if( usCheckVariable == usLastTaskCheck )
+ {
+ /* The check has not incremented so an error exists. */
+ xReturn = pdFALSE;
+ }
+
+ if( ulExpectedValue == ulLastExpectedValue )
+ {
+ /* The value being received by the queue receive task has not
+ incremented so an error exists. */
+ xReturn = pdFALSE;
+ }
+
+ if( xSuspendedQueueSendError == pdTRUE )
+ {
+ xReturn = pdFALSE;
+ }
+
+ if( xSuspendedQueueReceiveError == pdTRUE )
+ {
+ xReturn = pdFALSE;
+ }
+
+ usLastTaskCheck = usCheckVariable;
+ ulLastExpectedValue = ulExpectedValue;
+
+ return xReturn;
+}
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/flash.c b/third_party/FreeRTOS/Demo/Common/Minimal/flash.c new file mode 100644 index 0000000..fda5870 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/flash.c @@ -0,0 +1,157 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/**
+ * This version of flash .c is for use on systems that have limited stack space
+ * and no display facilities. The complete version can be found in the
+ * Demo/Common/Full directory.
+ *
+ * Three tasks are created, each of which flash an LED at a different rate. The first
+ * LED flashes every 200ms, the second every 400ms, the third every 600ms.
+ *
+ * The LED flash tasks provide instant visual feedback. They show that the scheduler
+ * is still operational.
+ *
+ */
+
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Demo program include files. */
+#include "partest.h"
+#include "flash.h"
+
+#define ledSTACK_SIZE configMINIMAL_STACK_SIZE
+#define ledNUMBER_OF_LEDS ( 3 )
+#define ledFLASH_RATE_BASE ( ( portTickType ) 333 )
+
+/* Variable used by the created tasks to calculate the LED number to use, and
+the rate at which they should flash the LED. */
+static volatile unsigned portBASE_TYPE uxFlashTaskNumber = 0;
+
+/* The task that is created three times. */
+static portTASK_FUNCTION_PROTO( vLEDFlashTask, pvParameters );
+
+/*-----------------------------------------------------------*/
+
+void vStartLEDFlashTasks( unsigned portBASE_TYPE uxPriority )
+{
+signed portBASE_TYPE xLEDTask;
+
+ /* Create the three tasks. */
+ for( xLEDTask = 0; xLEDTask < ledNUMBER_OF_LEDS; ++xLEDTask )
+ {
+ /* Spawn the task. */
+ xTaskCreate( vLEDFlashTask, ( signed char * ) "LEDx", ledSTACK_SIZE, NULL, uxPriority, ( xTaskHandle * ) NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vLEDFlashTask, pvParameters )
+{
+portTickType xFlashRate, xLastFlashTime;
+unsigned portBASE_TYPE uxLED;
+
+ /* The parameters are not used. */
+ ( void ) pvParameters;
+
+ /* Calculate the LED and flash rate. */
+ portENTER_CRITICAL();
+ {
+ /* See which of the eight LED's we should use. */
+ uxLED = uxFlashTaskNumber;
+
+ /* Update so the next task uses the next LED. */
+ uxFlashTaskNumber++;
+ }
+ portEXIT_CRITICAL();
+
+ xFlashRate = ledFLASH_RATE_BASE + ( ledFLASH_RATE_BASE * ( portTickType ) uxLED );
+ xFlashRate /= portTICK_RATE_MS;
+
+ /* We will turn the LED on and off again in the delay period, so each
+ delay is only half the total period. */
+ xFlashRate /= ( portTickType ) 2;
+
+ /* We need to initialise xLastFlashTime prior to the first call to
+ vTaskDelayUntil(). */
+ xLastFlashTime = xTaskGetTickCount();
+
+ for(;;)
+ {
+ /* Delay for half the flash period then turn the LED on. */
+ vTaskDelayUntil( &xLastFlashTime, xFlashRate );
+ vParTestToggleLED( uxLED );
+
+ /* Delay for half the flash period then turn the LED off. */
+ vTaskDelayUntil( &xLastFlashTime, xFlashRate );
+ vParTestToggleLED( uxLED );
+ }
+} /*lint !e715 !e818 !e830 Function definition must be standard for task creation. */
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/flash_timer.c b/third_party/FreeRTOS/Demo/Common/Minimal/flash_timer.c new file mode 100644 index 0000000..a5985ff --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/flash_timer.c @@ -0,0 +1,136 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/**
+ * Repeatedly toggles one or more LEDs using software timers - one timer per
+ * LED.
+ */
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "timers.h"
+
+/* Demo program include files. */
+#include "partest.h"
+#include "flash_timer.h"
+
+/* The toggle rates are all a multple of ledFLASH_RATE_BASE. */
+#define ledFLASH_RATE_BASE ( ( ( portTickType ) 333 ) / portTICK_RATE_MS )
+
+/* A block time of zero simple means "don't block". */
+#define ledDONT_BLOCK ( ( portTickType ) 0 )
+
+/*-----------------------------------------------------------*/
+
+/*
+ * The callback function used by each LED flashing timer. All the timers use
+ * this function, and the timer ID is used within the function to determine
+ * which timer has actually expired.
+ */
+static void prvLEDTimerCallback( xTimerHandle xTimer );
+
+/*-----------------------------------------------------------*/
+
+void vStartLEDFlashTimers( unsigned portBASE_TYPE uxNumberOfLEDs )
+{
+unsigned portBASE_TYPE uxLEDTimer;
+xTimerHandle xTimer;
+
+ /* Create and start the requested number of timers. */
+ for( uxLEDTimer = 0; uxLEDTimer < uxNumberOfLEDs; ++uxLEDTimer )
+ {
+ /* Create the timer. */
+ xTimer = xTimerCreate( ( const signed char * const ) "Flasher",/* A text name, purely to help debugging. */
+ ledFLASH_RATE_BASE * ( uxLEDTimer + 1 ), /* The timer period, which is a multiple of ledFLASH_RATE_BASE. */
+ pdTRUE, /* This is an auto-reload timer, so xAutoReload is set to pdTRUE. */
+ ( void * ) uxLEDTimer, /* The ID is used to identify the timer within the timer callback function, as each timer uses the same callback. */
+ prvLEDTimerCallback /* Each timer uses the same callback. */
+ );
+
+ /* If the timer was created successfully, attempt to start it. If the
+ scheduler has not yet been started then the timer command queue must
+ be long enough to hold each command sent to it until such time that the
+ scheduler is started. The timer command queue length is set by
+ configTIMER_QUEUE_LENGTH in FreeRTOSConfig.h. */
+ if( xTimer != NULL )
+ {
+ xTimerStart( xTimer, ledDONT_BLOCK );
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvLEDTimerCallback( xTimerHandle xTimer )
+{
+portBASE_TYPE xTimerID;
+
+ /* The timer ID is used to identify the timer that has actually expired as
+ each timer uses the same callback. The ID is then also used as the number
+ of the LED that is to be toggled. */
+ xTimerID = ( portBASE_TYPE ) pvTimerGetTimerID( xTimer );
+ vParTestToggleLED( xTimerID );
+}
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/flop.c b/third_party/FreeRTOS/Demo/Common/Minimal/flop.c new file mode 100644 index 0000000..e45ec64 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/flop.c @@ -0,0 +1,383 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * Creates eight tasks, each of which loops continuously performing a 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.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Demo program include files. */
+#include "flop.h"
+
+#define mathSTACK_SIZE configMINIMAL_STACK_SIZE
+#define mathNUMBER_OF_TASKS ( 4 )
+
+/* Four tasks, each of which performs a different floating point calculation.
+Each of the four is created twice. */
+static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
+static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
+static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
+static portTASK_FUNCTION_PROTO( vCompetingMathTask4, pvParameters );
+
+/* These variables are used to check that all the tasks are still running. If a
+task gets a calculation wrong it will stop setting its check variable. */
+static volatile unsigned short usTaskCheck[ mathNUMBER_OF_TASKS ] = { ( unsigned short ) 0 };
+
+/*-----------------------------------------------------------*/
+
+void vStartMathTasks( unsigned portBASE_TYPE uxPriority )
+{
+ xTaskCreate( vCompetingMathTask1, ( signed char * ) "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask2, ( signed char * ) "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask3, ( signed char * ) "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask4, ( signed char * ) "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vCompetingMathTask1, pvParameters )
+{
+volatile portDOUBLE d1, d2, d3, d4;
+volatile unsigned short *pusTaskCheckVariable;
+volatile portDOUBLE dAnswer;
+short sError = pdFALSE;
+
+ /* Some ports require that tasks that use a hardware floating point unit
+ tell the kernel that they require a floating point context before any
+ floating point instructions are executed. */
+ portTASK_USES_FLOATING_POINT();
+
+ d1 = 123.4567;
+ d2 = 2345.6789;
+ d3 = -918.222;
+
+ dAnswer = ( d1 + d2 ) * d3;
+
+ /* 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;
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* If the calculation does not match the expected constant, stop the
+ increment of the check variable. */
+ if( fabs( d4 - dAnswer ) > 0.001 )
+ {
+ sError = pdTRUE;
+ }
+
+ if( sError == pdFALSE )
+ {
+ /* If the calculation has always been correct then set set the check
+ variable. The check variable will get set to pdFALSE each time
+ xAreMathsTaskStillRunning() is executed. */
+ ( *pusTaskCheckVariable ) = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vCompetingMathTask2, pvParameters )
+{
+volatile portDOUBLE d1, d2, d3, d4;
+volatile unsigned short *pusTaskCheckVariable;
+volatile portDOUBLE dAnswer;
+short sError = pdFALSE;
+
+ /* Some ports require that tasks that use a hardware floating point unit
+ tell the kernel that they require a floating point context before any
+ floating point instructions are executed. */
+ portTASK_USES_FLOATING_POINT();
+
+ d1 = -389.38;
+ d2 = 32498.2;
+ d3 = -2.0001;
+
+ dAnswer = ( d1 / d2 ) * d3;
+
+
+ /* 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;
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* If the calculation does not match the expected constant, stop the
+ increment of the check variable. */
+ if( fabs( d4 - dAnswer ) > 0.001 )
+ {
+ sError = pdTRUE;
+ }
+
+ if( sError == pdFALSE )
+ {
+ /* If the calculation has always been correct then set set the check
+ variable. The check variable will get set to pdFALSE each time
+ xAreMathsTaskStillRunning() is executed. */
+ ( *pusTaskCheckVariable ) = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vCompetingMathTask3, pvParameters )
+{
+volatile portDOUBLE *pdArray, dTotal1, dTotal2, dDifference;
+volatile unsigned short *pusTaskCheckVariable;
+const size_t xArraySize = 10;
+size_t xPosition;
+short sError = pdFALSE;
+
+ /* Some ports require that tasks that use a hardware floating point unit
+ tell the kernel that they require a floating point context before any
+ floating point instructions are executed. */
+ portTASK_USES_FLOATING_POINT();
+
+ /* The variable this task increments to show it is still running is passed in
+ as the parameter. */
+ pusTaskCheckVariable = ( unsigned short * ) pvParameters;
+
+ pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * 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( xPosition = 0; xPosition < xArraySize; xPosition++ )
+ {
+ pdArray[ xPosition ] = ( portDOUBLE ) xPosition + 5.5;
+ dTotal1 += ( portDOUBLE ) xPosition + 5.5;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ for( xPosition = 0; xPosition < xArraySize; xPosition++ )
+ {
+ dTotal2 += pdArray[ xPosition ];
+ }
+
+ dDifference = dTotal1 - dTotal2;
+ if( fabs( dDifference ) > 0.001 )
+ {
+ sError = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ if( sError == pdFALSE )
+ {
+ /* If the calculation has always been correct then set set the check
+ variable. The check variable will get set to pdFALSE each time
+ xAreMathsTaskStillRunning() is executed. */
+ ( *pusTaskCheckVariable ) = pdTRUE;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vCompetingMathTask4, pvParameters )
+{
+volatile portDOUBLE *pdArray, dTotal1, dTotal2, dDifference;
+volatile unsigned short *pusTaskCheckVariable;
+const size_t xArraySize = 10;
+size_t xPosition;
+short sError = pdFALSE;
+
+ /* Some ports require that tasks that use a hardware floating point unit
+ tell the kernel that they require a floating point context before any
+ floating point instructions are executed. */
+ portTASK_USES_FLOATING_POINT();
+
+ /* The variable this task increments to show it is still running is passed in
+ as the parameter. */
+ pusTaskCheckVariable = ( unsigned short * ) pvParameters;
+
+ pdArray = ( portDOUBLE * ) pvPortMalloc( xArraySize * 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( xPosition = 0; xPosition < xArraySize; xPosition++ )
+ {
+ pdArray[ xPosition ] = ( portDOUBLE ) xPosition * 12.123;
+ dTotal1 += ( portDOUBLE ) xPosition * 12.123;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ for( xPosition = 0; xPosition < xArraySize; xPosition++ )
+ {
+ dTotal2 += pdArray[ xPosition ];
+ }
+
+ dDifference = dTotal1 - dTotal2;
+ if( fabs( dDifference ) > 0.001 )
+ {
+ sError = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ if( sError == pdFALSE )
+ {
+ /* If the calculation has always been correct then set set the check
+ variable. The check variable will get set to pdFALSE each time
+ xAreMathsTaskStillRunning() is executed. */
+ ( *pusTaskCheckVariable ) = pdTRUE;
+ }
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running. */
+portBASE_TYPE xAreMathsTaskStillRunning( void )
+{
+portBASE_TYPE xReturn = pdPASS, xTask;
+
+ /* Check the maths tasks are still running by ensuring their check variables
+ have been set to pdPASS. */
+ for( xTask = 0; xTask < mathNUMBER_OF_TASKS; xTask++ )
+ {
+ if( usTaskCheck[ xTask ] != pdTRUE )
+ {
+ /* The check has not been set so the associated task has either
+ stalled or detected an error. */
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ /* Reset the variable so it can be checked again the next time this
+ function is executed. */
+ usTaskCheck[ xTask ] = pdFALSE;
+ }
+ }
+
+ return xReturn;
+}
+
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/integer.c b/third_party/FreeRTOS/Demo/Common/Minimal/integer.c new file mode 100644 index 0000000..76ea423 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/integer.c @@ -0,0 +1,201 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * Creates one or more tasks that repeatedly perform a set of integer
+ * calculations. The result of each run-time calculation is compared to the
+ * known expected result - with a mismatch being indicative of an error in the
+ * context switch mechanism.
+ */
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Demo program include files. */
+#include "integer.h"
+
+/* The constants used in the calculation. */
+#define intgCONST1 ( ( long ) 123 )
+#define intgCONST2 ( ( long ) 234567 )
+#define intgCONST3 ( ( long ) -3 )
+#define intgCONST4 ( ( long ) 7 )
+#define intgEXPECTED_ANSWER ( ( ( intgCONST1 + intgCONST2 ) * intgCONST3 ) / intgCONST4 )
+
+#define intgSTACK_SIZE configMINIMAL_STACK_SIZE
+
+/* As this is the minimal version, we will only create one task. */
+#define intgNUMBER_OF_TASKS ( 1 )
+
+/* The task function. Repeatedly performs a 32 bit calculation, checking the
+result against the expected result. If the result is incorrect then the
+context switch must have caused some corruption. */
+static portTASK_FUNCTION_PROTO( vCompeteingIntMathTask, pvParameters );
+
+/* Variables that are set to true within the calculation task to indicate
+that the task is still executing. The check task sets the variable back to
+false, flagging an error if the variable is still false the next time it
+is called. */
+static volatile signed portBASE_TYPE xTaskCheck[ intgNUMBER_OF_TASKS ] = { ( signed portBASE_TYPE ) pdFALSE };
+
+/*-----------------------------------------------------------*/
+
+void vStartIntegerMathTasks( unsigned portBASE_TYPE uxPriority )
+{
+short sTask;
+
+ for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
+ {
+ xTaskCreate( vCompeteingIntMathTask, ( signed char * ) "IntMath", intgSTACK_SIZE, ( void * ) &( xTaskCheck[ sTask ] ), uxPriority, ( xTaskHandle * ) NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vCompeteingIntMathTask, pvParameters )
+{
+/* These variables are all effectively set to constants so they are volatile to
+ensure the compiler does not just get rid of them. */
+volatile long lValue;
+short sError = pdFALSE;
+volatile signed portBASE_TYPE *pxTaskHasExecuted;
+
+ /* Set a pointer to the variable we are going to set to true each
+ iteration. This is also a good test of the parameter passing mechanism
+ within each port. */
+ pxTaskHasExecuted = ( volatile signed portBASE_TYPE * ) pvParameters;
+
+ /* Keep performing a calculation and checking the result against a constant. */
+ for( ;; )
+ {
+ /* Perform the calculation. This will store partial value in
+ registers, resulting in a good test of the context switch mechanism. */
+ lValue = intgCONST1;
+ lValue += intgCONST2;
+
+ /* Yield in case cooperative scheduling is being used. */
+ #if configUSE_PREEMPTION == 0
+ {
+ taskYIELD();
+ }
+ #endif
+
+ /* Finish off the calculation. */
+ lValue *= intgCONST3;
+ lValue /= intgCONST4;
+
+ /* If the calculation is found to be incorrect we stop setting the
+ TaskHasExecuted variable so the check task can see an error has
+ occurred. */
+ if( lValue != intgEXPECTED_ANSWER ) /*lint !e774 volatile used to prevent this being optimised out. */
+ {
+ sError = pdTRUE;
+ }
+
+ if( sError == pdFALSE )
+ {
+ /* We have not encountered any errors, so set the flag that show
+ we are still executing. This will be periodically cleared by
+ the check task. */
+ portENTER_CRITICAL();
+ *pxTaskHasExecuted = pdTRUE;
+ portEXIT_CRITICAL();
+ }
+
+ /* Yield in case cooperative scheduling is being used. */
+ #if configUSE_PREEMPTION == 0
+ {
+ taskYIELD();
+ }
+ #endif
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running. */
+portBASE_TYPE xAreIntegerMathsTaskStillRunning( void )
+{
+portBASE_TYPE xReturn = pdTRUE;
+short sTask;
+
+ /* Check the maths tasks are still running by ensuring their check variables
+ are still being set to true. */
+ for( sTask = 0; sTask < intgNUMBER_OF_TASKS; sTask++ )
+ {
+ if( xTaskCheck[ sTask ] == pdFALSE )
+ {
+ /* The check has not incremented so an error exists. */
+ xReturn = pdFALSE;
+ }
+
+ /* Reset the check variable so we can tell if it has been set by
+ the next time around. */
+ xTaskCheck[ sTask ] = pdFALSE;
+ }
+
+ return xReturn;
+}
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/recmutex.c b/third_party/FreeRTOS/Demo/Common/Minimal/recmutex.c new file mode 100644 index 0000000..760233c --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/recmutex.c @@ -0,0 +1,440 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ The tasks defined on this page demonstrate the use of recursive mutexes.
+
+ For recursive mutex functionality the created mutex should be created using
+ xSemaphoreCreateRecursiveMutex(), then be manipulated
+ using the xSemaphoreTakeRecursive() and xSemaphoreGiveRecursive() API
+ functions.
+
+ This demo creates three tasks all of which access the same recursive mutex:
+
+ prvRecursiveMutexControllingTask() has the highest priority so executes
+ first and grabs the mutex. It then performs some recursive accesses -
+ between each of which it sleeps for a short period to let the lower
+ priority tasks execute. When it has completed its demo functionality
+ it gives the mutex back before suspending itself.
+
+ prvRecursiveMutexBlockingTask() attempts to access the mutex by performing
+ a blocking 'take'. The blocking task has a lower priority than the
+ controlling task so by the time it executes the mutex has already been
+ taken by the controlling task, causing the blocking task to block. It
+ does not unblock until the controlling task has given the mutex back,
+ and it does not actually run until the controlling task has suspended
+ itself (due to the relative priorities). When it eventually does obtain
+ the mutex all it does is give the mutex back prior to also suspending
+ itself. At this point both the controlling task and the blocking task are
+ suspended.
+
+ prvRecursiveMutexPollingTask() runs at the idle priority. It spins round
+ a tight loop attempting to obtain the mutex with a non-blocking call. As
+ the lowest priority task it will not successfully obtain the mutex until
+ both the controlling and blocking tasks are suspended. Once it eventually
+ does obtain the mutex it first unsuspends both the controlling task and
+ blocking task prior to giving the mutex back - resulting in the polling
+ task temporarily inheriting the controlling tasks priority.
+*/
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* Demo app include files. */
+#include "recmutex.h"
+
+/* Priorities assigned to the three tasks. recmuCONTROLLING_TASK_PRIORITY can
+be overridden by a definition in FreeRTOSConfig.h. */
+#ifndef recmuCONTROLLING_TASK_PRIORITY
+ #define recmuCONTROLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
+#endif
+#define recmuBLOCKING_TASK_PRIORITY ( tskIDLE_PRIORITY + 1 )
+#define recmuPOLLING_TASK_PRIORITY ( tskIDLE_PRIORITY + 0 )
+
+/* The recursive call depth. */
+#define recmuMAX_COUNT ( 10 )
+
+/* Misc. */
+#define recmuSHORT_DELAY ( 20 / portTICK_RATE_MS )
+#define recmuNO_DELAY ( ( portTickType ) 0 )
+#define recmuFIVE_TICK_DELAY ( ( portTickType ) 5 )
+
+/* The three tasks as described at the top of this file. */
+static void prvRecursiveMutexControllingTask( void *pvParameters );
+static void prvRecursiveMutexBlockingTask( void *pvParameters );
+static void prvRecursiveMutexPollingTask( void *pvParameters );
+
+/* The mutex used by the demo. */
+static xSemaphoreHandle xMutex;
+
+/* Variables used to detect and latch errors. */
+static volatile portBASE_TYPE xErrorOccurred = pdFALSE, xControllingIsSuspended = pdFALSE, xBlockingIsSuspended = pdFALSE;
+static volatile unsigned portBASE_TYPE uxControllingCycles = 0, uxBlockingCycles = 0, uxPollingCycles = 0;
+
+/* Handles of the two higher priority tasks, required so they can be resumed
+(unsuspended). */
+static xTaskHandle xControllingTaskHandle, xBlockingTaskHandle;
+
+/*-----------------------------------------------------------*/
+
+void vStartRecursiveMutexTasks( void )
+{
+ /* Just creates the mutex and the three tasks. */
+
+ xMutex = xSemaphoreCreateRecursiveMutex();
+
+ /* vQueueAddToRegistry() adds the mutex to the registry, if one is
+ in use. The registry is provided as a means for kernel aware
+ debuggers to locate mutex and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( ( xQueueHandle ) xMutex, ( signed portCHAR * ) "Recursive_Mutex" );
+
+
+ if( xMutex != NULL )
+ {
+ xTaskCreate( prvRecursiveMutexControllingTask, ( signed portCHAR * ) "Rec1", configMINIMAL_STACK_SIZE, NULL, recmuCONTROLLING_TASK_PRIORITY, &xControllingTaskHandle );
+ xTaskCreate( prvRecursiveMutexBlockingTask, ( signed portCHAR * ) "Rec2", configMINIMAL_STACK_SIZE, NULL, recmuBLOCKING_TASK_PRIORITY, &xBlockingTaskHandle );
+ xTaskCreate( prvRecursiveMutexPollingTask, ( signed portCHAR * ) "Rec3", configMINIMAL_STACK_SIZE, NULL, recmuPOLLING_TASK_PRIORITY, NULL );
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvRecursiveMutexControllingTask( void *pvParameters )
+{
+unsigned portBASE_TYPE ux;
+
+ /* Just to remove compiler warning. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* Should not be able to 'give' the mutex, as we have not yet 'taken'
+ it. The first time through, the mutex will not have been used yet,
+ subsequent times through, at this point the mutex will be held by the
+ polling task. */
+ if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ for( ux = 0; ux < recmuMAX_COUNT; ux++ )
+ {
+ /* We should now be able to take the mutex as many times as
+ we like.
+
+ The first time through the mutex will be immediately available, on
+ subsequent times through the mutex will be held by the polling task
+ at this point and this Take will cause the polling task to inherit
+ the priority of this task. In this case the block time must be
+ long enough to ensure the polling task will execute again before the
+ block time expires. If the block time does expire then the error
+ flag will be set here. */
+ if( xSemaphoreTakeRecursive( xMutex, recmuFIVE_TICK_DELAY ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Ensure the other task attempting to access the mutex (and the
+ other demo tasks) are able to execute to ensure they either block
+ (where a block time is specified) or return an error (where no
+ block time is specified) as the mutex is held by this task. */
+ vTaskDelay( recmuSHORT_DELAY );
+ }
+
+ /* For each time we took the mutex, give it back. */
+ for( ux = 0; ux < recmuMAX_COUNT; ux++ )
+ {
+ /* Ensure the other task attempting to access the mutex (and the
+ other demo tasks) are able to execute. */
+ vTaskDelay( recmuSHORT_DELAY );
+
+ /* We should now be able to give the mutex as many times as we
+ took it. When the mutex is available again the Blocking task
+ should be unblocked but not run because it has a lower priority
+ than this task. The polling task should also not run at this point
+ as it too has a lower priority than this task. */
+ if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+ }
+
+ /* Having given it back the same number of times as it was taken, we
+ should no longer be the mutex owner, so the next give should fail. */
+ if( xSemaphoreGiveRecursive( xMutex ) == pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Keep count of the number of cycles this task has performed so a
+ stall can be detected. */
+ uxControllingCycles++;
+
+ /* Suspend ourselves so the blocking task can execute. */
+ xControllingIsSuspended = pdTRUE;
+ vTaskSuspend( NULL );
+ xControllingIsSuspended = pdFALSE;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvRecursiveMutexBlockingTask( void *pvParameters )
+{
+ /* Just to remove compiler warning. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* This task will run while the controlling task is blocked, and the
+ controlling task will block only once it has the mutex - therefore
+ this call should block until the controlling task has given up the
+ mutex, and not actually execute past this call until the controlling
+ task is suspended. portMAX_DELAY - 1 is used instead of portMAX_DELAY
+ to ensure the task's state is reported as Blocked and not Suspended in
+ a later call to configASSERT() (within the polling task). */
+ if( xSemaphoreTakeRecursive( xMutex, ( portMAX_DELAY - 1 ) ) == pdPASS )
+ {
+ if( xControllingIsSuspended != pdTRUE )
+ {
+ /* Did not expect to execute until the controlling task was
+ suspended. */
+ xErrorOccurred = pdTRUE;
+ }
+ else
+ {
+ /* Give the mutex back before suspending ourselves to allow
+ the polling task to obtain the mutex. */
+ if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ xBlockingIsSuspended = pdTRUE;
+ vTaskSuspend( NULL );
+ xBlockingIsSuspended = pdFALSE;
+ }
+ }
+ else
+ {
+ /* We should not leave the xSemaphoreTakeRecursive() function
+ until the mutex was obtained. */
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* The controlling and blocking tasks should be in lock step. */
+ if( uxControllingCycles != ( uxBlockingCycles + 1 ) )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ /* Keep count of the number of cycles this task has performed so a
+ stall can be detected. */
+ uxBlockingCycles++;
+ }
+}
+/*-----------------------------------------------------------*/
+
+static void prvRecursiveMutexPollingTask( void *pvParameters )
+{
+ /* Just to remove compiler warning. */
+ ( void ) pvParameters;
+
+ for( ;; )
+ {
+ /* Keep attempting to obtain the mutex. We should only obtain it when
+ the blocking task has suspended itself, which in turn should only
+ happen when the controlling task is also suspended. */
+ if( xSemaphoreTakeRecursive( xMutex, recmuNO_DELAY ) == pdPASS )
+ {
+ #if( INCLUDE_eTaskGetState == 1 )
+ {
+ configASSERT( eTaskGetState( xControllingTaskHandle ) == eSuspended );
+ configASSERT( eTaskGetState( xBlockingTaskHandle ) == eSuspended );
+ }
+ #endif /* INCLUDE_eTaskGetState */
+
+ /* Is the blocking task suspended? */
+ if( ( xBlockingIsSuspended != pdTRUE ) || ( xControllingIsSuspended != pdTRUE ) )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+ else
+ {
+ /* Keep count of the number of cycles this task has performed
+ so a stall can be detected. */
+ uxPollingCycles++;
+
+ /* We can resume the other tasks here even though they have a
+ higher priority than the polling task. When they execute they
+ will attempt to obtain the mutex but fail because the polling
+ task is still the mutex holder. The polling task (this task)
+ will then inherit the higher priority. The Blocking task will
+ block indefinitely when it attempts to obtain the mutex, the
+ Controlling task will only block for a fixed period and an
+ error will be latched if the polling task has not returned the
+ mutex by the time this fixed period has expired. */
+ vTaskResume( xBlockingTaskHandle );
+ vTaskResume( xControllingTaskHandle );
+
+ /* The other two tasks should now have executed and no longer
+ be suspended. */
+ if( ( xBlockingIsSuspended == pdTRUE ) || ( xControllingIsSuspended == pdTRUE ) )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ #if( INCLUDE_uxTaskPriorityGet == 1 )
+ {
+ /* Check priority inherited. */
+ configASSERT( uxTaskPriorityGet( NULL ) == recmuCONTROLLING_TASK_PRIORITY );
+ }
+ #endif /* INCLUDE_uxTaskPriorityGet */
+
+ #if( INCLUDE_eTaskGetState == 1 )
+ {
+ configASSERT( eTaskGetState( xControllingTaskHandle ) == eBlocked );
+ configASSERT( eTaskGetState( xBlockingTaskHandle ) == eBlocked );
+ }
+ #endif /* INCLUDE_eTaskGetState */
+
+ /* Release the mutex, disinheriting the higher priority again. */
+ if( xSemaphoreGiveRecursive( xMutex ) != pdPASS )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+
+ #if( INCLUDE_uxTaskPriorityGet == 1 )
+ {
+ /* Check priority disinherited. */
+ configASSERT( uxTaskPriorityGet( NULL ) == recmuPOLLING_TASK_PRIORITY );
+ }
+ #endif /* INCLUDE_uxTaskPriorityGet */
+ }
+ }
+
+ #if configUSE_PREEMPTION == 0
+ {
+ taskYIELD();
+ }
+ #endif
+ }
+}
+/*-----------------------------------------------------------*/
+
+/* This is called to check that all the created tasks are still running. */
+portBASE_TYPE xAreRecursiveMutexTasksStillRunning( void )
+{
+portBASE_TYPE xReturn;
+static unsigned portBASE_TYPE uxLastControllingCycles = 0, uxLastBlockingCycles = 0, uxLastPollingCycles = 0;
+
+ /* Is the controlling task still cycling? */
+ if( uxLastControllingCycles == uxControllingCycles )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+ else
+ {
+ uxLastControllingCycles = uxControllingCycles;
+ }
+
+ /* Is the blocking task still cycling? */
+ if( uxLastBlockingCycles == uxBlockingCycles )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+ else
+ {
+ uxLastBlockingCycles = uxBlockingCycles;
+ }
+
+ /* Is the polling task still cycling? */
+ if( uxLastPollingCycles == uxPollingCycles )
+ {
+ xErrorOccurred = pdTRUE;
+ }
+ else
+ {
+ uxLastPollingCycles = uxPollingCycles;
+ }
+
+ if( xErrorOccurred == pdTRUE )
+ {
+ xReturn = pdFAIL;
+ }
+ else
+ {
+ xReturn = pdTRUE;
+ }
+
+ return xReturn;
+}
+
+
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/semtest.c b/third_party/FreeRTOS/Demo/Common/Minimal/semtest.c new file mode 100644 index 0000000..f25547f --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/semtest.c @@ -0,0 +1,298 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * 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.
+ *
+ */
+
+
+#include <stdlib.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+#include "semphr.h"
+
+/* Demo app include files. */
+#include "semtest.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 ( ( portTickType ) 10 )
+
+/* The task function as described at the top of the file. */
+static portTASK_FUNCTION_PROTO( prvSemaphoreTest, pvParameters );
+
+/* Structure used to pass parameters to each task. */
+typedef struct SEMAPHORE_PARAMETERS
+{
+ xSemaphoreHandle xSemaphore;
+ volatile unsigned long *pulSharedVariable;
+ portTickType 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;
+
+/*-----------------------------------------------------------*/
+
+void vStartSemaphoreTasks( unsigned portBASE_TYPE uxPriority )
+{
+xSemaphoreParameters *pxFirstSemaphoreParameters, *pxSecondSemaphoreParameters;
+const portTickType xBlockTime = ( portTickType ) 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. */
+ pxFirstSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary();
+ xSemaphoreGive( 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 = ( portTickType ) 0;
+
+ /* Spawn the first two tasks. As they poll they operate at the idle priority. */
+ xTaskCreate( prvSemaphoreTest, ( signed char * ) "PolSEM1", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) NULL );
+ xTaskCreate( prvSemaphoreTest, ( signed char * ) "PolSEM2", semtstSTACK_SIZE, ( void * ) pxFirstSemaphoreParameters, tskIDLE_PRIORITY, ( xTaskHandle * ) 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 )
+ {
+ pxSecondSemaphoreParameters->xSemaphore = xSemaphoreCreateBinary();
+ xSemaphoreGive( pxSecondSemaphoreParameters->xSemaphore );
+
+ if( pxSecondSemaphoreParameters->xSemaphore != NULL )
+ {
+ pxSecondSemaphoreParameters->pulSharedVariable = ( unsigned long * ) pvPortMalloc( sizeof( unsigned long ) );
+ *( pxSecondSemaphoreParameters->pulSharedVariable ) = semtstBLOCKING_EXPECTED_VALUE;
+ pxSecondSemaphoreParameters->xBlockTime = xBlockTime / portTICK_RATE_MS;
+
+ xTaskCreate( prvSemaphoreTest, ( signed char * ) "BlkSEM1", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );
+ xTaskCreate( prvSemaphoreTest, ( signed char * ) "BlkSEM2", semtstSTACK_SIZE, ( void * ) pxSecondSemaphoreParameters, uxPriority, ( xTaskHandle * ) NULL );
+ }
+ }
+
+ /* vQueueAddToRegistry() adds the semaphore to the registry, if one is
+ in use. The registry is provided as a means for kernel aware
+ debuggers to locate semaphores and has no purpose if a kernel aware debugger
+ is not being used. The call to vQueueAddToRegistry() will be removed
+ by the pre-processor if configQUEUE_REGISTRY_SIZE is not defined or is
+ defined to be less than 1. */
+ vQueueAddToRegistry( ( xQueueHandle ) pxFirstSemaphoreParameters->xSemaphore, ( signed char * ) "Counting_Sem_1" );
+ vQueueAddToRegistry( ( xQueueHandle ) pxSecondSemaphoreParameters->xSemaphore, ( signed char * ) "Counting_Sem_2" );
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( prvSemaphoreTest, 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();
+
+ /* 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 > ( portTickType ) 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 )
+ {
+ 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 )
+ {
+ sError = pdTRUE;
+ }
+ }
+
+ /* Release the semaphore, and if no errors have occurred increment the check
+ variable. */
+ if( xSemaphoreGive( pxParameters->xSemaphore ) == pdFALSE )
+ {
+ 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 == ( portTickType ) 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. */
+portBASE_TYPE 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;
+}
+
+
diff --git a/third_party/FreeRTOS/Demo/Common/Minimal/sp_flop.c b/third_party/FreeRTOS/Demo/Common/Minimal/sp_flop.c new file mode 100644 index 0000000..7545344 --- /dev/null +++ b/third_party/FreeRTOS/Demo/Common/Minimal/sp_flop.c @@ -0,0 +1,365 @@ +/*
+ FreeRTOS V7.6.0 - Copyright (C) 2013 Real Time Engineers Ltd.
+ All rights reserved
+
+ VISIT http://www.FreeRTOS.org TO ENSURE YOU ARE USING THE LATEST VERSION.
+
+ ***************************************************************************
+ * *
+ * FreeRTOS provides completely free yet professionally developed, *
+ * robust, strictly quality controlled, supported, and cross *
+ * platform software that has become a de facto standard. *
+ * *
+ * Help yourself get started quickly and support the FreeRTOS *
+ * project by purchasing a FreeRTOS tutorial book, reference *
+ * manual, or both from: http://www.FreeRTOS.org/Documentation *
+ * *
+ * Thank you! *
+ * *
+ ***************************************************************************
+
+ This file is part of the FreeRTOS distribution.
+
+ FreeRTOS is free software; you can redistribute it and/or modify it under
+ the terms of the GNU General Public License (version 2) as published by the
+ Free Software Foundation >>!AND MODIFIED BY!<< the FreeRTOS exception.
+
+ >>! NOTE: The modification to the GPL is included to allow you to distribute
+ >>! a combined work that includes FreeRTOS without being obliged to provide
+ >>! the source code for proprietary components outside of the FreeRTOS
+ >>! kernel.
+
+ FreeRTOS is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. Full license text is available from the following
+ link: http://www.freertos.org/a00114.html
+
+ 1 tab == 4 spaces!
+
+ ***************************************************************************
+ * *
+ * Having a problem? Start by reading the FAQ "My application does *
+ * not run, what could be wrong?" *
+ * *
+ * http://www.FreeRTOS.org/FAQHelp.html *
+ * *
+ ***************************************************************************
+
+ http://www.FreeRTOS.org - Documentation, books, training, latest versions,
+ license and Real Time Engineers Ltd. contact details.
+
+ http://www.FreeRTOS.org/plus - A selection of FreeRTOS ecosystem products,
+ including FreeRTOS+Trace - an indispensable productivity tool, a DOS
+ compatible FAT file system, and our tiny thread aware UDP/IP stack.
+
+ http://www.OpenRTOS.com - Real Time Engineers ltd license FreeRTOS to High
+ Integrity Systems to sell under the OpenRTOS brand. Low cost OpenRTOS
+ licenses offer ticketed support, indemnification and middleware.
+
+ http://www.SafeRTOS.com - High Integrity Systems also provide a safety
+ engineered and independently SIL3 certified version for use in safety and
+ mission critical applications that require provable dependability.
+
+ 1 tab == 4 spaces!
+*/
+
+/*
+ * Creates eight tasks, each of which loops continuously performing a floating
+ * point calculation - using single precision variables.
+ *
+ * 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.
+ */
+
+#include <stdlib.h>
+#include <math.h>
+
+/* Scheduler include files. */
+#include "FreeRTOS.h"
+#include "task.h"
+
+/* Demo program include files. */
+#include "flop.h"
+
+#define mathSTACK_SIZE configMINIMAL_STACK_SIZE
+#define mathNUMBER_OF_TASKS ( 8 )
+
+/* Four tasks, each of which performs a different floating point calculation.
+Each of the four is created twice. */
+static portTASK_FUNCTION_PROTO( vCompetingMathTask1, pvParameters );
+static portTASK_FUNCTION_PROTO( vCompetingMathTask2, pvParameters );
+static portTASK_FUNCTION_PROTO( vCompetingMathTask3, pvParameters );
+static portTASK_FUNCTION_PROTO( vCompetingMathTask4, 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, ( signed char * ) "Math1", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 0 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask2, ( signed char * ) "Math2", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 1 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask3, ( signed char * ) "Math3", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 2 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask4, ( signed char * ) "Math4", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 3 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask1, ( signed char * ) "Math5", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 4 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask2, ( signed char * ) "Math6", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 5 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask3, ( signed char * ) "Math7", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 6 ] ), uxPriority, NULL );
+ xTaskCreate( vCompetingMathTask4, ( signed char * ) "Math8", mathSTACK_SIZE, ( void * ) &( usTaskCheck[ 7 ] ), uxPriority, NULL );
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vCompetingMathTask1, pvParameters )
+{
+volatile float f1, f2, f3, f4;
+volatile unsigned short *pusTaskCheckVariable;
+volatile float fAnswer;
+short sError = pdFALSE;
+
+ f1 = 123.4567F;
+ f2 = 2345.6789F;
+ f3 = -918.222F;
+
+ fAnswer = ( f1 + f2 ) * f3;
+
+ /* 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(;;)
+ {
+ f1 = 123.4567F;
+ f2 = 2345.6789F;
+ f3 = -918.222F;
+
+ f4 = ( f1 + f2 ) * f3;
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* If the calculation does not match the expected constant, stop the
+ increment of the check variable. */
+ if( fabs( f4 - fAnswer ) > 0.001F )
+ {
+ 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 )++;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vCompetingMathTask2, pvParameters )
+{
+volatile float f1, f2, f3, f4;
+volatile unsigned short *pusTaskCheckVariable;
+volatile float fAnswer;
+short sError = pdFALSE;
+
+ f1 = -389.38F;
+ f2 = 32498.2F;
+ f3 = -2.0001F;
+
+ fAnswer = ( f1 / f2 ) * f3;
+
+
+ /* 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( ;; )
+ {
+ f1 = -389.38F;
+ f2 = 32498.2F;
+ f3 = -2.0001F;
+
+ f4 = ( f1 / f2 ) * f3;
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ /* If the calculation does not match the expected constant, stop the
+ increment of the check variable. */
+ if( fabs( f4 - fAnswer ) > 0.001F )
+ {
+ 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 )++;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+ }
+}
+/*-----------------------------------------------------------*/
+
+static portTASK_FUNCTION( vCompetingMathTask3, pvParameters )
+{
+volatile float *pfArray, fTotal1, fTotal2, fDifference, fPosition;
+volatile unsigned short *pusTaskCheckVariable;
+const size_t xArraySize = 10;
+size_t xPosition;
+short sError = pdFALSE;
+
+ /* The variable this task increments to show it is still running is passed in
+ as the parameter. */
+ pusTaskCheckVariable = ( unsigned short * ) pvParameters;
+
+ pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );
+
+ /* 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( ;; )
+ {
+ fTotal1 = 0.0F;
+ fTotal2 = 0.0F;
+ fPosition = 0.0F;
+
+ for( xPosition = 0; xPosition < xArraySize; xPosition++ )
+ {
+ pfArray[ xPosition ] = fPosition + 5.5F;
+ fTotal1 += fPosition + 5.5F;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ for( xPosition = 0; xPosition < xArraySize; xPosition++ )
+ {
+ fTotal2 += pfArray[ xPosition ];
+ }
+
+ fDifference = fTotal1 - fTotal2;
+ if( fabs( fDifference ) > 0.001F )
+ {
+ sError = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ 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 portTASK_FUNCTION( vCompetingMathTask4, pvParameters )
+{
+volatile float *pfArray, fTotal1, fTotal2, fDifference, fPosition;
+volatile unsigned short *pusTaskCheckVariable;
+const size_t xArraySize = 10;
+size_t xPosition;
+short sError = pdFALSE;
+
+ /* The variable this task increments to show it is still running is passed in
+ as the parameter. */
+ pusTaskCheckVariable = ( unsigned short * ) pvParameters;
+
+ pfArray = ( float * ) pvPortMalloc( xArraySize * sizeof( float ) );
+
+ /* 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( ;; )
+ {
+ fTotal1 = 0.0F;
+ fTotal2 = 0.0F;
+ fPosition = 0.0F;
+
+ for( xPosition = 0; xPosition < xArraySize; xPosition++ )
+ {
+ pfArray[ xPosition ] = fPosition * 12.123F;
+ fTotal1 += fPosition * 12.123F;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ for( xPosition = 0; xPosition < xArraySize; xPosition++ )
+ {
+ fTotal2 += pfArray[ xPosition ];
+ }
+
+ fDifference = fTotal1 - fTotal2;
+ if( fabs( fDifference ) > 0.001F )
+ {
+ sError = pdTRUE;
+ }
+
+ #if configUSE_PREEMPTION == 0
+ taskYIELD();
+ #endif
+
+ 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;
+}
+
+
+
|
