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