1 /*
2 * Percepio Trace Recorder for Tracealyzer v4.6.6
3 * Copyright 2021 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * The implementation for print.
9 */
10 
11 #include <trcRecorder.h>
12 
13 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
14 
15 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
16 
17 #if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)
18 
19 #include <stdarg.h>
20 
21 static traceResult prvTraceVPrintF(TraceStringHandle_t xChannel, const char* szFormat, uint32_t uiLength, uint32_t uiArgs, va_list *pxVL);
22 
23 typedef struct TracePrintInfo
24 {
25 	TraceStringHandle_t defaultChannel;
26 	TraceStringHandle_t consoleChannel;
27 } TracePrintInfo_t;
28 
29 static TracePrintInfo_t *pxPrintInfo;
30 
xTracePrintInitialize(TracePrintBuffer_t * pxBuffer)31 traceResult xTracePrintInitialize(TracePrintBuffer_t *pxBuffer)
32 {
33 	TRC_ASSERT_EQUAL_SIZE(TracePrintBuffer_t, TracePrintInfo_t);
34 
35 	/* This should never fail */
36 	TRC_ASSERT(pxBuffer != 0);
37 
38 	pxPrintInfo = (TracePrintInfo_t*)pxBuffer;
39 	pxPrintInfo->defaultChannel = 0;
40 	pxPrintInfo->consoleChannel = 0;
41 
42 	xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_PRINT);
43 
44 	return TRC_SUCCESS;
45 }
46 
47 /******************************************************************************
48  * xTracePrint
49  *
50  * Generates "User Events", with unformatted text.
51  *
52  * User Events can be used for very efficient application logging, and are shown
53  * as yellow labels in the main trace view.
54  *
55  * You may group User Events into User Event Channels. The yellow User Event
56  * labels shows the logged string, preceded by the channel  name within
57  * brackets. For example:
58  *
59  *  "[MyChannel] Hello World!"
60  *
61  * The User Event Channels are shown in the View Filter, which makes it easy to
62  * select what User Events you wish to display. User Event Channels are created
63  * using xTraceStringRegister().
64  *
65  * Example:
66  *
67  *	 TraceStringHandle_t xChannel = xTraceStringRegister("MyChannel");
68  *	 ...
69  *	 xTracePrint(xChannel, "Hello World!");
70  *
71  ******************************************************************************/
xTracePrint(TraceStringHandle_t xChannel,const char * szString)72 traceResult xTracePrint(TraceStringHandle_t xChannel, const char* szString)
73 {
74 	uint32_t uiLength = 0;
75 	uint32_t i = 0;
76 
77 	/* We need to check this */
78 	if (!xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT))
79 	{
80 		return TRC_FAIL;
81 	}
82 
83 	if (szString == 0)
84 	{
85 		szString = "";
86 	}
87 
88 	while ((szString[i] != 0) && (i < 128))
89 	{
90 		i++;
91 	}
92 
93 	uiLength = i + 1; /* Null termination */
94 
95 	return prvTraceVPrintF(xChannel, szString, uiLength, 0, (va_list*)0);
96 }
97 
98 /*******************************************************************************
99 * xTraceConsoleChannelPrintF
100 *
101 * Wrapper for vTracePrint, using the default channel. Can be used as a drop-in
102 * replacement for printf and similar functions, e.g. in a debug logging macro.
103 *
104 * Example:
105 *
106 *	 // Old: #define LogString debug_console_printf
107 *
108 *    // New, log to Tracealyzer instead:
109 *	 #define LogString xTraceConsoleChannelPrintF
110 *	 ...
111 *	 LogString("My value is: %d", myValue);
112 ******************************************************************************/
xTraceConsoleChannelPrintF(const char * szFormat,...)113 traceResult xTraceConsoleChannelPrintF(const char* szFormat, ...)
114 {
115 	traceResult xResult;
116 	va_list xVL;
117 
118 	/* We need to check this */
119 	if (!xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT))
120 	{
121 		return TRC_FAIL;
122 	}
123 
124 	if (pxPrintInfo->consoleChannel == 0)
125 	{
126 		if (xTraceStringRegister("Debug Console", &pxPrintInfo->consoleChannel) == TRC_FAIL)
127 		{
128 			return TRC_FAIL;
129 		}
130 	}
131 
132 	va_start(xVL, szFormat);
133 	xResult = xTraceVPrintF(pxPrintInfo->consoleChannel, szFormat, xVL);
134 	va_end(xVL);
135 
136 	return xResult;
137 }
138 
139 /******************************************************************************
140  * xTracePrintF
141  *
142  * Generates "User Events", with formatted text and data, similar to a "printf".
143  * It is very fast since the actual formatting is done on the host side when the
144  * trace is displayed.
145  *
146  * User Events can be used for very efficient application logging, and are shown
147  * as yellow labels in the main trace view.
148  * An advantage of User Events is that data can be plotted in the "User Event
149  * Signal Plot" view, visualizing any data you log as User Events, discrete
150  * states or control system signals (e.g. system inputs or outputs).
151  *
152  * You may group User Events into User Event Channels. The yellow User Event
153  * labels show the logged string, preceded by the channel name within brackets.
154  *
155  * Example:
156  *
157  *  "[MyChannel] Hello World!"
158  *
159  * The User Event Channels are shown in the View Filter, which makes it easy to
160  * select what User Events you wish to display. User Event Channels are created
161  * using xTraceStringRegister().
162  *
163  * Example:
164  *
165  *	 TraceStringHandle_t adc_uechannel = xTraceStringRegister("ADC User Events");
166  *	 ...
167  *	 xTracePrintF(adc_uechannel,
168  *				 "ADC channel %d: %d volts",
169  *				 ch, adc_reading);
170  *
171  * All data arguments are assumed to be 32 bit wide. The following formats are
172  * supported:
173  * %d - signed integer. The following width and padding format is supported: "%05d" -> "-0042" and "%5d" -> "  -42"
174  * %u - unsigned integer. The following width and padding format is supported: "%05u" -> "00042" and "%5u" -> "   42"
175  * %X - hexadecimal (uppercase). The following width and padding format is supported: "%04X" -> "002A" and "%4X" -> "  2A"
176  * %x - hexadecimal (lowercase). The following width and padding format is supported: "%04x" -> "002a" and "%4x" -> "  2a"
177  * %s - string (currently, this must be an earlier stored symbol name)
178  *
179  * Up to 15 data arguments are allowed, with a total size of maximum 60 byte
180  * including 8 byte for the base event fields and the format string. So with
181  * one data argument, the maximum string length is 48 chars. If this is exceeded
182  * the string is truncated (4 bytes at a time).
183  *
184  ******************************************************************************/
xTracePrintF(TraceStringHandle_t xChannel,const char * szFormat,...)185 traceResult xTracePrintF(TraceStringHandle_t xChannel, const char* szFormat, ...)
186 {
187 	traceResult xResult;
188 	va_list xVL;
189 
190 	/* We need to check this */
191 	if (!xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT))
192 	{
193 		return TRC_FAIL;
194 	}
195 
196 	va_start(xVL, szFormat);
197 	xResult = xTraceVPrintF(xChannel, szFormat, xVL);
198 	va_end(xVL);
199 
200 	return xResult;
201 }
202 
203 /******************************************************************************
204  * xTraceVPrintF
205  *
206  * xTracePrintF variant that accepts a va_list.
207  * See xTraceVPrintF documentation for further details.
208  *
209  ******************************************************************************/
xTraceVPrintF(TraceStringHandle_t xChannel,const char * szFormat,va_list xVL)210 traceResult xTraceVPrintF(TraceStringHandle_t xChannel, const char* szFormat, va_list xVL)
211 {
212 	uint32_t i = 0;
213 	uint32_t uiArgs = 0;
214 	uint32_t uiLength;
215 
216 	/* We need to check this */
217 	if (!xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT))
218 	{
219 		return TRC_FAIL;
220 	}
221 
222 	if (szFormat == 0)
223 	{
224 		szFormat = "";
225 	}
226 
227 	/* Count the number of arguments in the format string (e.g., %d) */
228 	for (i = 0; (szFormat[i] != 0) && (i < 128); i++)
229 	{
230 		if (szFormat[i] == '%')
231 		{
232 			if (szFormat[i + 1] == 0)
233 			{
234 				/* Found end of string, let for loop detect it */
235 				continue;
236 			}
237 
238 			if (szFormat[i + 1] != '%')
239 			{
240 				uiArgs++;        /* Found an argument */
241 			}
242 
243 			i++;      /* Move past format specifier or non-argument '%' */
244 		}
245 	}
246 
247 	uiLength = i + 1; /* Null termination */
248 
249 	return prvTraceVPrintF(xChannel, szFormat, uiLength, uiArgs, &xVL);
250 }
251 
prvTraceVPrintF(TraceStringHandle_t xChannel,const char * szFormat,uint32_t uiLength,uint32_t uiArgs,va_list * pxVL)252 static traceResult prvTraceVPrintF(TraceStringHandle_t xChannel, const char* szFormat, uint32_t uiLength, uint32_t uiArgs, va_list *pxVL)
253 {
254 	TraceEventHandle_t xEventHandle = 0;
255 	uint32_t i, uiRemaining;
256 	uint32_t uiValue;
257 	uint32_t uiEventCode = PSF_EVENT_USER_EVENT + 1 + uiArgs; /* Add channel (1) */
258 	uint32_t uiSize = sizeof(void*) + uiArgs * sizeof(TraceUnsignedBaseType_t) + uiLength; /* Add channel (sizeof(void*)) */
259 
260 	if (xChannel == 0)
261 	{
262 		if (pxPrintInfo->defaultChannel == 0)
263 		{
264 			/* Channel is not present */
265 			if (xTraceStringRegister("Default", &pxPrintInfo->defaultChannel) == TRC_FAIL)
266 			{
267 				return TRC_FAIL;
268 			}
269 		}
270 
271 		xChannel = pxPrintInfo->defaultChannel;
272 	}
273 
274 	/* Added channel to uiEventCode and uiSize */
275 	if (xTraceEventBegin(uiEventCode, uiSize , &xEventHandle) == TRC_FAIL)
276 	{
277 		return TRC_FAIL;
278 	}
279 
280 	/* Add xChannel */
281 	xTraceEventAddPointer(xEventHandle, (void*)xChannel);
282 
283 	/* Add all arguments */
284 	for (i = 0; i < uiArgs; i++)
285 	{
286 		xTraceEventAddUnsignedBaseType(xEventHandle, va_arg(*pxVL, TraceUnsignedBaseType_t));
287 	}
288 
289 	xTraceEventPayloadRemaining(xEventHandle, &uiRemaining);
290 	if (uiRemaining < uiLength)
291 	{
292 		uiLength = uiRemaining - 1; /* Make room for null termination */
293 	}
294 
295 	/* Add format string */
296 	xTraceEventAddData(xEventHandle, (void*)szFormat, uiLength);
297 
298 	/* Check if we can truncate */
299 	xTraceEventPayloadRemaining(xEventHandle, &uiValue);
300 	if (uiValue > 0)
301 	{
302 		xTraceEventAdd8(xEventHandle, 0);
303 	}
304 
305 	xTraceEventEnd(xEventHandle);
306 
307 	return TRC_SUCCESS;
308 }
309 
310 #endif /* (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) */
311 
312 #endif /* (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) */
313 
314 #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
315