/******************************************************************************* | |
* 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)*/ |