mirror of
https://github.com/FreeRTOS/FreeRTOS-Kernel.git
synced 2025-10-14 00:37:44 -04:00
* Use new version of CI-CD Actions, checkout@v3 instead of checkout@v2 on all jobs * Use cSpell spell check, and use ubuntu-20.04 for formatting check * Add in bot formatting action * Update freertos_demo.yml and freertos_plus_demo.yml files to increase github log readability * Add in a Qemu demo onto the workflows.
260 lines
9.6 KiB
C
260 lines
9.6 KiB
C
/*
|
|
* Percepio Trace Recorder for Tracealyzer v4.6.0
|
|
* Copyright 2021 Percepio AB
|
|
* www.percepio.com
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
* The implementation for the event buffer.
|
|
*/
|
|
|
|
#include <trcRecorder.h>
|
|
|
|
#if ( TRC_USE_TRACEALYZER_RECORDER == 1 )
|
|
|
|
#if ( TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING )
|
|
|
|
traceResult xTraceEventBufferInitialize( TraceEventBuffer_t * pxTraceEventBuffer,
|
|
uint32_t uiOptions,
|
|
uint8_t * puiBuffer,
|
|
uint32_t uiSize )
|
|
{
|
|
/* This should never fail */
|
|
TRC_ASSERT( pxTraceEventBuffer != 0 );
|
|
|
|
/* This should never fail */
|
|
TRC_ASSERT( puiBuffer != 0 );
|
|
|
|
pxTraceEventBuffer->uiOptions = uiOptions;
|
|
pxTraceEventBuffer->uiHead = 0;
|
|
pxTraceEventBuffer->uiTail = 0;
|
|
pxTraceEventBuffer->uiSize = uiSize;
|
|
pxTraceEventBuffer->uiFree = uiSize;
|
|
pxTraceEventBuffer->puiBuffer = puiBuffer;
|
|
pxTraceEventBuffer->uiTimerWraparounds = 0;
|
|
|
|
xTraceSetComponentInitialized( TRC_RECORDER_COMPONENT_EVENT_BUFFER );
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
/**
|
|
* @brief Pops the oldest event from the Event Buffer.
|
|
*
|
|
* @param[in] pxTraceEventBuffer Pointer to initialized trace event buffer.
|
|
*
|
|
* @retval TRC_FAIL Failure
|
|
* @retval TRC_SUCCESS Success
|
|
*/
|
|
static traceResult prvTraceEventBufferPop( TraceEventBuffer_t * pxTraceEventBuffer )
|
|
{
|
|
uint32_t uiFreeSize = 0;
|
|
|
|
/* Get size of event we are freeing */
|
|
/* This should never fail */
|
|
TRC_ASSERT_ALWAYS_EVALUATE( xTraceEventGetSize( ( ( void * ) &( pxTraceEventBuffer->puiBuffer[ pxTraceEventBuffer->uiTail ] ) ), &uiFreeSize ) == TRC_SUCCESS );
|
|
|
|
pxTraceEventBuffer->uiFree += uiFreeSize;
|
|
|
|
/* Update tail to point to the new last event */
|
|
pxTraceEventBuffer->uiTail = ( pxTraceEventBuffer->uiTail + uiFreeSize ) % pxTraceEventBuffer->uiSize;
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
traceResult xTraceEventBufferPush( TraceEventBuffer_t * pxTraceEventBuffer,
|
|
void * pxData,
|
|
uint32_t uiDataSize,
|
|
int32_t * piBytesWritten )
|
|
{
|
|
uint32_t uiBufferSize;
|
|
|
|
/* This should never fail */
|
|
TRC_ASSERT( pxTraceEventBuffer != 0 );
|
|
|
|
/* This should never fail */
|
|
TRC_ASSERT( pxData != 0 );
|
|
|
|
uiBufferSize = pxTraceEventBuffer->uiSize;
|
|
|
|
/* Check if the data size is larger than the buffer */
|
|
/* This should never fail */
|
|
TRC_ASSERT( uiDataSize <= uiBufferSize );
|
|
|
|
/* Check byte alignment */
|
|
/* This should never fail */
|
|
TRC_ASSERT( ( uiDataSize % 4 ) == 0 );
|
|
|
|
/* Ensure bytes written start at 0 */
|
|
/* This should never fail */
|
|
TRC_ASSERT( piBytesWritten != 0 );
|
|
|
|
*piBytesWritten = 0;
|
|
|
|
/* This should never fail */
|
|
TRC_ASSERT_ALWAYS_EVALUATE( xTraceTimestampGetWraparounds( &pxTraceEventBuffer->uiTimerWraparounds ) == TRC_SUCCESS );
|
|
|
|
/* In ring buffer mode we cannot provide lock free access since the producer modified
|
|
* the head and tail variables in the same call. This option is only safe when used
|
|
* with an internal buffer (streaming snapshot) which no consumer accesses.
|
|
*/
|
|
switch( pxTraceEventBuffer->uiOptions )
|
|
{
|
|
case TRC_EVENT_BUFFER_OPTION_OVERWRITE:
|
|
{
|
|
uint32_t uiHead = pxTraceEventBuffer->uiHead;
|
|
|
|
/* If there isn't enough space in the buffer pop events until there is */
|
|
while( pxTraceEventBuffer->uiFree < uiDataSize )
|
|
{
|
|
prvTraceEventBufferPop( pxTraceEventBuffer );
|
|
}
|
|
|
|
/* Copy data */
|
|
if( ( uiBufferSize - uiHead ) > uiDataSize )
|
|
{
|
|
TRC_MEMCPY( &pxTraceEventBuffer->puiBuffer[ uiHead ], pxData, uiDataSize );
|
|
}
|
|
else
|
|
{
|
|
TRC_MEMCPY( &pxTraceEventBuffer->puiBuffer[ uiHead ], pxData, uiBufferSize - uiHead );
|
|
TRC_MEMCPY( pxTraceEventBuffer->puiBuffer,
|
|
( void * ) ( &( ( uint8_t * ) pxData )[ ( uiBufferSize - uiHead ) ] ),
|
|
uiDataSize - ( uiBufferSize - uiHead ) );
|
|
}
|
|
|
|
pxTraceEventBuffer->uiFree -= uiDataSize;
|
|
|
|
pxTraceEventBuffer->uiHead = ( uiHead + uiDataSize ) % uiBufferSize;
|
|
|
|
*piBytesWritten = uiDataSize;
|
|
|
|
break;
|
|
}
|
|
|
|
case TRC_EVENT_BUFFER_OPTION_SKIP:
|
|
{
|
|
/* Since a consumer could potentially update tail (free) during the procedure
|
|
* we have to save it here to avoid problems with the push algorithm.
|
|
*/
|
|
uint32_t uiHead = pxTraceEventBuffer->uiHead;
|
|
uint32_t uiTail = pxTraceEventBuffer->uiTail;
|
|
|
|
if( uiHead >= uiTail )
|
|
{
|
|
uint32_t uiFreeSpace = ( uiBufferSize - uiHead - sizeof( uint32_t ) ) + uiTail;
|
|
|
|
if( uiFreeSpace < uiDataSize )
|
|
{
|
|
*piBytesWritten = 0;
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
/* Copy data */
|
|
if( ( uiBufferSize - uiHead ) > uiDataSize )
|
|
{
|
|
TRC_MEMCPY( &pxTraceEventBuffer->puiBuffer[ pxTraceEventBuffer->uiHead ], pxData, uiDataSize );
|
|
}
|
|
else
|
|
{
|
|
TRC_MEMCPY( &pxTraceEventBuffer->puiBuffer[ uiHead ], pxData, uiBufferSize - uiHead );
|
|
TRC_MEMCPY( pxTraceEventBuffer->puiBuffer,
|
|
( void * ) ( &( ( uint8_t * ) pxData )[ ( uiBufferSize - uiHead ) ] ),
|
|
uiDataSize - ( uiBufferSize - uiHead ) );
|
|
}
|
|
|
|
pxTraceEventBuffer->uiHead = ( uiHead + uiDataSize ) % uiBufferSize;
|
|
}
|
|
else
|
|
{
|
|
uint32_t uiFreeSpace = uiTail - uiHead - sizeof( uint32_t );
|
|
|
|
if( uiFreeSpace < uiDataSize )
|
|
{
|
|
*piBytesWritten = 0;
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
/* Copy data */
|
|
TRC_MEMCPY( &pxTraceEventBuffer->puiBuffer[ pxTraceEventBuffer->uiHead ], pxData, uiDataSize );
|
|
|
|
pxTraceEventBuffer->uiHead = ( uiHead + uiDataSize );
|
|
}
|
|
|
|
*piBytesWritten = uiDataSize;
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
return TRC_FAIL;
|
|
}
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
traceResult xTraceEventBufferTransfer( TraceEventBuffer_t * pxTraceEventBuffer,
|
|
int32_t * piBytesWritten )
|
|
{
|
|
int32_t iBytesWritten = 0;
|
|
int32_t iSumBytesWritten = 0;
|
|
uint32_t uiHead;
|
|
uint32_t uiTail;
|
|
|
|
/* This should never fail */
|
|
TRC_ASSERT( pxTraceEventBuffer != 0 );
|
|
|
|
/* This should never fail */
|
|
TRC_ASSERT( piBytesWritten != 0 );
|
|
|
|
uiHead = pxTraceEventBuffer->uiHead;
|
|
uiTail = pxTraceEventBuffer->uiTail;
|
|
|
|
/* Check if core event buffer is empty */
|
|
if( uiHead == uiTail )
|
|
{
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
/* Check if we can do a direct write or if we have to handle wrapping */
|
|
if( uiHead > uiTail )
|
|
{
|
|
xTraceStreamPortWriteData( &pxTraceEventBuffer->puiBuffer[ uiTail ], ( uiHead - uiTail ), &iBytesWritten );
|
|
|
|
pxTraceEventBuffer->uiTail = uiHead;
|
|
}
|
|
else
|
|
{
|
|
xTraceStreamPortWriteData( &pxTraceEventBuffer->puiBuffer[ uiTail ], ( pxTraceEventBuffer->uiSize - uiTail ), &iBytesWritten );
|
|
|
|
iSumBytesWritten += iBytesWritten;
|
|
|
|
xTraceStreamPortWriteData( pxTraceEventBuffer->puiBuffer, uiHead, &iBytesWritten );
|
|
|
|
pxTraceEventBuffer->uiTail = uiHead;
|
|
}
|
|
|
|
iSumBytesWritten += iBytesWritten;
|
|
|
|
*piBytesWritten = iSumBytesWritten;
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
traceResult xTraceEventBufferClear( TraceEventBuffer_t * pxTraceEventBuffer )
|
|
{
|
|
/* This should never fail */
|
|
TRC_ASSERT( pxTraceEventBuffer != 0 );
|
|
|
|
pxTraceEventBuffer->uiHead = 0;
|
|
pxTraceEventBuffer->uiTail = 0;
|
|
pxTraceEventBuffer->uiFree = pxTraceEventBuffer->uiSize;
|
|
|
|
return TRC_SUCCESS;
|
|
}
|
|
|
|
#endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */
|
|
|
|
#endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
|