1 /*******************************************************************************
\r
2 * Trace Recorder Library for Tracealyzer v4.1.5
\r
3 * Percepio AB, www.percepio.com
\r
5 * trcStreamingRecorder.c
\r
7 * The generic core of the trace recorder's streaming mode.
\r
10 * This file is part of the trace recorder library (RECORDER), which is the
\r
11 * intellectual property of Percepio AB (PERCEPIO) and provided under a
\r
12 * license as follows.
\r
13 * The RECORDER may be used free of charge for the purpose of recording data
\r
14 * intended for analysis in PERCEPIO products. It may not be used or modified
\r
15 * for other purposes without explicit permission from PERCEPIO.
\r
16 * You may distribute the RECORDER in its original source code form, assuming
\r
17 * this text (terms of use, disclaimer, copyright notice) is unchanged. You are
\r
18 * allowed to distribute the RECORDER with minor modifications intended for
\r
19 * configuration or porting of the RECORDER, e.g., to allow using it on a
\r
20 * specific processor, processor family or with a specific communication
\r
21 * interface. Any such modifications should be documented directly below
\r
22 * this comment block.
\r
25 * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty
\r
26 * as to its use or performance. PERCEPIO does not and cannot warrant the
\r
27 * performance or results you may obtain by using the RECORDER or documentation.
\r
28 * PERCEPIO make no warranties, express or implied, as to noninfringement of
\r
29 * third party rights, merchantability, or fitness for any particular purpose.
\r
30 * In no event will PERCEPIO, its technology partners, or distributors be liable
\r
31 * to you for any consequential, incidental or special damages, including any
\r
32 * lost profits or lost savings, even if a representative of PERCEPIO has been
\r
33 * advised of the possibility of such damages, or for any claim by any third
\r
34 * party. Some jurisdictions do not allow the exclusion or limitation of
\r
35 * incidental, consequential or special damages, or the exclusion of implied
\r
36 * warranties or limitations on how long an implied warranty may last, so the
\r
37 * above limitations may not apply to you.
\r
39 * Tabs are used for indent in this file (1 tab = 4 spaces)
\r
41 * Copyright Percepio AB, 2018.
\r
43 ******************************************************************************/
\r
45 #include "trcRecorder.h"
\r
47 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)
\r
49 #if (TRC_USE_TRACEALYZER_RECORDER == 1)
\r
56 uint16_t EventCount;
\r
78 /* Used in event functions with variable number of parameters. */
\r
82 uint32_t data[15]; /* maximum payload size */
\r
90 uint16_t symbolSize;
\r
91 uint16_t symbolCount;
\r
92 uint16_t objectDataSize;
\r
93 uint16_t objectDataCount;
\r
97 /* The size of each slot in the Symbol Table */
\r
98 #define SYMBOL_TABLE_SLOT_SIZE (sizeof(uint32_t) + (((TRC_CFG_SYMBOL_MAX_LENGTH)+(sizeof(uint32_t)-1))/sizeof(uint32_t))*sizeof(uint32_t))
\r
100 #define OBJECT_DATA_SLOT_SIZE (sizeof(uint32_t) + sizeof(uint32_t))
\r
102 /* The total size of the Symbol Table */
\r
103 #define SYMBOL_TABLE_BUFFER_SIZE ((TRC_CFG_SYMBOL_TABLE_SLOTS) * SYMBOL_TABLE_SLOT_SIZE)
\r
105 /* The total size of the Object Data Table */
\r
106 #define OBJECT_DATA_TABLE_BUFFER_SIZE ((TRC_CFG_OBJECT_DATA_SLOTS) * OBJECT_DATA_SLOT_SIZE)
\r
108 /* The Symbol Table type - just a byte array */
\r
112 uint32_t pSymbolTableBufferUINT32[SYMBOL_TABLE_BUFFER_SIZE / sizeof(uint32_t)];
\r
113 uint8_t pSymbolTableBufferUINT8[SYMBOL_TABLE_BUFFER_SIZE];
\r
114 } SymbolTableBuffer;
\r
117 /* The Object Data Table type - just a byte array */
\r
121 uint32_t pObjectDataTableBufferUINT32[OBJECT_DATA_TABLE_BUFFER_SIZE / sizeof(uint32_t)];
\r
122 uint8_t pObjectDataTableBufferUINT8[OBJECT_DATA_TABLE_BUFFER_SIZE];
\r
123 } ObjectDataTableBuffer;
\r
127 uint16_t Status; /* 16 bit to avoid implicit padding (warnings) */
\r
128 uint16_t BytesRemaining;
\r
129 char* WritePointer;
\r
132 /* Code used for "task address" when no task has started. (NULL = idle task) */
\r
133 #define HANDLE_NO_TASK 2
\r
135 #define PAGE_STATUS_FREE 0
\r
136 #define PAGE_STATUS_WRITE 1
\r
137 #define PAGE_STATUS_READ 2
\r
139 #define PSF_ASSERT(_assert, _err) if (! (_assert)){ prvTraceError(_err); return; }
\r
141 /* Part of the PSF format - encodes the number of 32-bit params in an event */
\r
142 #define PARAM_COUNT(n) ((n & 0xF) << 12)
\r
144 /* The Symbol Table instance - keeps names of tasks and other named objects. */
\r
145 static SymbolTable symbolTable = { { { 0 } } };
\r
147 /* This points to the first unused entry in the symbol table. */
\r
148 static uint32_t firstFreeSymbolTableIndex = 0;
\r
150 /* The Object Data Table instance - keeps initial priorities of tasks. */
\r
151 static ObjectDataTable objectDataTable = { { { 0 } } };
\r
153 /* This points to the first unused entry in the object data table. */
\r
154 static uint32_t firstFreeObjectDataTableIndex = 0;
\r
156 /* Keeps track of ISR nesting */
\r
157 static uint32_t ISR_stack[TRC_CFG_MAX_ISR_NESTING];
\r
159 /* Keeps track of ISR nesting */
\r
160 static int8_t ISR_stack_index = -1;
\r
162 /* Any error that occurred in the recorder (also creates User Event) */
\r
163 static int errorCode = 0;
\r
165 /* Counts the number of trace sessions (not yet used) */
\r
166 static uint32_t SessionCounter = 0u;
\r
168 /* Master switch for recording (0 => Disabled, 1 => Enabled) */
\r
169 uint32_t RecorderEnabled = 0u;
\r
171 /* Used to determine endian of data (big/little) */
\r
172 static uint32_t PSFEndianessIdentifier = 0x50534600;
\r
174 /* Used to interpret the data format */
\r
175 static uint16_t FormatVersion = 0x0004;
\r
177 /* The number of events stored. Used as event sequence number. */
\r
178 static uint32_t eventCounter = 0;
\r
180 /* Remembers if an earlier ISR in a sequence of adjacent ISRs has triggered a task switch.
\r
181 In that case, vTraceStoreISREnd does not store a return to the previously executing task. */
\r
182 int32_t isPendingContextSwitch = 0;
\r
184 uint32_t uiTraceTickCount = 0;
\r
185 uint32_t timestampFrequency = 0;
\r
186 uint32_t DroppedEventCounter = 0;
\r
187 uint32_t TotalBytesRemaining_LowWaterMark = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
\r
188 uint32_t TotalBytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
\r
190 PageType PageInfo[TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT];
\r
192 char* EventBuffer = NULL;
\r
194 /*******************************************************************************
\r
197 * Incremented on prvTraceSaveSymbol if no room for saving the symbol name. This
\r
198 * is used for storing the names of:
\r
200 * - Named ISRs (xTraceSetISRProperties)
\r
201 * - Named kernel objects (vTraceStoreKernelObjectName)
\r
202 * - User event channels (xTraceRegisterString)
\r
204 * This variable should be zero. If not, it shows the number of missing slots so
\r
205 * far. In that case, increment SYMBOL_TABLE_SLOTS with (at least) this value.
\r
206 ******************************************************************************/
\r
207 volatile uint32_t NoRoomForSymbol = 0;
\r
209 /*******************************************************************************
\r
210 * NoRoomForObjectData
\r
212 * Incremented on prvTraceSaveObjectData if no room for saving the object data,
\r
213 * i.e., the base priorities of tasks. There must be one slot for each task.
\r
214 * If not, this variable will show the difference.
\r
216 * This variable should be zero. If not, it shows the number of missing slots so
\r
217 * far. In that case, increment OBJECT_DATA_SLOTS with (at least) this value.
\r
218 ******************************************************************************/
\r
219 volatile uint32_t NoRoomForObjectData = 0;
\r
221 /*******************************************************************************
\r
222 * LongestSymbolName
\r
224 * Updated in prvTraceSaveSymbol. Should not exceed TRC_CFG_SYMBOL_MAX_LENGTH,
\r
225 * otherwise symbol names will be truncated. In that case, set
\r
226 * TRC_CFG_SYMBOL_MAX_LENGTH to (at least) this value.
\r
227 ******************************************************************************/
\r
228 volatile uint32_t LongestSymbolName = 0;
\r
230 /*******************************************************************************
\r
231 * MaxBytesTruncated
\r
233 * Set in prvTraceStoreStringEvent if the total data payload exceeds 60 bytes,
\r
234 * including data arguments and the string. For user events, that is 52 bytes
\r
235 * for string and data arguments. In that is exceeded, the event is truncated
\r
236 * (usually only the string, unless more than 15 parameters) and this variable
\r
237 * holds the maximum number of truncated bytes, from any event.
\r
238 ******************************************************************************/
\r
239 volatile uint32_t MaxBytesTruncated = 0;
\r
241 uint16_t CurrentFilterMask = 0xFFFF;
\r
243 uint16_t CurrentFilterGroup = FilterGroup0;
\r
245 /* Internal common function for storing string events */
\r
246 static void prvTraceStoreStringEventHelper( int nArgs,
\r
248 traceString userEvtChannel,
\r
253 /* Not static to avoid warnings from SysGCC/PPC */
\r
254 void prvTraceStoreSimpleStringEventHelper(traceString userEvtChannel,
\r
258 /* Stores the header information on Start */
\r
259 static void prvTraceStoreHeader(void);
\r
261 /* Stores the symbol table on Start */
\r
262 static void prvTraceStoreSymbolTable(void);
\r
264 /* Stores the object table on Start */
\r
265 static void prvTraceStoreObjectDataTable(void);
\r
267 /* Store the Timestamp Config on Start */
\r
268 static void prvTraceStoreTSConfig(void);
\r
270 /* Store the current warnings */
\r
271 static void prvTraceStoreWarnings(void);
\r
273 /* Internal function for starting/stopping the recorder. */
\r
274 static void prvSetRecorderEnabled(uint32_t isEnabled);
\r
276 /* Mark the page read as complete. */
\r
277 static void prvPageReadComplete(int pageIndex);
\r
279 /* Retrieve a buffer page to write to. */
\r
280 static int prvAllocateBufferPage(int prevPage);
\r
282 /* Get the current buffer page index (return value) and the number
\r
283 of valid bytes in the buffer page (bytesUsed). */
\r
284 static int prvGetBufferPage(int32_t* bytesUsed);
\r
286 /* Performs timestamping using definitions in trcHardwarePort.h */
\r
287 static uint32_t prvGetTimestamp32(void);
\r
289 /* Signal an error. */
\r
290 void prvTraceError(int errCode);
\r
292 /* Signal an warning (does not stop the recorder). */
\r
293 void prvTraceWarning(int errCode);
\r
295 /******************************************************************************
\r
296 * vTraceInstanceFinishedNow
\r
298 * Creates an event that ends the current task instance at this very instant.
\r
299 * This makes the viewer to splits the current fragment at this point and begin
\r
300 * a new actor instance, even if no task-switch has occurred.
\r
301 *****************************************************************************/
\r
302 void vTraceInstanceFinishedNow(void)
\r
304 prvTraceStoreEvent0(PSF_EVENT_IFE_DIRECT);
\r
307 /******************************************************************************
\r
308 * vTraceInstanceFinishedNext
\r
310 * Marks the current "task instance" as finished on the next kernel call.
\r
312 * If that kernel call is blocking, the instance ends after the blocking event
\r
313 * and the corresponding return event is then the start of the next instance.
\r
314 * If the kernel call is not blocking, the viewer instead splits the current
\r
315 * fragment right before the kernel call, which makes this call the first event
\r
316 * of the next instance.
\r
317 *****************************************************************************/
\r
318 void vTraceInstanceFinishedNext(void)
\r
320 prvTraceStoreEvent0(PSF_EVENT_IFE_NEXT);
\r
323 /*******************************************************************************
\r
324 * vTraceStoreKernelObjectName
\r
326 * Parameter object: pointer to the Event Group that shall be named
\r
327 * Parameter name: the name to set (const string literal)
\r
329 * Sets a name for a kernel object for display in Tracealyzer.
\r
330 ******************************************************************************/
\r
331 void vTraceStoreKernelObjectName(void* object, const char* name)
\r
333 /* Always save in symbol table, if the recording has not yet started */
\r
334 prvTraceSaveSymbol(object, name);
\r
336 prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, name, (uint32_t)object);
\r
340 /******************************************************************************
\r
341 * vTraceSetFrequency
\r
343 * Registers the clock rate of the time source for the event timestamping.
\r
344 * This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ)
\r
345 * should be incorrect for your setup, you can override it using this function.
\r
347 * Must be called prior to vTraceEnable, and the time source is assumed to
\r
348 * have a fixed clock frequency after the startup.
\r
349 *****************************************************************************/
\r
350 void vTraceSetFrequency(uint32_t frequency)
\r
352 timestampFrequency = frequency;
\r
355 #if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)
\r
357 /*******************************************************************************
\r
358 * xTraceRegisterString
\r
360 * Stores a name for a user event channel, returns the handle.
\r
361 ******************************************************************************/
\r
362 traceString xTraceRegisterString(const char* name)
\r
364 prvTraceSaveSymbol((const void*)name, name);
\r
366 /* Always save in symbol table, if the recording has not yet started */
\r
367 prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, (const char*)name, (uint32_t)name);
\r
369 return (traceString)name;
\r
372 /******************************************************************************
\r
375 * Generates "User Events", with unformatted text.
\r
377 * User Events can be used for very efficient application logging, and are shown
\r
378 * as yellow labels in the main trace view.
\r
380 * You may group User Events into User Event Channels. The yellow User Event
\r
381 * labels shows the logged string, preceded by the channel name within
\r
382 * brackets. For example:
\r
384 * "[MyChannel] Hello World!"
\r
386 * The User Event Channels are shown in the View Filter, which makes it easy to
\r
387 * select what User Events you wish to display. User Event Channels are created
\r
388 * using xTraceRegisterString().
\r
392 * traceString chn = xTraceRegisterString("MyChannel");
\r
394 * vTracePrint(chn, "Hello World!");
\r
396 ******************************************************************************/
\r
397 void vTracePrint(traceString chn, const char* str)
\r
399 prvTraceStoreSimpleStringEventHelper(chn, str);
\r
403 /*******************************************************************************
\r
404 * vTraceConsoleChannelPrintF
\r
406 * Wrapper for vTracePrint, using the default channel. Can be used as a drop-in
\r
407 * replacement for printf and similar functions, e.g. in a debug logging macro.
\r
411 * // Old: #define LogString debug_console_printf
\r
413 * // New, log to Tracealyzer instead:
\r
414 * #define LogString vTraceConsoleChannelPrintF
\r
416 * LogString("My value is: %d", myValue);
\r
417 ******************************************************************************/
\r
418 void vTraceConsoleChannelPrintF(const char* fmt, ...)
\r
422 static traceString consoleChannel = NULL;
\r
424 if (consoleChannel == NULL)
\r
425 consoleChannel = xTraceRegisterString("Debug Console");
\r
428 vsnprintf(tempBuf, 60, fmt, vl);
\r
429 vTracePrint(consoleChannel, tempBuf);
\r
433 /******************************************************************************
\r
436 * Generates "User Events", with formatted text and data, similar to a "printf".
\r
437 * It is very fast since the actual formatting is done on the host side when the
\r
438 * trace is displayed.
\r
440 * User Events can be used for very efficient application logging, and are shown
\r
441 * as yellow labels in the main trace view.
\r
442 * An advantage of User Events is that data can be plotted in the "User Event
\r
443 * Signal Plot" view, visualizing any data you log as User Events, discrete
\r
444 * states or control system signals (e.g. system inputs or outputs).
\r
446 * You may group User Events into User Event Channels. The yellow User Event
\r
447 * labels show the logged string, preceded by the channel name within brackets.
\r
451 * "[MyChannel] Hello World!"
\r
453 * The User Event Channels are shown in the View Filter, which makes it easy to
\r
454 * select what User Events you wish to display. User Event Channels are created
\r
455 * using xTraceRegisterString().
\r
459 * traceString adc_uechannel = xTraceRegisterString("ADC User Events");
\r
461 * vTracePrintF(adc_uechannel,
\r
462 * "ADC channel %d: %d volts",
\r
463 * ch, adc_reading);
\r
465 * All data arguments are assumed to be 32 bit wide. The following formats are
\r
467 * %d - signed integer. The following width and padding format is supported: "%05d" -> "-0042" and "%5d" -> " -42"
\r
468 * %u - unsigned integer. The following width and padding format is supported: "%05u" -> "00042" and "%5u" -> " 42"
\r
469 * %X - hexadecimal (uppercase). The following width and padding format is supported: "%04X" -> "002A" and "%4X" -> " 2A"
\r
470 * %x - hexadecimal (lowercase). The following width and padding format is supported: "%04x" -> "002a" and "%4x" -> " 2a"
\r
471 * %s - string (currently, this must be an earlier stored symbol name)
\r
473 * Up to 15 data arguments are allowed, with a total size of maximum 60 byte
\r
474 * including 8 byte for the base event fields and the format string. So with
\r
475 * one data argument, the maximum string length is 48 chars. If this is exceeded
\r
476 * the string is truncated (4 bytes at a time).
\r
478 ******************************************************************************/
\r
479 void vTracePrintF(traceString chn, const char* fmt, ...)
\r
486 /* Count the number of arguments in the format string (e.g., %d) */
\r
487 for (i = 0; (fmt[i] != 0) && (i < 52); i++)
\r
491 if (fmt[i + 1] != 0 && fmt[i + 1] != '%')
\r
493 nArgs++; /* Found an argument */
\r
496 i++; /* Move past format specifier or non-argument '%' */
\r
504 prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs + 1), chn, i, fmt, &vl);
\r
508 prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs), chn, i, fmt, &vl);
\r
512 #endif /* (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) */
\r
514 /*******************************************************************************
\r
515 * xTraceSetISRProperties
\r
517 * Stores a name and priority level for an Interrupt Service Routine, to allow
\r
518 * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin.
\r
521 * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
523 * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
\r
525 * void ISR_handler()
\r
527 * vTraceStoreISRBegin(Timer1Handle);
\r
529 * vTraceStoreISREnd(0);
\r
532 ******************************************************************************/
\r
533 traceHandle xTraceSetISRProperties(const char* name, uint8_t priority)
\r
535 /* Save object data in object data table */
\r
536 prvTraceSaveObjectData((const void*)name, priority);
\r
538 /* Note: "name" is used both as a string argument, and the address as ID */
\r
539 prvTraceStoreStringEvent(2, PSF_EVENT_DEFINE_ISR, name, name, priority);
\r
541 /* Always save in symbol table, if the recording has not yet started */
\r
542 prvTraceSaveSymbol((const void*)name, name);
\r
544 return (traceHandle)name;
\r
547 /*******************************************************************************
\r
548 * vTraceStoreISRBegin
\r
550 * Registers the beginning of an Interrupt Service Routine, using a traceHandle
\r
551 * provided by xTraceSetISRProperties.
\r
554 * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
556 * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
\r
558 * void ISR_handler()
\r
560 * vTraceStoreISRBegin(Timer1Handle);
\r
562 * vTraceStoreISREnd(0);
\r
565 ******************************************************************************/
\r
566 void vTraceStoreISRBegin(traceHandle handle)
\r
568 TRACE_ALLOC_CRITICAL_SECTION();
\r
570 TRACE_ENTER_CRITICAL_SECTION();
\r
572 /* We are at the start of a possible ISR chain.
\r
573 No context switches should have been triggered now. */
\r
574 if (ISR_stack_index == -1)
\r
575 isPendingContextSwitch = 0;
\r
577 if (ISR_stack_index < (TRC_CFG_MAX_ISR_NESTING) - 1)
\r
580 ISR_stack[ISR_stack_index] = (uint32_t)handle;
\r
581 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
\r
582 prvTraceStoreEvent1(PSF_EVENT_ISR_BEGIN, (uint32_t)handle);
\r
584 TRACE_EXIT_CRITICAL_SECTION();
\r
588 TRACE_EXIT_CRITICAL_SECTION();
\r
589 prvTraceError(PSF_ERROR_ISR_NESTING_OVERFLOW);
\r
593 /*******************************************************************************
\r
594 * vTraceStoreISREnd
\r
596 * Registers the end of an Interrupt Service Routine.
\r
598 * The parameter pendingISR indicates if the interrupt has requested a
\r
599 * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the
\r
600 * interrupt is assumed to return to the previous context.
\r
603 * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
604 * traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder
\r
606 * traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1);
\r
608 * void ISR_handler()
\r
610 * vTraceStoreISRBegin(traceHandleIsrTimer1);
\r
612 * vTraceStoreISREnd(0);
\r
615 ******************************************************************************/
\r
616 void vTraceStoreISREnd(int isTaskSwitchRequired)
\r
618 TRACE_ALLOC_CRITICAL_SECTION();
\r
620 TRACE_ENTER_CRITICAL_SECTION();
\r
624 /* Is there a pending task-switch? (perhaps from an earlier ISR) */
\r
625 isPendingContextSwitch |= isTaskSwitchRequired;
\r
627 if (ISR_stack_index > 0)
\r
631 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
\r
632 /* Store return to interrupted ISR (if nested ISRs)*/
\r
633 prvTraceStoreEvent1(PSF_EVENT_ISR_RESUME, (uint32_t)ISR_stack[ISR_stack_index]);
\r
640 /* Store return to interrupted task, if no context switch will occur in between. */
\r
641 if ((isPendingContextSwitch == 0) || (prvTraceIsSchedulerSuspended()))
\r
643 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
\r
644 prvTraceStoreEvent1(PSF_EVENT_TS_RESUME, (uint32_t)TRACE_GET_CURRENT_TASK());
\r
649 TRACE_EXIT_CRITICAL_SECTION();
\r
653 /*******************************************************************************
\r
654 * xTraceGetLastError
\r
656 * Returns the last error or warning, as a string, or NULL if none.
\r
657 *****************************************************************************/
\r
658 const char* xTraceGetLastError(void)
\r
660 /* Note: the error messages are short, in order to fit in a User Event.
\r
661 Instead, the users can read more in the below comments.*/
\r
666 case PSF_WARNING_SYMBOL_TABLE_SLOTS:
\r
667 /* There was not enough symbol table slots for storing symbol names.
\r
668 The number of missing slots is counted by NoRoomForSymbol. Inspect this
\r
669 variable and increase TRC_CFG_SYMBOL_TABLE_SLOTS by at least that value. */
\r
671 return "Exceeded SYMBOL_TABLE_SLOTS (see xTraceGetLastError)";
\r
673 case PSF_WARNING_SYMBOL_MAX_LENGTH:
\r
674 /* A symbol name exceeded TRC_CFG_SYMBOL_MAX_LENGTH in length.
\r
675 Make sure the symbol names are at most TRC_CFG_SYMBOL_MAX_LENGTH,
\r
676 or inspect LongestSymbolName and increase TRC_CFG_SYMBOL_MAX_LENGTH
\r
677 to at least this value. */
\r
679 return "Exceeded SYMBOL_MAX_LENGTH (see xTraceGetLastError)";
\r
681 case PSF_WARNING_OBJECT_DATA_SLOTS:
\r
682 /* There was not enough symbol object table slots for storing object
\r
683 properties, such as task priorites. The number of missing slots is
\r
684 counted by NoRoomForObjectData. Inspect this variable and increase
\r
685 TRC_CFG_OBJECT_DATA_SLOTS by at least that value. */
\r
687 return "Exceeded OBJECT_DATA_SLOTS (see xTraceGetLastError)";
\r
689 case PSF_WARNING_STRING_TOO_LONG:
\r
690 /* Some string argument was longer than the maximum payload size
\r
691 and has been truncated by "MaxBytesTruncated" bytes.
\r
693 This may happen for the following functions:
\r
696 - vTraceStoreKernelObjectName
\r
697 - xTraceRegisterString
\r
698 - vTraceSetISRProperties
\r
700 A PSF event may store maximum 60 bytes payload, including data
\r
701 arguments and string characters. For User Events, also the User
\r
702 Event Channel (4 bytes) must be squeezed in, if a channel is
\r
703 specified (can be NULL). */
\r
705 return "String too long (see xTraceGetLastError)";
\r
707 case PSF_WARNING_STREAM_PORT_READ:
\r
708 /* TRC_STREAM_PORT_READ_DATA is expected to return 0 when completed successfully.
\r
709 This means there is an error in the communication with host/Tracealyzer. */
\r
711 return "TRC_STREAM_PORT_READ_DATA returned error (!= 0).";
\r
713 case PSF_WARNING_STREAM_PORT_WRITE:
\r
714 /* TRC_STREAM_PORT_WRITE_DATA is expected to return 0 when completed successfully.
\r
715 This means there is an error in the communication with host/Tracealyzer. */
\r
717 return "TRC_STREAM_PORT_WRITE_DATA returned error (!= 0).";
\r
719 case PSF_ERROR_EVENT_CODE_TOO_LARGE:
\r
720 /* The highest allowed event code is 4095, anything higher is an unexpected error.
\r
721 Please contact support@percepio.com for assistance.*/
\r
723 return "Invalid event code (see xTraceGetLastError)";
\r
725 case PSF_ERROR_ISR_NESTING_OVERFLOW:
\r
726 /* Nesting of ISR trace calls exceeded the limit (TRC_CFG_MAX_ISR_NESTING).
\r
727 If this is unlikely, make sure that you call vTraceStoreISRExit in the end
\r
728 of all ISR handlers. Or increase TRC_CFG_MAX_ISR_NESTING. */
\r
730 return "Exceeded ISR nesting (see xTraceGetLastError)";
\r
732 case PSF_ERROR_DWT_NOT_SUPPORTED:
\r
733 /* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.
\r
734 DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M
\r
735 macro normally set by ARM's CMSIS library, since typically available. You can however select
\r
736 SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/
\r
738 return "DWT not supported (see xTraceGetLastError)";
\r
740 case PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED:
\r
741 /* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.
\r
742 DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M
\r
743 macro normally set by ARM's CMSIS library, since typically available. You can however select
\r
744 SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/
\r
746 return "DWT_CYCCNT not supported (see xTraceGetLastError)";
\r
748 case PSF_ERROR_TZCTRLTASK_NOT_CREATED:
\r
749 /* vTraceEnable failed creating the trace control task (TzCtrl) - incorrect parameters (priority?)
\r
750 or insufficient heap size? */
\r
751 return "Could not create TzCtrl (see xTraceGetLastError)";
\r
758 /*******************************************************************************
\r
761 * Clears any errors.
\r
762 *****************************************************************************/
\r
763 void vTraceClearError(void)
\r
765 NoRoomForSymbol = 0;
\r
766 LongestSymbolName = 0;
\r
767 NoRoomForObjectData = 0;
\r
768 MaxBytesTruncated = 0;
\r
769 errorCode = PSF_ERROR_NONE;
\r
772 /*******************************************************************************
\r
775 * Stops the tracing.
\r
776 *****************************************************************************/
\r
777 void vTraceStop(void)
\r
779 prvSetRecorderEnabled(0);
\r
782 /*******************************************************************************
\r
783 * vTraceSetRecorderDataBuffer
\r
785 * If custom allocation is used, this function must be called so the recorder
\r
786 * library knows where to save the trace data.
\r
787 ******************************************************************************/
\r
788 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)
\r
790 extern char* _TzTraceData;
\r
792 void vTraceSetRecorderDataBuffer(void* pRecorderData)
\r
794 _TzTraceData = pRecorderData;
\r
799 /*******************************************************************************
\r
800 * xTraceIsRecordingEnabled
\r
801 * Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0.
\r
802 ******************************************************************************/
\r
803 int xTraceIsRecordingEnabled(void)
\r
805 return (int)RecorderEnabled;
\r
808 void vTraceSetFilterMask(uint16_t filterMask)
\r
810 CurrentFilterMask = filterMask;
\r
813 void vTraceSetFilterGroup(uint16_t filterGroup)
\r
815 CurrentFilterGroup = filterGroup;
\r
819 /******************************************************************************/
\r
820 /*** INTERNAL FUNCTIONS *******************************************************/
\r
821 /******************************************************************************/
\r
823 /* Internal function for starting/stopping the recorder. */
\r
824 static void prvSetRecorderEnabled(uint32_t isEnabled)
\r
828 TRACE_ALLOC_CRITICAL_SECTION();
\r
830 if (RecorderEnabled == isEnabled)
\r
835 currentTask = TRACE_GET_CURRENT_TASK();
\r
837 TRACE_ENTER_CRITICAL_SECTION();
\r
839 RecorderEnabled = isEnabled;
\r
841 if (currentTask == NULL)
\r
843 currentTask = (void*)HANDLE_NO_TASK;
\r
846 if (RecorderEnabled)
\r
848 TRC_STREAM_PORT_ON_TRACE_BEGIN();
\r
850 #if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)
\r
851 prvPagedEventBufferInit(_TzTraceData);
\r
855 ISR_stack_index = -1;
\r
856 prvTraceStoreHeader();
\r
857 prvTraceStoreSymbolTable();
\r
858 prvTraceStoreObjectDataTable();
\r
859 prvTraceStoreEvent3( PSF_EVENT_TRACE_START,
\r
860 (uint32_t)TRACE_GET_OS_TICKS(),
\r
861 (uint32_t)currentTask,
\r
863 prvTraceStoreTSConfig();
\r
864 prvTraceStoreWarnings();
\r
868 TRC_STREAM_PORT_ON_TRACE_END();
\r
871 TRACE_EXIT_CRITICAL_SECTION();
\r
874 /* Stores the symbol table on Start */
\r
875 static void prvTraceStoreSymbolTable(void)
\r
879 TRACE_ALLOC_CRITICAL_SECTION();
\r
881 TRACE_ENTER_CRITICAL_SECTION();
\r
883 if (RecorderEnabled)
\r
885 for (i = 0; i < (sizeof(SymbolTable) / sizeof(uint32_t)); i += (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)))
\r
887 TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, SYMBOL_TABLE_SLOT_SIZE);
\r
890 for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)); j++)
\r
892 data[j] = symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i+j];
\r
894 TRC_STREAM_PORT_COMMIT_EVENT(data, SYMBOL_TABLE_SLOT_SIZE);
\r
898 TRACE_EXIT_CRITICAL_SECTION();
\r
901 /* Stores the object table on Start */
\r
902 static void prvTraceStoreObjectDataTable(void)
\r
906 TRACE_ALLOC_CRITICAL_SECTION();
\r
908 TRACE_ENTER_CRITICAL_SECTION();
\r
910 if (RecorderEnabled)
\r
912 for (i = 0; i < (sizeof(ObjectDataTable) / sizeof(uint32_t)); i += (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)))
\r
914 TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, OBJECT_DATA_SLOT_SIZE);
\r
917 for (j = 0; j < (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)); j++)
\r
919 data[j] = objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i+j];
\r
921 TRC_STREAM_PORT_COMMIT_EVENT(data, OBJECT_DATA_SLOT_SIZE);
\r
925 TRACE_EXIT_CRITICAL_SECTION();
\r
928 /* Stores the header information on Start */
\r
929 static void prvTraceStoreHeader(void)
\r
931 TRACE_ALLOC_CRITICAL_SECTION();
\r
933 TRACE_ENTER_CRITICAL_SECTION();
\r
935 if (RecorderEnabled)
\r
937 TRC_STREAM_PORT_ALLOCATE_EVENT(PSFHeaderInfo, header, sizeof(PSFHeaderInfo));
\r
938 if (header != NULL)
\r
940 header->psf = PSFEndianessIdentifier;
\r
941 header->version = FormatVersion;
\r
942 header->platform = TRACE_KERNEL_VERSION;
\r
943 header->options = 0;
\r
944 /* Lowest bit used for TRC_IRQ_PRIORITY_ORDER */
\r
945 header->options = header->options | (TRC_IRQ_PRIORITY_ORDER << 0);
\r
946 header->symbolSize = SYMBOL_TABLE_SLOT_SIZE;
\r
947 header->symbolCount = (TRC_CFG_SYMBOL_TABLE_SLOTS);
\r
948 header->objectDataSize = 8;
\r
949 header->objectDataCount = (TRC_CFG_OBJECT_DATA_SLOTS);
\r
950 TRC_STREAM_PORT_COMMIT_EVENT(header, sizeof(PSFHeaderInfo));
\r
953 TRACE_EXIT_CRITICAL_SECTION();
\r
956 /* Store the current warnings */
\r
957 static void prvTraceStoreWarnings(void)
\r
959 if (RecorderEnabled)
\r
961 const char* errStr = xTraceGetLastError();
\r
963 if (errStr != NULL)
\r
965 vTracePrint(trcWarningChannel, errStr);
\r
970 /* Store an event with zero parameters (event ID only) */
\r
971 void prvTraceStoreEvent0(uint16_t eventID)
\r
973 TRACE_ALLOC_CRITICAL_SECTION();
\r
975 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
977 TRACE_ENTER_CRITICAL_SECTION();
\r
979 if (RecorderEnabled)
\r
984 TRC_STREAM_PORT_ALLOCATE_EVENT(BaseEvent, event, sizeof(BaseEvent));
\r
987 event->EventID = eventID | PARAM_COUNT(0);
\r
988 event->EventCount = (uint16_t)eventCounter;
\r
989 event->TS = prvGetTimestamp32();
\r
990 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(BaseEvent));
\r
994 TRACE_EXIT_CRITICAL_SECTION();
\r
997 /* Store an event with one 32-bit parameter (pointer address or an int) */
\r
998 void prvTraceStoreEvent1(uint16_t eventID, uint32_t param1)
\r
1000 TRACE_ALLOC_CRITICAL_SECTION();
\r
1002 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1004 TRACE_ENTER_CRITICAL_SECTION();
\r
1006 if (RecorderEnabled)
\r
1011 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_1, event, sizeof(EventWithParam_1));
\r
1012 if (event != NULL)
\r
1014 event->base.EventID = eventID | PARAM_COUNT(1);
\r
1015 event->base.EventCount = (uint16_t)eventCounter;
\r
1016 event->base.TS = prvGetTimestamp32();
\r
1017 event->param1 = (uint32_t)param1;
\r
1018 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_1));
\r
1022 TRACE_EXIT_CRITICAL_SECTION();
\r
1025 /* Store an event with two 32-bit parameters */
\r
1026 void prvTraceStoreEvent2(uint16_t eventID, uint32_t param1, uint32_t param2)
\r
1028 TRACE_ALLOC_CRITICAL_SECTION();
\r
1030 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1032 TRACE_ENTER_CRITICAL_SECTION();
\r
1034 if (RecorderEnabled)
\r
1039 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_2, event, sizeof(EventWithParam_2));
\r
1040 if (event != NULL)
\r
1042 event->base.EventID = eventID | PARAM_COUNT(2);
\r
1043 event->base.EventCount = (uint16_t)eventCounter;
\r
1044 event->base.TS = prvGetTimestamp32();
\r
1045 event->param1 = (uint32_t)param1;
\r
1046 event->param2 = param2;
\r
1047 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_2));
\r
1051 TRACE_EXIT_CRITICAL_SECTION();
\r
1054 /* Store an event with three 32-bit parameters */
\r
1055 void prvTraceStoreEvent3( uint16_t eventID,
\r
1060 TRACE_ALLOC_CRITICAL_SECTION();
\r
1062 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1064 TRACE_ENTER_CRITICAL_SECTION();
\r
1066 if (RecorderEnabled)
\r
1071 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_3, event, sizeof(EventWithParam_3));
\r
1072 if (event != NULL)
\r
1074 event->base.EventID = eventID | PARAM_COUNT(3);
\r
1075 event->base.EventCount = (uint16_t)eventCounter;
\r
1076 event->base.TS = prvGetTimestamp32();
\r
1077 event->param1 = (uint32_t)param1;
\r
1078 event->param2 = param2;
\r
1079 event->param3 = param3;
\r
1080 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_3));
\r
1084 TRACE_EXIT_CRITICAL_SECTION();
\r
1087 /* Stores an event with <nParam> 32-bit integer parameters */
\r
1088 void prvTraceStoreEvent(int nParam, uint16_t eventID, ...)
\r
1092 TRACE_ALLOC_CRITICAL_SECTION();
\r
1094 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1096 TRACE_ENTER_CRITICAL_SECTION();
\r
1098 if (RecorderEnabled)
\r
1100 int eventSize = (int)sizeof(BaseEvent) + nParam * (int)sizeof(uint32_t);
\r
1105 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1106 if (event != NULL)
\r
1108 event->base.EventID = eventID | (uint16_t)PARAM_COUNT(nParam);
\r
1109 event->base.EventCount = (uint16_t)eventCounter;
\r
1110 event->base.TS = prvGetTimestamp32();
\r
1112 va_start(vl, eventID);
\r
1113 for (i = 0; i < nParam; i++)
\r
1115 uint32_t* tmp = (uint32_t*) &(event->data[i]);
\r
1116 *tmp = va_arg(vl, uint32_t);
\r
1120 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1124 TRACE_EXIT_CRITICAL_SECTION();
\r
1127 /* Stories an event with a string and <nParam> 32-bit integer parameters */
\r
1128 void prvTraceStoreStringEvent(int nArgs, uint16_t eventID, const char* str, ...)
\r
1133 for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */
\r
1135 va_start(vl, str);
\r
1136 prvTraceStoreStringEventHelper(nArgs, eventID, NULL, len, str, &vl);
\r
1140 /* Internal common function for storing string events */
\r
1141 static void prvTraceStoreStringEventHelper(int nArgs,
\r
1143 traceString userEvtChannel,
\r
1152 TRACE_ALLOC_CRITICAL_SECTION();
\r
1154 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1156 /* The string length in multiples of 32 bit words (+1 for null character) */
\r
1157 nStrWords = (len+1+3)/4;
\r
1159 /* If a user event channel is specified, add in the list */
\r
1160 if (userEvtChannel)
\r
1163 offset = nArgs * 4;
\r
1165 /* The total number of 32-bit words needed for the whole payload */
\r
1166 nWords = nStrWords + nArgs;
\r
1168 if (nWords > 15) /* if attempting to store more than 60 byte (= max) */
\r
1170 /* Truncate event if too large. The string characters are stored
\r
1171 last, so usually only the string is truncated, unless there a lot
\r
1172 of parameters... */
\r
1174 /* Diagnostics ... */
\r
1175 uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;
\r
1177 if (bytesTruncated > MaxBytesTruncated)
\r
1179 MaxBytesTruncated = bytesTruncated;
\r
1183 len = 15 * 4 - offset;
\r
1186 TRACE_ENTER_CRITICAL_SECTION();
\r
1188 if (RecorderEnabled)
\r
1190 int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);
\r
1195 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1196 if (event != NULL)
\r
1200 event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);
\r
1201 event->base.EventCount = (uint16_t)eventCounter;
\r
1202 event->base.TS = prvGetTimestamp32();
\r
1204 /* 32-bit write-pointer for the data argument */
\r
1205 data32 = (uint32_t*) &(event->data[0]);
\r
1207 for (i = 0; i < nArgs; i++)
\r
1209 if ((userEvtChannel != NULL) && (i == 0))
\r
1211 /* First, add the User Event Channel if not NULL */
\r
1212 data32[i] = (uint32_t)userEvtChannel;
\r
1216 /* Add data arguments... */
\r
1217 data32[i] = va_arg(*vl, uint32_t);
\r
1220 data8 = (uint8_t*)&(event->data[0]);
\r
1221 for (i = 0; i < len; i++)
\r
1223 data8[offset + i] = str[i];
\r
1226 if (len < (15 * 4 - offset))
\r
1227 data8[offset + len] = 0; /* Only truncate if we don't fill up the buffer completely */
\r
1228 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1233 TRACE_EXIT_CRITICAL_SECTION();
\r
1236 /* Internal common function for storing string events without additional arguments */
\r
1237 void prvTraceStoreSimpleStringEventHelper(traceString userEvtChannel,
\r
1246 uint16_t eventID = PSF_EVENT_USER_EVENT;
\r
1247 TRACE_ALLOC_CRITICAL_SECTION();
\r
1249 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1251 for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */
\r
1253 /* The string length in multiples of 32 bit words (+1 for null character) */
\r
1254 nStrWords = (len+1+3)/4;
\r
1256 /* If a user event channel is specified, add in the list */
\r
1257 if (userEvtChannel)
\r
1263 offset = nArgs * 4;
\r
1265 /* The total number of 32-bit words needed for the whole payload */
\r
1266 nWords = nStrWords + nArgs;
\r
1268 if (nWords > 15) /* if attempting to store more than 60 byte (= max) */
\r
1270 /* Truncate event if too large. The string characters are stored
\r
1271 last, so usually only the string is truncated, unless there a lot
\r
1272 of parameters... */
\r
1274 /* Diagnostics ... */
\r
1275 uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;
\r
1277 if (bytesTruncated > MaxBytesTruncated)
\r
1279 MaxBytesTruncated = bytesTruncated;
\r
1283 len = 15 * 4 - offset;
\r
1286 TRACE_ENTER_CRITICAL_SECTION();
\r
1288 if (RecorderEnabled)
\r
1290 int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);
\r
1295 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1296 if (event != NULL)
\r
1300 event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);
\r
1301 event->base.EventCount = (uint16_t)eventCounter;
\r
1302 event->base.TS = prvGetTimestamp32();
\r
1304 /* 32-bit write-pointer for the data argument */
\r
1305 data32 = (uint32_t*) &(event->data[0]);
\r
1307 if (userEvtChannel != NULL)
\r
1309 /* First, add the User Event Channel if not NULL */
\r
1310 data32[0] = (uint32_t)userEvtChannel;
\r
1313 data8 = (uint8_t*) &(event->data[0]);
\r
1314 for (i = 0; i < len; i++)
\r
1316 data8[offset + i] = str[i];
\r
1319 if (len < (15 * 4 - offset))
\r
1320 data8[offset + len] = 0; /* Only truncate if we don't fill up the buffer completely */
\r
1321 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1326 TRACE_EXIT_CRITICAL_SECTION();
\r
1329 /* Saves a symbol name (task name etc.) in symbol table */
\r
1330 void prvTraceSaveSymbol(const void *address, const char *name)
\r
1333 uint32_t foundSlot;
\r
1334 uint32_t *ptrAddress;
\r
1335 uint8_t *ptrSymbol;
\r
1336 TRACE_ALLOC_CRITICAL_SECTION();
\r
1338 TRACE_ENTER_CRITICAL_SECTION();
\r
1340 foundSlot = firstFreeSymbolTableIndex;
\r
1342 /* First look for previous entries using this address */
\r
1343 for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)
\r
1345 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1346 ptrAddress = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];
\r
1347 if (*ptrAddress == (uint32_t)address)
\r
1354 if (foundSlot < SYMBOL_TABLE_BUFFER_SIZE)
\r
1356 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1357 symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;
\r
1359 /* We access the symbol table via the union member pSymbolTableBufferUINT8 to avoid strict-aliasing issues */
\r
1360 ptrSymbol = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT8[foundSlot + sizeof(uint32_t)];
\r
1361 for (i = 0; i < (TRC_CFG_SYMBOL_MAX_LENGTH); i++)
\r
1363 ptrSymbol[i] = (uint8_t)name[i]; /* We do this first to ensure we also get the 0 termination, if there is one */
\r
1369 /* Check the length of "name", if longer than SYMBOL_MAX_LENGTH */
\r
1370 while ((name[i] != 0) && i < 128)
\r
1375 /* Remember the longest symbol name, for diagnostic purposes */
\r
1376 if (i > LongestSymbolName)
\r
1378 LongestSymbolName = i;
\r
1381 /* Is this the last entry in the symbol table? */
\r
1382 if (foundSlot == firstFreeSymbolTableIndex)
\r
1384 firstFreeSymbolTableIndex += SYMBOL_TABLE_SLOT_SIZE;
\r
1389 NoRoomForSymbol++;
\r
1392 TRACE_EXIT_CRITICAL_SECTION();
\r
1395 /* Deletes a symbol name (task name etc.) from symbol table */
\r
1396 void prvTraceDeleteSymbol(void *address)
\r
1399 uint32_t *ptr, *lastEntryPtr;
\r
1400 TRACE_ALLOC_CRITICAL_SECTION();
\r
1402 TRACE_ENTER_CRITICAL_SECTION();
\r
1404 for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)
\r
1406 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1407 ptr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];
\r
1408 if (*ptr == (uint32_t)address)
\r
1410 /* See if we have another entry in the table, and that this isn't already the last entry */
\r
1411 if (firstFreeSymbolTableIndex > SYMBOL_TABLE_SLOT_SIZE && i != (firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE))
\r
1413 /* Another entry is available, get pointer to the last one */
\r
1414 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1415 lastEntryPtr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[(firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t)];
\r
1417 /* Copy last entry to this position */
\r
1418 for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t); j++)
\r
1420 ptr[j] = lastEntryPtr[j];
\r
1423 /* For good measure we also zero out the original position */
\r
1424 *lastEntryPtr = 0;
\r
1427 *ptr = 0; /* No other entry found, or this is the last entry */
\r
1430 firstFreeSymbolTableIndex -= SYMBOL_TABLE_SLOT_SIZE;
\r
1436 TRACE_EXIT_CRITICAL_SECTION();
\r
1439 /* Saves an object data entry (current task priority) in object data table */
\r
1440 void prvTraceSaveObjectData(const void *address, uint32_t data)
\r
1443 uint32_t foundSlot;
\r
1445 TRACE_ALLOC_CRITICAL_SECTION();
\r
1447 TRACE_ENTER_CRITICAL_SECTION();
\r
1449 foundSlot = firstFreeObjectDataTableIndex;
\r
1451 /* First look for previous entries using this address */
\r
1452 for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)
\r
1454 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1455 ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];
\r
1456 if (*ptr == (uint32_t)address)
\r
1463 if (foundSlot < OBJECT_DATA_TABLE_BUFFER_SIZE)
\r
1465 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1466 objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;
\r
1467 objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t) + 1] = data;
\r
1469 /* Is this the last entry in the object data table? */
\r
1470 if (foundSlot == firstFreeObjectDataTableIndex)
\r
1472 firstFreeObjectDataTableIndex += OBJECT_DATA_SLOT_SIZE;
\r
1477 NoRoomForObjectData++;
\r
1480 TRACE_EXIT_CRITICAL_SECTION();
\r
1483 /* Removes an object data entry (task base priority) from object data table */
\r
1484 void prvTraceDeleteObjectData(void *address)
\r
1487 uint32_t *ptr, *lastEntryPtr;
\r
1488 TRACE_ALLOC_CRITICAL_SECTION();
\r
1490 TRACE_ENTER_CRITICAL_SECTION();
\r
1492 for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)
\r
1494 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1495 ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];
\r
1496 if (*ptr == (uint32_t)address)
\r
1498 /* See if we have another entry in the table, and that this isn't already the last entry */
\r
1499 if (firstFreeObjectDataTableIndex > OBJECT_DATA_SLOT_SIZE && i != (firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE))
\r
1501 /* Another entry is available, get pointer to the last one */
\r
1502 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1503 lastEntryPtr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[(firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t)];
\r
1505 /* Copy last entry to this position */
\r
1506 for (j = 0; j < (OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t); j++)
\r
1508 ptr[j] = lastEntryPtr[j];
\r
1511 /* For good measure we also zero out the original position */
\r
1512 *lastEntryPtr = 0;
\r
1515 *ptr = 0; /* No other entry found, or this is the last entry */
\r
1518 firstFreeObjectDataTableIndex -= OBJECT_DATA_SLOT_SIZE;
\r
1524 TRACE_EXIT_CRITICAL_SECTION();
\r
1527 /* Checks if the provided command is a valid command */
\r
1528 int prvIsValidCommand(TracealyzerCommandType* cmd)
\r
1530 uint16_t checksum = (uint16_t)(0xFFFF - ( cmd->cmdCode +
\r
1537 if (cmd->checksumMSB != (unsigned char)(checksum >> 8))
\r
1540 if (cmd->checksumLSB != (unsigned char)(checksum & 0xFF))
\r
1543 if (cmd->cmdCode > CMD_LAST_COMMAND)
\r
1549 /* Executed the received command (Start or Stop) */
\r
1550 void prvProcessCommand(TracealyzerCommandType* cmd)
\r
1552 switch(cmd->cmdCode)
\r
1554 case CMD_SET_ACTIVE:
\r
1555 prvSetRecorderEnabled(cmd->param1);
\r
1562 /* Called on warnings, when the recording can continue. */
\r
1563 void prvTraceWarning(int errCode)
\r
1567 errorCode = errCode;
\r
1568 prvTraceStoreWarnings();
\r
1572 /* Called on critical errors in the recorder. Stops the recorder! */
\r
1573 void prvTraceError(int errCode)
\r
1577 errorCode = errCode;
\r
1578 prvTraceStoreWarnings();
\r
1579 vTracePrintF(trcWarningChannel, "Recorder stopped in prvTraceError()");
\r
1581 prvSetRecorderEnabled(0);
\r
1585 /* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */
\r
1586 #ifndef TRC_CFG_ARM_CM_USE_SYSTICK
\r
1587 #if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03)))
\r
1589 void prvTraceInitCortexM()
\r
1591 /* Make sure the DWT registers are unlocked, in case the debugger doesn't do this. */
\r
1592 TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK;
\r
1594 /* Make sure DWT is enabled is enabled, if supported */
\r
1595 TRC_REG_DEMCR |= TRC_DEMCR_TRCENA;
\r
1599 /* Verify that DWT is supported */
\r
1600 if (TRC_REG_DEMCR == 0)
\r
1602 /* This function is called on Cortex-M3, M4 and M7 devices to initialize
\r
1603 the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
\r
1605 If the below error is produced, the DWT unit does not seem to be available.
\r
1607 In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
\r
1608 to use SysTick timestamping instead, or define your own timestamping by
\r
1609 setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
\r
1610 and make the necessary definitions, as explained in trcHardwarePort.h.*/
\r
1612 prvTraceError(PSF_ERROR_DWT_NOT_SUPPORTED);
\r
1616 /* Verify that DWT_CYCCNT is supported */
\r
1617 if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT)
\r
1619 /* This function is called on Cortex-M3, M4 and M7 devices to initialize
\r
1620 the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
\r
1622 If the below error is produced, the cycle counter does not seem to be available.
\r
1624 In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
\r
1625 to use SysTick timestamping instead, or define your own timestamping by
\r
1626 setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
\r
1627 and make the necessary definitions, as explained in trcHardwarePort.h.*/
\r
1629 prvTraceError(PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED);
\r
1633 /* Reset the cycle counter */
\r
1634 TRC_REG_DWT_CYCCNT = 0;
\r
1636 /* Enable the cycle counter */
\r
1637 TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA;
\r
1639 } while(0); /* breaks above jump here */
\r
1644 /* Performs timestamping using definitions in trcHardwarePort.h */
\r
1645 static uint32_t prvGetTimestamp32(void)
\r
1647 #if ((TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR) || (TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR))
\r
1648 return TRC_HWTC_COUNT;
\r
1651 #if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR))
\r
1652 return TRC_HWTC_COUNT;
\r
1655 #if ((TRC_HWTC_TYPE == TRC_OS_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR))
\r
1656 uint32_t ticks = TRACE_GET_OS_TICKS();
\r
1657 return ((TRC_HWTC_COUNT) & 0x00FFFFFFU) + ((ticks & 0x000000FFU) << 24);
\r
1661 /* Store the Timestamp Config event */
\r
1662 static void prvTraceStoreTSConfig(void)
\r
1664 /* If not overridden using vTraceSetFrequency, use default value */
\r
1665 if (timestampFrequency == 0)
\r
1667 timestampFrequency = TRC_HWTC_FREQ_HZ;
\r
1670 #if (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR || TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR)
\r
1672 prvTraceStoreEvent(5,
\r
1673 PSF_EVENT_TS_CONFIG,
\r
1674 (uint32_t)timestampFrequency,
\r
1675 (uint32_t)(TRACE_TICK_RATE_HZ),
\r
1676 (uint32_t)(TRC_HWTC_TYPE),
\r
1677 (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD),
\r
1678 (uint32_t)(TRC_HWTC_PERIOD));
\r
1682 prvTraceStoreEvent(4,
\r
1683 PSF_EVENT_TS_CONFIG,
\r
1684 (uint32_t)timestampFrequency,
\r
1685 (uint32_t)(TRACE_TICK_RATE_HZ),
\r
1686 (uint32_t)(TRC_HWTC_TYPE),
\r
1687 (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD));
\r
1691 /* Retrieve a buffer page to write to. */
\r
1692 static int prvAllocateBufferPage(int prevPage)
\r
1697 index = (prevPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);
\r
1699 while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)))
\r
1701 index = (index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);
\r
1704 if (PageInfo[index].Status == PAGE_STATUS_FREE)
\r
1712 /* Mark the page read as complete. */
\r
1713 static void prvPageReadComplete(int pageIndex)
\r
1715 TRACE_ALLOC_CRITICAL_SECTION();
\r
1717 TRACE_ENTER_CRITICAL_SECTION();
\r
1718 PageInfo[pageIndex].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
\r
1719 PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)];
\r
1720 PageInfo[pageIndex].Status = PAGE_STATUS_FREE;
\r
1722 TotalBytesRemaining += (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
\r
1724 TRACE_EXIT_CRITICAL_SECTION();
\r
1727 /* Get the current buffer page index and remaining number of bytes. */
\r
1728 static int prvGetBufferPage(int32_t* bytesUsed)
\r
1730 static int8_t lastPage = -1;
\r
1732 int8_t index = (int8_t) ((lastPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT));
\r
1734 while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)))
\r
1736 index = (int8_t)((index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT));
\r
1739 if (PageInfo[index].Status == PAGE_STATUS_READ)
\r
1741 *bytesUsed = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) - PageInfo[index].BytesRemaining;
\r
1751 /*******************************************************************************
\r
1752 * uint32_t prvPagedEventBufferTransfer(void)
\r
1754 * Transfers one buffer page of trace data, if a full page is available, using
\r
1755 * the macro TRC_STREAM_PORT_WRITE_DATA as defined in trcStreamingPort.h.
\r
1757 * This function is intended to be called the periodic TzCtrl task with a suitable
\r
1758 * delay (e.g. 10-100 ms).
\r
1760 * Returns the number of bytes sent. If non-zero, it is good to call this
\r
1761 * again, in order to send any additional data waiting in the buffer.
\r
1762 * If zero, wait a while before calling again.
\r
1764 * In case of errors from the streaming interface, it registers a warning
\r
1765 * (PSF_WARNING_STREAM_PORT_WRITE) provided by xTraceGetLastError().
\r
1767 *******************************************************************************/
\r
1768 uint32_t prvPagedEventBufferTransfer(void)
\r
1770 int8_t pageToTransfer = -1;
\r
1771 int32_t bytesTransferredTotal = 0;
\r
1772 int32_t bytesTransferredNow = 0;
\r
1773 int32_t bytesToTransfer;
\r
1775 pageToTransfer = (int8_t)prvGetBufferPage(&bytesToTransfer);
\r
1777 /* bytesToTransfer now contains the number of "valid" bytes in the buffer page, that should be transmitted.
\r
1778 There might be some unused junk bytes in the end, that must be ignored. */
\r
1780 if (pageToTransfer > -1)
\r
1782 while (1) /* Keep going until we have transferred all that we intended to */
\r
1784 if (TRC_STREAM_PORT_WRITE_DATA(
\r
1785 &EventBuffer[pageToTransfer * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) + bytesTransferredTotal],
\r
1786 (uint32_t)(bytesToTransfer - bytesTransferredTotal),
\r
1787 &bytesTransferredNow) == 0)
\r
1789 /* Write was successful. Update the number of transferred bytes. */
\r
1790 bytesTransferredTotal += bytesTransferredNow;
\r
1792 if (bytesTransferredTotal == bytesToTransfer)
\r
1794 /* All bytes have been transferred. Mark the buffer page as "Read Complete" (so it can be written to) and return OK. */
\r
1795 prvPageReadComplete(pageToTransfer);
\r
1796 return (uint32_t)bytesTransferredTotal;
\r
1801 /* Some error from the streaming interface... */
\r
1802 prvTraceWarning(PSF_WARNING_STREAM_PORT_WRITE);
\r
1810 /*******************************************************************************
\r
1811 * void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)
\r
1813 * Returns a pointer to an available location in the buffer able to store the
\r
1816 * Return value: The pointer.
\r
1819 * - sizeOfEvent: The size of the event that is to be placed in the buffer.
\r
1821 *******************************************************************************/
\r
1822 void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)
\r
1825 static int currentWritePage = -1;
\r
1827 if (currentWritePage == -1)
\r
1829 currentWritePage = prvAllocateBufferPage(currentWritePage);
\r
1830 if (currentWritePage == -1)
\r
1832 DroppedEventCounter++;
\r
1837 if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0)
\r
1839 PageInfo[currentWritePage].Status = PAGE_STATUS_READ;
\r
1841 TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes
\r
1843 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
\r
1844 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
\r
1846 currentWritePage = prvAllocateBufferPage(currentWritePage);
\r
1847 if (currentWritePage == -1)
\r
1849 DroppedEventCounter++;
\r
1853 ret = PageInfo[currentWritePage].WritePointer;
\r
1854 PageInfo[currentWritePage].WritePointer += sizeOfEvent;
\r
1855 PageInfo[currentWritePage].BytesRemaining = (uint16_t)(PageInfo[currentWritePage].BytesRemaining -sizeOfEvent);
\r
1857 TotalBytesRemaining = (TotalBytesRemaining-(uint16_t)sizeOfEvent);
\r
1859 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
\r
1860 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
\r
1865 /*******************************************************************************
\r
1866 * void prvPagedEventBufferInit(char* buffer)
\r
1868 * Assigns the buffer to use and initializes the PageInfo structure.
\r
1870 * Return value: void
\r
1873 * - char* buffer: pointer to the trace data buffer, allocated by the caller.
\r
1875 *******************************************************************************/
\r
1876 void prvPagedEventBufferInit(char* buffer)
\r
1879 TRACE_ALLOC_CRITICAL_SECTION();
\r
1881 EventBuffer = buffer;
\r
1883 TRACE_ENTER_CRITICAL_SECTION();
\r
1884 for (i = 0; i < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); i++)
\r
1886 PageInfo[i].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
\r
1887 PageInfo[i].WritePointer = &EventBuffer[i * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)];
\r
1888 PageInfo[i].Status = PAGE_STATUS_FREE;
\r
1890 TRACE_EXIT_CRITICAL_SECTION();
\r
1894 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
\r
1896 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
\r