You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
597 lines
15 KiB
C
597 lines
15 KiB
C
/*
|
|
* Trace Recorder for Tracealyzer v4.6.0
|
|
* Copyright 2021 Percepio AB
|
|
* www.percepio.com
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* The generic core of the trace recorder's streaming mode.
|
|
*/
|
|
|
|
#include <trcRecorder.h>
|
|
|
|
#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
|
|
|
|
#if (TRC_USE_TRACEALYZER_RECORDER == 1)
|
|
|
|
typedef struct TraceHeader
|
|
{
|
|
uint32_t uiPSF;
|
|
uint16_t uiVersion;
|
|
uint16_t uiPlatform;
|
|
uint32_t uiOptions;
|
|
uint32_t uiNumCores;
|
|
uint32_t isrTailchainingThreshold;
|
|
char platformCfg[8];
|
|
uint16_t uiPlatformCfgPatch;
|
|
uint8_t uiPlatformCfgMinor;
|
|
uint8_t uiPlatformCfgMajor;
|
|
} TraceHeader_t;
|
|
|
|
/* The data structure for commands (a bit overkill) */
|
|
typedef struct TraceCommandType_t
|
|
{
|
|
unsigned char cmdCode;
|
|
unsigned char param1;
|
|
unsigned char param2;
|
|
unsigned char param3;
|
|
unsigned char param4;
|
|
unsigned char param5;
|
|
unsigned char checksumLSB;
|
|
unsigned char checksumMSB;
|
|
} TraceCommand_t;
|
|
|
|
#ifndef TRC_CFG_RECORDER_DATA_INIT
|
|
#define TRC_CFG_RECORDER_DATA_INIT 1
|
|
#endif
|
|
|
|
/* Used to interpret the data format */
|
|
#define TRACE_FORMAT_VERSION ((uint16_t)0x000A)
|
|
|
|
/* Used to determine endian of data (big/little) */
|
|
#define TRACE_PSF_ENDIANESS_IDENTIFIER ((uint32_t)0x50534600)
|
|
|
|
#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC)
|
|
static TraceRecorderData_t xRecorderData TRC_CFG_RECORDER_DATA_ATTRIBUTE;
|
|
TraceRecorderData_t* pxTraceRecorderData = &xRecorderData;
|
|
#else
|
|
/* If using DYNAMIC or CUSTOM allocation */
|
|
TraceRecorderData_t* pxTraceRecorderData TRC_CFG_RECORDER_DATA_ATTRIBUTE;
|
|
#endif
|
|
|
|
static TraceHeader_t* pxHeader;
|
|
|
|
/*******************************************************************************
|
|
* RecorderInitialized
|
|
*
|
|
* Makes sure the recorder data is only initialized once.
|
|
*
|
|
* NOTE: RecorderInitialized is only initialized to 0 if
|
|
* TRC_CFG_RECORDER_DATA_INIT is non-zero.
|
|
* This will avoid issues where the recorder must be started before main(),
|
|
* which can lead to RecorderInitialized be cleared by late initialization after
|
|
* xTraceEnable(TRC_INIT) was called and assigned RecorderInitialized its'
|
|
* value.
|
|
******************************************************************************/
|
|
#if (TRC_CFG_RECORDER_DATA_INIT != 0)
|
|
uint32_t RecorderInitialized = 0;
|
|
#else /* (TRC_CFG_RECORDER_DATA_INIT != 0) */
|
|
uint32_t RecorderInitialized TRC_CFG_RECORDER_DATA_ATTRIBUTE;
|
|
#endif /* (TRC_CFG_RECORDER_DATA_INIT != 0) */
|
|
|
|
#if (TRC_EXTERNAL_BUFFERS == 0)
|
|
/* Stores the header information on Start */
|
|
static void prvTraceStoreHeader(void);
|
|
|
|
/* Store the Timestamp info */
|
|
static void prvTraceStoreTimestampInfo(void);
|
|
|
|
/* Stores the entry table on Start */
|
|
static void prvTraceStoreEntryTable(void);
|
|
|
|
#else /* (TRC_EXTERNAL_BUFFERS == 0) */
|
|
|
|
#define prvTraceStoreHeader()
|
|
#define prvTraceStoreTimestampInfo()
|
|
#define prvTraceStoreEntryTable()
|
|
|
|
#endif /* (TRC_EXTERNAL_BUFFERS == 0) */
|
|
|
|
/* Store start event. */
|
|
static void prvTraceStoreStartEvent(void);
|
|
|
|
/* Checks if the provided command is a valid command */
|
|
static int prvIsValidCommand(TraceCommand_t* cmd);
|
|
|
|
/* Executed the received command (Start or Stop) */
|
|
static void prvProcessCommand(TraceCommand_t* cmd);
|
|
|
|
/* Internal function for starting the recorder */
|
|
static void prvSetRecorderEnabled(void);
|
|
|
|
/* Internal function for stopping the recorder */
|
|
static void prvSetRecorderDisabled(void);
|
|
|
|
/******************************************************************************
|
|
* xTraceInitialize
|
|
*
|
|
* Initializes the recorder data.
|
|
* This function will be called by xTraceEnable(...).
|
|
* Only needs to be called manually if traced objects are created before the
|
|
* trace recorder can be enabled, at which point make sure to call this function
|
|
* as early as possible.
|
|
* See TRC_CFG_RECORDER_DATA_INIT in trcConfig.h.
|
|
******************************************************************************/
|
|
traceResult xTraceInitialize(void)
|
|
{
|
|
TRC_ASSERT_EQUAL_SIZE(TraceRecorderDataBuffer_t, TraceRecorderData_t);
|
|
|
|
if (RecorderInitialized != 0)
|
|
{
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC)
|
|
pxRecorderData = TRC_MALLOC(sizeof(TraceRecorderData_t));
|
|
#endif
|
|
|
|
/* These are set on init so they aren't overwritten by late initialization values. */
|
|
pxTraceRecorderData->uiSessionCounter = 0;
|
|
pxTraceRecorderData->uiRecorderEnabled = 0;
|
|
pxTraceRecorderData->uiTraceSystemState = TRC_STATE_IN_STARTUP;
|
|
|
|
#if (TRC_EXTERNAL_BUFFERS == 0)
|
|
if (xTraceHeaderInitialize(&pxTraceRecorderData->xHeaderBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceEntryTableInitialize(&pxTraceRecorderData->xEntryTableBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceTimestampInitialize(&pxTraceRecorderData->xTimestampBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
#endif
|
|
|
|
if (xTraceStackMonitorInitialize(&pxTraceRecorderData->xStackMonitorBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceStreamPortInitialize(&pxTraceRecorderData->xStreamPortBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceAssertInitialize(&pxTraceRecorderData->xAssertBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceDiagnosticsInitialize(&pxTraceRecorderData->xDiagnosticsBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceStaticBufferInitialize(&pxTraceRecorderData->xStaticBufferBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceEventInitialize(&pxTraceRecorderData->xEventDataBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTracePrintInitialize(&pxTraceRecorderData->xPrintBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceErrorInitialize(&pxTraceRecorderData->xErrorBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceISRInitialize(&pxTraceRecorderData->xISRInfoBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceTaskInitialize(&pxTraceRecorderData->xTaskInfoBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (xTraceKernelPortInitialize(&pxTraceRecorderData->xKernelPortBuffer) == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_CORE);
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
traceResult xTraceHeaderInitialize(TraceHeaderBuffer_t *pxBuffer)
|
|
{
|
|
uint32_t i;
|
|
char* platform_cfg = TRC_PLATFORM_CFG;
|
|
|
|
TRC_ASSERT_EQUAL_SIZE(TraceHeaderBuffer_t, TraceHeader_t);
|
|
|
|
if (pxBuffer == 0)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
pxHeader = (TraceHeader_t*)pxBuffer;
|
|
|
|
pxHeader->uiPSF = TRACE_PSF_ENDIANESS_IDENTIFIER;
|
|
pxHeader->uiVersion = TRACE_FORMAT_VERSION;
|
|
pxHeader->uiPlatform = TRACE_KERNEL_VERSION;
|
|
|
|
for (i = 0; i < TRC_PLATFORM_CFG_LENGTH; i++)
|
|
{
|
|
pxHeader->platformCfg[i] = platform_cfg[i];
|
|
if (platform_cfg[i] == 0)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
pxHeader->uiPlatformCfgPatch = TRC_PLATFORM_CFG_PATCH;
|
|
pxHeader->uiPlatformCfgMinor = TRC_PLATFORM_CFG_MINOR;
|
|
pxHeader->uiPlatformCfgMajor = TRC_PLATFORM_CFG_MAJOR;
|
|
pxHeader->uiNumCores = TRC_CFG_CORE_COUNT;
|
|
pxHeader->isrTailchainingThreshold = TRC_CFG_ISR_TAILCHAINING_THRESHOLD;
|
|
|
|
/* Lowest bit used for TRC_IRQ_PRIORITY_ORDER */
|
|
pxHeader->uiOptions = ((TRC_IRQ_PRIORITY_ORDER) << 0);
|
|
|
|
/* 3rd bit used for TRC_CFG_TEST_MODE */
|
|
pxHeader->uiOptions |= ((TRC_CFG_TEST_MODE) << 2);
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
traceResult xTraceEnable(uint32_t uiStartOption)
|
|
{
|
|
TraceCommand_t xCommand;
|
|
int32_t iBytes = 0;
|
|
|
|
if (xTraceInitialize() == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
xTraceStreamPortOnEnable(uiStartOption);
|
|
|
|
if (xTraceKernelPortEnable() == TRC_FAIL)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (uiStartOption == TRC_START_AWAIT_HOST)
|
|
{
|
|
/* We keep trying to read commands from host until the recorder has been started */
|
|
do
|
|
{
|
|
iBytes = 0;
|
|
|
|
if (xTraceStreamPortReadData(&xCommand, sizeof(TraceCommand_t), (int32_t*)&iBytes) == TRC_FAIL)
|
|
{
|
|
xTraceWarning(TRC_WARNING_STREAM_PORT_READ);
|
|
}
|
|
|
|
if (iBytes == sizeof(TraceCommand_t))
|
|
{
|
|
if (prvIsValidCommand(&xCommand))
|
|
{
|
|
if (xCommand.cmdCode == CMD_SET_ACTIVE && xCommand.param1 == 1)
|
|
{
|
|
/* On start, init and reset the timestamping */
|
|
TRC_PORT_SPECIFIC_INIT();
|
|
}
|
|
|
|
prvProcessCommand(&xCommand);
|
|
}
|
|
}
|
|
} while (pxTraceRecorderData->uiRecorderEnabled == 0);
|
|
}
|
|
else if (uiStartOption == TRC_START)
|
|
{
|
|
/* We start streaming directly - this assumes that the host interface is ready! */
|
|
TRC_PORT_SPECIFIC_INIT();
|
|
|
|
xCommand.cmdCode = CMD_SET_ACTIVE;
|
|
xCommand.param1 = 1;
|
|
prvProcessCommand(&xCommand);
|
|
}
|
|
else if (uiStartOption == TRC_START_FROM_HOST)
|
|
{
|
|
/* We prepare the system to receive commands from host, but let system resume execution until that happens */
|
|
TRC_PORT_SPECIFIC_INIT();
|
|
}
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
traceResult xTraceDisable(void)
|
|
{
|
|
prvSetRecorderDisabled();
|
|
|
|
xTraceStreamPortOnDisable();
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)
|
|
traceResult xTraceSetBuffer(TraceRecorderDataBuffer_t* pxBuffer)
|
|
{
|
|
if (pxBuffer == 0)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
pxTraceRecorderData = (TraceRecorderData_t*)pxBuffer;
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
#endif
|
|
|
|
traceResult xTraceGetEventBuffer(void **ppvBuffer, TraceUnsignedBaseType_t *puiSize)
|
|
{
|
|
if (pxTraceRecorderData == 0 || ppvBuffer == 0 || puiSize == 0)
|
|
{
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
/* Returns the xStreamPortBuffer since that is the one containing trace data */
|
|
*ppvBuffer = (void*)&pxTraceRecorderData->xStreamPortBuffer;
|
|
*puiSize = sizeof(pxTraceRecorderData->xStreamPortBuffer);
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
traceResult xTraceTzCtrl(void)
|
|
{
|
|
TraceCommand_t xCommand;
|
|
int32_t iBytes = 0;
|
|
|
|
do
|
|
{
|
|
/* Listen for new commands */
|
|
iBytes = 0;
|
|
if (xTraceStreamPortReadData(&xCommand, sizeof(TraceCommand_t), &iBytes) == TRC_FAIL)
|
|
{
|
|
/* The connection has failed, stop tracing */
|
|
xTraceDisable();
|
|
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
if (iBytes == sizeof(TraceCommand_t))
|
|
{
|
|
if (prvIsValidCommand(&xCommand))
|
|
{
|
|
prvProcessCommand(&xCommand); /* Start or Stop currently... */
|
|
}
|
|
}
|
|
|
|
#if (TRC_USE_INTERNAL_BUFFER == 1)
|
|
xTraceInternalEventBufferTransfer(&iBytes);
|
|
#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 (iBytes != 0);
|
|
|
|
if (xTraceIsRecorderEnabled())
|
|
{
|
|
xTraceDiagnosticsCheckStatus();
|
|
xTraceStackMonitorReport();
|
|
}
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
void vTraceSetFilterGroup(uint16_t filterGroup)
|
|
{
|
|
(void)filterGroup;
|
|
}
|
|
|
|
void vTraceSetFilterMask(uint16_t filterMask)
|
|
{
|
|
(void)filterMask;
|
|
}
|
|
|
|
/******************************************************************************/
|
|
/*** INTERNAL FUNCTIONS *******************************************************/
|
|
/******************************************************************************/
|
|
/* Internal function for starting/stopping the recorder. */
|
|
static void prvSetRecorderEnabled(void)
|
|
{
|
|
uint32_t timestampFrequency = 0;
|
|
|
|
TRACE_ALLOC_CRITICAL_SECTION();
|
|
|
|
if (pxTraceRecorderData->uiRecorderEnabled == 1)
|
|
{
|
|
return;
|
|
}
|
|
|
|
xTraceTimestampGetFrequency(×tampFrequency);
|
|
/* If not overridden using xTraceTimestampSetFrequency(...), use default value */
|
|
if (timestampFrequency == 0)
|
|
{
|
|
timestampFrequency = TRC_HWTC_FREQ_HZ;
|
|
xTraceTimestampSetFrequency(timestampFrequency);
|
|
}
|
|
|
|
TRACE_ENTER_CRITICAL_SECTION();
|
|
|
|
/* If the internal event buffer is used, we must clear it */
|
|
xTraceInternalEventBufferClear();
|
|
|
|
xTraceStreamPortOnTraceBegin();
|
|
|
|
prvTraceStoreHeader();
|
|
prvTraceStoreTimestampInfo();
|
|
prvTraceStoreEntryTable();
|
|
prvTraceStoreStartEvent();
|
|
|
|
pxTraceRecorderData->uiSessionCounter++;
|
|
|
|
pxTraceRecorderData->uiRecorderEnabled = 1;
|
|
|
|
TRACE_EXIT_CRITICAL_SECTION();
|
|
}
|
|
|
|
static void prvSetRecorderDisabled(void)
|
|
{
|
|
TRACE_ALLOC_CRITICAL_SECTION();
|
|
|
|
if (pxTraceRecorderData->uiRecorderEnabled == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
TRACE_ENTER_CRITICAL_SECTION();
|
|
|
|
pxTraceRecorderData->uiRecorderEnabled = 0;
|
|
|
|
xTraceStreamPortOnTraceEnd();
|
|
|
|
TRACE_EXIT_CRITICAL_SECTION();
|
|
}
|
|
|
|
#if (TRC_EXTERNAL_BUFFERS == 0)
|
|
/* Stores the header information on Start */
|
|
static void prvTraceStoreHeader(void)
|
|
{
|
|
TraceEventHandle_t xEventHandle;
|
|
|
|
if (xTraceEventBeginRawOfflineBlocking(sizeof(TraceHeader_t), &xEventHandle) == TRC_SUCCESS)
|
|
{
|
|
xTraceEventAddData(xEventHandle, pxHeader, sizeof(TraceHeader_t));
|
|
xTraceEventEndOfflineBlocking(xEventHandle);
|
|
}
|
|
}
|
|
|
|
/* Store the Timestamp */
|
|
static void prvTraceStoreTimestampInfo(void)
|
|
{
|
|
TraceEventHandle_t xEventHandle;
|
|
uint32_t timestampFrequency = 0;
|
|
|
|
xTraceTimestampGetFrequency(×tampFrequency);
|
|
|
|
if (xTraceEventBeginRawOfflineBlocking(sizeof(TraceTimestampBuffer_t), &xEventHandle) == TRC_SUCCESS)
|
|
{
|
|
xTraceEventAddData(xEventHandle, &pxTraceRecorderData->xTimestampBuffer, sizeof(TraceTimestampBuffer_t));
|
|
xTraceEventEndOfflineBlocking(xEventHandle);
|
|
}
|
|
}
|
|
|
|
/* Stores the entry table on Start */
|
|
static void prvTraceStoreEntryTable(void)
|
|
{
|
|
uint32_t i = 0;
|
|
TraceEventHandle_t xEventHandle;
|
|
TraceEntryHandle_t xEntryHandle;
|
|
uint32_t uiEntryCount;
|
|
void *pvEntryAddress;
|
|
|
|
xTraceEntryGetCount(&uiEntryCount);
|
|
|
|
if (xTraceEventBeginRawOfflineBlocking(sizeof(uint32_t) + sizeof(uint32_t) + sizeof(uint32_t), &xEventHandle) == TRC_SUCCESS)
|
|
{
|
|
xTraceEventAdd32(xEventHandle, uiEntryCount);
|
|
xTraceEventAdd32(xEventHandle, TRC_ENTRY_TABLE_SLOT_SYMBOL_SIZE);
|
|
xTraceEventAdd32(xEventHandle, TRC_ENTRY_TABLE_STATE_COUNT);
|
|
xTraceEventEndOfflineBlocking(xEventHandle);
|
|
}
|
|
|
|
for (i = 0; i < (TRC_ENTRY_TABLE_SLOTS); i++)
|
|
{
|
|
xTraceEntryGetAtIndex(i, &xEntryHandle);
|
|
xTraceEntryGetAddress(xEntryHandle, &pvEntryAddress);
|
|
/* We only send used entry slots */
|
|
if (pvEntryAddress != 0)
|
|
{
|
|
/* Send entry */
|
|
if (xTraceEventBeginRawOfflineBlocking(sizeof(TraceEntry_t), &xEventHandle) == TRC_SUCCESS)
|
|
{
|
|
xTraceEventAddData(xEventHandle, (void*)xEntryHandle, sizeof(TraceEntry_t));
|
|
xTraceEventEndOfflineBlocking(xEventHandle);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#endif /* (TRC_EXTERNAL_BUFFERS == 0) */
|
|
|
|
static void prvTraceStoreStartEvent()
|
|
{
|
|
TraceEventHandle_t xEventHandle;
|
|
void* pvCurrentTask;
|
|
|
|
xTraceTaskGetCurrent(&pvCurrentTask);
|
|
|
|
if (xTraceEventBeginOffline(PSF_EVENT_TRACE_START, sizeof(uint32_t), &xEventHandle) == TRC_SUCCESS)
|
|
{
|
|
xTraceEventAdd32(xEventHandle, (uint32_t)pvCurrentTask);
|
|
xTraceEventEndOffline(xEventHandle);
|
|
}
|
|
}
|
|
|
|
/* Checks if the provided command is a valid command */
|
|
static int prvIsValidCommand(TraceCommand_t* cmd)
|
|
{
|
|
uint16_t checksum = (uint16_t)(0xFFFF - ( cmd->cmdCode +
|
|
cmd->param1 +
|
|
cmd->param2 +
|
|
cmd->param3 +
|
|
cmd->param4 +
|
|
cmd->param5));
|
|
|
|
if (cmd->checksumMSB != (unsigned char)(checksum >> 8))
|
|
return 0;
|
|
|
|
if (cmd->checksumLSB != (unsigned char)(checksum & 0xFF))
|
|
return 0;
|
|
|
|
if (cmd->cmdCode > CMD_LAST_COMMAND)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Executed the received command (Start or Stop) */
|
|
static void prvProcessCommand(TraceCommand_t* cmd)
|
|
{
|
|
switch(cmd->cmdCode)
|
|
{
|
|
case CMD_SET_ACTIVE:
|
|
if (cmd->param1 == 1)
|
|
{
|
|
prvSetRecorderEnabled();
|
|
}
|
|
else
|
|
{
|
|
prvSetRecorderDisabled();
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
#endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
|
|
|
|
#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
|