1114 lines
47 KiB
C
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 */
|