Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 18 additions & 1 deletion include/FreeRTOS.h
Original file line number Diff line number Diff line change
Expand Up @@ -1626,6 +1626,22 @@
#define traceRETURN_xTimerGetExpiryTime( xReturn )
#endif

#ifndef traceENTER_uxTimerGetNumberOfTimers
#define traceENTER_uxTimerGetNumberOfTimers()
#endif

#ifndef traceRETURN_uxTimerGetNumberOfTimers
#define traceRETURN_uxTimerGetNumberOfTimers( uxNumberOfTimers )
#endif

#ifndef traceENTER_uxTimerGetSystemState
#define traceENTER_uxTimerGetSystemState( pxTimerStatusArray, uxArraySize )
#endif

#ifndef traceRETURN_uxTimerGetSystemState
#define traceRETURN_uxTimerGetSystemState( uxNumberOfTimers )
#endif

#ifndef traceENTER_xTimerGetStaticBuffer
#define traceENTER_xTimerGetStaticBuffer( xTimer, ppxTimerBuffer )
#endif
Expand Down Expand Up @@ -3319,8 +3335,9 @@ typedef struct xSTATIC_TIMER
TaskFunction_t pvDummy6;
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxDummy7;
void * pvDummy8;
#endif
uint8_t ucDummy8;
uint8_t ucDummy9;
} StaticTimer_t;

/*
Expand Down
57 changes: 57 additions & 0 deletions include/timers.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,19 @@
struct tmrTimerControl; /* The old naming convention is used to prevent breaking kernel aware debuggers. */
typedef struct tmrTimerControl * TimerHandle_t;

/* Used with uxTimerGetSystemState() to return the state of each timer in the
* timer registry. */
typedef struct xTIMER_STATUS
{
TimerHandle_t xHandle; /* The handle of the timer. This value will be invalid if the timer is deleted after the structure is populated. */
const char * pcTimerName; /* A pointer to the name assigned when the timer was created. */
TickType_t xTimerPeriodInTicks; /* The timer's period in ticks. */
TickType_t xNextExpiryTime; /* The next expiry time, or 0 if the timer is inactive. */
void * pvTimerID; /* The application-supplied timer ID. */
BaseType_t xIsActive; /* pdTRUE if the timer is active, otherwise pdFALSE. */
BaseType_t xAutoReload; /* pdTRUE for an auto-reload timer, otherwise pdFALSE. */
} TimerStatus_t;

/*
* Defines the prototype to which timer callback functions must conform.
*/
Expand Down Expand Up @@ -1333,6 +1346,50 @@ TickType_t xTimerGetPeriod( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;
*/
TickType_t xTimerGetExpiryTime( TimerHandle_t xTimer ) PRIVILEGED_FUNCTION;

/**
* configUSE_TRACE_FACILITY must be set to 1 for
* uxTimerGetNumberOfTimers() to be available.
*
* @return The number of timers currently stored in the timer registry.
*/
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTimerGetNumberOfTimers( void ) PRIVILEGED_FUNCTION;
#endif

/**
* configUSE_TRACE_FACILITY must be set to 1 for
* uxTimerGetSystemState() to be available.
*
* uxTimerGetSystemState() populates one TimerStatus_t structure for each
* timer currently stored in the timer registry. Timers are automatically
* added to the registry when they are created and removed when they are
* deleted.
*
* This function is intended for debugging use and suspends the scheduler while
* the registry is copied. The returned values provide a best-effort snapshot
* of timer state. Timer commands still waiting in the timer command queue are
* not reflected.
*
* TimerStatus_t contains borrowed handles and pointers. A timer handle becomes
* invalid when that timer is deleted, and the application must ensure that the
* memory referenced by timer names and IDs remains valid while it is used.
*
* When MPU wrappers are enabled, this API is privileged-only.
*
* @param pxTimerStatusArray A pointer to an array of TimerStatus_t structures.
* The array must contain at least one entry for each timer in the registry. The
* number of timers can be obtained using uxTimerGetNumberOfTimers().
*
* @param uxArraySize The number of TimerStatus_t entries in the array.
*
* @return The number of TimerStatus_t structures populated, or zero if the
* supplied array is too small or pxTimerStatusArray is NULL.
*/
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTimerGetSystemState( TimerStatus_t * const pxTimerStatusArray,
const UBaseType_t uxArraySize ) PRIVILEGED_FUNCTION;
#endif

/**
* BaseType_t xTimerGetStaticBuffer( TimerHandle_t xTimer,
* StaticTimer_t ** ppxTimerBuffer );
Expand Down
139 changes: 139 additions & 0 deletions timers.c
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,7 @@
portTIMER_CALLBACK_ATTRIBUTE TimerCallbackFunction_t pxCallbackFunction; /**< The function that will be called when the timer expires. */
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxTimerNumber; /**< An ID assigned by trace tools such as FreeRTOS+Trace */
struct tmrTimerControl * pxNextTimer; /**< Points to the next timer in the timer registry. */
#endif
uint8_t ucStatus; /**< Holds bits to say if the timer was statically allocated or not, and if it is active or not. */
} xTIMER;
Expand Down Expand Up @@ -149,6 +150,11 @@
PRIVILEGED_DATA static QueueHandle_t xTimerQueue = NULL;
PRIVILEGED_DATA static TaskHandle_t xTimerTaskHandle = NULL;

#if ( configUSE_TRACE_FACILITY == 1 )
PRIVILEGED_DATA static Timer_t * pxTimerRegistry = NULL;
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTimers = 0U;
#endif

/*-----------------------------------------------------------*/

