]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcSnapshotRecorder.c
commit 9f316c246baafa15c542a5aea81a94f26e3d6507
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-Trace / trcSnapshotRecorder.c
1 /*******************************************************************************\r
2  * Trace Recorder Library for Tracealyzer v4.1.5\r
3  * Percepio AB, www.percepio.com\r
4  *\r
5  * trcSnapshotRecorder.c\r
6  *\r
7  * The generic core of the trace recorder's snapshot 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_SNAPSHOT)\r
48 \r
49 #if (TRC_USE_TRACEALYZER_RECORDER == 1)\r
50 \r
51 #include <string.h>\r
52 #include <stdarg.h>\r
53 #include <stdint.h>\r
54 \r
55 #if ((TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_INCR) || (TRC_HWTC_TYPE == TRC_CUSTOM_TIMER_DECR))\r
56         #error "CUSTOM timestamping mode is not (yet) supported in snapshot mode!"\r
57 #endif\r
58 \r
59 /* DO NOT CHANGE */\r
60 #define TRACE_MINOR_VERSION 5\r
61 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)\r
62 static traceHandle isrstack[TRC_CFG_MAX_ISR_NESTING];\r
63 int32_t isPendingContextSwitch = 0;\r
64 #endif /* (TRC_CFG_INCLUDE_ISR_TRACING == 1) */\r
65 \r
66 #if !defined TRC_CFG_INCLUDE_READY_EVENTS || TRC_CFG_INCLUDE_READY_EVENTS == 1\r
67 static int readyEventsEnabled = 1;\r
68 #endif /*!defined TRC_CFG_INCLUDE_READY_EVENTS || TRC_CFG_INCLUDE_READY_EVENTS == 1*/\r
69 \r
70 /*******************************************************************************\r
71  * uiTraceTickCount\r
72  *\r
73  * This variable is should be updated by the Kernel tick interrupt. This does\r
74  * not need to be modified when developing a new timer port. It is preferred to\r
75  * keep any timer port changes in the HWTC macro definitions, which typically\r
76  * give sufficient flexibility.\r
77  ******************************************************************************/\r
78 uint32_t uiTraceTickCount = 0;\r
79 \r
80 uint32_t trace_disable_timestamp = 0;\r
81 \r
82 static uint32_t last_timestamp = 0;\r
83 \r
84 /* Flag that shows if inside a critical section of the recorder */\r
85 volatile int recorder_busy = 0;\r
86 \r
87 /* Holds the value set by vTraceSetFrequency */\r
88 uint32_t timestampFrequency = 0;\r
89 \r
90 /* The last error message of the recorder. NULL if no error message. */\r
91 const char* traceErrorMessage = NULL;\r
92 \r
93 int8_t nISRactive = 0;\r
94 \r
95 traceHandle handle_of_last_logged_task = 0;\r
96 \r
97 /* Called when the recorder is stopped, set by vTraceSetStopHook. */\r
98 TRACE_STOP_HOOK vTraceStopHookPtr = (TRACE_STOP_HOOK)0;\r
99 \r
100 uint16_t CurrentFilterMask = 0xFFFF;\r
101 \r
102 uint16_t CurrentFilterGroup = FilterGroup0;\r
103 \r
104 extern int8_t nISRactive;\r
105 \r
106 extern traceHandle handle_of_last_logged_task;\r
107 \r
108 /*************** Private Functions *******************************************/\r
109 static void prvStrncpy(char* dst, const char* src, uint32_t maxLength);\r
110 static uint8_t prvTraceGetObjectState(uint8_t objectclass, traceHandle id);\r
111 static void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength);\r
112 static void* prvTraceNextFreeEventBufferSlot(void);\r
113 static uint16_t prvTraceGetDTS(uint16_t param_maxDTS);\r
114 static traceString prvTraceOpenSymbol(const char* name, traceString userEventChannel);\r
115 static void prvTraceUpdateCounters(void);\r
116 \r
117 void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t signed_size);\r
118 \r
119 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)\r
120 static void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nEntries);\r
121 #endif\r
122 \r
123 static traceString prvTraceCreateSymbolTableEntry(const char* name,\r
124                                                                                  uint8_t crc6,\r
125                                                                                  uint8_t len,\r
126                                                                                  traceString channel);\r
127 \r
128 static traceString prvTraceLookupSymbolTableEntry(const char* name,\r
129                                                                                  uint8_t crc6,\r
130                                                                                  uint8_t len,\r
131                                                                                  traceString channel);\r
132 \r
133 \r
134 #if (TRC_CFG_INCLUDE_ISR_TRACING == 0)\r
135 /* ISR tracing is turned off */\r
136 void prvTraceIncreaseISRActive(void);\r
137 void prvTraceDecreaseISRActive(void);\r
138 #endif /*(TRC_CFG_INCLUDE_ISR_TRACING == 0)*/\r
139 \r
140 #if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1)\r
141 static uint8_t prvTraceGet8BitHandle(traceHandle handle);\r
142 #else\r
143 #define prvTraceGet8BitHandle(x) ((uint8_t)x)\r
144 #endif\r
145 \r
146 \r
147 #if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)\r
148 static uint32_t heapMemUsage = 0;\r
149 #endif\r
150 \r
151 #if (TRC_CFG_SCHEDULING_ONLY == 0)\r
152 static uint32_t prvTraceGetParam(uint32_t, uint32_t);\r
153 #endif\r
154 \r
155 /*******************************************************************************\r
156  * prvTraceInitTraceData\r
157  *\r
158  * Allocates and initializes the recorder data structure, based on the constants\r
159  * in trcConfig.h. This allows for allocating the data on the heap, instead of\r
160  * using a static declaration.\r
161  ******************************************************************************/\r
162 static void prvTraceInitTraceData(void);\r
163 \r
164 /*******************************************************************************\r
165  * prvTracePortGetTimeStamp\r
166  *\r
167  * Returns the current time based on the HWTC macros which provide a hardware\r
168  * isolation layer towards the hardware timer/counter.\r
169  *\r
170  * The HWTC macros and prvTracePortGetTimeStamp is the main porting issue\r
171  * or the trace recorder library. Typically you should not need to change\r
172  * the code of prvTracePortGetTimeStamp if using the HWTC macros.\r
173  *\r
174  ******************************************************************************/\r
175 void prvTracePortGetTimeStamp(uint32_t *puiTimestamp);\r
176 \r
177 static void prvTraceTaskInstanceFinish(int8_t direct);\r
178 \r
179 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
180 static void vTracePrintF_Helper(traceString eventLabel, const char* formatStr, va_list vl);\r
181 \r
182 #if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
183 static void vTraceUBData_Helper(traceUBChannel channelPair, va_list vl);\r
184 static void prvTraceUBHelper1(traceUBChannel channel, traceString eventLabel, traceString formatLabel, va_list vl);\r
185 static void prvTraceUBHelper2(traceUBChannel channel, uint32_t* data, uint32_t noOfSlots);\r
186 #endif /*(TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)*/\r
187 #endif /* ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1)) */\r
188 \r
189 /********* Public Functions **************************************************/\r
190 \r
191 uint16_t uiIndexOfObject(traceHandle objecthandle, uint8_t objectclass);\r
192 \r
193 /*******************************************************************************\r
194  * prvTraceError\r
195  *\r
196  * Called by various parts in the recorder. Stops the recorder and stores a\r
197  * pointer to an error message, which is printed by the monitor task.\r
198  ******************************************************************************/\r
199 void prvTraceError(const char* msg);\r
200 \r
201 /******************************************************************************\r
202 * vTraceEnable(int startOption) - snapshot mode\r
203 *\r
204 * Initializes and optionally starts the trace, depending on the start option.\r
205 * To use the trace recorder, the startup must call vTraceEnable before any RTOS\r
206 * calls are made (including "create" calls). Three start options are provided:\r
207 *\r
208 * TRC_START: Starts the tracing directly. In snapshot mode this allows for\r
209 * starting the trace at any point in your code, assuming vTraceEnable(TRC_INIT)\r
210 * has been called in the startup.\r
211 * Can also be used for streaming without Tracealyzer control, e.g. to a local\r
212 * flash file system (assuming such a "stream port", see trcStreamingPort.h).\r
213 *\r
214 * TRC_INIT: Initializes the trace recorder, but does not start the tracing.\r
215 * In snapshot mode, this must be followed by a vTraceEnable(TRC_START) sometime\r
216 * later.\r
217 *\r
218 * Usage examples, in snapshot mode:\r
219 *\r
220 * Snapshot trace, from startup:\r
221 *       <board init>\r
222 *       vTraceEnable(TRC_START);\r
223 *       <RTOS init>\r
224 *\r
225 * Snapshot trace, from a later point:\r
226 *       <board init>\r
227 *       vTraceEnable(TRC_INIT);\r
228 *       <RTOS init>\r
229 *       ...\r
230 *       vTraceEnable(TRC_START); // e.g., in task context, at some relevant event\r
231 *\r
232 *\r
233 * Note: See other implementation of vTraceEnable in trcStreamingRecorder.c\r
234 ******************************************************************************/\r
235 void vTraceEnable(int startOption)\r
236 {\r
237         prvTraceInitTraceData();\r
238 \r
239         if (startOption == TRC_START)\r
240         {\r
241                 vTraceStart();\r
242         }\r
243         else if (startOption == TRC_START_AWAIT_HOST)\r
244         {\r
245                 prvTraceError("vTraceEnable(TRC_START_AWAIT_HOST) not allowed in Snapshot mode");\r
246         }\r
247         else if (startOption != TRC_INIT)\r
248         {\r
249                 prvTraceError("Unexpected argument to vTraceEnable (snapshot mode)");\r
250         }\r
251 }\r
252 \r
253 /*******************************************************************************\r
254  * vTraceSetRecorderDataBuffer\r
255  *\r
256  * If custom allocation is used, this function must be called so the recorder\r
257  * library knows where to save the trace data.\r
258  ******************************************************************************/\r
259 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)\r
260 void vTraceSetRecorderDataBuffer(void* pRecorderData)\r
261 {\r
262         TRACE_ASSERT(pRecorderData != NULL, "vTraceSetRecorderDataBuffer, pRecorderData == NULL", TRC_UNUSED);\r
263         RecorderDataPtr = pRecorderData;\r
264 }\r
265 #endif\r
266 \r
267 /*******************************************************************************\r
268  * vTraceSetStopHook\r
269  *\r
270  * Sets a function to be called when the recorder is stopped. This can be used\r
271  * to save the trace to a file system, if available. This is only implemented\r
272  * for snapshot mode.\r
273  ******************************************************************************/\r
274 void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction)\r
275 {\r
276         vTraceStopHookPtr = stopHookFunction;\r
277 }\r
278 \r
279 /*******************************************************************************\r
280  * vTraceClear\r
281  *\r
282  * Resets the recorder. Only necessary if a restart is desired - this is not\r
283  * needed in the startup initialization.\r
284  ******************************************************************************/\r
285 void vTraceClear(void)\r
286 {\r
287         TRACE_ALLOC_CRITICAL_SECTION();\r
288         trcCRITICAL_SECTION_BEGIN();\r
289         RecorderDataPtr->absTimeLastEventSecond = 0;\r
290         RecorderDataPtr->absTimeLastEvent = 0;\r
291         RecorderDataPtr->nextFreeIndex = 0;\r
292         RecorderDataPtr->numEvents = 0;\r
293         RecorderDataPtr->bufferIsFull = 0;\r
294         traceErrorMessage = NULL;\r
295         RecorderDataPtr->internalErrorOccured = 0;\r
296         (void)memset(RecorderDataPtr->eventData, 0, RecorderDataPtr->maxEvents * 4);\r
297         handle_of_last_logged_task = 0;\r
298         trcCRITICAL_SECTION_END();\r
299 }\r
300 \r
301 /*******************************************************************************\r
302  * uiTraceStart\r
303  *\r
304  * Starts the recorder. The recorder will not be started if an error has been\r
305  * indicated using prvTraceError, e.g. if any of the Nx constants in trcConfig.h\r
306  * has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc).\r
307  *\r
308  * Returns 1 if the recorder was started successfully.\r
309  * Returns 0 if the recorder start was prevented due to a previous internal\r
310  * error. In that case, check xTraceGetLastError to get the error message.\r
311  * Any error message is also presented when opening a trace file.\r
312  *\r
313  * This function is obsolete, but has been saved for backwards compatibility.\r
314  * We recommend using vTraceEnable instead.\r
315  ******************************************************************************/\r
316 uint32_t uiTraceStart(void)\r
317 {\r
318         traceHandle handle;\r
319         TRACE_ALLOC_CRITICAL_SECTION();\r
320 \r
321         handle = 0;\r
322 \r
323         if (RecorderDataPtr == NULL)\r
324         {\r
325                 TRACE_ASSERT(RecorderDataPtr != NULL, "Recorder not initialized. Use vTraceEnable() instead!", 0);\r
326                 return 0;\r
327         }\r
328 \r
329         if (RecorderDataPtr->recorderActive == 1)\r
330                 return 1; /* Already running */\r
331 \r
332         if (traceErrorMessage == NULL)\r
333         {\r
334                 trcCRITICAL_SECTION_BEGIN();\r
335                 RecorderDataPtr->recorderActive = 1;\r
336 \r
337                 handle = TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK());\r
338                 if (handle == 0)\r
339                 {\r
340                         /* This occurs if the scheduler is not yet started.\r
341                         This creates a dummy "(startup)" task entry internally in the\r
342                         recorder */\r
343                         handle = prvTraceGetObjectHandle(TRACE_CLASS_TASK);\r
344                         prvTraceSetObjectName(TRACE_CLASS_TASK, handle, "(startup)");\r
345 \r
346                         prvTraceSetPriorityProperty(TRACE_CLASS_TASK, handle, 0);\r
347                 }\r
348 \r
349                 prvTraceStoreTaskswitch(handle); /* Register the currently running task */\r
350                 trcCRITICAL_SECTION_END();\r
351         }\r
352 \r
353         return RecorderDataPtr->recorderActive;\r
354 }\r
355 \r
356 /*******************************************************************************\r
357  * vTraceStart\r
358  *\r
359  * Starts the recorder. The recorder will not be started if an error has been\r
360  * indicated using prvTraceError, e.g. if any of the Nx constants in trcConfig.h\r
361  * has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc).\r
362  *\r
363  * This function is obsolete, but has been saved for backwards compatibility.\r
364  * We recommend using vTraceEnable instead.\r
365  ******************************************************************************/\r
366 void vTraceStart(void)\r
367 {\r
368         (void)uiTraceStart();\r
369 }\r
370 \r
371 /*******************************************************************************\r
372  * vTraceStop\r
373  *\r
374  * Stops the recorder. The recording can be resumed by calling vTraceStart.\r
375  * This does not reset the recorder. Use vTraceClear if that is desired.\r
376  ******************************************************************************/\r
377 void vTraceStop(void)\r
378 {\r
379         if (RecorderDataPtr != NULL)\r
380         {\r
381                 RecorderDataPtr->recorderActive = 0;\r
382         }\r
383 \r
384         if (vTraceStopHookPtr != (TRACE_STOP_HOOK)0)\r
385         {\r
386                 (*vTraceStopHookPtr)();                 /* An application call-back function. */\r
387         }\r
388 }\r
389 \r
390 /*******************************************************************************\r
391 * xTraceIsRecordingEnabled\r
392 * Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0.\r
393 ******************************************************************************/\r
394 int xTraceIsRecordingEnabled(void)\r
395 {\r
396         if (RecorderDataPtr != NULL)\r
397         {\r
398                 return (int)RecorderDataPtr->recorderActive;\r
399         }\r
400         else\r
401         {\r
402                 return 0;\r
403         }\r
404 }\r
405 \r
406 /*******************************************************************************\r
407  * xTraceGetLastError\r
408  *\r
409  * Gives the last error message, if any. NULL if no error message is stored.\r
410  * Any error message is also presented when opening a trace file.\r
411  ******************************************************************************/\r
412 const char* xTraceGetLastError(void)\r
413 {\r
414         return traceErrorMessage;\r
415 }\r
416 \r
417 /*******************************************************************************\r
418 * vTraceClearError\r
419 *\r
420 * Removes any previous error message generated by recorder calling prvTraceError.\r
421 * By calling this function, it may be possible to start/restart the trace\r
422 * despite errors in the recorder, but there is no guarantee that the trace\r
423 * recorder will work correctly in that case, depending on the type of error.\r
424 ******************************************************************************/\r
425 void vTraceClearError(void)\r
426 {\r
427         traceErrorMessage = NULL;\r
428         if (RecorderDataPtr != NULL)\r
429         {\r
430                 RecorderDataPtr->internalErrorOccured = 0;\r
431         }\r
432 }\r
433 \r
434 /*******************************************************************************\r
435  * xTraceGetTraceBuffer\r
436  *\r
437  * Returns a pointer to the recorder data structure. Use this together with\r
438  * uiTraceGetTraceBufferSize if you wish to implement an own store/upload\r
439  * solution, e.g., in case a debugger connection is not available for uploading\r
440  * the data.\r
441  ******************************************************************************/\r
442 void* xTraceGetTraceBuffer(void)\r
443 {\r
444         return RecorderDataPtr;\r
445 }\r
446 \r
447 /*******************************************************************************\r
448  * uiTraceGetTraceBufferSize\r
449  *\r
450  * Gets the size of the recorder data structure. For use together with\r
451  * vTraceGetTraceBuffer if you wish to implement an own store/upload solution,\r
452  * e.g., in case a debugger connection is not available for uploading the data.\r
453  ******************************************************************************/\r
454 uint32_t uiTraceGetTraceBufferSize(void)\r
455 {\r
456         return sizeof(RecorderDataType);\r
457 }\r
458 \r
459 /******************************************************************************\r
460  * prvTraceTaskInstanceFinish\r
461  *\r
462  * Private common function for the vTraceTaskInstanceFinishXXX functions.\r
463  *****************************************************************************/\r
464 static void prvTraceTaskInstanceFinish(int8_t direct)\r
465 {\r
466         TaskInstanceStatusEvent* tis;\r
467         uint8_t dts45;\r
468 \r
469         TRACE_ALLOC_CRITICAL_SECTION();\r
470 \r
471         trcCRITICAL_SECTION_BEGIN();\r
472         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
473         {\r
474                 dts45 = (uint8_t)prvTraceGetDTS(0xFF);\r
475                 tis = (TaskInstanceStatusEvent*) prvTraceNextFreeEventBufferSlot();\r
476                 if (tis != NULL)\r
477                 {\r
478                         if (direct == 0)\r
479                                 tis->type = TASK_INSTANCE_FINISHED_NEXT_KSE;\r
480                         else\r
481                                 tis->type = TASK_INSTANCE_FINISHED_DIRECT;\r
482 \r
483                         tis->dts = dts45;\r
484                         prvTraceUpdateCounters();\r
485                 }\r
486         }\r
487         trcCRITICAL_SECTION_END();\r
488 }\r
489 \r
490 /******************************************************************************\r
491  * vTraceInstanceFinishedNext(void)\r
492  *\r
493  * Marks the current task instance as finished on the next kernel call.\r
494  *\r
495  * If that kernel call is blocking, the instance ends after the blocking event\r
496  * and the corresponding return event is then the start of the next instance.\r
497  * If the kernel call is not blocking, the viewer instead splits the current\r
498  * fragment right before the kernel call, which makes this call the first event\r
499  * of the next instance.\r
500  *\r
501  * See also TRC_CFG_USE_IMPLICIT_IFE_RULES in trcConfig.h\r
502  *\r
503  * Example:\r
504  *\r
505  *              while(1)\r
506  *              {\r
507  *                      xQueueReceive(CommandQueue, &command, timeoutDuration);\r
508  *                      processCommand(command);\r
509  *          vTraceInstanceFinishedNext();\r
510  *              }\r
511  *****************************************************************************/\r
512 void vTraceInstanceFinishedNext(void)\r
513 {\r
514     prvTraceTaskInstanceFinish(0);\r
515 }\r
516 \r
517 /******************************************************************************\r
518  * vTraceInstanceFinishedNow(void)\r
519  *\r
520  * Marks the current task instance as finished at this very instant.\r
521  * This makes the viewer to splits the current fragment at this point and begin\r
522  * a new actor instance.\r
523  *\r
524  * See also TRC_CFG_USE_IMPLICIT_IFE_RULES in trcConfig.h\r
525  *\r
526  * Example:\r
527  *\r
528  *              This example will generate two instances for each loop iteration.\r
529  *              The first instance ends at vTraceInstanceFinishedNow(), while the second\r
530  *      instance ends at the next xQueueReceive call.\r
531  *\r
532  *              while (1)\r
533  *              {\r
534  *          xQueueReceive(CommandQueue, &command, timeoutDuration);\r
535  *                      ProcessCommand(command);\r
536  *                      vTraceInstanceFinishedNow();\r
537  *                      DoSometingElse();\r
538  *          vTraceInstanceFinishedNext();\r
539  *      }\r
540  *****************************************************************************/\r
541 void vTraceInstanceFinishedNow(void)\r
542 {\r
543         prvTraceTaskInstanceFinish(1);\r
544 }\r
545 \r
546 /*******************************************************************************\r
547  * Interrupt recording functions\r
548  ******************************************************************************/\r
549 \r
550 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)\r
551 \r
552 /*******************************************************************************\r
553  * xTraceSetISRProperties\r
554  *\r
555  * Stores a name and priority level for an Interrupt Service Routine, to allow\r
556  * for better visualization. Returns a traceHandle used by vTraceStoreISRBegin.\r
557  *\r
558  * Example:\r
559  *       #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt\r
560  *       ...\r
561  *       traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);\r
562  *       ...\r
563  *       void ISR_handler()\r
564  *       {\r
565  *               vTraceStoreISRBegin(Timer1Handle);\r
566  *               ...\r
567  *               vTraceStoreISREnd(0);\r
568  *       }\r
569  ******************************************************************************/\r
570  traceHandle xTraceSetISRProperties(const char* name, uint8_t priority)\r
571 {\r
572         static traceHandle handle = 0;\r
573         TRACE_ASSERT(RecorderDataPtr != NULL, "Recorder not initialized, call vTraceEnable() first!", (traceHandle)0);\r
574         TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "xTraceSetISRProperties: Invalid value for handle", 0);\r
575         TRACE_ASSERT(name != NULL, "xTraceSetISRProperties: name == NULL", 0);\r
576 \r
577         handle++;\r
578 \r
579         prvTraceSetObjectName(TRACE_CLASS_ISR, handle, name);\r
580         prvTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority);\r
581 \r
582         return handle;\r
583 }\r
584 \r
585 /*******************************************************************************\r
586  * vTraceStoreISRBegin\r
587  *\r
588  * Registers the beginning of an Interrupt Service Routine, using a traceHandle\r
589  * provided by xTraceSetISRProperties.\r
590  *\r
591  * Example:\r
592  *       #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt\r
593  *       ...\r
594  *       traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1);\r
595  *       ...\r
596  *       void ISR_handler()\r
597  *       {\r
598  *               vTraceStoreISRBegin(Timer1Handle);\r
599  *               ...\r
600  *               vTraceStoreISREnd(0);\r
601  *       }\r
602  ******************************************************************************/\r
603 void vTraceStoreISRBegin(traceHandle handle)\r
604 {\r
605         TRACE_ALLOC_CRITICAL_SECTION();\r
606 \r
607         if (recorder_busy)\r
608         {\r
609                 /*************************************************************************\r
610                 * This occurs if an ISR calls a trace function, preempting a previous\r
611                 * trace call that is being processed in a different ISR or task.\r
612                 * If this occurs, there is probably a problem in the definition of the\r
613                 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and\r
614                 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt\r
615                 * and any other ISRs that calls the trace recorder directly or via\r
616                 * traced kernel functions. The ARM port disables all interrupts using the\r
617                 * PRIMASK register to avoid this issue.\r
618                 *************************************************************************/\r
619                 prvTraceError("vTraceStoreISRBegin - recorder busy! See code comment.");\r
620                 return;\r
621         }\r
622         trcCRITICAL_SECTION_BEGIN();\r
623 \r
624         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
625         {\r
626                 uint16_t dts4;\r
627 \r
628                 TRACE_ASSERT(handle != 0, "vTraceStoreISRBegin: Invalid ISR handle (NULL)", TRC_UNUSED);\r
629                 TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid ISR handle (> NISR)", TRC_UNUSED);\r
630 \r
631                 dts4 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
632 \r
633                 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
634                 {\r
635                         if (nISRactive < TRC_CFG_MAX_ISR_NESTING)\r
636                         {\r
637                                 TSEvent* ts;\r
638                                 uint8_t hnd8 = prvTraceGet8BitHandle(handle);\r
639                                 isrstack[nISRactive] = handle;\r
640                                 nISRactive++;\r
641                                 ts = (TSEvent*)prvTraceNextFreeEventBufferSlot();\r
642                                 if (ts != NULL)\r
643                                 {\r
644                                         ts->type = TS_ISR_BEGIN;\r
645                                         ts->dts = dts4;\r
646                                         ts->objHandle = hnd8;\r
647                                         prvTraceUpdateCounters();\r
648                                 }\r
649                         }\r
650                         else\r
651                         {\r
652                                 /* This should not occur unless something is very wrong */\r
653                                 prvTraceError("Too many nested interrupts!");\r
654                         }\r
655                 }\r
656         }\r
657         trcCRITICAL_SECTION_END();\r
658 }\r
659 \r
660 /*******************************************************************************\r
661  * vTraceStoreISREnd\r
662  *\r
663  * Registers the end of an Interrupt Service Routine.\r
664  *\r
665  * The parameter pendingISR indicates if the interrupt has requested a\r
666  * task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the\r
667  * interrupt is assumed to return to the previous context.\r
668  *\r
669  * Example:\r
670  *       #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt\r
671  *       traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder\r
672  *       ...\r
673  *       traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1);\r
674  *       ...\r
675  *       void ISR_handler()\r
676  *       {\r
677  *               vTraceStoreISRBegin(traceHandleIsrTimer1);\r
678  *               ...\r
679  *               vTraceStoreISREnd(0);\r
680  *       }\r
681  ******************************************************************************/\r
682 void vTraceStoreISREnd(int pendingISR)\r
683 {\r
684         TSEvent* ts;\r
685         uint16_t dts5;\r
686         uint8_t hnd8 = 0, type = 0;\r
687 \r
688         TRACE_ALLOC_CRITICAL_SECTION();\r
689 \r
690         if (! RecorderDataPtr->recorderActive ||  ! handle_of_last_logged_task)\r
691         {\r
692                 return;\r
693         }\r
694 \r
695         if (recorder_busy)\r
696         {\r
697                 /*************************************************************************\r
698                 * This occurs if an ISR calls a trace function, preempting a previous\r
699                 * trace call that is being processed in a different ISR or task.\r
700                 * If this occurs, there is probably a problem in the definition of the\r
701                 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and\r
702                 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt\r
703                 * and any other ISRs that calls the trace recorder directly or via\r
704                 * traced kernel functions. The ARM port disables all interrupts using the\r
705                 * PRIMASK register to avoid this issue.\r
706                 *************************************************************************/\r
707                 prvTraceError("vTraceStoreISREnd - recorder busy! See code comment.");\r
708                 return;\r
709         }\r
710 \r
711         if (nISRactive == 0)\r
712         {\r
713                 prvTraceError("Unmatched call to vTraceStoreISREnd (nISRactive == 0, expected > 0)");\r
714                 return;\r
715         }\r
716 \r
717         trcCRITICAL_SECTION_BEGIN();\r
718         isPendingContextSwitch |= pendingISR;   /* Is there a pending context switch right now? */\r
719         nISRactive--;\r
720         if (nISRactive > 0)\r
721         {\r
722                 /* Return to another ISR */\r
723                 type = TS_ISR_RESUME;\r
724                 hnd8 = prvTraceGet8BitHandle(isrstack[nISRactive - 1]); /* isrstack[nISRactive] is the handle of the ISR we're currently exiting. isrstack[nISRactive - 1] is the handle of the ISR that was executing previously. */\r
725         }\r
726         else if ((isPendingContextSwitch == 0) || (prvTraceIsSchedulerSuspended()))\r
727         {\r
728                 /* Return to interrupted task, if no context switch will occur in between. */\r
729                 type = TS_TASK_RESUME;\r
730                 hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task);\r
731         }\r
732 \r
733         if (type != 0)\r
734         {\r
735                 dts5 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
736                 ts = (TSEvent*)prvTraceNextFreeEventBufferSlot();\r
737                 if (ts != NULL)\r
738                 {\r
739                         ts->type = type;\r
740                         ts->objHandle = hnd8;\r
741                         ts->dts = dts5;\r
742                         prvTraceUpdateCounters();\r
743                 }\r
744         }\r
745 \r
746         trcCRITICAL_SECTION_END();\r
747 }\r
748 \r
749 #else\r
750 \r
751 /* ISR tracing is turned off */\r
752 void prvTraceIncreaseISRActive(void)\r
753 {\r
754         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
755                 nISRactive++;\r
756 }\r
757 \r
758 void prvTraceDecreaseISRActive(void)\r
759 {\r
760         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
761                 nISRactive--;\r
762 }\r
763 #endif /* (TRC_CFG_INCLUDE_ISR_TRACING == 1)*/\r
764 \r
765 \r
766 /********************************************************************************/\r
767 /* User Event functions                                                                                                                 */\r
768 /********************************************************************************/\r
769 \r
770 #define MAX_ARG_SIZE (4+32)\r
771 \r
772 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
773 static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value)\r
774 {\r
775         TRACE_ASSERT(buffer != NULL, "writeInt8: buffer == NULL", 0);\r
776 \r
777         if (i >= MAX_ARG_SIZE)\r
778         {\r
779                 return 255;\r
780         }\r
781 \r
782         ((uint8_t*)buffer)[i] = value;\r
783 \r
784         if (i + 1 > MAX_ARG_SIZE)\r
785         {\r
786                 return 255;\r
787         }\r
788 \r
789         return ((uint8_t) (i + 1));\r
790 }\r
791 #endif\r
792 \r
793 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
794 static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value)\r
795 {\r
796         TRACE_ASSERT(buffer != NULL, "writeInt16: buffer == NULL", 0);\r
797 \r
798         /* Align to multiple of 2 */\r
799         while ((i % 2) != 0)\r
800         {\r
801                 if (i >= MAX_ARG_SIZE)\r
802                 {\r
803                         return 255;\r
804                 }\r
805 \r
806                 ((uint8_t*)buffer)[i] = 0;\r
807                 i++;\r
808         }\r
809 \r
810         if (i + 2 > MAX_ARG_SIZE)\r
811         {\r
812                 return 255;\r
813         }\r
814 \r
815         ((uint16_t*)buffer)[i/2] = value;\r
816 \r
817         return ((uint8_t) (i + 2));\r
818 }\r
819 #endif\r
820 \r
821 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
822 static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value)\r
823 {\r
824         TRACE_ASSERT(buffer != NULL, "writeInt32: buffer == NULL", 0);\r
825 \r
826         /* A 32 bit value should begin at an even 4-byte address */\r
827         while ((i % 4) != 0)\r
828         {\r
829                 if (i >= MAX_ARG_SIZE)\r
830                 {\r
831                         return 255;\r
832                 }\r
833 \r
834                 ((uint8_t*)buffer)[i] = 0;\r
835                 i++;\r
836         }\r
837 \r
838         if (i + 4 > MAX_ARG_SIZE)\r
839         {\r
840                 return 255;\r
841         }\r
842 \r
843         ((uint32_t*)buffer)[i/4] = value;\r
844 \r
845         return ((uint8_t) (i + 4));\r
846 }\r
847 #endif\r
848 \r
849 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_INCLUDE_FLOAT_SUPPORT))\r
850 static uint8_t writeFloat(void * buffer, uint8_t i, float value)\r
851 {\r
852         TRACE_ASSERT(buffer != NULL, "writeFloat: buffer == NULL", 0);\r
853 \r
854         /* A 32 bit value should begin at an even 4-byte address */\r
855         while ((i % 4) != 0)\r
856         {\r
857                 if (i >= MAX_ARG_SIZE)\r
858                 {\r
859                         return 255;\r
860                 }\r
861 \r
862                 ((uint8_t*)buffer)[i] = 0;\r
863                 i++;\r
864         }\r
865 \r
866         if (i + 4 > MAX_ARG_SIZE)\r
867         {\r
868                 return 255;\r
869         }\r
870 \r
871         ((float*)buffer)[i/4] = value;\r
872 \r
873         return i + 4;\r
874 }\r
875 #endif\r
876 \r
877 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_INCLUDE_FLOAT_SUPPORT))\r
878 static uint8_t writeDouble(void * buffer, uint8_t i, double value)\r
879 {\r
880         uint32_t * dest;\r
881         uint32_t * src = (uint32_t*)&value;\r
882 \r
883         TRACE_ASSERT(buffer != NULL, "writeDouble: buffer == NULL", 0);\r
884 \r
885         /* The double is written as two 32 bit values, and should begin at an even\r
886         4-byte address (to avoid having to align with 8 byte) */\r
887         while (i % 4 != 0)\r
888         {\r
889                 if (i >= MAX_ARG_SIZE)\r
890                 {\r
891                         return 255;\r
892                 }\r
893 \r
894                 ((uint8_t*)buffer)[i] = 0;\r
895                 i++;\r
896         }\r
897 \r
898         if (i + 8 > MAX_ARG_SIZE)\r
899         {\r
900                 return 255;\r
901         }\r
902 \r
903         dest = &(((uint32_t *)buffer)[i/4]);\r
904 \r
905         dest[0] = src[0];\r
906         dest[1] = src[1];\r
907 \r
908         return i + 8;\r
909 }\r
910 #endif\r
911 \r
912 /*******************************************************************************\r
913  * prvTraceUserEventFormat\r
914  *\r
915  * Parses the format string and stores the arguments in the buffer.\r
916  ******************************************************************************/\r
917 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
918 static uint8_t prvTraceUserEventFormat(const char* formatStr, va_list vl, uint8_t* buffer, uint8_t byteOffset)\r
919 {\r
920         uint16_t formatStrIndex = 0;\r
921         uint8_t argCounter = 0;\r
922         uint8_t i = byteOffset;\r
923 \r
924         while (formatStr[formatStrIndex] != '\0')\r
925         {\r
926                 if (formatStr[formatStrIndex] == '%')\r
927                 {\r
928                         argCounter++;\r
929 \r
930                         if (argCounter > 15)\r
931                         {\r
932                                 prvTraceError("vTracePrintF - Too many arguments, max 15 allowed!");\r
933                                 return 0;\r
934                         }\r
935 \r
936                         formatStrIndex++;\r
937 \r
938                         while ((formatStr[formatStrIndex] >= '0' && formatStr[formatStrIndex] <= '9') || formatStr[formatStrIndex] == '#' || formatStr[formatStrIndex] == '.')\r
939                                 formatStrIndex++;\r
940 \r
941                         if (formatStr[formatStrIndex] != '\0')\r
942                         {\r
943                                 switch (formatStr[formatStrIndex])\r
944                                 {\r
945                                         case 'd':       i = writeInt32( buffer,\r
946                                                                                                 i,\r
947                                                                                                 (uint32_t)va_arg(vl, uint32_t));\r
948                                                                 break;\r
949                                         case 'x':\r
950                                         case 'X':\r
951                                         case 'u':       i = writeInt32( buffer,\r
952                                                                                                 i,\r
953                                                                                                 (uint32_t)va_arg(vl, uint32_t));\r
954                                                                 break;\r
955                                         case 's':       i = writeInt16( buffer,\r
956                                                                                                 i,\r
957                                                                                                 xTraceRegisterString((char*)va_arg(vl, char*)));\r
958                                                                 break;\r
959 \r
960 #if (TRC_CFG_INCLUDE_FLOAT_SUPPORT)\r
961                                         /* Yes, "double" as type also in the float\r
962                                         case. This since "float" is promoted into "double"\r
963                                         by the va_arg stuff. */\r
964                                         case 'f':       i = writeFloat( buffer,\r
965                                                                                                 i,\r
966                                                                                                 (float)va_arg(vl, double));\r
967                                                                 break;\r
968 #else\r
969                                         /* No support for floats, but attempt to store a float user event\r
970                                         avoid a possible crash due to float reference. Instead store the\r
971                                         data on uint_32 format (will not be displayed anyway). This is just\r
972                                         to keep va_arg and i consistent. */\r
973 \r
974                                         case 'f':       i = writeInt32( buffer,\r
975                                                                                                 i,\r
976                                                                                                 (uint32_t)va_arg(vl, double));\r
977                                                                 break;\r
978 #endif\r
979                                         case 'l':\r
980                                                                 formatStrIndex++;\r
981                                                                 switch (formatStr[formatStrIndex])\r
982                                                                 {\r
983 #if (TRC_CFG_INCLUDE_FLOAT_SUPPORT)\r
984                                                                         case 'f':       i = writeDouble(buffer,\r
985                                                                                                                                 i,\r
986                                                                                                                                 (double)va_arg(vl, double));\r
987                                                                                                 break;\r
988 #else\r
989                                                                         /* No support for floats, but attempt to store a float user event\r
990                                                                         avoid a possible crash due to float reference. Instead store the\r
991                                                                         data on uint_32 format (will not be displayed anyway). This is just\r
992                                                                         to keep va_arg and i consistent. */\r
993                                                                         case 'f':       i = writeInt32( buffer, /* In this case, the value will not be shown anyway */\r
994                                                                                                                                 i,\r
995                                                                                                                                 (uint32_t)va_arg(vl, double));\r
996 \r
997                                                                                                 i = writeInt32( buffer, /* Do it twice, to write in total 8 bytes */\r
998                                                                                                                                 i,\r
999                                                                                                                                 (uint32_t)va_arg(vl, double));\r
1000                                                                                 break;\r
1001 #endif\r
1002 \r
1003                                                                 }\r
1004                                                                 break;\r
1005                                         case 'h':\r
1006                                                                 formatStrIndex++;\r
1007                                                                 switch (formatStr[formatStrIndex])\r
1008                                                                 {\r
1009                                                                         case 'd':       i = writeInt16( buffer,\r
1010                                                                                                                                 i,\r
1011                                                                                                                                 (uint16_t)va_arg(vl, uint32_t));\r
1012                                                                                                 break;\r
1013                                                                         case 'u':       i = writeInt16( buffer,\r
1014                                                                                                                                 i,\r
1015                                                                                                                                 (uint16_t)va_arg(vl, uint32_t));\r
1016                                                                                                 break;\r
1017                                                                 }\r
1018                                                                 break;\r
1019                                         case 'b':\r
1020                                                                 formatStrIndex++;\r
1021                                                                 switch (formatStr[formatStrIndex])\r
1022                                                                 {\r
1023                                                                         case 'd':       i = writeInt8(  buffer,\r
1024                                                                                                                                 i,\r
1025                                                                                                                                 (uint8_t)va_arg(vl, uint32_t));\r
1026                                                                                                 break;\r
1027 \r
1028                                                                         case 'u':       i = writeInt8(  buffer,\r
1029                                                                                                                                 i,\r
1030                                                                                                                                 (uint8_t)va_arg(vl, uint32_t));\r
1031                                                                                                 break;\r
1032                                                                 }\r
1033                                                                 break;\r
1034                                 }\r
1035                         }\r
1036                         else\r
1037                                 break;\r
1038                 }\r
1039                 formatStrIndex++;\r
1040                 if (i == 255)\r
1041                 {\r
1042                         prvTraceError("vTracePrintF - Too large arguments, max 32 byte allowed!");\r
1043                         return 0;\r
1044                 }\r
1045         }\r
1046         return (uint8_t)(i+3)/4;\r
1047 }\r
1048 #endif\r
1049 \r
1050 /*******************************************************************************\r
1051  * prvTraceClearChannelBuffer\r
1052  *\r
1053  * Clears a number of items in the channel buffer, starting from nextSlotToWrite.\r
1054  ******************************************************************************/\r
1055 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))\r
1056 static void prvTraceClearChannelBuffer(uint32_t count)\r
1057 {\r
1058         uint32_t slots;\r
1059 \r
1060         TRACE_ASSERT((TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) >= count,\r
1061                 "prvTraceClearChannelBuffer: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED);\r
1062 \r
1063         /* Check if we're close to the end of the buffer */\r
1064         if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE))\r
1065         {\r
1066                 slots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */\r
1067                 (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, slots);\r
1068                 (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[0], 0, (count - slots));\r
1069         }\r
1070         else\r
1071                 (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, count);\r
1072 }\r
1073 #endif\r
1074 \r
1075 /*******************************************************************************\r
1076  * prvTraceCopyToDataBuffer\r
1077  *\r
1078  * Copies a number of items to the data buffer, starting from nextSlotToWrite.\r
1079  ******************************************************************************/\r
1080 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))\r
1081 static void prvTraceCopyToDataBuffer(uint32_t* data, uint32_t count)\r
1082 {\r
1083         uint32_t slots;\r
1084 \r
1085         TRACE_ASSERT(data != NULL,\r
1086                 "prvTraceCopyToDataBuffer: data == NULL.", TRC_UNUSED);\r
1087         TRACE_ASSERT(count <= (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE),\r
1088                 "prvTraceCopyToDataBuffer: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED);\r
1089         /* Check if we're close to the end of the buffer */\r
1090         if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE))\r
1091         {\r
1092                 slots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */\r
1093                 (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, slots * 4);\r
1094                 (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[0], data + slots, (count - slots) * 4);\r
1095         }\r
1096         else\r
1097         {\r
1098                 (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, count * 4);\r
1099         }\r
1100 }\r
1101 #endif\r
1102 \r
1103 /*******************************************************************************\r
1104  * prvTraceUBHelper1\r
1105  *\r
1106  * Calls on prvTraceUserEventFormat() to do the actual formatting, then goes on\r
1107  * to the next helper function.\r
1108  ******************************************************************************/\r
1109 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))\r
1110 static void prvTraceUBHelper1(traceUBChannel channel, traceString eventLabel, traceString formatLabel, va_list vl)\r
1111 {\r
1112         uint32_t data[(3 + MAX_ARG_SIZE) / 4];\r
1113         uint8_t byteOffset = 4; /* Need room for timestamp */\r
1114         uint8_t noOfSlots;\r
1115 \r
1116         if (channel == 0)\r
1117         {\r
1118                 /* We are dealing with an unknown channel format pair */\r
1119                 byteOffset = (uint8_t)(byteOffset + 4); /* Also need room for channel and format */\r
1120                 ((uint16_t*)data)[2] = eventLabel;\r
1121                 ((uint16_t*)data)[3] = formatLabel;\r
1122         }\r
1123 \r
1124         noOfSlots = prvTraceUserEventFormat((char*)&(RecorderDataPtr->SymbolTable.symbytes[formatLabel+4]), vl, (uint8_t*)data, byteOffset);\r
1125 \r
1126         prvTraceUBHelper2(channel, data, noOfSlots);\r
1127 }\r
1128 #endif\r
1129 \r
1130 /*******************************************************************************\r
1131  * prvTraceUBHelper2\r
1132  *\r
1133  * This function simply copies the data buffer to the actual user event buffer.\r
1134  ******************************************************************************/\r
1135 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))\r
1136 static void prvTraceUBHelper2(traceUBChannel channel, uint32_t* data, uint32_t noOfSlots)\r
1137 {\r
1138         static uint32_t old_timestamp = 0;\r
1139         uint32_t old_nextSlotToWrite = 0;\r
1140 \r
1141         TRACE_ALLOC_CRITICAL_SECTION();\r
1142 \r
1143         TRACE_ASSERT((TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) >= noOfSlots, "prvTraceUBHelper2: TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE is too small to handle this event.", TRC_UNUSED);\r
1144 \r
1145         trcCRITICAL_SECTION_BEGIN();\r
1146         /* Store the timestamp */\r
1147         prvTracePortGetTimeStamp(data);\r
1148 \r
1149         if (*data < old_timestamp)\r
1150         {\r
1151                 RecorderDataPtr->userEventBuffer.wraparoundCounter++;\r
1152         }\r
1153 \r
1154         old_timestamp = *data;\r
1155 \r
1156         /* Start by erasing any information in the channel buffer */\r
1157         prvTraceClearChannelBuffer(noOfSlots);\r
1158 \r
1159         prvTraceCopyToDataBuffer(data, noOfSlots); /* Will wrap around the data if necessary */\r
1160 \r
1161         old_nextSlotToWrite = RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Save the index that we want to write the channel data at when we're done */\r
1162         RecorderDataPtr->userEventBuffer.nextSlotToWrite = (RecorderDataPtr->userEventBuffer.nextSlotToWrite + noOfSlots) % (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE); /* Make sure we never end up outside the buffer */\r
1163 \r
1164         /* Write to the channel buffer to indicate that this user event is ready to be used */\r
1165         if (channel != 0)\r
1166         {\r
1167                 RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = channel;\r
1168         }\r
1169         else\r
1170         {\r
1171                 /* 0xFF indicates that this is not a normal channel id */\r
1172                 RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = (traceUBChannel)0xFF;\r
1173         }\r
1174         trcCRITICAL_SECTION_END();\r
1175 }\r
1176 #endif\r
1177 \r
1178 /*******************************************************************************\r
1179  * xTraceRegisterUBChannel\r
1180  *\r
1181  * Registers a channel for Separated User Events, i.e., those stored in the\r
1182  * separate user event buffer.\r
1183  *\r
1184  * Note: Only available if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is enabled in\r
1185  * trcSnapshotConfig.h\r
1186  ******************************************************************************/\r
1187 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))\r
1188 traceUBChannel xTraceRegisterUBChannel(traceString channel, traceString formatStr)\r
1189 {\r
1190         uint8_t i;\r
1191         traceUBChannel retVal = 0;\r
1192 \r
1193         TRACE_ALLOC_CRITICAL_SECTION();\r
1194 \r
1195         TRACE_ASSERT(formatStr != 0, "xTraceRegisterChannelFormat: formatStr == 0", (traceUBChannel)0);\r
1196 \r
1197         trcCRITICAL_SECTION_BEGIN();\r
1198         for (i = 1; i <= (TRC_CFG_UB_CHANNELS); i++) /* Size of the channels buffer is TRC_CFG_UB_CHANNELS + 1. Index 0 is unused. */\r
1199         {\r
1200                 if(RecorderDataPtr->userEventBuffer.channels[i].name == 0 && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == 0)\r
1201                 {\r
1202                         /* Found empty slot */\r
1203                         RecorderDataPtr->userEventBuffer.channels[i].name = channel;\r
1204                         RecorderDataPtr->userEventBuffer.channels[i].defaultFormat = formatStr;\r
1205                         retVal = (traceUBChannel)i;\r
1206                         break;\r
1207                 }\r
1208 \r
1209                 if (RecorderDataPtr->userEventBuffer.channels[i].name == channel && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == formatStr)\r
1210                 {\r
1211                         /* Found a match */\r
1212                         retVal = (traceUBChannel)i;\r
1213                         break;\r
1214                 }\r
1215         }\r
1216         trcCRITICAL_SECTION_END();\r
1217 \r
1218         return retVal;\r
1219 }\r
1220 #endif\r
1221 \r
1222 /******************************************************************************\r
1223  * vTraceUBData\r
1224  *\r
1225  * Slightly faster version of vTracePrintF() due to no lookups.\r
1226  *\r
1227  * Note: This is only available if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER is\r
1228  * enabled in trcSnapshotConfig.h\r
1229  ******************************************************************************/\r
1230 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))\r
1231 void vTraceUBData(traceUBChannel channelPair, ...)\r
1232 {\r
1233         va_list vl;\r
1234 \r
1235         TRACE_ASSERT(channelPair != 0, "vTraceUBData: Not a valid traceUBChannel!", TRC_UNUSED);\r
1236 \r
1237         va_start(vl, channelPair);\r
1238         vTraceUBData_Helper(channelPair, vl);\r
1239         va_end(vl);\r
1240 }\r
1241 #endif\r
1242 \r
1243 /* Extracts the channel name and format string from the traceUBChannel, then calls prvTraceUBHelper1. */\r
1244 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))\r
1245 void vTraceUBData_Helper(traceUBChannel channelPair, va_list vl)\r
1246 {\r
1247         traceString channel;\r
1248         traceString formatStr;\r
1249 \r
1250         TRACE_ASSERT(channelPair != 0, "vTraceUBData_Helper: channelPair == 0", TRC_UNUSED);\r
1251         TRACE_ASSERT(channelPair <= (TRC_CFG_UB_CHANNELS), "vTraceUBData_Helper: ", TRC_UNUSED);\r
1252 \r
1253         channel = RecorderDataPtr->userEventBuffer.channels[channelPair].name;\r
1254         formatStr = RecorderDataPtr->userEventBuffer.channels[channelPair].defaultFormat;\r
1255 \r
1256         prvTraceUBHelper1(channelPair, channel, formatStr, vl);\r
1257 }\r
1258 #endif\r
1259 \r
1260 /******************************************************************************\r
1261  * vTraceUBEvent\r
1262  *\r
1263  * Slightly faster version of ... due to no lookups.\r
1264  ******************************************************************************/\r
1265 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1))\r
1266 void vTraceUBEvent(traceUBChannel channelPair)\r
1267 {\r
1268         uint32_t data[(3 + MAX_ARG_SIZE) / 4];\r
1269 \r
1270         TRACE_ASSERT(channelPair != 0, "vTraceUBEvent: channelPair == 0", TRC_UNUSED);\r
1271         TRACE_ASSERT(channelPair <= (TRC_CFG_UB_CHANNELS), "vTraceUBEvent: ", TRC_UNUSED);\r
1272 \r
1273         prvTraceUBHelper2(channelPair, data, 1); /* Only need one slot for timestamp */\r
1274 }\r
1275 #endif\r
1276 \r
1277 /******************************************************************************\r
1278  * vTracePrintF\r
1279  *\r
1280  * Generates User Event with formatted text and data, similar to a "printf".\r
1281  * It is very fast compared to a normal "printf" since this function only\r
1282  * stores the arguments. The actual formatting is done\r
1283  * on the host PC when the trace is displayed in the viewer tool.\r
1284  *\r
1285  * User Event labels are created using xTraceRegisterString.\r
1286  * Example:\r
1287  *\r
1288  *       traceString adc_uechannel = xTraceRegisterString("ADC User Events");\r
1289  *       ...\r
1290  *       vTracePrintF(adc_uechannel,\r
1291  *                               "ADC channel %d: %lf volts",\r
1292  *                               ch, (double)adc_reading/(double)scale);\r
1293  *\r
1294  * This can be combined into one line, if desired, but this is slower:\r
1295  *\r
1296  *       vTracePrintF(xTraceRegisterString("ADC User Events"),\r
1297  *                               "ADC channel %d: %lf volts",\r
1298  *                               ch, (double)adc_reading/(double)scale);\r
1299  *\r
1300  * Calling xTraceRegisterString multiple times will not create duplicate entries, but\r
1301  * it is of course faster to just do it once, and then keep the handle for later\r
1302  * use. If you don't have any data arguments, only a text label/string, it is\r
1303  * better to use vTracePrint - it is faster.\r
1304  *\r
1305  * Format specifiers supported:\r
1306  * %d - 32 bit signed integer\r
1307  * %u - 32 bit unsigned integer\r
1308  * %f - 32 bit float\r
1309  * %s - string (is copied to the recorder symbol table)\r
1310  * %hd - 16 bit signed integer\r
1311  * %hu - 16 bit unsigned integer\r
1312  * %bd - 8 bit signed integer\r
1313  * %bu - 8 bit unsigned integer\r
1314  * %lf - double-precision float (Note! See below...)\r
1315  *\r
1316  * Up to 15 data arguments are allowed, with a total size of maximum 32 byte.\r
1317  * In case this is exceeded, the user event is changed into an error message.\r
1318  *\r
1319  * The data is stored in trace buffer, and is packed to allow storing multiple\r
1320  * smaller data entries in the same 4-byte record, e.g., four 8-bit values.\r
1321  * A string requires two bytes, as the symbol table is limited to 64K. Storing\r
1322  * a double (%lf) uses two records, so this is quite costly. Use float (%f)\r
1323  * unless the higher precision is really necessary.\r
1324  *\r
1325  * Note that the double-precision float (%lf) assumes a 64 bit double\r
1326  * representation. This does not seem to be the case on e.g. PIC24 and PIC32.\r
1327  * Before using a %lf argument on a 16-bit MCU, please verify that\r
1328  * "sizeof(double)" actually gives 8 as expected. If not, use %f instead.\r
1329  ******************************************************************************/\r
1330 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
1331 void vTracePrintF(traceString eventLabel, const char* formatStr, ...)\r
1332 {\r
1333         va_list vl;\r
1334 \r
1335         va_start(vl, formatStr);\r
1336         vTracePrintF_Helper(eventLabel, formatStr, vl);\r
1337         va_end(vl);\r
1338 }\r
1339 #endif\r
1340 \r
1341 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
1342 void vTracePrintF_Helper(traceString eventLabel, const char* formatStr, va_list vl)\r
1343 {\r
1344 #if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 0)\r
1345         uint32_t noOfSlots;\r
1346         UserEvent* ue1;\r
1347         uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];\r
1348         TRACE_ALLOC_CRITICAL_SECTION();\r
1349 \r
1350         TRACE_ASSERT(formatStr != NULL, "vTracePrintF_Helper: formatStr == NULL", TRC_UNUSED);\r
1351 \r
1352         trcCRITICAL_SECTION_BEGIN();\r
1353 \r
1354         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
1355         {\r
1356                 /* First, write the "primary" user event entry in the local buffer, but\r
1357                 let the event type be "EVENT_BEING_WRITTEN" for now...*/\r
1358 \r
1359                 ue1 = (UserEvent*)(&tempDataBuffer[0]);\r
1360 \r
1361                 ue1->type = EVENT_BEING_WRITTEN;         /* Update this as the last step */\r
1362 \r
1363                 noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4);\r
1364 \r
1365                 /* Store the format string, with a reference to the channel symbol */\r
1366                 ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel);\r
1367 \r
1368                 ue1->dts = (uint8_t)prvTraceGetDTS(0xFF);\r
1369 \r
1370                  /* prvTraceGetDTS might stop the recorder in some cases... */\r
1371                 if (RecorderDataPtr->recorderActive)\r
1372                 {\r
1373 \r
1374                         /* If the data does not fit in the remaining main buffer, wrap around to\r
1375                         0 if allowed, otherwise stop the recorder and quit). */\r
1376                         if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents)\r
1377                         {\r
1378                                 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)\r
1379                                 (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],\r
1380                                                 0,\r
1381                                                 (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4);\r
1382                                 RecorderDataPtr->nextFreeIndex = 0;\r
1383                                 RecorderDataPtr->bufferIsFull = 1;\r
1384                                 #else\r
1385 \r
1386                                 /* Stop recorder, since the event data will not fit in the\r
1387                                 buffer and not circular buffer in this case... */\r
1388                                 vTraceStop();\r
1389                                 #endif\r
1390                         }\r
1391 \r
1392                         /* Check if recorder has been stopped (i.e., vTraceStop above) */\r
1393                         if (RecorderDataPtr->recorderActive)\r
1394                         {\r
1395                                 /* Check that the buffer to be overwritten does not contain any user\r
1396                                 events that would be partially overwritten. If so, they must be "killed"\r
1397                                 by replacing the user event and following data with NULL events (i.e.,\r
1398                                 using a memset to zero).*/\r
1399                                 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)\r
1400                                 prvCheckDataToBeOverwrittenForMultiEntryEvents((uint8_t)noOfSlots);\r
1401                                 #endif\r
1402                                 /* Copy the local buffer to the main buffer */\r
1403                                 (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],\r
1404                                                 tempDataBuffer,\r
1405                                                 noOfSlots * 4);\r
1406 \r
1407                                 /* Update the event type, i.e., number of data entries following the\r
1408                                 main USER_EVENT entry (Note: important that this is after the memcpy,\r
1409                                 but within the critical section!)*/\r
1410                                 RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] =\r
1411                                  (uint8_t) ( USER_EVENT + noOfSlots - 1 );\r
1412 \r
1413                                 /* Update the main buffer event index (already checked that it fits in\r
1414                                 the buffer, so no need to check for wrapping)*/\r
1415 \r
1416                                 RecorderDataPtr->nextFreeIndex += noOfSlots;\r
1417                                 RecorderDataPtr->numEvents += noOfSlots;\r
1418 \r
1419                                 if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE))\r
1420                                 {\r
1421                                         #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)\r
1422                                         /* We have reached the end, but this is a ring buffer. Start from the beginning again. */\r
1423                                         RecorderDataPtr->bufferIsFull = 1;\r
1424                                         RecorderDataPtr->nextFreeIndex = 0;\r
1425                                         #else\r
1426                                         /* We have reached the end so we stop. */\r
1427                                         vTraceStop();\r
1428                                         #endif\r
1429                                 }\r
1430                         }\r
1431 \r
1432                         #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)\r
1433                         /* Make sure the next entry is cleared correctly */\r
1434                         prvCheckDataToBeOverwrittenForMultiEntryEvents(1);\r
1435                         #endif\r
1436 \r
1437                 }\r
1438         }\r
1439         trcCRITICAL_SECTION_END();\r
1440 \r
1441 #elif (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
1442         /* Use the separate user event buffer */\r
1443         traceString formatLabel;\r
1444         traceUBChannel channel;\r
1445 \r
1446         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
1447         {\r
1448                 formatLabel = xTraceRegisterString(formatStr);\r
1449 \r
1450                 channel = xTraceRegisterUBChannel(eventLabel, formatLabel);\r
1451 \r
1452                 prvTraceUBHelper1(channel, eventLabel, formatLabel, vl);\r
1453         }\r
1454 #endif\r
1455 }\r
1456 #endif\r
1457 \r
1458 /******************************************************************************\r
1459  * vTracePrint\r
1460  *\r
1461  * Basic user event\r
1462  *\r
1463  * Generates a User Event with a text label. The label is created/looked up\r
1464  * in the symbol table using xTraceRegisterString.\r
1465  ******************************************************************************/\r
1466 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
1467 void vTracePrint(traceString chn, const char* str)\r
1468 {\r
1469 #if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 0)\r
1470         UserEvent* ue;\r
1471         uint8_t dts1;\r
1472         TRACE_ALLOC_CRITICAL_SECTION();\r
1473 \r
1474         trcCRITICAL_SECTION_BEGIN();\r
1475         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
1476         {\r
1477                 dts1 = (uint8_t)prvTraceGetDTS(0xFF);\r
1478                 ue = (UserEvent*) prvTraceNextFreeEventBufferSlot();\r
1479                 if (ue != NULL)\r
1480                 {\r
1481                         ue->dts = dts1;\r
1482                         ue->type = USER_EVENT;\r
1483                         ue->payload = prvTraceOpenSymbol(str, chn);\r
1484                         prvTraceUpdateCounters();\r
1485                 }\r
1486         }\r
1487         trcCRITICAL_SECTION_END();\r
1488 \r
1489 #elif (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
1490         traceUBChannel channel;\r
1491         uint32_t noOfSlots = 1;\r
1492         uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];\r
1493         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
1494         {\r
1495                 traceString trcStr = prvTraceOpenSymbol(str, chn);\r
1496                 channel = xTraceRegisterUBChannel(chn, trcStr);\r
1497 \r
1498                 if (channel == 0)\r
1499                 {\r
1500                         /* We are dealing with an unknown channel format pair */\r
1501                         noOfSlots++; /* Also need room for channel and format */\r
1502                         ((uint16_t*)tempDataBuffer)[2] = chn;\r
1503                         ((uint16_t*)tempDataBuffer)[3] = trcStr;\r
1504                 }\r
1505 \r
1506                 prvTraceUBHelper2(channel, tempDataBuffer, noOfSlots);\r
1507         }\r
1508 #endif\r
1509 }\r
1510 #endif\r
1511 \r
1512 /*******************************************************************************\r
1513  * xTraceRegisterString\r
1514  *\r
1515  * Register strings in the recorder, e.g. for names of user event channels.\r
1516  *\r
1517  * Example:\r
1518  *       myEventHandle = xTraceRegisterString("MyUserEvent");\r
1519  *       ...\r
1520  *       vTracePrintF(myEventHandle, "My value is: %d", myValue);\r
1521  ******************************************************************************/\r
1522 #if ((TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1))\r
1523 traceString xTraceRegisterString(const char* label)\r
1524 {\r
1525         TRACE_ASSERT(label != NULL, "xTraceRegisterString: label == NULL", (traceString)0);\r
1526         TRACE_ASSERT(RecorderDataPtr != NULL, "Recorder not initialized, call vTraceEnable() first!", (traceHandle)0);\r
1527         return prvTraceOpenSymbol(label, 0);\r
1528 }\r
1529 #endif\r
1530 \r
1531 \r
1532 #if ((!defined TRC_CFG_INCLUDE_READY_EVENTS) || (TRC_CFG_INCLUDE_READY_EVENTS == 1))\r
1533 \r
1534 void prvTraceSetReadyEventsEnabled(int status)\r
1535 {\r
1536         readyEventsEnabled = status;\r
1537 }\r
1538 \r
1539 /*******************************************************************************\r
1540  * prvTraceStoreTaskReady\r
1541  *\r
1542  * This function stores a ready state for the task handle sent in as parameter.\r
1543  ******************************************************************************/\r
1544 void prvTraceStoreTaskReady(traceHandle handle)\r
1545 {\r
1546         uint16_t dts3;\r
1547         TREvent* tr;\r
1548         uint8_t hnd8;\r
1549 \r
1550         TRACE_ALLOC_CRITICAL_SECTION();\r
1551 \r
1552         if (handle == 0)\r
1553         {\r
1554                 /*  On FreeRTOS v7.3.0, this occurs when creating tasks due to a bad\r
1555                 placement of the trace macro. In that case, the events are ignored. */\r
1556                 return;\r
1557         }\r
1558 \r
1559         if (! readyEventsEnabled)\r
1560         {\r
1561                 /* When creating tasks, ready events are also created. If creating\r
1562                 a "hidden" (not traced) task, we must therefore disable recording\r
1563                 of ready events to avoid an undesired ready event... */\r
1564                 return;\r
1565         }\r
1566 \r
1567         TRACE_ASSERT(handle <= (TRC_CFG_NTASK), "prvTraceStoreTaskReady: Invalid value for handle", TRC_UNUSED);\r
1568 \r
1569         if (recorder_busy)\r
1570         {\r
1571                 /*************************************************************************\r
1572                 * This occurs if an ISR calls a trace function, preempting a previous\r
1573                 * trace call that is being processed in a different ISR or task.\r
1574                 * If this occurs, there is probably a problem in the definition of the\r
1575                 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and\r
1576                 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt\r
1577                 * and any other ISRs that calls the trace recorder directly or via\r
1578                 * traced kernel functions. The ARM port disables all interrupts using the\r
1579                 * PRIMASK register to avoid this issue.\r
1580                 *************************************************************************/\r
1581                 prvTraceError("Recorder busy - high priority ISR using syscall? (1)");\r
1582                 return;\r
1583         }\r
1584 \r
1585         trcCRITICAL_SECTION_BEGIN();\r
1586         if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
1587         {\r
1588                 dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
1589                 hnd8 = prvTraceGet8BitHandle(handle);\r
1590                 tr = (TREvent*)prvTraceNextFreeEventBufferSlot();\r
1591                 if (tr != NULL)\r
1592                 {\r
1593                         tr->type = DIV_TASK_READY;\r
1594                         tr->dts = dts3;\r
1595                         tr->objHandle = hnd8;\r
1596                         prvTraceUpdateCounters();\r
1597                 }\r
1598         }\r
1599         trcCRITICAL_SECTION_END();\r
1600 }\r
1601 #endif\r
1602 \r
1603 /*******************************************************************************\r
1604  * prvTraceStoreLowPower\r
1605  *\r
1606  * This function stores a low power state.\r
1607  ******************************************************************************/\r
1608 void prvTraceStoreLowPower(uint32_t flag)\r
1609 {\r
1610         uint16_t dts;\r
1611         LPEvent* lp;\r
1612         TRACE_ALLOC_CRITICAL_SECTION();\r
1613 \r
1614         TRACE_ASSERT(flag <= 1, "prvTraceStoreLowPower: Invalid flag value", TRC_UNUSED);\r
1615 \r
1616         if (recorder_busy)\r
1617         {\r
1618                 /*************************************************************************\r
1619                 * This occurs if an ISR calls a trace function, preempting a previous\r
1620                 * trace call that is being processed in a different ISR or task.\r
1621                 * If this occurs, there is probably a problem in the definition of the\r
1622                 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and\r
1623                 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt\r
1624                 * and any other ISRs that calls the trace recorder directly or via\r
1625                 * traced kernel functions. The ARM port disables all interrupts using the\r
1626                 * PRIMASK register to avoid this issue.\r
1627                 *************************************************************************/\r
1628                 prvTraceError("Recorder busy - high priority ISR using syscall? (1)");\r
1629                 return;\r
1630         }\r
1631 \r
1632         trcCRITICAL_SECTION_BEGIN();\r
1633         if (RecorderDataPtr->recorderActive)\r
1634         {\r
1635                 dts = (uint16_t)prvTraceGetDTS(0xFFFF);\r
1636                 lp = (LPEvent*)prvTraceNextFreeEventBufferSlot();\r
1637                 if (lp != NULL)\r
1638                 {\r
1639                         lp->type = (uint8_t) (LOW_POWER_BEGIN + ( uint8_t ) flag); /* BEGIN or END depending on flag */\r
1640                         lp->dts = dts;\r
1641                         prvTraceUpdateCounters();\r
1642                 }\r
1643         }\r
1644         trcCRITICAL_SECTION_END();\r
1645 }\r
1646 \r
1647 /*******************************************************************************\r
1648  * vTraceStoreMemMangEvent\r
1649  *\r
1650  * This function stores malloc and free events. Each call requires two records,\r
1651  * for size and address respectively. The event code parameter (ecode) is applied\r
1652  * to the first record (size) and the following address record gets event\r
1653  * code "ecode + 1", so make sure this is respected in the event code table.\r
1654  * Note: On "free" calls, the signed_size parameter should be negative.\r
1655  ******************************************************************************/\r
1656 #if (TRC_CFG_INCLUDE_MEMMANG_EVENTS == 1)\r
1657 #if (TRC_CFG_SCHEDULING_ONLY == 0)\r
1658 void vTraceStoreMemMangEvent(uint32_t ecode, uint32_t address, int32_t signed_size)\r
1659 {\r
1660         uint8_t dts1;\r
1661         MemEventSize * ms;\r
1662         MemEventAddr * ma;\r
1663         uint16_t size_low;\r
1664         uint16_t addr_low;\r
1665         uint8_t addr_high;\r
1666         uint32_t size;\r
1667         TRACE_ALLOC_CRITICAL_SECTION();\r
1668 \r
1669         if (RecorderDataPtr == NULL)\r
1670         {\r
1671                 /* Occurs in vTraceInitTraceData, if using dynamic allocation. */\r
1672                 return;\r
1673         }\r
1674 \r
1675         if (signed_size < 0)\r
1676                 size = (uint32_t)(- signed_size);\r
1677         else\r
1678                 size = (uint32_t)(signed_size);\r
1679 \r
1680         trcCRITICAL_SECTION_BEGIN();\r
1681 \r
1682         heapMemUsage = heapMemUsage + (uint32_t)signed_size;\r
1683 \r
1684         if (RecorderDataPtr->recorderActive)\r
1685         {\r
1686                 dts1 = (uint8_t)prvTraceGetDTS(0xFF);\r
1687                 size_low = (uint16_t)prvTraceGetParam(0xFFFF, size);\r
1688                 ms = (MemEventSize *)prvTraceNextFreeEventBufferSlot();\r
1689 \r
1690                 if (ms != NULL)\r
1691                 {\r
1692                         ms->dts = dts1;\r
1693                         ms->type = NULL_EVENT; /* Updated when all events are written */\r
1694                         ms->size = size_low;\r
1695                         prvTraceUpdateCounters();\r
1696 \r
1697                         /* Storing a second record with address (signals "failed" if null) */\r
1698                         #if (TRC_CFG_HEAP_SIZE_BELOW_16M)\r
1699                                 /* If the heap address range is within 16 MB, i.e., the upper 8 bits\r
1700                                 of addresses are constant, this optimization avoids storing an extra\r
1701                                 event record by ignoring the upper 8 bit of the address */\r
1702                                 addr_low = address & 0xFFFF;\r
1703                                 addr_high = (address >> 16) & 0xFF;\r
1704                         #else\r
1705                                 /* The whole 32 bit address is stored using a second event record\r
1706                                 for the upper 16 bit */\r
1707                                 addr_low = (uint16_t)prvTraceGetParam(0xFFFF, address);\r
1708                                 addr_high = 0;\r
1709                         #endif\r
1710 \r
1711                         ma = (MemEventAddr *) prvTraceNextFreeEventBufferSlot();\r
1712                         if (ma != NULL)\r
1713                         {\r
1714                                 ma->addr_low = addr_low;\r
1715                                 ma->addr_high = addr_high;\r
1716                                 ma->type = (uint8_t) (ecode  + 1); /* Note this! */\r
1717                                 ms->type = (uint8_t) ecode;\r
1718                                 prvTraceUpdateCounters();\r
1719                                 RecorderDataPtr->heapMemUsage = heapMemUsage;\r
1720                         }\r
1721                 }\r
1722         }\r
1723         trcCRITICAL_SECTION_END();\r
1724 }\r
1725 #endif /* TRC_CFG_SCHEDULING_ONLY */\r
1726 #endif\r
1727 \r
1728 /*******************************************************************************\r
1729  * prvTraceStoreKernelCall\r
1730  *\r
1731  * This is the main integration point for storing kernel calls, and\r
1732  * is called by the hooks in trcKernelHooks.h (see trcKernelPort.h for event codes).\r
1733  ******************************************************************************/\r
1734 #if (TRC_CFG_SCHEDULING_ONLY == 0)\r
1735 void prvTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber)\r
1736 {\r
1737         KernelCall * kse;\r
1738         uint16_t dts1;\r
1739         uint8_t hnd8;\r
1740         TRACE_ALLOC_CRITICAL_SECTION();\r
1741 \r
1742         TRACE_ASSERT(ecode < 0xFF, "prvTraceStoreKernelCall: ecode >= 0xFF", TRC_UNUSED);\r
1743         TRACE_ASSERT(objectClass < TRACE_NCLASSES, "prvTraceStoreKernelCall: objectClass >= TRACE_NCLASSES", TRC_UNUSED);\r
1744         TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "prvTraceStoreKernelCall: Invalid value for objectNumber", TRC_UNUSED);\r
1745 \r
1746         if (recorder_busy)\r
1747         {\r
1748                 /*************************************************************************\r
1749                 * This occurs if an ISR calls a trace function, preempting a previous\r
1750                 * trace call that is being processed in a different ISR or task.\r
1751                 * If this occurs, there is probably a problem in the definition of the\r
1752                 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and\r
1753                 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt\r
1754                 * and any other ISRs that calls the trace recorder directly or via\r
1755                 * traced kernel functions. The ARM port disables all interrupts using the\r
1756                 * PRIMASK register to avoid this issue.\r
1757                 *************************************************************************/\r
1758                 prvTraceError("Recorder busy - high priority ISR using syscall? (2)");\r
1759                 return;\r
1760         }\r
1761 \r
1762         if (handle_of_last_logged_task == 0)\r
1763         {\r
1764                 return;\r
1765         }\r
1766 \r
1767         trcCRITICAL_SECTION_BEGIN();\r
1768         if (RecorderDataPtr->recorderActive)\r
1769         {\r
1770                 dts1 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
1771                 hnd8 = prvTraceGet8BitHandle((traceHandle)objectNumber);\r
1772                 kse = (KernelCall*) prvTraceNextFreeEventBufferSlot();\r
1773                 if (kse != NULL)\r
1774                 {\r
1775                         kse->dts = dts1;\r
1776                         kse->type = (uint8_t)ecode;\r
1777                         kse->objHandle = hnd8;\r
1778                         prvTraceUpdateCounters();\r
1779                 }\r
1780         }\r
1781         trcCRITICAL_SECTION_END();\r
1782 }\r
1783 #endif /* TRC_CFG_SCHEDULING_ONLY */\r
1784 \r
1785 /*******************************************************************************\r
1786  * prvTraceStoreKernelCallWithParam\r
1787  *\r
1788  * Used for storing kernel calls with a handle and a numeric parameter. If the\r
1789  * numeric parameter does not fit in one byte, and extra XPS event is inserted\r
1790  * before the kernel call event containing the three upper bytes.\r
1791  ******************************************************************************/\r
1792 #if (TRC_CFG_SCHEDULING_ONLY == 0)\r
1793 void prvTraceStoreKernelCallWithParam(uint32_t evtcode,\r
1794                                                                         traceObjectClass objectClass,\r
1795                                                                         uint32_t objectNumber,\r
1796                                                                         uint32_t param)\r
1797 {\r
1798         KernelCallWithParamAndHandle * kse;\r
1799         uint8_t dts2;\r
1800         uint8_t hnd8;\r
1801         uint8_t p8;\r
1802         TRACE_ALLOC_CRITICAL_SECTION();\r
1803 \r
1804         TRACE_ASSERT(evtcode < 0xFF, "prvTraceStoreKernelCallWithParam: evtcode >= 0xFF", TRC_UNUSED);\r
1805         TRACE_ASSERT(objectClass < TRACE_NCLASSES, "prvTraceStoreKernelCallWithParam: objectClass >= TRACE_NCLASSES", TRC_UNUSED);\r
1806         TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "prvTraceStoreKernelCallWithParam: Invalid value for objectNumber", TRC_UNUSED);\r
1807 \r
1808         if (recorder_busy)\r
1809         {\r
1810                 /*************************************************************************\r
1811                 * This occurs if an ISR calls a trace function, preempting a previous\r
1812                 * trace call that is being processed in a different ISR or task.\r
1813                 * If this occurs, there is probably a problem in the definition of the\r
1814                 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and\r
1815                 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt\r
1816                 * and any other ISRs that calls the trace recorder directly or via\r
1817                 * traced kernel functions. The ARM port disables all interrupts using the\r
1818                 * PRIMASK register to avoid this issue.\r
1819                 *************************************************************************/\r
1820                 prvTraceError("Recorder busy - high priority ISR using syscall? (3)");\r
1821                 return;\r
1822         }\r
1823 \r
1824         trcCRITICAL_SECTION_BEGIN();\r
1825         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
1826         {\r
1827                 dts2 = (uint8_t)prvTraceGetDTS(0xFF);\r
1828                 p8 = (uint8_t) prvTraceGetParam(0xFF, param);\r
1829                 hnd8 = prvTraceGet8BitHandle((traceHandle)objectNumber);\r
1830                 kse = (KernelCallWithParamAndHandle*) prvTraceNextFreeEventBufferSlot();\r
1831                 if (kse != NULL)\r
1832                 {\r
1833                         kse->dts = dts2;\r
1834                         kse->type = (uint8_t)evtcode;\r
1835                         kse->objHandle = hnd8;\r
1836                         kse->param = p8;\r
1837                         prvTraceUpdateCounters();\r
1838                 }\r
1839         }\r
1840         trcCRITICAL_SECTION_END();\r
1841 }\r
1842 #endif /* TRC_CFG_SCHEDULING_ONLY */\r
1843 \r
1844 \r
1845 /*******************************************************************************\r
1846  * prvTraceGetParam\r
1847  *\r
1848  * Used for storing extra bytes for kernel calls with numeric parameters.\r
1849  *\r
1850  * May only be called within a critical section!\r
1851  ******************************************************************************/\r
1852 #if (TRC_CFG_SCHEDULING_ONLY == 0)\r
1853 static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param)\r
1854 {\r
1855         XPSEvent* xps;\r
1856 \r
1857         TRACE_ASSERT(param_max == 0xFF || param_max == 0xFFFF,\r
1858                 "prvTraceGetParam: Invalid value for param_max", param);\r
1859 \r
1860         if (param <= param_max)\r
1861         {\r
1862                 return param;\r
1863         }\r
1864         else\r
1865         {\r
1866                 xps = (XPSEvent*) prvTraceNextFreeEventBufferSlot();\r
1867                 if (xps != NULL)\r
1868                 {\r
1869                         xps->type = DIV_XPS;\r
1870                         xps->xps_8 = (uint8_t)((param & (0xFF00 & ~param_max)) >> 8);\r
1871                         xps->xps_16 = (uint16_t)((param & (0xFFFF0000 & ~param_max)) >> 16);\r
1872                         prvTraceUpdateCounters();\r
1873                 }\r
1874 \r
1875                 return param & param_max;\r
1876         }\r
1877 }\r
1878 #endif\r
1879 \r
1880 /*******************************************************************************\r
1881  * prvTraceStoreKernelCallWithNumericParamOnly\r
1882  *\r
1883  * Used for storing kernel calls with numeric parameters only. This is\r
1884  * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment.\r
1885  ******************************************************************************/\r
1886 #if (TRC_CFG_SCHEDULING_ONLY == 0)\r
1887 void prvTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param)\r
1888 {\r
1889         KernelCallWithParam16 * kse;\r
1890         uint8_t dts6;\r
1891         uint16_t restParam;\r
1892         TRACE_ALLOC_CRITICAL_SECTION();\r
1893 \r
1894         restParam = 0;\r
1895 \r
1896         TRACE_ASSERT(evtcode < 0xFF, "prvTraceStoreKernelCallWithNumericParamOnly: Invalid value for evtcode", TRC_UNUSED);\r
1897 \r
1898         if (recorder_busy)\r
1899         {\r
1900                 /*************************************************************************\r
1901                 * This occurs if an ISR calls a trace function, preempting a previous\r
1902                 * trace call that is being processed in a different ISR or task.\r
1903                 * If this occurs, there is probably a problem in the definition of the\r
1904                 * recorder's internal critical sections (TRACE_ENTER_CRITICAL_SECTION and\r
1905                 * TRACE_EXIT_CRITICAL_SECTION). They must disable the RTOS tick interrupt\r
1906                 * and any other ISRs that calls the trace recorder directly or via\r
1907                 * traced kernel functions. The ARM port disables all interrupts using the\r
1908                 * PRIMASK register to avoid this issue.\r
1909                 *************************************************************************/\r
1910                 prvTraceError("Recorder busy - high priority ISR using syscall? (4)");\r
1911                 return;\r
1912         }\r
1913 \r
1914         trcCRITICAL_SECTION_BEGIN();\r
1915         if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
1916         {\r
1917                 dts6 = (uint8_t)prvTraceGetDTS(0xFF);\r
1918                 restParam = (uint16_t)prvTraceGetParam(0xFFFF, param);\r
1919                 kse = (KernelCallWithParam16*) prvTraceNextFreeEventBufferSlot();\r
1920                 if (kse != NULL)\r
1921                 {\r
1922                         kse->dts = dts6;\r
1923                         kse->type = (uint8_t)evtcode;\r
1924                         kse->param = restParam;\r
1925                         prvTraceUpdateCounters();\r
1926                 }\r
1927         }\r
1928         trcCRITICAL_SECTION_END();\r
1929 }\r
1930 #endif /* TRC_CFG_SCHEDULING_ONLY */\r
1931 \r
1932 /*******************************************************************************\r
1933  * prvTraceStoreTaskswitch\r
1934  * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart.\r
1935  * At this point interrupts are assumed to be disabled!\r
1936  ******************************************************************************/\r
1937 void prvTraceStoreTaskswitch(traceHandle task_handle)\r
1938 {\r
1939         uint16_t dts3;\r
1940         TSEvent* ts;\r
1941         uint8_t hnd8;\r
1942 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)\r
1943         extern int32_t isPendingContextSwitch;\r
1944 #endif\r
1945         trcSR_ALLOC_CRITICAL_SECTION_ON_CORTEX_M_ONLY();\r
1946 \r
1947         TRACE_ASSERT(task_handle <= (TRC_CFG_NTASK),\r
1948                 "prvTraceStoreTaskswitch: Invalid value for task_handle", TRC_UNUSED);\r
1949 \r
1950         trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY();\r
1951 \r
1952         if ((task_handle != handle_of_last_logged_task) && (RecorderDataPtr->recorderActive))\r
1953         {\r
1954 #if (TRC_CFG_INCLUDE_ISR_TRACING == 1)\r
1955                 isPendingContextSwitch = 0;\r
1956 #endif\r
1957 \r
1958                 dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
1959                 handle_of_last_logged_task = task_handle;\r
1960                 hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task);\r
1961                 ts = (TSEvent*)prvTraceNextFreeEventBufferSlot();\r
1962 \r
1963                 if (ts != NULL)\r
1964                 {\r
1965                         if (prvTraceGetObjectState(TRACE_CLASS_TASK,\r
1966                                 handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE)\r
1967                         {\r
1968                                 ts->type = TS_TASK_RESUME;\r
1969                         }\r
1970                         else\r
1971                         {\r
1972                                 ts->type = TS_TASK_BEGIN;\r
1973                         }\r
1974 \r
1975                         ts->dts = dts3;\r
1976                         ts->objHandle = hnd8;\r
1977 \r
1978                         prvTraceSetObjectState(TRACE_CLASS_TASK,\r
1979                                                                         handle_of_last_logged_task,\r
1980                                                                         TASK_STATE_INSTANCE_ACTIVE);\r
1981 \r
1982                         prvTraceUpdateCounters();\r
1983                 }\r
1984         }\r
1985 \r
1986         trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY();\r
1987 }\r
1988 \r
1989 /*******************************************************************************\r
1990  * prvTraceStoreObjectNameOnCloseEvent\r
1991  *\r
1992  * Updates the symbol table with the name of this object from the dynamic\r
1993  * objects table and stores a "close" event, holding the mapping between handle\r
1994  * and name (a symbol table handle). The stored name-handle mapping is thus the\r
1995  * "old" one, valid up until this point.\r
1996  ******************************************************************************/\r
1997 void prvTraceStoreObjectNameOnCloseEvent(uint8_t evtcode, traceHandle handle,\r
1998                                                                                 traceObjectClass objectclass)\r
1999 {\r
2000         ObjCloseNameEvent * ce;\r
2001         const char * name;\r
2002         traceString idx;\r
2003 \r
2004         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2005                 "prvTraceStoreObjectNameOnCloseEvent: objectclass >= TRACE_NCLASSES", TRC_UNUSED);\r
2006         TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],\r
2007                 "prvTraceStoreObjectNameOnCloseEvent: Invalid value for handle", TRC_UNUSED);\r
2008 \r
2009         if (RecorderDataPtr->recorderActive)\r
2010         {\r
2011                 uint8_t hnd8 = prvTraceGet8BitHandle(handle);\r
2012                 name = TRACE_PROPERTY_NAME_GET(objectclass, handle);\r
2013                 idx = prvTraceOpenSymbol(name, 0);\r
2014 \r
2015                 // Interrupt disable not necessary, already done in trcHooks.h macro\r
2016                 ce = (ObjCloseNameEvent*) prvTraceNextFreeEventBufferSlot();\r
2017                 if (ce != NULL)\r
2018                 {\r
2019                         ce->type = (uint8_t) evtcode;\r
2020                         ce->objHandle = hnd8;\r
2021                         ce->symbolIndex = idx;\r
2022                         prvTraceUpdateCounters();\r
2023                 }\r
2024         }\r
2025 }\r
2026 \r
2027 void prvTraceStoreObjectPropertiesOnCloseEvent(uint8_t evtcode, traceHandle handle,\r
2028                                                                                          traceObjectClass objectclass)\r
2029 {\r
2030         ObjClosePropEvent * pe;\r
2031 \r
2032         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2033                 "prvTraceStoreObjectPropertiesOnCloseEvent: objectclass >= TRACE_NCLASSES", TRC_UNUSED);\r
2034         TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],\r
2035                 "prvTraceStoreObjectPropertiesOnCloseEvent: Invalid value for handle", TRC_UNUSED);\r
2036 \r
2037         if (RecorderDataPtr->recorderActive)\r
2038         {\r
2039                 // Interrupt disable not necessary, already done in trcHooks.h macro\r
2040                 pe = (ObjClosePropEvent*) prvTraceNextFreeEventBufferSlot();\r
2041                 if (pe != NULL)\r
2042                 {\r
2043                         if (objectclass == TRACE_CLASS_TASK)\r
2044                         {\r
2045                                 pe->arg1 = TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle);\r
2046                         }\r
2047                         else\r
2048                         {\r
2049                                 pe->arg1 = TRACE_PROPERTY_OBJECT_STATE(objectclass, handle);\r
2050                         }\r
2051                         pe->type = evtcode;\r
2052                         prvTraceUpdateCounters();\r
2053                 }\r
2054         }\r
2055 }\r
2056 \r
2057 void prvTraceSetPriorityProperty(uint8_t objectclass, traceHandle id, uint8_t value)\r
2058 {\r
2059         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2060                 "prvTraceSetPriorityProperty: objectclass >= TRACE_NCLASSES", TRC_UNUSED);\r
2061         TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],\r
2062                 "prvTraceSetPriorityProperty: Invalid value for id", TRC_UNUSED);\r
2063 \r
2064         TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value;\r
2065 }\r
2066 \r
2067 uint8_t prvTraceGetPriorityProperty(uint8_t objectclass, traceHandle id)\r
2068 {\r
2069         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2070                 "prvTraceGetPriorityProperty: objectclass >= TRACE_NCLASSES", 0);\r
2071         TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],\r
2072                 "prvTraceGetPriorityProperty: Invalid value for id", 0);\r
2073 \r
2074         return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id);\r
2075 }\r
2076 \r
2077 void prvTraceSetObjectState(uint8_t objectclass, traceHandle id, uint8_t value)\r
2078 {\r
2079         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2080                 "prvTraceSetObjectState: objectclass >= TRACE_NCLASSES", TRC_UNUSED);\r
2081         TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],\r
2082                 "prvTraceSetObjectState: Invalid value for id", TRC_UNUSED);\r
2083 \r
2084         TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value;\r
2085 }\r
2086 \r
2087 uint8_t prvTraceGetObjectState(uint8_t objectclass, traceHandle id)\r
2088 {\r
2089         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2090                 "prvTraceGetObjectState: objectclass >= TRACE_NCLASSES", 0);\r
2091         TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],\r
2092                 "prvTraceGetObjectState: Invalid value for id", 0);\r
2093 \r
2094         return TRACE_PROPERTY_OBJECT_STATE(objectclass, id);\r
2095 }\r
2096 \r
2097 void prvTraceSetTaskInstanceFinished(traceHandle handle)\r
2098 {\r
2099         TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_TASK],\r
2100                 "prvTraceSetTaskInstanceFinished: Invalid value for handle", TRC_UNUSED);\r
2101 \r
2102 #if (TRC_CFG_USE_IMPLICIT_IFE_RULES == 1)\r
2103         TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0;\r
2104 #endif\r
2105 }\r
2106 \r
2107 /*******************************************************************************\r
2108  * Static data initializations\r
2109  ******************************************************************************/\r
2110 \r
2111 /* A set of stacks that keeps track of available object handles for each class.\r
2112 The stacks are empty initially, meaning that allocation of new handles will be\r
2113 based on a counter (for each object class). Any delete operation will\r
2114 return the handle to the corresponding stack, for reuse on the next allocate.*/\r
2115 objectHandleStackType objectHandleStacks = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };\r
2116 \r
2117 /* Initial TRC_HWTC_COUNT value, for detecting if the time-stamping source is\r
2118 enabled. If using the OS periodic timer for time-stamping, this might not\r
2119 have been configured on the earliest events during the startup. */\r
2120 uint32_t init_hwtc_count;\r
2121 \r
2122 /*******************************************************************************\r
2123  * RecorderData\r
2124  *\r
2125  * The main data structure in snapshot mode, when using the default static memory\r
2126  * allocation (TRC_RECORDER_BUFFER_ALLOCATION_STATIC). The recorder uses a pointer\r
2127  * RecorderDataPtr to access the data, to also allow for dynamic or custom data\r
2128  * allocation (see TRC_CFG_RECORDER_BUFFER_ALLOCATION).\r
2129  ******************************************************************************/\r
2130 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC)\r
2131 RecorderDataType RecorderData;\r
2132 #endif\r
2133 \r
2134 /*******************************************************************************\r
2135  * RecorderDataPtr\r
2136  *\r
2137  * Pointer to the main data structure, when in snapshot mode.\r
2138  ******************************************************************************/\r
2139 RecorderDataType* RecorderDataPtr = NULL;\r
2140 \r
2141 /* This version of the function dynamically allocates the trace data */\r
2142 void prvTraceInitTraceData()\r
2143 {\r
2144 \r
2145         if (RecorderDataPtr == NULL)\r
2146         {\r
2147 #if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC)\r
2148         RecorderDataPtr = &RecorderData;\r
2149 #elif (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC)\r
2150         RecorderDataPtr = (RecorderDataType*)TRACE_MALLOC(sizeof(RecorderDataType));\r
2151         if (! RecorderDataPtr)\r
2152         {\r
2153                 prvTraceError("Failed allocating recorder buffer!");\r
2154                 return;\r
2155         }\r
2156 #elif (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM)\r
2157                 if (! RecorderDataPtr)\r
2158                 {\r
2159                         prvTraceError("Recorder data pointer not set! Use vTraceSetRecorderDataBuffer().");\r
2160                         return;\r
2161                 }\r
2162 #endif\r
2163         }\r
2164         else\r
2165         {\r
2166                 if (RecorderDataPtr->startmarker0 == 1)\r
2167                 {\r
2168                         /* Already initialized */\r
2169                         return;\r
2170                 }\r
2171         }\r
2172 \r
2173         init_hwtc_count = TRC_HWTC_COUNT;\r
2174 \r
2175         (void)memset(RecorderDataPtr, 0, sizeof(RecorderDataType));\r
2176 \r
2177         RecorderDataPtr->version = TRACE_KERNEL_VERSION;\r
2178         RecorderDataPtr->minor_version = TRACE_MINOR_VERSION;\r
2179         RecorderDataPtr->irq_priority_order = TRC_IRQ_PRIORITY_ORDER;\r
2180         RecorderDataPtr->filesize = sizeof(RecorderDataType);\r
2181         RecorderDataPtr->maxEvents = (TRC_CFG_EVENT_BUFFER_SIZE);\r
2182         RecorderDataPtr->debugMarker0 = (int32_t) 0xF0F0F0F0;\r
2183         RecorderDataPtr->isUsing16bitHandles = TRC_CFG_USE_16BIT_OBJECT_HANDLES;\r
2184         RecorderDataPtr->isrTailchainingThreshold = TRC_CFG_ISR_TAILCHAINING_THRESHOLD;\r
2185 \r
2186         /* This function is kernel specific */\r
2187         vTraceInitObjectPropertyTable();\r
2188 \r
2189         RecorderDataPtr->debugMarker1 = (int32_t)0xF1F1F1F1;\r
2190         RecorderDataPtr->SymbolTable.symTableSize = (TRC_CFG_SYMBOL_TABLE_SIZE);\r
2191         RecorderDataPtr->SymbolTable.nextFreeSymbolIndex = 1;\r
2192 #if (TRC_CFG_INCLUDE_FLOAT_SUPPORT == 1)\r
2193         RecorderDataPtr->exampleFloatEncoding = 1.0f; /* otherwise already zero */\r
2194 #endif\r
2195         RecorderDataPtr->debugMarker2 = (int32_t)0xF2F2F2F2;\r
2196         prvStrncpy(RecorderDataPtr->systemInfo, "Trace Recorder Demo", 80);\r
2197         RecorderDataPtr->debugMarker3 = (int32_t)0xF3F3F3F3;\r
2198         RecorderDataPtr->endmarker0 = 0x0A;\r
2199         RecorderDataPtr->endmarker1 = 0x0B;\r
2200         RecorderDataPtr->endmarker2 = 0x0C;\r
2201         RecorderDataPtr->endmarker3 = 0x0D;\r
2202         RecorderDataPtr->endmarker4 = 0x71;\r
2203         RecorderDataPtr->endmarker5 = 0x72;\r
2204         RecorderDataPtr->endmarker6 = 0x73;\r
2205         RecorderDataPtr->endmarker7 = 0x74;\r
2206         RecorderDataPtr->endmarker8 = 0xF1;\r
2207         RecorderDataPtr->endmarker9 = 0xF2;\r
2208         RecorderDataPtr->endmarker10 = 0xF3;\r
2209         RecorderDataPtr->endmarker11 = 0xF4;\r
2210 \r
2211 #if TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER\r
2212         RecorderDataPtr->userEventBuffer.bufferID = 1;\r
2213         RecorderDataPtr->userEventBuffer.version = 0;\r
2214         RecorderDataPtr->userEventBuffer.numberOfSlots = (TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE);\r
2215         RecorderDataPtr->userEventBuffer.numberOfChannels = (TRC_CFG_UB_CHANNELS) + 1;\r
2216 #endif\r
2217 \r
2218         /* Kernel specific initialization of the objectHandleStacks variable */\r
2219         vTraceInitObjectHandleStack();\r
2220 \r
2221 \r
2222         /* Finally, the 12-byte "start markers" are initialized, allowing for\r
2223         Tracealyzer to find the trace data in a larger RAM dump.\r
2224 \r
2225         The start and end markers must be unique, but without proper precautions there\r
2226         might be a risk of accidental duplicates of the start/end markers, e.g., due to\r
2227         compiler optimizations.\r
2228 \r
2229         The below initialization of the start marker is therefore made in reverse order\r
2230         and the fields are volatile to ensure this assignment order. This to avoid any\r
2231         chance of accidental duplicates of this elsewhere in memory.\r
2232 \r
2233         Moreover, the fields are set byte-by-byte to avoid endian issues.*/\r
2234 \r
2235         RecorderDataPtr->startmarker11 = 0xF4;\r
2236         RecorderDataPtr->startmarker10 = 0xF3;\r
2237         RecorderDataPtr->startmarker9 = 0xF2;\r
2238         RecorderDataPtr->startmarker8 = 0xF1;\r
2239         RecorderDataPtr->startmarker7 = 0x74;\r
2240         RecorderDataPtr->startmarker6 = 0x73;\r
2241         RecorderDataPtr->startmarker5 = 0x72;\r
2242         RecorderDataPtr->startmarker4 = 0x71;\r
2243         RecorderDataPtr->startmarker3 = 0x04;\r
2244         RecorderDataPtr->startmarker2 = 0x03;\r
2245         RecorderDataPtr->startmarker1 = 0x02;\r
2246         RecorderDataPtr->startmarker0 = 0x01;\r
2247 \r
2248         if (traceErrorMessage != NULL)\r
2249         {\r
2250                 // An error was detected before vTraceEnable was called, make sure this is stored in the trace data.\r
2251                 prvStrncpy(RecorderDataPtr->systemInfo, traceErrorMessage, 80);\r
2252                 RecorderDataPtr->internalErrorOccured = 1;\r
2253                 vTraceStop();\r
2254         }\r
2255 \r
2256 \r
2257 \r
2258 #ifdef TRC_PORT_SPECIFIC_INIT\r
2259         TRC_PORT_SPECIFIC_INIT();\r
2260 #endif\r
2261 }\r
2262 \r
2263 \r
2264 void* prvTraceNextFreeEventBufferSlot(void)\r
2265 {\r
2266         if (! RecorderDataPtr->recorderActive)\r
2267         {\r
2268                 /* If an XTS or XPS event prior to the main event has filled the buffer\r
2269                 before saving the main event, and store mode is "stop when full". */\r
2270                 return NULL;\r
2271         }\r
2272 \r
2273         if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE))\r
2274         {\r
2275                 prvTraceError("Attempt to index outside event buffer!");\r
2276                 return NULL;\r
2277         }\r
2278         return (void*)(&RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex*4]);\r
2279 }\r
2280 \r
2281 uint16_t uiIndexOfObject(traceHandle objecthandle, uint8_t objectclass)\r
2282 {\r
2283         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2284                 "uiIndexOfObject: Invalid value for objectclass", 0);\r
2285         TRACE_ASSERT(objecthandle > 0 && objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],\r
2286                 "uiIndexOfObject: Invalid value for objecthandle", 0);\r
2287 \r
2288         if ((objectclass < TRACE_NCLASSES) && (objecthandle > 0) &&\r
2289                 (objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]))\r
2290         {\r
2291                 return (uint16_t)(RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[objectclass] +\r
2292                         (RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * (objecthandle-1)));\r
2293         }\r
2294 \r
2295         prvTraceError("Object table lookup with invalid object handle or object class!");\r
2296         return 0;\r
2297 }\r
2298 \r
2299 traceHandle prvTraceGetObjectHandle(traceObjectClass objectclass)\r
2300 {\r
2301         traceHandle handle;\r
2302         static int indexOfHandle;\r
2303 \r
2304         TRACE_ALLOC_CRITICAL_SECTION();\r
2305 \r
2306         TRACE_ASSERT(RecorderDataPtr != NULL, "Recorder not initialized, call vTraceEnable() first!", (traceHandle)0);\r
2307 \r
2308         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2309                 "prvTraceGetObjectHandle: Invalid value for objectclass", (traceHandle)0);\r
2310 \r
2311         trcCRITICAL_SECTION_BEGIN();\r
2312         indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass];\r
2313         if (objectHandleStacks.objectHandles[indexOfHandle] == 0)\r
2314         {\r
2315                 /* Zero is used to indicate a never before used handle, i.e.,\r
2316                         new slots in the handle stack. The handle slot needs to\r
2317                         be initialized here (starts at 1). */\r
2318                 objectHandleStacks.objectHandles[indexOfHandle] =\r
2319                         (traceHandle)(1 + indexOfHandle -\r
2320                         objectHandleStacks.lowestIndexOfClass[objectclass]);\r
2321         }\r
2322 \r
2323         handle = objectHandleStacks.objectHandles[indexOfHandle];\r
2324 \r
2325         if (objectHandleStacks.indexOfNextAvailableHandle[objectclass]\r
2326                 > objectHandleStacks.highestIndexOfClass[objectclass])\r
2327         {\r
2328                 prvTraceError(pszTraceGetErrorNotEnoughHandles(objectclass));\r
2329                 handle = 0;\r
2330         }\r
2331         else\r
2332         {\r
2333                 int hndCount;\r
2334                 objectHandleStacks.indexOfNextAvailableHandle[objectclass]++;\r
2335 \r
2336                 hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] -\r
2337                         objectHandleStacks.lowestIndexOfClass[objectclass];\r
2338 \r
2339                 if (hndCount >\r
2340                         objectHandleStacks.handleCountWaterMarksOfClass[objectclass])\r
2341                 {\r
2342                         objectHandleStacks.handleCountWaterMarksOfClass[objectclass] =\r
2343                                 (traceHandle)hndCount;\r
2344                 }\r
2345         }\r
2346         trcCRITICAL_SECTION_END();\r
2347 \r
2348         return handle;\r
2349 }\r
2350 \r
2351 void prvTraceFreeObjectHandle(traceObjectClass objectclass, traceHandle handle)\r
2352 {\r
2353         int indexOfHandle;\r
2354 \r
2355         TRACE_ASSERT(objectclass < TRACE_NCLASSES,\r
2356                 "prvTraceFreeObjectHandle: Invalid value for objectclass", TRC_UNUSED);\r
2357         TRACE_ASSERT(handle > 0 && handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass],\r
2358                 "prvTraceFreeObjectHandle: Invalid value for handle", TRC_UNUSED);\r
2359 \r
2360         /* Check that there is room to push the handle on the stack */\r
2361         if ((objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) <\r
2362                 objectHandleStacks.lowestIndexOfClass[objectclass])\r
2363         {\r
2364                 /* Error */\r
2365                 prvTraceError("Attempt to free more handles than allocated!");\r
2366         }\r
2367         else\r
2368         {\r
2369                 objectHandleStacks.indexOfNextAvailableHandle[objectclass]--;\r
2370                 indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass];\r
2371                 objectHandleStacks.objectHandles[indexOfHandle] = handle;\r
2372         }\r
2373 }\r
2374 \r
2375 /*******************************************************************************\r
2376  * prvMarkObjectAsUsed\r
2377  *\r
2378  * Sets an "is used flag" on object creation, using the first byte of the name\r
2379  * field. This allows for counting the number of used Object Table slots, even\r
2380  * if no names have been set.\r
2381  ******************************************************************************/\r
2382 void prvMarkObjectAsUsed(traceObjectClass objectclass, traceHandle handle)\r
2383 {\r
2384         uint16_t idx = uiIndexOfObject(handle, objectclass);\r
2385         RecorderDataPtr->ObjectPropertyTable.objbytes[idx] = 1;\r
2386 }\r
2387 \r
2388 /*******************************************************************************\r
2389  * prvStrncpy\r
2390  *\r
2391  * Private string copy function, to improve portability between compilers.\r
2392  ******************************************************************************/\r
2393 static void prvStrncpy(char* dst, const char* src, uint32_t maxLength)\r
2394 {\r
2395         uint32_t i;\r
2396         for (i = 0; i < maxLength; i++)\r
2397         {\r
2398                 dst[i] = src[i];\r
2399                 if (src[i] == 0)\r
2400                         break;\r
2401         }\r
2402 }\r
2403 \r
2404 /*******************************************************************************\r
2405  * prvTraceSetObjectName\r
2406  *\r
2407  * Registers the names of queues, semaphores and other kernel objects in the\r
2408  * recorder's Object Property Table, at the given handle and object class.\r
2409  ******************************************************************************/\r
2410 void prvTraceSetObjectName(traceObjectClass objectclass,\r
2411                                                  traceHandle handle,\r
2412                                                  const char* name)\r
2413 {\r
2414         static uint16_t idx;\r
2415 \r
2416         TRACE_ASSERT(name != NULL, "prvTraceSetObjectName: name == NULL", TRC_UNUSED);\r
2417 \r
2418         if (objectclass >= TRACE_NCLASSES)\r
2419         {\r
2420                 prvTraceError("Illegal object class in prvTraceSetObjectName");\r
2421                 return;\r
2422         }\r
2423 \r
2424         if (handle == 0)\r
2425         {\r
2426                 prvTraceError("Illegal handle (0) in prvTraceSetObjectName.");\r
2427                 return;\r
2428         }\r
2429 \r
2430         if (handle > RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass])\r
2431         {\r
2432                 /* ERROR */\r
2433                 prvTraceError(pszTraceGetErrorNotEnoughHandles(objectclass));\r
2434         }\r
2435         else\r
2436         {\r
2437                 idx = uiIndexOfObject(handle, objectclass);\r
2438 \r
2439                 if (traceErrorMessage == NULL)\r
2440                 {\r
2441                         prvStrncpy((char*)&(RecorderDataPtr->ObjectPropertyTable.objbytes[idx]),\r
2442                                 name,\r
2443                                 RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ]);\r
2444                 }\r
2445         }\r
2446 }\r
2447 \r
2448 traceString prvTraceOpenSymbol(const char* name, traceString userEventChannel)\r
2449 {\r
2450         uint16_t result;\r
2451         uint8_t len;\r
2452         uint8_t crc;\r
2453         TRACE_ALLOC_CRITICAL_SECTION();\r
2454 \r
2455         len = 0;\r
2456         crc = 0;\r
2457 \r
2458         TRACE_ASSERT(name != NULL, "prvTraceOpenSymbol: name == NULL", (traceString)0);\r
2459 \r
2460         prvTraceGetChecksum(name, &crc, &len);\r
2461 \r
2462         trcCRITICAL_SECTION_BEGIN();\r
2463         result = prvTraceLookupSymbolTableEntry(name, crc, len, userEventChannel);\r
2464         if (!result)\r
2465         {\r
2466                 result = prvTraceCreateSymbolTableEntry(name, crc, len, userEventChannel);\r
2467         }\r
2468         trcCRITICAL_SECTION_END();\r
2469 \r
2470         return result;\r
2471 }\r
2472 \r
2473 \r
2474 /******************************************************************************\r
2475 * vTraceSetFrequency\r
2476 *\r
2477 * Registers the clock rate of the time source for the event timestamping.\r
2478 * This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ)\r
2479 * should be incorrect for your setup, you can override it using this function.\r
2480 *\r
2481 * Must be called prior to vTraceEnable, and the time source is assumed to\r
2482 * have a fixed clock frequency after the startup.\r
2483 *\r
2484 * Note that, in snapshot mode, the value is divided by the TRC_HWTC_DIVISOR.\r
2485 * This is a software "prescaler" that is also applied on the timestamps.\r
2486 *****************************************************************************/\r
2487 void vTraceSetFrequency(uint32_t frequency)\r
2488 {\r
2489         timestampFrequency = frequency;\r
2490 }\r
2491 \r
2492 /*******************************************************************************\r
2493  * Supporting functions\r
2494  ******************************************************************************/\r
2495 \r
2496 /*******************************************************************************\r
2497  * prvTraceError\r
2498  *\r
2499  * Called by various parts in the recorder. Stops the recorder and stores a\r
2500  * pointer to an error message, which is printed by the monitor task.\r
2501  * If you are not using the monitor task, you may use xTraceGetLastError()\r
2502  * from your application to check if the recorder is OK.\r
2503  *\r
2504  * Note: If a recorder error is registered before vTraceStart is called, the\r
2505  * trace start will be aborted. This can occur if any of the Nxxxx constants\r
2506  * (e.g., TRC_CFG_NTASK) in trcConfig.h is too small.\r
2507  ******************************************************************************/\r
2508 void prvTraceError(const char* msg)\r
2509 {\r
2510         /* Stop the recorder */\r
2511         if (RecorderDataPtr != NULL)\r
2512         {\r
2513                 vTraceStop();\r
2514         }\r
2515 \r
2516         /* If first error only... */\r
2517         if (traceErrorMessage == NULL)\r
2518         {\r
2519                 traceErrorMessage = (char*)(intptr_t) msg;\r
2520                 if (RecorderDataPtr != NULL)\r
2521                 {\r
2522                         prvStrncpy(RecorderDataPtr->systemInfo, traceErrorMessage, 80);\r
2523                         RecorderDataPtr->internalErrorOccured = 1;\r
2524                 }\r
2525         }\r
2526 }\r
2527 \r
2528 void vTraceSetFilterMask(uint16_t filterMask)\r
2529 {\r
2530         CurrentFilterMask = filterMask;\r
2531 }\r
2532 \r
2533 void vTraceSetFilterGroup(uint16_t filterGroup)\r
2534 {\r
2535         CurrentFilterGroup = filterGroup;\r
2536 }\r
2537 \r
2538 /******************************************************************************\r
2539  * prvCheckDataToBeOverwrittenForMultiEntryEvents\r
2540  *\r
2541  * This checks if the next event to be overwritten is a multi-entry user event,\r
2542  * i.e., a USER_EVENT followed by data entries.\r
2543  * Such data entries do not have an event code at byte 0, as other events.\r
2544  * All 4 bytes are user data, so the first byte of such data events must\r
2545  * not be interpreted as type field. The number of data entries following\r
2546  * a USER_EVENT is given in the event code of the USER_EVENT.\r
2547  * Therefore, when overwriting a USER_EVENT (when using in ring-buffer mode)\r
2548  * any data entries following must be replaced with NULL events (code 0).\r
2549  *\r
2550  * This is assumed to execute within a critical section...\r
2551  *****************************************************************************/\r
2552 \r
2553 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)\r
2554 void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck)\r
2555 {\r
2556         /* Generic "int" type is desired - should be 16 bit variable on 16 bit HW */\r
2557         unsigned int i = 0;\r
2558         unsigned int e = 0;\r
2559 \r
2560         TRACE_ASSERT(nofEntriesToCheck != 0,\r
2561                 "prvCheckDataToBeOverwrittenForMultiEntryEvents: nofEntriesToCheck == 0", TRC_UNUSED);\r
2562 \r
2563         while (i < nofEntriesToCheck)\r
2564         {\r
2565                 e = RecorderDataPtr->nextFreeIndex + i;\r
2566                 if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) &&\r
2567                         (RecorderDataPtr->eventData[e*4] < USER_EVENT + 16))\r
2568                 {\r
2569                         uint8_t nDataEvents = (uint8_t)(RecorderDataPtr->eventData[e*4] - USER_EVENT);\r
2570                         if ((e + nDataEvents) < RecorderDataPtr->maxEvents)\r
2571                         {\r
2572                                 (void)memset(& RecorderDataPtr->eventData[e*4], 0, (size_t) (4 + 4 * nDataEvents));\r
2573                         }\r
2574                 }\r
2575                 else if (RecorderDataPtr->eventData[e*4] == DIV_XPS)\r
2576                 {\r
2577                         if ((e + 1) < RecorderDataPtr->maxEvents)\r
2578                         {\r
2579                                 /* Clear 8 bytes */\r
2580                                 (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4);\r
2581                         }\r
2582                         else\r
2583                         {\r
2584                                 /* Clear 8 bytes, 4 first and 4 last */\r
2585                                 (void)memset(& RecorderDataPtr->eventData[0], 0, 4);\r
2586                                 (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4);\r
2587                         }\r
2588                 }\r
2589                 i++;\r
2590         }\r
2591 }\r
2592 #endif\r
2593 \r
2594 /*******************************************************************************\r
2595  * prvTraceUpdateCounters\r
2596  *\r
2597  * Updates the index of the event buffer.\r
2598  ******************************************************************************/\r
2599 void prvTraceUpdateCounters(void)\r
2600 {\r
2601         if (RecorderDataPtr->recorderActive == 0)\r
2602         {\r
2603                 return;\r
2604         }\r
2605 \r
2606         RecorderDataPtr->numEvents++;\r
2607 \r
2608         RecorderDataPtr->nextFreeIndex++;\r
2609 \r
2610         if (RecorderDataPtr->nextFreeIndex >= (TRC_CFG_EVENT_BUFFER_SIZE))\r
2611         {\r
2612 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)\r
2613                 RecorderDataPtr->bufferIsFull = 1;\r
2614                 RecorderDataPtr->nextFreeIndex = 0;\r
2615 #else\r
2616                 vTraceStop();\r
2617 #endif\r
2618         }\r
2619 \r
2620 #if (TRC_CFG_SNAPSHOT_MODE == TRC_SNAPSHOT_MODE_RING_BUFFER)\r
2621         prvCheckDataToBeOverwrittenForMultiEntryEvents(1);\r
2622 #endif\r
2623 }\r
2624 \r
2625 /******************************************************************************\r
2626  * prvTraceGetDTS\r
2627  *\r
2628  * Returns a differential timestamp (DTS), i.e., the time since\r
2629  * last event, and creates an XTS event if the DTS does not fit in the\r
2630  * number of bits given. The XTS event holds the MSB bytes of the DTS.\r
2631  *\r
2632  * The parameter param_maxDTS should be 0xFF for 8-bit dts or 0xFFFF for\r
2633  * events with 16-bit dts fields.\r
2634  *****************************************************************************/\r
2635 uint16_t prvTraceGetDTS(uint16_t param_maxDTS)\r
2636 {\r
2637         static uint32_t old_timestamp = 0;\r
2638         XTSEvent* xts = 0;\r
2639         uint32_t dts = 0;\r
2640         uint32_t timestamp = 0;\r
2641 \r
2642         TRACE_ASSERT(param_maxDTS == 0xFF || param_maxDTS == 0xFFFF, "prvTraceGetDTS: Invalid value for param_maxDTS", 0);\r
2643 \r
2644 \r
2645         if (RecorderDataPtr->frequency == 0)\r
2646         {\r
2647                 if (timestampFrequency != 0)\r
2648                 {\r
2649                         /* If to override default TRC_HWTC_FREQ_HZ value with value set by vTraceSetFrequency */\r
2650                         RecorderDataPtr->frequency = timestampFrequency / (TRC_HWTC_DIVISOR);\r
2651                 }\r
2652                 else if (init_hwtc_count != (TRC_HWTC_COUNT))\r
2653                 {\r
2654                         /* If using default value and timer has been started.\r
2655                         Note: If the default frequency value set here would be incorrect, e.g.,\r
2656                         if the timer has actually not been configured yet, override this\r
2657                         with vTraceSetFrequency.\r
2658                         */\r
2659                         RecorderDataPtr->frequency = (TRC_HWTC_FREQ_HZ) / (TRC_HWTC_DIVISOR);\r
2660                 }\r
2661                 /* If no override (vTraceSetFrequency) and timer inactive -> no action */\r
2662         }\r
2663 \r
2664         /**************************************************************************\r
2665         * The below statements read the timestamp from the timer port module.\r
2666         * If necessary, whole seconds are extracted using division while the rest\r
2667         * comes from the modulo operation.\r
2668         **************************************************************************/\r
2669 \r
2670         prvTracePortGetTimeStamp(&timestamp);\r
2671 \r
2672         /***************************************************************************\r
2673         * Since dts is unsigned the result will be correct even if timestamp has\r
2674         * wrapped around.\r
2675         ***************************************************************************/\r
2676         dts = timestamp - old_timestamp;\r
2677         old_timestamp = timestamp;\r
2678 \r
2679         if (RecorderDataPtr->frequency > 0)\r
2680         {\r
2681                 /* Check if dts > 1 second */\r
2682                 if (dts > RecorderDataPtr->frequency)\r
2683                 {\r
2684                         /* More than 1 second has passed */\r
2685                         RecorderDataPtr->absTimeLastEventSecond += dts / RecorderDataPtr->frequency;\r
2686                         /* The part that is not an entire second is added to absTimeLastEvent */\r
2687                         RecorderDataPtr->absTimeLastEvent += dts % RecorderDataPtr->frequency;\r
2688                 }\r
2689                 else\r
2690                 {\r
2691                         RecorderDataPtr->absTimeLastEvent += dts;\r
2692                 }\r
2693 \r
2694                 /* Check if absTimeLastEvent >= 1 second */\r
2695                 if (RecorderDataPtr->absTimeLastEvent >= RecorderDataPtr->frequency)\r
2696                 {\r
2697                         /* RecorderDataPtr->absTimeLastEvent is more than or equal to 1 second, but always less than 2 seconds */\r
2698                         RecorderDataPtr->absTimeLastEventSecond++;\r
2699                         RecorderDataPtr->absTimeLastEvent -= RecorderDataPtr->frequency;\r
2700                         /* RecorderDataPtr->absTimeLastEvent is now less than 1 second */\r
2701                 }\r
2702         }\r
2703         else\r
2704         {\r
2705                 /* Special case if the recorder has not yet started (frequency may be uninitialized, i.e., zero) */\r
2706                 RecorderDataPtr->absTimeLastEvent = timestamp;\r
2707         }\r
2708 \r
2709         /* If the dts (time since last event) does not fit in event->dts (only 8 or 16 bits) */\r
2710         if (dts > param_maxDTS)\r
2711         {\r
2712                 /* Create an XTS event (eXtended TimeStamp) containing the higher dts bits*/\r
2713                 xts = (XTSEvent*) prvTraceNextFreeEventBufferSlot();\r
2714 \r
2715                 if (xts != NULL)\r
2716                 {\r
2717                         if (param_maxDTS == 0xFFFF)\r
2718                         {\r
2719                                 xts->type = XTS16;\r
2720                                 xts->xts_16 = (uint16_t)((dts / 0x10000) & 0xFFFF);\r
2721                                 xts->xts_8 = 0;\r
2722                         }\r
2723                         else if (param_maxDTS == 0xFF)\r
2724                         {\r
2725                                 xts->type = XTS8;\r
2726                                 xts->xts_16 = (uint16_t)((dts / 0x100) & 0xFFFF);\r
2727                                 xts->xts_8 = (uint8_t)((dts / 0x1000000) & 0xFF);\r
2728                         }\r
2729                         else\r
2730                         {\r
2731                                 prvTraceError("Bad param_maxDTS in prvTraceGetDTS");\r
2732                         }\r
2733                         prvTraceUpdateCounters();\r
2734                 }\r
2735         }\r
2736 \r
2737         return (uint16_t)dts & param_maxDTS;\r
2738 }\r
2739 \r
2740 /*******************************************************************************\r
2741  * prvTraceLookupSymbolTableEntry\r
2742  *\r
2743  * Find an entry in the symbol table, return 0 if not present.\r
2744  *\r
2745  * The strings are stored in a byte pool, with four bytes of "meta-data" for\r
2746  * every string.\r
2747  * byte 0-1: index of next entry with same checksum (for fast lookup).\r
2748  * byte 2-3: reference to a symbol table entry, a label for vTracePrintF\r
2749  * format strings only (the handle of the destination channel).\r
2750  * byte 4..(4 + length): the string (object name or user event label), with\r
2751  * zero-termination\r
2752  ******************************************************************************/\r
2753 traceString prvTraceLookupSymbolTableEntry(const char* name,\r
2754                                                                                  uint8_t crc6,\r
2755                                                                                  uint8_t len,\r
2756                                                                                  traceString chn)\r
2757 {\r
2758         uint16_t i = RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ];\r
2759 \r
2760         TRACE_ASSERT(name != NULL, "prvTraceLookupSymbolTableEntry: name == NULL", (traceString)0);\r
2761         TRACE_ASSERT(len != 0, "prvTraceLookupSymbolTableEntry: len == 0", (traceString)0);\r
2762 \r
2763         while (i != 0)\r
2764         {\r
2765                 if (RecorderDataPtr->SymbolTable.symbytes[i + 2] == (chn & 0x00FF))\r
2766                 {\r
2767                         if (RecorderDataPtr->SymbolTable.symbytes[i + 3] == (chn / 0x100))\r
2768                         {\r
2769                                 if (RecorderDataPtr->SymbolTable.symbytes[i + 4 + len] == '\0')\r
2770                                 {\r
2771                                         if (strncmp((char*)(& RecorderDataPtr->SymbolTable.symbytes[i + 4]), name, len) == 0)\r
2772                                         {\r
2773                                                 break; /* found */\r
2774                                         }\r
2775                                 }\r
2776                         }\r
2777                 }\r
2778                 i = (uint16_t)(RecorderDataPtr->SymbolTable.symbytes[i] + (RecorderDataPtr->SymbolTable.symbytes[i + 1] * 0x100));\r
2779         }\r
2780         return i;\r
2781 }\r
2782 \r
2783 /*******************************************************************************\r
2784  * prvTraceCreateSymbolTableEntry\r
2785  *\r
2786  * Creates an entry in the symbol table, independent if it exists already.\r
2787  *\r
2788  * The strings are stored in a byte pool, with four bytes of "meta-data" for\r
2789  * every string.\r
2790  * byte 0-1: index of next entry with same checksum (for fast lookup).\r
2791  * byte 2-3: reference to a symbol table entry, a label for vTracePrintF\r
2792  * format strings only (the handle of the destination channel).\r
2793  * byte 4..(4 + length): the string (object name or user event label), with\r
2794  * zero-termination\r
2795  ******************************************************************************/\r
2796 uint16_t prvTraceCreateSymbolTableEntry(const char* name,\r
2797                                                                                 uint8_t crc6,\r
2798                                                                                 uint8_t len,\r
2799                                                                                 traceString channel)\r
2800 {\r
2801         uint16_t ret = 0;\r
2802 \r
2803         TRACE_ASSERT(name != NULL, "prvTraceCreateSymbolTableEntry: name == NULL", 0);\r
2804         TRACE_ASSERT(len != 0, "prvTraceCreateSymbolTableEntry: len == 0", 0);\r
2805 \r
2806         if (RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + len + 4 >= (TRC_CFG_SYMBOL_TABLE_SIZE))\r
2807         {\r
2808                 prvTraceError("Symbol table full. Increase TRC_CFG_SYMBOL_TABLE_SIZE in trcConfig.h");\r
2809                 ret = 0;\r
2810         }\r
2811         else\r
2812         {\r
2813 \r
2814                 RecorderDataPtr->SymbolTable.symbytes\r
2815                         [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] =\r
2816                         (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] & 0x00FF);\r
2817 \r
2818                 RecorderDataPtr->SymbolTable.symbytes\r
2819                         [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] =\r
2820                         (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] / 0x100);\r
2821 \r
2822                 RecorderDataPtr->SymbolTable.symbytes\r
2823                         [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] =\r
2824                         (uint8_t)(channel & 0x00FF);\r
2825 \r
2826                 RecorderDataPtr->SymbolTable.symbytes\r
2827                         [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] =\r
2828                         (uint8_t)(channel / 0x100);\r
2829 \r
2830                 /* set name (bytes 4...4+len-1) */\r
2831                 prvStrncpy((char*)&(RecorderDataPtr->SymbolTable.symbytes\r
2832                         [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4]), name, len);\r
2833 \r
2834                 /* Set zero termination (at offset 4+len) */\r
2835                 RecorderDataPtr->SymbolTable.symbytes\r
2836                         [RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4 + len] = '\0';\r
2837 \r
2838                 /* store index of entry (for return value, and as head of LL[crc6]) */\r
2839                 RecorderDataPtr->SymbolTable.latestEntryOfChecksum\r
2840                         [ crc6 ] = (uint16_t)RecorderDataPtr->SymbolTable.nextFreeSymbolIndex;\r
2841 \r
2842                 RecorderDataPtr->SymbolTable.nextFreeSymbolIndex += (uint32_t) (len + 5);\r
2843 \r
2844                 ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex - (uint8_t)(len + 5));\r
2845         }\r
2846 \r
2847         return ret;\r
2848 }\r
2849 \r
2850 \r
2851 /*******************************************************************************\r
2852  * prvTraceGetChecksum\r
2853  *\r
2854  * Calculates a simple 6-bit checksum from a string, used to index the string\r
2855  * for fast symbol table lookup.\r
2856  ******************************************************************************/\r
2857 void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength)\r
2858 {\r
2859         unsigned char c;\r
2860         int length = 1;         /* Should be 1 to account for '\0' */\r
2861         int crc = 0;\r
2862 \r
2863         TRACE_ASSERT(pname != NULL, "prvTraceGetChecksum: pname == NULL", TRC_UNUSED);\r
2864         TRACE_ASSERT(pcrc != NULL, "prvTraceGetChecksum: pcrc == NULL", TRC_UNUSED);\r
2865         TRACE_ASSERT(plength != NULL, "prvTraceGetChecksum: plength == NULL", TRC_UNUSED);\r
2866 \r
2867         if (pname != (const char *) 0)\r
2868         {\r
2869                 for (; (c = (unsigned char) *pname++) != '\0';)\r
2870                 {\r
2871                         crc += c;\r
2872                         length++;\r
2873                 }\r
2874         }\r
2875         *pcrc = (uint8_t)(crc & 0x3F);\r
2876         *plength = (uint8_t)length;\r
2877 }\r
2878 \r
2879 #if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1)\r
2880 \r
2881 static void prvTraceStoreXID(traceHandle handle);\r
2882 \r
2883 /******************************************************************************\r
2884  * prvTraceStoreXID\r
2885  *\r
2886  * Stores an XID (eXtended IDentifier) event.\r
2887  * This is used if an object/task handle is larger than 255.\r
2888  * The parameter "handle" is the full (16 bit) handle, assumed to be 256 or\r
2889  * larger. Handles below 256 should not use this function.\r
2890  *\r
2891  * NOTE: this function MUST be called from within a critical section.\r
2892  *****************************************************************************/\r
2893 static void prvTraceStoreXID(traceHandle handle)\r
2894 {\r
2895         XPSEvent* xid;\r
2896 \r
2897         TRACE_ASSERT(handle >= 256, "prvTraceStoreXID: Handle < 256", TRC_UNUSED);\r
2898 \r
2899         xid = (XPSEvent*)prvTraceNextFreeEventBufferSlot();\r
2900 \r
2901         if (xid != NULL)\r
2902         {\r
2903                 xid->type = XID;\r
2904 \r
2905                 /* This function is (only) used when traceHandle is 16 bit... */\r
2906                 xid->xps_16 = handle;\r
2907 \r
2908                 prvTraceUpdateCounters();\r
2909         }\r
2910 }\r
2911 \r
2912 static uint8_t prvTraceGet8BitHandle(traceHandle handle)\r
2913 {\r
2914         if (handle > 255)\r
2915         {\r
2916                 prvTraceStoreXID(handle);\r
2917                 /* The full handle (16 bit) is stored in the XID event.\r
2918                 This code (255) is used instead of zero (which is an error code).*/\r
2919                 return 255;\r
2920         }\r
2921         return (uint8_t)(handle & 0xFF);\r
2922 }\r
2923 #endif /*(TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1)*/\r
2924 \r
2925 \r
2926 /* If using DWT timestamping (default on ARM Cortex-M3, M4 and M7), make sure the DWT unit is initialized. */\r
2927 #ifndef TRC_CFG_ARM_CM_USE_SYSTICK\r
2928 #if ((TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) && (defined (__CORTEX_M) && (__CORTEX_M >= 0x03)))\r
2929 void prvTraceInitCortexM()\r
2930 {\r
2931         /* Ensure that the DWT registers are unlocked and can be modified. */\r
2932         TRC_REG_ITM_LOCKACCESS = TRC_ITM_LOCKACCESS_UNLOCK;\r
2933 \r
2934         /* Make sure DWT is enabled, if supported */\r
2935         TRC_REG_DEMCR |= TRC_DEMCR_TRCENA;\r
2936 \r
2937         do{\r
2938                 /* Verify that DWT is supported */\r
2939                 if (TRC_REG_DEMCR == 0)\r
2940                 {\r
2941                         /* This function is called on Cortex-M3, M4 and M7 devices to initialize\r
2942                         the DWT unit, assumed present. The DWT cycle counter is used for timestamping.\r
2943 \r
2944                         If the below error is produced, the DWT unit does not seem to be available.\r
2945 \r
2946                         In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build\r
2947                         to use SysTick timestamping instead, or define your own timestamping by\r
2948                         setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED\r
2949                         and make the necessary definitions, as explained in trcHardwarePort.h.*/\r
2950 \r
2951                         prvTraceError("DWT unit not available, see code comment.");\r
2952                         break;\r
2953                 }\r
2954 \r
2955                 /* Verify that DWT_CYCCNT is supported */\r
2956                 if (TRC_REG_DWT_CTRL & TRC_DWT_CTRL_NOCYCCNT)\r
2957                 {\r
2958                         /* This function is called on Cortex-M3, M4 and M7 devices to initialize\r
2959                         the DWT unit, assumed present. The DWT cycle counter is used for timestamping.\r
2960 \r
2961                         If the below error is produced, the cycle counter does not seem to be available.\r
2962 \r
2963                         In that case, define the macro TRC_CFG_ARM_CM_USE_SYSTICK in your build\r
2964                         to use SysTick timestamping instead, or define your own timestamping by\r
2965                         setting TRC_CFG_HARDWARE_PORT to TRC_HARDWARE_PORT_APPLICATION_DEFINED\r
2966                         and make the necessary definitions, as explained in trcHardwarePort.h.*/\r
2967 \r
2968                         prvTraceError("DWT_CYCCNT not available, see code comment.");\r
2969                         break;\r
2970                 }\r
2971 \r
2972                 /* Reset the cycle counter */\r
2973                 TRC_REG_DWT_CYCCNT = 0;\r
2974 \r
2975                 /* Enable the cycle counter */\r
2976                 TRC_REG_DWT_CTRL |= TRC_DWT_CTRL_CYCCNTENA;\r
2977 \r
2978         }while(0);      /* breaks above jump here */\r
2979 }\r
2980 #endif\r
2981 #endif\r
2982 \r
2983 /******************************************************************************\r
2984  * prvTracePortGetTimeStamp\r
2985  *\r
2986  * Returns the current time based on the HWTC macros which provide a hardware\r
2987  * isolation layer towards the hardware timer/counter.\r
2988  *\r
2989  * The HWTC macros and prvTracePortGetTimeStamp is the main porting issue\r
2990  * or the trace recorder library. Typically you should not need to change\r
2991  * the code of prvTracePortGetTimeStamp if using the HWTC macros.\r
2992  *\r
2993  ******************************************************************************/\r
2994 void prvTracePortGetTimeStamp(uint32_t *pTimestamp)\r
2995 {\r
2996         static uint32_t last_hwtc_count = 0;\r
2997         uint32_t hwtc_count = 0;\r
2998 \r
2999 #if TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR\r
3000         /* systick based timer */\r
3001         static uint32_t last_traceTickCount = 0;\r
3002         uint32_t traceTickCount = 0;\r
3003 #else /*TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR*/\r
3004         /* Free running timer */\r
3005         static uint32_t last_hwtc_rest = 0;\r
3006         uint32_t diff = 0;\r
3007         uint32_t diff_scaled = 0;\r
3008 #endif /*TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR*/\r
3009 \r
3010         if (trace_disable_timestamp == 1)\r
3011         {\r
3012                 if (pTimestamp)\r
3013                         *pTimestamp = last_timestamp;\r
3014                 return;\r
3015         }\r
3016 \r
3017         /* Retrieve TRC_HWTC_COUNT only once since the same value should be used all throughout this function. */\r
3018 #if (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_INCR)\r
3019         /* Get the increasing tick count */\r
3020         hwtc_count = (TRC_HWTC_COUNT);\r
3021 #elif (TRC_HWTC_TYPE == TRC_OS_TIMER_DECR || TRC_HWTC_TYPE == TRC_FREE_RUNNING_32BIT_DECR)\r
3022         /* Convert decreasing tick count into increasing tick count */\r
3023         hwtc_count = (TRC_HWTC_PERIOD) - (TRC_HWTC_COUNT);\r
3024 #else\r
3025         #error "TRC_HWTC_TYPE has unexpected value"\r
3026 #endif\r
3027 \r
3028 #if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_Win32)\r
3029         /* The Win32 port uses ulGetRunTimeCounterValue for timestamping, which in turn\r
3030         uses QueryPerformanceCounter. That function is not always reliable when used over\r
3031         multiple threads. We must therefore handle rare cases where the timestamp is less\r
3032         than the previous. In practice, this should "never" roll over since the\r
3033         performance counter is 64 bit wide. */\r
3034 \r
3035         if (last_hwtc_count > hwtc_count)\r
3036         {\r
3037                 hwtc_count = last_hwtc_count;\r
3038         }\r
3039 #endif\r
3040 \r
3041 #if (TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)\r
3042         /* Timestamping is based on a timer that wraps at TRC_HWTC_PERIOD */\r
3043         if (last_traceTickCount - uiTraceTickCount - 1 < 0x80000000)\r
3044         {\r
3045                 /* This means last_traceTickCount is higher than uiTraceTickCount,\r
3046                 so we have previously compensated for a missed tick.\r
3047                 Therefore we use the last stored value because that is more accurate. */\r
3048                 traceTickCount = last_traceTickCount;\r
3049         }\r
3050         else\r
3051         {\r
3052                 /* Business as usual */\r
3053                 traceTickCount = uiTraceTickCount;\r
3054         }\r
3055 \r
3056         /* Check for overflow. May occur if the update of uiTraceTickCount has been\r
3057         delayed due to disabled interrupts. */\r
3058         if (traceTickCount == last_traceTickCount && hwtc_count < last_hwtc_count)\r
3059         {\r
3060                 /* A trace tick has occurred but not been executed by the kernel, so we compensate manually. */\r
3061                 traceTickCount++;\r
3062         }\r
3063 \r
3064         /* Check if the return address is OK, then we perform the calculation. */\r
3065         if (pTimestamp)\r
3066         {\r
3067                 /* Get timestamp from trace ticks. Scale down the period to avoid unwanted overflows. */\r
3068                 last_timestamp = traceTickCount * ((TRC_HWTC_PERIOD) / (TRC_HWTC_DIVISOR));\r
3069                 /* Increase timestamp by (hwtc_count + "lost hardware ticks from scaling down period") / TRC_HWTC_DIVISOR. */\r
3070                 last_timestamp += (hwtc_count + traceTickCount * ((TRC_HWTC_PERIOD) % (TRC_HWTC_DIVISOR))) / (TRC_HWTC_DIVISOR);\r
3071         }\r
3072         /* Store the previous value */\r
3073         last_traceTickCount = traceTickCount;\r
3074 \r
3075 #else /*(TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)*/\r
3076 \r
3077         /* Timestamping is based on a free running timer */\r
3078         /* This part handles free running clocks that can be scaled down to avoid too large DTS values.\r
3079         Without this, the scaled timestamp will incorrectly wrap at (2^32 / TRC_HWTC_DIVISOR) ticks.\r
3080         The scaled timestamp returned from this function is supposed to go from 0 -> 2^32, which in real time would represent (0 -> 2^32 * TRC_HWTC_DIVISOR) ticks. */\r
3081 \r
3082         /* First we see how long time has passed since the last timestamp call, and we also add the ticks that was lost when we scaled down the last time. */\r
3083         diff = (hwtc_count - last_hwtc_count) + last_hwtc_rest;\r
3084 \r
3085         /* Scale down the diff */\r
3086         diff_scaled = diff / (TRC_HWTC_DIVISOR);\r
3087 \r
3088         /* Find out how many ticks were lost when scaling down, so we can add them the next time */\r
3089         last_hwtc_rest = diff % (TRC_HWTC_DIVISOR);\r
3090 \r
3091         /* We increase the scaled timestamp by the scaled amount */\r
3092         last_timestamp += diff_scaled;\r
3093 #endif /*(TRC_HWTC_TYPE == TRC_OS_TIMER_INCR || TRC_HWTC_TYPE == TRC_OS_TIMER_DECR)*/\r
3094 \r
3095         /* Is anyone interested in the results? */\r
3096         if (pTimestamp)\r
3097                 *pTimestamp = last_timestamp;\r
3098 \r
3099         /* Store the previous value */\r
3100         last_hwtc_count = hwtc_count;\r
3101 }\r
3102 \r
3103 #endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/\r
3104 \r
3105 #endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)*/\r