]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcStreamingRecorder.c
Update trace recorder code to the latest.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-Trace / trcStreamingRecorder.c
1 /*******************************************************************************\r
2  * Trace Recorder Library for Tracealyzer v4.1.5\r
3  * Percepio AB, www.percepio.com\r
4  *\r
5  * trcStreamingRecorder.c\r
6  *\r
7  * The generic core of the trace recorder's streaming mode.\r
8  *\r
9  * Terms of Use\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
23  *\r
24  * Disclaimer\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
38  *\r
39  * Tabs are used for indent in this file (1 tab = 4 spaces)\r
40  *\r
41  * Copyright Percepio AB, 2018.\r
42  * www.percepio.com\r
43  ******************************************************************************/\r
44 \r
45 #include "trcRecorder.h"\r
46 \r
47 #if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)\r
48 \r
49 #if (TRC_USE_TRACEALYZER_RECORDER == 1)\r
50 \r
51 #include <stdio.h>\r
52 #include <stdarg.h>\r
53 \r
54 typedef struct{\r
55         uint16_t EventID;\r
56         uint16_t EventCount;\r
57         uint32_t TS;\r
58 } BaseEvent;\r
59 \r
60 typedef struct{\r
61   BaseEvent base;\r
62   uint32_t param1;\r
63 } EventWithParam_1;\r
64 \r
65 typedef struct{\r
66   BaseEvent base;\r
67   uint32_t param1;\r
68   uint32_t param2;\r
69 } EventWithParam_2;\r
70 \r
71 typedef struct{\r
72   BaseEvent base;\r
73   uint32_t param1;\r
74   uint32_t param2;\r
75   uint32_t param3;\r
76 } EventWithParam_3;\r
77 \r
78 /* Used in event functions with variable number of parameters. */\r
79 typedef struct\r
80 {\r
81   BaseEvent base;\r
82   uint32_t data[15]; /* maximum payload size */\r
83 } largestEventType;\r
84 \r
85 typedef struct{\r
86   uint32_t psf;\r
87   uint16_t version;\r
88   uint16_t platform;\r
89   uint32_t options;\r
90   uint16_t symbolSize;\r
91   uint16_t symbolCount;\r
92   uint16_t objectDataSize;\r
93   uint16_t objectDataCount;\r
94 } PSFHeaderInfo;\r
95 \r
96 \r
97 /* The size of each slot in the Symbol Table */\r
98 #define SYMBOL_TABLE_SLOT_SIZE (sizeof(uint32_t) + (((TRC_CFG_SYMBOL_MAX_LENGTH)+(sizeof(uint32_t)-1))/sizeof(uint32_t))*sizeof(uint32_t))\r
99 \r
100 #define OBJECT_DATA_SLOT_SIZE (sizeof(uint32_t) + sizeof(uint32_t))\r
101 \r
102 /* The total size of the Symbol Table */\r
103 #define SYMBOL_TABLE_BUFFER_SIZE ((TRC_CFG_SYMBOL_TABLE_SLOTS) * SYMBOL_TABLE_SLOT_SIZE)\r
104 \r
105 /* The total size of the Object Data Table */\r
106 #define OBJECT_DATA_TABLE_BUFFER_SIZE ((TRC_CFG_OBJECT_DATA_SLOTS) * OBJECT_DATA_SLOT_SIZE)\r
107 \r
108 /* The Symbol Table type - just a byte array */\r
109 typedef struct{\r
110   union\r
111   {\r
112     uint32_t pSymbolTableBufferUINT32[SYMBOL_TABLE_BUFFER_SIZE / sizeof(uint32_t)];\r
113     uint8_t pSymbolTableBufferUINT8[SYMBOL_TABLE_BUFFER_SIZE];\r
114   } SymbolTableBuffer;\r
115 } SymbolTable;\r
116 \r
117 /* The Object Data Table type - just a byte array */\r
118 typedef struct{\r
119   union\r
120   {\r
121     uint32_t pObjectDataTableBufferUINT32[OBJECT_DATA_TABLE_BUFFER_SIZE / sizeof(uint32_t)];\r
122     uint8_t pObjectDataTableBufferUINT8[OBJECT_DATA_TABLE_BUFFER_SIZE];\r
123   } ObjectDataTableBuffer;\r
124 } ObjectDataTable;\r
125 \r
126 typedef struct{\r
127         uint16_t Status;  /* 16 bit to avoid implicit padding (warnings) */\r
128         uint16_t BytesRemaining;\r
129         char* WritePointer;\r
130 } PageType;\r
131 \r
132 /* Code used for "task address" when no task has started. (NULL = idle task) */\r
133 #define HANDLE_NO_TASK 2\r
134 \r
135 #define PAGE_STATUS_FREE 0\r
136 #define PAGE_STATUS_WRITE 1\r
137 #define PAGE_STATUS_READ 2\r
138 \r
139 #define PSF_ASSERT(_assert, _err) if (! (_assert)){ prvTraceError(_err); return; }\r
140 \r
141 /* Part of the PSF format - encodes the number of 32-bit params in an event */\r
142 #define PARAM_COUNT(n) ((n & 0xF) << 12)\r
143 \r
144 /* The Symbol Table instance - keeps names of tasks and other named objects. */\r
145 static SymbolTable symbolTable = { { { 0 } } };\r
146 \r
147 /* This points to the first unused entry in the symbol table. */\r
148 static uint32_t firstFreeSymbolTableIndex = 0;\r
149 \r
150 /* The Object Data Table instance - keeps initial priorities of tasks. */\r
151 static ObjectDataTable objectDataTable = { { { 0 } } };\r
152 \r
153 /* This points to the first unused entry in the object data table. */\r
154 static uint32_t firstFreeObjectDataTableIndex = 0;\r
155 \r
156 /* Keeps track of ISR nesting */\r
157 static uint32_t ISR_stack[TRC_CFG_MAX_ISR_NESTING];\r
158 \r
159 /* Keeps track of ISR nesting */\r
160 static int8_t ISR_stack_index = -1;\r
161 \r
162 /* Any error that occurred in the recorder (also creates User Event) */\r
163 static int errorCode = 0;\r
164 \r
165 /* Counts the number of trace sessions (not yet used) */\r
166 static uint32_t SessionCounter = 0u;\r
167 \r
168 /* Master switch for recording (0 => Disabled, 1 => Enabled) */\r
169 uint32_t RecorderEnabled = 0u;\r
170 \r
171 /* Used to determine endian of data (big/little) */\r
172 static uint32_t PSFEndianessIdentifier = 0x50534600;\r
173 \r
174 /* Used to interpret the data format */\r
175 static uint16_t FormatVersion = 0x0004;\r
176 \r
177 /* The number of events stored. Used as event sequence number. */\r
178 static uint32_t eventCounter = 0;\r
179 \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
183 \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
189 \r
190 PageType PageInfo[TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT];\r
191 \r
192 char* EventBuffer = NULL;\r
193 \r
194 /*******************************************************************************\r
195  * NoRoomForSymbol\r
196  *\r
197  * Incremented on prvTraceSaveSymbol if no room for saving the symbol name. This\r
198  * is used for storing the names of:\r
199  * - Tasks\r
200  * - Named ISRs (xTraceSetISRProperties)\r
201  * - Named kernel objects (vTraceStoreKernelObjectName)\r
202  * - User event channels (xTraceRegisterString)\r
203  *\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
208 \r
209 /*******************************************************************************\r
210  * NoRoomForObjectData\r
211  *\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
215  *\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
220 \r
221 /*******************************************************************************\r
222  * LongestSymbolName\r
223  *\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
229 \r
230 /*******************************************************************************\r
231  * MaxBytesTruncated\r
232  *\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
240 \r
241 uint16_t CurrentFilterMask = 0xFFFF;\r
242 \r
243 uint16_t CurrentFilterGroup = FilterGroup0;\r
244 \r
245 /* Internal common function for storing string events */\r
246 static void prvTraceStoreStringEventHelper(     int nArgs,\r
247                                                                                 uint16_t eventID,\r
248                                                                                 traceString userEvtChannel,\r
249                                                                                 int len,\r
250                                                                                 const char* str,\r
251                                                                                 va_list* vl);\r
252 \r
253 /* Not static to avoid warnings from SysGCC/PPC */ \r
254 void prvTraceStoreSimpleStringEventHelper(traceString userEvtChannel,\r
255                                                                                                 const char* str);\r
256 \r
257                                                                                 \r
258 /* Stores the header information on Start */\r
259 static void prvTraceStoreHeader(void);\r
260 \r
261 /* Stores the symbol table on Start */\r
262 static void prvTraceStoreSymbolTable(void);\r
263 \r
264 /* Stores the object table on Start */\r
265 static void prvTraceStoreObjectDataTable(void);\r
266 \r
267 /* Store the Timestamp Config on Start */\r
268 static void prvTraceStoreTSConfig(void);\r
269 \r
270 /* Store the current warnings */\r
271 static void prvTraceStoreWarnings(void);\r
272 \r
273 /* Internal function for starting/stopping the recorder. */\r
274 static void prvSetRecorderEnabled(uint32_t isEnabled);\r
275 \r
276 /* Mark the page read as complete. */\r
277 static void prvPageReadComplete(int pageIndex);\r
278 \r
279 /* Retrieve a buffer page to write to. */\r
280 static int prvAllocateBufferPage(int prevPage);\r
281 \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
285 \r
286 /* Performs timestamping using definitions in trcHardwarePort.h */\r
287 static uint32_t prvGetTimestamp32(void);\r
288 \r
289 /* Signal an error. */\r
290 void prvTraceError(int errCode);\r
291 \r
292 /* Signal an warning (does not stop the recorder). */\r
293 void prvTraceWarning(int errCode);\r
294 \r
295 /******************************************************************************\r
296  * vTraceInstanceFinishedNow\r
297  *\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
303 {\r
304         prvTraceStoreEvent0(PSF_EVENT_IFE_DIRECT);\r
305 }\r
306 \r
307 /******************************************************************************\r
308  * vTraceInstanceFinishedNext\r
309  *\r
310  * Marks the current "task instance" as finished on the next kernel call.\r
311  *\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
319 {\r
320         prvTraceStoreEvent0(PSF_EVENT_IFE_NEXT);\r
321 }\r
322 \r
323 /*******************************************************************************\r
324  * vTraceStoreKernelObjectName\r
325  *\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
328  *\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
332 {\r
333         /* Always save in symbol table, if the recording has not yet started */\r
334         prvTraceSaveSymbol(object, name);\r
335 \r
336         prvTraceStoreStringEvent(1, PSF_EVENT_OBJ_NAME, name, (uint32_t)object);\r
337 }\r
338 \r
339 \r
340 /******************************************************************************\r
341 * vTraceSetFrequency\r
342 *\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
346 *\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
351 {\r
352         timestampFrequency = frequency;\r
353 }\r
354 \r
355 #if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)\r
356 \r
357 /*******************************************************************************\r
358 * xTraceRegisterString\r
359 *\r
360 * Stores a name for a user event channel, returns the handle.\r
361 ******************************************************************************/\r
362 traceString xTraceRegisterString(const char* name)\r
363 {\r
364         prvTraceSaveSymbol((const void*)name, name);\r
365 \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
368 \r
369         return (traceString)name;\r
370 }\r
371 \r
372 /******************************************************************************\r
373  * vTracePrint\r
374  *\r
375  * Generates "User Events", with unformatted text.\r
376  *\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
379  *\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
383  *\r
384  *  "[MyChannel] Hello World!"\r
385  *\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
389  *\r
390  * Example:\r
391  *\r
392  *       traceString chn = xTraceRegisterString("MyChannel");\r
393  *       ...\r
394  *       vTracePrint(chn, "Hello World!");\r
395  *\r
396  ******************************************************************************/\r
397 void vTracePrint(traceString chn, const char* str)\r
398 {\r
399         prvTraceStoreSimpleStringEventHelper(chn, str);\r
400 }\r
401 \r
402 \r
403 /*******************************************************************************\r
404 * vTraceConsoleChannelPrintF\r
405 *\r
406 * Wrapper for vTracePrint, using the default channel. Can be used as a drop-in\r
407 * replacement for printf and similar functions, e.g. in a debug logging macro.\r
408 *\r
409 * Example:\r
410 *\r
411 *        // Old: #define LogString debug_console_printf\r
412 *\r
413 *    // New, log to Tracealyzer instead:\r
414 *        #define LogString vTraceConsoleChannelPrintF\r
415 *        ...\r
416 *        LogString("My value is: %d", myValue);\r
417 ******************************************************************************/\r
418 void vTraceConsoleChannelPrintF(const char* fmt, ...)\r
419 {\r
420                 va_list vl;\r
421                 char tempBuf[60];\r
422                 static traceString consoleChannel = NULL;\r
423 \r
424                 if (consoleChannel == NULL)\r
425                         consoleChannel = xTraceRegisterString("Debug Console");\r
426 \r
427                 va_start(vl, fmt);\r
428                 vsnprintf(tempBuf, 60, fmt, vl);\r
429                 vTracePrint(consoleChannel, tempBuf);\r
430                 va_end(vl);\r
431 }\r
432 \r
433 /******************************************************************************\r
434  * vTracePrintF\r
435  *\r
436  * Generates "User Events", with formatted text and data, similar to a "printf".\r
437  * It is very fast since the actual formatting is done on the host side when the\r
438  * trace is displayed.\r
439  *\r
440  * User Events can be used for very efficient application logging, and are shown\r
441  * as yellow labels in the main trace view.\r
442  * An advantage of User Events is that data can be plotted in the "User Event\r
443  * Signal Plot" view, visualizing any data you log as User Events, discrete\r
444  * states or control system signals (e.g. system inputs or outputs).\r
445  *\r
446  * You may group User Events into User Event Channels. The yellow User Event \r
447  * labels show the logged string, preceded by the channel name within brackets.\r
448  * \r
449  * Example:\r
450  *\r
451  *  "[MyChannel] Hello World!"\r
452  *\r
453  * The User Event Channels are shown in the View Filter, which makes it easy to\r
454  * select what User Events you wish to display. User Event Channels are created\r
455  * using xTraceRegisterString().\r
456  *\r
457  * Example:\r
458  *\r
459  *       traceString adc_uechannel = xTraceRegisterString("ADC User Events");\r
460  *       ...\r
461  *       vTracePrintF(adc_uechannel,\r
462  *                               "ADC channel %d: %d volts",\r
463  *                               ch, adc_reading);\r
464  *\r
465  * All data arguments are assumed to be 32 bit wide. The following formats are\r
466  * supported:\r
467  * %d - signed integer. The following width and padding format is supported: "%05d" -> "-0042" and "%5d" -> "  -42"\r
468  * %u - unsigned integer. The following width and padding format is supported: "%05u" -> "00042" and "%5u" -> "   42"\r
469  * %X - hexadecimal (uppercase). The following width and padding format is supported: "%04X" -> "002A" and "%4X" -> "  2A"\r
470  * %x - hexadecimal (lowercase). The following width and padding format is supported: "%04x" -> "002a" and "%4x" -> "  2a"\r
471  * %s - string (currently, this must be an earlier stored symbol name)\r
472  *\r
473  * Up to 15 data arguments are allowed, with a total size of maximum 60 byte\r
474  * including 8 byte for the base event fields and the format string. So with\r
475  * one data argument, the maximum string length is 48 chars. If this is exceeded\r
476  * the string is truncated (4 bytes at a time).\r
477  *\r
478  ******************************************************************************/\r
479 void vTracePrintF(traceString chn, const char* fmt, ...)\r
480 {\r
481         va_list vl;\r
482         int i = 0;\r
483 \r
484         int nArgs = 0;\r
485 \r
486         /* Count the number of arguments in the format string (e.g., %d) */\r
487         for (i = 0; (fmt[i] != 0) && (i < 52); i++)\r
488         {\r
489                 if (fmt[i] == '%')\r
490                 {\r
491                         if (fmt[i + 1] != 0 && fmt[i + 1] != '%')\r
492                         {\r
493                                 nArgs++;        /* Found an argument */\r
494                         }\r
495                         \r
496                         i++;      /* Move past format specifier or non-argument '%' */\r
497                 }\r
498         }\r
499 \r
500         va_start(vl, fmt);\r
501         \r
502         if (chn != NULL)\r
503         {\r
504                 prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs + 1), chn, i, fmt, &vl);\r
505         }\r
506         else\r
507         {\r
508                 prvTraceStoreStringEventHelper(nArgs, (uint16_t)(PSF_EVENT_USER_EVENT + nArgs), chn, i, fmt, &vl);\r
509         }\r
510         va_end(vl);\r
511 }\r
512 #endif /* (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) */\r
513 \r
514 /*******************************************************************************\r
515  * xTraceSetISRProperties\r
516  *\r
517  * Stores a name and priority level for an Interrupt Service Routine, to allow\r
518  * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin. \r
519  *\r
520  * Example:\r
521  *       #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt\r
522  *       ...\r
523  *       traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);\r
524  *       ...\r
525  *       void ISR_handler()\r
526  *       {\r
527  *               vTraceStoreISRBegin(Timer1Handle);\r
528  *               ...\r
529  *               vTraceStoreISREnd(0);\r
530  *       }\r
531  *\r
532  ******************************************************************************/\r
533 traceHandle xTraceSetISRProperties(const char* name, uint8_t priority)\r
534 {\r
535         /* Save object data in object data table */\r
536         prvTraceSaveObjectData((const void*)name, priority);\r
537         \r
538         /* Note: "name" is used both as a string argument, and the address as ID */\r
539         prvTraceStoreStringEvent(2, PSF_EVENT_DEFINE_ISR, name, name, priority);\r
540         \r
541         /* Always save in symbol table, if the recording has not yet started */\r
542         prvTraceSaveSymbol((const void*)name, name);\r
543         \r
544         return (traceHandle)name;\r
545 }\r
546 \r
547 /*******************************************************************************\r
548  * vTraceStoreISRBegin\r
549  *\r
550  * Registers the beginning of an Interrupt Service Routine, using a traceHandle\r
551  * provided by xTraceSetISRProperties.\r
552  *\r
553  * Example:\r
554  *       #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt\r
555  *       ...\r
556  *       traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);\r
557  *       ...\r
558  *       void ISR_handler()\r
559  *       {\r
560  *               vTraceStoreISRBegin(Timer1Handle);\r
561  *               ...\r
562  *               vTraceStoreISREnd(0);\r
563  *       }\r
564  *\r
565  ******************************************************************************/\r
566 void vTraceStoreISRBegin(traceHandle handle)\r
567 {\r
568         TRACE_ALLOC_CRITICAL_SECTION();\r
569 \r
570         TRACE_ENTER_CRITICAL_SECTION();\r
571 \r
572         /* We are at the start of a possible ISR chain. \r
573         No context switches should have been triggered now. */\r
574         if (ISR_stack_index == -1)\r
575                 isPendingContextSwitch = 0; \r
576         \r
577         if (ISR_stack_index < (TRC_CFG_MAX_ISR_NESTING) - 1)\r
578         {\r
579                 ISR_stack_index++;\r
580                 ISR_stack[ISR_stack_index] = (uint32_t)handle;\r
581 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)\r
582                 prvTraceStoreEvent1(PSF_EVENT_ISR_BEGIN, (uint32_t)handle);\r
583 #endif\r
584                 TRACE_EXIT_CRITICAL_SECTION();\r
585         }\r
586         else\r
587         {\r
588                 TRACE_EXIT_CRITICAL_SECTION();\r
589                 prvTraceError(PSF_ERROR_ISR_NESTING_OVERFLOW);\r
590         }\r
591 }\r
592 \r
593 /*******************************************************************************\r
594  * vTraceStoreISREnd\r
595  *\r
596  * Registers the end of an Interrupt Service Routine.\r
597  *\r
598  * The parameter pendingISR indicates if the interrupt has requested a\r
599  * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the \r
600  * interrupt is assumed to return to the previous context.\r
601  *\r
602  * Example:\r
603  *       #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt\r
604  *       traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder\r
605  *       ...\r
606  *       traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1);\r
607  *       ...\r
608  *       void ISR_handler()\r
609  *       {\r
610  *               vTraceStoreISRBegin(traceHandleIsrTimer1);\r
611  *               ...\r
612  *               vTraceStoreISREnd(0);\r
613  *       }\r
614  *\r
615  ******************************************************************************/\r
616 void vTraceStoreISREnd(int isTaskSwitchRequired)\r
617 {\r
618         TRACE_ALLOC_CRITICAL_SECTION();\r
619 \r
620         TRACE_ENTER_CRITICAL_SECTION();\r
621         \r
622         (void)ISR_stack;\r
623 \r
624         /* Is there a pending task-switch? (perhaps from an earlier ISR) */\r
625         isPendingContextSwitch |= isTaskSwitchRequired;\r
626 \r
627         if (ISR_stack_index > 0)\r
628         {\r
629                 ISR_stack_index--;\r
630 \r
631 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)\r
632                 /* Store return to interrupted ISR (if nested ISRs)*/\r
633                 prvTraceStoreEvent1(PSF_EVENT_ISR_RESUME, (uint32_t)ISR_stack[ISR_stack_index]);\r
634 #endif\r
635         }\r
636         else\r
637         {\r
638                 ISR_stack_index--;\r
639                 \r
640                 /* Store return to interrupted task, if no context switch will occur in between. */\r
641                 if ((isPendingContextSwitch == 0) || (prvTraceIsSchedulerSuspended()))\r
642                 {\r
643 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)\r
644                         prvTraceStoreEvent1(PSF_EVENT_TS_RESUME, (uint32_t)TRACE_GET_CURRENT_TASK());\r
645 #endif\r
646                 }\r
647         }\r
648 \r
649         TRACE_EXIT_CRITICAL_SECTION();\r
650 }\r
651 \r
652 \r
653 /*******************************************************************************\r
654  * xTraceGetLastError\r
655  *\r
656  * Returns the last error or warning, as a string, or NULL if none.\r
657  *****************************************************************************/\r
658 const char* xTraceGetLastError(void)\r
659 {\r
660         /* Note: the error messages are short, in order to fit in a User Event.\r
661         Instead, the users can read more in the below comments.*/\r
662         \r
663         switch (errorCode)\r
664         {\r
665         \r
666         case PSF_WARNING_SYMBOL_TABLE_SLOTS:\r
667                 /* There was not enough symbol table slots for storing symbol names.\r
668                 The number of missing slots is counted by NoRoomForSymbol. Inspect this\r
669                 variable and increase TRC_CFG_SYMBOL_TABLE_SLOTS by at least that value. */\r
670 \r
671                 return "Exceeded SYMBOL_TABLE_SLOTS (see xTraceGetLastError)";\r
672 \r
673         case PSF_WARNING_SYMBOL_MAX_LENGTH:\r
674                 /* A symbol name exceeded TRC_CFG_SYMBOL_MAX_LENGTH in length.\r
675                 Make sure the symbol names are at most TRC_CFG_SYMBOL_MAX_LENGTH,\r
676                 or inspect LongestSymbolName and increase TRC_CFG_SYMBOL_MAX_LENGTH\r
677                 to at least this value. */\r
678 \r
679                 return "Exceeded SYMBOL_MAX_LENGTH (see xTraceGetLastError)";\r
680 \r
681         case PSF_WARNING_OBJECT_DATA_SLOTS:\r
682                 /* There was not enough symbol object table slots for storing object\r
683                 properties, such as task priorites. The number of missing slots is \r
684                 counted by NoRoomForObjectData. Inspect this variable and increase \r
685                 TRC_CFG_OBJECT_DATA_SLOTS by at least that value. */\r
686                 \r
687                 return "Exceeded OBJECT_DATA_SLOTS (see xTraceGetLastError)";\r
688 \r
689         case PSF_WARNING_STRING_TOO_LONG:\r
690                 /* Some string argument was longer than the maximum payload size\r
691                 and has been truncated by "MaxBytesTruncated" bytes.\r
692 \r
693                 This may happen for the following functions:\r
694                 - vTracePrint\r
695                 - vTracePrintF\r
696                 - vTraceStoreKernelObjectName\r
697                 - xTraceRegisterString\r
698                 - vTraceSetISRProperties\r
699 \r
700                 A PSF event may store maximum 60 bytes payload, including data\r
701                 arguments and string characters. For User Events, also the User\r
702                 Event Channel (4 bytes) must be squeezed in, if a channel is\r
703                 specified (can be NULL). */\r
704 \r
705                 return "String too long (see xTraceGetLastError)";\r
706 \r
707         case PSF_WARNING_STREAM_PORT_READ:\r
708                 /* TRC_STREAM_PORT_READ_DATA is expected to return 0 when completed successfully.\r
709                 This means there is an error in the communication with host/Tracealyzer. */\r
710 \r
711                 return "TRC_STREAM_PORT_READ_DATA returned error (!= 0).";\r
712 \r
713         case PSF_WARNING_STREAM_PORT_WRITE:\r
714                 /* TRC_STREAM_PORT_WRITE_DATA is expected to return 0 when completed successfully.\r
715                 This means there is an error in the communication with host/Tracealyzer. */\r
716 \r
717                 return "TRC_STREAM_PORT_WRITE_DATA returned error (!= 0).";\r
718 \r
719         case PSF_ERROR_EVENT_CODE_TOO_LARGE:\r
720                 /* The highest allowed event code is 4095, anything higher is an unexpected error. \r
721                 Please contact support@percepio.com for assistance.*/\r
722                 \r
723                 return "Invalid event code (see xTraceGetLastError)";\r
724         \r
725         case PSF_ERROR_ISR_NESTING_OVERFLOW:\r
726                 /* Nesting of ISR trace calls exceeded the limit (TRC_CFG_MAX_ISR_NESTING).\r
727                 If this is unlikely, make sure that you call vTraceStoreISRExit in the end \r
728                 of all ISR handlers. Or increase TRC_CFG_MAX_ISR_NESTING. */\r
729 \r
730                 return "Exceeded ISR nesting (see xTraceGetLastError)";\r
731 \r
732         case PSF_ERROR_DWT_NOT_SUPPORTED:\r
733                 /* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.\r
734                 DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M\r
735                 macro normally set by ARM's CMSIS library, since typically available. You can however select\r
736                 SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/\r
737 \r
738                 return "DWT not supported (see xTraceGetLastError)";\r
739 \r
740         case PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED:\r
741                 /* On ARM Cortex-M only - failed to initialize DWT Cycle Counter since not supported by this chip.\r
742                 DWT timestamping is selected automatically for ART Cortex-M3, M4 and higher, based on the __CORTEX_M\r
743                 macro normally set by ARM's CMSIS library, since typically available. You can however select \r
744                 SysTick timestamping instead by defining adding "#define TRC_CFG_ARM_CM_USE_SYSTICK".*/\r
745                 \r
746                 return "DWT_CYCCNT not supported (see xTraceGetLastError)";\r
747         \r
748         case PSF_ERROR_TZCTRLTASK_NOT_CREATED:\r
749                 /* vTraceEnable failed creating the trace control task (TzCtrl) - incorrect parameters (priority?)\r
750                 or insufficient heap size? */\r
751                 return "Could not create TzCtrl (see xTraceGetLastError)";\r
752         \r
753         }\r
754         \r
755         return NULL;\r
756 }\r
757 \r
758 /*******************************************************************************\r
759  * vTraceClearError\r
760  *\r
761  * Clears any errors.\r
762  *****************************************************************************/\r
763 void vTraceClearError(void)\r
764 {\r
765         NoRoomForSymbol = 0;\r
766         LongestSymbolName = 0;\r
767         NoRoomForObjectData = 0;\r
768         MaxBytesTruncated = 0;\r
769         errorCode = PSF_ERROR_NONE;\r
770 }\r
771 \r
772 /*******************************************************************************\r
773  * vTraceStop\r
774  *\r
775  * Stops the tracing.\r
776  *****************************************************************************/\r
777 void vTraceStop(void)\r
778 {\r
779         prvSetRecorderEnabled(0);\r
780 }\r
781 \r
782 /*******************************************************************************\r
783  * vTraceSetRecorderDataBuffer\r
784  *\r
785  * If custom allocation is used, this function must be called so the recorder\r
786  * library knows where to save the trace data.\r
787  ******************************************************************************/\r
788 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)\r
789 \r
790 extern char* _TzTraceData;\r
791 \r
792 void vTraceSetRecorderDataBuffer(void* pRecorderData)\r
793 {\r
794         _TzTraceData = pRecorderData;\r
795 }\r
796 #endif\r
797 \r
798 \r
799 /*******************************************************************************\r
800 * xTraceIsRecordingEnabled\r
801 * Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0.\r
802 ******************************************************************************/\r
803 int xTraceIsRecordingEnabled(void)\r
804 {\r
805         return (int)RecorderEnabled;\r
806 }\r
807 \r
808 void vTraceSetFilterMask(uint16_t filterMask)\r
809 {\r
810         CurrentFilterMask = filterMask;\r
811 }\r
812 \r
813 void vTraceSetFilterGroup(uint16_t filterGroup)\r
814 {\r
815         CurrentFilterGroup = filterGroup;\r
816 }\r
817 \r
818 \r
819 /******************************************************************************/\r
820 /*** INTERNAL FUNCTIONS *******************************************************/\r
821 /******************************************************************************/\r
822 \r
823 /* Internal function for starting/stopping the recorder. */\r
824 static void prvSetRecorderEnabled(uint32_t isEnabled)\r
825 {\r
826         void* currentTask;\r
827         \r
828         TRACE_ALLOC_CRITICAL_SECTION();\r
829         \r
830         if (RecorderEnabled == isEnabled)\r
831         {\r
832                 return;\r
833         }\r
834         \r
835         currentTask = TRACE_GET_CURRENT_TASK();\r
836 \r
837         TRACE_ENTER_CRITICAL_SECTION();\r
838 \r
839     RecorderEnabled = isEnabled;\r
840 \r
841     if (currentTask == NULL)\r
842     {\r
843                 currentTask = (void*)HANDLE_NO_TASK;\r
844         }\r
845 \r
846         if (RecorderEnabled)\r
847         {\r
848                 TRC_STREAM_PORT_ON_TRACE_BEGIN();\r
849 \r
850                 #if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1)\r
851                 prvPagedEventBufferInit(_TzTraceData);\r
852                 #endif\r
853                 \r
854         eventCounter = 0;\r
855         ISR_stack_index = -1;\r
856         prvTraceStoreHeader();\r
857                 prvTraceStoreSymbolTable();\r
858         prvTraceStoreObjectDataTable();\r
859         prvTraceStoreEvent3(    PSF_EVENT_TRACE_START,\r
860                                                         (uint32_t)TRACE_GET_OS_TICKS(),\r
861                                                         (uint32_t)currentTask,\r
862                                                         SessionCounter++);\r
863         prvTraceStoreTSConfig();\r
864                 prvTraceStoreWarnings();\r
865         }\r
866     else\r
867     {\r
868                 TRC_STREAM_PORT_ON_TRACE_END();\r
869     }\r
870 \r
871         TRACE_EXIT_CRITICAL_SECTION();\r
872 }\r
873 \r
874 /* Stores the symbol table on Start */\r
875 static void prvTraceStoreSymbolTable(void)\r
876 {\r
877         uint32_t i = 0;\r
878         uint32_t j = 0;\r
879         TRACE_ALLOC_CRITICAL_SECTION();\r
880 \r
881         TRACE_ENTER_CRITICAL_SECTION();\r
882         \r
883         if (RecorderEnabled)\r
884         {\r
885                 for (i = 0; i < (sizeof(SymbolTable) / sizeof(uint32_t)); i += (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)))\r
886                 {\r
887             TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, SYMBOL_TABLE_SLOT_SIZE);\r
888             if (data != NULL)\r
889             {\r
890                 for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE / sizeof(uint32_t)); j++)\r
891                 {\r
892                         data[j] = symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i+j];\r
893                 }\r
894                             TRC_STREAM_PORT_COMMIT_EVENT(data, SYMBOL_TABLE_SLOT_SIZE);\r
895                         }\r
896                 }\r
897         }\r
898         TRACE_EXIT_CRITICAL_SECTION();\r
899 }\r
900 \r
901 /* Stores the object table on Start */\r
902 static void prvTraceStoreObjectDataTable(void)\r
903 {\r
904         uint32_t i = 0;\r
905         uint32_t j = 0;\r
906         TRACE_ALLOC_CRITICAL_SECTION();\r
907 \r
908         TRACE_ENTER_CRITICAL_SECTION();\r
909 \r
910         if (RecorderEnabled)\r
911         {\r
912                 for (i = 0; i < (sizeof(ObjectDataTable) / sizeof(uint32_t)); i += (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)))\r
913         {\r
914             TRC_STREAM_PORT_ALLOCATE_EVENT(uint32_t, data, OBJECT_DATA_SLOT_SIZE);\r
915             if (data != NULL)\r
916             {\r
917                 for (j = 0; j < (OBJECT_DATA_SLOT_SIZE / sizeof(uint32_t)); j++)\r
918                 {\r
919                         data[j] = objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i+j];\r
920                 }\r
921                 TRC_STREAM_PORT_COMMIT_EVENT(data, OBJECT_DATA_SLOT_SIZE);\r
922                         }\r
923         }\r
924         }\r
925         TRACE_EXIT_CRITICAL_SECTION();\r
926 }\r
927 \r
928 /* Stores the header information on Start */\r
929 static void prvTraceStoreHeader(void)\r
930 {\r
931         TRACE_ALLOC_CRITICAL_SECTION();\r
932 \r
933         TRACE_ENTER_CRITICAL_SECTION();\r
934 \r
935         if (RecorderEnabled)\r
936         {\r
937                 TRC_STREAM_PORT_ALLOCATE_EVENT(PSFHeaderInfo, header, sizeof(PSFHeaderInfo));\r
938                 if (header != NULL)\r
939                 {\r
940                         header->psf = PSFEndianessIdentifier;\r
941                         header->version = FormatVersion;\r
942                         header->platform = TRACE_KERNEL_VERSION;\r
943             header->options = 0;\r
944             /* Lowest bit used for TRC_IRQ_PRIORITY_ORDER */\r
945             header->options = header->options | (TRC_IRQ_PRIORITY_ORDER << 0);\r
946                         header->symbolSize = SYMBOL_TABLE_SLOT_SIZE;\r
947                         header->symbolCount = (TRC_CFG_SYMBOL_TABLE_SLOTS);\r
948                         header->objectDataSize = 8;\r
949                         header->objectDataCount = (TRC_CFG_OBJECT_DATA_SLOTS);\r
950                         TRC_STREAM_PORT_COMMIT_EVENT(header, sizeof(PSFHeaderInfo));\r
951                 }\r
952         }\r
953         TRACE_EXIT_CRITICAL_SECTION();\r
954 }\r
955 \r
956 /* Store the current warnings */\r
957 static void prvTraceStoreWarnings(void)\r
958 {\r
959         if (RecorderEnabled)\r
960         {\r
961                 const char* errStr = xTraceGetLastError();\r
962 \r
963                 if (errStr != NULL)\r
964                 {\r
965                         vTracePrint(trcWarningChannel, errStr);\r
966                 }\r
967         }\r
968 }\r
969 \r
970 /* Store an event with zero parameters (event ID only) */\r
971 void prvTraceStoreEvent0(uint16_t eventID)\r
972 {\r
973         TRACE_ALLOC_CRITICAL_SECTION();\r
974 \r
975         PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);\r
976 \r
977         TRACE_ENTER_CRITICAL_SECTION();\r
978 \r
979         if (RecorderEnabled)\r
980         {\r
981                 eventCounter++;\r
982 \r
983                 {\r
984                         TRC_STREAM_PORT_ALLOCATE_EVENT(BaseEvent, event, sizeof(BaseEvent));\r
985                         if (event != NULL)\r
986                         {\r
987                                 event->EventID = eventID | PARAM_COUNT(0);\r
988                                 event->EventCount = (uint16_t)eventCounter;\r
989                                 event->TS = prvGetTimestamp32();\r
990                                 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(BaseEvent));\r
991                         }\r
992                 }\r
993         }\r
994         TRACE_EXIT_CRITICAL_SECTION();\r
995 }\r
996 \r
997 /* Store an event with one 32-bit parameter (pointer address or an int) */\r
998 void prvTraceStoreEvent1(uint16_t eventID, uint32_t param1)\r
999 {\r
1000         TRACE_ALLOC_CRITICAL_SECTION();\r
1001 \r
1002         PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);\r
1003 \r
1004         TRACE_ENTER_CRITICAL_SECTION();\r
1005 \r
1006         if (RecorderEnabled)\r
1007         {\r
1008                 eventCounter++;\r
1009                 \r
1010                 {\r
1011                         TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_1, event, sizeof(EventWithParam_1));\r
1012                         if (event != NULL)\r
1013                         {\r
1014                                 event->base.EventID = eventID | PARAM_COUNT(1);\r
1015                                 event->base.EventCount = (uint16_t)eventCounter;\r
1016                                 event->base.TS = prvGetTimestamp32();\r
1017                                 event->param1 = (uint32_t)param1;\r
1018                                 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_1));\r
1019                         }\r
1020                 }\r
1021         }\r
1022         TRACE_EXIT_CRITICAL_SECTION();\r
1023 }\r
1024 \r
1025 /* Store an event with two 32-bit parameters */\r
1026 void prvTraceStoreEvent2(uint16_t eventID, uint32_t param1, uint32_t param2)\r
1027 {\r
1028         TRACE_ALLOC_CRITICAL_SECTION();\r
1029 \r
1030         PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);\r
1031 \r
1032         TRACE_ENTER_CRITICAL_SECTION();\r
1033 \r
1034         if (RecorderEnabled)\r
1035         {\r
1036                 eventCounter++;\r
1037 \r
1038                 {\r
1039                         TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_2, event, sizeof(EventWithParam_2));\r
1040                         if (event != NULL)\r
1041                         {\r
1042                                 event->base.EventID = eventID | PARAM_COUNT(2);\r
1043                                 event->base.EventCount = (uint16_t)eventCounter;\r
1044                                 event->base.TS = prvGetTimestamp32();\r
1045                                 event->param1 = (uint32_t)param1;\r
1046                                 event->param2 = param2;\r
1047                                 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_2));\r
1048                         }\r
1049                 }\r
1050         }\r
1051         TRACE_EXIT_CRITICAL_SECTION();\r
1052 }\r
1053 \r
1054 /* Store an event with three 32-bit parameters */\r
1055 void prvTraceStoreEvent3(       uint16_t eventID,\r
1056                                                 uint32_t param1,\r
1057                                                 uint32_t param2,\r
1058                                                 uint32_t param3)\r
1059 {\r
1060         TRACE_ALLOC_CRITICAL_SECTION();\r
1061 \r
1062         PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);\r
1063 \r
1064         TRACE_ENTER_CRITICAL_SECTION();\r
1065 \r
1066         if (RecorderEnabled)\r
1067         {\r
1068                 eventCounter++;\r
1069 \r
1070                 {\r
1071                         TRC_STREAM_PORT_ALLOCATE_EVENT(EventWithParam_3, event, sizeof(EventWithParam_3));\r
1072                         if (event != NULL)\r
1073                         {\r
1074                                 event->base.EventID = eventID | PARAM_COUNT(3);\r
1075                                 event->base.EventCount = (uint16_t)eventCounter;\r
1076                                 event->base.TS = prvGetTimestamp32();\r
1077                                 event->param1 = (uint32_t)param1;\r
1078                                 event->param2 = param2;\r
1079                                 event->param3 = param3;\r
1080                                 TRC_STREAM_PORT_COMMIT_EVENT(event, sizeof(EventWithParam_3));\r
1081                         }\r
1082                 }\r
1083         }\r
1084         TRACE_EXIT_CRITICAL_SECTION();\r
1085 }\r
1086 \r
1087 /* Stores an event with <nParam> 32-bit integer parameters */\r
1088 void prvTraceStoreEvent(int nParam, uint16_t eventID, ...)\r
1089 {\r
1090         va_list vl;\r
1091         int i;\r
1092     TRACE_ALLOC_CRITICAL_SECTION();\r
1093 \r
1094         PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);\r
1095 \r
1096         TRACE_ENTER_CRITICAL_SECTION();\r
1097 \r
1098         if (RecorderEnabled)\r
1099         {\r
1100                 int eventSize = (int)sizeof(BaseEvent) + nParam * (int)sizeof(uint32_t);\r
1101 \r
1102                 eventCounter++;\r
1103 \r
1104                 {\r
1105                         TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);\r
1106                         if (event != NULL)\r
1107                         {\r
1108                                 event->base.EventID = eventID | (uint16_t)PARAM_COUNT(nParam);\r
1109                                 event->base.EventCount = (uint16_t)eventCounter;\r
1110                                 event->base.TS = prvGetTimestamp32();\r
1111 \r
1112                                 va_start(vl, eventID);\r
1113                                 for (i = 0; i < nParam; i++)\r
1114                                 {\r
1115                                         uint32_t* tmp = (uint32_t*) &(event->data[i]);\r
1116                                         *tmp = va_arg(vl, uint32_t);\r
1117                                 }\r
1118                                 va_end(vl);\r
1119 \r
1120                                 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);\r
1121                         }\r
1122                 }\r
1123         }\r
1124         TRACE_EXIT_CRITICAL_SECTION();\r
1125 }\r
1126 \r
1127 /* Stories an event with a string and <nParam> 32-bit integer parameters */\r
1128 void prvTraceStoreStringEvent(int nArgs, uint16_t eventID, const char* str, ...)\r
1129 {\r
1130         int len;\r
1131         va_list vl;\r
1132 \r
1133         for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */\r
1134 \r
1135         va_start(vl, str);\r
1136         prvTraceStoreStringEventHelper(nArgs, eventID, NULL, len, str, &vl);\r
1137         va_end(vl);\r
1138 }\r
1139 \r
1140 /* Internal common function for storing string events */\r
1141 static void prvTraceStoreStringEventHelper(int nArgs,\r
1142                                                                                 uint16_t eventID,\r
1143                                                                                 traceString userEvtChannel,\r
1144                                                                                 int len,\r
1145                                                                                 const char* str,\r
1146                                                                                 va_list* vl)\r
1147 {\r
1148         int nWords;\r
1149         int nStrWords;\r
1150         int i;\r
1151         int offset = 0;\r
1152         TRACE_ALLOC_CRITICAL_SECTION();\r
1153 \r
1154         PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);\r
1155         \r
1156         /* The string length in multiples of 32 bit words (+1 for null character) */\r
1157         nStrWords = (len+1+3)/4;\r
1158 \r
1159         /* If a user event channel is specified, add in the list */\r
1160         if (userEvtChannel)\r
1161                 nArgs++;\r
1162 \r
1163         offset = nArgs * 4;\r
1164 \r
1165         /* The total number of 32-bit words needed for the whole payload */\r
1166         nWords = nStrWords + nArgs;\r
1167 \r
1168         if (nWords > 15) /* if attempting to store more than 60 byte (= max) */\r
1169         {\r
1170                 /* Truncate event if too large. The     string characters are stored\r
1171                 last, so usually only the string is truncated, unless there a lot\r
1172                 of parameters... */\r
1173 \r
1174                 /* Diagnostics ... */\r
1175                 uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;\r
1176 \r
1177                 if (bytesTruncated > MaxBytesTruncated)\r
1178                 {\r
1179                         MaxBytesTruncated = bytesTruncated;\r
1180                 }\r
1181 \r
1182                 nWords = 15;\r
1183                 len = 15 * 4 - offset;\r
1184         }\r
1185 \r
1186         TRACE_ENTER_CRITICAL_SECTION();\r
1187 \r
1188         if (RecorderEnabled)\r
1189         {\r
1190                 int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);\r
1191 \r
1192                 eventCounter++;\r
1193 \r
1194                 {\r
1195                         TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);\r
1196                         if (event != NULL)\r
1197                         {\r
1198                                 uint32_t* data32;\r
1199                                 uint8_t* data8;\r
1200                                 event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);\r
1201                                 event->base.EventCount = (uint16_t)eventCounter;\r
1202                                 event->base.TS = prvGetTimestamp32();\r
1203 \r
1204                                 /* 32-bit write-pointer for the data argument */\r
1205                                 data32 = (uint32_t*) &(event->data[0]);\r
1206 \r
1207                                 for (i = 0; i < nArgs; i++)\r
1208                                 {\r
1209                                         if ((userEvtChannel != NULL) && (i == 0))\r
1210                                         {\r
1211                                                 /* First, add the User Event Channel if not NULL */\r
1212                                                 data32[i] = (uint32_t)userEvtChannel;\r
1213                                         }\r
1214                                         else\r
1215                                         {\r
1216                                                 /* Add data arguments... */\r
1217                                                 data32[i] = va_arg(*vl, uint32_t);\r
1218                                         }\r
1219                                 }\r
1220                                 data8 = (uint8_t*)&(event->data[0]);\r
1221                                 for (i = 0; i < len; i++)\r
1222                                 {\r
1223                                         data8[offset + i] = str[i];\r
1224                                 }\r
1225 \r
1226                                 if (len < (15 * 4 - offset))\r
1227                                         data8[offset + len] = 0;        /* Only truncate if we don't fill up the buffer completely */\r
1228                                 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);\r
1229                         }\r
1230                 }\r
1231         }\r
1232         \r
1233         TRACE_EXIT_CRITICAL_SECTION();\r
1234 }\r
1235 \r
1236 /* Internal common function for storing string events without additional arguments */\r
1237 void prvTraceStoreSimpleStringEventHelper(traceString userEvtChannel,\r
1238                                                                                                         const char* str)\r
1239 {\r
1240         int len;\r
1241         int nWords;\r
1242         int nStrWords;\r
1243         int i;\r
1244         int nArgs = 0;\r
1245         int offset = 0;\r
1246         uint16_t eventID = PSF_EVENT_USER_EVENT;\r
1247         TRACE_ALLOC_CRITICAL_SECTION();\r
1248 \r
1249         PSF_ASSERT(eventID < 4096, PSF_ERROR_EVENT_CODE_TOO_LARGE);\r
1250 \r
1251         for (len = 0; (str[len] != 0) && (len < 52); len++); /* empty loop */\r
1252         \r
1253         /* The string length in multiples of 32 bit words (+1 for null character) */\r
1254         nStrWords = (len+1+3)/4;\r
1255 \r
1256         /* If a user event channel is specified, add in the list */\r
1257         if (userEvtChannel)\r
1258         {\r
1259                 nArgs++;\r
1260                 eventID++;\r
1261         }\r
1262 \r
1263         offset = nArgs * 4;\r
1264 \r
1265         /* The total number of 32-bit words needed for the whole payload */\r
1266         nWords = nStrWords + nArgs;\r
1267 \r
1268         if (nWords > 15) /* if attempting to store more than 60 byte (= max) */\r
1269         {\r
1270                 /* Truncate event if too large. The     string characters are stored\r
1271                 last, so usually only the string is truncated, unless there a lot\r
1272                 of parameters... */\r
1273 \r
1274                 /* Diagnostics ... */\r
1275                 uint32_t bytesTruncated = (uint32_t)(nWords - 15) * 4;\r
1276 \r
1277                 if (bytesTruncated > MaxBytesTruncated)\r
1278                 {\r
1279                         MaxBytesTruncated = bytesTruncated;\r
1280                 }\r
1281 \r
1282                 nWords = 15;\r
1283                 len = 15 * 4 - offset;\r
1284         }\r
1285 \r
1286         TRACE_ENTER_CRITICAL_SECTION();\r
1287 \r
1288         if (RecorderEnabled)\r
1289         {\r
1290                 int eventSize = (int)sizeof(BaseEvent) + nWords * (int)sizeof(uint32_t);\r
1291 \r
1292                 eventCounter++;\r
1293 \r
1294                 {\r
1295                         TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(largestEventType, event, eventSize);\r
1296                         if (event != NULL)\r
1297                         {\r
1298                                 uint32_t* data32;\r
1299                                 uint8_t* data8;\r
1300                                 event->base.EventID = (eventID) | (uint16_t)PARAM_COUNT(nWords);\r
1301                                 event->base.EventCount = (uint16_t)eventCounter;\r
1302                                 event->base.TS = prvGetTimestamp32();\r
1303 \r
1304                                 /* 32-bit write-pointer for the data argument */\r
1305                                 data32 = (uint32_t*) &(event->data[0]);\r
1306 \r
1307                                 if (userEvtChannel != NULL)\r
1308                                 {\r
1309                                         /* First, add the User Event Channel if not NULL */\r
1310                                         data32[0] = (uint32_t)userEvtChannel;\r
1311                                 }\r
1312 \r
1313                                 data8 = (uint8_t*) &(event->data[0]);\r
1314                                 for (i = 0; i < len; i++)\r
1315                                 {\r
1316                                         data8[offset + i] = str[i];\r
1317                                 }\r
1318 \r
1319                                 if (len < (15 * 4 - offset))\r
1320                                         data8[offset + len] = 0;        /* Only truncate if we don't fill up the buffer completely */\r
1321                                 TRC_STREAM_PORT_COMMIT_EVENT(event, (uint32_t)eventSize);\r
1322                         }\r
1323                 }\r
1324         }\r
1325         \r
1326         TRACE_EXIT_CRITICAL_SECTION();\r
1327 }\r
1328 \r
1329 /* Saves a symbol name (task name etc.) in symbol table */\r
1330 void prvTraceSaveSymbol(const void *address, const char *name)\r
1331 {\r
1332         uint32_t i;\r
1333         uint32_t foundSlot;\r
1334         uint32_t *ptrAddress;\r
1335         uint8_t *ptrSymbol;\r
1336         TRACE_ALLOC_CRITICAL_SECTION();\r
1337 \r
1338         TRACE_ENTER_CRITICAL_SECTION();\r
1339         \r
1340         foundSlot = firstFreeSymbolTableIndex;\r
1341 \r
1342         /* First look for previous entries using this address */\r
1343         for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)\r
1344         {\r
1345                 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */\r
1346                 ptrAddress = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];\r
1347                 if (*ptrAddress == (uint32_t)address)\r
1348                 {\r
1349                         foundSlot = i;\r
1350                         break;\r
1351                 }\r
1352         }\r
1353 \r
1354         if (foundSlot < SYMBOL_TABLE_BUFFER_SIZE)\r
1355         {\r
1356                 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */\r
1357                 symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;\r
1358                 \r
1359                 /* We access the symbol table via the union member pSymbolTableBufferUINT8 to avoid strict-aliasing issues */\r
1360                 ptrSymbol = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT8[foundSlot + sizeof(uint32_t)];\r
1361                 for (i = 0; i < (TRC_CFG_SYMBOL_MAX_LENGTH); i++)\r
1362         {\r
1363                         ptrSymbol[i] = (uint8_t)name[i];        /* We do this first to ensure we also get the 0 termination, if there is one */\r
1364 \r
1365                         if (name[i] == 0)\r
1366                                 break;\r
1367                 }\r
1368 \r
1369                 /* Check the length of "name", if longer than SYMBOL_MAX_LENGTH */\r
1370                 while ((name[i] != 0) && i < 128)\r
1371                 {\r
1372                         i++;\r
1373                 }\r
1374 \r
1375                 /* Remember the longest symbol name, for diagnostic purposes */\r
1376                 if (i > LongestSymbolName)\r
1377                 {\r
1378                         LongestSymbolName = i;\r
1379                 }\r
1380 \r
1381                 /* Is this the last entry in the symbol table? */\r
1382                 if (foundSlot == firstFreeSymbolTableIndex)\r
1383                 {\r
1384                         firstFreeSymbolTableIndex += SYMBOL_TABLE_SLOT_SIZE;\r
1385                 }\r
1386         }\r
1387         else\r
1388         {\r
1389                 NoRoomForSymbol++;\r
1390         }\r
1391 \r
1392         TRACE_EXIT_CRITICAL_SECTION();\r
1393 }\r
1394 \r
1395 /* Deletes a symbol name (task name etc.) from symbol table */\r
1396 void prvTraceDeleteSymbol(void *address)\r
1397 {\r
1398         uint32_t i, j;\r
1399         uint32_t *ptr, *lastEntryPtr;\r
1400         TRACE_ALLOC_CRITICAL_SECTION();\r
1401 \r
1402         TRACE_ENTER_CRITICAL_SECTION();\r
1403 \r
1404         for (i = 0; i < firstFreeSymbolTableIndex; i += SYMBOL_TABLE_SLOT_SIZE)\r
1405         {\r
1406                 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */\r
1407                 ptr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[i / sizeof(uint32_t)];\r
1408                 if (*ptr == (uint32_t)address)\r
1409                 {\r
1410                         /* See if we have another entry in the table, and that this isn't already the last entry */\r
1411                         if (firstFreeSymbolTableIndex > SYMBOL_TABLE_SLOT_SIZE && i != (firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE))\r
1412                         {\r
1413                                 /* Another entry is available, get pointer to the last one */\r
1414                                 /* We access the symbol table via the union member pSymbolTableBufferUINT32 to avoid strict-aliasing issues */\r
1415                                 lastEntryPtr = &symbolTable.SymbolTableBuffer.pSymbolTableBufferUINT32[(firstFreeSymbolTableIndex - SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t)];\r
1416                                 \r
1417                                 /* Copy last entry to this position */\r
1418                                 for (j = 0; j < (SYMBOL_TABLE_SLOT_SIZE) / sizeof(uint32_t); j++)\r
1419                                 {\r
1420                                         ptr[j] = lastEntryPtr[j];\r
1421                                 }\r
1422 \r
1423                                 /* For good measure we also zero out the original position */\r
1424                                 *lastEntryPtr = 0;\r
1425                         }\r
1426                         else\r
1427                                 *ptr = 0; /* No other entry found, or this is the last entry */\r
1428 \r
1429                         /* Lower index */\r
1430                         firstFreeSymbolTableIndex -= SYMBOL_TABLE_SLOT_SIZE;\r
1431 \r
1432                         break;\r
1433                 }\r
1434         }\r
1435 \r
1436         TRACE_EXIT_CRITICAL_SECTION();\r
1437 }\r
1438 \r
1439 /* Saves an object data entry (current task priority) in object data table */\r
1440 void prvTraceSaveObjectData(const void *address, uint32_t data)\r
1441 {\r
1442         uint32_t i;\r
1443         uint32_t foundSlot;\r
1444         uint32_t *ptr;\r
1445         TRACE_ALLOC_CRITICAL_SECTION();\r
1446 \r
1447         TRACE_ENTER_CRITICAL_SECTION();\r
1448         \r
1449         foundSlot = firstFreeObjectDataTableIndex;\r
1450 \r
1451         /* First look for previous entries using this address */\r
1452         for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)\r
1453         {\r
1454                 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */\r
1455                 ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];\r
1456                 if (*ptr == (uint32_t)address)\r
1457                 {\r
1458                         foundSlot = i;\r
1459                         break;\r
1460                 }\r
1461         }\r
1462 \r
1463         if (foundSlot < OBJECT_DATA_TABLE_BUFFER_SIZE)\r
1464         {\r
1465                 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */\r
1466                 objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t)] = (uint32_t)address;\r
1467                 objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[foundSlot / sizeof(uint32_t) + 1] = data;\r
1468 \r
1469                 /* Is this the last entry in the object data table? */\r
1470                 if (foundSlot == firstFreeObjectDataTableIndex)\r
1471                 {\r
1472                         firstFreeObjectDataTableIndex += OBJECT_DATA_SLOT_SIZE;\r
1473                 }\r
1474         }\r
1475         else\r
1476         {\r
1477                 NoRoomForObjectData++;\r
1478         }\r
1479 \r
1480         TRACE_EXIT_CRITICAL_SECTION();\r
1481 }\r
1482 \r
1483 /* Removes an object data entry (task base priority) from object data table */\r
1484 void prvTraceDeleteObjectData(void *address)\r
1485 {\r
1486         uint32_t i, j;\r
1487         uint32_t *ptr, *lastEntryPtr;\r
1488         TRACE_ALLOC_CRITICAL_SECTION();\r
1489 \r
1490         TRACE_ENTER_CRITICAL_SECTION();\r
1491 \r
1492         for (i = 0; i < firstFreeObjectDataTableIndex; i += OBJECT_DATA_SLOT_SIZE)\r
1493         {\r
1494                 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */\r
1495                 ptr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[i / sizeof(uint32_t)];\r
1496                 if (*ptr == (uint32_t)address)\r
1497                 {\r
1498                         /* See if we have another entry in the table, and that this isn't already the last entry */\r
1499                         if (firstFreeObjectDataTableIndex > OBJECT_DATA_SLOT_SIZE && i != (firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE))\r
1500                         {\r
1501                                 /* Another entry is available, get pointer to the last one */\r
1502                                 /* We access the data table via the union member pObjectDataTableBufferUINT32 to avoid strict-aliasing issues */\r
1503                                 lastEntryPtr = &objectDataTable.ObjectDataTableBuffer.pObjectDataTableBufferUINT32[(firstFreeObjectDataTableIndex - OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t)];\r
1504                                 \r
1505                                 /* Copy last entry to this position */\r
1506                                 for (j = 0; j < (OBJECT_DATA_SLOT_SIZE) / sizeof(uint32_t); j++)\r
1507                                 {\r
1508                                         ptr[j] = lastEntryPtr[j];\r
1509                                 }\r
1510 \r
1511                                 /* For good measure we also zero out the original position */\r
1512                                 *lastEntryPtr = 0;\r
1513                         }\r
1514                         else\r
1515                                 *ptr = 0; /* No other entry found, or this is the last entry */\r
1516 \r
1517                         /* Lower index */\r
1518                         firstFreeObjectDataTableIndex -= OBJECT_DATA_SLOT_SIZE;\r
1519 \r
1520                         break;\r
1521                 }\r
1522         }\r
1523 \r
1524         TRACE_EXIT_CRITICAL_SECTION();\r
1525 }\r
1526 \r
1527 /* Checks if the provided command is a valid command */\r
1528 int prvIsValidCommand(TracealyzerCommandType* cmd)\r
1529 {\r
1530         uint16_t checksum = (uint16_t)(0xFFFF - (       cmd->cmdCode +\r
1531                                                                                                 cmd->param1 +\r
1532                                                                                                 cmd->param2 +\r
1533                                                                                                 cmd->param3 +\r
1534                                                                                                 cmd->param4 +\r
1535                                                                                                 cmd->param5));\r
1536 \r
1537         if (cmd->checksumMSB != (unsigned char)(checksum >> 8))\r
1538                 return 0;\r
1539 \r
1540         if (cmd->checksumLSB != (unsigned char)(checksum & 0xFF))\r
1541                 return 0;\r
1542 \r
1543         if (cmd->cmdCode > CMD_LAST_COMMAND)\r
1544                 return 0;\r
1545 \r
1546         return 1;\r
1547 }\r
1548 \r
1549 /* Executed the received command (Start or Stop) */\r
1550 void prvProcessCommand(TracealyzerCommandType* cmd)\r
1551 {\r
1552         switch(cmd->cmdCode)\r
1553         {\r
1554                 case CMD_SET_ACTIVE:\r
1555                         prvSetRecorderEnabled(cmd->param1);\r
1556                         break;\r
1557                 default:\r
1558                         break;\r
1559         }\r
1560 }\r
1561 \r
1562 /* Called on warnings, when the recording can continue. */\r
1563 void prvTraceWarning(int errCode)\r
1564 {\r
1565         if (!errorCode)\r
1566         {\r
1567                 errorCode = errCode;\r
1568                 prvTraceStoreWarnings();\r
1569         }\r
1570 }\r
1571 \r
1572 /* Called on critical errors in the recorder. Stops the recorder! */\r
1573 void prvTraceError(int errCode)\r
1574 {\r
1575         if (! errorCode)\r
1576         {\r
1577                 errorCode = errCode;\r
1578                 prvTraceStoreWarnings();\r
1579                 vTracePrintF(trcWarningChannel, "Recorder stopped in prvTraceError()");\r
1580 \r
1581                 prvSetRecorderEnabled(0);\r
1582         }\r
1583 }\r
1584 \r
1585 /* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */\r
1586 #ifndef TRC_CFG_ARM_CM_USE_SYSTICK\r
1587 #if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03)))\r
1588 \r
1589 void prvTraceInitCortexM()\r
1590 {\r
1591         /* Make sure the DWT registers are unlocked, in case the debugger doesn't do this. */\r
1592         TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK;\r
1593 \r
1594         /* Make sure DWT is enabled is enabled, if supported */\r
1595         TRC_REG_DEMCR |= TRC_DEMCR_TRCENA;\r
1596 \r
1597         do\r
1598         {\r
1599                 /* Verify that DWT is supported */\r
1600                 if (TRC_REG_DEMCR == 0)\r
1601                 {\r
1602                         /* This function is called on Cortex-M3, M4 and M7 devices to initialize\r
1603                         the DWT unit, assumed present. The DWT cycle counter is used for timestamping. \r
1604                         \r
1605                         If the below error is produced, the DWT unit does not seem to be available.\r
1606                         \r
1607                         In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build\r
1608                         to use SysTick timestamping instead, or define your own timestamping by \r
1609                         setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED\r
1610                         and make the necessary definitions, as explained in trcHardwarePort.h.*/\r
1611                         \r
1612                         prvTraceError(PSF_ERROR_DWT_NOT_SUPPORTED);\r
1613                         break;\r
1614                 }\r
1615 \r
1616                 /* Verify that DWT_CYCCNT is supported */\r
1617                 if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT)\r
1618                 {\r
1619                         /* This function is called on Cortex-M3, M4 and M7 devices to initialize\r
1620                         the DWT unit, assumed present. The DWT cycle counter is used for timestamping. \r
1621                         \r
1622                         If the below error is produced, the cycle counter does not seem to be available.\r
1623                         \r
1624                         In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build\r
1625                         to use SysTick timestamping instead, or define your own timestamping by \r
1626                         setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED\r
1627                         and make the necessary definitions, as explained in trcHardwarePort.h.*/\r
1628 \r
1629                         prvTraceError(PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED);\r
1630                         break;\r
1631                 }\r
1632 \r
1633                 /* Reset the cycle counter */\r
1634                 TRC_REG_DWT_CYCCNT = 0;\r
1635 \r
1636                 /* Enable the cycle counter */\r
1637                 TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA;\r
1638 \r
1639         } while(0);     /* breaks above jump here */\r
1640 }\r
1641 #endif\r
1642 #endif\r
1643 \r
1644 /* Performs timestamping using definitions in trcHardwarePort.h */\r
1645 static uint32_t prvGetTimestamp32(void)\r
1646 {\r
1647 #if ((TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR) || (TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR))\r
1648         return TRC_HWTC_COUNT;\r
1649 #endif\r
1650         \r
1651 #if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR))\r
1652         return TRC_HWTC_COUNT;\r
1653 #endif\r
1654         \r
1655 #if ((TRC_HWTC_TYPE == TRC_OS_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR))\r
1656         uint32_t ticks = TRACE_GET_OS_TICKS();\r
1657         return ((TRC_HWTC_COUNT) & 0x00FFFFFFU) + ((ticks & 0x000000FFU) << 24);\r
1658 #endif\r
1659 }\r
1660 \r
1661 /* Store the Timestamp Config event */\r
1662 static void prvTraceStoreTSConfig(void)\r
1663 {\r
1664         /* If not overridden using vTraceSetFrequency, use default value */\r
1665         if (timestampFrequency == 0)\r
1666         {\r
1667                 timestampFrequency = TRC_HWTC_FREQ_HZ;\r
1668         }\r
1669         \r
1670         #if (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR || TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR)\r
1671         \r
1672                 prvTraceStoreEvent(5, \r
1673                                                         PSF_EVENT_TS_CONFIG,\r
1674                                                         (uint32_t)timestampFrequency,                       \r
1675                                                         (uint32_t)(TRACE_TICK_RATE_HZ),\r
1676                                                         (uint32_t)(TRC_HWTC_TYPE),\r
1677                                                         (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD),\r
1678                                                         (uint32_t)(TRC_HWTC_PERIOD));\r
1679         \r
1680         #else\r
1681         \r
1682         prvTraceStoreEvent(4, \r
1683                                                 PSF_EVENT_TS_CONFIG,\r
1684                                                 (uint32_t)timestampFrequency,                       \r
1685                                                 (uint32_t)(TRACE_TICK_RATE_HZ),\r
1686                                                 (uint32_t)(TRC_HWTC_TYPE),\r
1687                                                 (uint32_t)(TRC_CFG_ISR_TAILCHAINING_THRESHOLD));        \r
1688         #endif\r
1689 }\r
1690 \r
1691 /* Retrieve a buffer page to write to. */\r
1692 static int prvAllocateBufferPage(int prevPage)\r
1693 {\r
1694         int index;\r
1695         int count = 0;\r
1696 \r
1697         index = (prevPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);\r
1698 \r
1699         while((PageInfo[index].Status != PAGE_STATUS_FREE) && (count ++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)))\r
1700         {\r
1701                 index = (index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT);\r
1702         }\r
1703 \r
1704         if (PageInfo[index].Status == PAGE_STATUS_FREE)\r
1705         {\r
1706                 return index;\r
1707         }\r
1708 \r
1709         return -1;\r
1710 }\r
1711 \r
1712 /* Mark the page read as complete. */\r
1713 static void prvPageReadComplete(int pageIndex)\r
1714 {\r
1715         TRACE_ALLOC_CRITICAL_SECTION();\r
1716 \r
1717         TRACE_ENTER_CRITICAL_SECTION();\r
1718         PageInfo[pageIndex].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);\r
1719         PageInfo[pageIndex].WritePointer = &EventBuffer[pageIndex * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)];\r
1720         PageInfo[pageIndex].Status = PAGE_STATUS_FREE;\r
1721 \r
1722         TotalBytesRemaining += (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);\r
1723 \r
1724         TRACE_EXIT_CRITICAL_SECTION();\r
1725 }\r
1726 \r
1727 /* Get the current buffer page index and remaining number of bytes. */\r
1728 static int prvGetBufferPage(int32_t* bytesUsed)\r
1729 {\r
1730         static int8_t lastPage = -1;\r
1731         int count = 0;\r
1732         int8_t index = (int8_t) ((lastPage + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT));\r
1733 \r
1734         while((PageInfo[index].Status != PAGE_STATUS_READ) && (count++ < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT)))\r
1735         {\r
1736                 index = (int8_t)((index + 1) % (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT));\r
1737         }\r
1738 \r
1739         if (PageInfo[index].Status == PAGE_STATUS_READ)\r
1740         {\r
1741                 *bytesUsed = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) - PageInfo[index].BytesRemaining;\r
1742                 lastPage = index;\r
1743                 return index;\r
1744         }\r
1745 \r
1746         *bytesUsed = 0;\r
1747 \r
1748         return -1;\r
1749 }\r
1750 \r
1751 /*******************************************************************************\r
1752  * uint32_t prvPagedEventBufferTransfer(void)\r
1753  *\r
1754  * Transfers one buffer page of trace data, if a full page is available, using\r
1755  * the macro TRC_STREAM_PORT_WRITE_DATA as defined in trcStreamingPort.h.\r
1756  *\r
1757  * This function is intended to be called the periodic TzCtrl task with a suitable\r
1758  * delay (e.g. 10-100 ms).\r
1759  *\r
1760  * Returns the number of bytes sent. If non-zero, it is good to call this \r
1761  * again, in order to send any additional data waiting in the buffer.\r
1762  * If zero, wait a while before calling again.\r
1763  *\r
1764  * In case of errors from the streaming interface, it registers a warning\r
1765  * (PSF_WARNING_STREAM_PORT_WRITE) provided by xTraceGetLastError().\r
1766  *\r
1767  *******************************************************************************/\r
1768 uint32_t prvPagedEventBufferTransfer(void)\r
1769 {\r
1770         int8_t pageToTransfer = -1;\r
1771     int32_t bytesTransferredTotal = 0;\r
1772         int32_t bytesTransferredNow = 0;\r
1773         int32_t bytesToTransfer;\r
1774 \r
1775     pageToTransfer = (int8_t)prvGetBufferPage(&bytesToTransfer);\r
1776 \r
1777         /* bytesToTransfer now contains the number of "valid" bytes in the buffer page, that should be transmitted.\r
1778         There might be some unused junk bytes in the end, that must be ignored. */\r
1779     \r
1780     if (pageToTransfer > -1)\r
1781     {\r
1782         while (1)  /* Keep going until we have transferred all that we intended to */\r
1783         {\r
1784                         if (TRC_STREAM_PORT_WRITE_DATA(\r
1785                                         &EventBuffer[pageToTransfer * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE) + bytesTransferredTotal],\r
1786                                         (uint32_t)(bytesToTransfer - bytesTransferredTotal),\r
1787                                         &bytesTransferredNow) == 0)\r
1788                         {\r
1789                                 /* Write was successful. Update the number of transferred bytes. */\r
1790                                 bytesTransferredTotal += bytesTransferredNow;\r
1791 \r
1792                                 if (bytesTransferredTotal == bytesToTransfer)\r
1793                                 {\r
1794                                         /* All bytes have been transferred. Mark the buffer page as "Read Complete" (so it can be written to) and return OK. */\r
1795                                         prvPageReadComplete(pageToTransfer);\r
1796                                         return (uint32_t)bytesTransferredTotal;\r
1797                                 }\r
1798                         }\r
1799                         else\r
1800                         {\r
1801                                 /* Some error from the streaming interface... */\r
1802                                 prvTraceWarning(PSF_WARNING_STREAM_PORT_WRITE);\r
1803                                 return 0;\r
1804                         }\r
1805                 }\r
1806         }\r
1807         return 0;\r
1808 }\r
1809 \r
1810 /*******************************************************************************\r
1811  * void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)\r
1812  *\r
1813  * Returns a pointer to an available location in the buffer able to store the\r
1814  * requested size.\r
1815  * \r
1816  * Return value: The pointer.\r
1817  * \r
1818  * Parameters:\r
1819  * - sizeOfEvent: The size of the event that is to be placed in the buffer.\r
1820  *\r
1821 *******************************************************************************/\r
1822 void* prvPagedEventBufferGetWritePointer(int sizeOfEvent)\r
1823 {\r
1824         void* ret;\r
1825         static int currentWritePage = -1;\r
1826 \r
1827         if (currentWritePage == -1)\r
1828         {\r
1829             currentWritePage = prvAllocateBufferPage(currentWritePage);\r
1830                 if (currentWritePage == -1)\r
1831                 {\r
1832                         DroppedEventCounter++;\r
1833                         return NULL;\r
1834                 }\r
1835         }\r
1836 \r
1837     if (PageInfo[currentWritePage].BytesRemaining - sizeOfEvent < 0)\r
1838         {\r
1839                 PageInfo[currentWritePage].Status = PAGE_STATUS_READ;\r
1840 \r
1841                 TotalBytesRemaining -= PageInfo[currentWritePage].BytesRemaining; // Last trailing bytes\r
1842 \r
1843                 if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)\r
1844                   TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;\r
1845 \r
1846                 currentWritePage = prvAllocateBufferPage(currentWritePage);\r
1847                 if (currentWritePage == -1)\r
1848                 {\r
1849                   DroppedEventCounter++;\r
1850                   return NULL;\r
1851                 }\r
1852         }\r
1853         ret = PageInfo[currentWritePage].WritePointer;\r
1854         PageInfo[currentWritePage].WritePointer += sizeOfEvent;\r
1855         PageInfo[currentWritePage].BytesRemaining = (uint16_t)(PageInfo[currentWritePage].BytesRemaining -sizeOfEvent);\r
1856 \r
1857         TotalBytesRemaining = (TotalBytesRemaining-(uint16_t)sizeOfEvent);\r
1858 \r
1859         if (TotalBytesRemaining < TotalBytesRemaining_LowWaterMark)\r
1860                 TotalBytesRemaining_LowWaterMark = TotalBytesRemaining;\r
1861 \r
1862         return ret;\r
1863 }\r
1864 \r
1865 /*******************************************************************************\r
1866  * void prvPagedEventBufferInit(char* buffer)\r
1867  *\r
1868  * Assigns the buffer to use and initializes the PageInfo structure.\r
1869  *\r
1870  * Return value: void\r
1871  * \r
1872  * Parameters:\r
1873  * - char* buffer: pointer to the trace data buffer, allocated by the caller.\r
1874  *\r
1875 *******************************************************************************/\r
1876 void prvPagedEventBufferInit(char* buffer)\r
1877 {\r
1878         int i;\r
1879         TRACE_ALLOC_CRITICAL_SECTION();\r
1880     \r
1881     EventBuffer = buffer;\r
1882     \r
1883         TRACE_ENTER_CRITICAL_SECTION();\r
1884         for (i = 0; i < (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT); i++)\r
1885         {\r
1886                 PageInfo[i].BytesRemaining = (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE);\r
1887                 PageInfo[i].WritePointer = &EventBuffer[i * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)];\r
1888                 PageInfo[i].Status = PAGE_STATUS_FREE;\r
1889         }\r
1890         TRACE_EXIT_CRITICAL_SECTION();\r
1891 \r
1892 }\r
1893 \r
1894 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/\r
1895 \r
1896 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/\r