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