1 /*
2  * Trace Recorder for Tracealyzer v4.5.1
3  * Copyright 2021 Percepio AB
4  * www.percepio.com
5  *
6  * SPDX-License-Identifier: Apache-2.0
7  *
8  * The implementation of the internal buffer.
9  */
10 
11 #include "trcRecorder.h"
12 
13 #if (TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)
14 
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdarg.h>
18 #include "trcInternalBuffer.h"
19 
20 
21 /* The status codes for the pages of the internal trace buffer. */
22 #define PAGE_STATUS_FREE 0
23 #define PAGE_STATUS_WRITE 1
24 #define PAGE_STATUS_READ 2
25 
26 
27 typedef struct{
28 	uint16_t Status;  /* 16 bit to avoid implicit padding (warnings) */
29 	uint16_t BytesRemaining;
30 	char* WritePointer;
31 } PageType;
32 
33 
34 PageType PageInfo[TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT] TRC_CFG_RECORDER_DATA_ATTRIBUTE;
35 
36 
37 char* EventBuffer TRC_CFG_RECORDER_DATA_ATTRIBUTE;
38 uint32_t TotalBytesRemaining_LowWaterMark TRC_CFG_RECORDER_DATA_ATTRIBUTE;
39 uint32_t TotalBytesRemaining TRC_CFG_RECORDER_DATA_ATTRIBUTE;
40 
41 
42 /**
43  * @brief Retrieve a buffer page to write to.
44  *
45  * @param prevPage Index of previous page.
46  * @return int Index of available page or -1 if no page is currently available.
47  */
prvAllocateBufferPage(int prevPage)48 static int prvAllocateBufferPage(int prevPage)
49 {
50 	int index;
51 	int count = 0;
52 
53 	index = (prevPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);
54 
55 	while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)))
56 	{
57 		index = (index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);
58 	}
59 
60 	if (PageInfo[index].Status == PAGE_STATUS_FREE)
61 	{
62 		return index;
63 	}
64 
65 	return -1;
66 }
67 
68 /**
69  * @brief Mark a page read as complete.
70  *
71  * @param pageIndex Index of page
72  */
prvPageReadComplete(int pageIndex)73 static void prvPageReadComplete(int pageIndex)
74 {
75   	TRACE_ALLOC_CRITICAL_SECTION();
76 
77 	TRACE_ENTER_CRITICAL_SECTION();
78 	PageInfo[pageIndex].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
79 	PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)];
80 	PageInfo[pageIndex].Status = PAGE_STATUS_FREE;
81 
82 	TotalBytesRemaining += (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
83 
84 	TRACE_EXIT_CRITICAL_SECTION();
85 }
86 
87 /**
88  * @brief Get the current buffer page index and remaining number of bytes.
89  *
90  * @param bytesUsed Pointer to int where bytes used will be written.
91  * @return int Index of page or -1 if there is no current page.
92  */
prvGetBufferPage(int32_t * bytesUsed)93 static int prvGetBufferPage(int32_t* bytesUsed)
94 {
95 	static int8_t lastPage = -1;
96 	int count = 0;
97   	int8_t index = (int8_t) ((lastPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT));
98 
99 	while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)))
100 	{
101 		index = (int8_t)((index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT));
102 	}
103 
104 	if (PageInfo[index].Status == PAGE_STATUS_READ)
105 	{
106 		*bytesUsed = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) - PageInfo[index].BytesRemaining;
107 		lastPage = index;
108 		return index;
109 	}
110 
111 	*bytesUsed = 0;
112 
113 	return -1;
114 }
115 
prvPagedEventBufferInit(char * buffer)116 void prvPagedEventBufferInit(char* buffer)
117 {
118 	TotalBytesRemaining_LowWaterMark = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)* (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
119 	TotalBytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)* (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
120 
121   	int i;
122   	TRACE_ALLOC_CRITICAL_SECTION();
123 
124     EventBuffer = buffer;
125 
126 	TRACE_ENTER_CRITICAL_SECTION();
127 	for (i = 0; i < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); i++)
128 	{
129 		PageInfo[i].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
130 		PageInfo[i].WritePointer = &EventBuffer[i * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)];
131 		PageInfo[i].Status = PAGE_STATUS_FREE;
132 	}
133 	TRACE_EXIT_CRITICAL_SECTION();
134 }
135 
prvPagedEventBufferGetWritePointer(int sizeOfEvent)136 void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)
137 {
138 	void* ret;
139 	static int currentWritePage = -1;
140 
141 	if (currentWritePage == -1)
142 	{
143 	    currentWritePage = prvAllocateBufferPage(currentWritePage);
144 		if (currentWritePage == -1)
145 		{
146 		  	//DroppedEventCounter++;
147 			return NULL;
148 		}
149 	}
150 
151     if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0)
152 	{
153 		PageInfo[currentWritePage].Status = PAGE_STATUS_READ;
154 
155 		TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes
156 
157 		if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
158 		  TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
159 
160 		currentWritePage = prvAllocateBufferPage(currentWritePage);
161 		if (currentWritePage == -1)
162 		{
163 		  //DroppedEventCounter++;
164 		  return NULL;
165 		}
166 	}
167 	ret = PageInfo[currentWritePage].WritePointer;
168 	PageInfo[currentWritePage].WritePointer += sizeOfEvent;
169 	PageInfo[currentWritePage].BytesRemaining = (uint16_t)(PageInfo[currentWritePage].BytesRemaining -sizeOfEvent);
170 
171 	TotalBytesRemaining = (TotalBytesRemaining-(uint16_t)sizeOfEvent);
172 
173 	if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
174 		TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
175 
176 	return ret;
177 }
178 
prvPagedEventBufferTransfer(void)179 uint32_t prvPagedEventBufferTransfer(void)
180 {
181 	int8_t pageToTransfer = -1;
182     int32_t bytesTransferredTotal = 0;
183 	int32_t bytesTransferredNow = 0;
184 	int32_t bytesToTransfer;
185 
186     pageToTransfer = (int8_t)prvGetBufferPage(&bytesToTransfer);
187 
188 	/* bytesToTransfer now contains the number of "valid" bytes in the buffer page, that should be transmitted.
189 	There might be some unused junk bytes in the end, that must be ignored. */
190 
191     if (pageToTransfer > -1)
192     {
193         while (1)  /* Keep going until we have transferred all that we intended to */
194         {
195 			if (TRC_STREAM_PORT_WRITE_DATA(
196 					&EventBuffer[pageToTransfer * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) + bytesTransferredTotal],
197 					(uint32_t)(bytesToTransfer - bytesTransferredTotal),
198 					&bytesTransferredNow) == 0)
199 			{
200 				/* Write was successful. Update the number of transferred bytes. */
201 				bytesTransferredTotal += bytesTransferredNow;
202 
203 				if (bytesTransferredTotal == bytesToTransfer)
204 				{
205 					/* All bytes have been transferred. Mark the buffer page as "Read Complete" (so it can be written to) and return OK. */
206 					prvPageReadComplete(pageToTransfer);
207 					return (uint32_t)bytesTransferredTotal;
208 				}
209 			}
210 			else
211 			{
212 				/* Some error from the streaming interface... */
213 				vTraceStop();
214 				return 0;
215 			}
216 		}
217 	}
218 	return 0;
219 }
220 
221 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1) && (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)*/
222