diff --git a/FreeRTOS/Demo/WIN32-MSVC/main.c b/FreeRTOS/Demo/WIN32-MSVC/main.c
index 1160a05ea..0dc4dcd45 100644
--- a/FreeRTOS/Demo/WIN32-MSVC/main.c
+++ b/FreeRTOS/Demo/WIN32-MSVC/main.c
@@ -132,6 +132,7 @@
#include "death.h"
#include "dynamic.h"
#include "QueueSet.h"
+#include "QueueOverwrite.h"
/* Priorities at which the tasks are created. */
#define mainCHECK_TASK_PRIORITY ( configMAX_PRIORITIES - 1 )
@@ -144,6 +145,7 @@
#define mainINTEGER_TASK_PRIORITY ( tskIDLE_PRIORITY )
#define mainGEN_QUEUE_TASK_PRIORITY ( tskIDLE_PRIORITY )
#define mainFLOP_TASK_PRIORITY ( tskIDLE_PRIORITY )
+#define mainQUEUE_OVERWRITE_PRIORITY ( tskIDLE_PRIORITY )
#define mainTIMER_TEST_PERIOD ( 50 )
@@ -160,6 +162,12 @@ static void prvTestTask( void *pvParameters );
*/
static void prvSaveTraceFile( void );
+/*
+ * Called from the idle task hook function to demonstrate a few utility
+ * functions that are not demonstrated by any of the standard demo tasks.
+ */
+static void prvDemonstrateTaskStateAndHandleGetFunctions( void );
+
/*-----------------------------------------------------------*/
/* The variable into which error messages are latched. */
@@ -200,6 +208,7 @@ int main( void )
vStartCountingSemaphoreTasks();
vStartDynamicPriorityTasks();
vStartQueueSetTasks();
+ vStartQueueOverwriteTask( mainQUEUE_OVERWRITE_PRIORITY );
/* The suicide tasks must be created last as they need to know how many
tasks were running prior to their creation. This then allows them to
@@ -294,6 +303,10 @@ const portTickType xCycleFrequency = 1000 / portTICK_RATE_MS;
{
pcStatusMessage = "Error: Queue set\r\n";
}
+ else if( xIsQueueOverwriteTaskStillRunning() != pdPASS )
+ {
+ pcStatusMessage = "Error: Queue overwrite\r\n";
+ }
/* This is the only task that uses stdout so its ok to call printf()
directly. */
@@ -323,9 +336,7 @@ const unsigned long ulMSToSleep = 5;
void vApplicationIdleHook( void )
{
const unsigned long ulMSToSleep = 15;
-xTaskHandle xIdleTaskHandle, xTimerTaskHandle, xTestTask;
-signed char *pcTaskName;
-const unsigned char ucConstQueueNumber = 0xaaU, ucConstTaskNumber = 0x55U;
+const unsigned char ucConstQueueNumber = 0xaaU;
void *pvAllocated;
static portBASE_TYPE xTraceRunning = pdTRUE;
@@ -341,39 +352,9 @@ extern unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask );
tasks waiting to be terminated by the idle task. */
Sleep( ulMSToSleep );
- /* Demonstrate the use of the xTimerGetTimerDaemonTaskHandle() and
- xTaskGetIdleTaskHandle() functions. Also try using the function that sets
- the task number. */
- xIdleTaskHandle = xTaskGetIdleTaskHandle();
- xTimerTaskHandle = xTimerGetTimerDaemonTaskHandle();
- vTaskSetTaskNumber( xIdleTaskHandle, ( unsigned long ) ucConstTaskNumber );
- configASSERT( uxTaskGetTaskNumber( xIdleTaskHandle ) == ucConstTaskNumber );
-
- /* This is the idle hook, so the current task handle should equal the
- returned idle task handle. */
- if( xTaskGetCurrentTaskHandle() != xIdleTaskHandle )
- {
- pcStatusMessage = "Error: Returned idle task handle was incorrect";
- }
-
- /* Check the timer task handle was returned correctly. */
- pcTaskName = pcTaskGetTaskName( xTimerTaskHandle );
- if( strcmp( pcTaskName, "Tmr Svc" ) != 0 )
- {
- pcStatusMessage = "Error: Returned timer task handle was incorrect";
- }
-
- /* This task is running, make sure its state is returned as running. */
- if( eTaskStateGet( xIdleTaskHandle ) != eRunning )
- {
- pcStatusMessage = "Error: Returned idle task state was incorrect";
- }
-
- /* If this task is running, then the timer task must be blocked. */
- if( eTaskStateGet( xTimerTaskHandle ) != eBlocked )
- {
- pcStatusMessage = "Error: Returned timer task state was incorrect";
- }
+ /* Demonstrate a few utility functions that are not demonstrated by any of
+ the standard demo tasks. */
+ prvDemonstrateTaskStateAndHandleGetFunctions();
/* If xMutexToDelete has not already been deleted, then delete it now.
This is done purely to demonstrate the use of, and test, the
@@ -393,34 +374,6 @@ extern unsigned portBASE_TYPE uxTaskGetTaskNumber( xTaskHandle xTask );
configASSERT( ucQueueGetQueueType( xMutexToDelete ) == queueQUEUE_TYPE_MUTEX );
vSemaphoreDelete( xMutexToDelete );
xMutexToDelete = NULL;
-
- /* Other tests that should only be performed once follow. The test task
- is not created on each iteration because to do so would cause the death
- task to report an error (too many tasks running). */
-
- /* Create a test task to use to test other eTaskStateGet() return values. */
- if( xTaskCreate( prvTestTask, "Test", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTestTask ) == pdPASS )
- {
- /* If this task is running, the test task must be in the ready state. */
- if( eTaskStateGet( xTestTask ) != eReady )
- {
- pcStatusMessage = "Error: Returned test task state was incorrect 1";
- }
-
- /* Now suspend the test task and check its state is reported correctly. */
- vTaskSuspend( xTestTask );
- if( eTaskStateGet( xTestTask ) != eSuspended )
- {
- pcStatusMessage = "Error: Returned test task state was incorrect 2";
- }
-
- /* Now delete the task and check its state is reported correctly. */
- vTaskDelete( xTestTask );
- if( eTaskStateGet( xTestTask ) != eDeleted )
- {
- pcStatusMessage = "Error: Returned test task state was incorrect 3";
- }
- }
}
/* Exercise heap_4 a bit. The malloc failed hook will trap failed
@@ -499,3 +452,81 @@ FILE* pxOutputFile;
printf( "\r\nFailed to create trace dump file\r\n" );
}
}
+/*-----------------------------------------------------------*/
+
+static void prvDemonstrateTaskStateAndHandleGetFunctions( void )
+{
+xTaskHandle xIdleTaskHandle, xTimerTaskHandle;
+const unsigned char ucConstTaskNumber = 0x55U;
+signed char *pcTaskName;
+static portBASE_TYPE xPerformedOneShotTests = pdFALSE;
+xTaskHandle xTestTask;
+
+ /* Demonstrate the use of the xTimerGetTimerDaemonTaskHandle() and
+ xTaskGetIdleTaskHandle() functions. Also try using the function that sets
+ the task number. */
+ xIdleTaskHandle = xTaskGetIdleTaskHandle();
+ xTimerTaskHandle = xTimerGetTimerDaemonTaskHandle();
+ vTaskSetTaskNumber( xIdleTaskHandle, ( unsigned long ) ucConstTaskNumber );
+ configASSERT( uxTaskGetTaskNumber( xIdleTaskHandle ) == ucConstTaskNumber );
+
+ /* This is the idle hook, so the current task handle should equal the
+ returned idle task handle. */
+ if( xTaskGetCurrentTaskHandle() != xIdleTaskHandle )
+ {
+ pcStatusMessage = "Error: Returned idle task handle was incorrect";
+ }
+
+ /* Check the timer task handle was returned correctly. */
+ pcTaskName = pcTaskGetTaskName( xTimerTaskHandle );
+ if( strcmp( pcTaskName, "Tmr Svc" ) != 0 )
+ {
+ pcStatusMessage = "Error: Returned timer task handle was incorrect";
+ }
+
+ /* This task is running, make sure it's state is returned as running. */
+ if( eTaskStateGet( xIdleTaskHandle ) != eRunning )
+ {
+ pcStatusMessage = "Error: Returned idle task state was incorrect";
+ }
+
+ /* If this task is running, then the timer task must be blocked. */
+ if( eTaskStateGet( xTimerTaskHandle ) != eBlocked )
+ {
+ pcStatusMessage = "Error: Returned timer task state was incorrect";
+ }
+
+ /* Other tests that should only be performed once follow. The test task
+ is not created on each iteration because to do so would cause the death
+ task to report an error (too many tasks running). */
+ if( xPerformedOneShotTests == pdFALSE )
+ {
+ /* Don't run this part of the test again. */
+ xPerformedOneShotTests = pdTRUE;
+
+ /* Create a test task to use to test other eTaskStateGet() return values. */
+ if( xTaskCreate( prvTestTask, "Test", configMINIMAL_STACK_SIZE, NULL, tskIDLE_PRIORITY, &xTestTask ) == pdPASS )
+ {
+ /* If this task is running, the test task must be in the ready state. */
+ if( eTaskStateGet( xTestTask ) != eReady )
+ {
+ pcStatusMessage = "Error: Returned test task state was incorrect 1";
+ }
+
+ /* Now suspend the test task and check its state is reported correctly. */
+ vTaskSuspend( xTestTask );
+ if( eTaskStateGet( xTestTask ) != eSuspended )
+ {
+ pcStatusMessage = "Error: Returned test task state was incorrect 2";
+ }
+
+ /* Now delete the task and check its state is reported correctly. */
+ vTaskDelete( xTestTask );
+ if( eTaskStateGet( xTestTask ) != eDeleted )
+ {
+ pcStatusMessage = "Error: Returned test task state was incorrect 3";
+ }
+ }
+ }
+}
+
diff --git a/FreeRTOS/Source/include/queue.h b/FreeRTOS/Source/include/queue.h
index 3de926022..f81a91fae 100644
--- a/FreeRTOS/Source/include/queue.h
+++ b/FreeRTOS/Source/include/queue.h
@@ -109,8 +109,9 @@ typedef void * xQueueSetHandle;
typedef void * xQueueSetMemberHandle;
/* For internal use only. */
-#define queueSEND_TO_BACK ( 0 )
-#define queueSEND_TO_FRONT ( 1 )
+#define queueSEND_TO_BACK ( 0 )
+#define queueSEND_TO_FRONT ( 1 )
+#define queueOVERWRITE ( 2 )
/* For internal use only. These definitions *must* match those in queue.c. */
#define queueQUEUE_TYPE_BASE ( 0U )
@@ -426,6 +427,88 @@ typedef void * xQueueSetMemberHandle;
*/
#define xQueueSend( xQueue, pvItemToQueue, xTicksToWait ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), ( xTicksToWait ), queueSEND_TO_BACK )
+/**
+ * queue. h
+ *
+ portBASE_TYPE xQueueOverwrite(
+ xQueueHandle xQueue,
+ const void * pvItemToQueue,
+ );
+ *
+ *
+ * Only for use with queues that can hold a single item - so the queue is either
+ * empty or full.
+ *
+ * Post an item on a queue. If the queue is already full then overwrite the
+ * value held in the queue. The item is queued by copy, not by reference.
+ * This function must not be called from an interrupt service routine.
+ * See xQueueOverwriteFromISR () for an alternative which may be used in an ISR.
+ *
+ * @param xQueue The handle to the queue on which the item is to be posted.
+ *
+ * @param pvItemToQueue A pointer to the item that is to be placed on the
+ * queue. The size of the items the queue will hold was defined when the
+ * queue was created, so this many bytes will be copied from pvItemToQueue
+ * into the queue storage area.
+ *
+ * @return xQueueOverwrite() is a macro that calls xQueueGenericSend(), and
+ * therefore has the same return values as xQueueSendToFront(). However, as
+ * xQueueOverwrite() will write to the queue even when the queue is full pdPASS
+ * will be returned in all cases (errQUEUE_FULL will never be returned).
+ *
+ * Example usage:
+
+
+ void vFunction( void *pvParameters )
+ {
+ xQueueHandle xQueue;
+ unsigned long ulVarToSend, ulValReceived;
+
+ // Create a queue to hold one unsigned long value. It is strongly
+ // recommended *not* to use xQueueOverwrite() on queues that can
+ // contain more than one value, and doing so will trigger an assertion
+ // if configASSERT() is defined.
+ xQueue = xQueueCreate( 1, sizeof( unsigned long ) );
+
+ // Write the value 10 to the queue using xQueueOverwrite().
+ ulVarToSend = 10;
+ xQueueOverwrite( xQueue, &ulVarToSend );
+
+ // Peeking the queue should now return 10, but leave the value 10 in
+ // the queue. A block time of zero is used as it is known that the
+ // queue holds a value.
+ ulValReceived = 0;
+ xQueuePeek( xQueue, &ulValReceived, 0 );
+
+ if( ulValReceived != 10 )
+ {
+ // Error!
+ }
+
+ // The queue is still full. Use xQueueOverwrite() to overwrite the
+ // value held in the queue with 100.
+ ulVarToSend = 100;
+ xQueueOverwrite( xQueue, &ulVarToSend );
+
+ // This time read from the queue, leaving the queue empty once more.
+ // A block time of 0 is used again.
+ xQueueReceive( xQueue, &ulValReceived, 0 );
+
+ // The value read should be the last value written, even though the
+ // queue was already full when the value was written.
+ if( ulValReceived != 100 )
+ {
+ // Error!
+ }
+
+ // ...
+}
+
+ * \defgroup xQueueOverwrite xQueueOverwrite
+ * \ingroup QueueManagement
+ */
+#define xQueueOverwrite( xQueue, pvItemToQueue ) xQueueGenericSend( ( xQueue ), ( pvItemToQueue ), 0, queueOVERWRITE )
+
/**
* queue. h
diff --git a/FreeRTOS/Source/queue.c b/FreeRTOS/Source/queue.c
index 2698099f5..cd1c8545e 100644
--- a/FreeRTOS/Source/queue.c
+++ b/FreeRTOS/Source/queue.c
@@ -570,6 +570,7 @@ xQUEUE *pxQueue;
pxQueue = ( xQUEUE * ) xQueue;
configASSERT( pxQueue );
configASSERT( !( ( pvItemToQueue == NULL ) && ( pxQueue->uxItemSize != ( unsigned portBASE_TYPE ) 0U ) ) );
+ configASSERT( !( ( xCopyPosition == queueOVERWRITE ) && ( pxQueue->uxLength != 1 ) ) );
/* This function relaxes the coding standard somewhat to allow return
statements within the function itself. This is done in the interest
@@ -578,9 +579,11 @@ xQUEUE *pxQueue;
{
taskENTER_CRITICAL();
{
- /* Is there room on the queue now? To be running we must be
- the highest priority task wanting to access the queue. */
- if( pxQueue->uxMessagesWaiting < pxQueue->uxLength )
+ /* Is there room on the queue now? The running task must be
+ the highest priority task wanting to access the queue. If
+ the head item in the queue is to be overwritten then it does
+ not matter if the queue is full. */
+ if( ( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) || ( xCopyPosition == queueOVERWRITE ) )
{
traceQUEUE_SEND( pxQueue );
prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
@@ -1046,7 +1049,8 @@ xQUEUE *pxQueue;
the highest priority task wanting to access the queue. */
if( pxQueue->uxMessagesWaiting > ( unsigned portBASE_TYPE ) 0 )
{
- /* Remember our read position in case we are just peeking. */
+ /* Remember the read position in case the queue is only being
+ peeked. */
pcOriginalReadPosition = pxQueue->u.pcReadFrom;
prvCopyDataFromQueue( pxQueue, pvBuffer );
@@ -1320,7 +1324,7 @@ static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, port
pxQueue->pxMutexHolder = NULL;
}
}
- #endif
+ #endif /* configUSE_MUTEXES */
}
else if( xPosition == queueSEND_TO_BACK )
{
@@ -1339,6 +1343,18 @@ static void prvCopyDataToQueue( xQUEUE *pxQueue, const void *pvItemToQueue, port
{
pxQueue->u.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
}
+
+ if( xPosition == queueOVERWRITE )
+ {
+ if( pxQueue->uxMessagesWaiting > 0 )
+ {
+ /* An item is not being added but overwritten, so subtract
+ one from the recorded number of items in the queue so when
+ one is added again below the number of recorded items remains
+ correct. */
+ --( pxQueue->uxMessagesWaiting );
+ }
+ }
}
++( pxQueue->uxMessagesWaiting );
diff --git a/FreeRTOS/Source/tasks.c b/FreeRTOS/Source/tasks.c
index b8dd771ca..6bdf13c4f 100644
--- a/FreeRTOS/Source/tasks.c
+++ b/FreeRTOS/Source/tasks.c
@@ -115,7 +115,7 @@ typedef struct tskTaskControlBlock
xMPU_SETTINGS xMPUSettings; /*< The MPU settings are defined as part of the port layer. THIS MUST BE THE SECOND MEMBER OF THE TCB STRUCT. */
#endif
- xListItem xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
+ xListItem xGenericListItem; /*< The list that the state list item of a task is reference from denotes the state of that task (Ready, Blocked, Suspended ). */
xListItem xEventListItem; /*< Used to reference a task from an event list. */
unsigned portBASE_TYPE uxPriority; /*< The priority of the task. 0 is the lowest priority. */
portSTACK_TYPE *pxStack; /*< Points to the start of the stack. */
@@ -149,8 +149,11 @@ typedef struct tskTaskControlBlock
#if ( configUSE_NEWLIB_REENTRANT == 1 )
/* Allocate a Newlib reent structure that is specific to this task.
Note Newlib support has been included by popular demand, but is not
- used by the FreeRTOS maintainers themselves, and therefore receives
- less rigorous testing than the rest of the FreeRTOS code. */
+ used by the FreeRTOS maintainers themselves. FreeRTOS is not
+ responsible for resulting newlib operation. User must be familiar with
+ newlib and must provide system-wide implementations of the necessary
+ stubs. Be warned that (at the time of writing) the current newlib design
+ implements a system-wide malloc() that must be provided with locks. */
struct _reent xNewLib_reent;
#endif