1 /*******************************************************************************
\r
2 * Trace Recorder Library for Tracealyzer v3.1.2
\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, 2017.
\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
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 #define PSF_ERROR_NONE 0
\r
139 #define PSF_ERROR_EVENT_CODE_TOO_LARGE 1
\r
140 #define PSF_ERROR_ISR_NESTING_OVERFLOW 2
\r
141 #define PSF_ERROR_DWT_NOT_SUPPORTED 3
\r
142 #define PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED 4
\r
143 #define PSF_ERROR_AUTO_ISR_END 5
\r
145 /* Part of the PSF format - encodes the number of 32-bit params in an event */
\r
146 #define PARAM_COUNT(n) ((n & 0xF) << 12)
\r
148 /* The Symbol Table instance - keeps names of tasks and other named objects. */
\r
149 static SymbolTable symbolTable = { { { 0 } } };
\r
151 /* This points to the first unused entry in the symbol table. */
\r
152 static uint32_t firstFreeSymbolTableIndex = 0;
\r
154 /* The Object Data Table instance - keeps initial priorities of tasks. */
\r
155 static ObjectDataTable objectDataTable = { { { 0 } } };
\r
157 /* This points to the first unused entry in the object data table. */
\r
158 static uint32_t firstFreeObjectDataTableIndex = 0;
\r
160 /* Keeps track of ISR nesting */
\r
161 static uint32_t ISR_stack[TRC_CFG_MAX_ISR_NESTING];
\r
163 /* Keeps track of ISR nesting */
\r
164 static int8_t ISR_stack_index = -1;
\r
166 /* Any error that occurred in the recorder (also creates User Event) */
\r
167 static int errorCode = 0;
\r
169 /* Counts the number of trace sessions (not yet used) */
\r
170 static uint32_t SessionCounter = 0u;
\r
172 /* Master switch for recording (0 => Disabled, 1 => Enabled) */
\r
173 uint32_t RecorderEnabled = 0u;
\r
175 /* Used to determine endian of data (big/little) */
\r
176 static uint32_t PSFEndianessIdentifier = 0x50534600;
\r
178 /* Used to interpret the data format */
\r
179 static uint16_t FormatVersion = 0x0004;
\r
181 /* The number of events stored. Used as event sequence number. */
\r
182 static uint32_t eventCounter = 0;
\r
184 /* The user event channel for recorder warnings, defined in trcKernelPort.c */
\r
185 extern char* trcWarningChannel;
\r
187 /* Remembers if an earlier ISR in a sequence of adjacent ISRs has triggered a task switch.
\r
188 In that case, vTraceStoreISREnd does not store a return to the previously executing task. */
\r
189 int32_t isPendingContextSwitch = 0;
\r
191 uint32_t uiTraceTickCount = 0;
\r
192 uint32_t timestampFrequency = 0;
\r
193 uint32_t DroppedEventCounter = 0; // Total number of dropped events (failed allocations)
\r
194 uint32_t TotalBytesRemaining_LowWaterMark = TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
195 uint32_t TotalBytesRemaining = TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT * TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
197 PageType PageInfo[TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT];
\r
199 char* EventBuffer = NULL;
\r
201 /*******************************************************************************
\r
204 * Incremented on prvTraceSaveSymbol if no room for saving the symbol name. This
\r
205 * is used for storing the names of:
\r
207 * - Named ISRs (xTraceSetISRProperties)
\r
208 * - Named kernel objects (vTraceStoreKernelObjectName)
\r
209 * - User event channels (xTraceRegisterString)
\r
211 * This variable should be zero. If not, it shows the number of missing slots so
\r
212 * far. In that case, increment SYMBOL_TABLE_SLOTS with (at least) this value.
\r
213 ******************************************************************************/
\r
214 volatile uint32_t NoRoomForSymbol = 0;
\r
216 /*******************************************************************************
\r
217 * NoRoomForObjectData
\r
219 * Incremented on prvTraceSaveObjectData if no room for saving the object data,
\r
220 * i.e., the base priorities of tasks. There must be one slot for each task.
\r
221 * If not, this variable will show the difference.
\r
223 * This variable should be zero. If not, it shows the number of missing slots so
\r
224 * far. In that case, increment OBJECT_DATA_SLOTS with (at least) this value.
\r
225 ******************************************************************************/
\r
226 volatile uint32_t NoRoomForObjectData = 0;
\r
228 /*******************************************************************************
\r
229 * LongestSymbolName
\r
231 * Updated in prvTraceSaveSymbol. Should not exceed SYMBOL_MAX_LENGTH, otherwise
\r
232 * symbol names will be truncated. In that case, set SYMBOL_MAX_LENGTH to (at
\r
233 * least) this value.
\r
234 ******************************************************************************/
\r
235 volatile uint32_t LongestSymbolName = 0;
\r
237 /*******************************************************************************
\r
238 * MaxBytesTruncated
\r
240 * Set in prvTraceStoreStringEvent if the total data payload exceeds 60 bytes,
\r
241 * including data arguments and the string. For user events, that is 52 bytes
\r
242 * for string and data arguments. In that is exceeded, the event is truncated
\r
243 * (usually only the string, unless more than 15 parameters) and this variable
\r
244 * holds the maximum number of truncated bytes, from any event.
\r
245 ******************************************************************************/
\r
246 volatile uint32_t MaxBytesTruncated = 0;
\r
248 /* Internal common function for storing string events */
\r
249 static void prvTraceStoreStringEventHelper( int nArgs,
\r
251 traceString userEvtChannel,
\r
254 static void prvTraceStoreSimpleStringEventHelper( traceString userEvtChannel,
\r
257 /* Stores the header information on Start */
\r
258 static void prvTraceStoreHeader(void);
\r
260 /* Stores the symbol table on Start */
\r
261 static void prvTraceStoreSymbolTable(void);
\r
263 /* Stores the object table on Start */
\r
264 static void prvTraceStoreObjectDataTable(void);
\r
266 /* Store the Timestamp Config on Start */
\r
267 static void prvTraceStoreTSConfig(void);
\r
269 /* Store the current warnings */
\r
270 static void prvTraceStoreWarnings(void);
\r
272 /* Internal function for starting/stopping the recorder. */
\r
273 static void prvSetRecorderEnabled(uint32_t isEnabled);
\r
275 /* Mark the page read as complete. */
\r
276 static void prvPageReadComplete(int pageIndex);
\r
278 /* Retrieve a buffer page to write to. */
\r
279 static int prvAllocateBufferPage(int prevPage);
\r
281 /* Get the current buffer page index and remaining number of bytes. */
\r
282 static int prvGetBufferPage(int32_t* bytesUsed);
\r
284 /* Performs timestamping using definitions in trcHardwarePort.h */
\r
285 static uint32_t prvGetTimestamp32(void);
\r
287 /* Signal an error. */
\r
288 void prvTraceError(int errCode);
\r
290 /******************************************************************************
\r
291 * vTraceInstanceFinishedNow
\r
293 * Creates an event that ends the current task instance at this very instant.
\r
294 * This makes the viewer to splits the current fragment at this point and begin
\r
295 * a new actor instance, even if no task-switch has occurred.
\r
296 *****************************************************************************/
\r
297 void vTraceInstanceFinishedNow(void)
\r
299 prvTraceStoreEvent0(PSF_EVENT_IFE_DIRECT);
\r
302 /******************************************************************************
\r
303 * vTraceInstanceFinishedNext
\r
305 * Marks the current "task instance" as finished on the next kernel call.
\r
307 * If that kernel call is blocking, the instance ends after the blocking event
\r
308 * and the corresponding return event is then the start of the next instance.
\r
309 * If the kernel call is not blocking, the viewer instead splits the current
\r
310 * fragment right before the kernel call, which makes this call the first event
\r
311 * of the next instance.
\r
312 *****************************************************************************/
\r
313 void vTraceInstanceFinishedNext(void)
\r
315 prvTraceStoreEvent0(PSF_EVENT_IFE_NEXT);
\r
318 /*******************************************************************************
\r
319 * xTraceRegisterString
\r
321 * Stores a name for a user event channel, returns the handle.
\r
322 ******************************************************************************/
\r
323 traceString xTraceRegisterString(const char* name)
\r
325 prvTraceSaveSymbol((const void*)name, name);
\r
327 /* Always save in symbol table, if the recording has not yet started */
\r
328 prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, (const char*)name, (uint32_t)name);
\r
330 return (traceString)name;
\r
333 /*******************************************************************************
\r
334 * vTraceStoreKernelObjectName
\r
336 * Parameter object: pointer to the Event Group that shall be named
\r
337 * Parameter name: the name to set (const string literal)
\r
339 * Sets a name for a kernel object for display in Tracealyzer.
\r
340 ******************************************************************************/
\r
341 void vTraceStoreKernelObjectName(void* object, const char* name)
\r
343 /* Always save in symbol table, if the recording has not yet started */
\r
344 prvTraceSaveSymbol(object, name);
\r
346 prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, name, (uint32_t)object);
\r
350 /******************************************************************************
\r
351 * vTraceSetFrequency
\r
353 * Registers the clock rate of the time source for the event timestamping.
\r
354 * This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ)
\r
355 * should be incorrect for your setup, you can override it using this function.
\r
357 * Must be called prior to vTraceEnable, and the time source is assumed to
\r
358 * have a fixed clock frequency after the startup.
\r
359 *****************************************************************************/
\r
360 void vTraceSetFrequency(uint32_t frequency)
\r
362 timestampFrequency = frequency;
\r
365 /******************************************************************************
\r
368 * Generates "User Events", with unformatted text.
\r
370 * User Events can be used for very efficient application logging, and are shown
\r
371 * as yellow labels in the main trace view.
\r
373 * You may group User Events into User Event Channels. The yellow User Event
\r
374 * labels shows the logged string, preceded by the channel name within
\r
375 * brackets. For example:
\r
377 * "[MyChannel] Hello World!"
\r
379 * The User Event Channels are shown in the View Filter, which makes it easy to
\r
380 * select what User Events you wish to display. User Event Channels are created
\r
381 * using xTraceRegisterString().
\r
385 * traceString chn = xTraceRegisterString("MyChannel");
\r
387 * vTracePrint(chn, "Hello World!");
\r
389 ******************************************************************************/
\r
390 void vTracePrint(traceString chn, const char* str)
\r
392 prvTraceStoreSimpleStringEventHelper(chn, str);
\r
395 /******************************************************************************
\r
398 * Generates "User Events", with formatted text and data, similar to a "printf".
\r
399 * It is very fast since the actual formatting is done on the host side when the
\r
400 * trace is displayed.
\r
402 * User Events can be used for very efficient application logging, and are shown
\r
403 * as yellow labels in the main trace view.
\r
404 * An advantage of User Events is that data can be plotted in the "User Event
\r
405 * Signal Plot" view, visualizing any data you log as User Events, discrete
\r
406 * states or control system signals (e.g. system inputs or outputs).
\r
408 * You may group User Events into User Event Channels. The yellow User Event
\r
409 * labels show the logged string, preceded by the channel name within brackets.
\r
413 * "[MyChannel] Hello World!"
\r
415 * The User Event Channels are shown in the View Filter, which makes it easy to
\r
416 * select what User Events you wish to display. User Event Channels are created
\r
417 * using xTraceRegisterString().
\r
421 * traceString adc_uechannel = xTraceRegisterString("ADC User Events");
\r
423 * vTracePrintF(adc_uechannel,
\r
424 * "ADC channel %d: %d volts",
\r
425 * ch, adc_reading);
\r
427 * All data arguments are assumed to be 32 bit wide. The following formats are
\r
429 * %d - signed integer. The following width and padding format is supported: "%05d" -> "-0042" and "%5d" -> " -42"
\r
430 * %u - unsigned integer. The following width and padding format is supported: "%05u" -> "00042" and "%5u" -> " 42"
\r
431 * %X - hexadecimal (uppercase). The following width and padding format is supported: "%04X" -> "002A" and "%4X" -> " 2A"
\r
432 * %x - hexadecimal (lowercase). The following width and padding format is supported: "%04x" -> "002a" and "%4x" -> " 2a"
\r
433 * %s - string (currently, this must be an earlier stored symbol name)
\r
435 * Up to 15 data arguments are allowed, with a total size of maximum 60 byte
\r
436 * including 8 byte for the base event fields and the format string. So with
\r
437 * one data argument, the maximum string length is 48 chars. If this is exceeded
\r
438 * the string is truncated (4 bytes at a time).
\r
440 ******************************************************************************/
\r
441 void vTracePrintF(traceString chn, const char* fmt, ...)
\r
448 /* Count the number of arguments in the format string (e.g., %d) */
\r
449 for (i = 0; (fmt[i] != 0) && (i < 52); i++)
\r
453 if (fmt[i + 1] != '%')
\r
455 nArgs++; /* Found an argument */
\r
458 i++; /* Move past format specifier or non-argument '%' */
\r
466 prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs + 1), chn, fmt, &vl);
\r
470 prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs), chn, fmt, &vl);
\r
476 /*******************************************************************************
\r
477 * xTraceSetISRProperties
\r
479 * Stores a name and priority level for an Interrupt Service Routine, to allow
\r
480 * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin.
\r
483 * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
485 * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
\r
487 * void ISR_handler()
\r
489 * vTraceStoreISRBegin(Timer1Handle);
\r
491 * vTraceStoreISREnd(0);
\r
494 ******************************************************************************/
\r
495 traceHandle xTraceSetISRProperties(const char* name, uint8_t priority)
\r
497 /* Save object data in object data table */
\r
498 prvTraceSaveObjectData((const void*)name, priority);
\r
500 /* Note: "name" is used both as a string argument, and the address as ID */
\r
501 prvTraceStoreStringEvent(2, PSF_EVENT_DEFINE_ISR, name, name, priority);
\r
503 /* Always save in symbol table, if the recording has not yet started */
\r
504 prvTraceSaveSymbol((const void*)name, name);
\r
506 return (traceHandle)name;
\r
509 /*******************************************************************************
\r
510 * vTraceStoreISRBegin
\r
512 * Registers the beginning of an Interrupt Service Routine, using a traceHandle
\r
513 * provided by xTraceSetISRProperties.
\r
516 * #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
518 * traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);
\r
520 * void ISR_handler()
\r
522 * vTraceStoreISRBegin(Timer1Handle);
\r
524 * vTraceStoreISREnd(0);
\r
527 ******************************************************************************/
\r
528 void vTraceStoreISRBegin(traceHandle handle)
\r
530 TRACE_ALLOC_CRITICAL_SECTION();
\r
532 TRACE_ENTER_CRITICAL_SECTION();
\r
534 /* We are at the start of a possible ISR chain.
\r
535 No context switches should have been triggered now. */
\r
536 if (ISR_stack_index == -1)
\r
537 isPendingContextSwitch = 0;
\r
539 if (ISR_stack_index < TRC_CFG_MAX_ISR_NESTING - 1)
\r
542 ISR_stack[ISR_stack_index] = (uint32_t)handle;
\r
543 prvTraceStoreEvent1(PSF_EVENT_ISR_BEGIN, (uint32_t)handle);
\r
544 TRACE_EXIT_CRITICAL_SECTION();
\r
548 TRACE_EXIT_CRITICAL_SECTION();
\r
549 prvTraceError(PSF_ERROR_ISR_NESTING_OVERFLOW);
\r
553 /*******************************************************************************
\r
554 * vTraceStoreISREnd
\r
556 * Registers the end of an Interrupt Service Routine.
\r
558 * The parameter pendingISR indicates if the interrupt has requested a
\r
559 * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the
\r
560 * interrupt is assumed to return to the previous context.
\r
563 * #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt
\r
564 * traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder
\r
566 * traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1);
\r
568 * void ISR_handler()
\r
570 * vTraceStoreISRBegin(traceHandleIsrTimer1);
\r
572 * vTraceStoreISREnd(0);
\r
575 ******************************************************************************/
\r
576 void vTraceStoreISREnd(int isTaskSwitchRequired)
\r
578 TRACE_ALLOC_CRITICAL_SECTION();
\r
580 TRACE_ENTER_CRITICAL_SECTION();
\r
582 /* Is there a pending task-switch? (perhaps from an earlier ISR) */
\r
583 isPendingContextSwitch |= isTaskSwitchRequired;
\r
585 if (ISR_stack_index > 0)
\r
589 /* Store return to interrupted ISR (if nested ISRs)*/
\r
590 prvTraceStoreEvent1(PSF_EVENT_ISR_RESUME, (uint32_t)ISR_stack[ISR_stack_index]);
\r
596 /* Store return to interrupted task, if no context switch will occur in between. */
\r
597 if ((isPendingContextSwitch == 0) || (prvTraceIsSchedulerSuspended()))
\r
599 prvTraceStoreEvent1(PSF_EVENT_TS_RESUME, (uint32_t)TRACE_GET_CURRENT_TASK());
\r
603 TRACE_EXIT_CRITICAL_SECTION();
\r
607 /*******************************************************************************
\r
608 * xTraceGetLastError
\r
610 * Returns the last error, if any.
\r
611 *****************************************************************************/
\r
612 const char* xTraceGetLastError(void)
\r
614 if (NoRoomForSymbol > 0)
\r
616 return "TRC_CFG_SYMBOL_TABLE_SLOTS too small.";
\r
619 if (LongestSymbolName > (TRC_CFG_SYMBOL_MAX_LENGTH))
\r
621 return "TRC_CFG_SYMBOL_MAX_LENGTH too small.";
\r
624 if (NoRoomForObjectData > 0)
\r
626 return "TRC_CFG_OBJECT_DATA_SLOTS too small.";
\r
629 if (MaxBytesTruncated > 0)
\r
631 return "String or User Event too long.";
\r
636 case PSF_ERROR_EVENT_CODE_TOO_LARGE:
\r
637 return "An invalid event code was used.";
\r
638 case PSF_ERROR_ISR_NESTING_OVERFLOW:
\r
639 return "Too much ISR nesting.";
\r
640 case PSF_ERROR_DWT_NOT_SUPPORTED:
\r
641 return "DWT not supported by this chip.";
\r
642 case PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED:
\r
643 return "DWT_CYCCNT not supported by this chip.";
\r
649 /*******************************************************************************
\r
652 * Clears any errors.
\r
653 *****************************************************************************/
\r
654 void vTraceClearError(void)
\r
656 NoRoomForSymbol = 0;
\r
657 LongestSymbolName = 0;
\r
658 NoRoomForObjectData = 0;
\r
659 MaxBytesTruncated = 0;
\r
660 errorCode = PSF_ERROR_NONE;
\r
663 /*******************************************************************************
\r
666 * Stops the tracing.
\r
667 *****************************************************************************/
\r
668 void vTraceStop(void)
\r
670 prvSetRecorderEnabled(0);
\r
673 /*******************************************************************************
\r
674 * vTraceSetRecorderDataBuffer
\r
676 * If custom allocation is used, this function must be called so the recorder
\r
677 * library knows where to save the trace data.
\r
678 ******************************************************************************/
\r
679 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)
\r
681 extern char* _TzTraceData;
\r
683 void vTraceSetRecorderDataBuffer(void* pRecorderData)
\r
685 _TzTraceData = pRecorderData;
\r
689 /******************************************************************************/
\r
690 /*** INTERNAL FUNCTIONS *******************************************************/
\r
691 /******************************************************************************/
\r
693 /* Internal function for starting/stopping the recorder. */
\r
694 static void prvSetRecorderEnabled(uint32_t isEnabled)
\r
698 TRACE_ALLOC_CRITICAL_SECTION();
\r
700 currentTask = TRACE_GET_CURRENT_TASK();
\r
702 TRACE_ENTER_CRITICAL_SECTION();
\r
704 RecorderEnabled = isEnabled;
\r
706 if (currentTask == NULL)
\r
708 currentTask = (void*)HANDLE_NO_TASK;
\r
711 if (RecorderEnabled)
\r
716 ISR_stack_index = -1;
\r
717 prvTraceStoreHeader();
\r
718 prvTraceStoreSymbolTable();
\r
719 prvTraceStoreObjectDataTable();
\r
720 prvTraceStoreEvent3( PSF_EVENT_TRACE_START,
\r
721 (uint32_t)TRACE_GET_OS_TICKS(),
\r
722 (uint32_t)currentTask,
\r
724 prvTraceStoreTSConfig();
\r
725 prvTraceStoreWarnings();
\r
732 TRACE_EXIT_CRITICAL_SECTION();
\r
735 /* Stores the symbol table on Start */
\r
736 static void prvTraceStoreSymbolTable()
\r
740 TRACE_ALLOC_CRITICAL_SECTION();
\r
742 TRACE_ENTER_CRITICAL_SECTION();
\r
744 if (RecorderEnabled)
\r
746 for (i = 0; i < (sizeof(SymbolTable) / sizeof(uint32_t)); i += (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)))
\r
748 TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, SYMBOL_TABLE_SLOT_SIZE);
\r
751 for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)); j++)
\r
753 data[j] = symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i+j];
\r
755 TRC_STREAM_PORT_COMMIT_EVENT(data, SYMBOL_TABLE_SLOT_SIZE);
\r
759 TRACE_EXIT_CRITICAL_SECTION();
\r
762 /* Stores the object table on Start */
\r
763 static void prvTraceStoreObjectDataTable()
\r
767 TRACE_ALLOC_CRITICAL_SECTION();
\r
769 TRACE_ENTER_CRITICAL_SECTION();
\r
771 if (RecorderEnabled)
\r
773 for (i = 0; i < (sizeof(ObjectDataTable) / sizeof(uint32_t)); i += (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)))
\r
775 TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, OBJECT_DATA_SLOT_SIZE);
\r
778 for (j = 0; j < (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)); j++)
\r
780 data[j] = objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i+j];
\r
782 TRC_STREAM_PORT_COMMIT_EVENT(data, OBJECT_DATA_SLOT_SIZE);
\r
786 TRACE_EXIT_CRITICAL_SECTION();
\r
789 /* Stores the header information on Start */
\r
790 static void prvTraceStoreHeader()
\r
792 TRACE_ALLOC_CRITICAL_SECTION();
\r
794 TRACE_ENTER_CRITICAL_SECTION();
\r
796 if (RecorderEnabled)
\r
798 TRC_STREAM_PORT_ALLOCATE_EVENT(PSFHeaderInfo, header, sizeof(PSFHeaderInfo));
\r
799 if (header != NULL)
\r
801 header->psf = PSFEndianessIdentifier;
\r
802 header->version = FormatVersion;
\r
803 header->platform = TRACE_KERNEL_VERSION;
\r
804 header->options = 0;
\r
805 /* Lowest bit used for TRC_IRQ_PRIORITY_ORDER */
\r
806 header->options = header->options | (TRC_IRQ_PRIORITY_ORDER << 0);
\r
807 header->symbolSize = SYMBOL_TABLE_SLOT_SIZE;
\r
808 header->symbolCount = (TRC_CFG_SYMBOL_TABLE_SLOTS);
\r
809 header->objectDataSize = 8;
\r
810 header->objectDataCount = TRC_CFG_OBJECT_DATA_SLOTS;
\r
811 TRC_STREAM_PORT_COMMIT_EVENT(header, sizeof(PSFHeaderInfo));
\r
814 TRACE_EXIT_CRITICAL_SECTION();
\r
817 /* Store the current warnings */
\r
818 static void prvTraceStoreWarnings()
\r
820 TRACE_ALLOC_CRITICAL_SECTION();
\r
822 TRACE_ENTER_CRITICAL_SECTION();
\r
824 if (RecorderEnabled)
\r
826 if (NoRoomForSymbol > 0)
\r
828 vTracePrintF(trcWarningChannel, "TRC_CFG_SYMBOL_TABLE_SLOTS too small. Add %d slots.", NoRoomForSymbol);
\r
831 if (LongestSymbolName > 0)
\r
833 if (LongestSymbolName > (TRC_CFG_SYMBOL_MAX_LENGTH))
\r
835 vTracePrintF(trcWarningChannel, "TRC_CFG_SYMBOL_MAX_LENGTH too small. Add %d chars.", LongestSymbolName - (TRC_CFG_SYMBOL_MAX_LENGTH));
\r
839 if (NoRoomForObjectData > 0)
\r
841 /* We don't know how many objects we actually need to make room for since NoRoomForObjectData can be increased multiple times for the same object! */
\r
842 vTracePrintF(trcWarningChannel, "TRC_CFG_OBJECT_DATA_SLOTS too small. Add more slots.");
\r
845 if (MaxBytesTruncated > 0)
\r
847 /* Some string event generated a too long string that was truncated.
\r
848 This may happen for the following functions:
\r
850 - vTraceStoreKernelObjectName
\r
851 - vTraceStoreUserEventChannelName
\r
852 - vTraceSetISRProperties
\r
854 A PSF event may store maximum 60 bytes payload, including data arguments
\r
855 and string characters. For User Events, also the User Event Channel ptr
\r
856 must be squeezed in, if a channel is specified. */
\r
858 vTracePrintF(trcWarningChannel, "String event too long, up to %d bytes truncated.", MaxBytesTruncated);
\r
863 case PSF_ERROR_EVENT_CODE_TOO_LARGE:
\r
865 case PSF_ERROR_ISR_NESTING_OVERFLOW:
\r
867 case PSF_ERROR_DWT_NOT_SUPPORTED:
\r
868 vTracePrintF(trcWarningChannel, "DWT not supported, see prvTraceInitCortexM.");
\r
870 case PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED:
\r
871 vTracePrintF(trcWarningChannel, "DWT_CYCCNT not supported, see prvTraceInitCortexM.");
\r
875 TRACE_EXIT_CRITICAL_SECTION();
\r
878 /* Store an event with zero parameters (event ID only) */
\r
879 void prvTraceStoreEvent0(uint16_t eventID)
\r
881 TRACE_ALLOC_CRITICAL_SECTION();
\r
883 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
885 TRACE_ENTER_CRITICAL_SECTION();
\r
887 if (RecorderEnabled)
\r
892 TRC_STREAM_PORT_ALLOCATE_EVENT(BaseEvent, event, sizeof(BaseEvent));
\r
895 event->EventID = eventID | PARAM_COUNT(0);
\r
896 event->EventCount = (uint16_t)eventCounter;
\r
897 event->TS = prvGetTimestamp32();
\r
898 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(BaseEvent));
\r
902 TRACE_EXIT_CRITICAL_SECTION();
\r
905 /* Store an event with one 32-bit parameter (pointer address or an int) */
\r
906 void prvTraceStoreEvent1(uint16_t eventID, uint32_t param1)
\r
908 TRACE_ALLOC_CRITICAL_SECTION();
\r
910 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
912 TRACE_ENTER_CRITICAL_SECTION();
\r
914 if (RecorderEnabled)
\r
919 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_1, event, sizeof(EventWithParam_1));
\r
922 event->base.EventID = eventID | PARAM_COUNT(1);
\r
923 event->base.EventCount = (uint16_t)eventCounter;
\r
924 event->base.TS = prvGetTimestamp32();
\r
925 event->param1 = (uint32_t)param1;
\r
926 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_1));
\r
930 TRACE_EXIT_CRITICAL_SECTION();
\r
933 /* Store an event with two 32-bit parameters */
\r
934 void prvTraceStoreEvent2(uint16_t eventID, uint32_t param1, uint32_t param2)
\r
936 TRACE_ALLOC_CRITICAL_SECTION();
\r
938 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
940 TRACE_ENTER_CRITICAL_SECTION();
\r
942 if (RecorderEnabled)
\r
947 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_2, event, sizeof(EventWithParam_2));
\r
950 event->base.EventID = eventID | PARAM_COUNT(2);
\r
951 event->base.EventCount = (uint16_t)eventCounter;
\r
952 event->base.TS = prvGetTimestamp32();
\r
953 event->param1 = (uint32_t)param1;
\r
954 event->param2 = param2;
\r
955 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_2));
\r
959 TRACE_EXIT_CRITICAL_SECTION();
\r
962 /* Store an event with three 32-bit parameters */
\r
963 void prvTraceStoreEvent3( uint16_t eventID,
\r
968 TRACE_ALLOC_CRITICAL_SECTION();
\r
970 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
972 TRACE_ENTER_CRITICAL_SECTION();
\r
974 if (RecorderEnabled)
\r
979 TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_3, event, sizeof(EventWithParam_3));
\r
982 event->base.EventID = eventID | PARAM_COUNT(3);
\r
983 event->base.EventCount = (uint16_t)eventCounter;
\r
984 event->base.TS = prvGetTimestamp32();
\r
985 event->param1 = (uint32_t)param1;
\r
986 event->param2 = param2;
\r
987 event->param3 = param3;
\r
988 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_3));
\r
992 TRACE_EXIT_CRITICAL_SECTION();
\r
995 /* Stores an event with <nParam> 32-bit integer parameters */
\r
996 void prvTraceStoreEvent(int nParam, uint16_t eventID, ...)
\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
1008 int eventSize = (int)sizeof(BaseEvent) + nParam * (int)sizeof(uint32_t);
\r
1013 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1014 if (event != NULL)
\r
1016 event->base.EventID = eventID | (uint16_t)PARAM_COUNT(nParam);
\r
1017 event->base.EventCount = (uint16_t)eventCounter;
\r
1018 event->base.TS = prvGetTimestamp32();
\r
1020 va_start(vl, eventID);
\r
1021 for (i = 0; i < nParam; i++)
\r
1023 uint32_t* tmp = (uint32_t*) &(event->data[i]);
\r
1024 *tmp = va_arg(vl, uint32_t);
\r
1028 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1032 TRACE_EXIT_CRITICAL_SECTION();
\r
1035 /* Stories an event with a string and <nParam> 32-bit integer parameters */
\r
1036 void prvTraceStoreStringEvent(int nArgs, uint16_t eventID, const char* str, ...)
\r
1040 va_start(vl, str);
\r
1041 prvTraceStoreStringEventHelper(nArgs, eventID, NULL, str, &vl);
\r
1045 /* Internal common function for storing string events */
\r
1046 static void prvTraceStoreStringEventHelper( int nArgs,
\r
1048 traceString userEvtChannel,
\r
1049 const char* str, va_list* vl)
\r
1056 TRACE_ALLOC_CRITICAL_SECTION();
\r
1058 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1060 for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */
\r
1062 /* The string length in multiples of 32 bit words (+1 for null character) */
\r
1063 nStrWords = (len+1+3)/4;
\r
1065 /* If a user event channel is specified, add in the list */
\r
1066 if (userEvtChannel)
\r
1069 offset = nArgs * 4;
\r
1071 /* The total number of 32-bit words needed for the whole payload */
\r
1072 nWords = nStrWords + nArgs;
\r
1074 if (nWords > 15) /* if attempting to store more than 60 byte (= max) */
\r
1076 /* Truncate event if too large. The string characters are stored
\r
1077 last, so usually only the string is truncated, unless there a lot
\r
1078 of parameters... */
\r
1080 /* Diagnostics ... */
\r
1081 uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;
\r
1083 if (bytesTruncated > MaxBytesTruncated)
\r
1085 MaxBytesTruncated = bytesTruncated;
\r
1089 len = 15 * 4 - offset;
\r
1092 TRACE_ENTER_CRITICAL_SECTION();
\r
1094 if (RecorderEnabled)
\r
1096 int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);
\r
1101 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1102 if (event != NULL)
\r
1106 event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);
\r
1107 event->base.EventCount = (uint16_t)eventCounter;
\r
1108 event->base.TS = prvGetTimestamp32();
\r
1110 /* 32-bit write-pointer for the data argument */
\r
1111 data32 = (uint32_t*) &(event->data[0]);
\r
1113 for (i = 0; i < nArgs; i++)
\r
1115 if ((userEvtChannel != NULL) && (i == 0))
\r
1117 /* First, add the User Event Channel if not NULL */
\r
1118 data32[i] = (uint32_t)userEvtChannel;
\r
1122 /* Add data arguments... */
\r
1123 data32[i] = va_arg(*vl, uint32_t);
\r
1126 data8 = (uint8_t*)&(event->data[0]);
\r
1127 for (i = 0; i < len; i++)
\r
1129 data8[offset + i] = str[i];
\r
1132 if (len < (15 * 4 - offset))
\r
1133 data8[offset + len] = 0; /* Only truncate if we don't fill up the buffer completely */
\r
1134 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1139 TRACE_EXIT_CRITICAL_SECTION();
\r
1142 /* Internal common function for storing string events without additional arguments */
\r
1143 static void prvTraceStoreSimpleStringEventHelper( traceString userEvtChannel,
\r
1152 uint16_t eventID = PSF_EVENT_USER_EVENT;
\r
1153 TRACE_ALLOC_CRITICAL_SECTION();
\r
1155 PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);
\r
1157 for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */
\r
1159 /* The string length in multiples of 32 bit words (+1 for null character) */
\r
1160 nStrWords = (len+1+3)/4;
\r
1162 /* If a user event channel is specified, add in the list */
\r
1163 if (userEvtChannel)
\r
1169 offset = nArgs * 4;
\r
1171 /* The total number of 32-bit words needed for the whole payload */
\r
1172 nWords = nStrWords + nArgs;
\r
1174 if (nWords > 15) /* if attempting to store more than 60 byte (= max) */
\r
1176 /* Truncate event if too large. The string characters are stored
\r
1177 last, so usually only the string is truncated, unless there a lot
\r
1178 of parameters... */
\r
1180 /* Diagnostics ... */
\r
1181 uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;
\r
1183 if (bytesTruncated > MaxBytesTruncated)
\r
1185 MaxBytesTruncated = bytesTruncated;
\r
1189 len = 15 * 4 - offset;
\r
1192 TRACE_ENTER_CRITICAL_SECTION();
\r
1194 if (RecorderEnabled)
\r
1196 int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);
\r
1201 TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);
\r
1202 if (event != NULL)
\r
1206 event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);
\r
1207 event->base.EventCount = (uint16_t)eventCounter;
\r
1208 event->base.TS = prvGetTimestamp32();
\r
1210 /* 32-bit write-pointer for the data argument */
\r
1211 data32 = (uint32_t*) &(event->data[0]);
\r
1213 if (userEvtChannel != NULL)
\r
1215 /* First, add the User Event Channel if not NULL */
\r
1216 data32[0] = (uint32_t)userEvtChannel;
\r
1219 data8 = (uint8_t*) &(event->data[0]);
\r
1220 for (i = 0; i < len; i++)
\r
1222 data8[offset + i] = str[i];
\r
1225 if (len < (15 * 4 - offset))
\r
1226 data8[offset + len] = 0; /* Only truncate if we don't fill up the buffer completely */
\r
1227 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);
\r
1232 TRACE_EXIT_CRITICAL_SECTION();
\r
1235 /* Saves a symbol name (task name etc.) in symbol table */
\r
1236 void prvTraceSaveSymbol(const void *address, const char *name)
\r
1239 uint32_t foundSlot;
\r
1240 uint32_t *ptrAddress;
\r
1241 uint8_t *ptrSymbol;
\r
1242 TRACE_ALLOC_CRITICAL_SECTION();
\r
1244 TRACE_ENTER_CRITICAL_SECTION();
\r
1246 foundSlot = firstFreeSymbolTableIndex;
\r
1248 /* First look for previous entries using this address */
\r
1249 for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)
\r
1251 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1252 ptrAddress = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];
\r
1253 if (*ptrAddress == (uint32_t)address)
\r
1260 if (foundSlot < SYMBOL_TABLE_BUFFER_SIZE)
\r
1262 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1263 symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;
\r
1265 /* We access the symbol table via the union member pSymbolTableBufferUINT8 to avoid strict-aliasing issues */
\r
1266 ptrSymbol = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT8[foundSlot + sizeof(uint32_t)];
\r
1267 for (i = 0; i < (TRC_CFG_SYMBOL_MAX_LENGTH); i++)
\r
1269 ptrSymbol[i] = (uint8_t)name[i]; /* We do this first to ensure we also get the 0 termination, if there is one */
\r
1275 /* Check the length of "name", if longer than SYMBOL_MAX_LENGTH */
\r
1276 while ((name[i] != 0) && i < 128)
\r
1281 /* Remember the longest symbol name, for diagnostic purposes */
\r
1282 if (i > LongestSymbolName)
\r
1284 LongestSymbolName = i;
\r
1287 /* Is this the last entry in the symbol table? */
\r
1288 if (foundSlot == firstFreeSymbolTableIndex)
\r
1290 firstFreeSymbolTableIndex += SYMBOL_TABLE_SLOT_SIZE;
\r
1295 NoRoomForSymbol++;
\r
1298 TRACE_EXIT_CRITICAL_SECTION();
\r
1301 /* Deletes a symbol name (task name etc.) from symbol table */
\r
1302 void prvTraceDeleteSymbol(void *address)
\r
1305 uint32_t *ptr, *lastEntryPtr;
\r
1306 TRACE_ALLOC_CRITICAL_SECTION();
\r
1308 TRACE_ENTER_CRITICAL_SECTION();
\r
1310 for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)
\r
1312 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1313 ptr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];
\r
1314 if (*ptr == (uint32_t)address)
\r
1316 /* See if we have another entry in the table, and that this isn't already the last entry */
\r
1317 if (firstFreeSymbolTableIndex > SYMBOL_TABLE_SLOT_SIZE && i != (firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE))
\r
1319 /* Another entry is available, get pointer to the last one */
\r
1320 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */
\r
1321 lastEntryPtr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[(firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t)];
\r
1323 /* Copy last entry to this position */
\r
1324 for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t); j++)
\r
1326 ptr[j] = lastEntryPtr[j];
\r
1329 /* For good measure we also zero out the original position */
\r
1330 *lastEntryPtr = 0;
\r
1333 *ptr = 0; /* No other entry found, or this is the last entry */
\r
1336 firstFreeSymbolTableIndex -= SYMBOL_TABLE_SLOT_SIZE;
\r
1342 TRACE_EXIT_CRITICAL_SECTION();
\r
1345 /* Saves an object data entry (current task priority) in object data table */
\r
1346 void prvTraceSaveObjectData(const void *address, uint32_t data)
\r
1349 uint32_t foundSlot;
\r
1351 TRACE_ALLOC_CRITICAL_SECTION();
\r
1353 TRACE_ENTER_CRITICAL_SECTION();
\r
1355 foundSlot = firstFreeObjectDataTableIndex;
\r
1357 /* First look for previous entries using this address */
\r
1358 for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)
\r
1360 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1361 ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];
\r
1362 if (*ptr == (uint32_t)address)
\r
1369 if (foundSlot < OBJECT_DATA_TABLE_BUFFER_SIZE)
\r
1371 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1372 objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;
\r
1373 objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t) + 1] = data;
\r
1375 /* Is this the last entry in the object data table? */
\r
1376 if (foundSlot == firstFreeObjectDataTableIndex)
\r
1378 firstFreeObjectDataTableIndex += OBJECT_DATA_SLOT_SIZE;
\r
1383 NoRoomForObjectData++;
\r
1386 TRACE_EXIT_CRITICAL_SECTION();
\r
1389 /* Removes an object data entry (task base priority) from object data table */
\r
1390 void prvTraceDeleteObjectData(void *address)
\r
1393 uint32_t *ptr, *lastEntryPtr;
\r
1394 TRACE_ALLOC_CRITICAL_SECTION();
\r
1396 TRACE_ENTER_CRITICAL_SECTION();
\r
1398 for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)
\r
1400 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1401 ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];
\r
1402 if (*ptr == (uint32_t)address)
\r
1404 /* See if we have another entry in the table, and that this isn't already the last entry */
\r
1405 if (firstFreeObjectDataTableIndex > OBJECT_DATA_SLOT_SIZE && i != (firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE))
\r
1407 /* Another entry is available, get pointer to the last one */
\r
1408 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */
\r
1409 lastEntryPtr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[(firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t)];
\r
1411 /* Copy last entry to this position */
\r
1412 for (j = 0; j < (OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t); j++)
\r
1414 ptr[j] = lastEntryPtr[j];
\r
1417 /* For good measure we also zero out the original position */
\r
1418 *lastEntryPtr = 0;
\r
1421 *ptr = 0; /* No other entry found, or this is the last entry */
\r
1424 firstFreeObjectDataTableIndex -= OBJECT_DATA_SLOT_SIZE;
\r
1430 TRACE_EXIT_CRITICAL_SECTION();
\r
1433 /* Checks if the provided command is a valid command */
\r
1434 int prvIsValidCommand(TracealyzerCommandType* cmd)
\r
1436 uint16_t checksum = (uint16_t)(0xFFFF - ( cmd->cmdCode +
\r
1443 if (cmd->checksumMSB != (unsigned char)(checksum >> 8))
\r
1446 if (cmd->checksumLSB != (unsigned char)(checksum & 0xFF))
\r
1449 if (cmd->cmdCode > CMD_LAST_COMMAND)
\r
1455 /* Executed the received command (Start or Stop) */
\r
1456 void prvProcessCommand(TracealyzerCommandType* cmd)
\r
1458 switch(cmd->cmdCode)
\r
1460 case CMD_SET_ACTIVE:
\r
1461 prvSetRecorderEnabled(cmd->param1);
\r
1468 /* Called on critical errors in the recorder. Stops the recorder! */
\r
1469 void prvTraceError(int errCode)
\r
1473 errorCode = errCode;
\r
1474 prvTraceStoreWarnings();
\r
1475 vTracePrintF(trcWarningChannel, "Error detected. Stopped recorder.");
\r
1477 prvSetRecorderEnabled(0);
\r
1481 /* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */
\r
1482 #ifndef TRC_CFG_ARM_CM_USE_SYSTICK
\r
1483 #if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03)))
\r
1485 void prvTraceInitCortexM()
\r
1487 /* Make sure the DWT registers are unlocked, in case the debugger doesn't do this. */
\r
1488 TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK;
\r
1490 /* Make sure DWT is enabled is enabled, if supported */
\r
1491 TRC_REG_DEMCR |= TRC_DEMCR_TRCENA;
\r
1495 /* Verify that DWT is supported */
\r
1496 if (TRC_REG_DEMCR == 0)
\r
1498 /* This function is called on Cortex-M3, M4 and M7 devices to initialize
\r
1499 the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
\r
1501 If the below error is produced, the DWT unit does not seem to be available.
\r
1503 In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
\r
1504 to use SysTick timestamping instead, or define your own timestamping by
\r
1505 setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
\r
1506 and make the necessary definitions, as explained in trcHardwarePort.h.*/
\r
1508 prvTraceError(PSF_ERROR_DWT_NOT_SUPPORTED);
\r
1512 /* Verify that DWT_CYCCNT is supported */
\r
1513 if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT)
\r
1515 /* This function is called on Cortex-M3, M4 and M7 devices to initialize
\r
1516 the DWT unit, assumed present. The DWT cycle counter is used for timestamping.
\r
1518 If the below error is produced, the cycle counter does not seem to be available.
\r
1520 In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build
\r
1521 to use SysTick timestamping instead, or define your own timestamping by
\r
1522 setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED
\r
1523 and make the necessary definitions, as explained in trcHardwarePort.h.*/
\r
1525 prvTraceError(PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED);
\r
1529 /* Reset the cycle counter */
\r
1530 TRC_REG_DWT_CYCCNT = 0;
\r
1532 /* Enable the cycle counter */
\r
1533 TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA;
\r
1535 } while(0); /* breaks above jump here */
\r
1540 /* Performs timestamping using definitions in trcHardwarePort.h */
\r
1541 static uint32_t prvGetTimestamp32(void)
\r
1543 #if ((TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR) || (TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR))
\r
1544 return TRC_HWTC_COUNT;
\r
1547 #if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR))
\r
1548 return TRC_HWTC_COUNT;
\r
1551 #if ((TRC_HWTC_TYPE == TRC_OS_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR))
\r
1552 uint32_t ticks = TRACE_GET_OS_TICKS();
\r
1553 return (TRC_HWTC_COUNT & 0x00FFFFFFU) + ((ticks & 0x000000FFU) << 24);
\r
1557 /* Store the Timestamp Config event */
\r
1558 static void prvTraceStoreTSConfig(void)
\r
1560 /* If not overridden using vTraceSetFrequency, use default value */
\r
1561 if (timestampFrequency == 0)
\r
1563 timestampFrequency = TRC_HWTC_FREQ_HZ;
\r
1566 if (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR || TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR)
\r
1568 prvTraceStoreEvent(5,
\r
1569 PSF_EVENT_TS_CONFIG,
\r
1570 (uint32_t)timestampFrequency,
\r
1571 (uint32_t)TRACE_TICK_RATE_HZ,
\r
1572 (uint32_t)TRC_HWTC_TYPE,
\r
1573 (uint32_t)TRC_CFG_ISR_TAILCHAINING_THRESHOLD,
\r
1574 (uint32_t)TRC_HWTC_PERIOD);
\r
1578 prvTraceStoreEvent(4,
\r
1579 PSF_EVENT_TS_CONFIG,
\r
1580 (uint32_t)timestampFrequency,
\r
1581 (uint32_t)TRACE_TICK_RATE_HZ,
\r
1582 (uint32_t)TRC_HWTC_TYPE,
\r
1583 (uint32_t)TRC_CFG_ISR_TAILCHAINING_THRESHOLD);
\r
1587 /* Retrieve a buffer page to write to. */
\r
1588 static int prvAllocateBufferPage(int prevPage)
\r
1593 index = (prevPage + 1) % TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT;
\r
1595 while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT))
\r
1597 index = (index + 1) % TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT;
\r
1600 if (PageInfo[index].Status == PAGE_STATUS_FREE)
\r
1608 /* Mark the page read as complete. */
\r
1609 static void prvPageReadComplete(int pageIndex)
\r
1611 TRACE_ALLOC_CRITICAL_SECTION();
\r
1613 TRACE_ENTER_CRITICAL_SECTION();
\r
1614 PageInfo[pageIndex].BytesRemaining = TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
1615 PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE];
\r
1616 PageInfo[pageIndex].Status = PAGE_STATUS_FREE;
\r
1618 TotalBytesRemaining += TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
1620 TRACE_EXIT_CRITICAL_SECTION();
\r
1623 /* Get the current buffer page index and remaining number of bytes. */
\r
1624 static int prvGetBufferPage(int32_t* bytesUsed)
\r
1626 static int8_t lastPage = -1;
\r
1628 int8_t index = (int8_t) ((lastPage + 1) % TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);
\r
1630 while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT))
\r
1632 index = (int8_t)((index + 1) % TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);
\r
1635 if (PageInfo[index].Status == PAGE_STATUS_READ)
\r
1637 *bytesUsed = TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE - PageInfo[index].BytesRemaining;
\r
1647 /*******************************************************************************
\r
1649 int32_t prvPagedEventBufferTransfer(int32_t (*writeFunc)(void* data,
\r
1651 int32_t* nofBytes)
\r
1653 Transfers one block of trace data, if available for reading. Returns the number
\r
1654 of bytes transfered, or a negative error code. If data was transferred (return
\r
1655 value > 0), it can be good to call this function again until all data available
\r
1656 has been transfered.
\r
1658 This function is intended to be called by a periodic task with a suitable
\r
1659 delay (e.g. 10-100 ms).
\r
1661 Return value: as returned from writeFunc (0 == OK)
\r
1666 Function pointer (example: int32_t write(void* data, uint32_t size))
\r
1667 The function passed as writeFunc should write "size" bytes from "data" to the
\r
1668 socket/file/channel, and return a status code where 0 means OK,
\r
1669 and any other non-zero value means an error.
\r
1671 - int32_t* nofBytes
\r
1672 Pointer to an integer assigned the number of bytes that was transfered.
\r
1674 *******************************************************************************/
\r
1675 int32_t prvPagedEventBufferTransfer(int32_t (*writeFunc)(void* data, uint32_t size, int32_t* ptrBytesWritten), int32_t* nofBytes)
\r
1677 int8_t pageToTransfer = -1;
\r
1678 int32_t transferred = 0;
\r
1681 pageToTransfer = (int8_t)prvGetBufferPage(nofBytes);
\r
1682 size = *nofBytes; // The number of bytes we want to transfer
\r
1683 transferred = 0; // The number of bytes we have transferred so far
\r
1685 if (pageToTransfer > -1)
\r
1687 while (1) // Keep going until we have transferred all that we intended to
\r
1689 if (writeFunc(&EventBuffer[pageToTransfer * TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE + transferred], (uint32_t)(size - transferred), nofBytes) == 0)
\r
1691 // Write was successful. Update the number of transferred bytes.
\r
1692 transferred += *nofBytes;
\r
1693 if (size == transferred)
\r
1695 // All bytes have been transferred. Mark as Complete and return.
\r
1696 *nofBytes = transferred;
\r
1697 prvPageReadComplete(pageToTransfer);
\r
1711 /*******************************************************************************
\r
1713 void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)
\r
1715 Returns a pointer to an available location in the buffer able to store the
\r
1718 Return value: The pointer.
\r
1723 The size of the event that is to be placed in the buffer.
\r
1725 *******************************************************************************/
\r
1726 void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)
\r
1729 static int currentWritePage = -1;
\r
1731 if (currentWritePage == -1)
\r
1733 currentWritePage = prvAllocateBufferPage(currentWritePage);
\r
1734 if (currentWritePage == -1)
\r
1736 DroppedEventCounter++;
\r
1741 if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0)
\r
1743 PageInfo[currentWritePage].Status = PAGE_STATUS_READ;
\r
1745 TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes
\r
1747 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
\r
1748 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
\r
1750 currentWritePage = prvAllocateBufferPage(currentWritePage);
\r
1751 if (currentWritePage == -1)
\r
1753 DroppedEventCounter++;
\r
1757 ret = PageInfo[currentWritePage].WritePointer;
\r
1758 PageInfo[currentWritePage].WritePointer += sizeOfEvent;
\r
1759 PageInfo[currentWritePage].BytesRemaining = (uint16_t)(PageInfo[currentWritePage].BytesRemaining -sizeOfEvent);
\r
1761 TotalBytesRemaining = (TotalBytesRemaining-(uint16_t)sizeOfEvent);
\r
1763 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)
\r
1764 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;
\r
1769 /*******************************************************************************
\r
1771 void prvPagedEventBufferInit(char* buffer)
\r
1773 Assigns the buffer to use and initializes the PageInfo structure.
\r
1775 Return value: void
\r
1780 Pointer to the buffer location that is dynamically or statically allocated by
\r
1783 *******************************************************************************/
\r
1784 void prvPagedEventBufferInit(char* buffer)
\r
1787 TRACE_ALLOC_CRITICAL_SECTION();
\r
1789 EventBuffer = buffer;
\r
1791 TRACE_ENTER_CRITICAL_SECTION();
\r
1792 for (i = 0; i < TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT; i++)
\r
1794 PageInfo[i].BytesRemaining = TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE;
\r
1795 PageInfo[i].WritePointer = &EventBuffer[i * TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE];
\r
1796 PageInfo[i].Status = PAGE_STATUS_FREE;
\r
1798 TRACE_EXIT_CRITICAL_SECTION();
\r
1801 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/
\r
1803 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/
\r