/* * Percepio Trace Recorder for Tracealyzer v4.6.6 * Copyright 2021 Percepio AB * www.percepio.com * * SPDX-License-Identifier: Apache-2.0 * * The implementation for the event buffer. */ #include #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) { /* No wrapping */ xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (uiHead - uiTail), &iBytesWritten); } else { /* Wrapping */ xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[uiTail], (pxTraceEventBuffer->uiSize - uiTail), &iBytesWritten); if (iBytesWritten == (int32_t)(pxTraceEventBuffer->uiSize - uiTail)) { /* Everything written, do the rest as well */ /* uiTail is moved to start of buffer */ pxTraceEventBuffer->uiTail = 0; iSumBytesWritten += iBytesWritten; iBytesWritten = 0; xTraceStreamPortWriteData(&pxTraceEventBuffer->puiBuffer[0], uiHead, &iBytesWritten); } } /* Move tail */ pxTraceEventBuffer->uiTail += iBytesWritten; 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) */