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