/*******************************************************************************
* Trace Recorder Library for Tracealyzer v4 .1 .5
* Percepio AB , www . percepio . com
*
* trcKernelPort . c
*
* The FreeRTOS - specific parts of the trace recorder
*
* Terms of Use
* This file is part of the trace recorder library ( RECORDER ) , which is the
* intellectual property of Percepio AB ( PERCEPIO ) and provided under a
* license as follows .
* The RECORDER may be used free of charge for the purpose of recording data
* intended for analysis in PERCEPIO products . It may not be used or modified
* for other purposes without explicit permission from PERCEPIO .
* You may distribute the RECORDER in its original source code form , assuming
* this text ( terms of use , disclaimer , copyright notice ) is unchanged . You are
* allowed to distribute the RECORDER with minor modifications intended for
* configuration or porting of the RECORDER , e . g . , to allow using it on a
* specific processor , processor family or with a specific communication
* interface . Any such modifications should be documented directly below
* this comment block .
*
* Disclaimer
* The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty
* as to its use or performance . PERCEPIO does not and cannot warrant the
* performance or results you may obtain by using the RECORDER or documentation .
* PERCEPIO make no warranties , express or implied , as to noninfringement of
* third party rights , merchantability , or fitness for any particular purpose .
* In no event will PERCEPIO , its technology partners , or distributors be liable
* to you for any consequential , incidental or special damages , including any
* lost profits or lost savings , even if a representative of PERCEPIO has been
* advised of the possibility of such damages , or for any claim by any third
* party . Some jurisdictions do not allow the exclusion or limitation of
* incidental , consequential or special damages , or the exclusion of implied
* warranties or limitations on how long an implied warranty may last , so the
* above limitations may not apply to you .
*
* Tabs are used for indent in this file ( 1 tab = 4 spaces )
*
* Copyright Percepio AB , 2018.
* www . percepio . com
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# include "FreeRTOS.h"
# if (!defined(TRC_USE_TRACEALYZER_RECORDER) && configUSE_TRACE_FACILITY == 1)
# error Trace Recorder: You need to include trcRecorder.h at the end of your FreeRTOSConfig.h!
# endif
# if (defined(TRC_USE_TRACEALYZER_RECORDER) && TRC_USE_TRACEALYZER_RECORDER == 1)
# ifndef TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS
/* TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS is missing in trcConfig.h. */
# error "TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS must be defined in trcConfig.h."
# endif
# ifndef TRC_CFG_INCLUDE_TIMER_EVENTS
/* TRC_CFG_INCLUDE_TIMER_EVENTS is missing in trcConfig.h. */
# error "TRC_CFG_INCLUDE_TIMER_EVENTS must be defined in trcConfig.h."
# endif
# ifndef TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS
/* TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS is missing in trcConfig.h. */
# error "TRC_CFG_INCLUDE_PEND_FUNC_CALL_EVENTS must be defined in trcConfig.h."
# endif
# ifndef TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS
/* TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS is missing in trcConfig.h. Define this as 1 if using FreeRTOS v10 or later and like to trace stream buffer or message buffer events, otherwise 0. */
# error "TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS must be defined in trcConfig.h."
# endif
# if (configUSE_TICKLESS_IDLE != 0 && (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR))
/*
The below error message is to alert you on the following issue :
The hardware port selected in trcConfig . h uses the operating system timer for the
timestamping , i . e . , the periodic interrupt timer that drives the OS tick interrupt .
When using " tickless idle " mode , the recorder needs an independent time source in
order to correctly record the durations of the idle times . Otherwise , the trace may appear
to have a different length than in reality , and the reported CPU load is also affected .
You may override this warning by defining the TRC_CFG_ACKNOWLEDGE_TICKLESS_IDLE_WARNING
macro in your trcConfig . h file . But then the time scale may be incorrect during
tickless idle periods .
To get this correct , override the default timestamping by setting TRC_CFG_HARDWARE_PORT
in trcConfig . h to TRC_HARDWARE_PORT_APPLICATION_DEFINED and define the HWTC macros
accordingly , using a free running counter or an independent periodic interrupt timer .
See trcHardwarePort . h for details .
For ARM Cortex - M3 , M4 and M7 MCUs this is not an issue , since the recorder uses the
DWT cycle counter for timestamping in these cases .
*/
# ifndef TRC_CFG_ACKNOWLEDGE_TICKLESS_IDLE_WARNING
# error Trace Recorder: This timestamping mode is not recommended with Tickless Idle.
# endif
# endif /* (configUSE_TICKLESS_IDLE != 0 && (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)) */
# include "task.h"
# include "queue.h"
# if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X)
/* If the project does not include the FreeRTOS timers, TRC_CFG_INCLUDE_TIMER_EVENTS must be set to 0 */
# include "timers.h"
# endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */
# if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X)
/* If the project does not include the FreeRTOS event groups, TRC_CFG_INCLUDE_TIMER_EVENTS must be set to 0 */
# include "event_groups.h"
# endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */
# if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
/* If the project does not include the FreeRTOS stream buffers, TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS must be set to 0 */
# include "stream_buffer.h"
# endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
uint32_t prvTraceGetQueueNumber ( void * handle ) ;
# if (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_8_X)
extern unsigned char ucQueueGetQueueNumber ( xQueueHandle pxQueue ) ;
extern void vQueueSetQueueNumber ( xQueueHandle pxQueue , unsigned char ucQueueNumber ) ;
extern unsigned char ucQueueGetQueueType ( xQueueHandle pxQueue ) ;
uint32_t prvTraceGetQueueNumber ( void * handle )
{
return ( uint32_t ) ucQueueGetQueueNumber ( handle ) ;
}
# else
uint32_t prvTraceGetQueueNumber ( void * handle )
{
return ( uint32_t ) uxQueueGetQueueNumber ( handle ) ;
}
# endif /* (TRC_CFG_FREERTOS_VERSION < TRC_FREERTOS_VERSION_8_X) */
uint8_t prvTraceGetQueueType ( void * handle )
{
// This is either declared in header file in FreeRTOS 8 and later, or as extern above
return ucQueueGetQueueType ( handle ) ;
}
/* Tasks */
uint16_t prvTraceGetTaskNumberLow16 ( void * handle )
{
return TRACE_GET_LOW16 ( uxTaskGetTaskNumber ( handle ) ) ;
}
uint16_t prvTraceGetTaskNumberHigh16 ( void * handle )
{
return TRACE_GET_HIGH16 ( uxTaskGetTaskNumber ( handle ) ) ;
}
void prvTraceSetTaskNumberLow16 ( void * handle , uint16_t value )
{
vTaskSetTaskNumber ( handle , TRACE_SET_LOW16 ( uxTaskGetTaskNumber ( handle ) , value ) ) ;
}
void prvTraceSetTaskNumberHigh16 ( void * handle , uint16_t value )
{
vTaskSetTaskNumber ( handle , TRACE_SET_HIGH16 ( uxTaskGetTaskNumber ( handle ) , value ) ) ;
}
uint16_t prvTraceGetQueueNumberLow16 ( void * handle )
{
return TRACE_GET_LOW16 ( prvTraceGetQueueNumber ( handle ) ) ;
}
uint16_t prvTraceGetQueueNumberHigh16 ( void * handle )
{
return TRACE_GET_HIGH16 ( prvTraceGetQueueNumber ( handle ) ) ;
}
void prvTraceSetQueueNumberLow16 ( void * handle , uint16_t value )
{
vQueueSetQueueNumber ( handle , TRACE_SET_LOW16 ( prvTraceGetQueueNumber ( handle ) , value ) ) ;
}
void prvTraceSetQueueNumberHigh16 ( void * handle , uint16_t value )
{
vQueueSetQueueNumber ( handle , TRACE_SET_HIGH16 ( prvTraceGetQueueNumber ( handle ) , value ) ) ;
}
# if (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
uint16_t prvTraceGetTimerNumberLow16 ( void * handle )
{
return TRACE_GET_LOW16 ( uxTimerGetTimerNumber ( handle ) ) ;
}
uint16_t prvTraceGetTimerNumberHigh16 ( void * handle )
{
return TRACE_GET_HIGH16 ( uxTimerGetTimerNumber ( handle ) ) ;
}
void prvTraceSetTimerNumberLow16 ( void * handle , uint16_t value )
{
vTimerSetTimerNumber ( handle , TRACE_SET_LOW16 ( uxTimerGetTimerNumber ( handle ) , value ) ) ;
}
void prvTraceSetTimerNumberHigh16 ( void * handle , uint16_t value )
{
vTimerSetTimerNumber ( handle , TRACE_SET_HIGH16 ( uxTimerGetTimerNumber ( handle ) , value ) ) ;
}
# endif /* (TRC_CFG_INCLUDE_TIMER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
# if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
uint16_t prvTraceGetEventGroupNumberLow16 ( void * handle )
{
return TRACE_GET_LOW16 ( uxEventGroupGetNumber ( handle ) ) ;
}
uint16_t prvTraceGetEventGroupNumberHigh16 ( void * handle )
{
return TRACE_GET_HIGH16 ( uxEventGroupGetNumber ( handle ) ) ;
}
void prvTraceSetEventGroupNumberLow16 ( void * handle , uint16_t value )
{
vEventGroupSetNumber ( handle , TRACE_SET_LOW16 ( uxEventGroupGetNumber ( handle ) , value ) ) ;
}
void prvTraceSetEventGroupNumberHigh16 ( void * handle , uint16_t value )
{
vEventGroupSetNumber ( handle , TRACE_SET_HIGH16 ( uxEventGroupGetNumber ( handle ) , value ) ) ;
}
# endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
# if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
uint16_t prvTraceGetStreamBufferNumberLow16 ( void * handle )
{
return TRACE_GET_LOW16 ( uxStreamBufferGetStreamBufferNumber ( handle ) ) ;
}
uint16_t prvTraceGetStreamBufferNumberHigh16 ( void * handle )
{
return TRACE_GET_HIGH16 ( uxStreamBufferGetStreamBufferNumber ( handle ) ) ;
}
void prvTraceSetStreamBufferNumberLow16 ( void * handle , uint16_t value )
{
vStreamBufferSetStreamBufferNumber ( handle , TRACE_SET_LOW16 ( uxStreamBufferGetStreamBufferNumber ( handle ) , value ) ) ;
}
void prvTraceSetStreamBufferNumberHigh16 ( void * handle , uint16_t value )
{
vStreamBufferSetStreamBufferNumber ( handle , TRACE_SET_HIGH16 ( uxStreamBufferGetStreamBufferNumber ( handle ) , value ) ) ;
}
# endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
# if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
static void * pCurrentTCB = NULL ;
# if (defined(configENABLE_BACKWARD_COMPATIBILITY) && configENABLE_BACKWARD_COMPATIBILITY == 0)
/* We're explicitly not using compatibility mode */
static TaskHandle_t HandleTzCtrl = NULL ; /* TzCtrl task TCB */
# else
/* We're using compatibility mode, or we're running an old kernel */
static xTaskHandle HandleTzCtrl = NULL ; /* TzCtrl task TCB */
# endif
# if defined(configSUPPORT_STATIC_ALLOCATION)
# if (configSUPPORT_STATIC_ALLOCATION == 1)
static StackType_t stackTzCtrl [ TRC_CFG_CTRL_TASK_STACK_SIZE ] ;
static StaticTask_t tcbTzCtrl ;
# endif
# endif
/* Monitored by TzCtrl task, that give warnings as User Events */
extern volatile uint32_t NoRoomForSymbol ;
extern volatile uint32_t NoRoomForObjectData ;
extern volatile uint32_t LongestSymbolName ;
extern volatile uint32_t MaxBytesTruncated ;
/* Keeps track of previous values, to only react on changes. */
static uint32_t NoRoomForSymbol_last = 0 ;
static uint32_t NoRoomForObjectData_last = 0 ;
static uint32_t LongestSymbolName_last = 0 ;
static uint32_t MaxBytesTruncated_last = 0 ;
/* User Event Channel for giving warnings regarding NoRoomForSymbol etc. */
traceString trcWarningChannel ;
# define TRC_PORT_MALLOC(size) pvPortMalloc(size)
TRC_STREAM_PORT_ALLOCATE_FIELDS ( )
/* Called by TzCtrl task periodically (Normally every 100 ms) */
static void prvCheckRecorderStatus ( void ) ;
extern void prvTraceWarning ( int errCode ) ;
/* The TzCtrl task - receives commands from Tracealyzer (start/stop) */
static portTASK_FUNCTION ( TzCtrl , pvParameters ) ;
/*******************************************************************************
* vTraceEnable
*
* Function that enables the tracing and creates the control task . It will halt
* execution until a Start command has been received if haltUntilStart is true .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceEnable ( int startOption )
{
int32_t bytes = 0 ;
int32_t status ;
extern uint32_t RecorderEnabled ;
TracealyzerCommandType msg ;
/* Only do this first time...*/
if ( HandleTzCtrl = = NULL )
{
TRC_STREAM_PORT_INIT ( ) ;
/* Note: Requires that TRC_CFG_INCLUDE_USER_EVENTS is 1. */
trcWarningChannel = xTraceRegisterString ( " Warnings from Recorder " ) ;
/* Creates the TzCtrl task - receives trace commands (start, stop, ...) */
# if defined(configSUPPORT_STATIC_ALLOCATION) && (configSUPPORT_STATIC_ALLOCATION == 1)
HandleTzCtrl = xTaskCreateStatic ( TzCtrl , STRING_CAST ( " TzCtrl " ) , TRC_CFG_CTRL_TASK_STACK_SIZE , NULL , TRC_CFG_CTRL_TASK_PRIORITY , stackTzCtrl , & tcbTzCtrl ) ;
# else
xTaskCreate ( TzCtrl , STRING_CAST ( " TzCtrl " ) , TRC_CFG_CTRL_TASK_STACK_SIZE , NULL , TRC_CFG_CTRL_TASK_PRIORITY , & HandleTzCtrl ) ;
# endif
if ( HandleTzCtrl = = NULL )
{
prvTraceError ( PSF_ERROR_TZCTRLTASK_NOT_CREATED ) ;
}
}
if ( startOption = = TRC_START_AWAIT_HOST )
{
/* We keep trying to read commands until the recorder has been started */
do
{
bytes = 0 ;
status = TRC_STREAM_PORT_READ_DATA ( & msg , sizeof ( TracealyzerCommandType ) , ( int32_t * ) & bytes ) ;
if ( status ! = 0 )
{
prvTraceWarning ( PSF_WARNING_STREAM_PORT_READ ) ;
}
if ( ( status = = 0 ) & & ( bytes = = sizeof ( TracealyzerCommandType ) ) )
{
if ( prvIsValidCommand ( & msg ) )
{
if ( msg . cmdCode = = CMD_SET_ACTIVE & & msg . param1 = = 1 )
{
/* On start, init and reset the timestamping */
TRC_PORT_SPECIFIC_INIT ( ) ;
}
prvProcessCommand ( & msg ) ;
}
}
}
while ( RecorderEnabled = = 0 ) ;
}
else if ( startOption = = TRC_START )
{
/* We start streaming directly - this assumes that the interface is ready! */
TRC_PORT_SPECIFIC_INIT ( ) ;
msg . cmdCode = CMD_SET_ACTIVE ;
msg . param1 = 1 ;
prvProcessCommand ( & msg ) ;
}
else
{
/* On TRC_INIT */
TRC_PORT_SPECIFIC_INIT ( ) ;
}
}
# if (TRC_CFG_SCHEDULING_ONLY == 0)
/*******************************************************************************
* vTraceSetQueueName ( void * object , const char * name )
*
* Parameter object : pointer to the Queue that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for Queue objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetQueueName ( void * object , const char * name )
{
vTraceStoreKernelObjectName ( object , name ) ;
}
/*******************************************************************************
* vTraceSetSemaphoreName ( void * object , const char * name )
*
* Parameter object : pointer to the Semaphore that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for Semaphore objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetSemaphoreName ( void * object , const char * name )
{
vTraceStoreKernelObjectName ( object , name ) ;
}
/*******************************************************************************
* vTraceSetMutexName ( void * object , const char * name )
*
* Parameter object : pointer to the Mutex that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for Mutex objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetMutexName ( void * object , const char * name )
{
vTraceStoreKernelObjectName ( object , name ) ;
}
# if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X)
/*******************************************************************************
* vTraceSetEventGroupName ( void * object , const char * name )
*
* Parameter object : pointer to the vTraceSetEventGroupName that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for EventGroup objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetEventGroupName ( void * object , const char * name )
{
vTraceStoreKernelObjectName ( object , name ) ;
}
# endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */
# if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
/*******************************************************************************
* vTraceSetStreamBufferName ( void * object , const char * name )
*
* Parameter object : pointer to the StreamBuffer that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for StreamBuffer objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetStreamBufferName ( void * object , const char * name )
{
vTraceStoreKernelObjectName ( object , name ) ;
}
/*******************************************************************************
* vTraceSetMessageBufferName ( void * object , const char * name )
*
* Parameter object : pointer to the MessageBuffer that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for MessageBuffer objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetMessageBufferName ( void * object , const char * name )
{
vTraceStoreKernelObjectName ( object , name ) ;
}
# endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
# endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */
/*******************************************************************************
* prvGetCurrentTaskHandle
*
* Function that returns the handle to the currently executing task .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void * prvTraceGetCurrentTaskHandle ( void )
{
return xTaskGetCurrentTaskHandle ( ) ;
}
/*******************************************************************************
* prvIsNewTCB
*
* Tells if this task is already executing , or if there has been a task - switch .
* Assumed to be called within a trace hook in kernel context .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
uint32_t prvIsNewTCB ( void * pNewTCB )
{
if ( pCurrentTCB ! = pNewTCB )
{
pCurrentTCB = pNewTCB ;
return 1 ;
}
return 0 ;
}
/*******************************************************************************
* prvTraceIsSchedulerSuspended
*
* Returns true if the RTOS scheduler currently is disabled , thus preventing any
* task - switches from occurring . Only called from vTraceStoreISREnd .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
unsigned char prvTraceIsSchedulerSuspended ( void )
{
/* Assumed to be available in FreeRTOS. According to the FreeRTOS docs,
INCLUDE_xTaskGetSchedulerState or configUSE_TIMERS must be set to 1 in
FreeRTOSConfig . h for this function to be available . */
return xTaskGetSchedulerState ( ) = = taskSCHEDULER_SUSPENDED ;
}
/*******************************************************************************
* prvCheckRecorderStatus
*
* Called by TzCtrl task periodically ( every 100 ms - seems reasonable ) .
* Checks a number of diagnostic variables and give warnings as user events ,
* in most cases including a suggested solution .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static void prvCheckRecorderStatus ( void )
{
if ( NoRoomForSymbol > NoRoomForSymbol_last )
{
if ( NoRoomForSymbol > 0 )
{
prvTraceWarning ( PSF_WARNING_SYMBOL_TABLE_SLOTS ) ;
}
NoRoomForSymbol_last = NoRoomForSymbol ;
}
if ( NoRoomForObjectData > NoRoomForObjectData_last )
{
if ( NoRoomForObjectData > 0 )
{
prvTraceWarning ( PSF_WARNING_OBJECT_DATA_SLOTS ) ;
}
NoRoomForObjectData_last = NoRoomForObjectData ;
}
if ( LongestSymbolName > LongestSymbolName_last )
{
if ( LongestSymbolName > ( TRC_CFG_SYMBOL_MAX_LENGTH ) )
{
prvTraceWarning ( PSF_WARNING_SYMBOL_MAX_LENGTH ) ;
}
LongestSymbolName_last = LongestSymbolName ;
}
if ( MaxBytesTruncated > MaxBytesTruncated_last )
{
if ( MaxBytesTruncated > 0 )
{
prvTraceWarning ( PSF_WARNING_STRING_TOO_LONG ) ;
}
MaxBytesTruncated_last = MaxBytesTruncated ;
}
}
/*******************************************************************************
* TzCtrl
*
* Task for sending the trace data from the internal buffer to the stream
* interface ( assuming TRC_STREAM_PORT_USE_INTERNAL_BUFFER = = 1 ) and for
* receiving commands from Tracealyzer . Also does some diagnostics .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static portTASK_FUNCTION ( TzCtrl , pvParameters )
{
TracealyzerCommandType msg ;
int32_t bytes = 0 ;
int32_t status = 0 ;
( void ) pvParameters ;
while ( 1 )
{
do
{
/* Listen for new commands */
bytes = 0 ;
status = TRC_STREAM_PORT_READ_DATA ( & msg , sizeof ( TracealyzerCommandType ) , ( int32_t * ) & bytes ) ;
if ( status ! = 0 )
{
prvTraceWarning ( PSF_WARNING_STREAM_PORT_READ ) ;
}
if ( ( status = = 0 ) & & ( bytes = = sizeof ( TracealyzerCommandType ) ) )
{
if ( prvIsValidCommand ( & msg ) )
{
prvProcessCommand ( & msg ) ; /* Start or Stop currently... */
}
}
/* If the internal buffer is disabled, the COMMIT macro instead sends the data directly
from the " event functions " ( using TRC_STREAM_PORT_WRITE_DATA ) . */
# if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)
/* If there is a buffer page, this sends it to the streaming interface using TRC_STREAM_PORT_WRITE_DATA. */
bytes = prvPagedEventBufferTransfer ( ) ;
# endif
/* If there was data sent or received (bytes != 0), loop around and repeat, if there is more data to send or receive.
Otherwise , step out of this loop and sleep for a while . */
} while ( bytes ! = 0 ) ;
prvCheckRecorderStatus ( ) ;
vTaskDelay ( TRC_CFG_CTRL_TASK_DELAY ) ;
}
}
# endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
# if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
/* Internal flag to tell the context of tracePEND_FUNC_CALL_FROM_ISR */
int uiInEventGroupSetBitsFromISR = 0 ;
/******************************************************************************
* TraceQueueClassTable
* Translates a FreeRTOS QueueType into trace objects classes ( TRACE_CLASS_ ) .
* Has one entry for each QueueType , gives TRACE_CLASS ID .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
traceObjectClass TraceQueueClassTable [ 5 ] = {
TRACE_CLASS_QUEUE ,
TRACE_CLASS_MUTEX ,
TRACE_CLASS_SEMAPHORE ,
TRACE_CLASS_SEMAPHORE ,
TRACE_CLASS_MUTEX
} ;
# if (TRC_CFG_SCHEDULING_ONLY == 0)
/*******************************************************************************
* vTraceSetQueueName ( void * object , const char * name )
*
* Parameter object : pointer to the Queue that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for Queue objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetQueueName ( void * object , const char * name )
{
prvTraceSetObjectName ( TRACE_CLASS_QUEUE , TRACE_GET_OBJECT_NUMBER ( QUEUE , object ) , name ) ;
}
/*******************************************************************************
* vTraceSetSemaphoreName ( void * object , const char * name )
*
* Parameter object : pointer to the Semaphore that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for Semaphore objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetSemaphoreName ( void * object , const char * name )
{
prvTraceSetObjectName ( TRACE_CLASS_SEMAPHORE , TRACE_GET_OBJECT_NUMBER ( QUEUE , object ) , name ) ;
}
/*******************************************************************************
* vTraceSetMutexName ( void * object , const char * name )
*
* Parameter object : pointer to the Mutex that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for Semaphore objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetMutexName ( void * object , const char * name )
{
prvTraceSetObjectName ( TRACE_CLASS_MUTEX , TRACE_GET_OBJECT_NUMBER ( QUEUE , object ) , name ) ;
}
# if (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X)
/*******************************************************************************
* vTraceSetEventGroupName ( void * object , const char * name )
*
* Parameter object : pointer to the EventGroup that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for EventGroup objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetEventGroupName ( void * object , const char * name )
{
prvTraceSetObjectName ( TRACE_CLASS_EVENTGROUP , TRACE_GET_OBJECT_NUMBER ( EVENTGROUP , object ) , name ) ;
}
# endif /* (TRC_CFG_INCLUDE_EVENT_GROUP_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_8_X) */
# if (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0)
/*******************************************************************************
* vTraceSetStreamBufferName ( void * object , const char * name )
*
* Parameter object : pointer to the StreamBuffer that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for StreamBuffer objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetStreamBufferName ( void * object , const char * name )
{
prvTraceSetObjectName ( TRACE_CLASS_STREAMBUFFER , TRACE_GET_OBJECT_NUMBER ( STREAMBUFFER , object ) , name ) ;
}
/*******************************************************************************
* vTraceSetMessageBufferName ( void * object , const char * name )
*
* Parameter object : pointer to the MessageBuffer that shall be named
* Parameter name : the name to set ( const string literal )
*
* Sets a name for MessageBuffer objects for display in Tracealyzer .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
void vTraceSetMessageBufferName ( void * object , const char * name )
{
prvTraceSetObjectName ( TRACE_CLASS_MESSAGEBUFFER , TRACE_GET_OBJECT_NUMBER ( STREAMBUFFER , object ) , name ) ;
}
# endif /* (TRC_CFG_INCLUDE_STREAM_BUFFER_EVENTS == 1 && TRC_CFG_FREERTOS_VERSION >= TRC_FREERTOS_VERSION_10_0_0) */
# endif /* (TRC_CFG_SCHEDULING_ONLY == 0) */
void * prvTraceGetCurrentTaskHandle ( )
{
return xTaskGetCurrentTaskHandle ( ) ;
}
/* Initialization of the object property table */
void vTraceInitObjectPropertyTable ( )
{
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectClasses = TRACE_NCLASSES ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 0 ] = TRC_CFG_NQUEUE ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 1 ] = TRC_CFG_NSEMAPHORE ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 2 ] = TRC_CFG_NMUTEX ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 3 ] = TRC_CFG_NTASK ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 4 ] = TRC_CFG_NISR ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 5 ] = TRC_CFG_NTIMER ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 6 ] = TRC_CFG_NEVENTGROUP ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 7 ] = TRC_CFG_NSTREAMBUFFER ;
RecorderDataPtr - > ObjectPropertyTable . NumberOfObjectsPerClass [ 8 ] = TRC_CFG_NMESSAGEBUFFER ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 0 ] = TRC_CFG_NAME_LEN_QUEUE ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 1 ] = TRC_CFG_NAME_LEN_SEMAPHORE ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 2 ] = TRC_CFG_NAME_LEN_MUTEX ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 3 ] = TRC_CFG_NAME_LEN_TASK ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 4 ] = TRC_CFG_NAME_LEN_ISR ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 5 ] = TRC_CFG_NAME_LEN_TIMER ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 6 ] = TRC_CFG_NAME_LEN_EVENTGROUP ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 7 ] = TRC_CFG_NAME_LEN_STREAMBUFFER ;
RecorderDataPtr - > ObjectPropertyTable . NameLengthPerClass [ 8 ] = TRC_CFG_NAME_LEN_MESSAGEBUFFER ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 0 ] = PropertyTableSizeQueue ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 1 ] = PropertyTableSizeSemaphore ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 2 ] = PropertyTableSizeMutex ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 3 ] = PropertyTableSizeTask ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 4 ] = PropertyTableSizeISR ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 5 ] = PropertyTableSizeTimer ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 6 ] = PropertyTableSizeEventGroup ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 7 ] = PropertyTableSizeStreamBuffer ;
RecorderDataPtr - > ObjectPropertyTable . TotalPropertyBytesPerClass [ 8 ] = PropertyTableSizeMessageBuffer ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 0 ] = StartIndexQueue ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 1 ] = StartIndexSemaphore ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 2 ] = StartIndexMutex ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 3 ] = StartIndexTask ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 4 ] = StartIndexISR ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 5 ] = StartIndexTimer ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 6 ] = StartIndexEventGroup ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 7 ] = StartIndexStreamBuffer ;
RecorderDataPtr - > ObjectPropertyTable . StartIndexOfClass [ 8 ] = StartIndexMessageBuffer ;
RecorderDataPtr - > ObjectPropertyTable . ObjectPropertyTableSizeInBytes = TRACE_OBJECT_TABLE_SIZE ;
}
/* Initialization of the handle mechanism, see e.g, prvTraceGetObjectHandle */
void vTraceInitObjectHandleStack ( )
{
objectHandleStacks . indexOfNextAvailableHandle [ 0 ] = objectHandleStacks . lowestIndexOfClass [ 0 ] = 0 ;
objectHandleStacks . indexOfNextAvailableHandle [ 1 ] = objectHandleStacks . lowestIndexOfClass [ 1 ] = ( TRC_CFG_NQUEUE ) ;
objectHandleStacks . indexOfNextAvailableHandle [ 2 ] = objectHandleStacks . lowestIndexOfClass [ 2 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) ;
objectHandleStacks . indexOfNextAvailableHandle [ 3 ] = objectHandleStacks . lowestIndexOfClass [ 3 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) ;
objectHandleStacks . indexOfNextAvailableHandle [ 4 ] = objectHandleStacks . lowestIndexOfClass [ 4 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) ;
objectHandleStacks . indexOfNextAvailableHandle [ 5 ] = objectHandleStacks . lowestIndexOfClass [ 5 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) ;
objectHandleStacks . indexOfNextAvailableHandle [ 6 ] = objectHandleStacks . lowestIndexOfClass [ 6 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) + ( TRC_CFG_NTIMER ) ;
objectHandleStacks . indexOfNextAvailableHandle [ 7 ] = objectHandleStacks . lowestIndexOfClass [ 7 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) + ( TRC_CFG_NTIMER ) + ( TRC_CFG_NEVENTGROUP ) ;
objectHandleStacks . indexOfNextAvailableHandle [ 8 ] = objectHandleStacks . lowestIndexOfClass [ 8 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) + ( TRC_CFG_NTIMER ) + ( TRC_CFG_NEVENTGROUP ) + ( TRC_CFG_NSTREAMBUFFER ) ;
objectHandleStacks . highestIndexOfClass [ 0 ] = ( TRC_CFG_NQUEUE ) - 1 ;
objectHandleStacks . highestIndexOfClass [ 1 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) - 1 ;
objectHandleStacks . highestIndexOfClass [ 2 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) - 1 ;
objectHandleStacks . highestIndexOfClass [ 3 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) - 1 ;
objectHandleStacks . highestIndexOfClass [ 4 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) - 1 ;
objectHandleStacks . highestIndexOfClass [ 5 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) + ( TRC_CFG_NTIMER ) - 1 ;
objectHandleStacks . highestIndexOfClass [ 6 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) + ( TRC_CFG_NTIMER ) + ( TRC_CFG_NEVENTGROUP ) - 1 ;
objectHandleStacks . highestIndexOfClass [ 7 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) + ( TRC_CFG_NTIMER ) + ( TRC_CFG_NEVENTGROUP ) + ( TRC_CFG_NSTREAMBUFFER ) - 1 ;
objectHandleStacks . highestIndexOfClass [ 8 ] = ( TRC_CFG_NQUEUE ) + ( TRC_CFG_NSEMAPHORE ) + ( TRC_CFG_NMUTEX ) + ( TRC_CFG_NTASK ) + ( TRC_CFG_NISR ) + ( TRC_CFG_NTIMER ) + ( TRC_CFG_NEVENTGROUP ) + ( TRC_CFG_NSTREAMBUFFER ) + ( TRC_CFG_NMESSAGEBUFFER ) - 1 ;
}
/* Returns the "Not enough handles" error message for this object class */
const char * pszTraceGetErrorNotEnoughHandles ( traceObjectClass objectclass )
{
switch ( objectclass )
{
case TRACE_CLASS_TASK :
return " Not enough TASK handles - increase TRC_CFG_NTASK in trcSnapshotConfig.h " ;
case TRACE_CLASS_ISR :
return " Not enough ISR handles - increase TRC_CFG_NISR in trcSnapshotConfig.h " ;
case TRACE_CLASS_SEMAPHORE :
return " Not enough SEMAPHORE handles - increase TRC_CFG_NSEMAPHORE in trcSnapshotConfig.h " ;
case TRACE_CLASS_MUTEX :
return " Not enough MUTEX handles - increase TRC_CFG_NMUTEX in trcSnapshotConfig.h " ;
case TRACE_CLASS_QUEUE :
return " Not enough QUEUE handles - increase TRC_CFG_NQUEUE in trcSnapshotConfig.h " ;
case TRACE_CLASS_TIMER :
return " Not enough TIMER handles - increase TRC_CFG_NTIMER in trcSnapshotConfig.h " ;
case TRACE_CLASS_EVENTGROUP :
return " Not enough EVENTGROUP handles - increase TRC_CFG_NEVENTGROUP in trcSnapshotConfig.h " ;
case TRACE_CLASS_STREAMBUFFER :
return " Not enough STREAMBUFFER handles - increase TRC_CFG_NSTREAMBUFFER in trcSnapshotConfig.h " ;
case TRACE_CLASS_MESSAGEBUFFER :
return " Not enough MESSAGEBUFFER handles - increase TRC_CFG_NMESSAGEBUFFER in trcSnapshotConfig.h " ;
default :
return " pszTraceGetErrorHandles: Invalid objectclass! " ;
}
}
/*******************************************************************************
* prvTraceIsSchedulerSuspended
*
* Returns true if the RTOS scheduler currently is disabled , thus preventing any
* task - switches from occurring . Only called from vTraceStoreISREnd .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
unsigned char prvTraceIsSchedulerSuspended ( void )
{
/* Assumed to be available in FreeRTOS. According to the FreeRTOS docs,
INCLUDE_xTaskGetSchedulerState or configUSE_TIMERS must be set to 1 in
FreeRTOSConfig . h for this function to be available . */
return xTaskGetSchedulerState ( ) = = taskSCHEDULER_SUSPENDED ;
}
# endif
# endif /* Snapshot mode */
# endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/