/******************************************************************************* * Trace Recorder Library for Tracealyzer v3.0.2 * Percepio AB, www.percepio.com * * trcPagedEventBuffer.c * * Implements a paged buffer that can be used by TCP/IP or custom transfer * methods. * * Terms of Use * This software (the "Tracealyzer Recorder Library") is the intellectual * property of Percepio AB and may not be sold or in other ways commercially * redistributed without explicit written permission by Percepio AB. * * Separate conditions applies for the SEGGER branded source code included. * * The recorder library is free for use together with Percepio products. * You may distribute the recorder library in its original form, but public * distribution of modified versions require approval by Percepio AB. * * Disclaimer * The trace tool and recorder library is being delivered to you AS IS and * Percepio AB makes no warranty as to its use or performance. Percepio AB does * not and cannot warrant the performance or results you may obtain by using the * software or documentation. Percepio AB 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 AB, 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 AB 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, 2015. * www.percepio.com ******************************************************************************/ #include #include #include #include "trcConfig.h" #include "trcPagedEventBuffer.h" #include "trcPagedEventBufferConfig.h" #include "trcKernelPort.h" uint32_t DroppedEventCounter = 0; // Total number of dropped events (failed allocations) uint32_t TotalBytesRemaining_LowWaterMark = TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE; #if (USE_TRACEALYZER_RECORDER == 1) #define PAGE_STATUS_FREE 0 #define PAGE_STATUS_WRITE 1 #define PAGE_STATUS_READ 2 uint32_t TotalBytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE; typedef struct{ uint8_t Status; uint16_t BytesRemaining; char* WritePointer; } PageType; PageType PageInfo[TRC_PAGED_EVENT_BUFFER_PAGE_COUNT]; char* EventBuffer = NULL; static void prvPageReadComplete(int pageIndex); static int prvAllocateBufferPage(int prevPage); static int prvAllocateBufferPage(int prevPage) { int index; int count = 0; index = (prevPage + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT; while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT)) { index = (index + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT; } if (PageInfo[index].Status == PAGE_STATUS_FREE) { return index; } return -1; } static void prvPageReadComplete(int pageIndex) { TRACE_ALLOC_CRITICAL_SECTION(); TRACE_ENTER_CRITICAL_SECTION(); PageInfo[pageIndex].BytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE; PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE]; PageInfo[pageIndex].Status = PAGE_STATUS_FREE; TotalBytesRemaining += TRC_PAGED_EVENT_BUFFER_PAGE_SIZE; TRACE_EXIT_CRITICAL_SECTION(); } static int prvGetBufferPage(int32_t* bytesUsed) { static int8_t lastPage = -1; int count = 0; int8_t index = (lastPage + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT; while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT)) { index = (index + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT; } if (PageInfo[index].Status == PAGE_STATUS_READ) { *bytesUsed = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE - PageInfo[index].BytesRemaining; lastPage = index; return index; } *bytesUsed = 0; return -1; } /******************************************************************************* int32_t vPagedEventBufferTransfer(int32_t (*writeFunc)(void* data, uint32_t size), int32_t* nofBytes) Transfers one block of trace data, if available for reading. Returns the number of bytes transfered, or a negative error code. If data was transferred (return value > 0), it can be good to call this function again until all data available has been transfered. This function is intended to be called by a periodic task with a suitable delay (e.g. 10-100 ms). Example: TickType_t lastWakeTime = xTaskGetTickCount(); while(1) { do{ // Transfer all available data status = vPagedEventBufferTransfer(MyWrite, ptrBytes); }while(status > 0); if (status < 0) { // A negative return value is an error code... } vTraceDelayUntil(lastWakeTime, 50); // 50 ms -> 20 times/sec } Return value: returnvalue of writeFunc (0 == OK) Parameters: - writeFunc Function pointer (example: int32_t write(void* data, uint32_t size)) The function passed as writeFunc should write "size" bytes from "data" to the socket/file/channel, and return a status code where 0 means OK, and any other non-zero value means an error. - int32_t* nofBytes Pointer to an integer assigned the number of bytes that was transfered. *******************************************************************************/ int32_t vPagedEventBufferTransfer(int32_t (*writeFunc)(void* data, uint32_t size, int32_t* ptrBytesWritten), int32_t* nofBytes) { static int firstTime = 1; int8_t pageToTransfer = -1; pageToTransfer = prvGetBufferPage(nofBytes); if (firstTime) { firstTime = 0; } if (pageToTransfer > -1) { if (writeFunc(&EventBuffer[pageToTransfer * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE], *nofBytes, nofBytes) == 0) { prvPageReadComplete(pageToTransfer); return 0; } else { return 1; } } return 0; } /******************************************************************************* void* vPagedEventBufferGetWritePointer(int sizeOfEvent) Returns a pointer to an available location in the buffer able to store the requested size. Return value: The pointer. Parameters: - sizeOfEvent The size of the event that is to be placed in the buffer. *******************************************************************************/ void* vPagedEventBufferGetWritePointer(int sizeOfEvent) { void* ret; static int currentWritePage = -1; if (currentWritePage == -1) { currentWritePage = prvAllocateBufferPage(currentWritePage); if (currentWritePage == -1) { DroppedEventCounter++; return NULL; } } if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0) { PageInfo[currentWritePage].Status = PAGE_STATUS_READ; TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark) TotalBytesRemaining_LowWaterMark = TotalBytesRemaining; currentWritePage = prvAllocateBufferPage(currentWritePage); if (currentWritePage == -1) { DroppedEventCounter++; return NULL; } } ret = PageInfo[currentWritePage].WritePointer; PageInfo[currentWritePage].WritePointer += sizeOfEvent; PageInfo[currentWritePage].BytesRemaining -= sizeOfEvent; TotalBytesRemaining -= sizeOfEvent; if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark) TotalBytesRemaining_LowWaterMark = TotalBytesRemaining; return ret; } /******************************************************************************* void vPagedEventBufferInit(char* buffer) Assigns the buffer to use and initializes the PageInfo structure. Return value: void Parameters: - buffer Pointer to the buffer location that is dynamically or statically allocated by the caller. *******************************************************************************/ void vPagedEventBufferInit(char* buffer) { TRACE_ALLOC_CRITICAL_SECTION(); int i; EventBuffer = buffer; TRACE_ENTER_CRITICAL_SECTION(); for (i = 0; i < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT; i++) { PageInfo[i].BytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE; PageInfo[i].WritePointer = &EventBuffer[i * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE]; PageInfo[i].Status = PAGE_STATUS_FREE; } TRACE_EXIT_CRITICAL_SECTION(); } #endif