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