/*
Expand All @@ -157,6 +163,11 @@
*/
static void prvCheckForValidListAndQueue( void ) PRIVILEGED_FUNCTION;

#if ( configUSE_TRACE_FACILITY == 1 )
static void prvAddTimerToRegistry( Timer_t * pxTimer ) PRIVILEGED_FUNCTION;
static void prvRemoveTimerFromRegistry( Timer_t * pxTimer ) PRIVILEGED_FUNCTION;
#endif

/*
* The timer service task (daemon). Timer functionality is controlled by this
* task. Other tasks communicate with the timer service task using the
Expand Down Expand Up @@ -441,10 +452,56 @@
pxNewTimer->ucStatus |= ( uint8_t ) tmrSTATUS_IS_AUTORELOAD;
}

#if ( configUSE_TRACE_FACILITY == 1 )
{
prvAddTimerToRegistry( pxNewTimer );
}
#endif

traceTIMER_CREATE( pxNewTimer );
}
/*-----------------------------------------------------------*/

#if ( configUSE_TRACE_FACILITY == 1 )

static void prvAddTimerToRegistry( Timer_t * pxTimer )
{
taskENTER_CRITICAL();
{
pxTimer->pxNextTimer = pxTimerRegistry;
pxTimerRegistry = pxTimer;
uxCurrentNumberOfTimers++;
}
taskEXIT_CRITICAL();
}

static void prvRemoveTimerFromRegistry( Timer_t * pxTimer )
{
Timer_t ** ppxTimer = &pxTimerRegistry;

taskENTER_CRITICAL();
{
while( *ppxTimer != NULL )
{
if( *ppxTimer == pxTimer )
{
*ppxTimer = pxTimer->pxNextTimer;
pxTimer->pxNextTimer = NULL;
uxCurrentNumberOfTimers--;
break;
}
else
{
ppxTimer = &( ( *ppxTimer )->pxNextTimer );
}
}
}
taskEXIT_CRITICAL();
}

#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/

BaseType_t xTimerGenericCommandFromTask( TimerHandle_t xTimer,
const BaseType_t xCommandID,
const TickType_t xOptionalValue,
Expand Down Expand Up @@ -1047,6 +1104,12 @@
break;

case tmrCOMMAND_DELETE:
#if ( configUSE_TRACE_FACILITY == 1 )
{
prvRemoveTimerFromRegistry( pxTimer );
}
#endif

#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
{
/* The timer has already been removed from the active list,
Expand Down Expand Up @@ -1310,6 +1373,75 @@
#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/

#if ( configUSE_TRACE_FACILITY == 1 )

UBaseType_t uxTimerGetNumberOfTimers( void )
{
UBaseType_t uxNumberOfTimers;

traceENTER_uxTimerGetNumberOfTimers();

/* A critical section is not required because the variable is of
* type UBaseType_t. */
uxNumberOfTimers = uxCurrentNumberOfTimers;

traceRETURN_uxTimerGetNumberOfTimers( uxNumberOfTimers );

return uxNumberOfTimers;
}

UBaseType_t uxTimerGetSystemState( TimerStatus_t * const pxTimerStatusArray,
const UBaseType_t uxArraySize )
{
UBaseType_t uxNumberOfTimers = 0U;

traceENTER_uxTimerGetSystemState( pxTimerStatusArray, uxArraySize );

if( pxTimerStatusArray != NULL )
{
vTaskSuspendAll();
{
if( uxArraySize >= uxCurrentNumberOfTimers )
{
Timer_t * pxTimer = pxTimerRegistry;
UBaseType_t uxTimer = 0U;

while( pxTimer != NULL )
{
pxTimerStatusArray[ uxTimer ].xHandle = pxTimer;
pxTimerStatusArray[ uxTimer ].pcTimerName = pxTimer->pcTimerName;
pxTimerStatusArray[ uxTimer ].xTimerPeriodInTicks = pxTimer->xTimerPeriodInTicks;
pxTimerStatusArray[ uxTimer ].pvTimerID = pxTimer->pvTimerID;
pxTimerStatusArray[ uxTimer ].xIsActive = ( ( pxTimer->ucStatus & tmrSTATUS_IS_ACTIVE ) != 0U ) ? pdTRUE : pdFALSE;
pxTimerStatusArray[ uxTimer ].xAutoReload = ( ( pxTimer->ucStatus & tmrSTATUS_IS_AUTORELOAD ) != 0U ) ? pdTRUE : pdFALSE;

if( pxTimerStatusArray[ uxTimer ].xIsActive != pdFALSE )
{
pxTimerStatusArray[ uxTimer ].xNextExpiryTime = listGET_LIST_ITEM_VALUE( &( pxTimer->xTimerListItem ) );
}
else
{
pxTimerStatusArray[ uxTimer ].xNextExpiryTime = 0U;
}

uxTimer++;
pxTimer = pxTimer->pxNextTimer;
}

uxNumberOfTimers = uxTimer;
}
}
( void ) xTaskResumeAll();
}

traceRETURN_uxTimerGetSystemState( uxNumberOfTimers );

return uxNumberOfTimers;
}

#endif /* configUSE_TRACE_FACILITY */
/*-----------------------------------------------------------*/

#if ( configUSE_TRACE_FACILITY == 1 )

void vTimerSetTimerNumber( TimerHandle_t xTimer,
Expand All @@ -1334,6 +1466,13 @@
{
xTimerQueue = NULL;
xTimerTaskHandle = NULL;

#if ( configUSE_TRACE_FACILITY == 1 )
{
pxTimerRegistry = NULL;
uxCurrentNumberOfTimers = 0U;
}
#endif
}
/*-----------------------------------------------------------*/

Expand Down