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