]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace(streaming)/trcPagedEventBuffer.c
Update FreeRTOS+Trace recorder library to v3.0.2
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-Trace(streaming) / trcPagedEventBuffer.c
1 /*******************************************************************************\r
2  * Trace Recorder Library for Tracealyzer v3.0.2\r
3  * Percepio AB, www.percepio.com\r
4  *\r
5  * trcPagedEventBuffer.c\r
6  *\r
7  * Implements a paged buffer that can be used by TCP/IP or custom transfer\r
8  * methods.\r
9  *\r
10  * Terms of Use\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
14  *\r
15  * Separate conditions applies for the SEGGER branded source code included.\r
16  *\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
20  *\r
21  * Disclaimer\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
35  *\r
36  * Tabs are used for indent in this file (1 tab = 4 spaces)\r
37  *\r
38  * Copyright Percepio AB, 2015.\r
39  * www.percepio.com\r
40  ******************************************************************************/\r
41 \r
42 #include <stdio.h>\r
43 #include <stdint.h>\r
44 #include <string.h>\r
45 \r
46 #include "trcConfig.h"\r
47 #include "trcPagedEventBuffer.h"\r
48 #include "trcPagedEventBufferConfig.h"\r
49 #include "trcKernelPort.h"\r
50 \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
53 \r
54 #if (USE_TRACEALYZER_RECORDER == 1)\r
55 \r
56 #define PAGE_STATUS_FREE 0\r
57 #define PAGE_STATUS_WRITE 1\r
58 #define PAGE_STATUS_READ 2\r
59 \r
60 uint32_t TotalBytesRemaining = TRC_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;\r
61 \r
62 typedef struct{\r
63         uint8_t Status;\r
64         uint16_t BytesRemaining;\r
65         char* WritePointer;\r
66 } PageType;\r
67 \r
68 PageType PageInfo[TRC_PAGED_EVENT_BUFFER_PAGE_COUNT];\r
69 \r
70 char* EventBuffer = NULL;\r
71 \r
72 static void prvPageReadComplete(int pageIndex);\r
73 static int prvAllocateBufferPage(int prevPage);\r
74 \r
75 static int prvAllocateBufferPage(int prevPage)\r
76 {\r
77         int index;\r
78         int count = 0;\r
79 \r
80         index = (prevPage + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;\r
81 \r
82         while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT))\r
83         {\r
84                 index = (index + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;\r
85         }\r
86 \r
87         if (PageInfo[index].Status == PAGE_STATUS_FREE)\r
88         {\r
89                 return index;\r
90         }\r
91 \r
92         return -1;\r
93 }\r
94 \r
95 static void prvPageReadComplete(int pageIndex)\r
96 {\r
97         TRACE_ALLOC_CRITICAL_SECTION();\r
98 \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
103 \r
104         TotalBytesRemaining += TRC_PAGED_EVENT_BUFFER_PAGE_SIZE;\r
105 \r
106         TRACE_EXIT_CRITICAL_SECTION();\r
107 }\r
108 \r
109 static int prvGetBufferPage(int32_t* bytesUsed)\r
110 {\r
111         static int8_t lastPage = -1;\r
112         int count = 0;\r
113         int8_t index = (lastPage + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;\r
114 \r
115         while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT))\r
116         {\r
117                 index = (index + 1) % TRC_PAGED_EVENT_BUFFER_PAGE_COUNT;\r
118         }\r
119 \r
120         if (PageInfo[index].Status == PAGE_STATUS_READ)\r
121         {\r
122                 *bytesUsed = TRC_PAGED_EVENT_BUFFER_PAGE_SIZE - PageInfo[index].BytesRemaining;\r
123                 lastPage = index;\r
124                 return index;\r
125         }\r
126 \r
127         *bytesUsed = 0;\r
128 \r
129         return -1;\r
130 }\r
131 \r
132 /*******************************************************************************\r
133 \r
134 int32_t vPagedEventBufferTransfer(int32_t (*writeFunc)(void* data,\r
135                                                         uint32_t size),\r
136                                             int32_t* nofBytes)\r
137 \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
142 \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
145 \r
146 Example:\r
147 \r
148         TickType_t lastWakeTime = xTaskGetTickCount();\r
149 \r
150         while(1)\r
151         {\r
152 \r
153                 do{\r
154                         // Transfer all available data\r
155                         status = vPagedEventBufferTransfer(MyWrite, ptrBytes);\r
156                 }while(status > 0);\r
157 \r
158                 if (status < 0)\r
159                 {\r
160                         // A negative return value is an error code...\r
161                 }\r
162 \r
163                 vTraceDelayUntil(lastWakeTime, 50); // 50 ms -> 20 times/sec\r
164         }\r
165 \r
166 Return value: returnvalue of writeFunc (0 == OK)\r
167 \r
168 Parameters:\r
169 \r
170 - writeFunc\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
175 \r
176 - int32_t* nofBytes\r
177 Pointer to an integer assigned the number of bytes that was transfered.\r
178 \r
179 *******************************************************************************/\r
180 \r
181 int32_t vPagedEventBufferTransfer(int32_t (*writeFunc)(void* data, uint32_t size, int32_t* ptrBytesWritten), int32_t* nofBytes)\r
182 {\r
183         static int firstTime = 1;\r
184         int8_t pageToTransfer = -1;\r
185 \r
186         pageToTransfer = prvGetBufferPage(nofBytes);\r
187 \r
188         if (firstTime)\r
189         {\r
190                 firstTime = 0;\r
191         }\r
192 \r
193         if (pageToTransfer > -1)\r
194         {\r
195                 if (writeFunc(&EventBuffer[pageToTransfer * TRC_PAGED_EVENT_BUFFER_PAGE_SIZE], *nofBytes, nofBytes) == 0)\r
196                 {\r
197                         prvPageReadComplete(pageToTransfer);\r
198             \r
199             return 0;\r
200                 }\r
201         else\r
202         {\r
203             return 1;\r
204         }\r
205         }\r
206         return 0;\r
207 }\r
208 \r
209 /*******************************************************************************\r
210 \r
211 void* vPagedEventBufferGetWritePointer(int sizeOfEvent)\r
212 \r
213 Returns a pointer to an available location in the buffer able to store the\r
214 requested size.\r
215 \r
216 Return value: The pointer.\r
217 \r
218 Parameters:\r
219 \r
220 - sizeOfEvent\r
221 The size of the event that is to be placed in the buffer.\r
222 \r
223 *******************************************************************************/\r
224 void* vPagedEventBufferGetWritePointer(int sizeOfEvent)\r
225 {\r
226         void* ret;\r
227         static int currentWritePage = -1;\r
228 \r
229         if (currentWritePage == -1)\r
230         {\r
231             currentWritePage = prvAllocateBufferPage(currentWritePage);\r
232                 if (currentWritePage == -1)\r
233                 {\r
234                         DroppedEventCounter++;\r
235                         return NULL;\r
236                 }\r
237         }\r
238 \r
239     if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0)\r
240         {\r
241                 PageInfo[currentWritePage].Status = PAGE_STATUS_READ;\r
242 \r
243                 TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes\r
244 \r
245                 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)\r
246                   TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;\r
247 \r
248                 currentWritePage = prvAllocateBufferPage(currentWritePage);\r
249                 if (currentWritePage == -1)\r
250                 {\r
251                   DroppedEventCounter++;\r
252                   return NULL;\r
253                 }\r
254         }\r
255         ret = PageInfo[currentWritePage].WritePointer;\r
256         PageInfo[currentWritePage].WritePointer += sizeOfEvent;\r
257         PageInfo[currentWritePage].BytesRemaining -= sizeOfEvent;\r
258 \r
259         TotalBytesRemaining -= sizeOfEvent;\r
260 \r
261         if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)\r
262                 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;\r
263 \r
264         return ret;\r
265 }\r
266 \r
267 /*******************************************************************************\r
268 \r
269 void vPagedEventBufferInit(char* buffer)\r
270 \r
271 Assigns the buffer to use and initializes the PageInfo structure.\r
272 \r
273 Return value: void\r
274 \r
275 Parameters:\r
276 \r
277 - buffer\r
278 Pointer to the buffer location that is dynamically or statically allocated by\r
279 the caller.\r
280 \r
281 *******************************************************************************/\r
282 void vPagedEventBufferInit(char* buffer)\r
283 {\r
284         TRACE_ALLOC_CRITICAL_SECTION();\r
285         int i;\r
286     \r
287     EventBuffer = buffer;\r
288     \r
289         TRACE_ENTER_CRITICAL_SECTION();\r
290         for (i = 0; i < TRC_PAGED_EVENT_BUFFER_PAGE_COUNT; i++)\r
291         {\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
295         }\r
296         TRACE_EXIT_CRITICAL_SECTION();\r
297 }\r
298 \r
299 #endif\r
300 \r
301 \r
302 \r