1 /*
2 * Percepio Trace Recorder for Tracealyzer v4.9.2
3 * Copyright 2023 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) && (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)
14 
15 #include <stdarg.h>
16 
17 static traceResult prvTraceVPrintF(const TraceStringHandle_t xChannel, const char* szFormat, uint32_t uiLength, uint32_t uiArgs, va_list* pxVariableList);
18 
19 static TracePrintData_t *pxPrintData TRC_CFG_RECORDER_DATA_ATTRIBUTE;
20 
xTracePrintInitialize(TracePrintData_t * pxBuffer)21 traceResult xTracePrintInitialize(TracePrintData_t *pxBuffer)
22 {
23 	/* This should never fail */
24 	TRC_ASSERT(pxBuffer != (void*)0);
25 
26 	pxPrintData = pxBuffer;
27 
28 	pxPrintData->defaultChannel = 0;
29 	pxPrintData->consoleChannel = 0;
30 
31 	xTraceSetComponentInitialized(TRC_RECORDER_COMPONENT_PRINT);
32 
33 	return TRC_SUCCESS;
34 }
35 
36 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/
xTracePrint(TraceStringHandle_t xChannel,const char * szString)37 traceResult xTracePrint(TraceStringHandle_t xChannel, const char* szString)
38 {
39 	uint32_t uiLength;
40 	uint32_t i;
41 
42 	/* We need to check this */
43 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
44 	{
45 		return TRC_FAIL;
46 	}
47 
48 	if (szString == (void*)0)
49 	{
50 		szString = ""; /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
51 	}
52 
53 	for (i = 0u; (szString[i] != (char)0) && (i < 128u); i++) {} /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress char base type usage checks*/ /*cstat !MISRAC2004-17.4_b We need to access every character in the string*/
54 
55 	uiLength = i + 1u; /* Null termination */
56 
57 	return prvTraceVPrintF(xChannel, szString, uiLength, 0u, (va_list*)0);  /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 Suppress conversion of pointer to integer check*/ /*cstat !MISRAC2012-Rule-11.9 Suppress NULL recommendation*/
58 }
59 
60 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-16.1 Suppress variable parameter count check*/
xTraceConsoleChannelPrintF(const char * szFormat,...)61 traceResult xTraceConsoleChannelPrintF(const char* szFormat, ...)
62 {
63 	traceResult xResult;
64 	va_list xVariableList; /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
65 
66 	/* We need to check this */
67 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
68 	{
69 		return TRC_FAIL;
70 	}
71 
72 	if (pxPrintData->consoleChannel == 0)
73 	{
74 		if (xTraceStringRegister("Debug Console", &pxPrintData->consoleChannel) == TRC_FAIL)
75 		{
76 			return TRC_FAIL;
77 		}
78 	}
79 
80 	va_start(xVariableList, szFormat);
81 	xResult = xTraceVPrintF(pxPrintData->consoleChannel, szFormat, &xVariableList);
82 	va_end(xVariableList);
83 
84 	return xResult;
85 }
86 
87 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-16.1 Suppress variable parameter count check*/
xTracePrintCompactF(const char * szChannel,const char * szFormat,...)88 traceResult xTracePrintCompactF(const char* szChannel, const char* szFormat, ...)
89 {
90 	uint32_t i;
91 	uint32_t uiArgs = 0u;
92 	traceResult xResult;
93 	va_list xVariableList; /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
94 	TraceUnsignedBaseType_t uxArg1, uxArg2, uxArg3, uxArg4;
95 
96 	/* We need to check this */
97 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
98 	{
99 		return TRC_FAIL;
100 	}
101 
102 	if (szFormat == (void*)0)
103 	{
104 		szFormat = ""; /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
105 	}
106 
107 	/* Count the number of arguments in the format string (e.g., %d) */
108 	for (i = 0u; (szFormat[i] != (char)0) && (i < 128u); i++) /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress char base type usage checks*/ /*cstat !MISRAC2012-Rule-14.2 Suppress malformed for loop due to i being incremented inside*/ /*cstat !MISRAC2004-17.4_b We need to access every character in the string*/
109 	{
110 		if (szFormat[i] == '%') /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
111 		{
112 			if (szFormat[i + 1u] == (char)0) /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
113 			{
114 				/* Found end of string, let for loop detect it */
115 				continue; /*cstat !MISRAC2004-14.5 Suppress continue usage check*/
116 			}
117 
118 			if (szFormat[i + 1u] != '%') /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
119 			{
120 				uiArgs++;        /* Found an argument */
121 			}
122 
123 			/* Move past format specifier or non-argument '%' */
124 			i++; /*cstat !MISRAC2004-13.6 Suppress i increment inside for loop check*/
125 		}
126 	}
127 
128 	va_start(xVariableList, szFormat);
129 	switch(uiArgs)
130 	{
131 	case 0:
132 		xResult = xTraceEventCreate2(PSF_EVENT_USER_EVENT_FIXED, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
133 		break;
134 	case 1:
135 		uxArg1 = va_arg(xVariableList, TraceUnsignedBaseType_t);
136 		xResult = xTraceEventCreate3(PSF_EVENT_USER_EVENT_FIXED + 1UL, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat, uxArg1); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
137 		break;
138 	case 2:
139 		uxArg1 = va_arg(xVariableList, TraceUnsignedBaseType_t);
140 		uxArg2 = va_arg(xVariableList, TraceUnsignedBaseType_t);
141 		xResult = xTraceEventCreate4(PSF_EVENT_USER_EVENT_FIXED + 2UL, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat, uxArg1, uxArg2); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
142 		break;
143 	case 3:
144 		uxArg1 = va_arg(xVariableList, TraceUnsignedBaseType_t);
145 		uxArg2 = va_arg(xVariableList, TraceUnsignedBaseType_t);
146 		uxArg3 = va_arg(xVariableList, TraceUnsignedBaseType_t);
147 		xResult = xTraceEventCreate5(PSF_EVENT_USER_EVENT_FIXED + 3UL, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat, uxArg1, uxArg2, uxArg3); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
148 		break;
149 	case 4:
150 		uxArg1 = va_arg(xVariableList, TraceUnsignedBaseType_t);
151 		uxArg2 = va_arg(xVariableList, TraceUnsignedBaseType_t);
152 		uxArg3 = va_arg(xVariableList, TraceUnsignedBaseType_t);
153 		uxArg4 = va_arg(xVariableList, TraceUnsignedBaseType_t);
154 		xResult = xTraceEventCreate6(PSF_EVENT_USER_EVENT_FIXED + 4UL, (TraceUnsignedBaseType_t)szChannel, (TraceUnsignedBaseType_t)szFormat, uxArg1, uxArg2, uxArg3, uxArg4); /*cstat !MISRAC2004-11.3 !MISRAC2012-Rule-11.4 We need the addresses*/
155 		break;
156 	default:
157 		xResult = TRC_FAIL;
158 		break;
159 	}
160 	va_end(xVariableList);
161 
162 	return xResult;
163 }
164 
165 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-16.1 Suppress variable parameter count check*/
xTracePrintF(TraceStringHandle_t xChannel,const char * szFormat,...)166 traceResult xTracePrintF(TraceStringHandle_t xChannel, const char* szFormat, ...)
167 {
168 	traceResult xResult;
169 	va_list xVariableList; /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
170 
171 	/* We need to check this */
172 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
173 	{
174 		return TRC_FAIL;
175 	}
176 
177 	va_start(xVariableList, szFormat);
178 	xResult = xTraceVPrintF(xChannel, szFormat, &xVariableList);
179 	va_end(xVariableList);
180 
181 	return xResult;
182 }
183 
184 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
xTraceVPrintF(TraceStringHandle_t xChannel,const char * szFormat,va_list * pxVariableList)185 traceResult xTraceVPrintF(TraceStringHandle_t xChannel, const char* szFormat, va_list* pxVariableList)
186 {
187 	uint32_t i;
188 	uint32_t uiArgs = 0u;
189 	uint32_t uiLength;
190 
191 	/* We need to check this */
192 	if (xTraceIsComponentInitialized(TRC_RECORDER_COMPONENT_PRINT) == 0U)
193 	{
194 		return TRC_FAIL;
195 	}
196 
197 	if (szFormat == (void*)0)
198 	{
199 		szFormat = ""; /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
200 	}
201 
202 	/* Count the number of arguments in the format string (e.g., %d) */
203 	for (i = 0u; (szFormat[i] != (char)0) && (i < 128u); i++) /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress char base type usage checks*/ /*cstat !MISRAC2012-Rule-14.2 Suppress malformed for loop due to i being incremented inside*/ /*cstat !MISRAC2004-17.4_b We need to access every character in the string*/
204 	{
205 		if (szFormat[i] == '%') /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
206 		{
207 			if (szFormat[i + 1u] == (char)0) /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
208 			{
209 				/* Found end of string, let for loop detect it */
210 				continue; /*cstat !MISRAC2004-14.5 Suppress continue usage check*/
211 			}
212 
213 			if (szFormat[i + 1u] != '%') /*cstat !MISRAC2004-17.4_b We need to access a specific character in the string*/
214 			{
215 				uiArgs++;        /* Found an argument */
216 			}
217 
218 			/* Move past format specifier or non-argument '%' */
219 			i++; /*cstat !MISRAC2004-13.6 Suppress i increment inside for loop check*/
220 		}
221 	}
222 
223 	uiLength = i + 1u; /* Null termination */
224 
225 	return prvTraceVPrintF(xChannel, szFormat, uiLength, uiArgs, pxVariableList);
226 }
227 
228 /*cstat !MISRAC2004-6.3 !MISRAC2012-Dir-4.6_a Suppress basic char type usage*/ /*cstat !MISRAC2012-Rule-17.1 Suppress stdarg usage check*/
prvTraceVPrintF(TraceStringHandle_t xChannel,const char * szFormat,uint32_t uiLength,uint32_t uiArgs,va_list * pxVariableList)229 static traceResult prvTraceVPrintF(TraceStringHandle_t xChannel, const char* szFormat, uint32_t uiLength, uint32_t uiArgs, va_list* pxVariableList)
230 {
231 	const uint32_t uiEventCode = PSF_EVENT_USER_EVENT + 1u + uiArgs; /* Add channel (1) */
232 	traceResult xResult;
233 	TraceUnsignedBaseType_t uxParam1;
234 	TraceUnsignedBaseType_t uxParam2;
235 	TraceUnsignedBaseType_t uxParam3;
236 	TraceUnsignedBaseType_t uxParam4;
237 	TraceUnsignedBaseType_t uxParam5;
238 
239 	if (xChannel == 0)
240 	{
241 		if (pxPrintData->defaultChannel == 0)
242 		{
243 			/* Channel is not present */
244 			if (xTraceStringRegister("Default", &pxPrintData->defaultChannel) == TRC_FAIL)
245 			{
246 				return TRC_FAIL;
247 			}
248 		}
249 
250 		xChannel = pxPrintData->defaultChannel; /*cstat !MISRAC2012-Rule-17.8 Suppress modified function parameter check*/
251 	}
252 
253 	switch (uiArgs)
254 	{
255 		case 0:
256 			xResult = xTraceEventCreateData1(uiEventCode, (TraceUnsignedBaseType_t)xChannel, (TraceUnsignedBaseType_t*)szFormat, uiLength);
257 			break;
258 		case 1:
259 			uxParam1 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
260 			xResult = xTraceEventCreateData2(
261 				uiEventCode,
262 				(TraceUnsignedBaseType_t)xChannel,
263 				uxParam1,
264 				(TraceUnsignedBaseType_t*)szFormat,
265 				uiLength
266 			);
267 			break;
268 		case 2:
269 			uxParam1 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
270 			uxParam2 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
271 			xResult = xTraceEventCreateData3(
272 				uiEventCode,
273 				(TraceUnsignedBaseType_t)xChannel,
274 				uxParam1,
275 				uxParam2,
276 				(TraceUnsignedBaseType_t*)szFormat,
277 				uiLength
278 			);
279 			break;
280 		case 3:
281 			uxParam1 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
282 			uxParam2 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
283 			uxParam3 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
284 			xResult = xTraceEventCreateData4(
285 				uiEventCode,
286 				(TraceUnsignedBaseType_t)xChannel,
287 				uxParam1,
288 				uxParam2,
289 				uxParam3,
290 				(TraceUnsignedBaseType_t*)szFormat,
291 				uiLength
292 			);
293 			break;
294 		case 4:
295 			uxParam1 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
296 			uxParam2 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
297 			uxParam3 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
298 			uxParam4 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
299 			xResult = xTraceEventCreateData5(
300 				uiEventCode,
301 				(TraceUnsignedBaseType_t)xChannel,
302 				uxParam1,
303 				uxParam2,
304 				uxParam3,
305 				uxParam4,
306 				(TraceUnsignedBaseType_t*)szFormat,
307 				uiLength
308 			);
309 			break;
310 		case 5:
311 			uxParam1 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
312 			uxParam2 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
313 			uxParam3 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
314 			uxParam4 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
315 			uxParam5 = va_arg(*pxVariableList, TraceUnsignedBaseType_t);
316 			xResult = xTraceEventCreateData6(
317 				uiEventCode,
318 				(TraceUnsignedBaseType_t)xChannel,
319 				uxParam1,
320 				uxParam2,
321 				uxParam3,
322 				uxParam4,
323 				uxParam5,
324 				(TraceUnsignedBaseType_t*)szFormat,
325 				uiLength
326 			);
327 			break;
328 		default:
329 			xResult = TRC_FAIL;
330 			break;
331 	}
332 
333 	return xResult;
334 }
335 
336 #endif
337