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