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 generic core of the trace recorder's streaming mode.
9  */
10 
11 #include "trcRecorder.h"
12 
13 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
14 
15 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
16 
17 #include <stdio.h>
18 #include <string.h>
19 #include <stdarg.h>
20 
21 #include "trcExtensions.h"
22 #include "trcInternalBuffer.h"
23 
24 /* Unless specified in trcConfig.h we assume this is a single core target */
25 #ifndef TRC_CFG_PLATFORM_NUM_CORES
26 #define TRC_CFG_PLATFORM_NUM_CORES 1
27 #endif
28 
29 #ifndef TRC_GET_CURRENT_CORE
30 #define TRC_GET_CURRENT_CORE() 0
31 #endif
32 
33 #if (TRC_CFG_PLATFORM_NUM_CORES) > 1
34 #define TRC_GET_EVENT_COUNT(eventCounter) (((TRC_GET_CURRENT_CORE() & 0xF) << 12) | (eventCounter & 0xFFF))
35 #else
36 #define TRC_GET_EVENT_COUNT(eventCounter) eventCounter
37 #endif
38 
39 #define TRC_PLATFORM_CFG_LENGTH 8
40 
41 typedef struct{
42 	uint16_t EventID;
43 	uint16_t EventCount;
44 	uint32_t TS;
45 } BaseEvent;
46 
47 typedef struct{
48   BaseEvent base;
49   uint32_t param1;
50 } EventWithParam_1;
51 
52 typedef struct{
53   BaseEvent base;
54   uint32_t param1;
55   uint32_t param2;
56 } EventWithParam_2;
57 
58 typedef struct{
59   BaseEvent base;
60   uint32_t param1;
61   uint32_t param2;
62   uint32_t param3;
63 } EventWithParam_3;
64 
65 typedef struct{
66 	BaseEvent base;
67 	uint32_t param1;
68 	uint32_t param2;
69 	uint32_t param3;
70 	uint32_t param4;
71 } EventWithParam_4;
72 
73 typedef struct{
74 	BaseEvent base;
75 	uint32_t param1;
76 	uint32_t param2;
77 	uint32_t param3;
78 	uint32_t param4;
79 	uint32_t param5;
80 } EventWithParam_5;
81 
82 /* Used in event functions with variable number of parameters. */
83 typedef struct
84 {
85   BaseEvent base;
86   uint32_t data[15]; /* maximum payload size */
87 } largestEventType;
88 
89 typedef struct{
90   uint32_t psf;
91   uint16_t version;
92   uint16_t platform;
93   uint32_t options;
94   uint32_t numCores;
95   char platform_cfg[TRC_PLATFORM_CFG_LENGTH];
96   uint16_t platform_cfg_patch;
97   uint8_t platform_cfg_minor;
98   uint8_t platform_cfg_major;
99   uint32_t heapCounter;
100   uint32_t heapMax;
101   uint16_t symbolSize;
102   uint16_t symbolCount;
103   uint16_t objectDataSize;
104   uint16_t objectDataCount;
105 } PSFHeaderInfo;
106 
107 #ifndef TRC_CFG_RECORDER_DATA_INIT
108 #define TRC_CFG_RECORDER_DATA_INIT 1
109 #endif
110 
111 
112 /* The size of each slot in the Symbol Table */
113 #define SYMBOL_TABLE_SLOT_SIZE (sizeof(uint32_t) + (((TRC_CFG_SYMBOL_MAX_LENGTH)+(sizeof(uint32_t)-1))/sizeof(uint32_t))*sizeof(uint32_t))
114 
115 #define OBJECT_DATA_SLOT_SIZE (sizeof(uint32_t) + sizeof(uint32_t))
116 
117 /* The total size of the Symbol Table */
118 #define SYMBOL_TABLE_BUFFER_SIZE ((TRC_CFG_SYMBOL_TABLE_SLOTS) * SYMBOL_TABLE_SLOT_SIZE)
119 
120 /* The total size of the Object Data Table */
121 #define OBJECT_DATA_TABLE_BUFFER_SIZE ((TRC_CFG_OBJECT_DATA_SLOTS) * OBJECT_DATA_SLOT_SIZE)
122 
123 #if (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT > 128)
124 #error "TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT cannot be larger than 128"
125 #endif /* (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT > 128) */
126 
127 /* The Symbol Table type - just a byte array */
128 typedef struct{
129   union
130   {
131     uint32_t pSymbolTableBufferUINT32[SYMBOL_TABLE_BUFFER_SIZE / sizeof(uint32_t)];
132     uint8_t pSymbolTableBufferUINT8[SYMBOL_TABLE_BUFFER_SIZE];
133   } SymbolTableBuffer;
134 } SymbolTable;
135 
136 /* The Object Data Table type - just a byte array */
137 typedef struct{
138   union
139   {
140     uint32_t pObjectDataTableBufferUINT32[OBJECT_DATA_TABLE_BUFFER_SIZE / sizeof(uint32_t)];
141     uint8_t pObjectDataTableBufferUINT8[OBJECT_DATA_TABLE_BUFFER_SIZE];
142   } ObjectDataTableBuffer;
143 } ObjectDataTable;
144 
145 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
146 typedef struct {
147 	void* tcb;
148 	uint32_t uiPreviousLowMark;
149 } TaskStackMonitorEntry_t;
150 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
151 
152 /* Code used for "task address" when no task has started, to indicate "(startup)".
153  * This value was used since NULL/0 was already reserved for the idle task. */
154 #define HANDLE_NO_TASK 2
155 
156 /* Calls prvTraceError if the _assert condition is false. For void functions,
157 where no return value is to be provided. */
158 #define PSF_ASSERT_VOID(_assert, _err) if (! (_assert)){ prvTraceError(_err); return; }
159 
160 /* Calls prvTraceError if the _assert condition is false. For non-void functions,
161 where a return value is to be provided. */
162 #define PSF_ASSERT_RET(_assert, _err, _return) if (! (_assert)){ prvTraceError(_err); return _return; }
163 
164 /* Part of the PSF format - encodes the number of 32-bit params in an event */
165 #define PARAM_COUNT(n) ((n & 0xF) << 12)
166 
167 /* We skip the slot for PSF_ERROR_NONE so error code 1 is the first bit */
168 #define GET_ERROR_WARNING_FLAG(errCode) (ErrorAndWarningFlags & (1 << ((errCode) - 1)))
169 #define SET_ERROR_WARNING_FLAG(errCode) (ErrorAndWarningFlags |= (1 << ((errCode) - 1)))
170 
171 /* Counts the number of trace sessions (not yet used) */
172 static uint32_t SessionCounter = 0u;
173 
174 /* Used to determine endian of data (big/little) */
175 static uint32_t PSFEndianessIdentifier = 0x50534600;
176 
177 /* Used to interpret the data format */
178 static uint16_t FormatVersion = 0x0009;
179 
180 /* The number of events stored. Used as event sequence number. */
181 static uint32_t eventCounter = 0;
182 
183 /* The extension data */
184 PSFExtensionInfoType PSFExtensionInfo = TRC_EXTENSION_INFO;
185 
186 /* Used for flags indicating if a certain error or warning has occurred */
187 static uint32_t ErrorAndWarningFlags TRC_CFG_RECORDER_DATA_ATTRIBUTE;
188 
189 /* The Symbol Table instance - keeps names of tasks and other named objects. */
190 static SymbolTable symbolTable TRC_CFG_RECORDER_DATA_ATTRIBUTE;
191 
192 /* This points to the first unused entry in the symbol table. */
193 static uint32_t firstFreeSymbolTableIndex TRC_CFG_RECORDER_DATA_ATTRIBUTE;
194 
195 /* The Object Data Table instance - keeps initial priorities of tasks. */
196 static ObjectDataTable objectDataTable TRC_CFG_RECORDER_DATA_ATTRIBUTE;
197 
198 /* This points to the first unused entry in the object data table. */
199 static uint32_t firstFreeObjectDataTableIndex TRC_CFG_RECORDER_DATA_ATTRIBUTE;
200 
201 /* Keeps track of ISR nesting */
202 static uint32_t ISR_stack[TRC_CFG_MAX_ISR_NESTING] TRC_CFG_RECORDER_DATA_ATTRIBUTE;
203 
204 /* Keeps track of ISR nesting */
205 static int8_t ISR_stack_index TRC_CFG_RECORDER_DATA_ATTRIBUTE;
206 
207 /* Any error that occurred in the recorder (also creates User Event) */
208 static int errorCode TRC_CFG_RECORDER_DATA_ATTRIBUTE;
209 
210 /* The amount of Heap currently being used */
211 uint32_t trcHeapCounter TRC_CFG_RECORDER_DATA_ATTRIBUTE;
212 
213 /* The maximum amount of Heap that has been used */
214 uint32_t trcHeapMax TRC_CFG_RECORDER_DATA_ATTRIBUTE;
215 
216 /* Temporary event data storage */
217 static largestEventType xEventDataDummy = { { 0, 0, 0 }, { 0 } };
218 
219 /* The current event */
220 static largestEventType *pvCurrentEvent = 0;
221 
222 /* The payload of the current event that has been initialized using prvTraceBeginStoreEvent() */
223 static uint32_t uiCurrentEventPayloadSize = 0;
224 
225 /* The size of the current event that has been initialized using prvTraceBeginStoreEvent() */
226 static uint32_t uiCurrentEventSize = 0;
227 
228 /* The current event's payload pointer */
229 static uint32_t uiCurrentEventPayloadOffset = 0;
230 
231 /* The most recent tcb address */
232 static uint32_t xCurrentTask = 0;
233 
234 /* Remembers if an earlier ISR in a sequence of adjacent ISRs has triggered a task switch.
235 In that case, vTraceStoreISREnd does not store a return to the previously executing task. */
236 int32_t isPendingContextSwitch TRC_CFG_RECORDER_DATA_ATTRIBUTE;
237 
238 uint32_t uiTraceTickCount TRC_CFG_RECORDER_DATA_ATTRIBUTE;
239 uint32_t timestampFrequency TRC_CFG_RECORDER_DATA_ATTRIBUTE;
240 uint32_t DroppedEventCounter TRC_CFG_RECORDER_DATA_ATTRIBUTE;
241 
242 /*******************************************************************************
243  * NoRoomForSymbol
244  *
245  * Incremented on prvTraceSaveSymbol if no room for saving the symbol name. This
246  * is used for storing the names of:
247  * - Tasks
248  * - Named ISRs (xTraceSetISRProperties)
249  * - Named kernel objects (vTraceStoreKernelObjectName)
250  * - User event channels (xTraceRegisterString)
251  *
252  * This variable should be zero. If not, it shows the number of missing slots so
253  * far. In that case, increment SYMBOL_TABLE_SLOTS with (at least) this value.
254  ******************************************************************************/
255 volatile uint32_t NoRoomForSymbol TRC_CFG_RECORDER_DATA_ATTRIBUTE;
256 
257 /*******************************************************************************
258  * NoRoomForObjectData
259  *
260  * Incremented on prvTraceSaveObjectData if no room for saving the object data,
261  * i.e., the base priorities of tasks. There must be one slot for each task.
262  * If not, this variable will show the difference.
263  *
264  * This variable should be zero. If not, it shows the number of missing slots so
265  * far. In that case, increment OBJECT_DATA_SLOTS with (at least) this value.
266  ******************************************************************************/
267 volatile uint32_t NoRoomForObjectData TRC_CFG_RECORDER_DATA_ATTRIBUTE;
268 
269 /*******************************************************************************
270  * LongestSymbolName
271  *
272  * Updated in prvTraceSaveSymbol. Should not exceed TRC_CFG_SYMBOL_MAX_LENGTH,
273  * otherwise symbol names will be truncated. In that case, set
274  * TRC_CFG_SYMBOL_MAX_LENGTH to (at least) this value.
275  ******************************************************************************/
276 volatile uint32_t LongestSymbolName TRC_CFG_RECORDER_DATA_ATTRIBUTE;
277 
278 /*******************************************************************************
279  * MaxBytesTruncated
280  *
281  * Set in prvTraceStoreStringEvent if the total data payload exceeds 60 bytes,
282  * including data arguments and the string. For user events, that is 52 bytes
283  * for string and data arguments. In that is exceeded, the event is  truncated
284  * (usually only the string, unless more than 15 parameters) and this variable
285  * holds the maximum number of truncated bytes, from any event.
286  ******************************************************************************/
287 volatile uint32_t MaxBytesTruncated TRC_CFG_RECORDER_DATA_ATTRIBUTE;
288 
289 uint16_t CurrentFilterMask TRC_CFG_RECORDER_DATA_ATTRIBUTE;
290 
291 uint16_t CurrentFilterGroup TRC_CFG_RECORDER_DATA_ATTRIBUTE;
292 
293 volatile uint32_t uiTraceSystemState TRC_CFG_RECORDER_DATA_ATTRIBUTE;
294 
295 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
296 /*******************************************************************************
297 * TaskStacksNotIncluded
298 *
299 * Increased in prvAddTaskToStackMonitor(...) if there is no room in the stack
300 * monitor.
301 ******************************************************************************/
302 volatile uint32_t TaskStacksNotIncluded TRC_CFG_RECORDER_DATA_ATTRIBUTE;
303 
304 /*******************************************************************************
305 * tasksInStackMonitor
306 *
307 * Keeps track of the stacks for each task.
308 ******************************************************************************/
309 TaskStackMonitorEntry_t tasksInStackMonitor[TRC_CFG_STACK_MONITOR_MAX_TASKS] TRC_CFG_RECORDER_DATA_ATTRIBUTE;
310 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
311 
312 /* RecorderEnabled is a master switch for recording (0 => Disabled, 1 => Enabled) */
313 uint32_t RecorderEnabled TRC_CFG_RECORDER_DATA_ATTRIBUTE;
314 
315 /*******************************************************************************
316 * RecorderInitialized
317 *
318 * Makes sure the recorder data is only initialized once.
319 *
320 * NOTE: RecorderInitialized is only initialized to 0 if
321 * TRC_CFG_RECORDER_DATA_INIT is non-zero.
322 * This will avoid issues where the recorder must be started before main(),
323 * which can lead to RecorderInitialized be cleared by late initialization after
324 * vTraceEnable(TRC_INIT) was called and assigned RecorderInitialized its'
325 * value.
326 ******************************************************************************/
327 #if (TRC_CFG_RECORDER_DATA_INIT != 0)
328 uint32_t RecorderInitialized = 0;
329 #else /* (TRC_CFG_RECORDER_DATA_INIT != 0) */
330 uint32_t RecorderInitialized TRC_CFG_RECORDER_DATA_ATTRIBUTE;
331 #endif /* (TRC_CFG_RECORDER_DATA_INIT != 0) */
332 
333 /* Internal common function for storing string events */
334 static void prvTraceStoreStringEventHelper(	int nArgs,
335 										uint16_t eventID,
336 										traceString userEvtChannel,
337 										int len,
338 										const char* str,
339 										va_list vl);
340 
341 /* Not static to avoid warnings from SysGCC/PPC */
342 void prvTraceStoreSimpleStringEventHelper(uint16_t eventID,
343 											traceString userEvtChannel,
344 											const char* str);
345 
346 /* Stores the header information on Start */
347 static void prvTraceStoreHeader(void);
348 
349 /* Stores the Start Event */
350 static void prvTraceStoreStartEvent(void);
351 
352 /* Stores the symbol table on Start */
353 static void prvTraceStoreSymbolTable(void);
354 
355 /* Stores the object table on Start */
356 static void prvTraceStoreObjectDataTable(void);
357 
358 /* Store the Timestamp Config on Start */
359 static void prvTraceStoreTSConfig(void);
360 
361 /* Store information about trace library extensions. */
362 static void prvTraceStoreExtensionInfo(void);
363 
364 /* Internal function for starting/stopping the recorder. */
365 static void prvSetRecorderEnabled(uint32_t isEnabled);
366 
367 /* Performs timestamping using definitions in trcHardwarePort.h */
368 static uint32_t prvGetTimestamp32(void);
369 
370 /* Returns the string associated with the error code */
371 static const char* prvTraceGetError(int errCode);
372 
373 /* Signal an error. */
374 void prvTraceError(int errCode);
375 
376 /* Signal a warning (does not stop the recorder). */
377 void prvTraceWarning(int errCode);
378 
379 /******************************************************************************
380  * vTraceInstanceFinishedNow
381  *
382  * Creates an event that ends the current task instance at this very instant.
383  * This makes the viewer to splits the current fragment at this point and begin
384  * a new actor instance, even if no task-switch has occurred.
385  *****************************************************************************/
vTraceInstanceFinishedNow(void)386 void vTraceInstanceFinishedNow(void)
387 {
388 	prvTraceStoreEvent0(PSF_EVENT_IFE_DIRECT);
389 }
390 
391 /******************************************************************************
392  * vTraceInstanceFinishedNext
393  *
394  * Marks the current "task instance" as finished on the next kernel call.
395  *
396  * If that kernel call is blocking, the instance ends after the blocking event
397  * and the corresponding return event is then the start of the next instance.
398  * If the kernel call is not blocking, the viewer instead splits the current
399  * fragment right before the kernel call, which makes this call the first event
400  * of the next instance.
401  *****************************************************************************/
vTraceInstanceFinishedNext(void)402 void vTraceInstanceFinishedNext(void)
403 {
404 	prvTraceStoreEvent0(PSF_EVENT_IFE_NEXT);
405 }
406 
407 /*******************************************************************************
408  * vTraceStoreKernelObjectName
409  *
410  * Parameter object: pointer to the Event Group that shall be named
411  * Parameter name: the name to set (const string literal)
412  *
413  * Sets a name for a kernel object for display in Tracealyzer.
414  ******************************************************************************/
vTraceStoreKernelObjectName(void * object,const char * name)415 void vTraceStoreKernelObjectName(void* object, const char* name)
416 {
417 	uint16_t eventID = PSF_EVENT_OBJ_NAME;
418 
419 	PSF_ASSERT_VOID(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
420 
421 	/* Always save in symbol table, in case the recording has not yet started */
422 	prvTraceSaveObjectSymbol(object, name);
423 
424 	prvTraceStoreStringEvent(1, eventID, name, object);
425 }
426 
427 
428 /******************************************************************************
429 * vTraceSetFrequency
430 *
431 * Registers the clock rate of the time source for the event timestamping.
432 * This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ)
433 * should be incorrect for your setup, you can override it using this function.
434 *
435 * Must be called prior to vTraceEnable, and the time source is assumed to
436 * have a fixed clock frequency after the startup.
437 *****************************************************************************/
vTraceSetFrequency(uint32_t frequency)438 void vTraceSetFrequency(uint32_t frequency)
439 {
440 	timestampFrequency = frequency;
441 }
442 
443 #if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)
444 
445 /*******************************************************************************
446 * xTraceRegisterString
447 *
448 * Stores a name for a user event channel, returns the handle.
449 ******************************************************************************/
xTraceRegisterString(const char * name)450 traceString xTraceRegisterString(const char* name)
451 {
452 	traceString str;
453 	uint16_t eventID = PSF_EVENT_OBJ_NAME;
454 
455 	str = prvTraceSaveSymbol(name);
456 
457 	PSF_ASSERT_RET(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE, str);
458 
459 	/* Always save in symbol table, if the recording has not yet started */
460 	prvTraceStoreStringEvent(1, eventID, (const char*)name, str);
461 
462 	return str;
463 }
464 
465 /******************************************************************************
466  * vTracePrint
467  *
468  * Generates "User Events", with unformatted text.
469  *
470  * User Events can be used for very efficient application logging, and are shown
471  * as yellow labels in the main trace view.
472  *
473  * You may group User Events into User Event Channels. The yellow User Event
474  * labels shows the logged string, preceded by the channel  name within
475  * brackets. For example:
476  *
477  *  "[MyChannel] Hello World!"
478  *
479  * The User Event Channels are shown in the View Filter, which makes it easy to
480  * select what User Events you wish to display. User Event Channels are created
481  * using xTraceRegisterString().
482  *
483  * Example:
484  *
485  *	 traceString chn = xTraceRegisterString("MyChannel");
486  *	 ...
487  *	 vTracePrint(chn, "Hello World!");
488  *
489  ******************************************************************************/
vTracePrint(traceString chn,const char * str)490 void vTracePrint(traceString chn, const char* str)
491 {
492 	uint16_t eventID = PSF_EVENT_USER_EVENT;
493 	PSF_ASSERT_VOID(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
494 
495 	prvTraceStoreSimpleStringEventHelper(eventID, chn, str);
496 }
497 
498 /*******************************************************************************
499 * vTraceConsoleChannelPrintF
500 *
501 * Wrapper for vTracePrint, using the default channel. Can be used as a drop-in
502 * replacement for printf and similar functions, e.g. in a debug logging macro.
503 *
504 * Example:
505 *
506 *	 // Old: #define LogString debug_console_printf
507 *
508 *    // New, log to Tracealyzer instead:
509 *	 #define LogString vTraceConsoleChannelPrintF
510 *	 ...
511 *	 LogString("My value is: %d", myValue);
512 ******************************************************************************/
vTraceConsoleChannelPrintF(const char * fmt,...)513 void vTraceConsoleChannelPrintF(const char* fmt, ...)
514 {
515 		va_list vl;
516 		char tempBuf[60];
517 		static traceString consoleChannel = NULL;
518 
519 		if (consoleChannel == NULL)
520 			consoleChannel = xTraceRegisterString("Debug Console");
521 
522 		va_start(vl, fmt);
523 		vsnprintf(tempBuf, 60, fmt, vl);
524 		vTracePrint(consoleChannel, tempBuf);
525 		va_end(vl);
526 }
527 
528 /******************************************************************************
529  * vTracePrintF
530  *
531  * Generates "User Events", with formatted text and data, similar to a "printf".
532  * It is very fast since the actual formatting is done on the host side when the
533  * trace is displayed.
534  *
535  * User Events can be used for very efficient application logging, and are shown
536  * as yellow labels in the main trace view.
537  * An advantage of User Events is that data can be plotted in the "User Event
538  * Signal Plot" view, visualizing any data you log as User Events, discrete
539  * states or control system signals (e.g. system inputs or outputs).
540  *
541  * You may group User Events into User Event Channels. The yellow User Event
542  * labels show the logged string, preceded by the channel name within brackets.
543  *
544  * Example:
545  *
546  *  "[MyChannel] Hello World!"
547  *
548  * The User Event Channels are shown in the View Filter, which makes it easy to
549  * select what User Events you wish to display. User Event Channels are created
550  * using xTraceRegisterString().
551  *
552  * Example:
553  *
554  *	 traceString adc_uechannel = xTraceRegisterString("ADC User Events");
555  *	 ...
556  *	 vTracePrintF(adc_uechannel,
557  *				 "ADC channel %d: %d volts",
558  *				 ch, adc_reading);
559  *
560  * All data arguments are assumed to be 32 bit wide. The following formats are
561  * supported:
562  * %d - signed integer. The following width and padding format is supported: "%05d" -> "-0042" and "%5d" -> "  -42"
563  * %u - unsigned integer. The following width and padding format is supported: "%05u" -> "00042" and "%5u" -> "   42"
564  * %X - hexadecimal (uppercase). The following width and padding format is supported: "%04X" -> "002A" and "%4X" -> "  2A"
565  * %x - hexadecimal (lowercase). The following width and padding format is supported: "%04x" -> "002a" and "%4x" -> "  2a"
566  * %s - string (currently, this must be an earlier stored symbol name)
567  *
568  * Up to 15 data arguments are allowed, with a total size of maximum 60 byte
569  * including 8 byte for the base event fields and the format string. So with
570  * one data argument, the maximum string length is 48 chars. If this is exceeded
571  * the string is truncated (4 bytes at a time).
572  *
573  ******************************************************************************/
vTracePrintF(traceString chn,const char * fmt,...)574 void vTracePrintF(traceString chn, const char* fmt, ...)
575 {
576 	va_list vl;
577 
578 	va_start(vl, fmt);
579 	vTraceVPrintF(chn, fmt, vl);
580 	va_end(vl);
581 }
582 
583 /******************************************************************************
584  * vTraceVPrintF
585  *
586  * vTracePrintF variant that accepts a va_list.
587  * See vTracePrintF documentation for further details.
588  *
589  ******************************************************************************/
vTraceVPrintF(traceString chn,const char * fmt,va_list vl)590 void vTraceVPrintF(traceString chn, const char* fmt, va_list vl)
591 {
592 	int i = 0;
593 	int nArgs = 0;
594 	int eventID = PSF_EVENT_USER_EVENT;
595 
596 	/* Count the number of arguments in the format string (e.g., %d) */
597 	for (i = 0; (fmt[i] != 0) && (i < 52); i++)
598 	{
599 		if (fmt[i] == '%')
600 		{
601 			if (fmt[i + 1] == 0)
602 			{
603 				/* Found end of string, let for loop detect it */
604 				continue;
605 			}
606 
607 			if (fmt[i + 1] != '%')
608 			{
609 				nArgs++;        /* Found an argument */
610 			}
611 
612 			i++;      /* Move past format specifier or non-argument '%' */
613 		}
614 	}
615 
616 	if (chn != NULL)
617 	{
618 		/* Make room for the channel */
619 		nArgs++;
620 	}
621 	eventID += nArgs;
622 
623 	PSF_ASSERT_VOID(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
624 
625 	prvTraceStoreStringEventHelper(nArgs, (uint16_t)eventID, chn, i, fmt, vl);
626 }
627 #endif /* (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) */
628 
629 /*******************************************************************************
630  * xTraceSetISRProperties
631  *
632  * Stores a name and priority level for an Interrupt Service Routine, to allow
633  * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin.
634  *
635  * Example:
636  *	 #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt
637  *	 ...
638  *	 traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
639  *	 ...
640  *	 void ISR_handler()
641  *	 {
642  *		 vTraceStoreISRBegin(Timer1Handle);
643  *		 ...
644  *		 vTraceStoreISREnd(0);
645  *	 }
646  *
647  ******************************************************************************/
xTraceSetISRProperties(const char * name,uint8_t priority)648 traceHandle xTraceSetISRProperties(const char* name, uint8_t priority)
649 {
650 	traceHandle isrHandle;
651 	uint16_t eventID = PSF_EVENT_DEFINE_ISR;
652 
653 	/* Always save in symbol table, in case the recording has not yet started */
654 	isrHandle = prvTraceSaveSymbol(name);
655 
656 	/* Save object data in object data table */
657 	prvTraceSaveObjectData((void*)isrHandle, priority);
658 
659 	PSF_ASSERT_RET(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE, isrHandle);
660 
661 	prvTraceStoreStringEvent(2, eventID, name, isrHandle, priority);
662 
663 	return isrHandle;
664 }
665 
666 /*******************************************************************************
667  * vTraceStoreISRBegin
668  *
669  * Registers the beginning of an Interrupt Service Routine, using a traceHandle
670  * provided by xTraceSetISRProperties.
671  *
672  * Example:
673  *	 #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt
674  *	 ...
675  *	 traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
676  *	 ...
677  *	 void ISR_handler()
678  *	 {
679  *		 vTraceStoreISRBegin(Timer1Handle);
680  *		 ...
681  *		 vTraceStoreISREnd(0);
682  *	 }
683  *
684  ******************************************************************************/
vTraceStoreISRBegin(traceHandle handle)685 void vTraceStoreISRBegin(traceHandle handle)
686 {
687 	TRACE_ALLOC_CRITICAL_SECTION();
688 
689 	TRACE_ENTER_CRITICAL_SECTION();
690 
691 	/* We are at the start of a possible ISR chain.
692 	No context switches should have been triggered now. */
693 	if (ISR_stack_index == -1)
694 		isPendingContextSwitch = 0;
695 
696 	if (ISR_stack_index < (TRC_CFG_MAX_ISR_NESTING) - 1)
697 	{
698 		ISR_stack_index++;
699 		ISR_stack[ISR_stack_index] = (uint32_t)handle;
700 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
701 		prvTraceStoreEvent1(PSF_EVENT_ISR_BEGIN, (uint32_t)handle);
702 #endif
703 		TRACE_EXIT_CRITICAL_SECTION();
704 	}
705 	else
706 	{
707 		TRACE_EXIT_CRITICAL_SECTION();
708 		prvTraceError(PSF_ERROR_ISR_NESTING_OVERFLOW);
709 	}
710 }
711 
712 /*******************************************************************************
713  * vTraceStoreISREnd
714  *
715  * Registers the end of an Interrupt Service Routine.
716  *
717  * The parameter pendingISR indicates if the interrupt has requested a
718  * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the
719  * interrupt is assumed to return to the previous context.
720  *
721  * Example:
722  *	 #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt
723  *	 traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder
724  *	 ...
725  *	 traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1);
726  *	 ...
727  *	 void ISR_handler()
728  *	 {
729  *		 vTraceStoreISRBegin(traceHandleIsrTimer1);
730  *		 ...
731  *		 vTraceStoreISREnd(0);
732  *	 }
733  *
734  ******************************************************************************/
vTraceStoreISREnd(int isTaskSwitchRequired)735 void vTraceStoreISREnd(int isTaskSwitchRequired)
736 {
737 	TRACE_ALLOC_CRITICAL_SECTION();
738 
739 	TRACE_ENTER_CRITICAL_SECTION();
740 
741 	(void)ISR_stack;
742 
743 	/* Is there a pending task-switch? (perhaps from an earlier ISR) */
744 	isPendingContextSwitch |= isTaskSwitchRequired;
745 
746 	if (ISR_stack_index > 0)
747 	{
748 		ISR_stack_index--;
749 
750 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
751 		/* Store return to interrupted ISR (if nested ISRs)*/
752 		prvTraceStoreEvent1(PSF_EVENT_ISR_RESUME, (uint32_t)ISR_stack[ISR_stack_index]);
753 #endif
754 	}
755 	else
756 	{
757 		ISR_stack_index--;
758 
759 		/* Store return to interrupted task, if no context switch will occur in between. */
760 		if ((isPendingContextSwitch == 0) || (prvTraceIsSchedulerSuspended()))
761 		{
762 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
763 			prvTraceStoreEvent1(PSF_EVENT_TASK_ACTIVATE, (uint32_t)TRACE_GET_CURRENT_TASK());
764 #endif
765 		}
766 	}
767 
768 	TRACE_EXIT_CRITICAL_SECTION();
769 }
770 
771 /*******************************************************************************
772  * xTraceGetLastError
773  *
774  * Returns the last error or warning, as a string, or NULL if none.
775  *****************************************************************************/
xTraceGetLastError(void)776 const char* xTraceGetLastError(void)
777 {
778 	return prvTraceGetError(errorCode);
779 }
780 
781 /*******************************************************************************
782  * vTraceClearError
783  *
784  * Clears any errors.
785  *****************************************************************************/
vTraceClearError(void)786 void vTraceClearError(void)
787 {
788 	NoRoomForSymbol = 0;
789 	LongestSymbolName = 0;
790 	NoRoomForObjectData = 0;
791 	MaxBytesTruncated = 0;
792 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
793 	TaskStacksNotIncluded = 0;
794 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
795 	errorCode = PSF_ERROR_NONE;
796 }
797 
798 /*******************************************************************************
799  * vTraceStop
800  *
801  * Stops the tracing.
802  *****************************************************************************/
vTraceStop(void)803 void vTraceStop(void)
804 {
805 	prvSetRecorderEnabled(0);
806 }
807 
808 /*******************************************************************************
809  * vTraceSetRecorderDataBuffer
810  *
811  * If custom allocation is used, this function must be called so the recorder
812  * library knows where to save the trace data.
813  ******************************************************************************/
814 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)
815 
816 extern char* _TzTraceData;
817 
vTraceSetRecorderDataBuffer(void * pRecorderData)818 void vTraceSetRecorderDataBuffer(void* pRecorderData)
819 {
820 	_TzTraceData = pRecorderData;
821 }
822 #endif
823 
824 
825 /*******************************************************************************
826 * xTraceIsRecordingEnabled
827 * Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0.
828 ******************************************************************************/
xTraceIsRecordingEnabled(void)829 int xTraceIsRecordingEnabled(void)
830 {
831 	return (int)RecorderEnabled;
832 }
833 
vTraceSetFilterMask(uint16_t filterMask)834 void vTraceSetFilterMask(uint16_t filterMask)
835 {
836 	CurrentFilterMask = filterMask;
837 }
838 
vTraceSetFilterGroup(uint16_t filterGroup)839 void vTraceSetFilterGroup(uint16_t filterGroup)
840 {
841 	CurrentFilterGroup = filterGroup;
842 }
843 
844 /******************************************************************************
845 * vTraceInitialize
846 *
847 * Initializes the recorder data.
848 * This function will be called by vTraceEnable(...).
849 * Only needs to be called manually if traced objects are created before the
850 * trace recorder can be enabled, at which point make sure to call this function
851 * as early as possible.
852 * See TRC_CFG_RECORDER_DATA_INIT in trcConfig.h.
853 ******************************************************************************/
vTraceInitialize(void)854 void vTraceInitialize(void)
855 {
856 	uint32_t i = 0;
857 
858 	if (RecorderInitialized != 0)
859 	{
860 		return;
861 	}
862 
863 	/* These are set on init so they aren't overwritten by late initialization values. */
864 	RecorderEnabled = 0;
865 	NoRoomForSymbol = 0;
866 	LongestSymbolName = 0;
867 	NoRoomForObjectData = 0;
868 	MaxBytesTruncated = 0;
869 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
870 	TaskStacksNotIncluded = 0;
871 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
872 	CurrentFilterMask = 0xFFFF;
873 	CurrentFilterGroup = FilterGroup0;
874 	uiTraceSystemState = TRC_STATE_IN_STARTUP;
875 	uiTraceTickCount = 0;
876 	timestampFrequency = 0;
877 	DroppedEventCounter = 0;
878 	ErrorAndWarningFlags = 0;
879 	errorCode = 0;
880 	isPendingContextSwitch = 0;
881 	trcHeapCounter = 0;
882 	trcHeapMax = 0;
883 
884 	for (i = 0; i < (SYMBOL_TABLE_BUFFER_SIZE / sizeof(uint32_t)); i++)
885 	{
886 		symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i] = 0;
887 	}
888 	firstFreeSymbolTableIndex = 0;
889 
890 
891 	for (i = 0; i < (OBJECT_DATA_TABLE_BUFFER_SIZE / sizeof(uint32_t)); i++)
892 	{
893 		objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i] = 0;
894 	}
895 	firstFreeObjectDataTableIndex = 0;
896 
897 	for (i = 0; i < TRC_CFG_MAX_ISR_NESTING; i++)
898 	{
899 		ISR_stack[i] = 0;
900 	}
901 	ISR_stack_index = -1;
902 
903 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
904 	for (i = 0; i < TRC_CFG_STACK_MONITOR_MAX_TASKS; i++)
905 	{
906 		tasksInStackMonitor[i].tcb = 0;
907 		tasksInStackMonitor[i].uiPreviousLowMark = 0;
908 	}
909 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
910 
911 	RecorderInitialized = 1;
912 }
913 
914 /******************************************************************************/
915 /*** INTERNAL FUNCTIONS *******************************************************/
916 /******************************************************************************/
917 /* Internal function for starting/stopping the recorder. */
prvSetRecorderEnabled(uint32_t isEnabled)918 static void prvSetRecorderEnabled(uint32_t isEnabled)
919 {
920 	TRACE_ALLOC_CRITICAL_SECTION();
921 
922 	if (RecorderEnabled == isEnabled)
923 	{
924 		return;
925 	}
926 
927 	TRACE_ENTER_CRITICAL_SECTION();
928 
929 	if (isEnabled)
930 	{
931 		TRC_STREAM_PORT_ON_TRACE_BEGIN();
932 
933 		#if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)
934 		TRC_STREAM_PORT_INTERNAL_BUFFER_INIT();
935 		#endif
936 
937      	eventCounter = 0;
938         ISR_stack_index = -1;
939         prvTraceStoreHeader();
940 		prvTraceStoreSymbolTable();
941     	prvTraceStoreObjectDataTable();
942     	prvTraceStoreExtensionInfo();
943         prvTraceStoreStartEvent();
944         prvTraceStoreTSConfig();
945 	}
946     else
947     {
948 		TRC_STREAM_PORT_ON_TRACE_END();
949     }
950 
951 	RecorderEnabled = isEnabled;
952 
953 	TRACE_EXIT_CRITICAL_SECTION();
954 }
955 
prvTraceStoreStartEvent()956 static void prvTraceStoreStartEvent()
957 {
958 	void* currentTask;
959 
960 	TRACE_ALLOC_CRITICAL_SECTION();
961 
962 	TRACE_ENTER_CRITICAL_SECTION();
963 
964 	if (uiTraceSystemState == TRC_STATE_IN_STARTUP)
965 	{
966 		currentTask = (void*)HANDLE_NO_TASK;
967 	}
968 	else
969 	{
970 		currentTask = (void*)TRACE_GET_CURRENT_TASK();
971 	}
972 
973 	eventCounter++;
974 
975 	{
976 		TRC_STREAM_PORT_ALLOCATE_EVENT_BLOCKING(EventWithParam_3, pxEvent, sizeof(EventWithParam_3));
977 		if (pxEvent != NULL)
978 		{
979 			pxEvent->base.EventID = PSF_EVENT_TRACE_START | PARAM_COUNT(3);
980 			pxEvent->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
981 			pxEvent->base.TS = prvGetTimestamp32();
982 			pxEvent->param1 = (uint32_t)TRACE_GET_OS_TICKS();
983 			pxEvent->param2 = (uint32_t)currentTask;
984 			pxEvent->param3 = SessionCounter++;
985 			TRC_STREAM_PORT_COMMIT_EVENT_BLOCKING(pxEvent, sizeof(EventWithParam_3));
986 		}
987 	}
988 
989 	TRACE_EXIT_CRITICAL_SECTION();
990 }
991 
992 /* Store the Timestamp Config event */
prvTraceStoreTSConfig(void)993 static void prvTraceStoreTSConfig(void)
994 {
995 	/* If not overridden using vTraceSetFrequency, use default value */
996 	if (timestampFrequency == 0)
997 	{
998 		timestampFrequency = TRC_HWTC_FREQ_HZ;
999 	}
1000 
1001 	eventCounter++;
1002 
1003 
1004 	{
1005 #if (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR || TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR)
1006 
1007 		TRC_STREAM_PORT_ALLOCATE_EVENT_BLOCKING(EventWithParam_5, event, sizeof(EventWithParam_5));
1008 		if (event != NULL)
1009 		{
1010 			event->base.EventID = PSF_EVENT_TS_CONFIG | (uint16_t)PARAM_COUNT(5);
1011 			event->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1012 			event->base.TS = prvGetTimestamp32();
1013 
1014 			event->param1 = (uint32_t)timestampFrequency;
1015 			event->param2 = (uint32_t)(TRACE_TICK_RATE_HZ);
1016 			event->param3 = (uint32_t)(TRC_HWTC_TYPE);
1017 			event->param4 = (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD);
1018 			event->param5 = (uint32_t)(TRC_HWTC_PERIOD);
1019 			TRC_STREAM_PORT_COMMIT_EVENT_BLOCKING(event, (uint32_t)sizeof(EventWithParam_5));
1020 		}
1021 #else
1022 		TRC_STREAM_PORT_ALLOCATE_EVENT_BLOCKING(EventWithParam_4, event, sizeof(EventWithParam_4));
1023 		if (event != NULL)
1024 		{
1025 			event->base.EventID = PSF_EVENT_TS_CONFIG | (uint16_t)PARAM_COUNT(4);
1026 			event->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1027 			event->base.TS = prvGetTimestamp32();
1028 
1029 			event->param1 = (uint32_t)timestampFrequency;
1030 			event->param2 = (uint32_t)(TRACE_TICK_RATE_HZ);
1031 			event->param3 = (uint32_t)(TRC_HWTC_TYPE);
1032 			event->param4 = (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD);
1033 			TRC_STREAM_PORT_COMMIT_EVENT_BLOCKING(event, (uint32_t)sizeof(EventWithParam_4));
1034 		}
1035 #endif
1036 
1037 	}
1038 }
1039 
1040 /* Stores the symbol table on Start */
prvTraceStoreSymbolTable(void)1041 static void prvTraceStoreSymbolTable(void)
1042 {
1043 	uint32_t i = 0;
1044 	uint32_t j = 0;
1045 	TRACE_ALLOC_CRITICAL_SECTION();
1046 
1047 	TRACE_ENTER_CRITICAL_SECTION();
1048 
1049 	{
1050 		for (i = 0; i < (sizeof(SymbolTable) / sizeof(uint32_t)); i += (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)))
1051 		{
1052 			TRC_STREAM_PORT_ALLOCATE_EVENT_BLOCKING(uint32_t, data, SYMBOL_TABLE_SLOT_SIZE);
1053 
1054             for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)); j++)
1055             {
1056             	data[j] = symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i+j];
1057             }
1058 
1059 			TRC_STREAM_PORT_COMMIT_EVENT_BLOCKING(data, SYMBOL_TABLE_SLOT_SIZE);
1060 		}
1061 	}
1062 	TRACE_EXIT_CRITICAL_SECTION();
1063 }
1064 
1065 /* Stores the object table on Start */
prvTraceStoreObjectDataTable(void)1066 static void prvTraceStoreObjectDataTable(void)
1067 {
1068 	uint32_t i = 0;
1069 	uint32_t j = 0;
1070 	TRACE_ALLOC_CRITICAL_SECTION();
1071 
1072 	TRACE_ENTER_CRITICAL_SECTION();
1073 
1074 	{
1075 		for (i = 0; i < (sizeof(ObjectDataTable) / sizeof(uint32_t)); i += (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)))
1076         {
1077             TRC_STREAM_PORT_ALLOCATE_EVENT_BLOCKING(uint32_t, data, OBJECT_DATA_SLOT_SIZE);
1078 
1079             for (j = 0; j < (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)); j++)
1080             {
1081             	data[j] = objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i+j];
1082             }
1083 
1084 			TRC_STREAM_PORT_COMMIT_EVENT_BLOCKING(data, OBJECT_DATA_SLOT_SIZE);
1085         }
1086 	}
1087 	TRACE_EXIT_CRITICAL_SECTION();
1088 }
1089 
1090 /* Stores the header information on Start */
prvTraceStoreHeader(void)1091 static void prvTraceStoreHeader(void)
1092 {
1093 	int i;
1094 	char* platform_cfg = TRC_PLATFORM_CFG;
1095 
1096   	TRACE_ALLOC_CRITICAL_SECTION();
1097 
1098 	TRACE_ENTER_CRITICAL_SECTION();
1099 
1100 	{
1101 	  	TRC_STREAM_PORT_ALLOCATE_EVENT_BLOCKING(PSFHeaderInfo, header, sizeof(PSFHeaderInfo));
1102 		header->psf = PSFEndianessIdentifier;
1103 		header->version = FormatVersion;
1104 		header->platform = TRACE_KERNEL_VERSION;
1105 		header->options = 0;
1106 		for (i = 0; i < TRC_PLATFORM_CFG_LENGTH; i++)
1107 		{
1108 			header->platform_cfg[i] = platform_cfg[i];
1109 			if (platform_cfg[i] == 0)
1110 			{
1111 				break;
1112 			}
1113 		}
1114 		header->platform_cfg_patch = TRC_PLATFORM_CFG_PATCH;
1115 		header->platform_cfg_minor = TRC_PLATFORM_CFG_MINOR;
1116 		header->platform_cfg_major = TRC_PLATFORM_CFG_MAJOR;
1117 		header->options = 2;
1118 		header->numCores = TRC_CFG_PLATFORM_NUM_CORES;
1119 		header->heapCounter = trcHeapCounter;
1120 		header->heapMax = trcHeapMax;
1121         /* Lowest bit used for TRC_IRQ_PRIORITY_ORDER */
1122 		header->options = header->options | (TRC_IRQ_PRIORITY_ORDER << 0);
1123 		header->symbolSize = SYMBOL_TABLE_SLOT_SIZE;
1124 		header->symbolCount = (TRC_CFG_SYMBOL_TABLE_SLOTS);
1125 		header->objectDataSize = 8;
1126 		header->objectDataCount = (TRC_CFG_OBJECT_DATA_SLOTS);
1127 		TRC_STREAM_PORT_COMMIT_EVENT_BLOCKING(header, sizeof(PSFHeaderInfo));
1128 	}
1129 	TRACE_EXIT_CRITICAL_SECTION();
1130 }
1131 
1132 /* Stores the header information on Start */
prvTraceStoreExtensionInfo(void)1133 static void prvTraceStoreExtensionInfo(void)
1134 {
1135   	TRACE_ALLOC_CRITICAL_SECTION();
1136 
1137 	TRACE_ENTER_CRITICAL_SECTION();
1138 
1139 	{
1140 		TRC_STREAM_PORT_ALLOCATE_EVENT_BLOCKING(PSFExtensionInfoType, extinfo, sizeof(PSFExtensionInfoType));
1141 		memcpy(extinfo, &PSFExtensionInfo, sizeof(PSFExtensionInfoType));
1142 		TRC_STREAM_PORT_COMMIT_EVENT_BLOCKING(extinfo, sizeof(PSFExtensionInfoType));
1143 	}
1144 	TRACE_EXIT_CRITICAL_SECTION();
1145 }
1146 
1147 /* Returns the error or warning, as a string, or NULL if none. */
prvTraceGetError(int errCode)1148 static const char* prvTraceGetError(int errCode)
1149 {
1150 	/* Note: the error messages are short, in order to fit in a User Event.
1151 	Instead, the users can read more in the below comments.*/
1152 
1153 	switch (errCode)
1154 	{
1155 
1156 	case PSF_WARNING_SYMBOL_TABLE_SLOTS:
1157 		/* There was not enough symbol table slots for storing symbol names.
1158 		The number of missing slots is counted by NoRoomForSymbol. Inspect this
1159 		variable and increase TRC_CFG_SYMBOL_TABLE_SLOTS by at least that value. */
1160 
1161 		return "Exceeded SYMBOL_TABLE_SLOTS (see prvTraceGetError)";
1162 
1163 	case PSF_WARNING_SYMBOL_MAX_LENGTH:
1164 		/* A symbol name exceeded TRC_CFG_SYMBOL_MAX_LENGTH in length.
1165 		Make sure the symbol names are at most TRC_CFG_SYMBOL_MAX_LENGTH,
1166 		or inspect LongestSymbolName and increase TRC_CFG_SYMBOL_MAX_LENGTH
1167 		to at least this value. */
1168 
1169 		return "Exceeded SYMBOL_MAX_LENGTH (see prvTraceGetError)";
1170 
1171 	case PSF_WARNING_OBJECT_DATA_SLOTS:
1172 		/* There was not enough symbol object table slots for storing object
1173 		properties, such as task priorites. The number of missing slots is
1174 		counted by NoRoomForObjectData. Inspect this variable and increase
1175 		TRC_CFG_OBJECT_DATA_SLOTS by at least that value. */
1176 
1177 		return "Exceeded OBJECT_DATA_SLOTS (see prvTraceGetError)";
1178 
1179 	case PSF_WARNING_STRING_TOO_LONG:
1180 		/* Some string argument was longer than the maximum payload size
1181 		and has been truncated by "MaxBytesTruncated" bytes.
1182 
1183 		This may happen for the following functions:
1184 		- vTracePrint
1185 		- vTracePrintF
1186 		- vTraceStoreKernelObjectName
1187 		- xTraceRegisterString
1188 		- vTraceSetISRProperties
1189 
1190 		A PSF event may store maximum 60 bytes payload, including data
1191 		arguments and string characters. For User Events, also the User
1192 		Event Channel (4 bytes) must be squeezed in, if a channel is
1193 		specified (can be NULL). */
1194 
1195 		return "String too long (see prvTraceGetError)";
1196 
1197 	case PSF_WARNING_STREAM_PORT_READ:
1198 		/* TRC_STREAM_PORT_READ_DATA is expected to return 0 when completed successfully.
1199 		This means there is an error in the communication with host/Tracealyzer. */
1200 
1201 		return "TRC_STREAM_PORT_READ_DATA returned error (!= 0).";
1202 
1203 	case PSF_WARNING_STREAM_PORT_WRITE:
1204 		/* TRC_STREAM_PORT_WRITE_DATA is expected to return 0 when completed successfully.
1205 		This means there is an error in the communication with host/Tracealyzer. */
1206 
1207 		return "TRC_STREAM_PORT_WRITE_DATA returned error (!= 0).";
1208 
1209 	case PSF_WARNING_STACKMON_NO_SLOTS:
1210 		/* TRC_CFG_STACK_MONITOR_MAX_TASKS is too small to monitor all tasks. */
1211 
1212 		return "TRC_CFG_STACK_MONITOR_MAX_TASKS too small!";
1213 
1214 	case PSF_WARNING_STREAM_PORT_INITIAL_BLOCKING:
1215 		/* Blocking occurred during vTraceEnable. This happens if the trace buffer is
1216 		smaller than the initial transmission (trace header, object table, and symbol table). */
1217 
1218 		return "Blocking in vTraceEnable (see xTraceGetLastError)";
1219 
1220 	case PSF_ERROR_EVENT_CODE_TOO_LARGE:
1221 		/* The highest allowed event code is 4095, anything higher is an unexpected error.
1222 		Please contact support@percepio.com for assistance.*/
1223 
1224 		return "Invalid event code (see prvTraceGetError)";
1225 
1226 	case PSF_ERROR_ISR_NESTING_OVERFLOW:
1227 		/* Nesting of ISR trace calls exceeded the limit (TRC_CFG_MAX_ISR_NESTING).
1228 		If this is unlikely, make sure that you call vTraceStoreISRExit in the end
1229 		of all ISR handlers. Or increase TRC_CFG_MAX_ISR_NESTING. */
1230 
1231 		return "Exceeded ISR nesting (see prvTraceGetError)";
1232 
1233 	case PSF_ERROR_DWT_NOT_SUPPORTED:
1234 		/* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.
1235 		DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M
1236 		macro normally set by ARM's CMSIS library, since typically available. You can however select
1237 		SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/
1238 
1239 		return "DWT not supported (see prvTraceGetError)";
1240 
1241 	case PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED:
1242 		/* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.
1243 		DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M
1244 		macro normally set by ARM's CMSIS library, since typically available. You can however select
1245 		SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/
1246 
1247 		return "DWT_CYCCNT not supported (see prvTraceGetError)";
1248 
1249 	case PSF_ERROR_TZCTRLTASK_NOT_CREATED:
1250 		/* vTraceEnable failed creating the trace control task (TzCtrl) - incorrect parameters (priority?)
1251 		or insufficient heap size? */
1252 		return "Could not create TzCtrl (see prvTraceGetError)";
1253 
1254 	case PSF_ERROR_STREAM_PORT_WRITE:
1255 		/* TRC_STREAM_PORT_WRITE_DATA is expected to return 0 when completed successfully.
1256 		This means there is an error in the communication with host/Tracealyzer. */
1257 		return "TRC_STREAM_PORT_WRITE_DATA returned error (!= 0).";
1258 	}
1259 
1260 	return NULL;
1261 }
1262 
1263 /* Gets the most recent tcb address */
prvTraceGetCurrentTask(void)1264 uint32_t prvTraceGetCurrentTask(void)
1265 {
1266 	return xCurrentTask;
1267 }
1268 
1269 /* Sets the most recent tcb address */
prvTraceSetCurrentTask(uint32_t tcb)1270 void prvTraceSetCurrentTask(uint32_t tcb)
1271 {
1272 	xCurrentTask = tcb;
1273 }
1274 
1275 /* Begins an event with defined specified payload size. Must call prvTraceEndStoreEvent() to finalize event creation. */
prvTraceBeginStoreEvent(uint32_t uiEventCode,uint32_t uiTotalPayloadSize)1276 traceResult prvTraceBeginStoreEvent(uint32_t uiEventCode, uint32_t uiTotalPayloadSize)
1277 {
1278 	uint32_t uiPayloadCount;
1279 
1280 	if (RecorderEnabled == 0)
1281 	{
1282 		return TRACE_FAIL;
1283 	}
1284 
1285 	if (pvCurrentEvent != 0)
1286 	{
1287 		return TRACE_FAIL;
1288 	}
1289 
1290 	eventCounter++;
1291 
1292 	uiCurrentEventPayloadSize = uiTotalPayloadSize;
1293 	uiCurrentEventPayloadOffset = 0;
1294 	uiPayloadCount = (uiTotalPayloadSize + (sizeof(uint32_t) - 1)) / sizeof(uint32_t);	/* 4-byte align */
1295 	uiCurrentEventSize = sizeof(BaseEvent) + uiPayloadCount * sizeof(uint32_t);
1296 
1297 	TRC_STREAM_PORT_ALLOCATE_EVENT(largestEventType, pxEvent, uiCurrentEventSize);
1298 	if (pxEvent != 0)
1299 	{
1300 		pxEvent->base.EventID = (uint16_t)uiEventCode | PARAM_COUNT(uiPayloadCount);
1301 		pxEvent->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1302 
1303 		pvCurrentEvent = pxEvent;
1304 	}
1305 	else
1306 	{
1307 		uiCurrentEventSize = 0;
1308 		return TRACE_FAIL;
1309 	}
1310 
1311 	return TRACE_SUCCESS;
1312 }
1313 
1314 /* Ends the event that was begun by calling on prvTraceBeginStoreEvent() */
prvTraceEndStoreEvent()1315 traceResult prvTraceEndStoreEvent()
1316 {
1317 	if (RecorderEnabled == 0)
1318 	{
1319 		return TRACE_FAIL;
1320 	}
1321 
1322 	if (pvCurrentEvent == 0)
1323 	{
1324 		return TRACE_FAIL;
1325 	}
1326 
1327 	pvCurrentEvent->base.TS = prvGetTimestamp32();
1328 	TRC_STREAM_PORT_COMMIT_EVENT(pvCurrentEvent, uiCurrentEventSize);
1329 
1330 	uiCurrentEventPayloadSize = 0;
1331 	uiCurrentEventPayloadOffset = 0;
1332 	uiCurrentEventSize = 0;
1333 	pvCurrentEvent = 0;
1334 
1335 	return TRACE_SUCCESS;
1336 }
1337 
1338 /* Adds data of size uiSize as event payload */
prvTraceStoreEventPayload(void * pvData,uint32_t uiSize)1339 traceResult prvTraceStoreEventPayload(void *pvData, uint32_t uiSize)
1340 {
1341 	uint32_t i;
1342 
1343 	if (pvCurrentEvent == 0)
1344 	{
1345 		return TRACE_FAIL;
1346 	}
1347 
1348 	if (uiCurrentEventPayloadOffset + uiSize >  uiCurrentEventPayloadSize)
1349 	{
1350 		return TRACE_FAIL;
1351 	}
1352 
1353 	for (i = 0; i < uiSize; i++)
1354 	{
1355 		((uint8_t*)pvCurrentEvent->data)[uiCurrentEventPayloadOffset] = ((uint8_t*)pvData)[i];
1356 		uiCurrentEventPayloadOffset++;
1357 	}
1358 
1359 	return TRACE_SUCCESS;
1360 }
1361 
1362 /* Adds an uint32_t as event payload */
prvTraceStoreEventPayload32(uint32_t value)1363 traceResult prvTraceStoreEventPayload32(uint32_t value)
1364 {
1365 	if (pvCurrentEvent == 0)
1366 	{
1367 		return TRACE_FAIL;
1368 	}
1369 
1370 	if (uiCurrentEventPayloadOffset + sizeof(uint32_t) >  uiCurrentEventPayloadSize)
1371 	{
1372 		return TRACE_FAIL;
1373 	}
1374 
1375 	/* Make sure we are writing at 32-bit aligned offset */
1376 	if ((uiCurrentEventPayloadOffset & 3) != 0)
1377 	{
1378 		return TRACE_FAIL;
1379 	}
1380 
1381 	*(uint32_t*)&(((uint8_t*)pvCurrentEvent->data)[uiCurrentEventPayloadOffset]) = value;
1382 	uiCurrentEventPayloadOffset += sizeof(uint32_t);
1383 
1384 	return TRACE_SUCCESS;
1385 }
1386 
1387 /* Adds an uint16_t as event payload */
prvTraceStoreEventPayload16(uint16_t value)1388 traceResult prvTraceStoreEventPayload16(uint16_t value)
1389 {
1390 	if (pvCurrentEvent == 0)
1391 	{
1392 		return TRACE_FAIL;
1393 	}
1394 
1395 	if (uiCurrentEventPayloadOffset + sizeof(uint16_t) >  uiCurrentEventPayloadSize)
1396 	{
1397 		return TRACE_FAIL;
1398 	}
1399 
1400 	/* Make sure we are writing at 16-bit aligned offset */
1401 	if ((uiCurrentEventPayloadOffset & 1) != 0)
1402 	{
1403 		return TRACE_FAIL;
1404 	}
1405 
1406 	*(uint16_t*)&(((uint8_t*)pvCurrentEvent->data)[uiCurrentEventPayloadOffset]) = value;
1407 	uiCurrentEventPayloadOffset += sizeof(uint16_t);
1408 
1409 	return TRACE_SUCCESS;
1410 }
1411 
1412 /* Adds an uint8_t as event payload */
prvTraceStoreEventPayload8(uint8_t value)1413 traceResult prvTraceStoreEventPayload8(uint8_t value)
1414 {
1415 	if (pvCurrentEvent == 0)
1416 	{
1417 		return TRACE_FAIL;
1418 	}
1419 
1420 	if (uiCurrentEventPayloadOffset + sizeof(uint8_t) >  uiCurrentEventPayloadSize)
1421 	{
1422 		return TRACE_FAIL;
1423 	}
1424 
1425 	((uint8_t*)pvCurrentEvent->data)[uiCurrentEventPayloadOffset] = value;
1426 	uiCurrentEventPayloadOffset += sizeof(uint8_t);
1427 
1428 	return TRACE_SUCCESS;
1429 }
1430 
1431 /* Store an event with zero parameters (event ID only) */
prvTraceStoreEvent0(uint16_t eventID)1432 void prvTraceStoreEvent0(uint16_t eventID)
1433 {
1434   	TRACE_ALLOC_CRITICAL_SECTION();
1435 
1436 	PSF_ASSERT_VOID(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
1437 
1438 	TRACE_ENTER_CRITICAL_SECTION();
1439 
1440 	if (RecorderEnabled)
1441 	{
1442 		eventCounter++;
1443 
1444 		{
1445 			TRC_STREAM_PORT_ALLOCATE_EVENT(BaseEvent, event, sizeof(BaseEvent));
1446 			if (event != NULL)
1447 			{
1448 				event->EventID = eventID | PARAM_COUNT(0);
1449 				event->EventCount = (uint16_t)eventCounter;
1450 				event->TS = prvGetTimestamp32();
1451 				TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(BaseEvent));
1452 			}
1453 		}
1454 	}
1455 	TRACE_EXIT_CRITICAL_SECTION();
1456 }
1457 
1458 /* Store an event with one 32-bit parameter (pointer address or an int) */
prvTraceStoreEvent1(uint16_t eventID,uint32_t param1)1459 void prvTraceStoreEvent1(uint16_t eventID, uint32_t param1)
1460 {
1461   	TRACE_ALLOC_CRITICAL_SECTION();
1462 
1463 	PSF_ASSERT_VOID(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
1464 
1465 	TRACE_ENTER_CRITICAL_SECTION();
1466 
1467 	if (RecorderEnabled)
1468 	{
1469 		eventCounter++;
1470 
1471 		{
1472 			TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_1, event, sizeof(EventWithParam_1));
1473 			if (event != NULL)
1474 			{
1475 				event->base.EventID = eventID | PARAM_COUNT(1);
1476 				event->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1477 				event->base.TS = prvGetTimestamp32();
1478 				event->param1 = (uint32_t)param1;
1479 				TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_1));
1480 			}
1481 		}
1482 	}
1483 	TRACE_EXIT_CRITICAL_SECTION();
1484 }
1485 
1486 /* Store an event with two 32-bit parameters */
prvTraceStoreEvent2(uint16_t eventID,uint32_t param1,uint32_t param2)1487 void prvTraceStoreEvent2(uint16_t eventID, uint32_t param1, uint32_t param2)
1488 {
1489   	TRACE_ALLOC_CRITICAL_SECTION();
1490 
1491 	PSF_ASSERT_VOID(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
1492 
1493 	TRACE_ENTER_CRITICAL_SECTION();
1494 
1495 	if (RecorderEnabled)
1496 	{
1497 		eventCounter++;
1498 
1499 		{
1500 			TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_2, event, sizeof(EventWithParam_2));
1501 			if (event != NULL)
1502 			{
1503 				event->base.EventID = eventID | PARAM_COUNT(2);
1504 				event->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1505 				event->base.TS = prvGetTimestamp32();
1506 				event->param1 = (uint32_t)param1;
1507 				event->param2 = param2;
1508 				TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_2));
1509 			}
1510 		}
1511 	}
1512 	TRACE_EXIT_CRITICAL_SECTION();
1513 }
1514 
1515 /* Store an event with three 32-bit parameters */
prvTraceStoreEvent3(uint16_t eventID,uint32_t param1,uint32_t param2,uint32_t param3)1516 void prvTraceStoreEvent3(	uint16_t eventID,
1517 						uint32_t param1,
1518 						uint32_t param2,
1519 						uint32_t param3)
1520 {
1521   	TRACE_ALLOC_CRITICAL_SECTION();
1522 
1523 	PSF_ASSERT_VOID(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
1524 
1525 	TRACE_ENTER_CRITICAL_SECTION();
1526 
1527 	if (RecorderEnabled)
1528 	{
1529   		eventCounter++;
1530 
1531 		{
1532 			TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_3, event, sizeof(EventWithParam_3));
1533 			if (event != NULL)
1534 			{
1535 				event->base.EventID = eventID | PARAM_COUNT(3);
1536 				event->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1537 				event->base.TS = prvGetTimestamp32();
1538 				event->param1 = (uint32_t)param1;
1539 				event->param2 = param2;
1540 				event->param3 = param3;
1541 				TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_3));
1542 			}
1543 		}
1544 	}
1545 	TRACE_EXIT_CRITICAL_SECTION();
1546 }
1547 
1548 /* Stores an event with <nParam> 32-bit integer parameters */
prvTraceStoreEvent(int nParam,uint16_t eventID,...)1549 void prvTraceStoreEvent(int nParam, uint16_t eventID, ...)
1550 {
1551 	va_list vl;
1552 	int i;
1553     TRACE_ALLOC_CRITICAL_SECTION();
1554 
1555 	PSF_ASSERT_VOID(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
1556 
1557 	TRACE_ENTER_CRITICAL_SECTION();
1558 
1559 	if (RecorderEnabled)
1560 	{
1561 	  	int eventSize = (int)sizeof(BaseEvent) + nParam * (int)sizeof(uint32_t);
1562 
1563 		eventCounter++;
1564 
1565 		{
1566 			TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
1567 			if (event != NULL)
1568 			{
1569 				event->base.EventID = eventID | (uint16_t)PARAM_COUNT(nParam);
1570 				event->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1571 				event->base.TS = prvGetTimestamp32();
1572 
1573 				va_start(vl, eventID);
1574 				for (i = 0; i < nParam; i++)
1575 				{
1576 					uint32_t* tmp = (uint32_t*) &(event->data[i]);
1577 					*tmp = va_arg(vl, uint32_t);
1578 				}
1579 				va_end(vl);
1580 
1581 				TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
1582 			}
1583 		}
1584 	}
1585 	TRACE_EXIT_CRITICAL_SECTION();
1586 }
1587 
1588 /* Stories an event with a string and <nParam> 32-bit integer parameters */
prvTraceStoreStringEvent(int nArgs,uint16_t eventID,const char * str,...)1589 void prvTraceStoreStringEvent(int nArgs, uint16_t eventID, const char* str, ...)
1590 {
1591 	int len;
1592   	va_list vl;
1593 
1594 	if (str == 0)
1595 	{
1596 		str = "";
1597 	}
1598 
1599 	for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */
1600 
1601 	va_start(vl, str);
1602 	prvTraceStoreStringEventHelper(nArgs, eventID, NULL, len, str, vl);
1603 	va_end(vl);
1604 }
1605 
1606 /* Internal common function for storing string events */
prvTraceStoreStringEventHelper(int nArgs,uint16_t eventID,traceString userEvtChannel,int len,const char * str,va_list vl)1607 static void prvTraceStoreStringEventHelper(int nArgs,
1608 										uint16_t eventID,
1609 										traceString userEvtChannel,
1610 										int len,
1611 										const char* str,
1612 										va_list vl)
1613 {
1614   	int nWords;
1615 	int nStrWords;
1616 	int i;
1617 	int offset = 0;
1618   	TRACE_ALLOC_CRITICAL_SECTION();
1619 
1620 	/* The string length in multiples of 32 bit words (+1 for null character) */
1621 	nStrWords = (len+1+3)/4;
1622 
1623 	offset = nArgs * 4;
1624 
1625 	/* The total number of 32-bit words needed for the whole payload */
1626 	nWords = nStrWords + nArgs;
1627 
1628 	if (nWords > 15) /* if attempting to store more than 60 byte (= max) */
1629 	{
1630 		/* Truncate event if too large. The	string characters are stored
1631 		last, so usually only the string is truncated, unless there a lot
1632 		of parameters... */
1633 
1634 		/* Diagnostics ... */
1635 		uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;
1636 
1637 		if (bytesTruncated > MaxBytesTruncated)
1638 		{
1639 			MaxBytesTruncated = bytesTruncated;
1640 		}
1641 
1642 		nWords = 15;
1643 		len = 15 * 4 - offset;
1644 	}
1645 
1646 	TRACE_ENTER_CRITICAL_SECTION();
1647 
1648 	if (RecorderEnabled)
1649 	{
1650 		int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);
1651 
1652 		eventCounter++;
1653 
1654 		{
1655 			TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
1656 			if (event != NULL)
1657 			{
1658 				uint32_t* data32;
1659 				uint8_t* data8;
1660 				event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);
1661 				event->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1662 				event->base.TS = prvGetTimestamp32();
1663 
1664 				/* 32-bit write-pointer for the data argument */
1665 				data32 = (uint32_t*) &(event->data[0]);
1666 
1667 				for (i = 0; i < nArgs; i++)
1668 				{
1669 					if ((userEvtChannel != NULL) && (i == 0))
1670 					{
1671 						/* First, add the User Event Channel if not NULL */
1672 						data32[i] = (uint32_t)userEvtChannel;
1673 					}
1674 					else
1675 					{
1676 						/* Add data arguments... */
1677 						data32[i] = va_arg(vl, uint32_t);
1678 					}
1679 				}
1680 				data8 = (uint8_t*)&(event->data[0]);
1681 				for (i = 0; i < len; i++)
1682 				{
1683 					data8[offset + i] = str[i];
1684 				}
1685 
1686 				if (len < (15 * 4 - offset))
1687 					data8[offset + len] = 0;	/* Only truncate if we don't fill up the buffer completely */
1688 				TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
1689 			}
1690 		}
1691 	}
1692 
1693 	TRACE_EXIT_CRITICAL_SECTION();
1694 }
1695 
1696 /* Internal common function for storing string events without additional arguments */
prvTraceStoreSimpleStringEventHelper(uint16_t eventID,traceString userEvtChannel,const char * str)1697 void prvTraceStoreSimpleStringEventHelper(uint16_t eventID,
1698 													traceString userEvtChannel,
1699 													const char* str)
1700 {
1701 	int len;
1702   	int nWords;
1703 	int nStrWords;
1704 	int i;
1705 	int nArgs = 0;
1706 	int offset = 0;
1707   	TRACE_ALLOC_CRITICAL_SECTION();
1708 
1709 	for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */
1710 
1711 	/* The string length in multiples of 32 bit words (+1 for null character) */
1712 	nStrWords = (len+1+3)/4;
1713 
1714 	/* If a user event channel is specified, add in the list */
1715 	if (userEvtChannel)
1716 	{
1717 		nArgs++;
1718 		eventID++;
1719 	}
1720 
1721 	offset = nArgs * 4;
1722 
1723 	/* The total number of 32-bit words needed for the whole payload */
1724 	nWords = nStrWords + nArgs;
1725 
1726 	if (nWords > 15) /* if attempting to store more than 60 byte (= max) */
1727 	{
1728 		/* Truncate event if too large. The	string characters are stored
1729 		last, so usually only the string is truncated, unless there a lot
1730 		of parameters... */
1731 
1732 		/* Diagnostics ... */
1733 		uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;
1734 
1735 		if (bytesTruncated > MaxBytesTruncated)
1736 		{
1737 			MaxBytesTruncated = bytesTruncated;
1738 		}
1739 
1740 		nWords = 15;
1741 		len = 15 * 4 - offset;
1742 	}
1743 
1744 	TRACE_ENTER_CRITICAL_SECTION();
1745 
1746 	if (RecorderEnabled)
1747 	{
1748 		int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);
1749 
1750 		eventCounter++;
1751 
1752 		{
1753 			TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
1754 			if (event != NULL)
1755 			{
1756 				uint32_t* data32;
1757 				uint8_t* data8;
1758 				event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);
1759 				event->base.EventCount = (uint16_t)TRC_GET_EVENT_COUNT(eventCounter);
1760 				event->base.TS = prvGetTimestamp32();
1761 
1762 				/* 32-bit write-pointer for the data argument */
1763 				data32 = (uint32_t*) &(event->data[0]);
1764 
1765 				if (userEvtChannel != NULL)
1766 				{
1767 					/* First, add the User Event Channel if not NULL */
1768 					data32[0] = (uint32_t)userEvtChannel;
1769 				}
1770 
1771 				data8 = (uint8_t*) &(event->data[0]);
1772 				for (i = 0; i < len; i++)
1773 				{
1774 					data8[offset + i] = str[i];
1775 				}
1776 
1777 				if (len < (15 * 4 - offset))
1778 					data8[offset + len] = 0;	/* Only truncate if we don't fill up the buffer completely */
1779 				TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
1780 			}
1781 		}
1782 	}
1783 
1784 	TRACE_EXIT_CRITICAL_SECTION();
1785 }
1786 
1787 /* Saves a symbol name in the symbol table and returns the slot address */
prvTraceSaveSymbol(const char * name)1788 void* prvTraceSaveSymbol(const char *name)
1789 {
1790 	void* retVal = 0;
1791 	TRACE_ALLOC_CRITICAL_SECTION();
1792 
1793 	TRACE_ENTER_CRITICAL_SECTION();
1794 	if (firstFreeSymbolTableIndex < SYMBOL_TABLE_BUFFER_SIZE)
1795 	{
1796 		/* The address to the available symbol table slot is the address we use */
1797 		retVal = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT8[firstFreeSymbolTableIndex];
1798 		prvTraceSaveObjectSymbol(retVal, name);
1799 	}
1800 	TRACE_EXIT_CRITICAL_SECTION();
1801 
1802 	return retVal;
1803 }
1804 
1805 /* Saves a string in the symbol table for an object (task name etc.) */
prvTraceSaveObjectSymbol(void * address,const char * name)1806 void prvTraceSaveObjectSymbol(void* address, const char *name)
1807 {
1808 	uint32_t i;
1809 	uint8_t *ptrSymbol;
1810 	TRACE_ALLOC_CRITICAL_SECTION();
1811 
1812 	TRACE_ENTER_CRITICAL_SECTION();
1813 
1814 	if (name == 0)
1815 	{
1816 		name = "";
1817 	}
1818 
1819 	/* We do not look for previous entries -> changing a registered string is no longer possible */
1820 	if (firstFreeSymbolTableIndex < SYMBOL_TABLE_BUFFER_SIZE)
1821 	{
1822 		/* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
1823 		symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[firstFreeSymbolTableIndex / sizeof(uint32_t)] = (uint32_t)address;
1824 
1825 		/* We access the symbol table via the union member pSymbolTableBufferUINT8 to avoid strict-aliasing issues */
1826 		ptrSymbol = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT8[firstFreeSymbolTableIndex + sizeof(uint32_t)];
1827 		for (i = 0; i < (TRC_CFG_SYMBOL_MAX_LENGTH); i++)
1828 		{
1829 			ptrSymbol[i] = (uint8_t)name[i];	/* We do this first to ensure we also get the 0 termination, if there is one */
1830 
1831 			if (name[i] == 0)
1832 				break;
1833 		}
1834 
1835 		/* Check the length of "name", if longer than SYMBOL_MAX_LENGTH */
1836 		while ((name[i] != 0) && i < 128)
1837 		{
1838 			i++;
1839 		}
1840 
1841 		/* Remember the longest symbol name, for diagnostic purposes */
1842 		if (i > LongestSymbolName)
1843 		{
1844 			LongestSymbolName = i;
1845 		}
1846 
1847 		firstFreeSymbolTableIndex += SYMBOL_TABLE_SLOT_SIZE;
1848 	}
1849 	else
1850 	{
1851 		NoRoomForSymbol++;
1852 	}
1853 
1854 	TRACE_EXIT_CRITICAL_SECTION();
1855 }
1856 
1857 /* Deletes a symbol name (task name etc.) from symbol table */
prvTraceDeleteSymbol(void * address)1858 void prvTraceDeleteSymbol(void *address)
1859 {
1860 	uint32_t i, j;
1861 	uint32_t *ptr, *lastEntryPtr;
1862 	TRACE_ALLOC_CRITICAL_SECTION();
1863 
1864 	TRACE_ENTER_CRITICAL_SECTION();
1865 
1866 	for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)
1867 	{
1868 		/* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
1869 		ptr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];
1870 		if (*ptr == (uint32_t)address)
1871 		{
1872 			/* See if we have another entry in the table, and that this isn't already the last entry */
1873 			if (firstFreeSymbolTableIndex > SYMBOL_TABLE_SLOT_SIZE && i != (firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE))
1874 			{
1875 				/* Another entry is available, get pointer to the last one */
1876 				/* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
1877 				lastEntryPtr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[(firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t)];
1878 
1879 				/* Copy last entry to this position */
1880 				for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t); j++)
1881 				{
1882 					ptr[j] = lastEntryPtr[j];
1883 				}
1884 
1885 				/* For good measure we also zero out the original position */
1886 				*lastEntryPtr = 0;
1887 			}
1888 			else
1889 				*ptr = 0; /* No other entry found, or this is the last entry */
1890 
1891 			/* Lower index */
1892 			firstFreeSymbolTableIndex -= SYMBOL_TABLE_SLOT_SIZE;
1893 
1894 			break;
1895 		}
1896 	}
1897 
1898 	TRACE_EXIT_CRITICAL_SECTION();
1899 }
1900 
1901 /* Saves an object data entry (current task priority) in object data table */
prvTraceSaveObjectData(const void * address,uint32_t data)1902 void prvTraceSaveObjectData(const void *address, uint32_t data)
1903 {
1904 	uint32_t i;
1905 	uint32_t foundSlot;
1906 	uint32_t *ptr;
1907 	TRACE_ALLOC_CRITICAL_SECTION();
1908 
1909 	TRACE_ENTER_CRITICAL_SECTION();
1910 
1911 	foundSlot = firstFreeObjectDataTableIndex;
1912 
1913 	/* First look for previous entries using this address */
1914 	for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)
1915 	{
1916 		/* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
1917 		ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];
1918 		if (*ptr == (uint32_t)address)
1919 		{
1920 			foundSlot = i;
1921 			break;
1922 		}
1923 	}
1924 
1925 	if (foundSlot < OBJECT_DATA_TABLE_BUFFER_SIZE)
1926 	{
1927 		/* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
1928 		objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;
1929 		objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t) + 1] = data;
1930 
1931 		/* Is this the last entry in the object data table? */
1932 		if (foundSlot == firstFreeObjectDataTableIndex)
1933 		{
1934 			firstFreeObjectDataTableIndex += OBJECT_DATA_SLOT_SIZE;
1935 		}
1936 	}
1937 	else
1938 	{
1939 		NoRoomForObjectData++;
1940 	}
1941 
1942 	TRACE_EXIT_CRITICAL_SECTION();
1943 }
1944 
1945 /* Removes an object data entry (task base priority) from object data table */
prvTraceDeleteObjectData(void * address)1946 void prvTraceDeleteObjectData(void *address)
1947 {
1948 	uint32_t i, j;
1949 	uint32_t *ptr, *lastEntryPtr;
1950 	TRACE_ALLOC_CRITICAL_SECTION();
1951 
1952 	TRACE_ENTER_CRITICAL_SECTION();
1953 
1954 	for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)
1955 	{
1956 		/* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
1957 		ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];
1958 		if (*ptr == (uint32_t)address)
1959 		{
1960 			/* See if we have another entry in the table, and that this isn't already the last entry */
1961 			if (firstFreeObjectDataTableIndex > OBJECT_DATA_SLOT_SIZE && i != (firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE))
1962 			{
1963 				/* Another entry is available, get pointer to the last one */
1964 				/* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
1965 				lastEntryPtr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[(firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t)];
1966 
1967 				/* Copy last entry to this position */
1968 				for (j = 0; j < (OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t); j++)
1969 				{
1970 					ptr[j] = lastEntryPtr[j];
1971 				}
1972 
1973 				/* For good measure we also zero out the original position */
1974 				*lastEntryPtr = 0;
1975 			}
1976 			else
1977 				*ptr = 0; /* No other entry found, or this is the last entry */
1978 
1979 			/* Lower index */
1980 			firstFreeObjectDataTableIndex -= OBJECT_DATA_SLOT_SIZE;
1981 
1982 			break;
1983 		}
1984 	}
1985 
1986 	TRACE_EXIT_CRITICAL_SECTION();
1987 }
1988 
1989 /* Checks if the provided command is a valid command */
prvIsValidCommand(TracealyzerCommandType * cmd)1990 int prvIsValidCommand(TracealyzerCommandType* cmd)
1991 {
1992   	uint16_t checksum = (uint16_t)(0xFFFF - (	cmd->cmdCode +
1993 												cmd->param1 +
1994 												cmd->param2 +
1995 												cmd->param3 +
1996 												cmd->param4 +
1997 												cmd->param5));
1998 
1999 	if (cmd->checksumMSB != (unsigned char)(checksum >> 8))
2000 		return 0;
2001 
2002 	if (cmd->checksumLSB != (unsigned char)(checksum & 0xFF))
2003 		return 0;
2004 
2005 	if (cmd->cmdCode > CMD_LAST_COMMAND)
2006 		return 0;
2007 
2008 	return 1;
2009 }
2010 
2011 /* Executed the received command (Start or Stop) */
prvProcessCommand(TracealyzerCommandType * cmd)2012 void prvProcessCommand(TracealyzerCommandType* cmd)
2013 {
2014   	switch(cmd->cmdCode)
2015 	{
2016 		case CMD_SET_ACTIVE:
2017 		  	prvSetRecorderEnabled(cmd->param1);
2018 		  	break;
2019 		default:
2020 		  	break;
2021 	}
2022 }
2023 
2024 /* Called on warnings, when the recording can continue. */
prvTraceWarning(int errCode)2025 void prvTraceWarning(int errCode)
2026 {
2027 	if (GET_ERROR_WARNING_FLAG(errCode) == 0)
2028 	{
2029 		/* Will never reach this point more than once per warning type, since we verify if ErrorAndWarningFlags[errCode] has already been set */
2030 		SET_ERROR_WARNING_FLAG(errCode);
2031 
2032 		prvTraceStoreSimpleStringEventHelper(PSF_EVENT_USER_EVENT, trcWarningChannel, prvTraceGetError(errCode));
2033 	}
2034 }
2035 
2036 /* Called on critical errors in the recorder. Stops the recorder! */
prvTraceError(int errCode)2037 void prvTraceError(int errCode)
2038 {
2039 	if (errorCode == PSF_ERROR_NONE)
2040 	{
2041 		/* Will never reach this point more than once, since we verify if errorCode has already been set */
2042 		errorCode = errCode;
2043 		SET_ERROR_WARNING_FLAG(errorCode);
2044 
2045 		prvTraceStoreSimpleStringEventHelper(PSF_EVENT_USER_EVENT, trcWarningChannel, prvTraceGetError(errorCode));
2046 		prvTraceStoreSimpleStringEventHelper(PSF_EVENT_USER_EVENT, trcWarningChannel, "Recorder stopped in prvTraceError()");
2047 
2048 		prvSetRecorderEnabled(0);
2049 	}
2050 }
2051 
2052 /* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */
2053 #ifndef TRC_CFG_ARM_CM_USE_SYSTICK
2054 #if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03)))
2055 
prvTraceInitCortexM()2056 void prvTraceInitCortexM()
2057 {
2058 	/* Make sure the DWT registers are unlocked, in case the debugger doesn't do this. */
2059 	TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK;
2060 
2061 	/* Make sure DWT is enabled is enabled, if supported */
2062 	TRC_REG_DEMCR |= TRC_DEMCR_TRCENA;
2063 
2064 	do
2065 	{
2066 		/* Verify that DWT is supported */
2067 		if (TRC_REG_DEMCR == 0)
2068 		{
2069 			/* This function is called on Cortex-M3, M4 and M7 devices to initialize
2070 			the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
2071 
2072 			If the below error is produced, the DWT unit does not seem to be available.
2073 
2074 			In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
2075 			to use SysTick timestamping instead, or define your own timestamping by
2076 			setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
2077 			and make the necessary definitions, as explained in trcHardwarePort.h.*/
2078 
2079 			prvTraceError(PSF_ERROR_DWT_NOT_SUPPORTED);
2080 			break;
2081 		}
2082 
2083 		/* Verify that DWT_CYCCNT is supported */
2084 		if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT)
2085 		{
2086 			/* This function is called on Cortex-M3, M4 and M7 devices to initialize
2087 			the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
2088 
2089 			If the below error is produced, the cycle counter does not seem to be available.
2090 
2091 			In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
2092 			to use SysTick timestamping instead, or define your own timestamping by
2093 			setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
2094 			and make the necessary definitions, as explained in trcHardwarePort.h.*/
2095 
2096 			prvTraceError(PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED);
2097 			break;
2098 		}
2099 
2100 		/* Reset the cycle counter */
2101 		TRC_REG_DWT_CYCCNT = 0;
2102 
2103 		/* Enable the cycle counter */
2104 		TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA;
2105 
2106 	} while(0);	/* breaks above jump here */
2107 }
2108 #endif
2109 #endif
2110 
2111 /* Performs timestamping using definitions in trcHardwarePort.h */
prvGetTimestamp32(void)2112 static uint32_t prvGetTimestamp32(void)
2113 {
2114 #if ((TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR) || (TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR))
2115 	return TRC_HWTC_COUNT;
2116 #endif
2117 
2118 #if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR))
2119 	return TRC_HWTC_COUNT;
2120 #endif
2121 
2122 #if ((TRC_HWTC_TYPE == TRC_OS_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR))
2123 	uint32_t ticks = TRACE_GET_OS_TICKS();
2124 	return ((TRC_HWTC_COUNT) & 0x00FFFFFFU) + ((ticks & 0x000000FFU) << 24);
2125 #endif
2126 }
2127 
2128 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
2129 
prvAddTaskToStackMonitor(void * task)2130 void prvAddTaskToStackMonitor(void* task)
2131 {
2132 	int i;
2133 	int foundEmptySlot = 0;
2134 
2135 	// find an empty slot
2136 	for (i = 0; i < TRC_CFG_STACK_MONITOR_MAX_TASKS; i++)
2137 	{
2138 		if (tasksInStackMonitor[i].tcb == 0)
2139 		{
2140 			tasksInStackMonitor[i].tcb = task;
2141 			tasksInStackMonitor[i].uiPreviousLowMark = 0xFFFFFFFF;
2142 			foundEmptySlot = 1;
2143 			break;
2144 		}
2145 	}
2146 
2147 	if (foundEmptySlot == 0)
2148 	{
2149 		TaskStacksNotIncluded++;
2150 	}
2151 }
2152 
prvRemoveTaskFromStackMonitor(void * task)2153 void prvRemoveTaskFromStackMonitor(void* task)
2154 {
2155 	int i;
2156 
2157 	for (i = 0; i < TRC_CFG_STACK_MONITOR_MAX_TASKS; i++)
2158 	{
2159 		if (tasksInStackMonitor[i].tcb == task)
2160 		{
2161 			tasksInStackMonitor[i].tcb = NULL;
2162 			tasksInStackMonitor[i].uiPreviousLowMark = 0;
2163 		}
2164 	}
2165 }
2166 
prvReportStackUsage()2167 void prvReportStackUsage()
2168 {
2169 	static int i = 0;	/* Static index used to loop over the monitored tasks */
2170 	int count = 0;		/* The number of generated reports */
2171 	int initial = i;	/* Used to make sure we break if we are back at the inital value */
2172 
2173 	do
2174 	{
2175 		/* Check the current spot */
2176 		if (tasksInStackMonitor[i].tcb != NULL)
2177 		{
2178 			/* Get the amount of unused stack */
2179 			uint32_t unusedStackSpace = prvTraceGetStackHighWaterMark(tasksInStackMonitor[i].tcb);
2180 
2181 			/* Store for later use */
2182 			if (tasksInStackMonitor[i].uiPreviousLowMark > unusedStackSpace)
2183 				tasksInStackMonitor[i].uiPreviousLowMark = unusedStackSpace;
2184 
2185 			prvTraceStoreEvent2(PSF_EVENT_UNUSED_STACK, (uint32_t)tasksInStackMonitor[i].tcb, tasksInStackMonitor[i].uiPreviousLowMark);
2186 
2187 			count++;
2188 		}
2189 
2190 		i = (i + 1) % TRC_CFG_STACK_MONITOR_MAX_TASKS; // Move i beyond this task
2191 	} while (count < TRC_CFG_STACK_MONITOR_MAX_REPORTS && i != initial);
2192 }
2193 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
2194 
2195 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
2196 
2197 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
2198