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