EBIKE-FreeRTOS/Common/Minimal/StaticAllocation.c
2024-04-14 18:38:39 +08:00

1114 lines
47 KiB
C

/*
* FreeRTOS V202212.00
* Copyright (C) 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of
* this software and associated documentation files (the "Software"), to deal in
* the Software without restriction, including without limitation the rights to
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
* the Software, and to permit persons to whom the Software is furnished to do so,
* subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
* FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
* COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* https://www.FreeRTOS.org
* https://github.com/FreeRTOS
*
*/
/*
* Demonstrates how to create FreeRTOS objects using pre-allocated memory,
* rather than the normal dynamically allocated memory, and tests objects being
* created and deleted with both statically allocated memory and dynamically
* allocated memory.
*
* See http://www.FreeRTOS.org/Static_Vs_Dynamic_Memory_Allocation.html
*/
/* Scheduler include files. */
#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"
#include "event_groups.h"
#include "timers.h"
/* Demo program include files. */
#include "StaticAllocation.h"
/* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
/* The priority at which the task that performs the tests is created. */
#define staticTASK_PRIORITY ( tskIDLE_PRIORITY + 2 )
/* The length of the queue, in items, not bytes, used in the queue static
* allocation tests. */
#define staticQUEUE_LENGTH_IN_ITEMS ( 5 )
/* A block time of 0 simply means "don't block". */
#define staticDONT_BLOCK ( ( TickType_t ) 0 )
/* Binary semaphores have a maximum count of 1. */
#define staticBINARY_SEMAPHORE_MAX_COUNT ( 1 )
/* The size of the stack used by the task that runs the tests. */
#define staticCREATOR_TASK_STACK_SIZE ( configMINIMAL_STACK_SIZE * 2 )
/* The number of times the software timer will execute before stopping itself. */
#define staticMAX_TIMER_CALLBACK_EXECUTIONS ( 5 )
/*-----------------------------------------------------------*/
/*
* The task that repeatedly creates and deletes statically allocated tasks, and
* other RTOS objects.
*/
static void prvStaticallyAllocatedCreator( void * pvParameters );
/*
* The callback function used by the software timer that is repeatedly created
* and deleted using both static and dynamically allocated memory.
*/
static void prvTimerCallback( TimerHandle_t xExpiredTimer );
/*
* A task that is created and deleted multiple times, using both statically and
* dynamically allocated stack and TCB.
*/
static void prvStaticallyAllocatedTask( void * pvParameters );
/*
* A function that demonstrates and tests the API functions that create and
* delete tasks using both statically and dynamically allocated TCBs and stacks.
*/
static void prvCreateAndDeleteStaticallyAllocatedTasks( void );
/*
* A function that demonstrates and tests the API functions that create and
* delete event groups using both statically and dynamically allocated RAM.
*/
static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void );
/*
* A function that demonstrates and tests the API functions that create and
* delete queues using both statically and dynamically allocated RAM.
*/
static void prvCreateAndDeleteStaticallyAllocatedQueues( void );
/*
* A function that demonstrates and tests the API functions that create and
* delete binary semaphores using both statically and dynamically allocated RAM.
*/
static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void );
/*
* A function that demonstrates and tests the API functions that create and
* delete software timers using both statically and dynamically allocated RAM.
*/
static void prvCreateAndDeleteStaticallyAllocatedTimers( void );
/*
* A function that demonstrates and tests the API functions that create and
* delete mutexes using both statically and dynamically allocated RAM.
*/
static void prvCreateAndDeleteStaticallyAllocatedMutexes( void );
/*
* A function that demonstrates and tests the API functions that create and
* delete counting semaphores using both statically and dynamically allocated
* RAM.
*/
static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void );
/*
* A function that demonstrates and tests the API functions that create and
* delete recursive mutexes using both statically and dynamically allocated RAM.
*/
static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void );
/*
* Utility function to create pseudo random numbers.
*/
static UBaseType_t prvRand( void );
/*
* The task that creates and deletes other tasks has to delay occasionally to
* ensure lower priority tasks are not starved of processing time. A pseudo
* random delay time is used just to add a little bit of randomisation into the
* execution pattern. prvGetNextDelayTime() generates the pseudo random delay.
*/
static TickType_t prvGetNextDelayTime( void );
/*
* Checks the basic operation of a queue after it has been created.
*/
static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue );
/*
* Checks the basic operation of a recursive mutex after it has been created.
*/
static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore );
/*
* Checks the basic operation of a binary semaphore after it has been created.
*/
static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore,
UBaseType_t uxMaxCount );
/*
* Checks the basic operation of an event group after it has been created.
*/
static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup );
/*-----------------------------------------------------------*/
/* StaticTask_t is a publicly accessible structure that has the same size and
* alignment requirements as the real TCB structure. It is provided as a mechanism
* for applications to know the size of the TCB (which is dependent on the
* architecture and configuration file settings) without breaking the strict data
* hiding policy by exposing the real TCB. This StaticTask_t variable is passed
* into the xTaskCreateStatic() function that creates the
* prvStaticallyAllocatedCreator() task, and will hold the TCB of the created
* tasks. */
static StaticTask_t xCreatorTaskTCBBuffer;
/* This is the stack that will be used by the prvStaticallyAllocatedCreator()
* task, which is itself created using statically allocated buffers (so without any
* dynamic memory allocation). */
static StackType_t uxCreatorTaskStackBuffer[ staticCREATOR_TASK_STACK_SIZE ];
/* Used by the pseudo random number generating function. */
static uint32_t ulNextRand = 0;
/* Used so a check task can ensure this test is still executing, and not
* stalled. */
static volatile UBaseType_t uxCycleCounter = 0;
/* A variable that gets set to pdTRUE if an error is detected. */
static volatile BaseType_t xErrorOccurred = pdFALSE;
/*-----------------------------------------------------------*/
void vStartStaticallyAllocatedTasks( void )
{
/* Create a single task, which then repeatedly creates and deletes the other
* RTOS objects using both statically and dynamically allocated RAM. */
xTaskCreateStatic( prvStaticallyAllocatedCreator, /* The function that implements the task being created. */
"StatCreate", /* Text name for the task - not used by the RTOS, its just to assist debugging. */
staticCREATOR_TASK_STACK_SIZE, /* Size of the buffer passed in as the stack - in words, not bytes! */
NULL, /* Parameter passed into the task - not used in this case. */
staticTASK_PRIORITY, /* Priority of the task. */
&( uxCreatorTaskStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */
&xCreatorTaskTCBBuffer ); /* The variable that will hold the task's TCB. */
}
/*-----------------------------------------------------------*/
static void prvStaticallyAllocatedCreator( void * pvParameters )
{
/* Avoid compiler warnings. */
( void ) pvParameters;
for( ; ; )
{
/* Loop, running functions that create and delete the various RTOS
* objects that can be optionally created using either static or dynamic
* memory allocation. */
prvCreateAndDeleteStaticallyAllocatedTasks();
prvCreateAndDeleteStaticallyAllocatedQueues();
/* Delay to ensure lower priority tasks get CPU time, and increment the
* cycle counter so a 'check' task can determine that this task is still
* executing. */
vTaskDelay( prvGetNextDelayTime() );
uxCycleCounter++;
prvCreateAndDeleteStaticallyAllocatedBinarySemaphores();
prvCreateAndDeleteStaticallyAllocatedCountingSemaphores();
vTaskDelay( prvGetNextDelayTime() );
uxCycleCounter++;
prvCreateAndDeleteStaticallyAllocatedMutexes();
prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes();
vTaskDelay( prvGetNextDelayTime() );
uxCycleCounter++;
prvCreateAndDeleteStaticallyAllocatedEventGroups();
prvCreateAndDeleteStaticallyAllocatedTimers();
}
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedCountingSemaphores( void )
{
SemaphoreHandle_t xSemaphore;
const UBaseType_t uxMaxCount = ( UBaseType_t ) 10;
/* StaticSemaphore_t is a publicly accessible structure that has the same size
* and alignment requirements as the real semaphore structure. It is provided as a
* mechanism for applications to know the size of the semaphore (which is dependent
* on the architecture and configuration file settings) without breaking the strict
* data hiding policy by exposing the real semaphore internals. This
* StaticSemaphore_t variable is passed into the xSemaphoreCreateCountingStatic()
* function calls within this function. NOTE: In most usage scenarios now it is
* faster and more memory efficient to use a direct to task notification instead of
* a counting semaphore. http://www.freertos.org/RTOS-task-notifications.html */
StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. xSemaphoreCreateCountingStatic() has one more
* parameter than the usual xSemaphoreCreateCounting() function. The parameter
* is a pointer to the pre-allocated StaticSemaphore_t structure, which will
* hold information on the semaphore in an anonymous way. If the pointer is
* passed as NULL then the structure will be allocated dynamically, just as
* when xSemaphoreCreateCounting() is called. */
xSemaphore = xSemaphoreCreateCountingStatic( uxMaxCount, 0, &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed
* into the xSemaphoreCreateBinaryStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount );
/* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore );
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
/* Now do the same but using dynamically allocated buffers to ensure the
* delete functions are working correctly in both the static and dynamic
* allocation cases. */
xSemaphore = xSemaphoreCreateCounting( uxMaxCount, 0 );
configASSERT( xSemaphore != NULL );
prvSanityCheckCreatedSemaphore( xSemaphore, uxMaxCount );
vSemaphoreDelete( xSemaphore );
}
#endif
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedRecursiveMutexes( void )
{
SemaphoreHandle_t xSemaphore;
/* StaticSemaphore_t is a publicly accessible structure that has the same size
* and alignment requirements as the real semaphore structure. It is provided as a
* mechanism for applications to know the size of the semaphore (which is dependent
* on the architecture and configuration file settings) without breaking the strict
* data hiding policy by exposing the real semaphore internals. This
* StaticSemaphore_t variable is passed into the
* xSemaphoreCreateRecursiveMutexStatic() function calls within this function. */
StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. xSemaphoreCreateRecursiveMutexStatic() has one
* more parameter than the usual xSemaphoreCreateRecursiveMutex() function.
* The parameter is a pointer to the pre-allocated StaticSemaphore_t structure,
* which will hold information on the semaphore in an anonymous way. If the
* pointer is passed as NULL then the structure will be allocated dynamically,
* just as when xSemaphoreCreateRecursiveMutex() is called. */
xSemaphore = xSemaphoreCreateRecursiveMutexStatic( &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed
* into the xSemaphoreCreateBinaryStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Ensure the semaphore passes a few sanity checks as a valid
* recursive semaphore. */
prvSanityCheckCreatedRecursiveMutex( xSemaphore );
/* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore );
/* Now do the same using dynamically allocated buffers to ensure the delete
* functions are working correctly in both the static and dynamic memory
* allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
xSemaphore = xSemaphoreCreateRecursiveMutex();
configASSERT( xSemaphore != NULL );
prvSanityCheckCreatedRecursiveMutex( xSemaphore );
vSemaphoreDelete( xSemaphore );
}
#endif
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedQueues( void )
{
QueueHandle_t xQueue;
/* StaticQueue_t is a publicly accessible structure that has the same size and
* alignment requirements as the real queue structure. It is provided as a
* mechanism for applications to know the size of the queue (which is dependent on
* the architecture and configuration file settings) without breaking the strict
* data hiding policy by exposing the real queue internals. This StaticQueue_t
* variable is passed into the xQueueCreateStatic() function calls within this
* function. */
static StaticQueue_t xStaticQueue;
/* The queue storage area must be large enough to hold the maximum number of
* items it is possible for the queue to hold at any one time, which equals the
* queue length (in items, not bytes) multiplied by the size of each item. In this
* case the queue will hold staticQUEUE_LENGTH_IN_ITEMS 64-bit items. See
* http://www.freertos.org/Embedded-RTOS-Queues.html */
static uint8_t ucQueueStorageArea[ staticQUEUE_LENGTH_IN_ITEMS * sizeof( uint64_t ) ];
/* Create the queue. xQueueCreateStatic() has two more parameters than the
* usual xQueueCreate() function. The first new parameter is a pointer to the
* pre-allocated queue storage area. The second new parameter is a pointer to
* the StaticQueue_t structure that will hold the queue state information in
* an anonymous way. If the two pointers are passed as NULL then the data
* will be allocated dynamically as if xQueueCreate() had been called. */
xQueue = xQueueCreateStatic( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
sizeof( uint64_t ), /* The size of each item. */
ucQueueStorageArea, /* The buffer used to hold items within the queue. */
&xStaticQueue ); /* The static queue structure that will hold the state of the queue. */
/* The queue handle should equal the static queue structure passed into the
* xQueueCreateStatic() function. */
configASSERT( xQueue == ( QueueHandle_t ) &xStaticQueue );
/* Ensure the queue passes a few sanity checks as a valid queue. */
prvSanityCheckCreatedQueue( xQueue );
/* Delete the queue again so the buffers can be reused. */
vQueueDelete( xQueue );
/* Now do the same using a dynamically allocated queue to ensure the delete
* function is working correctly in both the static and dynamic memory
* allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
xQueue = xQueueCreate( staticQUEUE_LENGTH_IN_ITEMS, /* The maximum number of items the queue can hold. */
sizeof( uint64_t ) ); /* The size of each item. */
/* The queue handle should equal the static queue structure passed into the
* xQueueCreateStatic() function. */
configASSERT( xQueue != NULL );
/* Ensure the queue passes a few sanity checks as a valid queue. */
prvSanityCheckCreatedQueue( xQueue );
/* Delete the queue again so the buffers can be reused. */
vQueueDelete( xQueue );
}
#endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedMutexes( void )
{
SemaphoreHandle_t xSemaphore;
BaseType_t xReturned;
/* StaticSemaphore_t is a publicly accessible structure that has the same size
* and alignment requirements as the real semaphore structure. It is provided as a
* mechanism for applications to know the size of the semaphore (which is dependent
* on the architecture and configuration file settings) without breaking the strict
* data hiding policy by exposing the real semaphore internals. This
* StaticSemaphore_t variable is passed into the xSemaphoreCreateMutexStatic()
* function calls within this function. */
StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. xSemaphoreCreateMutexStatic() has one more
* parameter than the usual xSemaphoreCreateMutex() function. The parameter
* is a pointer to the pre-allocated StaticSemaphore_t structure, which will
* hold information on the semaphore in an anonymous way. If the pointer is
* passed as NULL then the structure will be allocated dynamically, just as
* when xSemaphoreCreateMutex() is called. */
xSemaphore = xSemaphoreCreateMutexStatic( &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed
* into the xSemaphoreCreateMutexStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Take the mutex so the mutex is in the state expected by the
* prvSanityCheckCreatedSemaphore() function. */
xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
/* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
/* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore );
/* Now do the same using a dynamically allocated mutex to ensure the delete
* function is working correctly in both the static and dynamic allocation
* cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
xSemaphore = xSemaphoreCreateMutex();
/* The semaphore handle should equal the static semaphore structure
* passed into the xSemaphoreCreateMutexStatic() function. */
configASSERT( xSemaphore != NULL );
/* Take the mutex so the mutex is in the state expected by the
* prvSanityCheckCreatedSemaphore() function. */
xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
/* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
/* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore );
}
#endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedBinarySemaphores( void )
{
SemaphoreHandle_t xSemaphore;
/* StaticSemaphore_t is a publicly accessible structure that has the same size
* and alignment requirements as the real semaphore structure. It is provided as a
* mechanism for applications to know the size of the semaphore (which is dependent
* on the architecture and configuration file settings) without breaking the strict
* data hiding policy by exposing the real semaphore internals. This
* StaticSemaphore_t variable is passed into the xSemaphoreCreateBinaryStatic()
* function calls within this function. NOTE: In most usage scenarios now it is
* faster and more memory efficient to use a direct to task notification instead of
* a binary semaphore. http://www.freertos.org/RTOS-task-notifications.html */
StaticSemaphore_t xSemaphoreBuffer;
/* Create the semaphore. xSemaphoreCreateBinaryStatic() has one more
* parameter than the usual xSemaphoreCreateBinary() function. The parameter
* is a pointer to the pre-allocated StaticSemaphore_t structure, which will
* hold information on the semaphore in an anonymous way. If the pointer is
* passed as NULL then the structure will be allocated dynamically, just as
* when xSemaphoreCreateBinary() is called. */
xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
/* The semaphore handle should equal the static semaphore structure passed
* into the xSemaphoreCreateBinaryStatic() function. */
configASSERT( xSemaphore == ( SemaphoreHandle_t ) &xSemaphoreBuffer );
/* Ensure the semaphore passes a few sanity checks as a valid semaphore. */
prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
/* Delete the semaphore again so the buffers can be reused. */
vSemaphoreDelete( xSemaphore );
/* Now do the same using a dynamically allocated semaphore to check the
* delete function is working correctly in both the static and dynamic
* allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
xSemaphore = xSemaphoreCreateBinary();
configASSERT( xSemaphore != NULL );
prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
vSemaphoreDelete( xSemaphore );
}
#endif
/* There isn't a static version of the old and deprecated
* vSemaphoreCreateBinary() macro (because its deprecated!), but check it is
* still functioning correctly. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
vSemaphoreCreateBinary( xSemaphore );
/* The macro starts with the binary semaphore available, but the test
* function expects it to be unavailable. */
if( xSemaphoreTake( xSemaphore, staticDONT_BLOCK ) == pdFAIL )
{
xErrorOccurred = __LINE__;
}
prvSanityCheckCreatedSemaphore( xSemaphore, staticBINARY_SEMAPHORE_MAX_COUNT );
vSemaphoreDelete( xSemaphore );
}
#endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
}
/*-----------------------------------------------------------*/
static void prvTimerCallback( TimerHandle_t xExpiredTimer )
{
UBaseType_t * puxVariableToIncrement;
BaseType_t xReturned;
/* The timer callback just demonstrates it is executing by incrementing a
* variable - the address of which is passed into the timer as its ID. Obtain
* the address of the variable to increment. */
puxVariableToIncrement = ( UBaseType_t * ) pvTimerGetTimerID( xExpiredTimer );
/* Increment the variable to show the timer callback has executed. */
( *puxVariableToIncrement )++;
/* If this callback has executed the required number of times, stop the
* timer. */
if( *puxVariableToIncrement == staticMAX_TIMER_CALLBACK_EXECUTIONS )
{
/* This is called from a timer callback so must not block. See
* http://www.FreeRTOS.org/FreeRTOS-timers-xTimerStop.html */
xReturned = xTimerStop( xExpiredTimer, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
}
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedTimers( void )
{
TimerHandle_t xTimer;
UBaseType_t uxVariableToIncrement;
const TickType_t xTimerPeriod = pdMS_TO_TICKS( 20 );
BaseType_t xReturned;
/* StaticTimer_t is a publicly accessible structure that has the same size
* and alignment requirements as the real timer structure. It is provided as a
* mechanism for applications to know the size of the timer structure (which is
* dependent on the architecture and configuration file settings) without breaking
* the strict data hiding policy by exposing the real timer internals. This
* StaticTimer_t variable is passed into the xTimerCreateStatic() function calls
* within this function. */
StaticTimer_t xTimerBuffer;
/* Create the software time. xTimerCreateStatic() has an extra parameter
* than the normal xTimerCreate() API function. The parameter is a pointer to
* the StaticTimer_t structure that will hold the software timer structure. If
* the parameter is passed as NULL then the structure will be allocated
* dynamically, just as if xTimerCreate() had been called. */
xTimer = xTimerCreateStatic( "T1", /* Text name for the task. Helps debugging only. Not used by FreeRTOS. */
xTimerPeriod, /* The period of the timer in ticks. */
pdTRUE, /* This is an auto-reload timer. */
( void * ) &uxVariableToIncrement, /* The variable incremented by the test is passed into the timer callback using the timer ID. */
prvTimerCallback, /* The function to execute when the timer expires. */
&xTimerBuffer ); /* The buffer that will hold the software timer structure. */
/* The timer handle should equal the static timer structure passed into the
* xTimerCreateStatic() function. */
configASSERT( xTimer == ( TimerHandle_t ) &xTimerBuffer );
/* Set the variable to 0, wait for a few timer periods to expire, then check
* the timer callback has incremented the variable to the expected value. */
uxVariableToIncrement = 0;
/* This is a low priority so a block time should not be needed. */
xReturned = xTimerStart( xTimer, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS );
/* By now the timer should have expired staticMAX_TIMER_CALLBACK_EXECUTIONS
* times, and then stopped itself. */
if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS )
{
xErrorOccurred = __LINE__;
}
/* Finished with the timer, delete it. */
xReturned = xTimerDelete( xTimer, staticDONT_BLOCK );
/* Again, as this is a low priority task it is expected that the timer
* command will have been sent even without a block time being used. */
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
/* Just to show the check task that this task is still executing. */
uxCycleCounter++;
/* Now do the same using a dynamically allocated software timer to ensure
* the delete function is working correctly in both the static and dynamic
* allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
xTimer = xTimerCreate( "T1", /* Text name for the task. Helps debugging only. Not used by FreeRTOS. */
xTimerPeriod, /* The period of the timer in ticks. */
pdTRUE, /* This is an auto-reload timer. */
( void * ) &uxVariableToIncrement, /* The variable incremented by the test is passed into the timer callback using the timer ID. */
prvTimerCallback ); /* The function to execute when the timer expires. */
configASSERT( xTimer != NULL );
uxVariableToIncrement = 0;
xReturned = xTimerStart( xTimer, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
vTaskDelay( xTimerPeriod * staticMAX_TIMER_CALLBACK_EXECUTIONS );
if( uxVariableToIncrement != staticMAX_TIMER_CALLBACK_EXECUTIONS )
{
xErrorOccurred = __LINE__;
}
xReturned = xTimerDelete( xTimer, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
}
#endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedEventGroups( void )
{
EventGroupHandle_t xEventGroup;
/* StaticEventGroup_t is a publicly accessible structure that has the same size
* and alignment requirements as the real event group structure. It is provided as
* a mechanism for applications to know the size of the event group (which is
* dependent on the architecture and configuration file settings) without breaking
* the strict data hiding policy by exposing the real event group internals. This
* StaticEventGroup_t variable is passed into the xSemaphoreCreateEventGroupStatic()
* function calls within this function. */
StaticEventGroup_t xEventGroupBuffer;
/* Create the event group. xEventGroupCreateStatic() has an extra parameter
* than the normal xEventGroupCreate() API function. The parameter is a
* pointer to the StaticEventGroup_t structure that will hold the event group
* structure. */
xEventGroup = xEventGroupCreateStatic( &xEventGroupBuffer );
/* The event group handle should equal the static event group structure
* passed into the xEventGroupCreateStatic() function. */
configASSERT( xEventGroup == ( EventGroupHandle_t ) &xEventGroupBuffer );
/* Ensure the event group passes a few sanity checks as a valid event
* group. */
prvSanityCheckCreatedEventGroup( xEventGroup );
/* Delete the event group again so the buffers can be reused. */
vEventGroupDelete( xEventGroup );
/* Now do the same using a dynamically allocated event group to ensure the
* delete function is working correctly in both the static and dynamic
* allocation cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
xEventGroup = xEventGroupCreate();
configASSERT( xEventGroup != NULL );
prvSanityCheckCreatedEventGroup( xEventGroup );
vEventGroupDelete( xEventGroup );
}
#endif
}
/*-----------------------------------------------------------*/
static void prvCreateAndDeleteStaticallyAllocatedTasks( void )
{
TaskHandle_t xCreatedTask;
/* The variable that will hold the TCB of tasks created by this function. See
* the comments above the declaration of the xCreatorTaskTCBBuffer variable for
* more information. NOTE: This is not static so relies on the tasks that use it
* being deleted before this function returns and deallocates its stack. That will
* only be the case if configUSE_PREEMPTION is set to 1. */
StaticTask_t xTCBBuffer;
/* This buffer that will be used as the stack of tasks created by this function.
* See the comments above the declaration of the uxCreatorTaskStackBuffer[] array
* above for more information. */
static StackType_t uxStackBuffer[ configMINIMAL_STACK_SIZE ];
/* Create the task. xTaskCreateStatic() has two more parameters than
* the usual xTaskCreate() function. The first new parameter is a pointer to
* the pre-allocated stack. The second new parameter is a pointer to the
* StaticTask_t structure that will hold the task's TCB. If both pointers are
* passed as NULL then the respective object will be allocated dynamically as
* if xTaskCreate() had been called. */
xCreatedTask = xTaskCreateStatic(
prvStaticallyAllocatedTask, /* Function that implements the task. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
uxTaskPriorityGet( NULL ) + 1, /* The priority of the task. */
&( uxStackBuffer[ 0 ] ), /* The buffer to use as the task's stack. */
&xTCBBuffer ); /* The variable that will hold that task's TCB. */
/* Check the task was created correctly, then delete the task. */
if( xCreatedTask == NULL )
{
xErrorOccurred = __LINE__;
}
else if( eTaskGetState( xCreatedTask ) != eSuspended )
{
/* The created task had a higher priority so should have executed and
* suspended itself by now. */
xErrorOccurred = __LINE__;
}
else
{
vTaskDelete( xCreatedTask );
}
/* Now do the same using a dynamically allocated task to ensure the delete
* function is working correctly in both the static and dynamic allocation
* cases. */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
BaseType_t xReturned;
xReturned = xTaskCreate(
prvStaticallyAllocatedTask, /* Function that implements the task - the same function is used but is actually dynamically allocated this time. */
"Static", /* Human readable name for the task. */
configMINIMAL_STACK_SIZE, /* Task's stack size, in words (not bytes!). */
NULL, /* Parameter to pass into the task. */
uxTaskPriorityGet( NULL ) + 1, /* The priority of the task. */
&xCreatedTask ); /* Handle of the task being created. */
if( eTaskGetState( xCreatedTask ) != eSuspended )
{
xErrorOccurred = __LINE__;
}
configASSERT( xReturned == pdPASS );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
vTaskDelete( xCreatedTask );
}
#endif /* if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) */
}
/*-----------------------------------------------------------*/
static void prvStaticallyAllocatedTask( void * pvParameters )
{
( void ) pvParameters;
/* The created task just suspends itself to wait to get deleted. The task
* that creates this task checks this task is in the expected Suspended state
* before deleting it. */
vTaskSuspend( NULL );
}
/*-----------------------------------------------------------*/
static UBaseType_t prvRand( void )
{
const uint32_t ulMultiplier = 0x015a4e35UL, ulIncrement = 1UL;
/* Utility function to generate a pseudo random number. */
ulNextRand = ( ulMultiplier * ulNextRand ) + ulIncrement;
return( ( ulNextRand >> 16UL ) & 0x7fffUL );
}
/*-----------------------------------------------------------*/
static TickType_t prvGetNextDelayTime( void )
{
TickType_t xNextDelay;
const TickType_t xMaxDelay = pdMS_TO_TICKS( ( TickType_t ) 150 );
const TickType_t xMinDelay = pdMS_TO_TICKS( ( TickType_t ) 75 );
const TickType_t xTinyDelay = pdMS_TO_TICKS( ( TickType_t ) 2 );
/* Generate the next delay time. This is kept within a narrow band so as
* not to disturb the timing of other tests - but does add in some pseudo
* randomisation into the tests. */
do
{
xNextDelay = prvRand() % xMaxDelay;
/* Just in case this loop is executed lots of times. */
vTaskDelay( xTinyDelay );
} while( xNextDelay < xMinDelay );
return xNextDelay;
}
/*-----------------------------------------------------------*/
static void prvSanityCheckCreatedEventGroup( EventGroupHandle_t xEventGroup )
{
EventBits_t xEventBits;
const EventBits_t xFirstTestBits = ( EventBits_t ) 0xaa, xSecondTestBits = ( EventBits_t ) 0x55;
/* The event group should not have any bits set yet. */
xEventBits = xEventGroupGetBits( xEventGroup );
if( xEventBits != ( EventBits_t ) 0 )
{
xErrorOccurred = __LINE__;
}
/* Some some bits, then read them back to check they are as expected. */
xEventGroupSetBits( xEventGroup, xFirstTestBits );
xEventBits = xEventGroupGetBits( xEventGroup );
if( xEventBits != xFirstTestBits )
{
xErrorOccurred = __LINE__;
}
xEventGroupSetBits( xEventGroup, xSecondTestBits );
xEventBits = xEventGroupGetBits( xEventGroup );
if( xEventBits != ( xFirstTestBits | xSecondTestBits ) )
{
xErrorOccurred = __LINE__;
}
/* Finally try clearing some bits too and check that operation proceeds as
* expected. */
xEventGroupClearBits( xEventGroup, xFirstTestBits );
xEventBits = xEventGroupGetBits( xEventGroup );
if( xEventBits != xSecondTestBits )
{
xErrorOccurred = __LINE__;
}
}
/*-----------------------------------------------------------*/
static void prvSanityCheckCreatedSemaphore( SemaphoreHandle_t xSemaphore,
UBaseType_t uxMaxCount )
{
BaseType_t xReturned;
UBaseType_t x;
const TickType_t xShortBlockTime = pdMS_TO_TICKS( 10 );
TickType_t xTickCount;
/* The binary semaphore should start 'empty', so a call to xSemaphoreTake()
* should fail. */
xTickCount = xTaskGetTickCount();
xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime )
{
/* Did not block on the semaphore as long as expected. */
xErrorOccurred = __LINE__;
}
if( xReturned != pdFAIL )
{
xErrorOccurred = __LINE__;
}
/* Should be possible to 'give' the semaphore up to a maximum of uxMaxCount
* times. */
for( x = 0; x < uxMaxCount; x++ )
{
xReturned = xSemaphoreGive( xSemaphore );
if( xReturned == pdFAIL )
{
xErrorOccurred = __LINE__;
}
}
/* Giving the semaphore again should fail, as it is 'full'. */
xReturned = xSemaphoreGive( xSemaphore );
if( xReturned != pdFAIL )
{
xErrorOccurred = __LINE__;
}
configASSERT( uxSemaphoreGetCount( xSemaphore ) == uxMaxCount );
/* Should now be possible to 'take' the semaphore up to a maximum of
* uxMaxCount times without blocking. */
for( x = 0; x < uxMaxCount; x++ )
{
xReturned = xSemaphoreTake( xSemaphore, staticDONT_BLOCK );
if( xReturned == pdFAIL )
{
xErrorOccurred = __LINE__;
}
}
/* Back to the starting condition, where the semaphore should not be
* available. */
xTickCount = xTaskGetTickCount();
xReturned = xSemaphoreTake( xSemaphore, xShortBlockTime );
if( ( ( TickType_t ) ( xTaskGetTickCount() - xTickCount ) ) < xShortBlockTime )
{
/* Did not block on the semaphore as long as expected. */
xErrorOccurred = __LINE__;
}
if( xReturned != pdFAIL )
{
xErrorOccurred = __LINE__;
}
configASSERT( uxSemaphoreGetCount( xSemaphore ) == 0 );
}
/*-----------------------------------------------------------*/
static void prvSanityCheckCreatedQueue( QueueHandle_t xQueue )
{
uint64_t ull, ullRead;
BaseType_t xReturned, xLoop;
/* This test is done twice to ensure the queue storage area wraps. */
for( xLoop = 0; xLoop < 2; xLoop++ )
{
/* A very basic test that the queue can be written to and read from as
* expected. First the queue should be empty. */
xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_EMPTY )
{
xErrorOccurred = __LINE__;
}
/* Now it should be possible to write to the queue staticQUEUE_LENGTH_IN_ITEMS
* times. */
for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
{
xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
}
/* Should not now be possible to write to the queue again. */
xReturned = xQueueSend( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_FULL )
{
xErrorOccurred = __LINE__;
}
/* Now read back from the queue to ensure the data read back matches that
* written. */
for( ull = 0; ull < staticQUEUE_LENGTH_IN_ITEMS; ull++ )
{
xReturned = xQueueReceive( xQueue, &ullRead, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
if( ullRead != ull )
{
xErrorOccurred = __LINE__;
}
}
/* The queue should be empty again. */
xReturned = xQueueReceive( xQueue, &ull, staticDONT_BLOCK );
if( xReturned != errQUEUE_EMPTY )
{
xErrorOccurred = __LINE__;
}
}
}
/*-----------------------------------------------------------*/
static void prvSanityCheckCreatedRecursiveMutex( SemaphoreHandle_t xSemaphore )
{
const BaseType_t xLoops = 5;
BaseType_t x, xReturned;
/* A very basic test that the recursive semaphore behaved like a recursive
* semaphore. First the semaphore should not be able to be given, as it has not
* yet been taken. */
xReturned = xSemaphoreGiveRecursive( xSemaphore );
if( xReturned != pdFAIL )
{
xErrorOccurred = __LINE__;
}
/* Now it should be possible to take the mutex a number of times. */
for( x = 0; x < xLoops; x++ )
{
xReturned = xSemaphoreTakeRecursive( xSemaphore, staticDONT_BLOCK );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
}
/* Should be possible to give the semaphore the same number of times as it
* was given in the loop above. */
for( x = 0; x < xLoops; x++ )
{
xReturned = xSemaphoreGiveRecursive( xSemaphore );
if( xReturned != pdPASS )
{
xErrorOccurred = __LINE__;
}
}
/* No more gives should be possible though. */
xReturned = xSemaphoreGiveRecursive( xSemaphore );
if( xReturned != pdFAIL )
{
xErrorOccurred = __LINE__;
}
}
/*-----------------------------------------------------------*/
BaseType_t xAreStaticAllocationTasksStillRunning( void )
{
static UBaseType_t uxLastCycleCounter = 0;
BaseType_t xReturn;
if( uxCycleCounter == uxLastCycleCounter )
{
xErrorOccurred = __LINE__;
}
else
{
uxLastCycleCounter = uxCycleCounter;
}
if( xErrorOccurred != pdFALSE )
{
xReturn = pdFAIL;
}
else
{
xReturn = pdPASS;
}
return xReturn;
}
/*-----------------------------------------------------------*/
/* Exclude the entire file if configSUPPORT_STATIC_ALLOCATION is 0. */
#endif /* configSUPPORT_STATIC_ALLOCATION == 1 */