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