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