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(×tamp);
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