build: W600-SDK importiert, Firmware-Build und Hello am EVK
Docker-Build mit gcc-arm-none-eabi 4.9-2014q4 (statt Homebrew-Cask) verwendet, Dockerfile/tools/docker.sh dafür aus Task 13 vorgezogen. cmake/sdk.cmake schont gcc 4.9 (kennt -fcommon/-Wno-error=... nicht). Zwei zusätzliche SDK-Stubs (EarlyInit, pre_gpio_config) in src/sys/sdk_stubs.c ergänzt, siehe sdk/PATCHES.md.
This commit is contained in:
@@ -0,0 +1,376 @@
|
||||
/*
|
||||
FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details. You should have received a copy of the GNU General Public
|
||||
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "croutine.h"
|
||||
#include "wm_config.h"
|
||||
|
||||
#if TLS_OS_FREERTOS
|
||||
/*
|
||||
* Some kernel aware debuggers require data to be viewed to be global, rather
|
||||
* than file scope.
|
||||
*/
|
||||
#ifdef portREMOVE_STATIC_QUALIFIER
|
||||
#define static
|
||||
#endif
|
||||
|
||||
|
||||
/* Lists for ready and blocked co-routines. --------------------*/
|
||||
static xList pxReadyCoRoutineLists[ configMAX_CO_ROUTINE_PRIORITIES ]; /*< Prioritised ready co-routines. */
|
||||
static xList xDelayedCoRoutineList1; /*< Delayed co-routines. */
|
||||
static xList xDelayedCoRoutineList2; /*< Delayed co-routines (two lists are used - one for delays that have overflowed the current tick count. */
|
||||
static xList * pxDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used. */
|
||||
static xList * pxOverflowDelayedCoRoutineList; /*< Points to the delayed co-routine list currently being used to hold co-routines that have overflowed the current tick count. */
|
||||
static xList xPendingReadyCoRoutineList; /*< Holds co-routines that have been readied by an external event. They cannot be added directly to the ready lists as the ready lists cannot be accessed by interrupts. */
|
||||
|
||||
/* Other file private variables. --------------------------------*/
|
||||
corCRCB * pxCurrentCoRoutine = NULL;
|
||||
static unsigned portBASE_TYPE uxTopCoRoutineReadyPriority = 0;
|
||||
static portTickType xCoRoutineTickCount = 0, xLastTickCount = 0, xPassedTicks = 0;
|
||||
|
||||
/* The initial state of the co-routine when it is created. */
|
||||
#define corINITIAL_STATE ( 0 )
|
||||
|
||||
/*
|
||||
* Place the co-routine represented by pxCRCB into the appropriate ready queue
|
||||
* for the priority. It is inserted at the end of the list.
|
||||
*
|
||||
* This macro accesses the co-routine ready lists and therefore must not be
|
||||
* used from within an ISR.
|
||||
*/
|
||||
#define prvAddCoRoutineToReadyQueue( pxCRCB ) \
|
||||
{ \
|
||||
if( pxCRCB->uxPriority > uxTopCoRoutineReadyPriority ) \
|
||||
{ \
|
||||
uxTopCoRoutineReadyPriority = pxCRCB->uxPriority; \
|
||||
} \
|
||||
vListInsertEnd( ( xList * ) &( pxReadyCoRoutineLists[ pxCRCB->uxPriority ] ), &( pxCRCB->xGenericListItem ) ); \
|
||||
}
|
||||
|
||||
/*
|
||||
* Utility to ready all the lists used by the scheduler. This is called
|
||||
* automatically upon the creation of the first co-routine.
|
||||
*/
|
||||
static void prvInitialiseCoRoutineLists( void );
|
||||
|
||||
/*
|
||||
* Co-routines that are readied by an interrupt cannot be placed directly into
|
||||
* the ready lists (there is no mutual exclusion). Instead they are placed in
|
||||
* in the pending ready list in order that they can later be moved to the ready
|
||||
* list by the co-routine scheduler.
|
||||
*/
|
||||
static void prvCheckPendingReadyList( void );
|
||||
|
||||
/*
|
||||
* Macro that looks at the list of co-routines that are currently delayed to
|
||||
* see if any require waking.
|
||||
*
|
||||
* Co-routines are stored in the queue in the order of their wake time -
|
||||
* meaning once one co-routine has been found whose timer has not expired
|
||||
* we need not look any further down the list.
|
||||
*/
|
||||
static void prvCheckDelayedList( void );
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xCoRoutineCreate( crCOROUTINE_CODE pxCoRoutineCode, unsigned portBASE_TYPE uxPriority, unsigned portBASE_TYPE uxIndex )
|
||||
{
|
||||
signed portBASE_TYPE xReturn;
|
||||
corCRCB *pxCoRoutine;
|
||||
|
||||
/* Allocate the memory that will store the co-routine control block. */
|
||||
pxCoRoutine = ( corCRCB * ) pvPortMalloc( sizeof( corCRCB ) );
|
||||
if( pxCoRoutine )
|
||||
{
|
||||
/* If pxCurrentCoRoutine is NULL then this is the first co-routine to
|
||||
be created and the co-routine data structures need initialising. */
|
||||
if( pxCurrentCoRoutine == NULL )
|
||||
{
|
||||
pxCurrentCoRoutine = pxCoRoutine;
|
||||
prvInitialiseCoRoutineLists();
|
||||
}
|
||||
|
||||
/* Check the priority is within limits. */
|
||||
if( uxPriority >= configMAX_CO_ROUTINE_PRIORITIES )
|
||||
{
|
||||
uxPriority = configMAX_CO_ROUTINE_PRIORITIES - 1;
|
||||
}
|
||||
|
||||
/* Fill out the co-routine control block from the function parameters. */
|
||||
pxCoRoutine->uxState = corINITIAL_STATE;
|
||||
pxCoRoutine->uxPriority = uxPriority;
|
||||
pxCoRoutine->uxIndex = uxIndex;
|
||||
pxCoRoutine->pxCoRoutineFunction = pxCoRoutineCode;
|
||||
|
||||
/* Initialise all the other co-routine control block parameters. */
|
||||
vListInitialiseItem( &( pxCoRoutine->xGenericListItem ) );
|
||||
vListInitialiseItem( &( pxCoRoutine->xEventListItem ) );
|
||||
|
||||
/* Set the co-routine control block as a link back from the xListItem.
|
||||
This is so we can get back to the containing CRCB from a generic item
|
||||
in a list. */
|
||||
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xGenericListItem ), pxCoRoutine );
|
||||
listSET_LIST_ITEM_OWNER( &( pxCoRoutine->xEventListItem ), pxCoRoutine );
|
||||
|
||||
/* Event lists are always in priority order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCoRoutine->xEventListItem ), configMAX_PRIORITIES - ( portTickType ) uxPriority );
|
||||
|
||||
/* Now the co-routine has been initialised it can be added to the ready
|
||||
list at the correct priority. */
|
||||
prvAddCoRoutineToReadyQueue( pxCoRoutine );
|
||||
|
||||
xReturn = pdPASS;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCoRoutineAddToDelayedList( portTickType xTicksToDelay, xList *pxEventList )
|
||||
{
|
||||
portTickType xTimeToWake;
|
||||
|
||||
/* Calculate the time to wake - this may overflow but this is
|
||||
not a problem. */
|
||||
xTimeToWake = xCoRoutineTickCount + xTicksToDelay;
|
||||
|
||||
/* We must remove ourselves from the ready list before adding
|
||||
ourselves to the blocked list as the same list item is used for
|
||||
both lists. */
|
||||
vListRemove( ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||
|
||||
/* The list item will be inserted in wake time order. */
|
||||
listSET_LIST_ITEM_VALUE( &( pxCurrentCoRoutine->xGenericListItem ), xTimeToWake );
|
||||
|
||||
if( xTimeToWake < xCoRoutineTickCount )
|
||||
{
|
||||
/* Wake time has overflowed. Place this item in the
|
||||
overflow list. */
|
||||
vListInsert( ( xList * ) pxOverflowDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wake time has not overflowed, so we can use the
|
||||
current block list. */
|
||||
vListInsert( ( xList * ) pxDelayedCoRoutineList, ( xListItem * ) &( pxCurrentCoRoutine->xGenericListItem ) );
|
||||
}
|
||||
|
||||
if( pxEventList )
|
||||
{
|
||||
/* Also add the co-routine to an event list. If this is done then the
|
||||
function must be called with interrupts disabled. */
|
||||
vListInsert( pxEventList, &( pxCurrentCoRoutine->xEventListItem ) );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckPendingReadyList( void )
|
||||
{
|
||||
/* Are there any co-routines waiting to get moved to the ready list? These
|
||||
are co-routines that have been readied by an ISR. The ISR cannot access
|
||||
the ready lists itself. */
|
||||
while( listLIST_IS_EMPTY( &xPendingReadyCoRoutineList ) == pdFALSE )
|
||||
{
|
||||
corCRCB *pxUnblockedCRCB;
|
||||
|
||||
/* The pending ready list can be accessed by an ISR. */
|
||||
portDISABLE_INTERRUPTS();
|
||||
{
|
||||
pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( (&xPendingReadyCoRoutineList) );
|
||||
vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
|
||||
vListRemove( &( pxUnblockedCRCB->xGenericListItem ) );
|
||||
prvAddCoRoutineToReadyQueue( pxUnblockedCRCB );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckDelayedList( void )
|
||||
{
|
||||
corCRCB *pxCRCB;
|
||||
|
||||
xPassedTicks = xTaskGetTickCount() - xLastTickCount;
|
||||
while( xPassedTicks )
|
||||
{
|
||||
xCoRoutineTickCount++;
|
||||
xPassedTicks--;
|
||||
|
||||
/* If the tick count has overflowed we need to swap the ready lists. */
|
||||
if( xCoRoutineTickCount == 0 )
|
||||
{
|
||||
xList * pxTemp;
|
||||
|
||||
/* Tick count has overflowed so we need to swap the delay lists. If there are
|
||||
any items in pxDelayedCoRoutineList here then there is an error! */
|
||||
pxTemp = pxDelayedCoRoutineList;
|
||||
pxDelayedCoRoutineList = pxOverflowDelayedCoRoutineList;
|
||||
pxOverflowDelayedCoRoutineList = pxTemp;
|
||||
}
|
||||
|
||||
/* See if this tick has made a timeout expire. */
|
||||
while( listLIST_IS_EMPTY( pxDelayedCoRoutineList ) == pdFALSE )
|
||||
{
|
||||
pxCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxDelayedCoRoutineList );
|
||||
|
||||
if( xCoRoutineTickCount < listGET_LIST_ITEM_VALUE( &( pxCRCB->xGenericListItem ) ) )
|
||||
{
|
||||
/* Timeout not yet expired. */
|
||||
break;
|
||||
}
|
||||
|
||||
portDISABLE_INTERRUPTS();
|
||||
{
|
||||
/* The event could have occurred just before this critical
|
||||
section. If this is the case then the generic list item will
|
||||
have been moved to the pending ready list and the following
|
||||
line is still valid. Also the pvContainer parameter will have
|
||||
been set to NULL so the following lines are also valid. */
|
||||
vListRemove( &( pxCRCB->xGenericListItem ) );
|
||||
|
||||
/* Is the co-routine waiting on an event also? */
|
||||
if( pxCRCB->xEventListItem.pvContainer )
|
||||
{
|
||||
vListRemove( &( pxCRCB->xEventListItem ) );
|
||||
}
|
||||
}
|
||||
portENABLE_INTERRUPTS();
|
||||
|
||||
prvAddCoRoutineToReadyQueue( pxCRCB );
|
||||
}
|
||||
}
|
||||
|
||||
xLastTickCount = xCoRoutineTickCount;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vCoRoutineSchedule( void )
|
||||
{
|
||||
/* See if any co-routines readied by events need moving to the ready lists. */
|
||||
prvCheckPendingReadyList();
|
||||
|
||||
/* See if any delayed co-routines have timed out. */
|
||||
prvCheckDelayedList();
|
||||
|
||||
/* Find the highest priority queue that contains ready co-routines. */
|
||||
while( listLIST_IS_EMPTY( &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) ) )
|
||||
{
|
||||
if( uxTopCoRoutineReadyPriority == 0 )
|
||||
{
|
||||
/* No more co-routines to check. */
|
||||
return;
|
||||
}
|
||||
--uxTopCoRoutineReadyPriority;
|
||||
}
|
||||
|
||||
/* listGET_OWNER_OF_NEXT_ENTRY walks through the list, so the co-routines
|
||||
of the same priority get an equal share of the processor time. */
|
||||
listGET_OWNER_OF_NEXT_ENTRY( pxCurrentCoRoutine, &( pxReadyCoRoutineLists[ uxTopCoRoutineReadyPriority ] ) );
|
||||
|
||||
/* Call the co-routine. */
|
||||
( pxCurrentCoRoutine->pxCoRoutineFunction )( pxCurrentCoRoutine, pxCurrentCoRoutine->uxIndex );
|
||||
|
||||
return;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInitialiseCoRoutineLists( void )
|
||||
{
|
||||
unsigned portBASE_TYPE uxPriority;
|
||||
|
||||
for( uxPriority = 0; uxPriority < configMAX_CO_ROUTINE_PRIORITIES; uxPriority++ )
|
||||
{
|
||||
vListInitialise( ( xList * ) &( pxReadyCoRoutineLists[ uxPriority ] ) );
|
||||
}
|
||||
|
||||
vListInitialise( ( xList * ) &xDelayedCoRoutineList1 );
|
||||
vListInitialise( ( xList * ) &xDelayedCoRoutineList2 );
|
||||
vListInitialise( ( xList * ) &xPendingReadyCoRoutineList );
|
||||
|
||||
/* Start with pxDelayedCoRoutineList using list1 and the
|
||||
pxOverflowDelayedCoRoutineList using list2. */
|
||||
pxDelayedCoRoutineList = &xDelayedCoRoutineList1;
|
||||
pxOverflowDelayedCoRoutineList = &xDelayedCoRoutineList2;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
signed portBASE_TYPE xCoRoutineRemoveFromEventList( const xList *pxEventList )
|
||||
{
|
||||
corCRCB *pxUnblockedCRCB;
|
||||
signed portBASE_TYPE xReturn;
|
||||
|
||||
/* This function is called from within an interrupt. It can only access
|
||||
event lists and the pending ready list. This function assumes that a
|
||||
check has already been made to ensure pxEventList is not empty. */
|
||||
pxUnblockedCRCB = ( corCRCB * ) listGET_OWNER_OF_HEAD_ENTRY( pxEventList );
|
||||
vListRemove( &( pxUnblockedCRCB->xEventListItem ) );
|
||||
vListInsertEnd( ( xList * ) &( xPendingReadyCoRoutineList ), &( pxUnblockedCRCB->xEventListItem ) );
|
||||
|
||||
if( pxUnblockedCRCB->uxPriority >= pxCurrentCoRoutine->uxPriority )
|
||||
{
|
||||
xReturn = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = pdFALSE;
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,288 @@
|
||||
/*
|
||||
FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details. You should have received a copy of the GNU General Public
|
||||
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/*
|
||||
* A sample implementation of pvPortMalloc() and vPortFree() that permits
|
||||
* allocated blocks to be freed, but does not combine adjacent free blocks
|
||||
* into a single larger block.
|
||||
*
|
||||
* See heap_1.c and heap_3.c for alternative implementations, and the memory
|
||||
* management pages of http://www.FreeRTOS.org for more information.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "wm_config.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
#if TLS_OS_FREERTOS
|
||||
#if configUSE_HEAP2
|
||||
/* Allocate the memory for the heap. The struct is used to force byte
|
||||
alignment without using any non-portable code. */
|
||||
static union xRTOS_HEAP
|
||||
{
|
||||
#if portBYTE_ALIGNMENT == 8
|
||||
volatile portDOUBLE dDummy;
|
||||
#else
|
||||
volatile unsigned long ulDummy;
|
||||
#endif
|
||||
unsigned char ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
} xHeap;
|
||||
|
||||
/* Define the linked list structure. This is used to link free blocks in order
|
||||
of their size. */
|
||||
typedef struct A_BLOCK_LINK
|
||||
{
|
||||
struct A_BLOCK_LINK *pxNextFreeBlock; /*<< The next free block in the list. */
|
||||
size_t xBlockSize; /*<< The size of the free block. */
|
||||
} xBlockLink;
|
||||
|
||||
|
||||
static const unsigned short heapSTRUCT_SIZE = ( sizeof( xBlockLink ) + portBYTE_ALIGNMENT - ( sizeof( xBlockLink ) % portBYTE_ALIGNMENT ) );
|
||||
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( heapSTRUCT_SIZE * 2 ) )
|
||||
|
||||
/* Create a couple of list links to mark the start and end of the list. */
|
||||
static xBlockLink xStart, xEnd;
|
||||
|
||||
/* Keeps track of the number of free bytes remaining, but says nothing about
|
||||
fragmentation. */
|
||||
static size_t xFreeBytesRemaining = configTOTAL_HEAP_SIZE;
|
||||
|
||||
/* STATIC FUNCTIONS ARE DEFINED AS MACROS TO MINIMIZE THE FUNCTION CALL DEPTH. */
|
||||
|
||||
/*
|
||||
* Insert a block into the list of free blocks - which is ordered by size of
|
||||
* the block. Small blocks at the start of the list and large blocks at the end
|
||||
* of the list.
|
||||
*/
|
||||
#define prvInsertBlockIntoFreeList( pxBlockToInsert ) \
|
||||
{ \
|
||||
xBlockLink *pxIterator; \
|
||||
size_t xBlockSize; \
|
||||
\
|
||||
xBlockSize = pxBlockToInsert->xBlockSize; \
|
||||
\
|
||||
/* Iterate through the list until a block is found that has a larger size */ \
|
||||
/* than the block we are inserting. */ \
|
||||
for( pxIterator = &xStart; pxIterator->pxNextFreeBlock->xBlockSize < xBlockSize; pxIterator = pxIterator->pxNextFreeBlock ) \
|
||||
{ \
|
||||
/* There is nothing to do here - just iterate to the correct position. */ \
|
||||
} \
|
||||
\
|
||||
/* Update the list to include the block being inserted in the correct */ \
|
||||
/* position. */ \
|
||||
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock; \
|
||||
pxIterator->pxNextFreeBlock = pxBlockToInsert; \
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#define prvHeapInit() \
|
||||
{ \
|
||||
xBlockLink *pxFirstFreeBlock; \
|
||||
\
|
||||
/* xStart is used to hold a pointer to the first item in the list of free */ \
|
||||
/* blocks. The void cast is used to prevent compiler warnings. */ \
|
||||
xStart.pxNextFreeBlock = ( void * ) xHeap.ucHeap; \
|
||||
xStart.xBlockSize = ( size_t ) 0; \
|
||||
\
|
||||
/* xEnd is used to mark the end of the list of free blocks. */ \
|
||||
xEnd.xBlockSize = configTOTAL_HEAP_SIZE; \
|
||||
xEnd.pxNextFreeBlock = NULL; \
|
||||
\
|
||||
/* To start with there is a single free block that is sized to take up the \
|
||||
entire heap space. */ \
|
||||
pxFirstFreeBlock = ( void * ) xHeap.ucHeap; \
|
||||
pxFirstFreeBlock->xBlockSize = configTOTAL_HEAP_SIZE; \
|
||||
pxFirstFreeBlock->pxNextFreeBlock = &xEnd; \
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void *pvPortMalloc( size_t xWantedSize )
|
||||
{
|
||||
xBlockLink *pxBlock, *pxPreviousBlock, *pxNewBlockLink;
|
||||
static portBASE_TYPE xHeapHasBeenInitialised = pdFALSE;
|
||||
void *pvReturn = NULL;
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* If this is the first call to malloc then the heap will require
|
||||
initialisation to setup the list of free blocks. */
|
||||
if( xHeapHasBeenInitialised == pdFALSE )
|
||||
{
|
||||
prvHeapInit();
|
||||
xHeapHasBeenInitialised = pdTRUE;
|
||||
}
|
||||
|
||||
/* The wanted size is increased so it can contain a xBlockLink
|
||||
structure in addition to the requested amount of bytes. */
|
||||
if( xWantedSize > 0 )
|
||||
{
|
||||
xWantedSize += heapSTRUCT_SIZE;
|
||||
|
||||
/* Ensure that blocks are always aligned to the required number of bytes. */
|
||||
if( xWantedSize & portBYTE_ALIGNMENT_MASK )
|
||||
{
|
||||
/* Byte alignment required. */
|
||||
xWantedSize += ( portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK ) );
|
||||
}
|
||||
}
|
||||
|
||||
if( ( xWantedSize > 0 ) && ( xWantedSize < configTOTAL_HEAP_SIZE ) )
|
||||
{
|
||||
/* Blocks are stored in byte order - traverse the list from the start
|
||||
(smallest) block until one of adequate size is found. */
|
||||
pxPreviousBlock = &xStart;
|
||||
pxBlock = xStart.pxNextFreeBlock;
|
||||
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock ) )
|
||||
{
|
||||
pxPreviousBlock = pxBlock;
|
||||
pxBlock = pxBlock->pxNextFreeBlock;
|
||||
}
|
||||
|
||||
/* If we found the end marker then a block of adequate size was not found. */
|
||||
if( pxBlock != &xEnd )
|
||||
{
|
||||
/* Return the memory space - jumping over the xBlockLink structure
|
||||
at its start. */
|
||||
pvReturn = ( void * ) ( ( ( unsigned char * ) pxPreviousBlock->pxNextFreeBlock ) + heapSTRUCT_SIZE );
|
||||
|
||||
/* This block is being returned for use so must be taken our of the
|
||||
list of free blocks. */
|
||||
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
|
||||
|
||||
/* If the block is larger than required it can be split into two. */
|
||||
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||
{
|
||||
/* This block is to be split into two. Create a new block
|
||||
following the number of bytes requested. The void cast is
|
||||
used to prevent byte alignment warnings from the compiler. */
|
||||
pxNewBlockLink = ( void * ) ( ( ( unsigned char * ) pxBlock ) + xWantedSize );
|
||||
|
||||
/* Calculate the sizes of two blocks split from the single
|
||||
block. */
|
||||
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
|
||||
pxBlock->xBlockSize = xWantedSize;
|
||||
|
||||
/* Insert the new block into the list of free blocks. */
|
||||
prvInsertBlockIntoFreeList( ( pxNewBlockLink ) );
|
||||
}
|
||||
|
||||
xFreeBytesRemaining -= pxBlock->xBlockSize;
|
||||
}
|
||||
}
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
|
||||
{
|
||||
if( pvReturn == NULL )
|
||||
{
|
||||
extern void vApplicationMallocFailedHook( void );
|
||||
vApplicationMallocFailedHook();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return pvReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortFree( void *pv )
|
||||
{
|
||||
unsigned char *puc = ( unsigned char * ) pv;
|
||||
xBlockLink *pxLink;
|
||||
|
||||
if( pv )
|
||||
{
|
||||
/* The memory being freed will have an xBlockLink structure immediately
|
||||
before it. */
|
||||
puc -= heapSTRUCT_SIZE;
|
||||
|
||||
/* This casting is to keep the compiler from issuing warnings. */
|
||||
pxLink = ( void * ) puc;
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Add this block to the list of free blocks. */
|
||||
prvInsertBlockIntoFreeList( ( ( xBlockLink * ) pxLink ) );
|
||||
xFreeBytesRemaining += pxLink->xBlockSize;
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetFreeHeapSize( void )
|
||||
{
|
||||
return xFreeBytesRemaining;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortInitialiseBlocks( void )
|
||||
{
|
||||
/* This just exists to keep the linker quiet. */
|
||||
}
|
||||
|
||||
int xPortMemIsKernel(void *mem)
|
||||
{
|
||||
return ((mem >= (void *)xHeap.ucHeap) && (mem <= (void *)(xHeap.ucHeap + configTOTAL_HEAP_SIZE))) ? 1 : 0;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details. You should have received a copy of the GNU General Public
|
||||
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
/*
|
||||
* Implementation of pvPortMalloc() and vPortFree() that relies on the
|
||||
* compilers own malloc() and free() implementations.
|
||||
*
|
||||
* This file can only be used if the linker is configured to to generate
|
||||
* a heap memory area.
|
||||
*
|
||||
* See heap_2.c and heap_1.c for alternative implementations, and the memory
|
||||
* management pages of http://www.FreeRTOS.org for more information.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "wm_config.h"
|
||||
#include "wm_mem.h"
|
||||
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
#if TLS_OS_FREERTOS
|
||||
#if configUSE_HEAP3
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void *pvPortMalloc( size_t xWantedSize )
|
||||
{
|
||||
void *pvReturn;
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
pvReturn = tls_mem_alloc( xWantedSize );
|
||||
}
|
||||
xTaskResumeAll();
|
||||
|
||||
#if( configUSE_MALLOC_FAILED_HOOK == 1 )
|
||||
{
|
||||
if( pvReturn == NULL )
|
||||
{
|
||||
extern void vApplicationMallocFailedHook( void );
|
||||
vApplicationMallocFailedHook();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return pvReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortFree( void *pv )
|
||||
{
|
||||
if( pv )
|
||||
{
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
tls_mem_free( pv );
|
||||
}
|
||||
xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
@@ -0,0 +1,600 @@
|
||||
/*
|
||||
* FreeRTOS Kernel <DEVELOPMENT BRANCH>
|
||||
* Copyright (C) 2021 Amazon.com, Inc. or its affiliates. All Rights Reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: MIT
|
||||
*
|
||||
* 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
|
||||
*
|
||||
*/
|
||||
|
||||
/*
|
||||
* A sample implementation of pvPortMalloc() and vPortFree() that combines
|
||||
* (coalescences) adjacent memory blocks as they are freed, and in so doing
|
||||
* limits memory fragmentation.
|
||||
*
|
||||
* See heap_1.c, heap_2.c and heap_3.c for alternative implementations, and the
|
||||
* memory management pages of https://www.FreeRTOS.org for more information.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#define configSUPPORT_DYNAMIC_ALLOCATION 1
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "wm_config.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
#if configUSE_HEAP4
|
||||
|
||||
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 0 )
|
||||
#error This file must not be used if configSUPPORT_DYNAMIC_ALLOCATION is 0
|
||||
#endif
|
||||
|
||||
#ifndef configHEAP_CLEAR_MEMORY_ON_FREE
|
||||
#define configHEAP_CLEAR_MEMORY_ON_FREE 0
|
||||
#endif
|
||||
|
||||
/* Block sizes must not get too small. */
|
||||
#define heapMINIMUM_BLOCK_SIZE ( ( size_t ) ( xHeapStructSize << 1 ) )
|
||||
|
||||
/* Assumes 8bit bytes! */
|
||||
#define heapBITS_PER_BYTE ( ( size_t ) 8 )
|
||||
|
||||
/* Max value that fits in a size_t type. */
|
||||
#define heapSIZE_MAX ( ~( ( size_t ) 0 ) )
|
||||
|
||||
/* Check if multiplying a and b will result in overflow. */
|
||||
#define heapMULTIPLY_WILL_OVERFLOW( a, b ) ( ( ( a ) > 0 ) && ( ( b ) > ( heapSIZE_MAX / ( a ) ) ) )
|
||||
|
||||
/* Check if adding a and b will result in overflow. */
|
||||
#define heapADD_WILL_OVERFLOW( a, b ) ( ( a ) > ( heapSIZE_MAX - ( b ) ) )
|
||||
|
||||
/* Check if the subtraction operation ( a - b ) will result in underflow. */
|
||||
#define heapSUBTRACT_WILL_UNDERFLOW( a, b ) ( ( a ) < ( b ) )
|
||||
|
||||
/* MSB of the xBlockSize member of an BlockLink_t structure is used to track
|
||||
* the allocation status of a block. When MSB of the xBlockSize member of
|
||||
* an BlockLink_t structure is set then the block belongs to the application.
|
||||
* When the bit is free the block is still part of the free heap space. */
|
||||
#define heapBLOCK_ALLOCATED_BITMASK ( ( ( size_t ) 1 ) << ( ( sizeof( size_t ) * heapBITS_PER_BYTE ) - 1 ) )
|
||||
#define heapBLOCK_SIZE_IS_VALID( xBlockSize ) ( ( ( xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) == 0 )
|
||||
#define heapBLOCK_IS_ALLOCATED( pxBlock ) ( ( ( pxBlock->xBlockSize ) & heapBLOCK_ALLOCATED_BITMASK ) != 0 )
|
||||
#define heapALLOCATE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) |= heapBLOCK_ALLOCATED_BITMASK )
|
||||
#define heapFREE_BLOCK( pxBlock ) ( ( pxBlock->xBlockSize ) &= ~heapBLOCK_ALLOCATED_BITMASK )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* Allocate the memory for the heap. */
|
||||
#if ( configAPPLICATION_ALLOCATED_HEAP == 1 )
|
||||
|
||||
/* The application writer has already defined the array used for the RTOS
|
||||
* heap - probably so it can be placed in a special segment or address. */
|
||||
extern uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
#else
|
||||
PRIVILEGED_DATA static uint8_t ucHeap[ configTOTAL_HEAP_SIZE ];
|
||||
#endif /* configAPPLICATION_ALLOCATED_HEAP */
|
||||
|
||||
/* Define the linked list structure. This is used to link free blocks in order
|
||||
* of their memory address. */
|
||||
typedef struct A_BLOCK_LINK
|
||||
{
|
||||
struct A_BLOCK_LINK * pxNextFreeBlock; /**< The next free block in the list. */
|
||||
size_t xBlockSize; /**< The size of the free block. */
|
||||
} BlockLink_t;
|
||||
|
||||
/* Setting configENABLE_HEAP_PROTECTOR to 1 enables heap block pointers
|
||||
* protection using an application supplied canary value to catch heap
|
||||
* corruption should a heap buffer overflow occur.
|
||||
*/
|
||||
#if ( configENABLE_HEAP_PROTECTOR == 1 )
|
||||
|
||||
/**
|
||||
* @brief Application provided function to get a random value to be used as canary.
|
||||
*
|
||||
* @param pxHeapCanary [out] Output parameter to return the canary value.
|
||||
*/
|
||||
extern void vApplicationGetRandomHeapCanary( portPOINTER_SIZE_TYPE * pxHeapCanary );
|
||||
|
||||
/* Canary value for protecting internal heap pointers. */
|
||||
PRIVILEGED_DATA static portPOINTER_SIZE_TYPE xHeapCanary;
|
||||
|
||||
/* Macro to load/store BlockLink_t pointers to memory. By XORing the
|
||||
* pointers with a random canary value, heap overflows will result
|
||||
* in randomly unpredictable pointer values which will be caught by
|
||||
* heapVALIDATE_BLOCK_POINTER assert. */
|
||||
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( ( BlockLink_t * ) ( ( ( portPOINTER_SIZE_TYPE ) ( pxBlock ) ) ^ xHeapCanary ) )
|
||||
#else
|
||||
|
||||
#define heapPROTECT_BLOCK_POINTER( pxBlock ) ( pxBlock )
|
||||
|
||||
#endif /* configENABLE_HEAP_PROTECTOR */
|
||||
|
||||
/* Assert that a heap block pointer is within the heap bounds. */
|
||||
#define heapVALIDATE_BLOCK_POINTER( pxBlock ) \
|
||||
configASSERT( ( ( uint8_t * ) ( pxBlock ) >= &( ucHeap[ 0 ] ) ) && \
|
||||
( ( uint8_t * ) ( pxBlock ) <= &( ucHeap[ configTOTAL_HEAP_SIZE - 1 ] ) ) )
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Inserts a block of memory that is being freed into the correct position in
|
||||
* the list of free memory blocks. The block being freed will be merged with
|
||||
* the block in front it and/or the block behind it if the memory blocks are
|
||||
* adjacent to each other.
|
||||
*/
|
||||
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Called automatically to setup the required heap structures the first time
|
||||
* pvPortMalloc() is called.
|
||||
*/
|
||||
static void prvHeapInit( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* The size of the structure placed at the beginning of each allocated memory
|
||||
* block must by correctly byte aligned. */
|
||||
static const size_t xHeapStructSize = ( sizeof( BlockLink_t ) + ( ( size_t ) ( portBYTE_ALIGNMENT - 1 ) ) ) & ~( ( size_t ) portBYTE_ALIGNMENT_MASK );
|
||||
|
||||
/* Create a couple of list links to mark the start and end of the list. */
|
||||
PRIVILEGED_DATA static BlockLink_t xStart;
|
||||
PRIVILEGED_DATA static BlockLink_t * pxEnd = NULL;
|
||||
|
||||
/* Keeps track of the number of calls to allocate and free memory as well as the
|
||||
* number of free bytes remaining, but says nothing about fragmentation. */
|
||||
PRIVILEGED_DATA static size_t xFreeBytesRemaining = ( size_t ) 0U;
|
||||
PRIVILEGED_DATA static size_t xMinimumEverFreeBytesRemaining = ( size_t ) 0U;
|
||||
PRIVILEGED_DATA static size_t xNumberOfSuccessfulAllocations = ( size_t ) 0U;
|
||||
PRIVILEGED_DATA static size_t xNumberOfSuccessfulFrees = ( size_t ) 0U;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void * pvPortMalloc( size_t xWantedSize )
|
||||
{
|
||||
BlockLink_t * pxBlock;
|
||||
BlockLink_t * pxPreviousBlock;
|
||||
BlockLink_t * pxNewBlockLink;
|
||||
void * pvReturn = NULL;
|
||||
size_t xAdditionalRequiredSize;
|
||||
size_t xAllocatedBlockSize = 0;
|
||||
|
||||
if( xWantedSize > 0 )
|
||||
{
|
||||
/* The wanted size must be increased so it can contain a BlockLink_t
|
||||
* structure in addition to the requested amount of bytes. */
|
||||
if( heapADD_WILL_OVERFLOW( xWantedSize, xHeapStructSize ) == 0 )
|
||||
{
|
||||
xWantedSize += xHeapStructSize;
|
||||
|
||||
/* Ensure that blocks are always aligned to the required number
|
||||
* of bytes. */
|
||||
if( ( xWantedSize & portBYTE_ALIGNMENT_MASK ) != 0x00 )
|
||||
{
|
||||
/* Byte alignment required. */
|
||||
xAdditionalRequiredSize = portBYTE_ALIGNMENT - ( xWantedSize & portBYTE_ALIGNMENT_MASK );
|
||||
|
||||
if( heapADD_WILL_OVERFLOW( xWantedSize, xAdditionalRequiredSize ) == 0 )
|
||||
{
|
||||
xWantedSize += xAdditionalRequiredSize;
|
||||
}
|
||||
else
|
||||
{
|
||||
xWantedSize = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xWantedSize = 0;
|
||||
}
|
||||
}
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* If this is the first call to malloc then the heap will require
|
||||
* initialisation to setup the list of free blocks. */
|
||||
if( pxEnd == NULL )
|
||||
{
|
||||
prvHeapInit();
|
||||
}
|
||||
|
||||
/* Check the block size we are trying to allocate is not so large that the
|
||||
* top bit is set. The top bit of the block size member of the BlockLink_t
|
||||
* structure is used to determine who owns the block - the application or
|
||||
* the kernel, so it must be free. */
|
||||
if( heapBLOCK_SIZE_IS_VALID( xWantedSize ) != 0 )
|
||||
{
|
||||
if( ( xWantedSize > 0 ) && ( xWantedSize <= xFreeBytesRemaining ) )
|
||||
{
|
||||
/* Traverse the list from the start (lowest address) block until
|
||||
* one of adequate size is found. */
|
||||
pxPreviousBlock = &xStart;
|
||||
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
|
||||
heapVALIDATE_BLOCK_POINTER( pxBlock );
|
||||
|
||||
while( ( pxBlock->xBlockSize < xWantedSize ) && ( pxBlock->pxNextFreeBlock != heapPROTECT_BLOCK_POINTER( NULL ) ) )
|
||||
{
|
||||
pxPreviousBlock = pxBlock;
|
||||
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
|
||||
heapVALIDATE_BLOCK_POINTER( pxBlock );
|
||||
}
|
||||
|
||||
/* If the end marker was reached then a block of adequate size
|
||||
* was not found. */
|
||||
if( pxBlock != pxEnd )
|
||||
{
|
||||
/* Return the memory space pointed to - jumping over the
|
||||
* BlockLink_t structure at its start. */
|
||||
pvReturn = ( void * ) ( ( ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxPreviousBlock->pxNextFreeBlock ) ) + xHeapStructSize );
|
||||
heapVALIDATE_BLOCK_POINTER( pvReturn );
|
||||
|
||||
/* This block is being returned for use so must be taken out
|
||||
* of the list of free blocks. */
|
||||
pxPreviousBlock->pxNextFreeBlock = pxBlock->pxNextFreeBlock;
|
||||
|
||||
/* If the block is larger than required it can be split into
|
||||
* two. */
|
||||
configASSERT( heapSUBTRACT_WILL_UNDERFLOW( pxBlock->xBlockSize, xWantedSize ) == 0 );
|
||||
|
||||
if( ( pxBlock->xBlockSize - xWantedSize ) > heapMINIMUM_BLOCK_SIZE )
|
||||
{
|
||||
/* This block is to be split into two. Create a new
|
||||
* block following the number of bytes requested. The void
|
||||
* cast is used to prevent byte alignment warnings from the
|
||||
* compiler. */
|
||||
pxNewBlockLink = ( void * ) ( ( ( uint8_t * ) pxBlock ) + xWantedSize );
|
||||
configASSERT( ( ( ( size_t ) pxNewBlockLink ) & portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
|
||||
/* Calculate the sizes of two blocks split from the
|
||||
* single block. */
|
||||
pxNewBlockLink->xBlockSize = pxBlock->xBlockSize - xWantedSize;
|
||||
pxBlock->xBlockSize = xWantedSize;
|
||||
|
||||
/* Insert the new block into the list of free blocks. */
|
||||
pxNewBlockLink->pxNextFreeBlock = pxPreviousBlock->pxNextFreeBlock;
|
||||
pxPreviousBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxNewBlockLink );
|
||||
}
|
||||
|
||||
xFreeBytesRemaining -= pxBlock->xBlockSize;
|
||||
|
||||
if( xFreeBytesRemaining < xMinimumEverFreeBytesRemaining )
|
||||
{
|
||||
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
|
||||
}
|
||||
|
||||
xAllocatedBlockSize = pxBlock->xBlockSize;
|
||||
|
||||
/* The block is being returned - it is allocated and owned
|
||||
* by the application and has no "next" block. */
|
||||
heapALLOCATE_BLOCK( pxBlock );
|
||||
pxBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( NULL );
|
||||
xNumberOfSuccessfulAllocations++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// traceMALLOC( pvReturn, xAllocatedBlockSize );
|
||||
|
||||
/* Prevent compiler warnings when trace macros are not used. */
|
||||
( void ) xAllocatedBlockSize;
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
#if ( configUSE_MALLOC_FAILED_HOOK == 1 )
|
||||
{
|
||||
if( pvReturn == NULL )
|
||||
{
|
||||
vApplicationMallocFailedHook();
|
||||
}
|
||||
}
|
||||
#endif /* if ( configUSE_MALLOC_FAILED_HOOK == 1 ) */
|
||||
|
||||
configASSERT( ( ( ( size_t ) pvReturn ) & ( size_t ) portBYTE_ALIGNMENT_MASK ) == 0 );
|
||||
return pvReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortFree( void * pv )
|
||||
{
|
||||
uint8_t * puc = ( uint8_t * ) pv;
|
||||
BlockLink_t * pxLink;
|
||||
|
||||
if( pv != NULL )
|
||||
{
|
||||
/* The memory being freed will have an BlockLink_t structure immediately
|
||||
* before it. */
|
||||
puc -= xHeapStructSize;
|
||||
|
||||
/* This casting is to keep the compiler from issuing warnings. */
|
||||
pxLink = ( void * ) puc;
|
||||
|
||||
heapVALIDATE_BLOCK_POINTER( pxLink );
|
||||
configASSERT( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 );
|
||||
configASSERT( pxLink->pxNextFreeBlock == heapPROTECT_BLOCK_POINTER( NULL ) );
|
||||
|
||||
if( heapBLOCK_IS_ALLOCATED( pxLink ) != 0 )
|
||||
{
|
||||
if( pxLink->pxNextFreeBlock == heapPROTECT_BLOCK_POINTER( NULL ) )
|
||||
{
|
||||
/* The block is being returned to the heap - it is no longer
|
||||
* allocated. */
|
||||
heapFREE_BLOCK( pxLink );
|
||||
#if ( configHEAP_CLEAR_MEMORY_ON_FREE == 1 )
|
||||
{
|
||||
/* Check for underflow as this can occur if xBlockSize is
|
||||
* overwritten in a heap block. */
|
||||
if( heapSUBTRACT_WILL_UNDERFLOW( pxLink->xBlockSize, xHeapStructSize ) == 0 )
|
||||
{
|
||||
( void ) memset( puc + xHeapStructSize, 0, pxLink->xBlockSize - xHeapStructSize );
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Add this block to the list of free blocks. */
|
||||
xFreeBytesRemaining += pxLink->xBlockSize;
|
||||
// traceFREE( pv, pxLink->xBlockSize );
|
||||
prvInsertBlockIntoFreeList( ( ( BlockLink_t * ) pxLink ) );
|
||||
xNumberOfSuccessfulFrees++;
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetFreeHeapSize( void )
|
||||
{
|
||||
return xFreeBytesRemaining;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
size_t xPortGetMinimumEverFreeHeapSize( void )
|
||||
{
|
||||
return xMinimumEverFreeBytesRemaining;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void xPortResetHeapMinimumEverFreeHeapSize( void )
|
||||
{
|
||||
xMinimumEverFreeBytesRemaining = xFreeBytesRemaining;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
int xPortMemIsKernel(void *mem)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vPortInitialiseBlocks( void )
|
||||
{
|
||||
/* This just exists to keep the linker quiet. */
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void * pvPortCalloc( size_t xNum,
|
||||
size_t xSize )
|
||||
{
|
||||
void * pv = NULL;
|
||||
|
||||
if( heapMULTIPLY_WILL_OVERFLOW( xNum, xSize ) == 0 )
|
||||
{
|
||||
pv = pvPortMalloc( xNum * xSize );
|
||||
|
||||
if( pv != NULL )
|
||||
{
|
||||
( void ) memset( pv, 0, xNum * xSize );
|
||||
}
|
||||
}
|
||||
|
||||
return pv;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvHeapInit( void ) /* PRIVILEGED_FUNCTION */
|
||||
{
|
||||
BlockLink_t * pxFirstFreeBlock;
|
||||
portPOINTER_SIZE_TYPE uxStartAddress, uxEndAddress;
|
||||
size_t xTotalHeapSize = configTOTAL_HEAP_SIZE;
|
||||
|
||||
/* Ensure the heap starts on a correctly aligned boundary. */
|
||||
uxStartAddress = ( portPOINTER_SIZE_TYPE ) ucHeap;
|
||||
|
||||
if( ( uxStartAddress & portBYTE_ALIGNMENT_MASK ) != 0 )
|
||||
{
|
||||
uxStartAddress += ( portBYTE_ALIGNMENT - 1 );
|
||||
uxStartAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
|
||||
xTotalHeapSize -= ( size_t ) ( uxStartAddress - ( portPOINTER_SIZE_TYPE ) ucHeap );
|
||||
}
|
||||
|
||||
#if ( configENABLE_HEAP_PROTECTOR == 1 )
|
||||
{
|
||||
vApplicationGetRandomHeapCanary( &( xHeapCanary ) );
|
||||
}
|
||||
#endif
|
||||
|
||||
/* xStart is used to hold a pointer to the first item in the list of free
|
||||
* blocks. The void cast is used to prevent compiler warnings. */
|
||||
xStart.pxNextFreeBlock = ( void * ) heapPROTECT_BLOCK_POINTER( uxStartAddress );
|
||||
xStart.xBlockSize = ( size_t ) 0;
|
||||
|
||||
/* pxEnd is used to mark the end of the list of free blocks and is inserted
|
||||
* at the end of the heap space. */
|
||||
uxEndAddress = uxStartAddress + ( portPOINTER_SIZE_TYPE ) xTotalHeapSize;
|
||||
uxEndAddress -= ( portPOINTER_SIZE_TYPE ) xHeapStructSize;
|
||||
uxEndAddress &= ~( ( portPOINTER_SIZE_TYPE ) portBYTE_ALIGNMENT_MASK );
|
||||
pxEnd = ( BlockLink_t * ) uxEndAddress;
|
||||
pxEnd->xBlockSize = 0;
|
||||
pxEnd->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( NULL );
|
||||
|
||||
/* To start with there is a single free block that is sized to take up the
|
||||
* entire heap space, minus the space taken by pxEnd. */
|
||||
pxFirstFreeBlock = ( BlockLink_t * ) uxStartAddress;
|
||||
pxFirstFreeBlock->xBlockSize = ( size_t ) ( uxEndAddress - ( portPOINTER_SIZE_TYPE ) pxFirstFreeBlock );
|
||||
pxFirstFreeBlock->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );
|
||||
|
||||
/* Only one block exists - and it covers the entire usable heap space. */
|
||||
xMinimumEverFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
|
||||
xFreeBytesRemaining = pxFirstFreeBlock->xBlockSize;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvInsertBlockIntoFreeList( BlockLink_t * pxBlockToInsert ) /* PRIVILEGED_FUNCTION */
|
||||
{
|
||||
BlockLink_t * pxIterator;
|
||||
uint8_t * puc;
|
||||
|
||||
/* Iterate through the list until a block is found that has a higher address
|
||||
* than the block being inserted. */
|
||||
for( pxIterator = &xStart; heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) < pxBlockToInsert; pxIterator = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
|
||||
{
|
||||
/* Nothing to do here, just iterate to the right position. */
|
||||
}
|
||||
|
||||
if( pxIterator != &xStart )
|
||||
{
|
||||
heapVALIDATE_BLOCK_POINTER( pxIterator );
|
||||
}
|
||||
|
||||
/* Do the block being inserted, and the block it is being inserted after
|
||||
* make a contiguous block of memory? */
|
||||
puc = ( uint8_t * ) pxIterator;
|
||||
|
||||
if( ( puc + pxIterator->xBlockSize ) == ( uint8_t * ) pxBlockToInsert )
|
||||
{
|
||||
pxIterator->xBlockSize += pxBlockToInsert->xBlockSize;
|
||||
pxBlockToInsert = pxIterator;
|
||||
}
|
||||
|
||||
/* Do the block being inserted, and the block it is being inserted before
|
||||
* make a contiguous block of memory? */
|
||||
puc = ( uint8_t * ) pxBlockToInsert;
|
||||
|
||||
if( ( puc + pxBlockToInsert->xBlockSize ) == ( uint8_t * ) heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) )
|
||||
{
|
||||
if( heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock ) != pxEnd )
|
||||
{
|
||||
/* Form one big block from the two blocks. */
|
||||
pxBlockToInsert->xBlockSize += heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->xBlockSize;
|
||||
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxIterator->pxNextFreeBlock )->pxNextFreeBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
pxBlockToInsert->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxEnd );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pxBlockToInsert->pxNextFreeBlock = pxIterator->pxNextFreeBlock;
|
||||
}
|
||||
|
||||
/* If the block being inserted plugged a gap, so was merged with the block
|
||||
* before and the block after, then it's pxNextFreeBlock pointer will have
|
||||
* already been set, and should not be set here as that would make it point
|
||||
* to itself. */
|
||||
if( pxIterator != pxBlockToInsert )
|
||||
{
|
||||
pxIterator->pxNextFreeBlock = heapPROTECT_BLOCK_POINTER( pxBlockToInsert );
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if 0
|
||||
void vPortGetHeapStats( HeapStats_t * pxHeapStats )
|
||||
{
|
||||
BlockLink_t * pxBlock;
|
||||
size_t xBlocks = 0, xMaxSize = 0, xMinSize = portMAX_DELAY; /* portMAX_DELAY used as a portable way of getting the maximum value. */
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
pxBlock = heapPROTECT_BLOCK_POINTER( xStart.pxNextFreeBlock );
|
||||
|
||||
/* pxBlock will be NULL if the heap has not been initialised. The heap
|
||||
* is initialised automatically when the first allocation is made. */
|
||||
if( pxBlock != NULL )
|
||||
{
|
||||
while( pxBlock != pxEnd )
|
||||
{
|
||||
/* Increment the number of blocks and record the largest block seen
|
||||
* so far. */
|
||||
xBlocks++;
|
||||
|
||||
if( pxBlock->xBlockSize > xMaxSize )
|
||||
{
|
||||
xMaxSize = pxBlock->xBlockSize;
|
||||
}
|
||||
|
||||
if( pxBlock->xBlockSize < xMinSize )
|
||||
{
|
||||
xMinSize = pxBlock->xBlockSize;
|
||||
}
|
||||
|
||||
/* Move to the next block in the chain until the last block is
|
||||
* reached. */
|
||||
pxBlock = heapPROTECT_BLOCK_POINTER( pxBlock->pxNextFreeBlock );
|
||||
}
|
||||
}
|
||||
}
|
||||
( void ) xTaskResumeAll();
|
||||
|
||||
pxHeapStats->xSizeOfLargestFreeBlockInBytes = xMaxSize;
|
||||
pxHeapStats->xSizeOfSmallestFreeBlockInBytes = xMinSize;
|
||||
pxHeapStats->xNumberOfFreeBlocks = xBlocks;
|
||||
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
pxHeapStats->xAvailableHeapSpaceInBytes = xFreeBytesRemaining;
|
||||
pxHeapStats->xNumberOfSuccessfulAllocations = xNumberOfSuccessfulAllocations;
|
||||
pxHeapStats->xNumberOfSuccessfulFrees = xNumberOfSuccessfulFrees;
|
||||
pxHeapStats->xMinimumEverFreeBytesRemaining = xMinimumEverFreeBytesRemaining;
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Reset the state in this file. This state is normally initialized at start up.
|
||||
* This function must be called by the application before restarting the
|
||||
* scheduler.
|
||||
*/
|
||||
void vPortHeapResetState( void )
|
||||
{
|
||||
pxEnd = NULL;
|
||||
|
||||
xFreeBytesRemaining = ( size_t ) 0U;
|
||||
xMinimumEverFreeBytesRemaining = ( size_t ) 0U;
|
||||
xNumberOfSuccessfulAllocations = ( size_t ) 0U;
|
||||
xNumberOfSuccessfulFrees = ( size_t ) 0U;
|
||||
}
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details. You should have received a copy of the GNU General Public
|
||||
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "rtoslist.h"
|
||||
#include "wm_config.h"
|
||||
|
||||
#if TLS_OS_FREERTOS
|
||||
/*-----------------------------------------------------------
|
||||
* PUBLIC LIST API documented in list.h
|
||||
*----------------------------------------------------------*/
|
||||
|
||||
void vListInitialise( xList *pxList )
|
||||
{
|
||||
/* The list structure contains a list item which is used to mark the
|
||||
end of the list. To initialise the list the list end is inserted
|
||||
as the only list entry. */
|
||||
pxList->pxIndex = ( xListItem * ) &( pxList->xListEnd );
|
||||
|
||||
/* The list end value is the highest possible value in the list to
|
||||
ensure it remains at the end of the list. */
|
||||
pxList->xListEnd.xItemValue = portMAX_DELAY;
|
||||
|
||||
/* The list end next and previous pointers point to itself so we know
|
||||
when the list is empty. */
|
||||
pxList->xListEnd.pxNext = ( xListItem * ) &( pxList->xListEnd );
|
||||
pxList->xListEnd.pxPrevious = ( xListItem * ) &( pxList->xListEnd );
|
||||
|
||||
pxList->uxNumberOfItems = ( unsigned portBASE_TYPE ) 0U;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vListInitialiseItem( xListItem *pxItem )
|
||||
{
|
||||
/* Make sure the list item is not recorded as being on a list. */
|
||||
pxItem->pvContainer = NULL;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vListInsertEnd( xList *pxList, xListItem *pxNewListItem )
|
||||
{
|
||||
volatile xListItem * pxIndex;
|
||||
|
||||
/* Insert a new list item into pxList, but rather than sort the list,
|
||||
makes the new list item the last item to be removed by a call to
|
||||
pvListGetOwnerOfNextEntry. This means it has to be the item pointed to by
|
||||
the pxIndex member. */
|
||||
pxIndex = pxList->pxIndex;
|
||||
|
||||
pxNewListItem->pxNext = pxIndex->pxNext;
|
||||
pxNewListItem->pxPrevious = pxList->pxIndex;
|
||||
pxIndex->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
|
||||
pxIndex->pxNext = ( volatile xListItem * ) pxNewListItem;
|
||||
pxList->pxIndex = ( volatile xListItem * ) pxNewListItem;
|
||||
|
||||
/* Remember which list the item is in. */
|
||||
pxNewListItem->pvContainer = ( void * ) pxList;
|
||||
|
||||
( pxList->uxNumberOfItems )++;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vListInsert( xList *pxList, xListItem *pxNewListItem )
|
||||
{
|
||||
volatile xListItem *pxIterator;
|
||||
portTickType xValueOfInsertion;
|
||||
|
||||
/* Insert the new list item into the list, sorted in ulListItem order. */
|
||||
xValueOfInsertion = pxNewListItem->xItemValue;
|
||||
|
||||
/* If the list already contains a list item with the same item value then
|
||||
the new list item should be placed after it. This ensures that TCB's which
|
||||
are stored in ready lists (all of which have the same ulListItem value)
|
||||
get an equal share of the CPU. However, if the xItemValue is the same as
|
||||
the back marker the iteration loop below will not end. This means we need
|
||||
to guard against this by checking the value first and modifying the
|
||||
algorithm slightly if necessary. */
|
||||
if( xValueOfInsertion == portMAX_DELAY )
|
||||
{
|
||||
pxIterator = pxList->xListEnd.pxPrevious;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* *** NOTE ***********************************************************
|
||||
If you find your application is crashing here then likely causes are:
|
||||
1) Stack overflow -
|
||||
see http://www.freertos.org/Stacks-and-stack-overflow-checking.html
|
||||
2) Incorrect interrupt priority assignment, especially on Cortex-M3
|
||||
parts where numerically high priority values denote low actual
|
||||
interrupt priories, which can seem counter intuitive. See
|
||||
configMAX_SYSCALL_INTERRUPT_PRIORITY on http://www.freertos.org/a00110.html
|
||||
3) Calling an API function from within a critical section or when
|
||||
the scheduler is suspended.
|
||||
4) Using a queue or semaphore before it has been initialised or
|
||||
before the scheduler has been started (are interrupts firing
|
||||
before vTaskStartScheduler() has been called?).
|
||||
See http://www.freertos.org/FAQHelp.html for more tips.
|
||||
**********************************************************************/
|
||||
|
||||
for( pxIterator = ( xListItem * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext )
|
||||
{
|
||||
/* There is nothing to do here, we are just iterating to the
|
||||
wanted insertion position. */
|
||||
}
|
||||
}
|
||||
|
||||
pxNewListItem->pxNext = pxIterator->pxNext;
|
||||
pxNewListItem->pxNext->pxPrevious = ( volatile xListItem * ) pxNewListItem;
|
||||
pxNewListItem->pxPrevious = pxIterator;
|
||||
pxIterator->pxNext = ( volatile xListItem * ) pxNewListItem;
|
||||
|
||||
/* Remember which list the item is in. This allows fast removal of the
|
||||
item later. */
|
||||
pxNewListItem->pvContainer = ( void * ) pxList;
|
||||
|
||||
( pxList->uxNumberOfItems )++;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void vListRemove( xListItem *pxItemToRemove )
|
||||
{
|
||||
xList * pxList;
|
||||
|
||||
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
|
||||
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
|
||||
|
||||
/* The list item knows which list it is in. Obtain the list from the list
|
||||
item. */
|
||||
pxList = ( xList * ) pxItemToRemove->pvContainer;
|
||||
|
||||
/* Make sure the index is left pointing to a valid item. */
|
||||
if( pxList->pxIndex == pxItemToRemove )
|
||||
{
|
||||
pxList->pxIndex = pxItemToRemove->pxPrevious;
|
||||
}
|
||||
|
||||
pxItemToRemove->pvContainer = NULL;
|
||||
( pxList->uxNumberOfItems )--;
|
||||
}
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,721 @@
|
||||
/*
|
||||
FreeRTOS V7.0.2 - Copyright (C) 2011 Real Time Engineers Ltd.
|
||||
|
||||
|
||||
***************************************************************************
|
||||
* *
|
||||
* FreeRTOS tutorial books are available in pdf and paperback. *
|
||||
* Complete, revised, and edited pdf reference manuals are also *
|
||||
* available. *
|
||||
* *
|
||||
* Purchasing FreeRTOS documentation will not only help you, by *
|
||||
* ensuring you get running as quickly as possible and with an *
|
||||
* in-depth knowledge of how to use FreeRTOS, it will also help *
|
||||
* the FreeRTOS project to continue with its mission of providing *
|
||||
* professional grade, cross platform, de facto standard solutions *
|
||||
* for microcontrollers - completely free of charge! *
|
||||
* *
|
||||
* >>> See http://www.FreeRTOS.org/Documentation for details. <<< *
|
||||
* *
|
||||
* Thank you for using FreeRTOS, and thank you for your support! *
|
||||
* *
|
||||
***************************************************************************
|
||||
|
||||
|
||||
This file is part of the FreeRTOS distribution.
|
||||
|
||||
FreeRTOS is free software; you can redistribute it and/or modify it under
|
||||
the terms of the GNU General Public License (version 2) as published by the
|
||||
Free Software Foundation AND MODIFIED BY the FreeRTOS exception.
|
||||
>>>NOTE<<< The modification to the GPL is included to allow you to
|
||||
distribute a combined work that includes FreeRTOS without being obliged to
|
||||
provide the source code for proprietary components outside of the FreeRTOS
|
||||
kernel. FreeRTOS is distributed in the hope that it will be useful, but
|
||||
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
|
||||
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
more details. You should have received a copy of the GNU General Public
|
||||
License and the FreeRTOS license exception along with FreeRTOS; if not it
|
||||
can be viewed here: http://www.freertos.org/a00114.html and also obtained
|
||||
by writing to Richard Barry, contact details for whom are available on the
|
||||
FreeRTOS WEB site.
|
||||
|
||||
1 tab == 4 spaces!
|
||||
|
||||
http://www.FreeRTOS.org - Documentation, latest information, license and
|
||||
contact details.
|
||||
|
||||
http://www.SafeRTOS.com - A version that is certified for use in safety
|
||||
critical systems.
|
||||
|
||||
http://www.OpenRTOS.com - Commercial support, development, porting,
|
||||
licensing and training services.
|
||||
*/
|
||||
|
||||
/* Defining MPU_WRAPPERS_INCLUDED_FROM_API_FILE prevents task.h from redefining
|
||||
all the API functions to use the MPU wrappers. That should only be done when
|
||||
task.h is included from an application file. */
|
||||
#define MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
|
||||
#include <stdio.h>
|
||||
#include "FreeRTOS.h"
|
||||
#include "task.h"
|
||||
#include "rtosqueue.h"
|
||||
#include "rtostimers.h"
|
||||
#include "wm_config.h"
|
||||
|
||||
#undef MPU_WRAPPERS_INCLUDED_FROM_API_FILE
|
||||
#if TLS_OS_FREERTOS
|
||||
/* This entire source file will be skipped if the application is not configured
|
||||
to include software timer functionality. This #if is closed at the very bottom
|
||||
of this file. If you want to include software timer functionality then ensure
|
||||
configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
|
||||
#if ( configUSE_TIMERS == 1 )
|
||||
|
||||
/* Misc definitions. */
|
||||
#define tmrNO_DELAY ( portTickType ) 0U
|
||||
#if 0
|
||||
/* The definition of the timers themselves. */
|
||||
typedef struct tmrTimerControl
|
||||
{
|
||||
const signed char *pcTimerName; /*<< Text name. This is not used by the kernel, it is included simply to make debugging easier. */
|
||||
xListItem xTimerListItem; /*<< Standard linked list item as used by all kernel features for event management. */
|
||||
portTickType xTimerPeriodInTicks;/*<< How quickly and often the timer expires. */
|
||||
unsigned portBASE_TYPE uxAutoReload; /*<< Set to pdTRUE if the timer should be automatically restarted once expired. Set to pdFALSE if the timer is, in effect, a one shot timer. */
|
||||
void *pvTimerID; /*<< An ID to identify the timer. This allows the timer to be identified when the same callback is used for multiple timers. */
|
||||
tmrTIMER_CALLBACK pxCallbackFunction; /*<< The function that will be called when the timer expires. */
|
||||
void *callback_arg; /*added by dave */
|
||||
} xTIMER;
|
||||
#endif
|
||||
/* The definition of messages that can be sent and received on the timer
|
||||
queue. */
|
||||
typedef struct tmrTimerQueueMessage
|
||||
{
|
||||
portBASE_TYPE xMessageID; /*<< The command being sent to the timer service task. */
|
||||
portTickType xMessageValue; /*<< An optional value used by a subset of commands, for example, when changing the period of a timer. */
|
||||
xTIMER * pxTimer; /*<< The timer to which the command will be applied. */
|
||||
} xTIMER_MESSAGE;
|
||||
|
||||
|
||||
/* The list in which active timers are stored. Timers are referenced in expire
|
||||
time order, with the nearest expiry time at the front of the list. Only the
|
||||
timer service task is allowed to access xActiveTimerList. */
|
||||
PRIVILEGED_DATA static xList xActiveTimerList1;
|
||||
PRIVILEGED_DATA static xList xActiveTimerList2;
|
||||
PRIVILEGED_DATA static xList *pxCurrentTimerList;
|
||||
PRIVILEGED_DATA static xList *pxOverflowTimerList;
|
||||
|
||||
/* A queue that is used to send commands to the timer service task. */
|
||||
PRIVILEGED_DATA static xQueueHandle xTimerQueue = NULL;
|
||||
|
||||
#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
|
||||
|
||||
PRIVILEGED_DATA static xTaskHandle xTimerTaskHandle = NULL;
|
||||
|
||||
#endif
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Initialise the infrastructure used by the timer service task if it has not
|
||||
* been initialised already.
|
||||
*/
|
||||
static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* The timer service task (daemon). Timer functionality is controlled by this
|
||||
* task. Other tasks communicate with the timer service task using the
|
||||
* xTimerQueue queue.
|
||||
*/
|
||||
static void prvTimerTask( void *pvParameters ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Called by the timer service task to interpret and process a command it
|
||||
* received on the timer queue.
|
||||
*/
|
||||
static void prvProcessReceivedCommands( void ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Insert the timer into either xActiveTimerList1, or xActiveTimerList2,
|
||||
* depending on if the expire time causes a timer counter overflow.
|
||||
*/
|
||||
static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* An active timer has reached its expire time. Reload the timer if it is an
|
||||
* auto reload timer, then call its callback.
|
||||
*/
|
||||
static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* The tick count has overflowed. Switch the timer lists after ensuring the
|
||||
* current timer list does not still reference some timers.
|
||||
*/
|
||||
static void prvSwitchTimerLists( portTickType xLastTime ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* Obtain the current tick count, setting *pxTimerListsWereSwitched to pdTRUE
|
||||
* if a tick count overflow occurred since prvSampleTimeNow() was last called.
|
||||
*/
|
||||
static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* If the timer list contains any active timers then return the expire time of
|
||||
* the timer that will expire first and set *pxListWasEmpty to false. If the
|
||||
* timer list does not contain any timers then return 0 and set *pxListWasEmpty
|
||||
* to pdTRUE.
|
||||
*/
|
||||
static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*
|
||||
* If a timer has expired, process it. Otherwise, block the timer service task
|
||||
* until either a timer does expire or a command is received.
|
||||
*/
|
||||
static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty ) PRIVILEGED_FUNCTION;
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xTimerCreateTimerTask( void )
|
||||
{
|
||||
portBASE_TYPE xReturn = pdFAIL;
|
||||
|
||||
/* This function is called when the scheduler is started if
|
||||
configUSE_TIMERS is set to 1. Check that the infrastructure used by the
|
||||
timer service task has been created/initialised. If timers have already
|
||||
been created then the initialisation will already have been performed. */
|
||||
prvCheckForValidListAndQueue();
|
||||
|
||||
if( xTimerQueue != NULL )
|
||||
{
|
||||
#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
|
||||
{
|
||||
/* Create the timer task, storing its handle in xTimerTaskHandle so
|
||||
it can be returned by the xTimerGetTimerDaemonTaskHandle() function. */
|
||||
xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "TIMER", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, &xTimerTaskHandle );
|
||||
}
|
||||
#else
|
||||
{
|
||||
/* Create the timer task without storing its handle. */
|
||||
xReturn = xTaskCreate( prvTimerTask, ( const signed char * ) "TIMER", ( unsigned short ) configTIMER_TASK_STACK_DEPTH, NULL, ( unsigned portBASE_TYPE ) configTIMER_TASK_PRIORITY, NULL);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
configASSERT( xReturn );
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
xTimerHandle xTimerCreate( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction )
|
||||
{
|
||||
xTIMER *pxNewTimer;
|
||||
|
||||
/* Allocate the timer structure. */
|
||||
if( xTimerPeriodInTicks == ( portTickType ) 0U )
|
||||
{
|
||||
pxNewTimer = NULL;
|
||||
configASSERT( ( xTimerPeriodInTicks > 0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
|
||||
if( pxNewTimer != NULL )
|
||||
{
|
||||
/* Ensure the infrastructure used by the timer service task has been
|
||||
created/initialised. */
|
||||
prvCheckForValidListAndQueue();
|
||||
|
||||
/* Initialise the timer structure members using the function parameters. */
|
||||
pxNewTimer->pcTimerName = pcTimerName;
|
||||
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
|
||||
pxNewTimer->uxAutoReload = uxAutoReload;
|
||||
pxNewTimer->pvTimerID = pvTimerID;
|
||||
pxNewTimer->pxCallbackFunction = pxCallbackFunction;
|
||||
pxNewTimer->callback_arg = NULL; //add by dave
|
||||
vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
|
||||
|
||||
traceTIMER_CREATE( pxNewTimer );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceTIMER_CREATE_FAILED();
|
||||
}
|
||||
}
|
||||
|
||||
return ( xTimerHandle ) pxNewTimer;
|
||||
}
|
||||
|
||||
xTimerHandle xTimerCreateExt( const signed char *pcTimerName, portTickType xTimerPeriodInTicks, unsigned portBASE_TYPE uxAutoReload, void *pvTimerID, tmrTIMER_CALLBACK pxCallbackFunction, void *callback_arg )
|
||||
{
|
||||
xTIMER *pxNewTimer;
|
||||
|
||||
/* Allocate the timer structure. */
|
||||
if( xTimerPeriodInTicks == ( portTickType ) 0U )
|
||||
{
|
||||
pxNewTimer = NULL;
|
||||
configASSERT( ( xTimerPeriodInTicks > 0 ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
pxNewTimer = ( xTIMER * ) pvPortMalloc( sizeof( xTIMER ) );
|
||||
if( pxNewTimer != NULL )
|
||||
{
|
||||
/* Ensure the infrastructure used by the timer service task has been
|
||||
created/initialised. */
|
||||
prvCheckForValidListAndQueue();
|
||||
|
||||
/* Initialise the timer structure members using the function parameters. */
|
||||
pxNewTimer->pcTimerName = pcTimerName;
|
||||
pxNewTimer->xTimerPeriodInTicks = xTimerPeriodInTicks;
|
||||
pxNewTimer->uxAutoReload = uxAutoReload;
|
||||
pxNewTimer->pvTimerID = pvTimerID;
|
||||
pxNewTimer->pxCallbackFunction = pxCallbackFunction;
|
||||
pxNewTimer->callback_arg = callback_arg; //add by dave
|
||||
vListInitialiseItem( &( pxNewTimer->xTimerListItem ) );
|
||||
|
||||
traceTIMER_CREATE( pxNewTimer );
|
||||
}
|
||||
else
|
||||
{
|
||||
traceTIMER_CREATE_FAILED();
|
||||
}
|
||||
}
|
||||
|
||||
return ( xTimerHandle ) pxNewTimer;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xTimerGenericCommand( xTimerHandle xTimer, portBASE_TYPE xCommandID, portTickType xOptionalValue, portBASE_TYPE *pxHigherPriorityTaskWoken, portTickType xBlockTime )
|
||||
{
|
||||
portBASE_TYPE xReturn = pdFAIL;
|
||||
xTIMER_MESSAGE xMessage;
|
||||
|
||||
/* Send a message to the timer service task to perform a particular action
|
||||
on a particular timer definition. */
|
||||
if( xTimerQueue != NULL )
|
||||
{
|
||||
/* Send a command to the timer service task to start the xTimer timer. */
|
||||
xMessage.xMessageID = xCommandID;
|
||||
xMessage.xMessageValue = xOptionalValue;
|
||||
xMessage.pxTimer = ( xTIMER * ) xTimer;
|
||||
|
||||
if( pxHigherPriorityTaskWoken == NULL )
|
||||
{
|
||||
if( xTaskGetSchedulerState() == taskSCHEDULER_RUNNING )
|
||||
{
|
||||
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, xBlockTime );
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = xQueueSendToBack( xTimerQueue, &xMessage, tmrNO_DELAY );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xReturn = xQueueSendToBackFromISR( xTimerQueue, &xMessage, pxHigherPriorityTaskWoken );
|
||||
}
|
||||
|
||||
traceTIMER_COMMAND_SEND( xTimer, xCommandID, xOptionalValue, xReturn );
|
||||
}
|
||||
|
||||
return xReturn;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
#if ( INCLUDE_xTimerGetTimerDaemonTaskHandle == 1 )
|
||||
|
||||
xTaskHandle xTimerGetTimerDaemonTaskHandle( void )
|
||||
{
|
||||
/* If xTimerGetTimerDaemonTaskHandle() is called before the scheduler has been
|
||||
started, then xTimerTaskHandle will be NULL. */
|
||||
configASSERT( ( xTimerTaskHandle != NULL ) );
|
||||
return xTimerTaskHandle;
|
||||
}
|
||||
|
||||
#endif
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvProcessExpiredTimer( portTickType xNextExpireTime, portTickType xTimeNow )
|
||||
{
|
||||
xTIMER *pxTimer;
|
||||
portBASE_TYPE xResult;
|
||||
|
||||
/* Remove the timer from the list of active timers. A check has already
|
||||
been performed to ensure the list is not empty. */
|
||||
pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
|
||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||
traceTIMER_EXPIRED( pxTimer );
|
||||
|
||||
/* If the timer is an auto reload timer then calculate the next
|
||||
expiry time and re-insert the timer in the list of active timers. */
|
||||
if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
|
||||
{
|
||||
/* This is the only time a timer is inserted into a list using
|
||||
a time relative to anything other than the current time. It
|
||||
will therefore be inserted into the correct list relative to
|
||||
the time this task thinks it is now, even if a command to
|
||||
switch lists due to a tick count overflow is already waiting in
|
||||
the timer queue. */
|
||||
if( prvInsertTimerInActiveList( pxTimer, ( xNextExpireTime + pxTimer->xTimerPeriodInTicks ), xTimeNow, xNextExpireTime ) == pdTRUE )
|
||||
{
|
||||
/* The timer expired before it was added to the active timer
|
||||
list. Reload it now. */
|
||||
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
|
||||
configASSERT( xResult );
|
||||
( void ) xResult;
|
||||
}
|
||||
}
|
||||
|
||||
/* Call the timer callback. */
|
||||
//pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
|
||||
pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer, pxTimer->callback_arg ); //modify by dave
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvTimerTask( void *pvParameters )
|
||||
{
|
||||
portTickType xNextExpireTime;
|
||||
portBASE_TYPE xListWasEmpty;
|
||||
|
||||
/* Just to avoid compiler warnings. */
|
||||
( void ) pvParameters;
|
||||
|
||||
for( ;; )
|
||||
{
|
||||
/* Query the timers list to see if it contains any timers, and if so,
|
||||
obtain the time at which the next timer will expire. */
|
||||
xNextExpireTime = prvGetNextExpireTime( &xListWasEmpty );
|
||||
|
||||
/* If a timer has expired, process it. Otherwise, block this task
|
||||
until either a timer does expire, or a command is received. */
|
||||
prvProcessTimerOrBlockTask( xNextExpireTime, xListWasEmpty );
|
||||
|
||||
/* Empty the command queue. */
|
||||
prvProcessReceivedCommands();
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvProcessTimerOrBlockTask( portTickType xNextExpireTime, portBASE_TYPE xListWasEmpty )
|
||||
{
|
||||
portTickType xTimeNow;
|
||||
portBASE_TYPE xTimerListsWereSwitched;
|
||||
|
||||
vTaskSuspendAll();
|
||||
{
|
||||
/* Obtain the time now to make an assessment as to whether the timer
|
||||
has expired or not. If obtaining the time causes the lists to switch
|
||||
then don't process this timer as any timers that remained in the list
|
||||
when the lists were switched will have been processed within the
|
||||
prvSampelTimeNow() function. */
|
||||
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
|
||||
if( xTimerListsWereSwitched == pdFALSE )
|
||||
{
|
||||
/* The tick count has not overflowed, has the timer expired? */
|
||||
if( ( xListWasEmpty == pdFALSE ) && ( xNextExpireTime <= xTimeNow ) )
|
||||
{
|
||||
xTaskResumeAll();
|
||||
prvProcessExpiredTimer( xNextExpireTime, xTimeNow );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The tick count has not overflowed, and the next expire
|
||||
time has not been reached yet. This task should therefore
|
||||
block to wait for the next expire time or a command to be
|
||||
received - whichever comes first. The following line cannot
|
||||
be reached unless xNextExpireTime > xTimeNow, except in the
|
||||
case when the current timer list is empty. */
|
||||
vQueueWaitForMessageRestricted( xTimerQueue, ( xNextExpireTime - xTimeNow ) );
|
||||
|
||||
if( xTaskResumeAll() == pdFALSE )
|
||||
{
|
||||
/* Yield to wait for either a command to arrive, or the block time
|
||||
to expire. If a command arrived between the critical section being
|
||||
exited and this yield then the yield will not cause the task
|
||||
to block. */
|
||||
portYIELD_WITHIN_API();
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
xTaskResumeAll();
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTickType prvGetNextExpireTime( portBASE_TYPE *pxListWasEmpty )
|
||||
{
|
||||
portTickType xNextExpireTime;
|
||||
|
||||
/* Timers are listed in expiry time order, with the head of the list
|
||||
referencing the task that will expire first. Obtain the time at which
|
||||
the timer with the nearest expiry time will expire. If there are no
|
||||
active timers then just set the next expire time to 0. That will cause
|
||||
this task to unblock when the tick count overflows, at which point the
|
||||
timer lists will be switched and the next expiry time can be
|
||||
re-assessed. */
|
||||
*pxListWasEmpty = listLIST_IS_EMPTY( pxCurrentTimerList );
|
||||
if( *pxListWasEmpty == pdFALSE )
|
||||
{
|
||||
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Ensure the task unblocks when the tick count rolls over. */
|
||||
xNextExpireTime = ( portTickType ) 0U;
|
||||
}
|
||||
|
||||
return xNextExpireTime;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portTickType prvSampleTimeNow( portBASE_TYPE *pxTimerListsWereSwitched )
|
||||
{
|
||||
portTickType xTimeNow;
|
||||
static portTickType xLastTime = ( portTickType ) 0U;
|
||||
|
||||
xTimeNow = xTaskGetTickCount();
|
||||
if( xTimeNow < xLastTime )
|
||||
{
|
||||
prvSwitchTimerLists( xLastTime );
|
||||
*pxTimerListsWereSwitched = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*pxTimerListsWereSwitched = pdFALSE;
|
||||
}
|
||||
|
||||
xLastTime = xTimeNow;
|
||||
|
||||
return xTimeNow;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static portBASE_TYPE prvInsertTimerInActiveList( xTIMER *pxTimer, portTickType xNextExpiryTime, portTickType xTimeNow, portTickType xCommandTime )
|
||||
{
|
||||
portBASE_TYPE xProcessTimerNow = pdFALSE;
|
||||
|
||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xNextExpiryTime );
|
||||
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
||||
|
||||
if( xNextExpiryTime <= xTimeNow )
|
||||
{
|
||||
/* Has the expiry time elapsed between the command to start/reset a
|
||||
timer was issued, and the time the command was processed? */
|
||||
if( ( ( portTickType ) ( xTimeNow - xCommandTime ) ) >= pxTimer->xTimerPeriodInTicks )
|
||||
{
|
||||
/* The time between a command being issued and the command being
|
||||
processed actually exceeds the timers period. */
|
||||
xProcessTimerNow = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
vListInsert( pxOverflowTimerList, &( pxTimer->xTimerListItem ) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if( ( xTimeNow < xCommandTime ) && ( xNextExpiryTime >= xCommandTime ) )
|
||||
{
|
||||
/* If, since the command was issued, the tick count has overflowed
|
||||
but the expiry time has not, then the timer must have already passed
|
||||
its expiry time and should be processed immediately. */
|
||||
xProcessTimerNow = pdTRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
|
||||
}
|
||||
}
|
||||
|
||||
return xProcessTimerNow;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvProcessReceivedCommands( void )
|
||||
{
|
||||
xTIMER_MESSAGE xMessage;
|
||||
xTIMER *pxTimer;
|
||||
portBASE_TYPE xTimerListsWereSwitched, xResult;
|
||||
portTickType xTimeNow;
|
||||
|
||||
/* In this case the xTimerListsWereSwitched parameter is not used, but it
|
||||
must be present in the function call. */
|
||||
//xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
|
||||
|
||||
while( xQueueReceive( xTimerQueue, &xMessage, tmrNO_DELAY ) != pdFAIL )
|
||||
{
|
||||
xTimeNow = prvSampleTimeNow( &xTimerListsWereSwitched );
|
||||
pxTimer = xMessage.pxTimer;
|
||||
|
||||
/* Is the timer already in a list of active timers? When the command
|
||||
is trmCOMMAND_PROCESS_TIMER_OVERFLOW, the timer will be NULL as the
|
||||
command is to the task rather than to an individual timer. */
|
||||
if( pxTimer != NULL )
|
||||
{
|
||||
if( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) == pdFALSE )
|
||||
{
|
||||
/* The timer is in a list, remove it. */
|
||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||
}
|
||||
}
|
||||
|
||||
traceTIMER_COMMAND_RECEIVED( pxTimer, xMessage.xMessageID, xMessage.xMessageValue );
|
||||
|
||||
switch( xMessage.xMessageID )
|
||||
{
|
||||
case tmrCOMMAND_START :
|
||||
/* Start or restart a timer. */
|
||||
if( prvInsertTimerInActiveList( pxTimer, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, xTimeNow, xMessage.xMessageValue ) == pdTRUE )
|
||||
{
|
||||
/* The timer expired before it was added to the active timer
|
||||
list. Process it now. */
|
||||
//pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
|
||||
pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer, pxTimer->callback_arg );//modify by dave
|
||||
|
||||
if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
|
||||
{
|
||||
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xMessage.xMessageValue + pxTimer->xTimerPeriodInTicks, NULL, tmrNO_DELAY );
|
||||
configASSERT( xResult );
|
||||
( void ) xResult;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case tmrCOMMAND_STOP :
|
||||
/* The timer has already been removed from the active list.
|
||||
There is nothing to do here. */
|
||||
break;
|
||||
|
||||
case tmrCOMMAND_CHANGE_PERIOD :
|
||||
pxTimer->xTimerPeriodInTicks = xMessage.xMessageValue;
|
||||
configASSERT( ( pxTimer->xTimerPeriodInTicks > 0 ) );
|
||||
prvInsertTimerInActiveList( pxTimer, ( xTimeNow + pxTimer->xTimerPeriodInTicks ), xTimeNow, xTimeNow );
|
||||
break;
|
||||
|
||||
case tmrCOMMAND_DELETE :
|
||||
/* The timer has already been removed from the active list,
|
||||
just free up the memory. */
|
||||
vPortFree( pxTimer );
|
||||
break;
|
||||
|
||||
default :
|
||||
/* Don't expect to get here. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvSwitchTimerLists( portTickType xLastTime )
|
||||
{
|
||||
portTickType xNextExpireTime, xReloadTime;
|
||||
xList *pxTemp;
|
||||
xTIMER *pxTimer;
|
||||
portBASE_TYPE xResult;
|
||||
|
||||
/* Remove compiler warnings if configASSERT() is not defined. */
|
||||
( void ) xLastTime;
|
||||
|
||||
/* The tick count has overflowed. The timer lists must be switched.
|
||||
If there are any timers still referenced from the current timer list
|
||||
then they must have expired and should be processed before the lists
|
||||
are switched. */
|
||||
while( listLIST_IS_EMPTY( pxCurrentTimerList ) == pdFALSE )
|
||||
{
|
||||
xNextExpireTime = listGET_ITEM_VALUE_OF_HEAD_ENTRY( pxCurrentTimerList );
|
||||
|
||||
/* Remove the timer from the list. */
|
||||
pxTimer = ( xTIMER * ) listGET_OWNER_OF_HEAD_ENTRY( pxCurrentTimerList );
|
||||
vListRemove( &( pxTimer->xTimerListItem ) );
|
||||
|
||||
/* Execute its callback, then send a command to restart the timer if
|
||||
it is an auto-reload timer. It cannot be restarted here as the lists
|
||||
have not yet been switched. */
|
||||
//pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer );
|
||||
pxTimer->pxCallbackFunction( ( xTimerHandle ) pxTimer, pxTimer->callback_arg ); //modify by dave
|
||||
|
||||
if( pxTimer->uxAutoReload == ( unsigned portBASE_TYPE ) pdTRUE )
|
||||
{
|
||||
/* Calculate the reload value, and if the reload value results in
|
||||
the timer going into the same timer list then it has already expired
|
||||
and the timer should be re-inserted into the current list so it is
|
||||
processed again within this loop. Otherwise a command should be sent
|
||||
to restart the timer to ensure it is only inserted into a list after
|
||||
the lists have been swapped. */
|
||||
xReloadTime = ( xNextExpireTime + pxTimer->xTimerPeriodInTicks );
|
||||
if( xReloadTime > xNextExpireTime )
|
||||
{
|
||||
listSET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ), xReloadTime );
|
||||
listSET_LIST_ITEM_OWNER( &( pxTimer->xTimerListItem ), pxTimer );
|
||||
vListInsert( pxCurrentTimerList, &( pxTimer->xTimerListItem ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
xResult = xTimerGenericCommand( pxTimer, tmrCOMMAND_START, xNextExpireTime, NULL, tmrNO_DELAY );
|
||||
configASSERT( xResult );
|
||||
( void ) xResult;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pxTemp = pxCurrentTimerList;
|
||||
pxCurrentTimerList = pxOverflowTimerList;
|
||||
pxOverflowTimerList = pxTemp;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
static void prvCheckForValidListAndQueue( void )
|
||||
{
|
||||
/* Check that the list from which active timers are referenced, and the
|
||||
queue used to communicate with the timer service, have been
|
||||
initialised. */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
if( xTimerQueue == NULL )
|
||||
{
|
||||
vListInitialise( &xActiveTimerList1 );
|
||||
vListInitialise( &xActiveTimerList2 );
|
||||
pxCurrentTimerList = &xActiveTimerList1;
|
||||
pxOverflowTimerList = &xActiveTimerList2;
|
||||
xTimerQueue = xQueueCreate( ( unsigned portBASE_TYPE ) configTIMER_QUEUE_LENGTH, sizeof( xTIMER_MESSAGE ) );
|
||||
}
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
portBASE_TYPE xTimerIsTimerActive( xTimerHandle xTimer )
|
||||
{
|
||||
portBASE_TYPE xTimerIsInActiveList;
|
||||
xTIMER *pxTimer = ( xTIMER * ) xTimer;
|
||||
|
||||
/* Is the timer in the list of active timers? */
|
||||
taskENTER_CRITICAL();
|
||||
{
|
||||
/* Checking to see if it is in the NULL list in effect checks to see if
|
||||
it is referenced from either the current or the overflow timer lists in
|
||||
one go, but the logic has to be reversed, hence the '!'. */
|
||||
xTimerIsInActiveList = !( listIS_CONTAINED_WITHIN( NULL, &( pxTimer->xTimerListItem ) ) );
|
||||
}
|
||||
taskEXIT_CRITICAL();
|
||||
|
||||
return xTimerIsInActiveList;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
void *pvTimerGetTimerID( xTimerHandle xTimer )
|
||||
{
|
||||
xTIMER *pxTimer = ( xTIMER * ) xTimer;
|
||||
|
||||
return pxTimer->pvTimerID;
|
||||
}
|
||||
/*-----------------------------------------------------------*/
|
||||
|
||||
/* This entire source file will be skipped if the application is not configured
|
||||
to include software timer functionality. If you want to include software timer
|
||||
functionality then ensure configUSE_TIMERS is set to 1 in FreeRTOSConfig.h. */
|
||||
#endif /* configUSE_TIMERS == 1 */
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user