1 /*
2 * Trace Recorder for Tracealyzer v4.6.6
3 * Copyright 2021 Percepio AB
4 * www.percepio.com
5 *
6 * SPDX-License-Identifier: Apache-2.0
7 *
8 * The generic core of the trace recorder's snapshot mode.
9 */
10
11 #include <trcRecorder.h>
12
13 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)
14
15 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
16
17 #include <string.h>
18 #include <stdarg.h>
19
20 #ifndef TRC_CFG_RECORDER_DATA_INIT
21 #define TRC_CFG_RECORDER_DATA_INIT 1
22 #endif
23
24 #if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR))
25 #error "CUSTOM timestamping mode is not (yet) supported in snapshot mode!"
26 #endif
27
28 /* DO NOT CHANGE */
29 #define TRACE_MINOR_VERSION 7
30
31 /* Keeps track of the task's stack low mark */
32 typedef struct {
33 void* tcb;
34 uint32_t uiPreviousLowMark;
35 } TaskStackMonitorEntry_t;
36
37 TraceKernelPortDataBuffer_t xKernelPortDataBuffer;
38
39 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
40 /*******************************************************************************
41 * isrstack
42 *
43 * Keeps track of nested interrupts.
44 ******************************************************************************/
45 static traceHandle isrstack[TRC_CFG_MAX_ISR_NESTING];
46
47 /*******************************************************************************
48 * isPendingContextSwitch
49 *
50 * Used to indicate if there is a pending context switch.
51 * If there is a pending context switch the recorder will not create an event
52 * when returning from the ISR.
53 ******************************************************************************/
54 int32_t isPendingContextSwitch = 0;
55 #endif /* (TRC_CFG_INCLUDE_ISR_TRACING == 1) */
56
57 /*******************************************************************************
58 * readyEventsEnabled
59 *
60 * This can be used to dynamically disable ready events.
61 ******************************************************************************/
62 #if !defined TRC_CFG_INCLUDE_READY_EVENTS || TRC_CFG_INCLUDE_READY_EVENTS == 1
63 static int readyEventsEnabled = 1;
64 #endif /*!defined TRC_CFG_INCLUDE_READY_EVENTS || TRC_CFG_INCLUDE_READY_EVENTS == 1*/
65
66 /*******************************************************************************
67 * uiTraceTickCount
68 *
69 * This variable is should be updated by the Kernel tick interrupt. This does
70 * not need to be modified when developing a new timer port. It is preferred to
71 * keep any timer port changes in the HWTC macro definitions, which typically
72 * give sufficient flexibility.
73 ******************************************************************************/
74 uint32_t uiTraceTickCount = 0;
75
76 /*******************************************************************************
77 * trace_disable_timestamp
78 *
79 * This can be used to disable timestamps as it will cause
80 * prvTracePortGetTimeStamp() to return the previous timestamp.
81 ******************************************************************************/
82 uint32_t trace_disable_timestamp = 0;
83
84 /*******************************************************************************
85 * last_timestamp
86 *
87 * The most recent timestamp.
88 ******************************************************************************/
89 static uint32_t last_timestamp = 0;
90
91 /*******************************************************************************
92 * uiTraceSystemState
93 *
94 * Indicates if we are currently performing a context switch or just running application code.
95 ******************************************************************************/
96 volatile uint32_t uiTraceSystemState = TRC_STATE_IN_STARTUP;
97
98 /*******************************************************************************
99 * recorder_busy
100 *
101 * Flag that shows if inside a critical section of the recorder.
102 ******************************************************************************/
103 volatile int recorder_busy = 0;
104
105 /*******************************************************************************
106 * timestampFrequency
107 *
108 * Holds the value set by vTraceSetFrequency.
109 ******************************************************************************/
110 uint32_t timestampFrequency = 0;
111
112 /*******************************************************************************
113 * nISRactive
114 *
115 * The number of currently active (including preempted) ISRs.
116 ******************************************************************************/
117 int8_t nISRactive = 0;
118
119 /*******************************************************************************
120 * handle_of_last_logged_task
121 *
122 * The current task.
123 ******************************************************************************/
124 traceHandle handle_of_last_logged_task = 0;
125
126 /*******************************************************************************
127 * vTraceStopHookPtr
128 *
129 * Called when the recorder is stopped, set by vTraceSetStopHook.
130 ******************************************************************************/
131 TRACE_STOP_HOOK vTraceStopHookPtr = (TRACE_STOP_HOOK)0;
132
133 /*******************************************************************************
134 * init_hwtc_count
135 *
136 * Initial TRC_HWTC_COUNT value, for detecting if the time-stamping source is
137 * enabled. If using the OS periodic timer for time-stamping, this might not
138 * have been configured on the earliest events during the startup.
139 ******************************************************************************/
140 uint32_t init_hwtc_count;
141
142 /*******************************************************************************
143 * CurrentFilterMask
144 *
145 * The filter mask that will be checked against each object's FilterGroup to see
146 * if they should be included in the trace or not.
147 ******************************************************************************/
148 uint16_t CurrentFilterMask TRC_CFG_RECORDER_DATA_ATTRIBUTE;
149
150 /*******************************************************************************
151 * CurrentFilterGroup
152 *
153 * The current filter group that will be assigned to newly created objects.
154 ******************************************************************************/
155 uint16_t CurrentFilterGroup TRC_CFG_RECORDER_DATA_ATTRIBUTE;
156
157 /*******************************************************************************
158 * objectHandleStacks
159 *
160 * A set of stacks that keeps track of available object handles for each class.
161 * The stacks are empty initially, meaning that allocation of new handles will be
162 * based on a counter (for each object class). Any delete operation will
163 * return the handle to the corresponding stack, for reuse on the next allocate.
164 ******************************************************************************/
165 objectHandleStackType objectHandleStacks TRC_CFG_RECORDER_DATA_ATTRIBUTE;
166
167 /*******************************************************************************
168 * traceErrorMessage
169 *
170 * The last error message of the recorder. NULL if no error message.
171 ******************************************************************************/
172 const char* traceErrorMessage TRC_CFG_RECORDER_DATA_ATTRIBUTE;
173
174 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
175 /*******************************************************************************
176 * tasksInStackMonitor
177 *
178 * Keeps track of all stack low marks for tasks.
179 ******************************************************************************/
180 TaskStackMonitorEntry_t tasksInStackMonitor[TRC_CFG_STACK_MONITOR_MAX_TASKS] TRC_CFG_RECORDER_DATA_ATTRIBUTE;
181
182 /*******************************************************************************
183 * tasksNotIncluded
184 *
185 * The number of tasks that did not fit in the stack monitor.
186 ******************************************************************************/
187 int tasksNotIncluded TRC_CFG_RECORDER_DATA_ATTRIBUTE;
188 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
189
190 /*******************************************************************************
191 * RecorderData
192 *
193 * The main data structure in snapshot mode, when using the default static memory
194 * allocation (TRC_RECORDER_BUFFER_ALLOCATION_STATIC). The recorder uses a pointer
195 * RecorderDataPtr to access the data, to also allow for dynamic or custom data
196 * allocation (see TRC_CFG_RECORDER_BUFFER_ALLOCATION).
197 ******************************************************************************/
198 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC)
199 RecorderDataType RecorderData TRC_CFG_RECORDER_DATA_ATTRIBUTE;
200 #endif
201
202 /* Pointer to the main data structure, when in snapshot mode */
203 RecorderDataType* RecorderDataPtr TRC_CFG_RECORDER_DATA_ATTRIBUTE;
204
205 #if (TRC_CFG_RECORDER_DATA_INIT != 0)
206 uint32_t RecorderInitialized = 0;
207 #else /* (TRC_CFG_RECORDER_DATA_INIT != 0) */
208 uint32_t RecorderInitialized TRC_CFG_RECORDER_DATA_ATTRIBUTE;
209 #endif /* (TRC_CFG_RECORDER_DATA_INIT != 0) */
210
211 /*************** Private Functions *******************************************/
212 static void prvStrncpy(char* dst, const char* src, uint32_t maxLength);
213 static uint8_t prvTraceGetObjectState(uint8_t objectclass, traceHandle id);
214 static void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength);
215 static void* prvTraceNextFreeEventBufferSlot(void);
216 static uint16_t prvTraceGetDTS(uint16_t param_maxDTS);
217 static TraceStringHandle_t prvTraceOpenSymbol(const char* name, TraceStringHandle_t userEventChannel);
218 static void prvTraceUpdateCounters(void);
219
220 void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t signed_size);
221
222 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)
223 static void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nEntries);
224 #endif
225
226 static TraceStringHandle_t prvTraceCreateSymbolTableEntry(const char* name,
227 uint8_t crc6,
228 uint8_t len,
229 TraceStringHandle_t channel);
230
231 static TraceStringHandle_t prvTraceLookupSymbolTableEntry(const char* name,
232 uint8_t crc6,
233 uint8_t len,
234 TraceStringHandle_t channel);
235
236
237 #if (TRC_CFG_INCLUDE_ISR_TRACING == 0)
238 /* ISR tracing is turned off */
239 void prvTraceIncreaseISRActive(void);
240 void prvTraceDecreaseISRActive(void);
241 #endif /*(TRC_CFG_INCLUDE_ISR_TRACING == 0)*/
242
243 #if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1)
244 static uint8_t prvTraceGet8BitHandle(traceHandle handle);
245 #else
246 #define prvTraceGet8BitHandle(x) ((uint8_t)x)
247 #endif
248
249 #if (TRC_CFG_SCHEDULING_ONLY == 0)
250 static uint32_t prvTraceGetParam(uint32_t, uint32_t);
251 #endif
252
253 /*******************************************************************************
254 * prvTracePortGetTimeStamp
255 *
256 * Returns the current time based on the HWTC macros which provide a hardware
257 * isolation layer towards the hardware timer/counter.
258 *
259 * The HWTC macros and prvTracePortGetTimeStamp is the main porting issue
260 * or the trace recorder library. Typically you should not need to change
261 * the code of prvTracePortGetTimeStamp if using the HWTC macros.
262 *
263 ******************************************************************************/
264 void prvTracePortGetTimeStamp(uint32_t *puiTimestamp);
265
266 static void prvTraceTaskInstanceFinish(int8_t direct);
267
268 /*******************************************************************************
269 * prvTraceInitTimestamps
270 *
271 * This will only be called once the recorder is started, and we can assume that
272 * all hardware has been initialized.
273 ******************************************************************************/
274 static void prvTraceInitTimestamps(void);
275
276 static void prvTraceStart(void);
277
278 static void prvTraceStop(void);
279
280 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
281 #if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)
282 static void vTraceUBData_Helper(traceUBChannel channelPair, va_list vl);
283 static void prvTraceUBHelper1(traceUBChannel channel, TraceStringHandle_t eventLabel, TraceStringHandle_t formatLabel, va_list vl);
284 static void prvTraceUBHelper2(traceUBChannel channel, uint32_t* data, uint32_t noOfSlots);
285 #endif /* (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) */
286 #endif /* ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) */
287
288 uint16_t uiIndexOfObject(traceHandle objecthandle, uint8_t objectclass);
289
290 /*******************************************************************************
291 * prvTraceError
292 *
293 * Called by various parts in the recorder. Stops the recorder and stores a
294 * pointer to an error message, which is printed by the monitor task.
295 ******************************************************************************/
296 void prvTraceError(const char* msg);
297
298 /********* Public Functions **************************************************/
299
300 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)
xTraceSetBuffer(TraceRecorderDataBuffer_t * pxBuffer)301 traceResult xTraceSetBuffer(TraceRecorderDataBuffer_t* pxBuffer)
302 {
303 if (pxBuffer == 0)
304 {
305 return TRC_FAIL;
306 }
307
308 RecorderDataPtr = (RecorderDataType*)pxBuffer;
309
310 return TRC_SUCCESS;
311 }
312 #endif
313
xTraceGetEventBuffer(void ** ppvBuffer,TraceUnsignedBaseType_t * puiSize)314 traceResult xTraceGetEventBuffer(void** ppvBuffer, TraceUnsignedBaseType_t* puiSize)
315 {
316 if (ppvBuffer == 0 || puiSize == 0)
317 {
318 return TRC_FAIL;
319 }
320
321 *ppvBuffer = (void*)RecorderDataPtr;
322 *puiSize = sizeof(RecorderDataType);
323
324 return TRC_SUCCESS;
325 }
326
xTraceEnable(uint32_t uiStartOption)327 traceResult xTraceEnable(uint32_t uiStartOption)
328 {
329 /* Make sure recorder data is initialized */
330 if (xTraceInitialize() == TRC_FAIL)
331 {
332 return TRC_FAIL;
333 }
334
335 if (uiStartOption == TRC_START)
336 {
337 if (xTraceKernelPortEnable() == TRC_FAIL)
338 {
339 return TRC_FAIL;
340 }
341
342 prvTraceInitTimestamps();
343
344 prvTraceStart();
345 }
346 else if (uiStartOption == TRC_START_AWAIT_HOST)
347 {
348 prvTraceError("xTraceEnable(TRC_START_AWAIT_HOST) not allowed in Snapshot mode");
349
350 return TRC_FAIL;
351 }
352 else if (uiStartOption != TRC_START_FROM_HOST)
353 {
354 prvTraceError("xTraceEnable(TRC_START_FROM_HOST) not allowed in Snapshot mode");
355
356 return TRC_FAIL;
357 }
358
359 return TRC_SUCCESS;
360 }
361
362
xTraceDisable(void)363 traceResult xTraceDisable(void)
364 {
365 prvTraceStop();
366
367 return TRC_SUCCESS;
368 }
369
vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction)370 void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction)
371 {
372 vTraceStopHookPtr = stopHookFunction;
373 }
374
vTraceClear(void)375 void vTraceClear(void)
376 {
377 TRACE_ALLOC_CRITICAL_SECTION();
378 trcCRITICAL_SECTION_BEGIN();
379 RecorderDataPtr->absTimeLastEventSecond = 0;
380 RecorderDataPtr->absTimeLastEvent = 0;
381 RecorderDataPtr->nextFreeIndex = 0;
382 RecorderDataPtr->numEvents = 0;
383 RecorderDataPtr->bufferIsFull = 0;
384 traceErrorMessage = 0;
385 RecorderDataPtr->internalErrorOccured = 0;
386 (void)memset(RecorderDataPtr->eventData, 0, RecorderDataPtr->maxEvents * 4);
387 handle_of_last_logged_task = 0;
388 trcCRITICAL_SECTION_END();
389 }
390
prvTraceStart(void)391 static void prvTraceStart(void)
392 {
393 traceHandle handle;
394 TRACE_ALLOC_CRITICAL_SECTION();
395
396 handle = 0;
397
398 if (RecorderDataPtr == 0)
399 {
400 TRACE_ASSERT(RecorderDataPtr != 0, "Recorder not initialized. Use vTraceEnable() instead!", TRC_UNUSED);
401 return;
402 }
403
404 if (RecorderDataPtr->recorderActive == 1)
405 return; /* Already running */
406
407 if (traceErrorMessage == 0)
408 {
409 trcCRITICAL_SECTION_BEGIN();
410 RecorderDataPtr->recorderActive = 1;
411
412 handle = TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK());
413 if (handle == 0)
414 {
415 /* This occurs if the scheduler is not yet started.
416 This creates a dummy "(startup)" task entry internally in the
417 recorder */
418 handle = prvTraceGetObjectHandle(TRACE_CLASS_TASK);
419 prvTraceSetObjectName(TRACE_CLASS_TASK, handle, "(startup)");
420
421 prvTraceSetPriorityProperty(TRACE_CLASS_TASK, handle, 0);
422 }
423
424 prvTraceStoreTaskswitch(handle); /* Register the currently running task */
425 trcCRITICAL_SECTION_END();
426 }
427 }
428
429 /*******************************************************************************
430 * prvTraceStop
431 *
432 * Stops the recorder. The recording can be resumed by calling vTraceStart.
433 * This does not reset the recorder. Use vTraceClear if that is desired.
434 ******************************************************************************/
prvTraceStop(void)435 static void prvTraceStop(void)
436 {
437 if (RecorderDataPtr != 0)
438 {
439 RecorderDataPtr->recorderActive = 0;
440 }
441
442 if (vTraceStopHookPtr != (TRACE_STOP_HOOK)0)
443 {
444 (*vTraceStopHookPtr)(); /* An application call-back function. */
445 }
446 }
447
448 /*******************************************************************************
449 * xTraceIsRecorderEnabled
450 * Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0.
451 ******************************************************************************/
xTraceIsRecorderEnabled(void)452 uint32_t xTraceIsRecorderEnabled(void)
453 {
454 if (RecorderInitialized == 1 && RecorderDataPtr != 0)
455 {
456 return RecorderDataPtr->recorderActive;
457 }
458 else
459 {
460 return 0;
461 }
462 }
463
464 /******************************************************************************
465 * xTraceIsRecorderInitialized
466 *
467 * Returns true (1) if the recorder is initialized.
468 ******************************************************************************/
xTraceIsRecorderInitialized(void)469 uint32_t xTraceIsRecorderInitialized(void)
470 {
471 return RecorderInitialized;
472 }
473
474 /*******************************************************************************
475 * xTraceErrorGetLast
476 *
477 * Gives the last error message, if any. NULL if no error message is stored.
478 * Any error message is also presented when opening a trace file.
479 ******************************************************************************/
xTraceErrorGetLast(void)480 const char* xTraceErrorGetLast(void)
481 {
482 return traceErrorMessage;
483 }
484
485 /*******************************************************************************
486 * vTraceClearError
487 *
488 * Removes any previous error message generated by recorder calling prvTraceError.
489 * By calling this function, it may be possible to start/restart the trace
490 * despite errors in the recorder, but there is no guarantee that the trace
491 * recorder will work correctly in that case, depending on the type of error.
492 ******************************************************************************/
vTraceClearError(void)493 void vTraceClearError(void)
494 {
495 traceErrorMessage = 0;
496 if (RecorderDataPtr != 0)
497 {
498 RecorderDataPtr->internalErrorOccured = 0;
499 }
500 }
501
502 /*******************************************************************************
503 * xTraceGetTraceBuffer
504 *
505 * Returns a pointer to the recorder data structure. Use this together with
506 * uiTraceGetTraceBufferSize if you wish to implement an own store/upload
507 * solution, e.g., in case a debugger connection is not available for uploading
508 * the data.
509 ******************************************************************************/
xTraceGetTraceBuffer(void)510 void* xTraceGetTraceBuffer(void)
511 {
512 return RecorderDataPtr;
513 }
514
515 /*******************************************************************************
516 * uiTraceGetTraceBufferSize
517 *
518 * Gets the size of the recorder data structure. For use together with
519 * vTraceGetTraceBuffer if you wish to implement an own store/upload solution,
520 * e.g., in case a debugger connection is not available for uploading the data.
521 ******************************************************************************/
uiTraceGetTraceBufferSize(void)522 uint32_t uiTraceGetTraceBufferSize(void)
523 {
524 return sizeof(RecorderDataType);
525 }
526
527 /*******************************************************************************
528 * prvTraceInitTimestamps
529 *
530 * If vTraceEnable(TRC_INIT) was called BEFORE the clock was initialized, this
531 * function must be called AFTER the clock is initialized to set a proper
532 * initial timestamp value. If vTraceEnable(...) is only called AFTER clock is
533 * initialized, there is no need to call this function.
534 ******************************************************************************/
prvTraceInitTimestamps(void)535 static void prvTraceInitTimestamps(void)
536 {
537 init_hwtc_count = TRC_HWTC_COUNT;
538 }
539
540 /******************************************************************************
541 * prvTraceTaskInstanceFinish
542 *
543 * Private common function for the vTraceTaskInstanceFinishXXX functions.
544 *****************************************************************************/
prvTraceTaskInstanceFinish(int8_t direct)545 static void prvTraceTaskInstanceFinish(int8_t direct)
546 {
547 TaskInstanceStatusEvent* tis;
548 uint8_t dts45;
549
550 TRACE_ALLOC_CRITICAL_SECTION();
551
552 trcCRITICAL_SECTION_BEGIN();
553 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
554 {
555 dts45 = (uint8_t)prvTraceGetDTS(0xFF);
556 tis = (TaskInstanceStatusEvent*) prvTraceNextFreeEventBufferSlot();
557 if (tis != 0)
558 {
559 if (direct == 0)
560 tis->type = TASK_INSTANCE_FINISHED_NEXT_KSE;
561 else
562 tis->type = TASK_INSTANCE_FINISHED_DIRECT;
563
564 tis->dts = dts45;
565 prvTraceUpdateCounters();
566 }
567 }
568 trcCRITICAL_SECTION_END();
569 }
570
571 /******************************************************************************
572 * xTraceTaskInstanceFinishedNext(void)
573 *
574 * Marks the current task instance as finished on the next kernel call.
575 *
576 * If that kernel call is blocking, the instance ends after the blocking event
577 * and the corresponding return event is then the start of the next instance.
578 * If the kernel call is not blocking, the viewer instead splits the current
579 * fragment right before the kernel call, which makes this call the first event
580 * of the next instance.
581 *
582 * See also TRC_CFG_USE_IMPLICIT_IFE_RULES in trcConfig.h
583 *
584 * Example:
585 *
586 * while(1)
587 * {
588 * xQueueReceive(CommandQueue, &command, timeoutDuration);
589 * processCommand(command);
590 * xTraceTaskInstanceFinishedNext();
591 * }
592 *****************************************************************************/
xTraceTaskInstanceFinishedNext(void)593 traceResult xTraceTaskInstanceFinishedNext(void)
594 {
595 prvTraceTaskInstanceFinish(0);
596
597 return TRC_SUCCESS;
598 }
599
600 /******************************************************************************
601 * xTraceTaskInstanceFinishedNow(void)
602 *
603 * Marks the current task instance as finished at this very instant.
604 * This makes the viewer to splits the current fragment at this point and begin
605 * a new actor instance.
606 *
607 * See also TRC_CFG_USE_IMPLICIT_IFE_RULES in trcConfig.h
608 *
609 * Example:
610 *
611 * This example will generate two instances for each loop iteration.
612 * The first instance ends at xTraceTaskInstanceFinishedNow(), while the second
613 * instance ends at the next xQueueReceive call.
614 *
615 * while (1)
616 * {
617 * xQueueReceive(CommandQueue, &command, timeoutDuration);
618 * ProcessCommand(command);
619 * xTraceTaskInstanceFinishedNow();
620 * DoSometingElse();
621 * xTraceTaskInstanceFinishedNext();
622 * }
623 *****************************************************************************/
xTraceTaskInstanceFinishedNow(void)624 traceResult xTraceTaskInstanceFinishedNow(void)
625 {
626 prvTraceTaskInstanceFinish(1);
627
628 return TRC_SUCCESS;
629 }
630
631 /*******************************************************************************
632 * Interrupt recording functions
633 ******************************************************************************/
634
635 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
636
xTraceISRRegister(const char * szName,uint32_t uiPriority,TraceISRHandle_t * pxISRHandle)637 traceResult xTraceISRRegister(const char* szName, uint32_t uiPriority, TraceISRHandle_t* pxISRHandle)
638 {
639 static TraceISRHandle_t xISRHandle = 0;
640
641 TRACE_ASSERT(RecorderDataPtr != 0, "Recorder not initialized, call vTraceEnable() first!", TRC_FAIL);
642 TRACE_ASSERT(xISRHandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "xTraceSetISRProperties: Invalid value for handle", TRC_FAIL);
643 TRACE_ASSERT(szName != 0, "xTraceSetISRProperties: name == NULL", TRC_FAIL);
644
645 xISRHandle++;
646
647 prvTraceSetObjectName(TRACE_CLASS_ISR, xISRHandle, szName);
648 prvTraceSetPriorityProperty(TRACE_CLASS_ISR, xISRHandle, uiPriority);
649
650 *pxISRHandle = xISRHandle;
651
652 return TRC_SUCCESS;
653 }
654
xTraceSetISRProperties(const char * szName,uint8_t uiPriority)655 traceHandle xTraceSetISRProperties(const char* szName, uint8_t uiPriority)
656 {
657 TraceISRHandle_t xISRHandle;
658
659 xTraceISRRegister(szName, uiPriority, &xISRHandle);
660
661 return xISRHandle;
662 }
663
xTraceISRBegin(TraceISRHandle_t handle)664 traceResult xTraceISRBegin(TraceISRHandle_t handle)
665 {
666 TRACE_ALLOC_CRITICAL_SECTION();
667
668 if (recorder_busy)
669 {
670 /*************************************************************************
671 * This occurs if an ISR calls a trace function, preempting a previous
672 * trace call that is being processed in a different ISR or task.
673 * If this occurs, there is probably a problem in the definition of the
674 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and
675 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt
676 * and any other ISRs that calls the trace recorder directly or via
677 * traced kernel functions. The ARM port disables all interrupts using the
678 * PRIMASK register to avoid this issue.
679 *************************************************************************/
680 prvTraceError("vTraceStoreISRBegin - recorder busy! See code comment.");
681 return TRC_FAIL;
682 }
683
684 trcCRITICAL_SECTION_BEGIN();
685
686 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
687 {
688 uint16_t dts4;
689
690 TRACE_ASSERT(handle != 0, "vTraceStoreISRBegin: Invalid ISR handle (NULL)", TRC_FAIL);
691 TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid ISR handle (> NISR)", TRC_FAIL);
692
693 dts4 = (uint16_t)prvTraceGetDTS(0xFFFF);
694
695 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
696 {
697 if (nISRactive < TRC_CFG_MAX_ISR_NESTING)
698 {
699 TSEvent* ts;
700 uint8_t hnd8 = prvTraceGet8BitHandle(handle);
701 isrstack[nISRactive] = handle;
702 nISRactive++;
703 ts = (TSEvent*)prvTraceNextFreeEventBufferSlot();
704 if (ts != 0)
705 {
706 ts->type = TS_ISR_BEGIN;
707 ts->dts = dts4;
708 ts->objHandle = hnd8;
709 prvTraceUpdateCounters();
710 }
711 }
712 else
713 {
714 /* This should not occur unless something is very wrong */
715 prvTraceError("Too many nested interrupts!");
716 }
717 }
718 }
719
720 trcCRITICAL_SECTION_END();
721
722 return TRC_SUCCESS;
723 }
724
xTraceISREnd(int pendingISR)725 traceResult xTraceISREnd(int pendingISR)
726 {
727 TSEvent* ts;
728 uint16_t dts5;
729 uint8_t hnd8 = 0, type = 0;
730
731 TRACE_ALLOC_CRITICAL_SECTION();
732
733 if (! RecorderDataPtr->recorderActive || ! handle_of_last_logged_task)
734 {
735 return TRC_SUCCESS;
736 }
737
738 if (recorder_busy)
739 {
740 /*************************************************************************
741 * This occurs if an ISR calls a trace function, preempting a previous
742 * trace call that is being processed in a different ISR or task.
743 * If this occurs, there is probably a problem in the definition of the
744 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and
745 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt
746 * and any other ISRs that calls the trace recorder directly or via
747 * traced kernel functions. The ARM port disables all interrupts using the
748 * PRIMASK register to avoid this issue.
749 *************************************************************************/
750 prvTraceError("vTraceStoreISREnd - recorder busy! See code comment.");
751 return TRC_FAIL;
752 }
753
754 if (nISRactive == 0)
755 {
756 prvTraceError("Unmatched call to vTraceStoreISREnd (nISRactive == 0, expected > 0)");
757 return TRC_FAIL;
758 }
759
760 trcCRITICAL_SECTION_BEGIN();
761
762 isPendingContextSwitch |= pendingISR; /* Is there a pending context switch right now? If so, we will not create an event since we will get an event when that context switch is executed. */
763 nISRactive--;
764 if (nISRactive > 0)
765 {
766 /* Return to another ISR */
767 type = TS_ISR_RESUME;
768 hnd8 = prvTraceGet8BitHandle(isrstack[nISRactive - 1]); /* isrstack[nISRactive] is the handle of the ISR we're currently exiting. isrstack[nISRactive - 1] is the handle of the ISR that was executing previously. */
769 }
770 else if ((isPendingContextSwitch == 0) || (xTraceKernelPortIsSchedulerSuspended()))
771 {
772 /* Return to interrupted task, if no context switch will occur in between. */
773 type = TS_TASK_RESUME;
774 hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task);
775 }
776
777 if (type != 0)
778 {
779 dts5 = (uint16_t)prvTraceGetDTS(0xFFFF);
780 ts = (TSEvent*)prvTraceNextFreeEventBufferSlot();
781 if (ts != 0)
782 {
783 ts->type = type;
784 ts->objHandle = hnd8;
785 ts->dts = dts5;
786 prvTraceUpdateCounters();
787 }
788 }
789
790 trcCRITICAL_SECTION_END();
791
792 return TRC_SUCCESS;
793 }
794
795 #else
796
797 /* ISR tracing is turned off */
prvTraceIncreaseISRActive(void)798 void prvTraceIncreaseISRActive(void)
799 {
800 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
801 nISRactive++;
802 }
803
prvTraceDecreaseISRActive(void)804 void prvTraceDecreaseISRActive(void)
805 {
806 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
807 nISRactive--;
808 }
809 #endif /* (TRC_CFG_INCLUDE_ISR_TRACING == 1)*/
810
811
812 /********************************************************************************/
813 /* User Event functions */
814 /********************************************************************************/
815
816 #define MAX_ARG_SIZE (4+32)
817
818 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
writeInt8(void * buffer,uint8_t i,uint8_t value)819 static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value)
820 {
821 TRACE_ASSERT(buffer != 0, "writeInt8: buffer == NULL", 0);
822
823 if (i >= MAX_ARG_SIZE)
824 {
825 return 255;
826 }
827
828 ((uint8_t*)buffer)[i] = value;
829
830 if (i + 1 > MAX_ARG_SIZE)
831 {
832 return 255;
833 }
834
835 return ((uint8_t) (i + 1));
836 }
837 #endif
838
839 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
writeInt16(void * buffer,uint8_t i,uint16_t value)840 static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value)
841 {
842 TRACE_ASSERT(buffer != 0, "writeInt16: buffer == NULL", 0);
843
844 /* Align to multiple of 2 */
845 while ((i % 2) != 0)
846 {
847 if (i >= MAX_ARG_SIZE)
848 {
849 return 255;
850 }
851
852 ((uint8_t*)buffer)[i] = 0;
853 i++;
854 }
855
856 if (i + 2 > MAX_ARG_SIZE)
857 {
858 return 255;
859 }
860
861 ((uint16_t*)buffer)[i/2] = value;
862
863 return ((uint8_t) (i + 2));
864 }
865 #endif
866
867 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
writeInt32(void * buffer,uint8_t i,uint32_t value)868 static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value)
869 {
870 TRACE_ASSERT(buffer != 0, "writeInt32: buffer == NULL", 0);
871
872 /* A 32 bit value should begin at an even 4-byte address */
873 while ((i % 4) != 0)
874 {
875 if (i >= MAX_ARG_SIZE)
876 {
877 return 255;
878 }
879
880 ((uint8_t*)buffer)[i] = 0;
881 i++;
882 }
883
884 if (i + 4 > MAX_ARG_SIZE)
885 {
886 return 255;
887 }
888
889 ((uint32_t*)buffer)[i/4] = value;
890
891 return ((uint8_t) (i + 4));
892 }
893 #endif
894
895 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_INCLUDE_FLOAT_SUPPORT))
writeFloat(void * buffer,uint8_t i,float value)896 static uint8_t writeFloat(void * buffer, uint8_t i, float value)
897 {
898 TRACE_ASSERT(buffer != 0, "writeFloat: buffer == NULL", 0);
899
900 /* A 32 bit value should begin at an even 4-byte address */
901 while ((i % 4) != 0)
902 {
903 if (i >= MAX_ARG_SIZE)
904 {
905 return 255;
906 }
907
908 ((uint8_t*)buffer)[i] = 0;
909 i++;
910 }
911
912 if (i + 4 > MAX_ARG_SIZE)
913 {
914 return 255;
915 }
916
917 ((float*)buffer)[i/4] = value;
918
919 return i + 4;
920 }
921 #endif
922
923 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_INCLUDE_FLOAT_SUPPORT))
writeDouble(void * buffer,uint8_t i,double value)924 static uint8_t writeDouble(void * buffer, uint8_t i, double value)
925 {
926 uint32_t * dest;
927 uint32_t * src = (uint32_t*)&value;
928
929 TRACE_ASSERT(buffer != 0, "writeDouble: buffer == NULL", 0);
930
931 /* The double is written as two 32 bit values, and should begin at an even
932 4-byte address (to avoid having to align with 8 byte) */
933 while (i % 4 != 0)
934 {
935 if (i >= MAX_ARG_SIZE)
936 {
937 return 255;
938 }
939
940 ((uint8_t*)buffer)[i] = 0;
941 i++;
942 }
943
944 if (i + 8 > MAX_ARG_SIZE)
945 {
946 return 255;
947 }
948
949 dest = &(((uint32_t *)buffer)[i/4]);
950
951 dest[0] = src[0];
952 dest[1] = src[1];
953
954 return i + 8;
955 }
956 #endif
957
958 /*******************************************************************************
959 * prvTraceUserEventFormat
960 *
961 * Parses the format string and stores the arguments in the buffer.
962 ******************************************************************************/
963 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
prvTraceUserEventFormat(const char * formatStr,va_list vl,uint8_t * buffer,uint8_t byteOffset)964 static uint8_t prvTraceUserEventFormat(const char* formatStr, va_list vl, uint8_t* buffer, uint8_t byteOffset)
965 {
966 uint16_t formatStrIndex = 0;
967 uint8_t argCounter = 0;
968 uint8_t i = byteOffset;
969
970 while (formatStr[formatStrIndex] != '\0')
971 {
972 if (formatStr[formatStrIndex] == '%')
973 {
974 if (formatStr[formatStrIndex + 1] == '%')
975 {
976 formatStrIndex += 2;
977 continue;
978 }
979
980 /* We found a possible argument */
981 argCounter++;
982
983 formatStrIndex++;
984
985 while ((formatStr[formatStrIndex] >= '0' && formatStr[formatStrIndex] <= '9') || formatStr[formatStrIndex] == '#' || formatStr[formatStrIndex] == '.')
986 formatStrIndex++;
987
988 /* This check is necessary to avoid moving past end of string. */
989 if (formatStr[formatStrIndex] != '\0')
990 {
991 switch (formatStr[formatStrIndex])
992 {
993 case 'd':
994 i = writeInt32( buffer,
995 i,
996 (uint32_t)va_arg(vl, uint32_t));
997 break;
998 case 'x':
999 case 'X':
1000 case 'u':
1001 i = writeInt32( buffer,
1002 i,
1003 (uint32_t)va_arg(vl, uint32_t));
1004 break;
1005 case 's':
1006 {
1007 TraceStringHandle_t xString;
1008 xTraceStringRegister((char*)va_arg(vl, char*), &xString);
1009
1010 i = writeInt16(buffer,
1011 i,
1012 (uint16_t)xString);
1013 }
1014 break;
1015
1016 #if (TRC_CFG_INCLUDE_FLOAT_SUPPORT)
1017 /* Yes, "double" as type also in the float
1018 case. This since "float" is promoted into "double"
1019 by the va_arg stuff. */
1020 case 'f':
1021 i = writeFloat( buffer,
1022 i,
1023 (float)va_arg(vl, double));
1024 break;
1025 #else
1026 /* No support for floats, but attempt to store a float user event
1027 avoid a possible crash due to float reference. Instead store the
1028 data on uint_32 format (will not be displayed anyway). This is just
1029 to keep va_arg and i consistent. */
1030
1031 case 'f':
1032 i = writeInt32( buffer,
1033 i,
1034 (uint32_t)va_arg(vl, double));
1035 break;
1036 #endif
1037 case 'l':
1038 formatStrIndex++;
1039 switch (formatStr[formatStrIndex])
1040 {
1041 #if (TRC_CFG_INCLUDE_FLOAT_SUPPORT)
1042 case 'f': i = writeDouble(buffer,
1043 i,
1044 (double)va_arg(vl, double));
1045 break;
1046 #else
1047 /* No support for floats, but attempt to store a float user event
1048 avoid a possible crash due to float reference. Instead store the
1049 data on uint_32 format (will not be displayed anyway). This is just
1050 to keep va_arg and i consistent. */
1051 case 'f':
1052 i = writeInt32( buffer, /* In this case, the value will not be shown anyway */
1053 i,
1054 (uint32_t)va_arg(vl, double));
1055
1056 i = writeInt32( buffer, /* Do it twice, to write in total 8 bytes */
1057 i,
1058 (uint32_t)va_arg(vl, double));
1059 break;
1060 #endif
1061 default:
1062 break;
1063 }
1064 break;
1065 case 'h':
1066 formatStrIndex++;
1067 switch (formatStr[formatStrIndex])
1068 {
1069 case 'd':
1070 i = writeInt16( buffer,
1071 i,
1072 (uint16_t)va_arg(vl, uint32_t));
1073 break;
1074 case 'u':
1075 i = writeInt16( buffer,
1076 i,
1077 (uint16_t)va_arg(vl, uint32_t));
1078 break;
1079
1080 default:
1081 break;
1082 }
1083 break;
1084 case 'b':
1085 formatStrIndex++;
1086 switch (formatStr[formatStrIndex])
1087 {
1088 case 'd':
1089 i = writeInt8( buffer,
1090 i,
1091 (uint8_t)va_arg(vl, uint32_t));
1092 break;
1093 case 'u':
1094 i = writeInt8( buffer,
1095 i,
1096 (uint8_t)va_arg(vl, uint32_t));
1097 break;
1098
1099 default:
1100 break;
1101 }
1102 break;
1103 default:
1104 /* False alarm: this wasn't a valid format specifier */
1105 argCounter--;
1106 break;
1107 }
1108
1109 if (argCounter > 15)
1110 {
1111 prvTraceError("xTracePrintF - Too many arguments, max 15 allowed!");
1112 return 0;
1113 }
1114 }
1115 else
1116 break;
1117 }
1118 formatStrIndex++;
1119 if (i == 255)
1120 {
1121 prvTraceError("xTracePrintF - Too large arguments, max 32 byte allowed!");
1122 return 0;
1123 }
1124 }
1125 return (uint8_t)(i+3)/4;
1126 }
1127 #endif
1128
1129 /*******************************************************************************
1130 * prvTraceClearChannelBuffer
1131 *
1132 * Clears a number of items in the channel buffer, starting from nextSlotToWrite.
1133 ******************************************************************************/
1134 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))
prvTraceClearChannelBuffer(uint32_t count)1135 static void prvTraceClearChannelBuffer(uint32_t count)
1136 {
1137 uint32_t slots;
1138
1139 TRACE_ASSERT((TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) >= count,
1140 "prvTraceClearChannelBuffer: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED);
1141
1142 /* Check if we're close to the end of the buffer */
1143 if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE))
1144 {
1145 slots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */
1146 (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, slots);
1147 (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[0], 0, (count - slots));
1148 }
1149 else
1150 (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, count);
1151 }
1152 #endif
1153
1154 /*******************************************************************************
1155 * prvTraceCopyToDataBuffer
1156 *
1157 * Copies a number of items to the data buffer, starting from nextSlotToWrite.
1158 ******************************************************************************/
1159 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))
prvTraceCopyToDataBuffer(uint32_t * data,uint32_t count)1160 static void prvTraceCopyToDataBuffer(uint32_t* data, uint32_t count)
1161 {
1162 uint32_t slots;
1163
1164 TRACE_ASSERT(data != 0,
1165 "prvTraceCopyToDataBuffer: data == NULL.", TRC_UNUSED);
1166 TRACE_ASSERT(count <= (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE),
1167 "prvTraceCopyToDataBuffer: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED);
1168 /* Check if we're close to the end of the buffer */
1169 if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE))
1170 {
1171 slots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */
1172 (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, slots * 4);
1173 (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[0], data + slots, (count - slots) * 4);
1174 }
1175 else
1176 {
1177 (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, count * 4);
1178 }
1179 }
1180 #endif
1181
1182 /*******************************************************************************
1183 * prvTraceUBHelper1
1184 *
1185 * Calls on prvTraceUserEventFormat() to do the actual formatting, then goes on
1186 * to the next helper function.
1187 ******************************************************************************/
1188 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))
prvTraceUBHelper1(traceUBChannel channel,TraceStringHandle_t eventLabel,TraceStringHandle_t formatLabel,va_list vl)1189 static void prvTraceUBHelper1(traceUBChannel channel, TraceStringHandle_t eventLabel, TraceStringHandle_t formatLabel, va_list vl)
1190 {
1191 uint32_t data[(3 + MAX_ARG_SIZE) / 4];
1192 uint8_t byteOffset = 4; /* Need room for timestamp */
1193 uint8_t noOfSlots;
1194
1195 if (channel == 0)
1196 {
1197 /* We are dealing with an unknown channel format pair */
1198 byteOffset = (uint8_t)(byteOffset + 4); /* Also need room for channel and format */
1199 ((uint16_t*)data)[2] = eventLabel;
1200 ((uint16_t*)data)[3] = formatLabel;
1201 }
1202
1203 noOfSlots = prvTraceUserEventFormat((char*)&(RecorderDataPtr->SymbolTable.symbytes[formatLabel+4]), vl, (uint8_t*)data, byteOffset);
1204
1205 prvTraceUBHelper2(channel, data, noOfSlots);
1206 }
1207 #endif
1208
1209 /*******************************************************************************
1210 * prvTraceUBHelper2
1211 *
1212 * This function simply copies the data buffer to the actual user event buffer.
1213 ******************************************************************************/
1214 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))
prvTraceUBHelper2(traceUBChannel channel,uint32_t * data,uint32_t noOfSlots)1215 static void prvTraceUBHelper2(traceUBChannel channel, uint32_t* data, uint32_t noOfSlots)
1216 {
1217 static uint32_t old_timestamp = 0;
1218 uint32_t old_nextSlotToWrite = 0;
1219
1220 TRACE_ALLOC_CRITICAL_SECTION();
1221
1222 TRACE_ASSERT((TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) >= noOfSlots, "prvTraceUBHelper2: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED);
1223
1224 trcCRITICAL_SECTION_BEGIN();
1225 /* Store the timestamp */
1226 prvTracePortGetTimeStamp(data);
1227
1228 if (*data < old_timestamp)
1229 {
1230 RecorderDataPtr->userEventBuffer.wraparoundCounter++;
1231 }
1232
1233 old_timestamp = *data;
1234
1235 /* Start by erasing any information in the channel buffer */
1236 prvTraceClearChannelBuffer(noOfSlots);
1237
1238 prvTraceCopyToDataBuffer(data, noOfSlots); /* Will wrap around the data if necessary */
1239
1240 old_nextSlotToWrite = RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Save the index that we want to write the channel data at when we're done */
1241 RecorderDataPtr->userEventBuffer.nextSlotToWrite = (RecorderDataPtr->userEventBuffer.nextSlotToWrite + noOfSlots) % (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE); /* Make sure we never end up outside the buffer */
1242
1243 /* Write to the channel buffer to indicate that this user event is ready to be used */
1244 if (channel != 0)
1245 {
1246 RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = channel;
1247 }
1248 else
1249 {
1250 /* 0xFF indicates that this is not a normal channel id */
1251 RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = (traceUBChannel)0xFF;
1252 }
1253 trcCRITICAL_SECTION_END();
1254 }
1255 #endif
1256
1257 /*******************************************************************************
1258 * xTraceRegisterUBChannel
1259 *
1260 * Registers a channel for Separated User Events, i.e., those stored in the
1261 * separate user event buffer.
1262 *
1263 * Note: Only available if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is enabled in
1264 * trcSnapshotConfig.h
1265 ******************************************************************************/
1266 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))
xTraceRegisterUBChannel(TraceStringHandle_t channel,TraceStringHandle_t formatStr)1267 traceUBChannel xTraceRegisterUBChannel(TraceStringHandle_t channel, TraceStringHandle_t formatStr)
1268 {
1269 uint8_t i;
1270 traceUBChannel retVal = 0;
1271
1272 TRACE_ALLOC_CRITICAL_SECTION();
1273
1274 TRACE_ASSERT(formatStr != 0, "xTraceRegisterChannelFormat: formatStr == 0", (traceUBChannel)0);
1275
1276 trcCRITICAL_SECTION_BEGIN();
1277 for (i = 1; i <= (TRC_CFG_UB_CHANNELS); i++) /* Size of the channels buffer is TRC_CFG_UB_CHANNELS + 1. Index 0 is unused. */
1278 {
1279 if(RecorderDataPtr->userEventBuffer.channels[i].name == 0 && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == 0)
1280 {
1281 /* Found empty slot */
1282 RecorderDataPtr->userEventBuffer.channels[i].name = channel;
1283 RecorderDataPtr->userEventBuffer.channels[i].defaultFormat = formatStr;
1284 retVal = (traceUBChannel)i;
1285 break;
1286 }
1287
1288 if (RecorderDataPtr->userEventBuffer.channels[i].name == channel && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == formatStr)
1289 {
1290 /* Found a match */
1291 retVal = (traceUBChannel)i;
1292 break;
1293 }
1294 }
1295 trcCRITICAL_SECTION_END();
1296
1297 return retVal;
1298 }
1299 #endif
1300
1301 /******************************************************************************
1302 * vTraceUBData
1303 *
1304 * Slightly faster version of xTracePrintF() due to no lookups.
1305 *
1306 * Note: This is only available if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is
1307 * enabled in trcSnapshotConfig.h
1308 ******************************************************************************/
1309 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))
vTraceUBData(traceUBChannel channelPair,...)1310 void vTraceUBData(traceUBChannel channelPair, ...)
1311 {
1312 va_list vl;
1313
1314 TRACE_ASSERT(channelPair != 0, "vTraceUBData: Not a valid traceUBChannel!", TRC_UNUSED);
1315
1316 va_start(vl, channelPair);
1317 vTraceUBData_Helper(channelPair, vl);
1318 va_end(vl);
1319 }
1320 #endif
1321
1322 /* Extracts the channel name and format string from the traceUBChannel, then calls prvTraceUBHelper1. */
1323 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))
vTraceUBData_Helper(traceUBChannel channelPair,va_list vl)1324 void vTraceUBData_Helper(traceUBChannel channelPair, va_list vl)
1325 {
1326 TraceStringHandle_t channel;
1327 TraceStringHandle_t formatStr;
1328
1329 TRACE_ASSERT(channelPair != 0, "vTraceUBData_Helper: channelPair == 0", TRC_UNUSED);
1330 TRACE_ASSERT(channelPair <= (TRC_CFG_UB_CHANNELS), "vTraceUBData_Helper: ", TRC_UNUSED);
1331
1332 channel = RecorderDataPtr->userEventBuffer.channels[channelPair].name;
1333 formatStr = RecorderDataPtr->userEventBuffer.channels[channelPair].defaultFormat;
1334
1335 prvTraceUBHelper1(channelPair, channel, formatStr, vl);
1336 }
1337 #endif
1338
1339 /******************************************************************************
1340 * vTraceUBEvent
1341 *
1342 * Slightly faster version of ... due to no lookups.
1343 ******************************************************************************/
1344 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))
vTraceUBEvent(traceUBChannel channelPair)1345 void vTraceUBEvent(traceUBChannel channelPair)
1346 {
1347 uint32_t data[(3 + MAX_ARG_SIZE) / 4];
1348
1349 TRACE_ASSERT(channelPair != 0, "vTraceUBEvent: channelPair == 0", TRC_UNUSED);
1350 TRACE_ASSERT(channelPair <= (TRC_CFG_UB_CHANNELS), "vTraceUBEvent: ", TRC_UNUSED);
1351
1352 prvTraceUBHelper2(channelPair, data, 1); /* Only need one slot for timestamp */
1353 }
1354 #endif
1355
1356 /******************************************************************************
1357 * xTracePrintF
1358 *
1359 * Generates User Event with formatted text and data, similar to a "printf".
1360 * It is very fast compared to a normal "printf" since this function only
1361 * stores the arguments. The actual formatting is done
1362 * on the host PC when the trace is displayed in the viewer tool.
1363 *
1364 * User Event labels are created using xTraceStringRegister.
1365 * Example:
1366 *
1367 * TraceStringHandle_t adc_uechannel;
1368 * xTraceStringRegister("ADC User Events", &adc_uechannel);
1369 * ...
1370 * xTracePrintF(adc_uechannel,
1371 * "ADC channel %d: %lf volts",
1372 * ch, (double)adc_reading/(double)scale);
1373 *
1374 * Calling xTraceStringRegister multiple times will not create duplicate entries, but
1375 * it is of course faster to just do it once, and then keep the handle for later
1376 * use. If you don't have any data arguments, only a text label/string, it is
1377 * better to use xTracePrint - it is faster.
1378 *
1379 * Format specifiers supported:
1380 * %d - 32 bit signed integer
1381 * %u - 32 bit unsigned integer
1382 * %f - 32 bit float
1383 * %s - string (is copied to the recorder symbol table)
1384 * %hd - 16 bit signed integer
1385 * %hu - 16 bit unsigned integer
1386 * %bd - 8 bit signed integer
1387 * %bu - 8 bit unsigned integer
1388 * %lf - double-precision float (Note! See below...)
1389 *
1390 * Up to 15 data arguments are allowed, with a total size of maximum 32 byte.
1391 * In case this is exceeded, the user event is changed into an error message.
1392 *
1393 * The data is stored in trace buffer, and is packed to allow storing multiple
1394 * smaller data entries in the same 4-byte record, e.g., four 8-bit values.
1395 * A string requires two bytes, as the symbol table is limited to 64K. Storing
1396 * a double (%lf) uses two records, so this is quite costly. Use float (%f)
1397 * unless the higher precision is really necessary.
1398 *
1399 * Note that the double-precision float (%lf) assumes a 64 bit double
1400 * representation. This does not seem to be the case on e.g. PIC24 and PIC32.
1401 * Before using a %lf argument on a 16-bit MCU, please verify that
1402 * "sizeof(double)" actually gives 8 as expected. If not, use %f instead.
1403 ******************************************************************************/
1404 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
xTracePrintF(TraceStringHandle_t eventLabel,const char * formatStr,...)1405 traceResult xTracePrintF(TraceStringHandle_t eventLabel, const char* formatStr, ...)
1406 {
1407 va_list vl;
1408
1409 va_start(vl, formatStr);
1410 xTraceVPrintF(eventLabel, formatStr, vl);
1411 va_end(vl);
1412
1413 return TRC_SUCCESS;
1414 }
1415 #endif
1416
1417 /******************************************************************************
1418 * xTraceVPrintF
1419 *
1420 * xTracePrintF variant that accepts a va_list.
1421 * See xTracePrintF documentation for further details.
1422 *
1423 ******************************************************************************/
1424 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
xTraceVPrintF(TraceStringHandle_t eventLabel,const char * formatStr,va_list vl)1425 traceResult xTraceVPrintF(TraceStringHandle_t eventLabel, const char* formatStr, va_list vl)
1426 {
1427 #if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 0)
1428 uint32_t noOfSlots;
1429 UserEvent* ue1;
1430 uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];
1431 TRACE_ALLOC_CRITICAL_SECTION();
1432
1433 TRACE_ASSERT(formatStr != 0, "vTraceVPrintF: formatStr == NULL", TRC_FAIL);
1434
1435 trcCRITICAL_SECTION_BEGIN();
1436
1437 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
1438 {
1439 /* First, write the "primary" user event entry in the local buffer, but
1440 let the event type be "EVENT_BEING_WRITTEN" for now...*/
1441
1442 ue1 = (UserEvent*)(&tempDataBuffer[0]);
1443
1444 ue1->type = EVENT_BEING_WRITTEN; /* Update this as the last step */
1445
1446 noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4);
1447
1448 /* Store the format string, with a reference to the channel symbol */
1449 ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel);
1450
1451 ue1->dts = (uint8_t)prvTraceGetDTS(0xFF);
1452
1453 /* prvTraceGetDTS might stop the recorder in some cases... */
1454 if (RecorderDataPtr->recorderActive)
1455 {
1456
1457 /* If the data does not fit in the remaining main buffer, wrap around to
1458 0 if allowed, otherwise stop the recorder and quit). */
1459 if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents)
1460 {
1461 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)
1462 (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],
1463 0,
1464 (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4);
1465 RecorderDataPtr->nextFreeIndex = 0;
1466 RecorderDataPtr->bufferIsFull = 1;
1467 #else
1468
1469 /* Stop recorder, since the event data will not fit in the
1470 buffer and not circular buffer in this case... */
1471 vTraceStop();
1472 #endif
1473 }
1474
1475 /* Check if recorder has been stopped (i.e., vTraceStop above) */
1476 if (RecorderDataPtr->recorderActive)
1477 {
1478 /* Check that the buffer to be overwritten does not contain any user
1479 events that would be partially overwritten. If so, they must be "killed"
1480 by replacing the user event and following data with NULL events (i.e.,
1481 using a memset to zero).*/
1482 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)
1483 prvCheckDataToBeOverwrittenForMultiEntryEvents((uint8_t)noOfSlots);
1484 #endif
1485 /* Copy the local buffer to the main buffer */
1486 (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],
1487 tempDataBuffer,
1488 noOfSlots * 4);
1489
1490 /* Update the event type, i.e., number of data entries following the
1491 main USER_EVENT entry (Note: important that this is after the memcpy,
1492 but within the critical section!)*/
1493 RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] =
1494 (uint8_t) ( USER_EVENT + noOfSlots - 1 );
1495
1496 /* Update the main buffer event index (already checked that it fits in
1497 the buffer, so no need to check for wrapping)*/
1498
1499 RecorderDataPtr->nextFreeIndex += noOfSlots;
1500 RecorderDataPtr->numEvents += noOfSlots;
1501
1502 if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE))
1503 {
1504 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)
1505 /* We have reached the end, but this is a ring buffer. Start from the beginning again. */
1506 RecorderDataPtr->bufferIsFull = 1;
1507 RecorderDataPtr->nextFreeIndex = 0;
1508 #else
1509 /* We have reached the end so we stop. */
1510 vTraceStop();
1511 #endif
1512 }
1513 }
1514
1515 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)
1516 /* Make sure the next entry is cleared correctly */
1517 prvCheckDataToBeOverwrittenForMultiEntryEvents(1);
1518 #endif
1519
1520 }
1521 }
1522 trcCRITICAL_SECTION_END();
1523
1524 #elif (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)
1525 /* Use the separate user event buffer */
1526 TraceStringHandle_t formatLabel;
1527 traceUBChannel channel;
1528
1529 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
1530 {
1531 xTraceStringRegister(formatStr, &formatLabel);
1532
1533 channel = xTraceRegisterUBChannel(eventLabel, formatLabel);
1534
1535 prvTraceUBHelper1(channel, eventLabel, formatLabel, vl);
1536 }
1537 #endif
1538
1539 return TRC_SUCCESS;
1540 }
1541 #endif
1542
1543 /******************************************************************************
1544 * xTracePrint
1545 *
1546 * Basic user event
1547 *
1548 * Generates a User Event with a text label. The label is created/looked up
1549 * in the symbol table using xTraceStringRegister.
1550 ******************************************************************************/
1551 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
xTracePrint(TraceStringHandle_t chn,const char * str)1552 traceResult xTracePrint(TraceStringHandle_t chn, const char* str)
1553 {
1554 #if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 0)
1555 UserEvent* ue;
1556 uint8_t dts1;
1557 TRACE_ALLOC_CRITICAL_SECTION();
1558
1559 trcCRITICAL_SECTION_BEGIN();
1560 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
1561 {
1562 dts1 = (uint8_t)prvTraceGetDTS(0xFF);
1563 ue = (UserEvent*) prvTraceNextFreeEventBufferSlot();
1564 if (ue != 0)
1565 {
1566 ue->dts = dts1;
1567 ue->type = USER_EVENT;
1568 ue->payload = prvTraceOpenSymbol(str, chn);
1569 prvTraceUpdateCounters();
1570 }
1571 }
1572 trcCRITICAL_SECTION_END();
1573
1574 #elif (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)
1575 traceUBChannel channel;
1576 uint32_t noOfSlots = 1;
1577 uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];
1578 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
1579 {
1580 TraceStringHandle_t trcStr = prvTraceOpenSymbol(str, chn);
1581 channel = xTraceRegisterUBChannel(chn, trcStr);
1582
1583 if (channel == 0)
1584 {
1585 /* We are dealing with an unknown channel format pair */
1586 noOfSlots++; /* Also need room for channel and format */
1587 ((uint16_t*)tempDataBuffer)[2] = chn;
1588 ((uint16_t*)tempDataBuffer)[3] = trcStr;
1589 }
1590
1591 prvTraceUBHelper2(channel, tempDataBuffer, noOfSlots);
1592 }
1593 #endif
1594
1595 return TRC_SUCCESS;
1596 }
1597 #endif
1598
1599 /*******************************************************************************
1600 * xTraceStringRegister
1601 *
1602 * Register strings in the recorder, e.g. for names of user event channels.
1603 *
1604 * Example:
1605 * xTraceStringRegister("MyUserEvent", &myStringHandle);
1606 * ...
1607 * xTracePrintF(myEventHandle, "My value is: %d", myValue);
1608 ******************************************************************************/
1609 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))
xTraceStringRegister(const char * label,TraceStringHandle_t * pxString)1610 traceResult xTraceStringRegister(const char* label, TraceStringHandle_t *pxString)
1611 {
1612 TRACE_ASSERT(label != 0, "xTraceStringRegister: label == NULL", TRC_FAIL);
1613 TRACE_ASSERT(RecorderDataPtr != 0, "Recorder not initialized, call vTraceEnable() first!", TRC_FAIL);
1614
1615 *pxString = prvTraceOpenSymbol(label, 0);
1616
1617 return TRC_SUCCESS;
1618 }
1619
1620 /* DEPRECATED */
xTraceRegisterString(const char * name)1621 TraceStringHandle_t xTraceRegisterString(const char* name)
1622 {
1623 TraceStringHandle_t trcStr = 0;
1624 xTraceStringRegister(name, &trcStr);
1625
1626 return trcStr;
1627 }
1628 #endif
1629
xTraceInitialize()1630 traceResult xTraceInitialize()
1631 {
1632 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
1633 uint32_t i;
1634 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
1635
1636 if (RecorderInitialized != 0)
1637 {
1638 return TRC_SUCCESS;
1639 }
1640
1641 /* These are set on init so they aren't overwritten by late initialization values. */
1642 CurrentFilterMask = 0xFFFF;
1643 CurrentFilterGroup = FilterGroup0;
1644 traceErrorMessage = 0;
1645
1646 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
1647 tasksNotIncluded = 0;
1648
1649 for (i = 0; i < TRC_CFG_STACK_MONITOR_MAX_TASKS; i++)
1650 {
1651 tasksInStackMonitor[i].tcb = 0;
1652 tasksInStackMonitor[i].uiPreviousLowMark = 0;
1653 }
1654 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
1655
1656 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC)
1657 RecorderDataPtr = &RecorderData;
1658 #elif (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC)
1659 /* Initialize heap */
1660 TRC_KERNEL_PORT_HEAP_INIT(sizeof(RecorderDataType));
1661
1662 /* Allocate data */
1663 RecorderDataPtr = (RecorderDataType*)TRC_KERNEL_PORT_HEAP_MALLOC(sizeof(RecorderDataType));
1664 if (!RecorderDataPtr)
1665 {
1666 prvTraceError("Failed allocating recorder buffer!");
1667 return TRC_FAIL;
1668 }
1669 #elif (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)
1670 if (!RecorderDataPtr)
1671 {
1672 prvTraceError("Recorder data pointer not set! Use vTraceSetRecorderDataBuffer().");
1673 return TRC_FAIL;
1674 }
1675 #endif
1676
1677 init_hwtc_count = TRC_HWTC_COUNT;
1678
1679 if (xTraceKernelPortInitialize(&xKernelPortDataBuffer) == TRC_FAIL)
1680 {
1681 return TRC_FAIL;
1682 }
1683
1684 (void)memset(RecorderDataPtr, 0, sizeof(RecorderDataType));
1685
1686 RecorderDataPtr->version = TRACE_KERNEL_VERSION;
1687 RecorderDataPtr->minor_version = TRACE_MINOR_VERSION;
1688 RecorderDataPtr->irq_priority_order = TRC_IRQ_PRIORITY_ORDER;
1689 RecorderDataPtr->filesize = sizeof(RecorderDataType);
1690 RecorderDataPtr->maxEvents = (TRC_CFG_EVENT_BUFFER_SIZE);
1691 RecorderDataPtr->debugMarker0 = (int32_t)0xF0F0F0F0;
1692 RecorderDataPtr->isUsing16bitHandles = TRC_CFG_USE_16BIT_OBJECT_HANDLES;
1693 RecorderDataPtr->isrTailchainingThreshold = TRC_CFG_ISR_TAILCHAINING_THRESHOLD;
1694
1695 /* This function is kernel specific */
1696 xTraceKernelPortInitObjectPropertyTable();
1697
1698 RecorderDataPtr->debugMarker1 = (int32_t)0xF1F1F1F1;
1699 RecorderDataPtr->SymbolTable.symTableSize = (TRC_CFG_SYMBOL_TABLE_SIZE);
1700 RecorderDataPtr->SymbolTable.nextFreeSymbolIndex = 1;
1701 #if (TRC_CFG_INCLUDE_FLOAT_SUPPORT == 1)
1702 RecorderDataPtr->exampleFloatEncoding = 1.0f; /* otherwise already zero */
1703 #endif
1704 RecorderDataPtr->debugMarker2 = (int32_t)0xF2F2F2F2;
1705 prvStrncpy(RecorderDataPtr->systemInfo, "Trace Recorder Demo", 80);
1706 RecorderDataPtr->debugMarker3 = (int32_t)0xF3F3F3F3;
1707 RecorderDataPtr->endmarker0 = 0x0A;
1708 RecorderDataPtr->endmarker1 = 0x0B;
1709 RecorderDataPtr->endmarker2 = 0x0C;
1710 RecorderDataPtr->endmarker3 = 0x0D;
1711 RecorderDataPtr->endmarker4 = 0x71;
1712 RecorderDataPtr->endmarker5 = 0x72;
1713 RecorderDataPtr->endmarker6 = 0x73;
1714 RecorderDataPtr->endmarker7 = 0x74;
1715 RecorderDataPtr->endmarker8 = 0xF1;
1716 RecorderDataPtr->endmarker9 = 0xF2;
1717 RecorderDataPtr->endmarker10 = 0xF3;
1718 RecorderDataPtr->endmarker11 = 0xF4;
1719
1720 #if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER
1721 RecorderDataPtr->userEventBuffer.bufferID = 1;
1722 RecorderDataPtr->userEventBuffer.version = 0;
1723 RecorderDataPtr->userEventBuffer.numberOfSlots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE);
1724 RecorderDataPtr->userEventBuffer.numberOfChannels = (TRC_CFG_UB_CHANNELS)+1;
1725 #endif
1726
1727 /* Kernel specific initialization of the objectHandleStacks variable */
1728 xTraceKernelPortInitObjectHandleStack();
1729
1730
1731 /* Finally, the 12-byte "start markers" are initialized, allowing for
1732 Tracealyzer to find the trace data in a larger RAM dump.
1733
1734 The start and end markers must be unique, but without proper precautions there
1735 might be a risk of accidental duplicates of the start/end markers, e.g., due to
1736 compiler optimizations.
1737
1738 The below initialization of the start marker is therefore made in reverse order
1739 and the fields are volatile to ensure this assignment order. This to avoid any
1740 chance of accidental duplicates of this elsewhere in memory.
1741
1742 Moreover, the fields are set byte-by-byte to avoid endian issues.*/
1743
1744 RecorderDataPtr->startmarker11 = 0xF4;
1745 RecorderDataPtr->startmarker10 = 0xF3;
1746 RecorderDataPtr->startmarker9 = 0xF2;
1747 RecorderDataPtr->startmarker8 = 0xF1;
1748 RecorderDataPtr->startmarker7 = 0x74;
1749 RecorderDataPtr->startmarker6 = 0x73;
1750 RecorderDataPtr->startmarker5 = 0x72;
1751 RecorderDataPtr->startmarker4 = 0x71;
1752 RecorderDataPtr->startmarker3 = 0x04;
1753 RecorderDataPtr->startmarker2 = 0x03;
1754 RecorderDataPtr->startmarker1 = 0x02;
1755 RecorderDataPtr->startmarker0 = 0x01;
1756
1757 if (traceErrorMessage != 0)
1758 {
1759 // An error was detected before vTraceEnable was called, make sure this is stored in the trace data.
1760 prvStrncpy(RecorderDataPtr->systemInfo, traceErrorMessage, 80);
1761 RecorderDataPtr->internalErrorOccured = 1;
1762 prvTraceStop();
1763 }
1764
1765 #ifdef TRC_PORT_SPECIFIC_INIT
1766 TRC_PORT_SPECIFIC_INIT();
1767 #endif
1768
1769 RecorderInitialized = 1;
1770
1771 return TRC_SUCCESS;
1772 }
1773
1774 #if ((!defined TRC_CFG_INCLUDE_READY_EVENTS) || (TRC_CFG_INCLUDE_READY_EVENTS == 1))
1775
prvTraceSetReadyEventsEnabled(uint32_t flag)1776 void prvTraceSetReadyEventsEnabled(uint32_t flag)
1777 {
1778 readyEventsEnabled = flag;
1779 }
1780
1781 /*******************************************************************************
1782 * prvTraceStoreTaskReady
1783 *
1784 * This function stores a ready state for the task handle sent in as parameter.
1785 ******************************************************************************/
prvTraceStoreTaskReady(traceHandle handle)1786 void prvTraceStoreTaskReady(traceHandle handle)
1787 {
1788 uint16_t dts3;
1789 TREvent* tr;
1790 uint8_t hnd8;
1791
1792 TRACE_ALLOC_CRITICAL_SECTION();
1793
1794 if (handle == 0)
1795 {
1796 /* On FreeRTOS v7.3.0, this occurs when creating tasks due to a bad
1797 placement of the trace macro. In that case, the events are ignored. */
1798 return;
1799 }
1800
1801 if (! readyEventsEnabled)
1802 {
1803 /* When creating tasks, ready events are also created. If creating
1804 a "hidden" (not traced) task, we must therefore disable recording
1805 of ready events to avoid an undesired ready event... */
1806 return;
1807 }
1808
1809 TRACE_ASSERT(handle <= (TRC_CFG_NTASK), "prvTraceStoreTaskReady: Invalid value for handle", TRC_UNUSED);
1810
1811 if (recorder_busy)
1812 {
1813 /*************************************************************************
1814 * This occurs if an ISR calls a trace function, preempting a previous
1815 * trace call that is being processed in a different ISR or task.
1816 * If this occurs, there is probably a problem in the definition of the
1817 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and
1818 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt
1819 * and any other ISRs that calls the trace recorder directly or via
1820 * traced kernel functions. The ARM port disables all interrupts using the
1821 * PRIMASK register to avoid this issue.
1822 *************************************************************************/
1823 prvTraceError("Recorder busy - high priority ISR using syscall? (1)");
1824 return;
1825 }
1826
1827 trcCRITICAL_SECTION_BEGIN();
1828 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
1829 {
1830 dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);
1831 hnd8 = prvTraceGet8BitHandle(handle);
1832 tr = (TREvent*)prvTraceNextFreeEventBufferSlot();
1833 if (tr != 0)
1834 {
1835 tr->type = DIV_TASK_READY;
1836 tr->dts = dts3;
1837 tr->objHandle = hnd8;
1838 prvTraceUpdateCounters();
1839 }
1840 }
1841 trcCRITICAL_SECTION_END();
1842 }
1843 #endif
1844
1845 /*******************************************************************************
1846 * prvTraceStoreLowPower
1847 *
1848 * This function stores a low power state.
1849 ******************************************************************************/
prvTraceStoreLowPower(uint32_t flag)1850 void prvTraceStoreLowPower(uint32_t flag)
1851 {
1852 uint16_t dts;
1853 LPEvent* lp;
1854 TRACE_ALLOC_CRITICAL_SECTION();
1855
1856 TRACE_ASSERT(flag <= 1, "prvTraceStoreLowPower: Invalid flag value", TRC_UNUSED);
1857
1858 if (recorder_busy)
1859 {
1860 /*************************************************************************
1861 * This occurs if an ISR calls a trace function, preempting a previous
1862 * trace call that is being processed in a different ISR or task.
1863 * If this occurs, there is probably a problem in the definition of the
1864 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and
1865 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt
1866 * and any other ISRs that calls the trace recorder directly or via
1867 * traced kernel functions. The ARM port disables all interrupts using the
1868 * PRIMASK register to avoid this issue.
1869 *************************************************************************/
1870 prvTraceError("Recorder busy - high priority ISR using syscall? (1)");
1871 return;
1872 }
1873
1874 trcCRITICAL_SECTION_BEGIN();
1875 if (RecorderDataPtr->recorderActive)
1876 {
1877 dts = (uint16_t)prvTraceGetDTS(0xFFFF);
1878 lp = (LPEvent*)prvTraceNextFreeEventBufferSlot();
1879 if (lp != 0)
1880 {
1881 lp->type = (uint8_t) (LOW_POWER_BEGIN + ( uint8_t ) flag); /* BEGIN or END depending on flag */
1882 lp->dts = dts;
1883 prvTraceUpdateCounters();
1884 }
1885 }
1886 trcCRITICAL_SECTION_END();
1887 }
1888
1889 /*******************************************************************************
1890 * vTraceStoreMemMangEvent
1891 *
1892 * This function stores malloc and free events. Each call requires two records,
1893 * for size and address respectively. The event code parameter (ecode) is applied
1894 * to the first record (size) and the following address record gets event
1895 * code "ecode + 1", so make sure this is respected in the event code table.
1896 * Note: On "free" calls, the signed_size parameter should be negative.
1897 ******************************************************************************/
1898 #if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1)
1899 #if (TRC_CFG_SCHEDULING_ONLY == 0)
vTraceStoreMemMangEvent(uint32_t ecode,uint32_t address,int32_t signed_size)1900 void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t signed_size)
1901 {
1902 uint8_t dts1;
1903 MemEventSize * ms;
1904 MemEventAddr * ma;
1905 uint16_t size_low;
1906 uint16_t addr_low;
1907 uint8_t addr_high;
1908 uint32_t size;
1909 TRACE_ALLOC_CRITICAL_SECTION();
1910
1911 if (RecorderDataPtr == 0)
1912 {
1913 /* Occurs in vTraceInitTraceData, if using dynamic allocation. */
1914 return;
1915 }
1916
1917 if (signed_size < 0)
1918 size = (uint32_t)(- signed_size);
1919 else
1920 size = (uint32_t)(signed_size);
1921
1922 trcCRITICAL_SECTION_BEGIN();
1923
1924 /* Only update heapMemUsage if we have a valid address */
1925 if (address != 0)
1926 {
1927 RecorderDataPtr->heapMemUsage += (uint32_t)signed_size;
1928
1929 if (RecorderDataPtr->heapMemUsage > RecorderDataPtr->heapMemMaxUsage)
1930 {
1931 RecorderDataPtr->heapMemMaxUsage = RecorderDataPtr->heapMemUsage;
1932 }
1933 }
1934
1935 if (RecorderDataPtr->recorderActive)
1936 {
1937 dts1 = (uint8_t)prvTraceGetDTS(0xFF);
1938 size_low = (uint16_t)prvTraceGetParam(0xFFFF, size);
1939 ms = (MemEventSize *)prvTraceNextFreeEventBufferSlot();
1940
1941 if (ms != 0)
1942 {
1943 ms->dts = dts1;
1944 ms->type = NULL_EVENT; /* Updated when all events are written */
1945 ms->size = size_low;
1946 prvTraceUpdateCounters();
1947
1948 /* Storing a second record with address (signals "failed" if null) */
1949 #if (TRC_CFG_HEAP_SIZE_BELOW_16M)
1950 /* If the heap address range is within 16 MB, i.e., the upper 8 bits
1951 of addresses are constant, this optimization avoids storing an extra
1952 event record by ignoring the upper 8 bit of the address */
1953 addr_low = address & 0xFFFF;
1954 addr_high = (address >> 16) & 0xFF;
1955 #else
1956 /* The whole 32 bit address is stored using a second event record
1957 for the upper 16 bit */
1958 addr_low = (uint16_t)prvTraceGetParam(0xFFFF, address);
1959 addr_high = 0;
1960 #endif
1961
1962 ma = (MemEventAddr *) prvTraceNextFreeEventBufferSlot();
1963 if (ma != 0)
1964 {
1965 ma->addr_low = addr_low;
1966 ma->addr_high = addr_high;
1967 ma->type = (uint8_t) (ecode + 1); /* Note this! */
1968 ms->type = (uint8_t) ecode; /* Set type of first event */
1969 prvTraceUpdateCounters();
1970 }
1971 }
1972 }
1973 trcCRITICAL_SECTION_END();
1974 }
1975 #endif /* TRC_CFG_SCHEDULING_ONLY */
1976 #endif
1977
1978 /*******************************************************************************
1979 * prvTraceStoreKernelCall
1980 *
1981 * This is the main integration point for storing kernel calls, and
1982 * is called by the hooks in trcKernelHooks.h (see trcKernelPort.h for event codes).
1983 ******************************************************************************/
1984 #if (TRC_CFG_SCHEDULING_ONLY == 0)
prvTraceStoreKernelCall(uint32_t ecode,traceObjectClass objectClass,uint32_t objectNumber)1985 void prvTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber)
1986 {
1987 KernelCall * kse;
1988 uint16_t dts1;
1989 uint8_t hnd8;
1990 TRACE_ALLOC_CRITICAL_SECTION();
1991
1992 /* Avoids warnings when asserts are disabled */
1993 (void)objectClass;
1994
1995 TRACE_ASSERT(ecode < 0xFF, "prvTraceStoreKernelCall: ecode >= 0xFF", TRC_UNUSED);
1996 TRACE_ASSERT(objectClass < TRACE_NCLASSES, "prvTraceStoreKernelCall: objectClass >= TRACE_NCLASSES", TRC_UNUSED);
1997 TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "prvTraceStoreKernelCall: Invalid value for objectNumber", TRC_UNUSED);
1998
1999 if (recorder_busy)
2000 {
2001 /*************************************************************************
2002 * This occurs if an ISR calls a trace function, preempting a previous
2003 * trace call that is being processed in a different ISR or task.
2004 * If this occurs, there is probably a problem in the definition of the
2005 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and
2006 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt
2007 * and any other ISRs that calls the trace recorder directly or via
2008 * traced kernel functions. The ARM port disables all interrupts using the
2009 * PRIMASK register to avoid this issue.
2010 *************************************************************************/
2011 prvTraceError("Recorder busy - high priority ISR using syscall? (2)");
2012 return;
2013 }
2014
2015 if (handle_of_last_logged_task == 0)
2016 {
2017 return;
2018 }
2019
2020 trcCRITICAL_SECTION_BEGIN();
2021 if (RecorderDataPtr->recorderActive)
2022 {
2023 dts1 = (uint16_t)prvTraceGetDTS(0xFFFF);
2024 hnd8 = prvTraceGet8BitHandle((traceHandle)objectNumber);
2025 kse = (KernelCall*) prvTraceNextFreeEventBufferSlot();
2026 if (kse != 0)
2027 {
2028 kse->dts = dts1;
2029 kse->type = (uint8_t)ecode;
2030 kse->objHandle = hnd8;
2031 prvTraceUpdateCounters();
2032 }
2033 }
2034 trcCRITICAL_SECTION_END();
2035 }
2036 #endif /* TRC_CFG_SCHEDULING_ONLY */
2037
2038 /*******************************************************************************
2039 * prvTraceStoreKernelCallWithParam
2040 *
2041 * Used for storing kernel calls with a handle and a numeric parameter. If the
2042 * numeric parameter does not fit in one byte, and extra XPS event is inserted
2043 * before the kernel call event containing the three upper bytes.
2044 ******************************************************************************/
2045 #if (TRC_CFG_SCHEDULING_ONLY == 0)
prvTraceStoreKernelCallWithParam(uint32_t evtcode,traceObjectClass objectClass,uint32_t objectNumber,uint32_t param)2046 void prvTraceStoreKernelCallWithParam(uint32_t evtcode,
2047 traceObjectClass objectClass,
2048 uint32_t objectNumber,
2049 uint32_t param)
2050 {
2051 KernelCallWithParamAndHandle * kse;
2052 uint8_t dts2;
2053 uint8_t hnd8;
2054 uint8_t p8;
2055 TRACE_ALLOC_CRITICAL_SECTION();
2056
2057 /* Avoids warnings when asserts are disabled */
2058 (void)objectClass;
2059
2060 TRACE_ASSERT(evtcode < 0xFF, "prvTraceStoreKernelCallWithParam: evtcode >= 0xFF", TRC_UNUSED);
2061 TRACE_ASSERT(objectClass < TRACE_NCLASSES, "prvTraceStoreKernelCallWithParam: objectClass >= TRACE_NCLASSES", TRC_UNUSED);
2062 TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "prvTraceStoreKernelCallWithParam: Invalid value for objectNumber", TRC_UNUSED);
2063
2064 if (recorder_busy)
2065 {
2066 /*************************************************************************
2067 * This occurs if an ISR calls a trace function, preempting a previous
2068 * trace call that is being processed in a different ISR or task.
2069 * If this occurs, there is probably a problem in the definition of the
2070 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and
2071 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt
2072 * and any other ISRs that calls the trace recorder directly or via
2073 * traced kernel functions. The ARM port disables all interrupts using the
2074 * PRIMASK register to avoid this issue.
2075 *************************************************************************/
2076 prvTraceError("Recorder busy - high priority ISR using syscall? (3)");
2077 return;
2078 }
2079
2080 trcCRITICAL_SECTION_BEGIN();
2081 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
2082 {
2083 dts2 = (uint8_t)prvTraceGetDTS(0xFF);
2084 p8 = (uint8_t) prvTraceGetParam(0xFF, param);
2085 hnd8 = prvTraceGet8BitHandle((traceHandle)objectNumber);
2086 kse = (KernelCallWithParamAndHandle*) prvTraceNextFreeEventBufferSlot();
2087 if (kse != 0)
2088 {
2089 kse->dts = dts2;
2090 kse->type = (uint8_t)evtcode;
2091 kse->objHandle = hnd8;
2092 kse->param = p8;
2093 prvTraceUpdateCounters();
2094 }
2095 }
2096 trcCRITICAL_SECTION_END();
2097 }
2098 #endif /* TRC_CFG_SCHEDULING_ONLY */
2099
2100
2101 /*******************************************************************************
2102 * prvTraceGetParam
2103 *
2104 * Used for storing extra bytes for kernel calls with numeric parameters.
2105 *
2106 * May only be called within a critical section!
2107 ******************************************************************************/
2108 #if (TRC_CFG_SCHEDULING_ONLY == 0)
prvTraceGetParam(uint32_t param_max,uint32_t param)2109 static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param)
2110 {
2111 XPSEvent* xps;
2112
2113 TRACE_ASSERT(param_max == 0xFF || param_max == 0xFFFF,
2114 "prvTraceGetParam: Invalid value for param_max", param);
2115
2116 if (param <= param_max)
2117 {
2118 return param;
2119 }
2120 else
2121 {
2122 xps = (XPSEvent*) prvTraceNextFreeEventBufferSlot();
2123 if (xps != 0)
2124 {
2125 xps->type = DIV_XPS;
2126 xps->xps_8 = (uint8_t)((param & (0xFF00 & ~param_max)) >> 8);
2127 xps->xps_16 = (uint16_t)((param & (0xFFFF0000 & ~param_max)) >> 16);
2128 prvTraceUpdateCounters();
2129 }
2130
2131 return param & param_max;
2132 }
2133 }
2134 #endif
2135
2136 /*******************************************************************************
2137 * prvTraceStoreKernelCallWithNumericParamOnly
2138 *
2139 * Used for storing kernel calls with numeric parameters only. This is
2140 * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment.
2141 ******************************************************************************/
2142 #if (TRC_CFG_SCHEDULING_ONLY == 0)
prvTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode,uint32_t param)2143 void prvTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param)
2144 {
2145 KernelCallWithParam16 * kse;
2146 uint8_t dts6;
2147 uint16_t restParam;
2148 TRACE_ALLOC_CRITICAL_SECTION();
2149
2150 restParam = 0;
2151
2152 TRACE_ASSERT(evtcode < 0xFF, "prvTraceStoreKernelCallWithNumericParamOnly: Invalid value for evtcode", TRC_UNUSED);
2153
2154 if (recorder_busy)
2155 {
2156 /*************************************************************************
2157 * This occurs if an ISR calls a trace function, preempting a previous
2158 * trace call that is being processed in a different ISR or task.
2159 * If this occurs, there is probably a problem in the definition of the
2160 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and
2161 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt
2162 * and any other ISRs that calls the trace recorder directly or via
2163 * traced kernel functions. The ARM port disables all interrupts using the
2164 * PRIMASK register to avoid this issue.
2165 *************************************************************************/
2166 prvTraceError("Recorder busy - high priority ISR using syscall? (4)");
2167 return;
2168 }
2169
2170 trcCRITICAL_SECTION_BEGIN();
2171 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)
2172 {
2173 dts6 = (uint8_t)prvTraceGetDTS(0xFF);
2174 restParam = (uint16_t)prvTraceGetParam(0xFFFF, param);
2175 kse = (KernelCallWithParam16*) prvTraceNextFreeEventBufferSlot();
2176 if (kse != 0)
2177 {
2178 kse->dts = dts6;
2179 kse->type = (uint8_t)evtcode;
2180 kse->param = restParam;
2181 prvTraceUpdateCounters();
2182 }
2183 }
2184 trcCRITICAL_SECTION_END();
2185 }
2186 #endif /* TRC_CFG_SCHEDULING_ONLY */
2187
2188 /*******************************************************************************
2189 * prvTraceStoreTaskswitch
2190 * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart.
2191 * At this point interrupts are assumed to be disabled!
2192 ******************************************************************************/
prvTraceStoreTaskswitch(traceHandle task_handle)2193 void prvTraceStoreTaskswitch(traceHandle task_handle)
2194 {
2195 uint16_t dts3;
2196 TSEvent* ts;
2197 uint8_t hnd8;
2198 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
2199 extern int32_t isPendingContextSwitch;
2200 #endif
2201 trcSR_ALLOC_CRITICAL_SECTION_ON_CORTEX_M_ONLY();
2202
2203 TRACE_ASSERT(task_handle <= (TRC_CFG_NTASK),
2204 "prvTraceStoreTaskswitch: Invalid value for task_handle", TRC_UNUSED);
2205
2206 trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY();
2207
2208 if ((task_handle != handle_of_last_logged_task) && (RecorderDataPtr->recorderActive))
2209 {
2210 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
2211 isPendingContextSwitch = 0;
2212 #endif
2213
2214 dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);
2215 handle_of_last_logged_task = task_handle;
2216 hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task);
2217 ts = (TSEvent*)prvTraceNextFreeEventBufferSlot();
2218
2219 if (ts != 0)
2220 {
2221 if (prvTraceGetObjectState(TRACE_CLASS_TASK,
2222 handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE)
2223 {
2224 ts->type = TS_TASK_RESUME;
2225 }
2226 else
2227 {
2228 ts->type = TS_TASK_BEGIN;
2229 }
2230
2231 ts->dts = dts3;
2232 ts->objHandle = hnd8;
2233
2234 prvTraceSetObjectState(TRACE_CLASS_TASK,
2235 handle_of_last_logged_task,
2236 TASK_STATE_INSTANCE_ACTIVE);
2237
2238 prvTraceUpdateCounters();
2239 }
2240 }
2241
2242 trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY();
2243 }
2244
2245 /*******************************************************************************
2246 * prvTraceStoreObjectNameOnCloseEvent
2247 *
2248 * Updates the symbol table with the name of this object from the dynamic
2249 * objects table and stores a "close" event, holding the mapping between handle
2250 * and name (a symbol table handle). The stored name-handle mapping is thus the
2251 * "old" one, valid up until this point.
2252 ******************************************************************************/
prvTraceStoreObjectNameOnCloseEvent(uint8_t evtcode,traceHandle handle,traceObjectClass objectclass)2253 void prvTraceStoreObjectNameOnCloseEvent(uint8_t evtcode, traceHandle handle,
2254 traceObjectClass objectclass)
2255 {
2256 ObjCloseNameEvent * ce;
2257 const char * name;
2258 TraceStringHandle_t idx;
2259
2260 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2261 "prvTraceStoreObjectNameOnCloseEvent: objectclass >= TRACE_NCLASSES", TRC_UNUSED);
2262 TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],
2263 "prvTraceStoreObjectNameOnCloseEvent: Invalid value for handle", TRC_UNUSED);
2264
2265 if (RecorderDataPtr->recorderActive)
2266 {
2267 uint8_t hnd8 = prvTraceGet8BitHandle(handle);
2268 name = TRACE_PROPERTY_NAME_GET(objectclass, handle);
2269 idx = prvTraceOpenSymbol(name, 0);
2270
2271 // Interrupt disable not necessary, already done in trcHooks.h macro
2272 ce = (ObjCloseNameEvent*) prvTraceNextFreeEventBufferSlot();
2273 if (ce != 0)
2274 {
2275 ce->type = (uint8_t) evtcode;
2276 ce->objHandle = hnd8;
2277 ce->symbolIndex = idx;
2278 prvTraceUpdateCounters();
2279 }
2280 }
2281 }
2282
prvTraceStoreObjectPropertiesOnCloseEvent(uint8_t evtcode,traceHandle handle,traceObjectClass objectclass)2283 void prvTraceStoreObjectPropertiesOnCloseEvent(uint8_t evtcode, traceHandle handle,
2284 traceObjectClass objectclass)
2285 {
2286 ObjClosePropEvent * pe;
2287
2288 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2289 "prvTraceStoreObjectPropertiesOnCloseEvent: objectclass >= TRACE_NCLASSES", TRC_UNUSED);
2290 TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],
2291 "prvTraceStoreObjectPropertiesOnCloseEvent: Invalid value for handle", TRC_UNUSED);
2292
2293 if (RecorderDataPtr->recorderActive)
2294 {
2295 // Interrupt disable not necessary, already done in trcHooks.h macro
2296 pe = (ObjClosePropEvent*) prvTraceNextFreeEventBufferSlot();
2297 if (pe != 0)
2298 {
2299 if (objectclass == TRACE_CLASS_TASK)
2300 {
2301 pe->arg1 = TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle);
2302 }
2303 else
2304 {
2305 pe->arg1 = TRACE_PROPERTY_OBJECT_STATE(objectclass, handle);
2306 }
2307 pe->type = evtcode;
2308 prvTraceUpdateCounters();
2309 }
2310 }
2311 }
2312
prvTraceSetPriorityProperty(uint8_t objectclass,traceHandle id,uint8_t value)2313 void prvTraceSetPriorityProperty(uint8_t objectclass, traceHandle id, uint8_t value)
2314 {
2315 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2316 "prvTraceSetPriorityProperty: objectclass >= TRACE_NCLASSES", TRC_UNUSED);
2317 TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],
2318 "prvTraceSetPriorityProperty: Invalid value for id", TRC_UNUSED);
2319
2320 TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value;
2321 }
2322
prvTraceGetPriorityProperty(uint8_t objectclass,traceHandle id)2323 uint8_t prvTraceGetPriorityProperty(uint8_t objectclass, traceHandle id)
2324 {
2325 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2326 "prvTraceGetPriorityProperty: objectclass >= TRACE_NCLASSES", 0);
2327 TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],
2328 "prvTraceGetPriorityProperty: Invalid value for id", 0);
2329
2330 return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id);
2331 }
2332
prvTraceSetObjectState(uint8_t objectclass,traceHandle id,uint8_t value)2333 void prvTraceSetObjectState(uint8_t objectclass, traceHandle id, uint8_t value)
2334 {
2335 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2336 "prvTraceSetObjectState: objectclass >= TRACE_NCLASSES", TRC_UNUSED);
2337 TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],
2338 "prvTraceSetObjectState: Invalid value for id", TRC_UNUSED);
2339
2340 TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value;
2341 }
2342
prvTraceGetObjectState(uint8_t objectclass,traceHandle id)2343 uint8_t prvTraceGetObjectState(uint8_t objectclass, traceHandle id)
2344 {
2345 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2346 "prvTraceGetObjectState: objectclass >= TRACE_NCLASSES", 0);
2347 TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],
2348 "prvTraceGetObjectState: Invalid value for id", 0);
2349
2350 return TRACE_PROPERTY_OBJECT_STATE(objectclass, id);
2351 }
2352
prvTraceSetTaskInstanceFinished(traceHandle handle)2353 void prvTraceSetTaskInstanceFinished(traceHandle handle)
2354 {
2355 /* Avoids warnings when asserts are disabled */
2356 (void)handle;
2357
2358 TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_TASK],
2359 "prvTraceSetTaskInstanceFinished: Invalid value for handle", TRC_UNUSED);
2360
2361 #if (TRC_CFG_USE_IMPLICIT_IFE_RULES == 1)
2362 TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0;
2363 #endif
2364 }
2365
prvTraceNextFreeEventBufferSlot(void)2366 void* prvTraceNextFreeEventBufferSlot(void)
2367 {
2368 if (! RecorderDataPtr->recorderActive)
2369 {
2370 /* If an XTS or XPS event prior to the main event has filled the buffer
2371 before saving the main event, and store mode is "stop when full". */
2372 return 0;
2373 }
2374
2375 if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE))
2376 {
2377 prvTraceError("Attempt to index outside event buffer!");
2378 return 0;
2379 }
2380 return (void*)(&RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex*4]);
2381 }
2382
uiIndexOfObject(traceHandle objecthandle,uint8_t objectclass)2383 uint16_t uiIndexOfObject(traceHandle objecthandle, uint8_t objectclass)
2384 {
2385 uint16_t index;
2386 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2387 "uiIndexOfObject: Invalid value for objectclass", 0);
2388 TRACE_ASSERT(objecthandle > 0 && objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],
2389 "uiIndexOfObject: Invalid value for objecthandle", 0);
2390
2391 if ((objectclass < TRACE_NCLASSES) && (objecthandle > 0) &&
2392 (objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]))
2393 {
2394 index = (uint16_t)(RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[objectclass] +
2395 (RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * (objecthandle - 1)));
2396 return index;
2397 }
2398
2399 prvTraceError("Object table lookup with invalid object handle or object class!");
2400 return 0;
2401 }
2402
prvTraceGetObjectHandle(traceObjectClass objectclass)2403 traceHandle prvTraceGetObjectHandle(traceObjectClass objectclass)
2404 {
2405 traceHandle handle;
2406 static int indexOfHandle;
2407
2408 TRACE_ALLOC_CRITICAL_SECTION();
2409
2410 TRACE_ASSERT(RecorderDataPtr != 0, "Recorder not initialized, call vTraceEnable() first!", (traceHandle)0);
2411
2412 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2413 "prvTraceGetObjectHandle: Invalid value for objectclass", (traceHandle)0);
2414
2415 trcCRITICAL_SECTION_BEGIN();
2416 indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass];
2417 if (objectHandleStacks.objectHandles[indexOfHandle] == 0)
2418 {
2419 /* Zero is used to indicate a never before used handle, i.e.,
2420 new slots in the handle stack. The handle slot needs to
2421 be initialized here (starts at 1). */
2422 objectHandleStacks.objectHandles[indexOfHandle] =
2423 (traceHandle)(1 + indexOfHandle -
2424 objectHandleStacks.lowestIndexOfClass[objectclass]);
2425 }
2426
2427 handle = objectHandleStacks.objectHandles[indexOfHandle];
2428
2429 if (objectHandleStacks.indexOfNextAvailableHandle[objectclass]
2430 > objectHandleStacks.highestIndexOfClass[objectclass])
2431 {
2432 prvTraceError(pszTraceGetErrorNotEnoughHandles(objectclass));
2433 handle = 0;
2434 }
2435 else
2436 {
2437 int hndCount;
2438 objectHandleStacks.indexOfNextAvailableHandle[objectclass]++;
2439
2440 hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] -
2441 objectHandleStacks.lowestIndexOfClass[objectclass];
2442
2443 if (hndCount >
2444 objectHandleStacks.handleCountWaterMarksOfClass[objectclass])
2445 {
2446 objectHandleStacks.handleCountWaterMarksOfClass[objectclass] =
2447 (traceHandle)hndCount;
2448 }
2449 }
2450 trcCRITICAL_SECTION_END();
2451
2452 return handle;
2453 }
2454
prvTraceFreeObjectHandle(traceObjectClass objectclass,traceHandle handle)2455 void prvTraceFreeObjectHandle(traceObjectClass objectclass, traceHandle handle)
2456 {
2457 int indexOfHandle;
2458
2459 TRACE_ASSERT(RecorderDataPtr != 0, "Recorder not initialized, call vTraceEnable() first!", TRC_UNUSED);
2460 TRACE_ASSERT(objectclass < TRACE_NCLASSES,
2461 "prvTraceFreeObjectHandle: Invalid value for objectclass", TRC_UNUSED);
2462 TRACE_ASSERT(handle > 0 && handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],
2463 "prvTraceFreeObjectHandle: Invalid value for handle", TRC_UNUSED);
2464
2465 /* Check that there is room to push the handle on the stack */
2466 if ((objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) <
2467 objectHandleStacks.lowestIndexOfClass[objectclass])
2468 {
2469 /* Error */
2470 prvTraceError("Attempt to free more handles than allocated!");
2471 }
2472 else
2473 {
2474 objectHandleStacks.indexOfNextAvailableHandle[objectclass]--;
2475 indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass];
2476 objectHandleStacks.objectHandles[indexOfHandle] = handle;
2477 }
2478 }
2479
2480 /*******************************************************************************
2481 * prvMarkObjectAsUsed
2482 *
2483 * Sets an "is used flag" on object creation, using the first byte of the name
2484 * field. This allows for counting the number of used Object Table slots, even
2485 * if no names have been set.
2486 ******************************************************************************/
prvMarkObjectAsUsed(traceObjectClass objectclass,traceHandle handle)2487 void prvMarkObjectAsUsed(traceObjectClass objectclass, traceHandle handle)
2488 {
2489 uint16_t idx = uiIndexOfObject(handle, objectclass);
2490 RecorderDataPtr->ObjectPropertyTable.objbytes[idx] = 1;
2491 }
2492
2493 /*******************************************************************************
2494 * prvStrncpy
2495 *
2496 * Private string copy function, to improve portability between compilers.
2497 ******************************************************************************/
prvStrncpy(char * dst,const char * src,uint32_t maxLength)2498 static void prvStrncpy(char* dst, const char* src, uint32_t maxLength)
2499 {
2500 uint32_t i;
2501 for (i = 0; i < maxLength; i++)
2502 {
2503 dst[i] = src[i];
2504 if (src[i] == 0)
2505 break;
2506 }
2507 }
2508
2509 /*******************************************************************************
2510 * prvTraceSetObjectName
2511 *
2512 * Registers the names of queues, semaphores and other kernel objects in the
2513 * recorder's Object Property Table, at the given handle and object class.
2514 ******************************************************************************/
prvTraceSetObjectName(traceObjectClass objectclass,traceHandle handle,const char * name)2515 void prvTraceSetObjectName(traceObjectClass objectclass,
2516 traceHandle handle,
2517 const char* name)
2518 {
2519 static uint16_t idx;
2520
2521 if (name == 0)
2522 {
2523 name = "";
2524 }
2525
2526 if (objectclass >= TRACE_NCLASSES)
2527 {
2528 prvTraceError("Illegal object class in prvTraceSetObjectName");
2529 return;
2530 }
2531
2532 if (handle == 0)
2533 {
2534 prvTraceError("Illegal handle (0) in prvTraceSetObjectName.");
2535 return;
2536 }
2537
2538 if (handle > RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass])
2539 {
2540 /* ERROR */
2541 prvTraceError(pszTraceGetErrorNotEnoughHandles(objectclass));
2542 }
2543 else
2544 {
2545 idx = uiIndexOfObject(handle, objectclass);
2546
2547 if (traceErrorMessage == 0)
2548 {
2549 prvStrncpy((char*)&(RecorderDataPtr->ObjectPropertyTable.objbytes[idx]),
2550 name,
2551 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ]);
2552 }
2553 }
2554 }
2555
prvTraceOpenSymbol(const char * name,TraceStringHandle_t userEventChannel)2556 TraceStringHandle_t prvTraceOpenSymbol(const char* name, TraceStringHandle_t userEventChannel)
2557 {
2558 uint16_t result;
2559 uint8_t len;
2560 uint8_t crc;
2561 TRACE_ALLOC_CRITICAL_SECTION();
2562
2563 len = 0;
2564 crc = 0;
2565
2566 TRACE_ASSERT(name != 0, "prvTraceOpenSymbol: name == NULL", (TraceStringHandle_t)0);
2567
2568 prvTraceGetChecksum(name, &crc, &len);
2569
2570 trcCRITICAL_SECTION_BEGIN();
2571 result = prvTraceLookupSymbolTableEntry(name, crc, len, userEventChannel);
2572 if (!result)
2573 {
2574 result = prvTraceCreateSymbolTableEntry(name, crc, len, userEventChannel);
2575 }
2576 trcCRITICAL_SECTION_END();
2577
2578 return result;
2579 }
2580
2581
2582 /******************************************************************************
2583 * vTraceSetFrequency
2584 *
2585 * Registers the clock rate of the time source for the event timestamping.
2586 * This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ)
2587 * should be incorrect for your setup, you can override it using this function.
2588 *
2589 * Must be called prior to vTraceEnable, and the time source is assumed to
2590 * have a fixed clock frequency after the startup.
2591 *
2592 * Note that, in snapshot mode, the value is divided by the TRC_HWTC_DIVISOR.
2593 * This is a software "prescaler" that is also applied on the timestamps.
2594 *****************************************************************************/
vTraceSetFrequency(uint32_t frequency)2595 void vTraceSetFrequency(uint32_t frequency)
2596 {
2597 timestampFrequency = frequency;
2598 }
2599
2600 /*******************************************************************************
2601 * Supporting functions
2602 ******************************************************************************/
2603
2604 /*******************************************************************************
2605 * prvTraceError
2606 *
2607 * Called by various parts in the recorder. Stops the recorder and stores a
2608 * pointer to an error message, which is printed by the monitor task.
2609 * If you are not using the monitor task, you may use xTraceErrorGetLast()
2610 * from your application to check if the recorder is OK.
2611 *
2612 * Note: If a recorder error is registered before vTraceStart is called, the
2613 * trace start will be aborted. This can occur if any of the Nxxxx constants
2614 * (e.g., TRC_CFG_NTASK) in trcConfig.h is too small.
2615 ******************************************************************************/
prvTraceError(const char * msg)2616 void prvTraceError(const char* msg)
2617 {
2618 /* Stop the recorder */
2619 if (RecorderDataPtr != 0)
2620 {
2621 xTraceDisable();
2622 }
2623
2624 /* If first error only... */
2625 if (traceErrorMessage == 0)
2626 {
2627 traceErrorMessage = (char*)(intptr_t) msg;
2628 if (RecorderDataPtr != 0)
2629 {
2630 prvStrncpy(RecorderDataPtr->systemInfo, traceErrorMessage, 80);
2631 RecorderDataPtr->internalErrorOccured = 1;
2632 }
2633 }
2634 }
2635
vTraceSetFilterMask(uint16_t filterMask)2636 void vTraceSetFilterMask(uint16_t filterMask)
2637 {
2638 CurrentFilterMask = filterMask;
2639 }
2640
vTraceSetFilterGroup(uint16_t filterGroup)2641 void vTraceSetFilterGroup(uint16_t filterGroup)
2642 {
2643 CurrentFilterGroup = filterGroup;
2644 }
2645
2646 /******************************************************************************
2647 * prvCheckDataToBeOverwrittenForMultiEntryEvents
2648 *
2649 * This checks if the next event to be overwritten is a multi-entry user event,
2650 * i.e., a USER_EVENT followed by data entries.
2651 * Such data entries do not have an event code at byte 0, as other events.
2652 * All 4 bytes are user data, so the first byte of such data events must
2653 * not be interpreted as type field. The number of data entries following
2654 * a USER_EVENT is given in the event code of the USER_EVENT.
2655 * Therefore, when overwriting a USER_EVENT (when using in ring-buffer mode)
2656 * any data entries following must be replaced with NULL events (code 0).
2657 *
2658 * This is assumed to execute within a critical section...
2659 *****************************************************************************/
2660
2661 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)
prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck)2662 void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck)
2663 {
2664 /* Generic "int" type is desired - should be 16 bit variable on 16 bit HW */
2665 unsigned int i = 0;
2666 unsigned int e = 0;
2667
2668 TRACE_ASSERT(nofEntriesToCheck != 0,
2669 "prvCheckDataToBeOverwrittenForMultiEntryEvents: nofEntriesToCheck == 0", TRC_UNUSED);
2670
2671 while (i < nofEntriesToCheck)
2672 {
2673 e = RecorderDataPtr->nextFreeIndex + i;
2674 if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) &&
2675 (RecorderDataPtr->eventData[e*4] < USER_EVENT + 16))
2676 {
2677 uint8_t nDataEvents = (uint8_t)(RecorderDataPtr->eventData[e*4] - USER_EVENT);
2678 if ((e + nDataEvents) < RecorderDataPtr->maxEvents)
2679 {
2680 (void)memset(& RecorderDataPtr->eventData[e*4], 0, (size_t) (4 + 4 * nDataEvents));
2681 }
2682 }
2683 else if (RecorderDataPtr->eventData[e*4] == DIV_XPS)
2684 {
2685 if ((e + 1) < RecorderDataPtr->maxEvents)
2686 {
2687 /* Clear 8 bytes */
2688 (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4);
2689 }
2690 else
2691 {
2692 /* Clear 8 bytes, 4 first and 4 last */
2693 (void)memset(& RecorderDataPtr->eventData[0], 0, 4);
2694 (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4);
2695 }
2696 }
2697 i++;
2698 }
2699 }
2700 #endif
2701
2702 /*******************************************************************************
2703 * prvTraceUpdateCounters
2704 *
2705 * Updates the index of the event buffer.
2706 ******************************************************************************/
prvTraceUpdateCounters(void)2707 void prvTraceUpdateCounters(void)
2708 {
2709 if (RecorderDataPtr->recorderActive == 0)
2710 {
2711 return;
2712 }
2713
2714 RecorderDataPtr->numEvents++;
2715
2716 RecorderDataPtr->nextFreeIndex++;
2717
2718 if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE))
2719 {
2720 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)
2721 RecorderDataPtr->bufferIsFull = 1;
2722 RecorderDataPtr->nextFreeIndex = 0;
2723 #else
2724 vTraceStop();
2725 #endif
2726 }
2727
2728 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)
2729 prvCheckDataToBeOverwrittenForMultiEntryEvents(1);
2730 #endif
2731 }
2732
2733 /******************************************************************************
2734 * prvTraceGetDTS
2735 *
2736 * Returns a differential timestamp (DTS), i.e., the time since
2737 * last event, and creates an XTS event if the DTS does not fit in the
2738 * number of bits given. The XTS event holds the MSB bytes of the DTS.
2739 *
2740 * The parameter param_maxDTS should be 0xFF for 8-bit dts or 0xFFFF for
2741 * events with 16-bit dts fields.
2742 *****************************************************************************/
prvTraceGetDTS(uint16_t param_maxDTS)2743 uint16_t prvTraceGetDTS(uint16_t param_maxDTS)
2744 {
2745 static uint32_t old_timestamp = 0;
2746 XTSEvent* xts = 0;
2747 uint32_t dts = 0;
2748 uint32_t timestamp = 0;
2749
2750 TRACE_ASSERT(param_maxDTS == 0xFF || param_maxDTS == 0xFFFF, "prvTraceGetDTS: Invalid value for param_maxDTS", 0);
2751
2752
2753 if (RecorderDataPtr->frequency == 0)
2754 {
2755 if (timestampFrequency != 0)
2756 {
2757 /* If to override default TRC_HWTC_FREQ_HZ value with value set by vTraceSetFrequency */
2758 RecorderDataPtr->frequency = timestampFrequency / (TRC_HWTC_DIVISOR);
2759 }
2760 else if (init_hwtc_count != (TRC_HWTC_COUNT))
2761 {
2762 /* If using default value and timer has been started.
2763 Note: If the default frequency value set here would be incorrect, e.g.,
2764 if the timer has actually not been configured yet, override this
2765 with vTraceSetFrequency.
2766 */
2767 RecorderDataPtr->frequency = (TRC_HWTC_FREQ_HZ) / (TRC_HWTC_DIVISOR);
2768 }
2769 /* If no override (vTraceSetFrequency) and timer inactive -> no action */
2770 }
2771
2772 /**************************************************************************
2773 * The below statements read the timestamp from the timer port module.
2774 * If necessary, whole seconds are extracted using division while the rest
2775 * comes from the modulo operation.
2776 **************************************************************************/
2777
2778 prvTracePortGetTimeStamp(×tamp);
2779
2780 /***************************************************************************
2781 * Since dts is unsigned the result will be correct even if timestamp has
2782 * wrapped around.
2783 ***************************************************************************/
2784 dts = timestamp - old_timestamp;
2785 old_timestamp = timestamp;
2786
2787 if (RecorderDataPtr->frequency > 0)
2788 {
2789 /* Check if dts > 1 second */
2790 if (dts > RecorderDataPtr->frequency)
2791 {
2792 /* More than 1 second has passed */
2793 RecorderDataPtr->absTimeLastEventSecond += dts / RecorderDataPtr->frequency;
2794 /* The part that is not an entire second is added to absTimeLastEvent */
2795 RecorderDataPtr->absTimeLastEvent += dts % RecorderDataPtr->frequency;
2796 }
2797 else
2798 {
2799 RecorderDataPtr->absTimeLastEvent += dts;
2800 }
2801
2802 /* Check if absTimeLastEvent >= 1 second */
2803 if (RecorderDataPtr->absTimeLastEvent >= RecorderDataPtr->frequency)
2804 {
2805 /* RecorderDataPtr->absTimeLastEvent is more than or equal to 1 second, but always less than 2 seconds */
2806 RecorderDataPtr->absTimeLastEventSecond++;
2807 RecorderDataPtr->absTimeLastEvent -= RecorderDataPtr->frequency;
2808 /* RecorderDataPtr->absTimeLastEvent is now less than 1 second */
2809 }
2810 }
2811 else
2812 {
2813 /* Special case if the recorder has not yet started (frequency may be uninitialized, i.e., zero) */
2814 RecorderDataPtr->absTimeLastEvent = timestamp;
2815 }
2816
2817 /* If the dts (time since last event) does not fit in event->dts (only 8 or 16 bits) */
2818 if (dts > param_maxDTS)
2819 {
2820 /* Create an XTS event (eXtended TimeStamp) containing the higher dts bits*/
2821 xts = (XTSEvent*) prvTraceNextFreeEventBufferSlot();
2822
2823 if (xts != 0)
2824 {
2825 if (param_maxDTS == 0xFFFF)
2826 {
2827 xts->type = XTS16;
2828 xts->xts_16 = (uint16_t)((dts / 0x10000) & 0xFFFF);
2829 xts->xts_8 = 0;
2830 }
2831 else if (param_maxDTS == 0xFF)
2832 {
2833 xts->type = XTS8;
2834 xts->xts_16 = (uint16_t)((dts / 0x100) & 0xFFFF);
2835 xts->xts_8 = (uint8_t)((dts / 0x1000000) & 0xFF);
2836 }
2837 else
2838 {
2839 prvTraceError("Bad param_maxDTS in prvTraceGetDTS");
2840 }
2841 prvTraceUpdateCounters();
2842 }
2843 }
2844
2845 return (uint16_t)dts & param_maxDTS;
2846 }
2847
2848 /*******************************************************************************
2849 * prvTraceLookupSymbolTableEntry
2850 *
2851 * Find an entry in the symbol table, return 0 if not present.
2852 *
2853 * The strings are stored in a byte pool, with four bytes of "meta-data" for
2854 * every string.
2855 * byte 0-1: index of next entry with same checksum (for fast lookup).
2856 * byte 2-3: reference to a symbol table entry, a label for xTracePrintF
2857 * format strings only (the handle of the destination channel).
2858 * byte 4..(4 + length): the string (object name or user event label), with
2859 * zero-termination
2860 ******************************************************************************/
prvTraceLookupSymbolTableEntry(const char * name,uint8_t crc6,uint8_t len,TraceStringHandle_t chn)2861 TraceStringHandle_t prvTraceLookupSymbolTableEntry(const char* name,
2862 uint8_t crc6,
2863 uint8_t len,
2864 TraceStringHandle_t chn)
2865 {
2866 uint16_t i = RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ];
2867
2868 TRACE_ASSERT(name != 0, "prvTraceLookupSymbolTableEntry: name == NULL", (TraceStringHandle_t)0);
2869 TRACE_ASSERT(len != 0, "prvTraceLookupSymbolTableEntry: len == 0", (TraceStringHandle_t)0);
2870
2871 while (i != 0)
2872 {
2873 if (RecorderDataPtr->SymbolTable.symbytes[i + 2] == (chn & 0x00FF))
2874 {
2875 if (RecorderDataPtr->SymbolTable.symbytes[i + 3] == (chn / 0x100))
2876 {
2877 if (RecorderDataPtr->SymbolTable.symbytes[i + 4 + len] == '\0')
2878 {
2879 if (strncmp((char*)(& RecorderDataPtr->SymbolTable.symbytes[i + 4]), name, len) == 0)
2880 {
2881 break; /* found */
2882 }
2883 }
2884 }
2885 }
2886 i = (uint16_t)(RecorderDataPtr->SymbolTable.symbytes[i] + (RecorderDataPtr->SymbolTable.symbytes[i + 1] * 0x100));
2887 }
2888 return i;
2889 }
2890
2891 /*******************************************************************************
2892 * prvTraceCreateSymbolTableEntry
2893 *
2894 * Creates an entry in the symbol table, independent if it exists already.
2895 *
2896 * The strings are stored in a byte pool, with four bytes of "meta-data" for
2897 * every string.
2898 * byte 0-1: index of next entry with same checksum (for fast lookup).
2899 * byte 2-3: reference to a symbol table entry, a label for xTracePrintF
2900 * format strings only (the handle of the destination channel).
2901 * byte 4..(4 + length): the string (object name or user event label), with
2902 * zero-termination
2903 ******************************************************************************/
prvTraceCreateSymbolTableEntry(const char * name,uint8_t crc6,uint8_t len,TraceStringHandle_t channel)2904 TraceStringHandle_t prvTraceCreateSymbolTableEntry(const char* name,
2905 uint8_t crc6,
2906 uint8_t len,
2907 TraceStringHandle_t channel)
2908 {
2909 TraceStringHandle_t ret = 0;
2910
2911 TRACE_ASSERT(name != 0, "prvTraceCreateSymbolTableEntry: name == NULL", 0);
2912 TRACE_ASSERT(len != 0, "prvTraceCreateSymbolTableEntry: len == 0", 0);
2913
2914 if (RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + len + 4 >= (TRC_CFG_SYMBOL_TABLE_SIZE))
2915 {
2916 prvTraceError("Symbol table full. Increase TRC_CFG_SYMBOL_TABLE_SIZE in trcConfig.h");
2917 ret = 0;
2918 }
2919 else
2920 {
2921
2922 RecorderDataPtr->SymbolTable.symbytes
2923 [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] =
2924 (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] & 0x00FF);
2925
2926 RecorderDataPtr->SymbolTable.symbytes
2927 [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] =
2928 (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] / 0x100);
2929
2930 RecorderDataPtr->SymbolTable.symbytes
2931 [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] =
2932 (uint8_t)(channel & 0x00FF);
2933
2934 RecorderDataPtr->SymbolTable.symbytes
2935 [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] =
2936 (uint8_t)(channel / 0x100);
2937
2938 /* set name (bytes 4...4+len-1) */
2939 prvStrncpy((char*)&(RecorderDataPtr->SymbolTable.symbytes
2940 [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4]), name, len);
2941
2942 /* Set zero termination (at offset 4+len) */
2943 RecorderDataPtr->SymbolTable.symbytes
2944 [RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4 + len] = '\0';
2945
2946 /* store index of entry (for return value, and as head of LL[crc6]) */
2947 RecorderDataPtr->SymbolTable.latestEntryOfChecksum
2948 [ crc6 ] = (uint16_t)RecorderDataPtr->SymbolTable.nextFreeSymbolIndex;
2949
2950 RecorderDataPtr->SymbolTable.nextFreeSymbolIndex += (uint32_t) (len + 5);
2951
2952 ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex - (uint8_t)(len + 5));
2953 }
2954
2955 return ret;
2956 }
2957
2958
2959 /*******************************************************************************
2960 * prvTraceGetChecksum
2961 *
2962 * Calculates a simple 6-bit checksum from a string, used to index the string
2963 * for fast symbol table lookup.
2964 ******************************************************************************/
prvTraceGetChecksum(const char * pname,uint8_t * pcrc,uint8_t * plength)2965 void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength)
2966 {
2967 unsigned char c;
2968 int length = 1; /* Should be 1 to account for '\0' */
2969 int crc = 0;
2970
2971 TRACE_ASSERT(pname != 0, "prvTraceGetChecksum: pname == NULL", TRC_UNUSED);
2972 TRACE_ASSERT(pcrc != 0, "prvTraceGetChecksum: pcrc == NULL", TRC_UNUSED);
2973 TRACE_ASSERT(plength != 0, "prvTraceGetChecksum: plength == NULL", TRC_UNUSED);
2974
2975 if (pname != (const char *) 0)
2976 {
2977 for (; (c = (unsigned char) *pname++) != '\0';)
2978 {
2979 crc += c;
2980 length++;
2981 }
2982 }
2983 *pcrc = (uint8_t)(crc & 0x3F);
2984 *plength = (uint8_t)length;
2985 }
2986
2987 #if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1)
2988
2989 static void prvTraceStoreXID(traceHandle handle);
2990
2991 /******************************************************************************
2992 * prvTraceStoreXID
2993 *
2994 * Stores an XID (eXtended IDentifier) event.
2995 * This is used if an object/task handle is larger than 255.
2996 * The parameter "handle" is the full (16 bit) handle, assumed to be 256 or
2997 * larger. Handles below 256 should not use this function.
2998 *
2999 * NOTE: this function MUST be called from within a critical section.
3000 *****************************************************************************/
prvTraceStoreXID(traceHandle handle)3001 static void prvTraceStoreXID(traceHandle handle)
3002 {
3003 XPSEvent* xid;
3004
3005 TRACE_ASSERT(handle >= 256, "prvTraceStoreXID: Handle < 256", TRC_UNUSED);
3006
3007 xid = (XPSEvent*)prvTraceNextFreeEventBufferSlot();
3008
3009 if (xid != 0)
3010 {
3011 xid->type = XID;
3012
3013 /* This function is (only) used when traceHandle is 16 bit... */
3014 xid->xps_16 = handle;
3015
3016 prvTraceUpdateCounters();
3017 }
3018 }
3019
prvTraceGet8BitHandle(traceHandle handle)3020 static uint8_t prvTraceGet8BitHandle(traceHandle handle)
3021 {
3022 if (handle > 255)
3023 {
3024 prvTraceStoreXID(handle);
3025 /* The full handle (16 bit) is stored in the XID event.
3026 This code (255) is used instead of zero (which is an error code).*/
3027 return 255;
3028 }
3029 return (uint8_t)(handle & 0xFF);
3030 }
3031 #endif /*(TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1)*/
3032
3033
3034 /* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */
3035 #ifndef TRC_CFG_ARM_CM_USE_SYSTICK
3036 #if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03)))
xTraceHardwarePortInitCortexM()3037 void xTraceHardwarePortInitCortexM()
3038 {
3039 /* Ensure that the DWT registers are unlocked and can be modified. */
3040 TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK;
3041
3042 /* Make sure DWT is enabled, if supported */
3043 TRC_REG_DEMCR |= TRC_DEMCR_TRCENA;
3044
3045 do{
3046 /* Verify that DWT is supported */
3047 if (TRC_REG_DEMCR == 0)
3048 {
3049 /* This function is called on Cortex-M3, M4 and M7 devices to initialize
3050 the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
3051
3052 If the below error is produced, the DWT unit does not seem to be available.
3053
3054 In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
3055 to use SysTick timestamping instead, or define your own timestamping by
3056 setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
3057 and make the necessary definitions, as explained in trcHardwarePort.h.*/
3058
3059 prvTraceError("DWT unit not available, see code comment.");
3060 break;
3061 }
3062
3063 /* Verify that DWT_CYCCNT is supported */
3064 if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT)
3065 {
3066 /* This function is called on Cortex-M3, M4 and M7 devices to initialize
3067 the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
3068
3069 If the below error is produced, the cycle counter does not seem to be available.
3070
3071 In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
3072 to use SysTick timestamping instead, or define your own timestamping by
3073 setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
3074 and make the necessary definitions, as explained in trcHardwarePort.h.*/
3075
3076 prvTraceError("DWT_CYCCNT not available, see code comment.");
3077 break;
3078 }
3079
3080 /* Reset the cycle counter */
3081 TRC_REG_DWT_CYCCNT = 0;
3082
3083 /* Enable the cycle counter */
3084 TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA;
3085
3086 }while(0); /* breaks above jump here */
3087 }
3088 #endif
3089 #endif
3090
3091 /******************************************************************************
3092 * prvTracePortGetTimeStamp
3093 *
3094 * Returns the current time based on the HWTC macros which provide a hardware
3095 * isolation layer towards the hardware timer/counter.
3096 *
3097 * The HWTC macros and prvTracePortGetTimeStamp is the main porting issue
3098 * or the trace recorder library. Typically you should not need to change
3099 * the code of prvTracePortGetTimeStamp if using the HWTC macros.
3100 *
3101 ******************************************************************************/
prvTracePortGetTimeStamp(uint32_t * pTimestamp)3102 void prvTracePortGetTimeStamp(uint32_t *pTimestamp)
3103 {
3104 static uint32_t last_hwtc_count = 0;
3105 uint32_t hwtc_count = 0;
3106
3107 #if TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR
3108 /* systick based timer */
3109 static uint32_t last_traceTickCount = 0;
3110 uint32_t traceTickCount = 0;
3111 #else /*TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR*/
3112 /* Free running timer */
3113 static uint32_t last_hwtc_rest = 0;
3114 uint32_t diff = 0;
3115 uint32_t diff_scaled = 0;
3116 #endif /*TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR*/
3117
3118 if (trace_disable_timestamp == 1)
3119 {
3120 if (pTimestamp)
3121 *pTimestamp = last_timestamp;
3122 return;
3123 }
3124
3125 /* Retrieve TRC_HWTC_COUNT only once since the same value should be used all throughout this function. */
3126 #if (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR)
3127 /* Get the increasing tick count */
3128 hwtc_count = (TRC_HWTC_COUNT);
3129 #elif (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR || TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR)
3130 /* Convert decreasing tick count into increasing tick count */
3131 hwtc_count = (TRC_HWTC_PERIOD) - (TRC_HWTC_COUNT);
3132 #else
3133 #error "TRC_HWTC_TYPE has unexpected value"
3134 #endif
3135
3136 #if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Win32)
3137 /* The Win32 port uses ulGetRunTimeCounterValue for timestamping, which in turn
3138 uses QueryPerformanceCounter. That function is not always reliable when used over
3139 multiple threads. We must therefore handle rare cases where the timestamp is less
3140 than the previous. In practice, this should "never" roll over since the
3141 performance counter is 64 bit wide. */
3142
3143 if (last_hwtc_count > hwtc_count)
3144 {
3145 hwtc_count = last_hwtc_count;
3146 }
3147 #endif
3148
3149 #if (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)
3150 /* Timestamping is based on a timer that wraps at TRC_HWTC_PERIOD */
3151 if (last_traceTickCount - uiTraceTickCount - 1 < 0x80000000)
3152 {
3153 /* This means last_traceTickCount is higher than uiTraceTickCount,
3154 so we have previously compensated for a missed tick.
3155 Therefore we use the last stored value because that is more accurate. */
3156 traceTickCount = last_traceTickCount;
3157 }
3158 else
3159 {
3160 /* Business as usual */
3161 traceTickCount = uiTraceTickCount;
3162 }
3163
3164 /* Check for overflow. May occur if the update of uiTraceTickCount has been
3165 delayed due to disabled interrupts. */
3166 if (traceTickCount == last_traceTickCount && hwtc_count < last_hwtc_count)
3167 {
3168 /* A trace tick has occurred but not been executed by the kernel, so we compensate manually. */
3169 traceTickCount++;
3170 }
3171
3172 /* Check if the return address is OK, then we perform the calculation. */
3173 if (pTimestamp)
3174 {
3175 /* Get timestamp from trace ticks. Scale down the period to avoid unwanted overflows. */
3176 last_timestamp = traceTickCount * ((TRC_HWTC_PERIOD) / (TRC_HWTC_DIVISOR));
3177 /* Increase timestamp by (hwtc_count + "lost hardware ticks from scaling down period") / TRC_HWTC_DIVISOR. */
3178 last_timestamp += (hwtc_count + traceTickCount * ((TRC_HWTC_PERIOD) % (TRC_HWTC_DIVISOR))) / (TRC_HWTC_DIVISOR);
3179 }
3180 /* Store the previous value */
3181 last_traceTickCount = traceTickCount;
3182
3183 #else /*(TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)*/
3184
3185 /* Timestamping is based on a free running timer */
3186 /* This part handles free running clocks that can be scaled down to avoid too large DTS values.
3187 Without this, the scaled timestamp will incorrectly wrap at (2^32 / TRC_HWTC_DIVISOR) ticks.
3188 The scaled timestamp returned from this function is supposed to go from 0 -> 2^32, which in real time would represent (0 -> 2^32 * TRC_HWTC_DIVISOR) ticks. */
3189
3190 /* First we see how long time has passed since the last timestamp call, and we also add the ticks that was lost when we scaled down the last time. */
3191 diff = (hwtc_count - last_hwtc_count) + last_hwtc_rest;
3192
3193 /* Scale down the diff */
3194 diff_scaled = diff / (TRC_HWTC_DIVISOR);
3195
3196 /* Find out how many ticks were lost when scaling down, so we can add them the next time */
3197 last_hwtc_rest = diff % (TRC_HWTC_DIVISOR);
3198
3199 /* We increase the scaled timestamp by the scaled amount */
3200 last_timestamp += diff_scaled;
3201 #endif /*(TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)*/
3202
3203 /* Is anyone interested in the results? */
3204 if (pTimestamp)
3205 *pTimestamp = last_timestamp;
3206
3207 /* Store the previous value */
3208 last_hwtc_count = hwtc_count;
3209 }
3210
3211 #if defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)
3212
prvAddTaskToStackMonitor(void * task)3213 void prvAddTaskToStackMonitor(void* task)
3214 {
3215 int i;
3216 int foundEmptySlot = 0;
3217
3218 // find an empty slot
3219 for (i = 0; i < TRC_CFG_STACK_MONITOR_MAX_TASKS; i++)
3220 {
3221 if (tasksInStackMonitor[i].tcb == 0)
3222 {
3223 tasksInStackMonitor[i].tcb = task;
3224 tasksInStackMonitor[i].uiPreviousLowMark = 0xFFFFFFFF;
3225 foundEmptySlot = 1;
3226 break;
3227 }
3228 }
3229
3230 if (foundEmptySlot == 0)
3231 {
3232 tasksNotIncluded++;
3233 }
3234 }
3235
prvRemoveTaskFromStackMonitor(void * task)3236 void prvRemoveTaskFromStackMonitor(void* task)
3237 {
3238 int i;
3239
3240 for (i = 0; i < TRC_CFG_STACK_MONITOR_MAX_TASKS; i++)
3241 {
3242 if (tasksInStackMonitor[i].tcb == task)
3243 {
3244 tasksInStackMonitor[i].tcb = 0;
3245 tasksInStackMonitor[i].uiPreviousLowMark = 0;
3246 }
3247 }
3248 }
3249
prvReportStackUsage()3250 void prvReportStackUsage()
3251 {
3252 static int i = 0; /* Static index used to loop over the monitored tasks */
3253 int count = 0; /* The number of generated reports */
3254 int initial = i; /* Used to make sure we break if we are back at the inital value */
3255
3256 do
3257 {
3258 /* Check the current spot */
3259 if (tasksInStackMonitor[i].tcb != 0)
3260 {
3261 /* Get the amount of unused stack */
3262 uint32_t unusedStackSpace;
3263 xTraceKernelPortGetUnusedStack(tasksInStackMonitor[i].tcb, &unusedStackSpace);
3264
3265 /* Store for later use */
3266 if (tasksInStackMonitor[i].uiPreviousLowMark > unusedStackSpace)
3267 tasksInStackMonitor[i].uiPreviousLowMark = unusedStackSpace;
3268
3269 prvTraceStoreKernelCallWithParam(TRACE_UNUSED_STACK, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(tasksInStackMonitor[i].tcb), tasksInStackMonitor[i].uiPreviousLowMark);
3270
3271 count++;
3272 }
3273
3274 i = (i + 1) % TRC_CFG_STACK_MONITOR_MAX_TASKS; // Move i beyond this task
3275 } while (count < TRC_CFG_STACK_MONITOR_MAX_REPORTS && i != initial);
3276 }
3277 #endif /* defined(TRC_CFG_ENABLE_STACK_MONITOR) && (TRC_CFG_ENABLE_STACK_MONITOR == 1) && (TRC_CFG_SCHEDULING_ONLY == 0) */
3278
3279
3280 #endif /* (TRC_USE_TRACEALYZER_RECORDER == 1) */
3281
3282 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)*/
3283