1 /*******************************************************************************
\r
2 * Trace Recorder Library for Tracealyzer v3.0.2
\r
3 * Percepio AB, www.percepio.com
\r
5 * trcPagedEventBuffer.c
\r
7 * Implements a paged buffer that can be used by TCP/IP or custom transfer
\r
11 * This software (the "Tracealyzer Recorder Library") is the intellectual
\r
12 * property of Percepio AB and may not be sold or in other ways commercially
\r
13 * redistributed without explicit written permission by Percepio AB.
\r
15 * Separate conditions applies for the SEGGER branded source code included.
\r
17 * The recorder library is free for use together with Percepio products.
\r
18 * You may distribute the recorder library in its original form, but public
\r
19 * distribution of modified versions require approval by Percepio AB.
\r
22 * The trace tool and recorder library is being delivered to you AS IS and
\r
23 * Percepio AB makes no warranty as to its use or performance. Percepio AB does
\r
24 * not and cannot warrant the performance or results you may obtain by using the
\r
25 * software or documentation. Percepio AB make no warranties, express or
\r
26 * implied, as to noninfringement of third party rights, merchantability, or
\r
27 * fitness for any particular purpose. In no event will Percepio AB, its
\r
28 * technology partners, or distributors be liable to you for any consequential,
\r
29 * incidental or special damages, including any lost profits or lost savings,
\r
30 * even if a representative of Percepio AB has been advised of the possibility
\r
31 * of such damages, or for any claim by any third party. Some jurisdictions do
\r
32 * not allow the exclusion or limitation of incidental, consequential or special
\r
33 * damages, or the exclusion of implied warranties or limitations on how long an
\r
34 * implied warranty may last, so the above limitations may not apply to you.
\r
36 * Tabs are used for indent in this file (1 tab = 4 spaces)
\r
38 * Copyright Percepio AB, 2015.
\r
40 ******************************************************************************/
\r
46 #include "trcConfig.h"
\r
47 #include "trcPagedEventBuffer.h"
\r
48 #include "trcPagedEventBufferConfig.h"
\r
49 #include "trcKernelPort.h"
\r
51 uint32_t DroppedEventCounter = 0; // Total number of dropped events (failed allocations)
\r
52 uint32_t TotalBytesRemaining_LowWaterMark = TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
54 #if (USE_TRACEALYZER_RECORDER == 1)
\r
56 #define PAGE_STATUS_FREE 0
\r
57 #define PAGE_STATUS_WRITE 1
\r
58 #define PAGE_STATUS_READ 2
\r
60 uint32_t TotalBytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
64 uint16_t BytesRemaining;
\r
68 PageType PageInfo[TRC_PAGED_EVENT_BUFFER_PAGE_COUNT];
\r
70 char* EventBuffer = NULL;
\r
72 static void prvPageReadComplete(int pageIndex);
\r
73 static int prvAllocateBufferPage(int prevPage);
\r
75 static int prvAllocateBufferPage(int prevPage)
\r
80 index = (prevPage + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;
\r
82 while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT))
\r
84 index = (index + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;
\r
87 if (PageInfo[index].Status == PAGE_STATUS_FREE)
\r
95 static void prvPageReadComplete(int pageIndex)
\r
97 TRACE_ALLOC_CRITICAL_SECTION();
\r
99 TRACE_ENTER_CRITICAL_SECTION();
\r
100 PageInfo[pageIndex].BytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
101 PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE];
\r
102 PageInfo[pageIndex].Status = PAGE_STATUS_FREE;
\r
104 TotalBytesRemaining += TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
106 TRACE_EXIT_CRITICAL_SECTION();
\r
109 static int prvGetBufferPage(int32_t* bytesUsed)
\r
111 static int8_t lastPage = -1;
\r
113 int8_t index = (lastPage + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;
\r
115 while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT))
\r
117 index = (index + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;
\r
120 if (PageInfo[index].Status == PAGE_STATUS_READ)
\r
122 *bytesUsed = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE - PageInfo[index].BytesRemaining;
\r
132 /*******************************************************************************
\r
134 int32_t vPagedEventBufferTransfer(int32_t (*writeFunc)(void* data,
\r
138 Transfers one block of trace data, if available for reading. Returns the number
\r
139 of bytes transfered, or a negative error code. If data was transferred (return
\r
140 value > 0), it can be good to call this function again until all data available
\r
141 has been transfered.
\r
143 This function is intended to be called by a periodic task with a suitable
\r
144 delay (e.g. 10-100 ms).
\r
148 TickType_t lastWakeTime = xTaskGetTickCount();
\r
154 // Transfer all available data
\r
155 status = vPagedEventBufferTransfer(MyWrite, ptrBytes);
\r
156 }while(status > 0);
\r
160 // A negative return value is an error code...
\r
163 vTraceDelayUntil(lastWakeTime, 50); // 50 ms -> 20 times/sec
\r
166 Return value: returnvalue of writeFunc (0 == OK)
\r
171 Function pointer (example: int32_t write(void* data, uint32_t size))
\r
172 The function passed as writeFunc should write "size" bytes from "data" to the
\r
173 socket/file/channel, and return a status code where 0 means OK,
\r
174 and any other non-zero value means an error.
\r
176 - int32_t* nofBytes
\r
177 Pointer to an integer assigned the number of bytes that was transfered.
\r
179 *******************************************************************************/
\r
181 int32_t vPagedEventBufferTransfer(int32_t (*writeFunc)(void* data, uint32_t size, int32_t* ptrBytesWritten), int32_t* nofBytes)
\r
183 static int firstTime = 1;
\r
184 int8_t pageToTransfer = -1;
\r
186 pageToTransfer = prvGetBufferPage(nofBytes);
\r
193 if (pageToTransfer > -1)
\r
195 if (writeFunc(&EventBuffer[pageToTransfer * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE], *nofBytes, nofBytes) == 0)
\r
197 prvPageReadComplete(pageToTransfer);
\r
209 /*******************************************************************************
\r
211 void* vPagedEventBufferGetWritePointer(int sizeOfEvent)
\r
213 Returns a pointer to an available location in the buffer able to store the
\r
216 Return value: The pointer.
\r
221 The size of the event that is to be placed in the buffer.
\r
223 *******************************************************************************/
\r
224 void* vPagedEventBufferGetWritePointer(int sizeOfEvent)
\r
227 static int currentWritePage = -1;
\r
229 if (currentWritePage == -1)
\r
231 currentWritePage = prvAllocateBufferPage(currentWritePage);
\r
232 if (currentWritePage == -1)
\r
234 DroppedEventCounter++;
\r
239 if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0)
\r
241 PageInfo[currentWritePage].Status = PAGE_STATUS_READ;
\r
243 TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes
\r
245 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
\r
246 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
\r
248 currentWritePage = prvAllocateBufferPage(currentWritePage);
\r
249 if (currentWritePage == -1)
\r
251 DroppedEventCounter++;
\r
255 ret = PageInfo[currentWritePage].WritePointer;
\r
256 PageInfo[currentWritePage].WritePointer += sizeOfEvent;
\r
257 PageInfo[currentWritePage].BytesRemaining -= sizeOfEvent;
\r
259 TotalBytesRemaining -= sizeOfEvent;
\r
261 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
\r
262 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
\r
267 /*******************************************************************************
\r
269 void vPagedEventBufferInit(char* buffer)
\r
271 Assigns the buffer to use and initializes the PageInfo structure.
\r
278 Pointer to the buffer location that is dynamically or statically allocated by
\r
281 *******************************************************************************/
\r
282 void vPagedEventBufferInit(char* buffer)
\r
284 TRACE_ALLOC_CRITICAL_SECTION();
\r
287 EventBuffer = buffer;
\r
289 TRACE_ENTER_CRITICAL_SECTION();
\r
290 for (i = 0; i < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT; i++)
\r
292 PageInfo[i].BytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
293 PageInfo[i].WritePointer = &EventBuffer[i * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE];
\r
294 PageInfo[i].Status = PAGE_STATUS_FREE;
\r
296 TRACE_EXIT_CRITICAL_SECTION();
\r