1 /*******************************************************************************
\r
2 * Trace Recorder Library for Tracealyzer v4.1.1
\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
53 uint16_t EventCount;
\r
75 /* Used in event functions with variable number of parameters. */
\r
79 uint32_t data[15]; /* maximum payload size */
\r
87 uint16_t symbolSize;
\r
88 uint16_t symbolCount;
\r
89 uint16_t objectDataSize;
\r
90 uint16_t objectDataCount;
\r
94 /* The size of each slot in the Symbol Table */
\r
95 #define SYMBOL_TABLE_SLOT_SIZE (sizeof(uint32_t) + (((TRC_CFG_SYMBOL_MAX_LENGTH)+(sizeof(uint32_t)-1))/sizeof(uint32_t))*sizeof(uint32_t))
\r
97 #define OBJECT_DATA_SLOT_SIZE (sizeof(uint32_t) + sizeof(uint32_t))
\r
99 /* The total size of the Symbol Table */
\r
100 #define SYMBOL_TABLE_BUFFER_SIZE ((TRC_CFG_SYMBOL_TABLE_SLOTS) * SYMBOL_TABLE_SLOT_SIZE)
\r
102 /* The total size of the Object Data Table */
\r
103 #define OBJECT_DATA_TABLE_BUFFER_SIZE ((TRC_CFG_OBJECT_DATA_SLOTS) * OBJECT_DATA_SLOT_SIZE)
\r
105 /* The Symbol Table type - just a byte array */
\r
109 uint32_t pSymbolTableBufferUINT32[SYMBOL_TABLE_BUFFER_SIZE / sizeof(uint32_t)];
\r
110 uint8_t pSymbolTableBufferUINT8[SYMBOL_TABLE_BUFFER_SIZE];
\r
111 } SymbolTableBuffer;
\r
114 /* The Object Data Table type - just a byte array */
\r
118 uint32_t pObjectDataTableBufferUINT32[OBJECT_DATA_TABLE_BUFFER_SIZE / sizeof(uint32_t)];
\r
119 uint8_t pObjectDataTableBufferUINT8[OBJECT_DATA_TABLE_BUFFER_SIZE];
\r
120 } ObjectDataTableBuffer;
\r
124 uint16_t Status; /* 16 bit to avoid implicit padding (warnings) */
\r
125 uint16_t BytesRemaining;
\r
126 char* WritePointer;
\r
129 /* Code used for "task address" when no task has started. (NULL = idle task) */
\r
130 #define HANDLE_NO_TASK 2
\r
132 #define PAGE_STATUS_FREE 0
\r
133 #define PAGE_STATUS_WRITE 1
\r
134 #define PAGE_STATUS_READ 2
\r
136 #define PSF_ASSERT(_assert, _err) if (! (_assert)){ prvTraceError(_err); return; }
\r
138 /* Part of the PSF format - encodes the number of 32-bit params in an event */
\r
139 #define PARAM_COUNT(n) ((n & 0xF) << 12)
\r
141 /* The Symbol Table instance - keeps names of tasks and other named objects. */
\r
142 static SymbolTable symbolTable = { { { 0 } } };
\r
144 /* This points to the first unused entry in the symbol table. */
\r
145 static uint32_t firstFreeSymbolTableIndex = 0;
\r
147 /* The Object Data Table instance - keeps initial priorities of tasks. */
\r
148 static ObjectDataTable objectDataTable = { { { 0 } } };
\r
150 /* This points to the first unused entry in the object data table. */
\r
151 static uint32_t firstFreeObjectDataTableIndex = 0;
\r
153 /* Keeps track of ISR nesting */
\r
154 static uint32_t ISR_stack[TRC_CFG_MAX_ISR_NESTING];
\r
156 /* Keeps track of ISR nesting */
\r
157 static int8_t ISR_stack_index = -1;
\r
159 /* Any error that occurred in the recorder (also creates User Event) */
\r
160 static int errorCode = 0;
\r
162 /* Counts the number of trace sessions (not yet used) */
\r
163 static uint32_t SessionCounter = 0u;
\r
165 /* Master switch for recording (0 => Disabled, 1 => Enabled) */
\r
166 uint32_t RecorderEnabled = 0u;
\r
168 /* Used to determine endian of data (big/little) */
\r
169 static uint32_t PSFEndianessIdentifier = 0x50534600;
\r
171 /* Used to interpret the data format */
\r
172 static uint16_t FormatVersion = 0x0004;
\r
174 /* The number of events stored. Used as event sequence number. */
\r
175 static uint32_t eventCounter = 0;
\r
177 /* The user event channel for recorder warnings, defined in trcKernelPort.c */
\r
178 extern char* trcWarningChannel;
\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
402 /******************************************************************************
\r
405 * Generates "User Events", with formatted text and data, similar to a "printf".
\r
406 * It is very fast since the actual formatting is done on the host side when the
\r
407 * trace is displayed.
\r
409 * User Events can be used for very efficient application logging, and are shown
\r
410 * as yellow labels in the main trace view.
\r
411 * An advantage of User Events is that data can be plotted in the "User Event
\r
412 * Signal Plot" view, visualizing any data you log as User Events, discrete
\r
413 * states or control system signals (e.g. system inputs or outputs).
\r
415 * You may group User Events into User Event Channels. The yellow User Event
\r
416 * labels show the logged string, preceded by the channel name within brackets.
\r
420 * "[MyChannel] Hello World!"
\r
422 * The User Event Channels are shown in the View Filter, which makes it easy to
\r
423 * select what User Events you wish to display. User Event Channels are created
\r
424 * using xTraceRegisterString().
\r
428 * traceString adc_uechannel = xTraceRegisterString("ADC User Events");
\r
430 * vTracePrintF(adc_uechannel,
\r
431 * "ADC channel %d: %d volts",
\r
432 * ch, adc_reading);
\r
434 * All data arguments are assumed to be 32 bit wide. The following formats are
\r
436 * %d - signed integer. The following width and padding format is supported: "%05d" -> "-0042" and "%5d" -> " -42"
\r
437 * %u - unsigned integer. The following width and padding format is supported: "%05u" -> "00042" and "%5u" -> " 42"
\r
438 * %X - hexadecimal (uppercase). The following width and padding format is supported: "%04X" -> "002A" and "%4X" -> " 2A"
\r
439 * %x - hexadecimal (lowercase). The following width and padding format is supported: "%04x" -> "002a" and "%4x" -> " 2a"
\r
440 * %s - string (currently, this must be an earlier stored symbol name)
\r
442 * Up to 15 data arguments are allowed, with a total size of maximum 60 byte
\r
443 * including 8 byte for the base event fields and the format string. So with
\r
444 * one data argument, the maximum string length is 48 chars. If this is exceeded
\r
445 * the string is truncated (4 bytes at a time).
\r
447 ******************************************************************************/
\r
448 void vTracePrintF(traceString chn, const char* fmt, ...)
\r
455 /* Count the number of arguments in the format string (e.g., %d) */
\r
456 for (i = 0; (fmt[i] != 0) && (i < 52); i++)
\r
460 if (fmt[i + 1] != 0 && fmt[i + 1] != '%')
\r
462 nArgs++; /* Found an argument */
\r
465 i++; /* Move past format specifier or non-argument '%' */
\r
473 prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs + 1), chn, i, fmt, &vl);
\r
477 prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs), chn, i, fmt, &vl);
\r
481 #endif /* (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) */
\r
483 /*******************************************************************************
\r
484 * xTraceSetISRProperties
\r
486 * Stores a name and priority level for an Interrupt Service Routine, to allow
\r
487 * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin.
\r
490 * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
492 * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
\r
494 * void ISR_handler()
\r
496 * vTraceStoreISRBegin(Timer1Handle);
\r
498 * vTraceStoreISREnd(0);
\r
501 ******************************************************************************/
\r
502 traceHandle xTraceSetISRProperties(const char* name, uint8_t priority)
\r
504 /* Save object data in object data table */
\r
505 prvTraceSaveObjectData((const void*)name, priority);
\r
507 /* Note: "name" is used both as a string argument, and the address as ID */
\r
508 prvTraceStoreStringEvent(2, PSF_EVENT_DEFINE_ISR, name, name, priority);
\r
510 /* Always save in symbol table, if the recording has not yet started */
\r
511 prvTraceSaveSymbol((const void*)name, name);
\r
513 return (traceHandle)name;
\r
516 /*******************************************************************************
\r
517 * vTraceStoreISRBegin
\r
519 * Registers the beginning of an Interrupt Service Routine, using a traceHandle
\r
520 * provided by xTraceSetISRProperties.
\r
523 * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
525 * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
\r
527 * void ISR_handler()
\r
529 * vTraceStoreISRBegin(Timer1Handle);
\r
531 * vTraceStoreISREnd(0);
\r
534 ******************************************************************************/
\r
535 void vTraceStoreISRBegin(traceHandle handle)
\r
537 TRACE_ALLOC_CRITICAL_SECTION();
\r
539 TRACE_ENTER_CRITICAL_SECTION();
\r
541 /* We are at the start of a possible ISR chain.
\r
542 No context switches should have been triggered now. */
\r
543 if (ISR_stack_index == -1)
\r
544 isPendingContextSwitch = 0;
\r
546 if (ISR_stack_index < (TRC_CFG_MAX_ISR_NESTING) - 1)
\r
549 ISR_stack[ISR_stack_index] = (uint32_t)handle;
\r
550 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
\r
551 prvTraceStoreEvent1(PSF_EVENT_ISR_BEGIN, (uint32_t)handle);
\r
553 TRACE_EXIT_CRITICAL_SECTION();
\r
557 TRACE_EXIT_CRITICAL_SECTION();
\r
558 prvTraceError(PSF_ERROR_ISR_NESTING_OVERFLOW);
\r
562 /*******************************************************************************
\r
563 * vTraceStoreISREnd
\r
565 * Registers the end of an Interrupt Service Routine.
\r
567 * The parameter pendingISR indicates if the interrupt has requested a
\r
568 * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the
\r
569 * interrupt is assumed to return to the previous context.
\r
572 * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
573 * traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder
\r
575 * traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1);
\r
577 * void ISR_handler()
\r
579 * vTraceStoreISRBegin(traceHandleIsrTimer1);
\r
581 * vTraceStoreISREnd(0);
\r
584 ******************************************************************************/
\r
585 void vTraceStoreISREnd(int isTaskSwitchRequired)
\r
587 TRACE_ALLOC_CRITICAL_SECTION();
\r
589 TRACE_ENTER_CRITICAL_SECTION();
\r
593 /* Is there a pending task-switch? (perhaps from an earlier ISR) */
\r
594 isPendingContextSwitch |= isTaskSwitchRequired;
\r
596 if (ISR_stack_index > 0)
\r
600 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
\r
601 /* Store return to interrupted ISR (if nested ISRs)*/
\r
602 prvTraceStoreEvent1(PSF_EVENT_ISR_RESUME, (uint32_t)ISR_stack[ISR_stack_index]);
\r
609 /* Store return to interrupted task, if no context switch will occur in between. */
\r
610 if ((isPendingContextSwitch == 0) || (prvTraceIsSchedulerSuspended()))
\r
612 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)
\r
613 prvTraceStoreEvent1(PSF_EVENT_TS_RESUME, (uint32_t)TRACE_GET_CURRENT_TASK());
\r
618 TRACE_EXIT_CRITICAL_SECTION();
\r
622 /*******************************************************************************
\r
623 * xTraceGetLastError
\r
625 * Returns the last error or warning, as a string, or NULL if none.
\r
626 *****************************************************************************/
\r
627 const char* xTraceGetLastError(void)
\r
629 /* Note: the error messages are short, in order to fit in a User Event.
\r
630 Instead, the users can read more in the below comments.*/
\r
635 case PSF_WARNING_SYMBOL_TABLE_SLOTS:
\r
636 /* There was not enough symbol table slots for storing symbol names.
\r
637 The number of missing slots is counted by NoRoomForSymbol. Inspect this
\r
638 variable and increase TRC_CFG_SYMBOL_TABLE_SLOTS by at least that value. */
\r
640 return "Exceeded SYMBOL_TABLE_SLOTS (see xTraceGetLastError)";
\r
642 case PSF_WARNING_SYMBOL_MAX_LENGTH:
\r
643 /* A symbol name exceeded TRC_CFG_SYMBOL_MAX_LENGTH in length.
\r
644 Make sure the symbol names are at most TRC_CFG_SYMBOL_MAX_LENGTH,
\r
645 or inspect LongestSymbolName and increase TRC_CFG_SYMBOL_MAX_LENGTH
\r
646 to at least this value. */
\r
648 return "Exceeded SYMBOL_MAX_LENGTH (see xTraceGetLastError)";
\r
650 case PSF_WARNING_OBJECT_DATA_SLOTS:
\r
651 /* There was not enough symbol object table slots for storing object
\r
652 properties, such as task priorites. The number of missing slots is
\r
653 counted by NoRoomForObjectData. Inspect this variable and increase
\r
654 TRC_CFG_OBJECT_DATA_SLOTS by at least that value. */
\r
656 return "Exceeded OBJECT_DATA_SLOTS (see xTraceGetLastError)";
\r
658 case PSF_WARNING_STRING_TOO_LONG:
\r
659 /* Some string argument was longer than the maximum payload size
\r
660 and has been truncated by "MaxBytesTruncated" bytes.
\r
662 This may happen for the following functions:
\r
665 - vTraceStoreKernelObjectName
\r
666 - xTraceRegisterString
\r
667 - vTraceSetISRProperties
\r
669 A PSF event may store maximum 60 bytes payload, including data
\r
670 arguments and string characters. For User Events, also the User
\r
671 Event Channel (4 bytes) must be squeezed in, if a channel is
\r
672 specified (can be NULL). */
\r
674 return "String too long (see xTraceGetLastError)";
\r
676 case PSF_WARNING_STREAM_PORT_READ:
\r
677 /* TRC_STREAM_PORT_READ_DATA is expected to return 0 when completed successfully.
\r
678 This means there is an error in the communication with host/Tracealyzer. */
\r
680 return "TRC_STREAM_PORT_READ_DATA returned error (!= 0).";
\r
682 case PSF_WARNING_STREAM_PORT_WRITE:
\r
683 /* TRC_STREAM_PORT_WRITE_DATA is expected to return 0 when completed successfully.
\r
684 This means there is an error in the communication with host/Tracealyzer. */
\r
686 return "TRC_STREAM_PORT_WRITE_DATA returned error (!= 0).";
\r
688 case PSF_ERROR_EVENT_CODE_TOO_LARGE:
\r
689 /* The highest allowed event code is 4095, anything higher is an unexpected error.
\r
690 Please contact support@percepio.com for assistance.*/
\r
692 return "Invalid event code (see xTraceGetLastError)";
\r
694 case PSF_ERROR_ISR_NESTING_OVERFLOW:
\r
695 /* Nesting of ISR trace calls exceeded the limit (TRC_CFG_MAX_ISR_NESTING).
\r
696 If this is unlikely, make sure that you call vTraceStoreISRExit in the end
\r
697 of all ISR handlers. Or increase TRC_CFG_MAX_ISR_NESTING. */
\r
699 return "Exceeded ISR nesting (see xTraceGetLastError)";
\r
701 case PSF_ERROR_DWT_NOT_SUPPORTED:
\r
702 /* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.
\r
703 DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M
\r
704 macro normally set by ARM's CMSIS library, since typically available. You can however select
\r
705 SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/
\r
707 return "DWT not supported (see xTraceGetLastError)";
\r
709 case PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED:
\r
710 /* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.
\r
711 DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M
\r
712 macro normally set by ARM's CMSIS library, since typically available. You can however select
\r
713 SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/
\r
715 return "DWT_CYCCNT not supported (see xTraceGetLastError)";
\r
717 case PSF_ERROR_TZCTRLTASK_NOT_CREATED:
\r
718 /* vTraceEnable failed creating the trace control task (TzCtrl) - incorrect parameters (priority?)
\r
719 or insufficient heap size? */
\r
720 return "Could not create TzCtrl (see xTraceGetLastError)";
\r
727 /*******************************************************************************
\r
730 * Clears any errors.
\r
731 *****************************************************************************/
\r
732 void vTraceClearError(void)
\r
734 NoRoomForSymbol = 0;
\r
735 LongestSymbolName = 0;
\r
736 NoRoomForObjectData = 0;
\r
737 MaxBytesTruncated = 0;
\r
738 errorCode = PSF_ERROR_NONE;
\r
741 /*******************************************************************************
\r
744 * Stops the tracing.
\r
745 *****************************************************************************/
\r
746 void vTraceStop(void)
\r
748 prvSetRecorderEnabled(0);
\r
751 /*******************************************************************************
\r
752 * vTraceSetRecorderDataBuffer
\r
754 * If custom allocation is used, this function must be called so the recorder
\r
755 * library knows where to save the trace data.
\r
756 ******************************************************************************/
\r
757 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)
\r
759 extern char* _TzTraceData;
\r
761 void vTraceSetRecorderDataBuffer(void* pRecorderData)
\r
763 _TzTraceData = pRecorderData;
\r
768 /*******************************************************************************
\r
769 * xTraceIsRecordingEnabled
\r
770 * Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0.
\r
771 ******************************************************************************/
\r
772 int xTraceIsRecordingEnabled(void)
\r
774 return (int)RecorderEnabled;
\r
777 void vTraceSetFilterMask(uint16_t filterMask)
\r
779 CurrentFilterMask = filterMask;
\r
782 void vTraceSetFilterGroup(uint16_t filterGroup)
\r
784 CurrentFilterGroup = filterGroup;
\r
788 /******************************************************************************/
\r
789 /*** INTERNAL FUNCTIONS *******************************************************/
\r
790 /******************************************************************************/
\r
792 /* Internal function for starting/stopping the recorder. */
\r
793 static void prvSetRecorderEnabled(uint32_t isEnabled)
\r
797 TRACE_ALLOC_CRITICAL_SECTION();
\r
799 if (RecorderEnabled == isEnabled)
\r
804 currentTask = TRACE_GET_CURRENT_TASK();
\r
806 TRACE_ENTER_CRITICAL_SECTION();
\r
808 RecorderEnabled = isEnabled;
\r
810 if (currentTask == NULL)
\r
812 currentTask = (void*)HANDLE_NO_TASK;
\r
815 if (RecorderEnabled)
\r
817 TRC_STREAM_PORT_ON_TRACE_BEGIN();
\r
819 #if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)
\r
820 prvPagedEventBufferInit(_TzTraceData);
\r
824 ISR_stack_index = -1;
\r
825 prvTraceStoreHeader();
\r
826 prvTraceStoreSymbolTable();
\r
827 prvTraceStoreObjectDataTable();
\r
828 prvTraceStoreEvent3( PSF_EVENT_TRACE_START,
\r
829 (uint32_t)TRACE_GET_OS_TICKS(),
\r
830 (uint32_t)currentTask,
\r
832 prvTraceStoreTSConfig();
\r
833 prvTraceStoreWarnings();
\r
837 TRC_STREAM_PORT_ON_TRACE_END();
\r
840 TRACE_EXIT_CRITICAL_SECTION();
\r
843 /* Stores the symbol table on Start */
\r
844 static void prvTraceStoreSymbolTable(void)
\r
848 TRACE_ALLOC_CRITICAL_SECTION();
\r
850 TRACE_ENTER_CRITICAL_SECTION();
\r
852 if (RecorderEnabled)
\r
854 for (i = 0; i < (sizeof(SymbolTable) / sizeof(uint32_t)); i += (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)))
\r
856 TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, SYMBOL_TABLE_SLOT_SIZE);
\r
859 for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)); j++)
\r
861 data[j] = symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i+j];
\r
863 TRC_STREAM_PORT_COMMIT_EVENT(data, SYMBOL_TABLE_SLOT_SIZE);
\r
867 TRACE_EXIT_CRITICAL_SECTION();
\r
870 /* Stores the object table on Start */
\r
871 static void prvTraceStoreObjectDataTable(void)
\r
875 TRACE_ALLOC_CRITICAL_SECTION();
\r
877 TRACE_ENTER_CRITICAL_SECTION();
\r
879 if (RecorderEnabled)
\r
881 for (i = 0; i < (sizeof(ObjectDataTable) / sizeof(uint32_t)); i += (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)))
\r
883 TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, OBJECT_DATA_SLOT_SIZE);
\r
886 for (j = 0; j < (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)); j++)
\r
888 data[j] = objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i+j];
\r
890 TRC_STREAM_PORT_COMMIT_EVENT(data, OBJECT_DATA_SLOT_SIZE);
\r
894 TRACE_EXIT_CRITICAL_SECTION();
\r
897 /* Stores the header information on Start */
\r
898 static void prvTraceStoreHeader(void)
\r
900 TRACE_ALLOC_CRITICAL_SECTION();
\r
902 TRACE_ENTER_CRITICAL_SECTION();
\r
904 if (RecorderEnabled)
\r
906 TRC_STREAM_PORT_ALLOCATE_EVENT(PSFHeaderInfo, header, sizeof(PSFHeaderInfo));
\r
907 if (header != NULL)
\r
909 header->psf = PSFEndianessIdentifier;
\r
910 header->version = FormatVersion;
\r
911 header->platform = TRACE_KERNEL_VERSION;
\r
912 header->options = 0;
\r
913 /* Lowest bit used for TRC_IRQ_PRIORITY_ORDER */
\r
914 header->options = header->options | (TRC_IRQ_PRIORITY_ORDER << 0);
\r
915 header->symbolSize = SYMBOL_TABLE_SLOT_SIZE;
\r
916 header->symbolCount = (TRC_CFG_SYMBOL_TABLE_SLOTS);
\r
917 header->objectDataSize = 8;
\r
918 header->objectDataCount = (TRC_CFG_OBJECT_DATA_SLOTS);
\r
919 TRC_STREAM_PORT_COMMIT_EVENT(header, sizeof(PSFHeaderInfo));
\r
922 TRACE_EXIT_CRITICAL_SECTION();
\r
925 /* Store the current warnings */
\r
926 static void prvTraceStoreWarnings(void)
\r
928 if (RecorderEnabled)
\r
930 const char* errStr = xTraceGetLastError();
\r
932 if (errStr != NULL)
\r
934 vTracePrint(trcWarningChannel, errStr);
\r
939 /* Store an event with zero parameters (event ID only) */
\r
940 void prvTraceStoreEvent0(uint16_t eventID)
\r
942 TRACE_ALLOC_CRITICAL_SECTION();
\r
944 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
946 TRACE_ENTER_CRITICAL_SECTION();
\r
948 if (RecorderEnabled)
\r
953 TRC_STREAM_PORT_ALLOCATE_EVENT(BaseEvent, event, sizeof(BaseEvent));
\r
956 event->EventID = eventID | PARAM_COUNT(0);
\r
957 event->EventCount = (uint16_t)eventCounter;
\r
958 event->TS = prvGetTimestamp32();
\r
959 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(BaseEvent));
\r
963 TRACE_EXIT_CRITICAL_SECTION();
\r
966 /* Store an event with one 32-bit parameter (pointer address or an int) */
\r
967 void prvTraceStoreEvent1(uint16_t eventID, uint32_t param1)
\r
969 TRACE_ALLOC_CRITICAL_SECTION();
\r
971 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
973 TRACE_ENTER_CRITICAL_SECTION();
\r
975 if (RecorderEnabled)
\r
980 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_1, event, sizeof(EventWithParam_1));
\r
983 event->base.EventID = eventID | PARAM_COUNT(1);
\r
984 event->base.EventCount = (uint16_t)eventCounter;
\r
985 event->base.TS = prvGetTimestamp32();
\r
986 event->param1 = (uint32_t)param1;
\r
987 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_1));
\r
991 TRACE_EXIT_CRITICAL_SECTION();
\r
994 /* Store an event with two 32-bit parameters */
\r
995 void prvTraceStoreEvent2(uint16_t eventID, uint32_t param1, uint32_t param2)
\r
997 TRACE_ALLOC_CRITICAL_SECTION();
\r
999 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1001 TRACE_ENTER_CRITICAL_SECTION();
\r
1003 if (RecorderEnabled)
\r
1008 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_2, event, sizeof(EventWithParam_2));
\r
1009 if (event != NULL)
\r
1011 event->base.EventID = eventID | PARAM_COUNT(2);
\r
1012 event->base.EventCount = (uint16_t)eventCounter;
\r
1013 event->base.TS = prvGetTimestamp32();
\r
1014 event->param1 = (uint32_t)param1;
\r
1015 event->param2 = param2;
\r
1016 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_2));
\r
1020 TRACE_EXIT_CRITICAL_SECTION();
\r
1023 /* Store an event with three 32-bit parameters */
\r
1024 void prvTraceStoreEvent3( uint16_t eventID,
\r
1029 TRACE_ALLOC_CRITICAL_SECTION();
\r
1031 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1033 TRACE_ENTER_CRITICAL_SECTION();
\r
1035 if (RecorderEnabled)
\r
1040 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_3, event, sizeof(EventWithParam_3));
\r
1041 if (event != NULL)
\r
1043 event->base.EventID = eventID | PARAM_COUNT(3);
\r
1044 event->base.EventCount = (uint16_t)eventCounter;
\r
1045 event->base.TS = prvGetTimestamp32();
\r
1046 event->param1 = (uint32_t)param1;
\r
1047 event->param2 = param2;
\r
1048 event->param3 = param3;
\r
1049 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_3));
\r
1053 TRACE_EXIT_CRITICAL_SECTION();
\r
1056 /* Stores an event with <nParam> 32-bit integer parameters */
\r
1057 void prvTraceStoreEvent(int nParam, uint16_t eventID, ...)
\r
1061 TRACE_ALLOC_CRITICAL_SECTION();
\r
1063 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1065 TRACE_ENTER_CRITICAL_SECTION();
\r
1067 if (RecorderEnabled)
\r
1069 int eventSize = (int)sizeof(BaseEvent) + nParam * (int)sizeof(uint32_t);
\r
1074 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1075 if (event != NULL)
\r
1077 event->base.EventID = eventID | (uint16_t)PARAM_COUNT(nParam);
\r
1078 event->base.EventCount = (uint16_t)eventCounter;
\r
1079 event->base.TS = prvGetTimestamp32();
\r
1081 va_start(vl, eventID);
\r
1082 for (i = 0; i < nParam; i++)
\r
1084 uint32_t* tmp = (uint32_t*) &(event->data[i]);
\r
1085 *tmp = va_arg(vl, uint32_t);
\r
1089 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1093 TRACE_EXIT_CRITICAL_SECTION();
\r
1096 /* Stories an event with a string and <nParam> 32-bit integer parameters */
\r
1097 void prvTraceStoreStringEvent(int nArgs, uint16_t eventID, const char* str, ...)
\r
1102 for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */
\r
1104 va_start(vl, str);
\r
1105 prvTraceStoreStringEventHelper(nArgs, eventID, NULL, len, str, &vl);
\r
1109 /* Internal common function for storing string events */
\r
1110 static void prvTraceStoreStringEventHelper(int nArgs,
\r
1112 traceString userEvtChannel,
\r
1121 TRACE_ALLOC_CRITICAL_SECTION();
\r
1123 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1125 /* The string length in multiples of 32 bit words (+1 for null character) */
\r
1126 nStrWords = (len+1+3)/4;
\r
1128 /* If a user event channel is specified, add in the list */
\r
1129 if (userEvtChannel)
\r
1132 offset = nArgs * 4;
\r
1134 /* The total number of 32-bit words needed for the whole payload */
\r
1135 nWords = nStrWords + nArgs;
\r
1137 if (nWords > 15) /* if attempting to store more than 60 byte (= max) */
\r
1139 /* Truncate event if too large. The string characters are stored
\r
1140 last, so usually only the string is truncated, unless there a lot
\r
1141 of parameters... */
\r
1143 /* Diagnostics ... */
\r
1144 uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;
\r
1146 if (bytesTruncated > MaxBytesTruncated)
\r
1148 MaxBytesTruncated = bytesTruncated;
\r
1152 len = 15 * 4 - offset;
\r
1155 TRACE_ENTER_CRITICAL_SECTION();
\r
1157 if (RecorderEnabled)
\r
1159 int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);
\r
1164 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1165 if (event != NULL)
\r
1169 event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);
\r
1170 event->base.EventCount = (uint16_t)eventCounter;
\r
1171 event->base.TS = prvGetTimestamp32();
\r
1173 /* 32-bit write-pointer for the data argument */
\r
1174 data32 = (uint32_t*) &(event->data[0]);
\r
1176 for (i = 0; i < nArgs; i++)
\r
1178 if ((userEvtChannel != NULL) && (i == 0))
\r
1180 /* First, add the User Event Channel if not NULL */
\r
1181 data32[i] = (uint32_t)userEvtChannel;
\r
1185 /* Add data arguments... */
\r
1186 data32[i] = va_arg(*vl, uint32_t);
\r
1189 data8 = (uint8_t*)&(event->data[0]);
\r
1190 for (i = 0; i < len; i++)
\r
1192 data8[offset + i] = str[i];
\r
1195 if (len < (15 * 4 - offset))
\r
1196 data8[offset + len] = 0; /* Only truncate if we don't fill up the buffer completely */
\r
1197 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1202 TRACE_EXIT_CRITICAL_SECTION();
\r
1205 /* Internal common function for storing string events without additional arguments */
\r
1206 void prvTraceStoreSimpleStringEventHelper(traceString userEvtChannel,
\r
1215 uint16_t eventID = PSF_EVENT_USER_EVENT;
\r
1216 TRACE_ALLOC_CRITICAL_SECTION();
\r
1218 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1220 for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */
\r
1222 /* The string length in multiples of 32 bit words (+1 for null character) */
\r
1223 nStrWords = (len+1+3)/4;
\r
1225 /* If a user event channel is specified, add in the list */
\r
1226 if (userEvtChannel)
\r
1232 offset = nArgs * 4;
\r
1234 /* The total number of 32-bit words needed for the whole payload */
\r
1235 nWords = nStrWords + nArgs;
\r
1237 if (nWords > 15) /* if attempting to store more than 60 byte (= max) */
\r
1239 /* Truncate event if too large. The string characters are stored
\r
1240 last, so usually only the string is truncated, unless there a lot
\r
1241 of parameters... */
\r
1243 /* Diagnostics ... */
\r
1244 uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;
\r
1246 if (bytesTruncated > MaxBytesTruncated)
\r
1248 MaxBytesTruncated = bytesTruncated;
\r
1252 len = 15 * 4 - offset;
\r
1255 TRACE_ENTER_CRITICAL_SECTION();
\r
1257 if (RecorderEnabled)
\r
1259 int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);
\r
1264 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1265 if (event != NULL)
\r
1269 event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);
\r
1270 event->base.EventCount = (uint16_t)eventCounter;
\r
1271 event->base.TS = prvGetTimestamp32();
\r
1273 /* 32-bit write-pointer for the data argument */
\r
1274 data32 = (uint32_t*) &(event->data[0]);
\r
1276 if (userEvtChannel != NULL)
\r
1278 /* First, add the User Event Channel if not NULL */
\r
1279 data32[0] = (uint32_t)userEvtChannel;
\r
1282 data8 = (uint8_t*) &(event->data[0]);
\r
1283 for (i = 0; i < len; i++)
\r
1285 data8[offset + i] = str[i];
\r
1288 if (len < (15 * 4 - offset))
\r
1289 data8[offset + len] = 0; /* Only truncate if we don't fill up the buffer completely */
\r
1290 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1295 TRACE_EXIT_CRITICAL_SECTION();
\r
1298 /* Saves a symbol name (task name etc.) in symbol table */
\r
1299 void prvTraceSaveSymbol(const void *address, const char *name)
\r
1302 uint32_t foundSlot;
\r
1303 uint32_t *ptrAddress;
\r
1304 uint8_t *ptrSymbol;
\r
1305 TRACE_ALLOC_CRITICAL_SECTION();
\r
1307 TRACE_ENTER_CRITICAL_SECTION();
\r
1309 foundSlot = firstFreeSymbolTableIndex;
\r
1311 /* First look for previous entries using this address */
\r
1312 for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)
\r
1314 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1315 ptrAddress = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];
\r
1316 if (*ptrAddress == (uint32_t)address)
\r
1323 if (foundSlot < SYMBOL_TABLE_BUFFER_SIZE)
\r
1325 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1326 symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;
\r
1328 /* We access the symbol table via the union member pSymbolTableBufferUINT8 to avoid strict-aliasing issues */
\r
1329 ptrSymbol = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT8[foundSlot + sizeof(uint32_t)];
\r
1330 for (i = 0; i < (TRC_CFG_SYMBOL_MAX_LENGTH); i++)
\r
1332 ptrSymbol[i] = (uint8_t)name[i]; /* We do this first to ensure we also get the 0 termination, if there is one */
\r
1338 /* Check the length of "name", if longer than SYMBOL_MAX_LENGTH */
\r
1339 while ((name[i] != 0) && i < 128)
\r
1344 /* Remember the longest symbol name, for diagnostic purposes */
\r
1345 if (i > LongestSymbolName)
\r
1347 LongestSymbolName = i;
\r
1350 /* Is this the last entry in the symbol table? */
\r
1351 if (foundSlot == firstFreeSymbolTableIndex)
\r
1353 firstFreeSymbolTableIndex += SYMBOL_TABLE_SLOT_SIZE;
\r
1358 NoRoomForSymbol++;
\r
1361 TRACE_EXIT_CRITICAL_SECTION();
\r
1364 /* Deletes a symbol name (task name etc.) from symbol table */
\r
1365 void prvTraceDeleteSymbol(void *address)
\r
1368 uint32_t *ptr, *lastEntryPtr;
\r
1369 TRACE_ALLOC_CRITICAL_SECTION();
\r
1371 TRACE_ENTER_CRITICAL_SECTION();
\r
1373 for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)
\r
1375 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1376 ptr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];
\r
1377 if (*ptr == (uint32_t)address)
\r
1379 /* See if we have another entry in the table, and that this isn't already the last entry */
\r
1380 if (firstFreeSymbolTableIndex > SYMBOL_TABLE_SLOT_SIZE && i != (firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE))
\r
1382 /* Another entry is available, get pointer to the last one */
\r
1383 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1384 lastEntryPtr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[(firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t)];
\r
1386 /* Copy last entry to this position */
\r
1387 for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t); j++)
\r
1389 ptr[j] = lastEntryPtr[j];
\r
1392 /* For good measure we also zero out the original position */
\r
1393 *lastEntryPtr = 0;
\r
1396 *ptr = 0; /* No other entry found, or this is the last entry */
\r
1399 firstFreeSymbolTableIndex -= SYMBOL_TABLE_SLOT_SIZE;
\r
1405 TRACE_EXIT_CRITICAL_SECTION();
\r
1408 /* Saves an object data entry (current task priority) in object data table */
\r
1409 void prvTraceSaveObjectData(const void *address, uint32_t data)
\r
1412 uint32_t foundSlot;
\r
1414 TRACE_ALLOC_CRITICAL_SECTION();
\r
1416 TRACE_ENTER_CRITICAL_SECTION();
\r
1418 foundSlot = firstFreeObjectDataTableIndex;
\r
1420 /* First look for previous entries using this address */
\r
1421 for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)
\r
1423 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1424 ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];
\r
1425 if (*ptr == (uint32_t)address)
\r
1432 if (foundSlot < OBJECT_DATA_TABLE_BUFFER_SIZE)
\r
1434 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1435 objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;
\r
1436 objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t) + 1] = data;
\r
1438 /* Is this the last entry in the object data table? */
\r
1439 if (foundSlot == firstFreeObjectDataTableIndex)
\r
1441 firstFreeObjectDataTableIndex += OBJECT_DATA_SLOT_SIZE;
\r
1446 NoRoomForObjectData++;
\r
1449 TRACE_EXIT_CRITICAL_SECTION();
\r
1452 /* Removes an object data entry (task base priority) from object data table */
\r
1453 void prvTraceDeleteObjectData(void *address)
\r
1456 uint32_t *ptr, *lastEntryPtr;
\r
1457 TRACE_ALLOC_CRITICAL_SECTION();
\r
1459 TRACE_ENTER_CRITICAL_SECTION();
\r
1461 for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)
\r
1463 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1464 ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];
\r
1465 if (*ptr == (uint32_t)address)
\r
1467 /* See if we have another entry in the table, and that this isn't already the last entry */
\r
1468 if (firstFreeObjectDataTableIndex > OBJECT_DATA_SLOT_SIZE && i != (firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE))
\r
1470 /* Another entry is available, get pointer to the last one */
\r
1471 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1472 lastEntryPtr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[(firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t)];
\r
1474 /* Copy last entry to this position */
\r
1475 for (j = 0; j < (OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t); j++)
\r
1477 ptr[j] = lastEntryPtr[j];
\r
1480 /* For good measure we also zero out the original position */
\r
1481 *lastEntryPtr = 0;
\r
1484 *ptr = 0; /* No other entry found, or this is the last entry */
\r
1487 firstFreeObjectDataTableIndex -= OBJECT_DATA_SLOT_SIZE;
\r
1493 TRACE_EXIT_CRITICAL_SECTION();
\r
1496 /* Checks if the provided command is a valid command */
\r
1497 int prvIsValidCommand(TracealyzerCommandType* cmd)
\r
1499 uint16_t checksum = (uint16_t)(0xFFFF - ( cmd->cmdCode +
\r
1506 if (cmd->checksumMSB != (unsigned char)(checksum >> 8))
\r
1509 if (cmd->checksumLSB != (unsigned char)(checksum & 0xFF))
\r
1512 if (cmd->cmdCode > CMD_LAST_COMMAND)
\r
1518 /* Executed the received command (Start or Stop) */
\r
1519 void prvProcessCommand(TracealyzerCommandType* cmd)
\r
1521 switch(cmd->cmdCode)
\r
1523 case CMD_SET_ACTIVE:
\r
1524 prvSetRecorderEnabled(cmd->param1);
\r
1531 /* Called on warnings, when the recording can continue. */
\r
1532 void prvTraceWarning(int errCode)
\r
1536 errorCode = errCode;
\r
1537 prvTraceStoreWarnings();
\r
1541 /* Called on critical errors in the recorder. Stops the recorder! */
\r
1542 void prvTraceError(int errCode)
\r
1546 errorCode = errCode;
\r
1547 prvTraceStoreWarnings();
\r
1548 vTracePrintF(trcWarningChannel, "Recorder stopped in prvTraceError()");
\r
1550 prvSetRecorderEnabled(0);
\r
1554 /* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */
\r
1555 #ifndef TRC_CFG_ARM_CM_USE_SYSTICK
\r
1556 #if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03)))
\r
1558 void prvTraceInitCortexM()
\r
1560 /* Make sure the DWT registers are unlocked, in case the debugger doesn't do this. */
\r
1561 TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK;
\r
1563 /* Make sure DWT is enabled is enabled, if supported */
\r
1564 TRC_REG_DEMCR |= TRC_DEMCR_TRCENA;
\r
1568 /* Verify that DWT is supported */
\r
1569 if (TRC_REG_DEMCR == 0)
\r
1571 /* This function is called on Cortex-M3, M4 and M7 devices to initialize
\r
1572 the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
\r
1574 If the below error is produced, the DWT unit does not seem to be available.
\r
1576 In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
\r
1577 to use SysTick timestamping instead, or define your own timestamping by
\r
1578 setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
\r
1579 and make the necessary definitions, as explained in trcHardwarePort.h.*/
\r
1581 prvTraceError(PSF_ERROR_DWT_NOT_SUPPORTED);
\r
1585 /* Verify that DWT_CYCCNT is supported */
\r
1586 if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT)
\r
1588 /* This function is called on Cortex-M3, M4 and M7 devices to initialize
\r
1589 the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
\r
1591 If the below error is produced, the cycle counter does not seem to be available.
\r
1593 In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
\r
1594 to use SysTick timestamping instead, or define your own timestamping by
\r
1595 setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
\r
1596 and make the necessary definitions, as explained in trcHardwarePort.h.*/
\r
1598 prvTraceError(PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED);
\r
1602 /* Reset the cycle counter */
\r
1603 TRC_REG_DWT_CYCCNT = 0;
\r
1605 /* Enable the cycle counter */
\r
1606 TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA;
\r
1608 } while(0); /* breaks above jump here */
\r
1613 /* Performs timestamping using definitions in trcHardwarePort.h */
\r
1614 static uint32_t prvGetTimestamp32(void)
\r
1616 #if ((TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR) || (TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR))
\r
1617 return TRC_HWTC_COUNT;
\r
1620 #if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR))
\r
1621 return TRC_HWTC_COUNT;
\r
1624 #if ((TRC_HWTC_TYPE == TRC_OS_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR))
\r
1625 uint32_t ticks = TRACE_GET_OS_TICKS();
\r
1626 return ((TRC_HWTC_COUNT) & 0x00FFFFFFU) + ((ticks & 0x000000FFU) << 24);
\r
1630 /* Store the Timestamp Config event */
\r
1631 static void prvTraceStoreTSConfig(void)
\r
1633 /* If not overridden using vTraceSetFrequency, use default value */
\r
1634 if (timestampFrequency == 0)
\r
1636 timestampFrequency = TRC_HWTC_FREQ_HZ;
\r
1639 #if (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR || TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR)
\r
1641 prvTraceStoreEvent(5,
\r
1642 PSF_EVENT_TS_CONFIG,
\r
1643 (uint32_t)timestampFrequency,
\r
1644 (uint32_t)(TRACE_TICK_RATE_HZ),
\r
1645 (uint32_t)(TRC_HWTC_TYPE),
\r
1646 (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD),
\r
1647 (uint32_t)(TRC_HWTC_PERIOD));
\r
1651 prvTraceStoreEvent(4,
\r
1652 PSF_EVENT_TS_CONFIG,
\r
1653 (uint32_t)timestampFrequency,
\r
1654 (uint32_t)(TRACE_TICK_RATE_HZ),
\r
1655 (uint32_t)(TRC_HWTC_TYPE),
\r
1656 (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD));
\r
1660 /* Retrieve a buffer page to write to. */
\r
1661 static int prvAllocateBufferPage(int prevPage)
\r
1666 index = (prevPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);
\r
1668 while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)))
\r
1670 index = (index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);
\r
1673 if (PageInfo[index].Status == PAGE_STATUS_FREE)
\r
1681 /* Mark the page read as complete. */
\r
1682 static void prvPageReadComplete(int pageIndex)
\r
1684 TRACE_ALLOC_CRITICAL_SECTION();
\r
1686 TRACE_ENTER_CRITICAL_SECTION();
\r
1687 PageInfo[pageIndex].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
\r
1688 PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)];
\r
1689 PageInfo[pageIndex].Status = PAGE_STATUS_FREE;
\r
1691 TotalBytesRemaining += (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
\r
1693 TRACE_EXIT_CRITICAL_SECTION();
\r
1696 /* Get the current buffer page index and remaining number of bytes. */
\r
1697 static int prvGetBufferPage(int32_t* bytesUsed)
\r
1699 static int8_t lastPage = -1;
\r
1701 int8_t index = (int8_t) ((lastPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT));
\r
1703 while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)))
\r
1705 index = (int8_t)((index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT));
\r
1708 if (PageInfo[index].Status == PAGE_STATUS_READ)
\r
1710 *bytesUsed = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) - PageInfo[index].BytesRemaining;
\r
1720 /*******************************************************************************
\r
1721 * uint32_t prvPagedEventBufferTransfer(void)
\r
1723 * Transfers one buffer page of trace data, if a full page is available, using
\r
1724 * the macro TRC_STREAM_PORT_WRITE_DATA as defined in trcStreamingPort.h.
\r
1726 * This function is intended to be called the periodic TzCtrl task with a suitable
\r
1727 * delay (e.g. 10-100 ms).
\r
1729 * Returns the number of bytes sent. If non-zero, it is good to call this
\r
1730 * again, in order to send any additional data waiting in the buffer.
\r
1731 * If zero, wait a while before calling again.
\r
1733 * In case of errors from the streaming interface, it registers a warning
\r
1734 * (PSF_WARNING_STREAM_PORT_WRITE) provided by xTraceGetLastError().
\r
1736 *******************************************************************************/
\r
1737 uint32_t prvPagedEventBufferTransfer(void)
\r
1739 int8_t pageToTransfer = -1;
\r
1740 int32_t bytesTransferredTotal = 0;
\r
1741 int32_t bytesTransferredNow = 0;
\r
1742 int32_t bytesToTransfer;
\r
1744 pageToTransfer = (int8_t)prvGetBufferPage(&bytesToTransfer);
\r
1746 /* bytesToTransfer now contains the number of "valid" bytes in the buffer page, that should be transmitted.
\r
1747 There might be some unused junk bytes in the end, that must be ignored. */
\r
1749 if (pageToTransfer > -1)
\r
1751 while (1) /* Keep going until we have transferred all that we intended to */
\r
1753 if (TRC_STREAM_PORT_WRITE_DATA(
\r
1754 &EventBuffer[pageToTransfer * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) + bytesTransferredTotal],
\r
1755 (uint32_t)(bytesToTransfer - bytesTransferredTotal),
\r
1756 &bytesTransferredNow) == 0)
\r
1758 /* Write was successful. Update the number of transferred bytes. */
\r
1759 bytesTransferredTotal += bytesTransferredNow;
\r
1761 if (bytesTransferredTotal == bytesToTransfer)
\r
1763 /* All bytes have been transferred. Mark the buffer page as "Read Complete" (so it can be written to) and return OK. */
\r
1764 prvPageReadComplete(pageToTransfer);
\r
1765 return (uint32_t)bytesTransferredTotal;
\r
1770 /* Some error from the streaming interface... */
\r
1771 prvTraceWarning(PSF_WARNING_STREAM_PORT_WRITE);
\r
1779 /*******************************************************************************
\r
1780 * void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)
\r
1782 * Returns a pointer to an available location in the buffer able to store the
\r
1785 * Return value: The pointer.
\r
1788 * - sizeOfEvent: The size of the event that is to be placed in the buffer.
\r
1790 *******************************************************************************/
\r
1791 void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)
\r
1794 static int currentWritePage = -1;
\r
1796 if (currentWritePage == -1)
\r
1798 currentWritePage = prvAllocateBufferPage(currentWritePage);
\r
1799 if (currentWritePage == -1)
\r
1801 DroppedEventCounter++;
\r
1806 if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0)
\r
1808 PageInfo[currentWritePage].Status = PAGE_STATUS_READ;
\r
1810 TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes
\r
1812 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
\r
1813 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
\r
1815 currentWritePage = prvAllocateBufferPage(currentWritePage);
\r
1816 if (currentWritePage == -1)
\r
1818 DroppedEventCounter++;
\r
1822 ret = PageInfo[currentWritePage].WritePointer;
\r
1823 PageInfo[currentWritePage].WritePointer += sizeOfEvent;
\r
1824 PageInfo[currentWritePage].BytesRemaining = (uint16_t)(PageInfo[currentWritePage].BytesRemaining -sizeOfEvent);
\r
1826 TotalBytesRemaining = (TotalBytesRemaining-(uint16_t)sizeOfEvent);
\r
1828 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
\r
1829 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
\r
1834 /*******************************************************************************
\r
1835 * void prvPagedEventBufferInit(char* buffer)
\r
1837 * Assigns the buffer to use and initializes the PageInfo structure.
\r
1839 * Return value: void
\r
1842 * - char* buffer: pointer to the trace data buffer, allocated by the caller.
\r
1844 *******************************************************************************/
\r
1845 void prvPagedEventBufferInit(char* buffer)
\r
1848 TRACE_ALLOC_CRITICAL_SECTION();
\r
1850 EventBuffer = buffer;
\r
1852 TRACE_ENTER_CRITICAL_SECTION();
\r
1853 for (i = 0; i < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); i++)
\r
1855 PageInfo[i].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);
\r
1856 PageInfo[i].WritePointer = &EventBuffer[i * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)];
\r
1857 PageInfo[i].Status = PAGE_STATUS_FREE;
\r
1859 TRACE_EXIT_CRITICAL_SECTION();
\r
1863 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
\r
1865 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
\r