]> begriffs open source - freertos/blob - FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c
Correct compiler warnings in trace recorder code.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-Trace / trcBase.c
1 /*******************************************************************************\r
2  * Tracealyzer v2.5.0 Recorder Library\r
3  * Percepio AB, www.percepio.com\r
4  *\r
5  * trcBase.c\r
6  *\r
7  * Core functionality of the trace recorder library.\r
8  *\r
9  * Terms of Use\r
10  * This software is copyright Percepio AB. The recorder library is free for\r
11  * use together with Percepio products. You may distribute the recorder library\r
12  * in its original form, including modifications in trcHardwarePort.c/.h\r
13  * given that these modification are clearly marked as your own modifications\r
14  * and documented in the initial comment section of these source files.\r
15  * This software is the intellectual property of Percepio AB and may not be\r
16  * sold or in other ways commercially redistributed without explicit written\r
17  * permission by Percepio AB.\r
18  *\r
19  * Disclaimer\r
20  * The trace tool and recorder library is being delivered to you AS IS and\r
21  * Percepio AB makes no warranty as to its use or performance. Percepio AB does\r
22  * not and cannot warrant the performance or results you may obtain by using the\r
23  * software or documentation. Percepio AB make no warranties, express or\r
24  * implied, as to noninfringement of third party rights, merchantability, or\r
25  * fitness for any particular purpose. In no event will Percepio AB, its\r
26  * technology partners, or distributors be liable to you for any consequential,\r
27  * incidental or special damages, including any lost profits or lost savings,\r
28  * even if a representative of Percepio AB has been advised of the possibility\r
29  * of such damages, or for any claim by any third party. Some jurisdictions do\r
30  * not allow the exclusion or limitation of incidental, consequential or special\r
31  * damages, or the exclusion of implied warranties or limitations on how long an\r
32  * implied warranty may last, so the above limitations may not apply to you.\r
33  *\r
34  * Copyright Percepio AB, 2013.\r
35  * www.percepio.com\r
36  ******************************************************************************/\r
37 \r
38 #include "trcBase.h"\r
39 \r
40 #if (USE_TRACEALYZER_RECORDER == 1)\r
41 \r
42 #include <stdint.h>\r
43 \r
44 /*******************************************************************************\r
45  * Static data initializations\r
46  ******************************************************************************/\r
47 \r
48 /* Structure to handle the exclude flags for all objects and tasks. We add some extra objects since index 0 is not used for each object class. */\r
49 uint8_t excludedObjects[(TRACE_KERNEL_OBJECT_COUNT + TRACE_NCLASSES) / 8 + 1] = { 0 };\r
50 \r
51 /* Structure to handle the exclude flags for all event codes */\r
52 uint8_t excludedEventCodes[NEventCodes / 8 + 1] = { 0 };\r
53 \r
54 /* Keeps track of available handles */\r
55 objectHandleStackType objectHandleStacks = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } };\r
56 \r
57 uint32_t init_hwtc_count;\r
58 \r
59 /*******************************************************************************\r
60  * RecorderData\r
61  *\r
62  * The main data structure. This is the data read by Tracealyzer, typically\r
63  * through a debugger RAM dump. The recorder access this through the pointer\r
64  * RecorderDataPtr, to allow for dynamic memory allocation as well.\r
65  *\r
66  * On the NXP LPC17xx you may use the secondary RAM bank (AHB RAM) for this\r
67  * purpose. For instance, the LPC1766 has 32 KB AHB RAM which allows for\r
68  * allocating a buffer size of at least 7500 events without affecting the main\r
69  * RAM. To place RecorderData in this RAM bank, use the below declaration.\r
70  *\r
71  *     #pragma location="AHB_RAM_MEMORY"\r
72  *     RecorderDataType RecorderData = ...\r
73  *\r
74  * This of course works for other hardware architectures with additional RAM\r
75  * banks as well, just replace "AHB_RAM_MEMORY" with the name of the right\r
76  * address section from the linker file.\r
77  *\r
78  * However, to keep trcBase.c portable and still have a preconfigured IAR demo\r
79  * using AHB RAM, we don't add the pragma directly in trcBase.c but in a header\r
80  * included where the pragma should go. This is used depending on the setting\r
81  * USE_LINKER_PRAGMA, defined in trcConfig.h.\r
82  *\r
83  * If using GCC, this is instead done by adding a "section" attribute:\r
84  *\r
85  *     RecorderDataType RecorderData __attribute__ ((section ("name"))) = ...\r
86  *\r
87  * Remember to replace "name" with the correct section name.\r
88  ******************************************************************************/\r
89 \r
90 static void vInitStartMarkers(void);\r
91 \r
92 #if (TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_STATIC)\r
93 #if (USE_LINKER_PRAGMA == 1)\r
94 #include "recorderdata_linker_pragma.h"\r
95 #endif\r
96 \r
97 RecorderDataType RecorderData;\r
98 \r
99 #endif\r
100 \r
101 RecorderDataType* RecorderDataPtr = NULL;\r
102 \r
103 /* This version of the function dynamically allocates the trace data */\r
104 void prvTraceInitTraceData()\r
105 {\r
106         init_hwtc_count = HWTC_COUNT;\r
107         \r
108 #if TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_STATIC\r
109         RecorderDataPtr = &RecorderData;\r
110 #elif TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_DYNAMIC\r
111         RecorderDataPtr = (RecorderDataType*)TRACE_MALLOC(sizeof(RecorderDataType));\r
112 #elif TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_CUSTOM\r
113         /* DO NOTHING */\r
114 #endif\r
115 \r
116         TRACE_ASSERT(RecorderDataPtr != NULL, "prvTraceInitTraceData, RecorderDataPtr == NULL", );\r
117 \r
118     if (! RecorderDataPtr)\r
119     {\r
120         vTraceError("No recorder data structure allocated!");\r
121         return;\r
122     }\r
123 \r
124     (void)memset(RecorderDataPtr, 0, sizeof(RecorderDataType));\r
125 \r
126     RecorderDataPtr->startmarker0 = 0x00;\r
127     RecorderDataPtr->startmarker1 = 0x01;\r
128     RecorderDataPtr->startmarker2 = 0x02;\r
129     RecorderDataPtr->startmarker3 = 0x03;\r
130     RecorderDataPtr->startmarker4 = 0x70;\r
131     RecorderDataPtr->startmarker5 = 0x71;\r
132     RecorderDataPtr->startmarker6 = 0x72;\r
133     RecorderDataPtr->startmarker7 = 0x73;\r
134     RecorderDataPtr->startmarker8 = 0xF0;\r
135     RecorderDataPtr->startmarker9 = 0xF1;\r
136     RecorderDataPtr->startmarker10 = 0xF2;\r
137     RecorderDataPtr->startmarker11 = 0xF3;\r
138 \r
139     RecorderDataPtr->version = TRACE_KERNEL_VERSION;\r
140     RecorderDataPtr->minor_version = TRACE_MINOR_VERSION;\r
141     RecorderDataPtr->irq_priority_order = IRQ_PRIORITY_ORDER;\r
142     RecorderDataPtr->filesize = sizeof(RecorderDataType);\r
143 \r
144     RecorderDataPtr->maxEvents = EVENT_BUFFER_SIZE;\r
145 \r
146     RecorderDataPtr->debugMarker0 = 0xF0F0F0F0;\r
147 \r
148         /* This function is kernel specific */\r
149         vTraceInitObjectPropertyTable();\r
150 \r
151     RecorderDataPtr->debugMarker1 = 0xF1F1F1F1;\r
152     RecorderDataPtr->SymbolTable.symTableSize = SYMBOL_TABLE_SIZE;\r
153     RecorderDataPtr->SymbolTable.nextFreeSymbolIndex = 1;\r
154 #if (INCLUDE_FLOAT_SUPPORT == 1)\r
155     RecorderDataPtr->exampleFloatEncoding = (float)1.0; /* otherwise already zero */\r
156 #endif\r
157     RecorderDataPtr->debugMarker2 = 0xF2F2F2F2;\r
158     (void)strncpy(RecorderDataPtr->systemInfo, TRACE_DESCRIPTION, TRACE_DESCRIPTION_MAX_LENGTH);\r
159     RecorderDataPtr->debugMarker3 = 0xF3F3F3F3;\r
160     RecorderDataPtr->endmarker0 = 0x0A;\r
161     RecorderDataPtr->endmarker1 = 0x0B;\r
162     RecorderDataPtr->endmarker2 = 0x0C;\r
163     RecorderDataPtr->endmarker3 = 0x0D;\r
164     RecorderDataPtr->endmarker4 = 0x71;\r
165     RecorderDataPtr->endmarker5 = 0x72;\r
166     RecorderDataPtr->endmarker6 = 0x73;\r
167     RecorderDataPtr->endmarker7 = 0x74;\r
168     RecorderDataPtr->endmarker8 = 0xF1;\r
169     RecorderDataPtr->endmarker9 = 0xF2;\r
170     RecorderDataPtr->endmarker10 = 0xF3;\r
171     RecorderDataPtr->endmarker11 = 0xF4;\r
172 \r
173 #if USE_SEPARATE_USER_EVENT_BUFFER\r
174         RecorderDataPtr->userEventBuffer.bufferID = 1;\r
175         RecorderDataPtr->userEventBuffer.version = 0;\r
176         RecorderDataPtr->userEventBuffer.numberOfSlots = USER_EVENT_BUFFER_SIZE;\r
177         RecorderDataPtr->userEventBuffer.numberOfChannels = CHANNEL_FORMAT_PAIRS + 1;\r
178 #endif\r
179 \r
180         /* Kernel specific initialization of the objectHandleStacks variable */\r
181         vTraceInitObjectHandleStack();\r
182 \r
183         /* Fix the start markers of the trace data structure */\r
184         vInitStartMarkers();\r
185 }\r
186 \r
187 static void vInitStartMarkers()\r
188 {\r
189         uint32_t i;\r
190         uint8_t *ptr = (uint8_t*)&(RecorderDataPtr->startmarker0);\r
191         if ((*ptr) == 0)\r
192         {\r
193                 for (i = 0; i < 12; i++)\r
194                 {\r
195                         ptr[i] += 1;\r
196                 }\r
197         }\r
198         else\r
199         {\r
200                 vTraceError("Trace start markers already initialized!");\r
201         }\r
202 }\r
203 \r
204 volatile int recorder_busy = 0;\r
205 \r
206 /* Gives the last error message of the recorder. NULL if no error message. */\r
207 char* traceErrorMessage = NULL;\r
208 \r
209 void* xTraceNextFreeEventBufferSlot(void)\r
210 {\r
211     if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE)\r
212     {\r
213         vTraceError("Attempt to index outside event buffer!");\r
214         return NULL;\r
215     }\r
216     return (void*)(&RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex*4]);\r
217 }\r
218 \r
219 uint16_t uiIndexOfObject(objectHandleType objecthandle, uint8_t objectclass)\r
220 {\r
221         TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiIndexOfObject: Invalid value for objectclass", 0);\r
222         TRACE_ASSERT(objecthandle > 0 && objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiIndexOfObject: Invalid value for objecthandle", 0);\r
223 \r
224     if ((objectclass < TRACE_NCLASSES) && (objecthandle > 0) && (objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]))\r
225     {\r
226         return (uint16_t)(RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[objectclass] + (RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * (objecthandle-1)));\r
227     }\r
228 \r
229     vTraceError("Object table lookup with invalid object handle or object class!");\r
230     return 0;\r
231 }\r
232 \r
233 /*******************************************************************************\r
234  * Object handle system\r
235  * This provides a mechanism to assign each kernel object (tasks, queues, etc)\r
236  * with a 1-byte handle, that is used to identify the object in the trace.\r
237  * This way, only one byte instead of four is necessary to identify the object.\r
238  * This allows for maximum 255 objects, of each object class, active at any\r
239  * moment.\r
240  * Note that zero is reserved as an error code and is not a valid handle.\r
241  *\r
242  * In order to allow for fast dynamic allocation and release of object handles,\r
243  * the handles of each object class (e.g., TASK) are stored in a stack. When a\r
244  * handle is needed, e.g., on task creation, the next free handle is popped from\r
245  * the stack. When an object (e.g., task) is deleted, its handle is pushed back\r
246  * on the stack and can thereby be reused for other objects.\r
247  *\r
248  * Since this allows for reuse of object handles, a specific handle (e.g, "8")\r
249  * may refer to TASK_X at one point, and later mean "TASK_Y". To resolve this,\r
250  * the recorder uses "Close events", which are stored in the main event buffer\r
251  * when objects are deleted and their handles are released. The close event\r
252  * contains the mapping between object handle and object name which was valid up\r
253  * to this point in time. The object name is stored as a symbol table entry.\r
254  ******************************************************************************/\r
255 \r
256 objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass)\r
257 {\r
258     static objectHandleType handle;\r
259     static int indexOfHandle;\r
260 \r
261         TRACE_ASSERT(objectclass < TRACE_NCLASSES, "xTraceGetObjectHandle: Invalid value for objectclass", (objectHandleType)0);\r
262 \r
263     indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass];\r
264     if (objectHandleStacks.objectHandles[indexOfHandle] == 0)\r
265     {\r
266         /* Zero is used to indicate a never before used handle, i.e.,\r
267            new slots in the handle stack. The handle slot needs to\r
268            be initialized here (starts at 1). */\r
269         objectHandleStacks.objectHandles[indexOfHandle] =\r
270             (objectHandleType)(1 + indexOfHandle -\r
271             objectHandleStacks.lowestIndexOfClass[objectclass]);\r
272     }\r
273 \r
274     handle = objectHandleStacks.objectHandles[indexOfHandle];\r
275 \r
276     if (objectHandleStacks.indexOfNextAvailableHandle[objectclass]\r
277         > objectHandleStacks.highestIndexOfClass[objectclass])\r
278     {\r
279         /* ERROR */\r
280                 vTraceError(pszTraceGetErrorNotEnoughHandles(objectclass));\r
281 \r
282         handle = 0; /* an invalid/anonymous handle - but the recorder is stopped now... */\r
283     }\r
284     else\r
285     {\r
286         int hndCount;\r
287         objectHandleStacks.indexOfNextAvailableHandle[objectclass]++;\r
288 \r
289         hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] -\r
290             objectHandleStacks.lowestIndexOfClass[objectclass];\r
291 \r
292         if (hndCount >\r
293             objectHandleStacks.handleCountWaterMarksOfClass[objectclass])\r
294         {\r
295             objectHandleStacks.handleCountWaterMarksOfClass[objectclass] =\r
296                 (objectHandleType)hndCount;\r
297         }\r
298 \r
299                 TRACE_CLEAR_OBJECT_FLAG_ISEXCLUDED(objectclass, handle);\r
300     }\r
301 \r
302     return handle;\r
303 }\r
304 \r
305 void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handle)\r
306 {\r
307     int indexOfHandle;\r
308 \r
309     TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceFreeObjectHandle: Invalid value for objectclass", );\r
310     TRACE_ASSERT(handle > 0 && handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceFreeObjectHandle: Invalid value for handle", );\r
311 \r
312     /* Check that there is room to push the handle on the stack */\r
313     if ((objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) <\r
314         objectHandleStacks.lowestIndexOfClass[objectclass])\r
315     {\r
316         /* Error */\r
317         vTraceError("Attempt to free more handles than allocated! (duplicate xTaskDelete or xQueueDelete?)");\r
318     }\r
319     else\r
320     {\r
321         objectHandleStacks.indexOfNextAvailableHandle[objectclass]--;\r
322         indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass];\r
323         objectHandleStacks.objectHandles[indexOfHandle] = handle;\r
324     }\r
325 \r
326 }\r
327 \r
328 /*******************************************************************************\r
329  * Objects Property Table\r
330  *\r
331  * This holds the names and properties of the currently active objects, such as\r
332  * tasks and queues. This is developed to support "dynamic" objects which might\r
333  * be deleted during runtime. Their handles are only valid during their\r
334  * lifetime, i.e., from create to delete, as they might be reused on later\r
335  * create operations. When an object is deleted from the OPT, its data is moved\r
336  * to the trace buffer and/or the symbol table.\r
337  * When an object (task, queue, etc.) is created, it receives a handle, which\r
338  * together with the object class specifies its location in the OPT. Thus,\r
339  * objects of different types may share the same name and/or handle, but still\r
340  * be independent objects.\r
341  ******************************************************************************/\r
342 \r
343 /*******************************************************************************\r
344  * vTraceSetObjectName\r
345  *\r
346  * Registers the names of queues, semaphores and other kernel objects in the\r
347  * recorder's Object Property Table, at the given handle and object class.\r
348  ******************************************************************************/\r
349 void vTraceSetObjectName(traceObjectClass objectclass,\r
350                          objectHandleType handle,\r
351                          const char* name)\r
352 {\r
353     static uint16_t idx;\r
354 \r
355         TRACE_ASSERT(name != NULL, "vTraceSetObjectName: name == NULL", );\r
356 \r
357     if (objectclass >= TRACE_NCLASSES)\r
358     {\r
359         vTraceError("Illegal object class in vTraceSetObjectName");\r
360         return;\r
361     }\r
362 \r
363     if (handle == 0)\r
364     {\r
365         vTraceError("Illegal handle (0) in vTraceSetObjectName.");\r
366         return;\r
367     }\r
368 \r
369     if (handle > RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass])\r
370     {\r
371             /* ERROR */\r
372             vTraceError(pszTraceGetErrorNotEnoughHandles(objectclass));\r
373     }\r
374     else\r
375     {\r
376         idx = uiIndexOfObject(handle, objectclass);\r
377 \r
378         if (traceErrorMessage == NULL)\r
379         {\r
380             (void)strncpy((char*)&(RecorderDataPtr->ObjectPropertyTable.objbytes[idx]),\r
381                     name,\r
382                     RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ]);\r
383         }\r
384     }\r
385 }\r
386 \r
387 traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel)\r
388 {\r
389     uint16_t result;\r
390     uint8_t len;\r
391     uint8_t crc;\r
392     len = 0;\r
393     crc = 0;\r
394 \r
395     TRACE_ASSERT(name != NULL, "prvTraceOpenSymbol: name == NULL", (traceLabel)0);\r
396 \r
397     prvTraceGetChecksum(name, &crc, &len);\r
398 \r
399     trcCRITICAL_SECTION_BEGIN();\r
400     result = prvTraceLookupSymbolTableEntry(name, crc, len, userEventChannel);\r
401     if (!result)\r
402     {\r
403         result = prvTraceCreateSymbolTableEntry(name, crc, len, userEventChannel);\r
404     }\r
405     trcCRITICAL_SECTION_END();\r
406 \r
407     return result;\r
408 }\r
409 \r
410 /*******************************************************************************\r
411  * Supporting functions\r
412  ******************************************************************************/\r
413 \r
414 extern volatile uint32_t rtest_error_flag;\r
415 \r
416 /*******************************************************************************\r
417  * vTraceError\r
418  *\r
419  * Called by various parts in the recorder. Stops the recorder and stores a\r
420  * pointer to an error message, which is printed by the monitor task.\r
421  * If you are not using the monitor task, you may use xTraceGetLastError()\r
422  * from your application to check if the recorder is OK.\r
423  *\r
424  * Note: If a recorder error is registered before vTraceStart is called, the\r
425  * trace start will be aborted. This can occur if any of the Nxxxx constants\r
426  * (e.g., NTask) in trcConfig.h is too small.\r
427  ******************************************************************************/\r
428 void vTraceError(const char* msg)\r
429 {\r
430         TRACE_ASSERT(msg != NULL, "vTraceError: msg == NULL", );\r
431         TRACE_ASSERT(RecorderDataPtr != NULL, "vTraceError: RecorderDataPtr == NULL", );\r
432 \r
433         // Stop the recorder. Note: We do not call vTraceStop, since that adds a weird\r
434         // and unnecessary dependency to trcUser.c.\r
435 \r
436         RecorderDataPtr->recorderActive = 0;\r
437 \r
438     if (traceErrorMessage == NULL)\r
439     {\r
440       traceErrorMessage = (char*)msg;\r
441       (void)strncpy(RecorderDataPtr->systemInfo, traceErrorMessage, TRACE_DESCRIPTION_MAX_LENGTH);\r
442       RecorderDataPtr->internalErrorOccured = 1;                 \r
443     }\r
444         \r
445 }\r
446 \r
447 /******************************************************************************\r
448  * prvCheckDataToBeOverwrittenForMultiEntryEvents\r
449  *\r
450  * This checks if the next event to be overwritten is a multi-entry user event,\r
451  * i.e., a USER_EVENT followed by data entries.\r
452  * Such data entries do not have an event code at byte 0, as other events.\r
453  * All 4 bytes are user data, so the first byte of such data events must\r
454  * not be interpreted as type field. The number of data entries following\r
455  * a USER_EVENT is given in the event code of the USER_EVENT.\r
456  * Therefore, when overwriting a USER_EVENT (when using in ringbuffer mode)\r
457  * any data entries following must be replaced with NULL events (code 0).\r
458  *\r
459  * This is assumed to execute within a critical section...\r
460  *****************************************************************************/\r
461 \r
462 void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck)\r
463 {\r
464     /* Generic "int" type is desired - should be 16 bit variable on 16 bit HW */\r
465     unsigned int i = 0;\r
466     unsigned int e = 0;\r
467 \r
468     TRACE_ASSERT(nofEntriesToCheck != 0, "prvCheckDataToBeOverwrittenForMultiEntryEvents: nofEntriesToCheck == 0", );\r
469 \r
470     while (i < nofEntriesToCheck)\r
471     {\r
472         e = RecorderDataPtr->nextFreeIndex + i;\r
473         if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) &&\r
474             (RecorderDataPtr->eventData[e*4] < USER_EVENT + 16))\r
475         {\r
476             uint8_t nDataEvents = (uint8_t)(RecorderDataPtr->eventData[e*4] - USER_EVENT);\r
477             if ((e + nDataEvents) < RecorderDataPtr->maxEvents)\r
478             {\r
479                 (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4 * nDataEvents);\r
480             }\r
481         }\r
482                 else if (RecorderDataPtr->eventData[e*4] == DIV_XPS)\r
483         {\r
484             if ((e + 1) < RecorderDataPtr->maxEvents)\r
485             {\r
486                                 /* Clear 8 bytes */\r
487                 (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4);\r
488             }\r
489             else\r
490             {\r
491                     /* Clear 8 bytes, 4 first and 4 last */\r
492                     (void)memset(& RecorderDataPtr->eventData[0], 0, 4);\r
493                     (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4);\r
494             }\r
495         }\r
496         i++;\r
497     }\r
498 }\r
499 \r
500 /*******************************************************************************\r
501  * prvTraceUpdateCounters\r
502  *\r
503  * Updates the index of the event buffer.\r
504  ******************************************************************************/\r
505 void prvTraceUpdateCounters(void)\r
506 {\r
507     if (RecorderDataPtr->recorderActive == 0)\r
508     {\r
509         return;\r
510     }\r
511 \r
512     RecorderDataPtr->numEvents++;\r
513 \r
514     RecorderDataPtr->nextFreeIndex++;\r
515 \r
516     if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE)\r
517     {\r
518 #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
519         RecorderDataPtr->bufferIsFull = 1;\r
520         RecorderDataPtr->nextFreeIndex = 0;\r
521 #else\r
522         vTraceStop();\r
523 #endif\r
524     }\r
525 \r
526 #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
527     prvCheckDataToBeOverwrittenForMultiEntryEvents(1);\r
528 #endif\r
529 \r
530 #ifdef STOP_AFTER_N_EVENTS\r
531 #if (STOP_AFTER_N_EVENTS > -1)\r
532     if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS)\r
533     {\r
534         vTraceStop();\r
535     }\r
536 #endif\r
537 #endif\r
538 }\r
539 \r
540 /******************************************************************************\r
541  * prvTraceGetDTS\r
542  *\r
543  * Returns a differential timestamp (DTS), i.e., the time since\r
544  * last event, and creates an XTS event if the DTS does not fit in the\r
545  * number of bits given. The XTS event holds the MSB bytes of the DTS.\r
546  *\r
547  * The parameter param_maxDTS should be 0xFF for 8-bit dts or 0xFFFF for\r
548  * events with 16-bit dts fields.\r
549  *****************************************************************************/\r
550 uint16_t prvTraceGetDTS(uint16_t param_maxDTS)\r
551 {\r
552     static uint32_t old_timestamp = 0;\r
553     XTSEvent* xts = 0;\r
554     uint32_t dts = 0;\r
555     uint32_t timestamp = 0;\r
556 \r
557     TRACE_ASSERT(param_maxDTS == 0xFF || param_maxDTS == 0xFFFF, "prvTraceGetDTS: Invalid value for param_maxDTS", 0);\r
558 \r
559     if (RecorderDataPtr->frequency == 0 && init_hwtc_count != HWTC_COUNT)\r
560     {\r
561         /* If HWTC_PERIOD is mapped to the timer reload register,\r
562         such as in the Cortex M port, it might not be initialized\r
563                 before the Kernel scheduler has been started has been\r
564                 started. We therefore store the frequency of the timer\r
565                 once the counter register has changed. */\r
566 \r
567 #if (SELECTED_PORT == PORT_Win32)\r
568         RecorderDataPtr->frequency = 100000;\r
569 #elif (SELECTED_PORT == PORT_HWIndependent)\r
570         RecorderDataPtr->frequency = TRACE_TICK_RATE_HZ;\r
571 #else\r
572                 RecorderDataPtr->frequency = (HWTC_PERIOD * TRACE_TICK_RATE_HZ) / (uint32_t)HWTC_DIVISOR;\r
573 #endif\r
574     }\r
575 \r
576     /**************************************************************************\r
577     * The below statements read the timestamp from the timer port module.\r
578     * If necessary, whole seconds are extracted using division while the rest\r
579     * comes from the modulo operation.\r
580     **************************************************************************/\r
581 \r
582     vTracePortGetTimeStamp(&timestamp);\r
583 \r
584     /***************************************************************************\r
585     * Since dts is unsigned the result will be correct even if timestamp has\r
586         * wrapped around.\r
587     ***************************************************************************/\r
588         dts = timestamp - old_timestamp;\r
589     old_timestamp = timestamp;\r
590 \r
591     if (RecorderDataPtr->frequency > 0)\r
592     {\r
593         /* Check if dts > 1 second */\r
594         if (dts > RecorderDataPtr->frequency)\r
595         {\r
596             /* More than 1 second has passed */\r
597             RecorderDataPtr->absTimeLastEventSecond += dts / RecorderDataPtr->frequency;\r
598             /* The part that is not an entire second is added to absTimeLastEvent */\r
599             RecorderDataPtr->absTimeLastEvent += dts % RecorderDataPtr->frequency;\r
600         }\r
601         else\r
602                 {\r
603             RecorderDataPtr->absTimeLastEvent += dts;\r
604                 }\r
605 \r
606         /* Check if absTimeLastEvent >= 1 second */\r
607         if (RecorderDataPtr->absTimeLastEvent >= RecorderDataPtr->frequency)\r
608         {\r
609             /* RecorderDataPtr->absTimeLastEvent is more than or equal to 1 second, but always less than 2 seconds */\r
610             RecorderDataPtr->absTimeLastEventSecond++;\r
611             RecorderDataPtr->absTimeLastEvent -= RecorderDataPtr->frequency;\r
612             /* RecorderDataPtr->absTimeLastEvent is now less than 1 second */\r
613         }\r
614     }\r
615     else\r
616     {\r
617         /* Special case if the recorder has not yet started (frequency may be uninitialized, i.e., zero) */\r
618         RecorderDataPtr->absTimeLastEvent = timestamp;\r
619     }\r
620 \r
621     /* If the dts (time since last event) does not fit in event->dts (only 8 or 16 bits) */\r
622     if (dts > param_maxDTS)\r
623     {\r
624         /* Create an XTS event (eXtended TimeStamp) containing the higher dts bits*/\r
625         xts = (XTSEvent*) xTraceNextFreeEventBufferSlot();\r
626 \r
627         if (xts != NULL)\r
628         {\r
629             if (param_maxDTS == 0xFFFF)\r
630             {\r
631                 xts->type = XTS16;\r
632                 xts->xts_16 = (uint16_t)((dts / 0x10000) & 0xFFFF);\r
633                 xts->xts_8 = 0;\r
634             }\r
635             else if (param_maxDTS == 0xFF)\r
636             {\r
637                 xts->type = XTS8;\r
638                 xts->xts_16 = (uint16_t)((dts / 0x100) & 0xFFFF);\r
639                 xts->xts_8 = (uint8_t)((dts / 0x1000000) & 0xFF);\r
640             }\r
641             else\r
642             {\r
643                 vTraceError("Bad param_maxDTS in prvTraceGetDTS");\r
644             }\r
645             prvTraceUpdateCounters();\r
646         }\r
647     }\r
648 \r
649     return (uint16_t)dts & param_maxDTS;\r
650 }\r
651 \r
652 /*******************************************************************************\r
653  * prvTraceLookupSymbolTableEntry\r
654  *\r
655  * Find an entry in the symbol table, return 0 if not present.\r
656  *\r
657  * The strings are stored in a byte pool, with four bytes of "meta-data" for\r
658  * every string.\r
659  * byte 0-1: index of next entry with same checksum (for fast lookup).\r
660  * byte 2-3: reference to a symbol table entry, a label for vTracePrintF\r
661  * format strings only (the handle of the destination channel).\r
662  * byte 4..(4 + length): the string (object name or user event label), with\r
663  * zero-termination\r
664  ******************************************************************************/\r
665 traceLabel prvTraceLookupSymbolTableEntry(const char* name,\r
666                                           uint8_t crc6,\r
667                                           uint8_t len,\r
668                                           traceLabel chn)\r
669 {\r
670     uint16_t i = RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ];\r
671 \r
672         TRACE_ASSERT(name != NULL, "prvTraceLookupSymbolTableEntry: name == NULL", (traceLabel)0);\r
673         TRACE_ASSERT(len != 0, "prvTraceLookupSymbolTableEntry: len == 0", (traceLabel)0);\r
674 \r
675     while (i != 0)\r
676     {\r
677         if (RecorderDataPtr->SymbolTable.symbytes[i + 2] == (chn & 0x00FF))\r
678         {\r
679             if (RecorderDataPtr->SymbolTable.symbytes[i + 3] == (chn / 0x100))\r
680             {\r
681                 if (RecorderDataPtr->SymbolTable.symbytes[i + 4 + len] == '\0')\r
682                 {\r
683                     if (strncmp((char*)(& RecorderDataPtr->SymbolTable.symbytes[i + 4]), name, len) == 0)\r
684                     {\r
685                         break; /* found */\r
686                     }\r
687                 }\r
688             }\r
689         }\r
690         i = (uint16_t)(RecorderDataPtr->SymbolTable.symbytes[i] + (RecorderDataPtr->SymbolTable.symbytes[i + 1] * 0x100));\r
691     }\r
692     return i;\r
693 }\r
694 \r
695 /*******************************************************************************\r
696  * prvTraceCreateSymbolTableEntry\r
697  *\r
698  * Creates an entry in the symbol table, independent if it exists already.\r
699  *\r
700  * The strings are stored in a byte pool, with four bytes of "meta-data" for\r
701  * every string.\r
702  * byte 0-1: index of next entry with same checksum (for fast lookup).\r
703  * byte 2-3: reference to a symbol table entry, a label for vTracePrintF\r
704  * format strings only (the handle of the destination channel).\r
705  * byte 4..(4 + length): the string (object name or user event label), with\r
706  * zero-termination\r
707  ******************************************************************************/\r
708 uint16_t prvTraceCreateSymbolTableEntry(const char* name,\r
709                                         uint8_t crc6,\r
710                                         uint8_t len,\r
711                                         traceLabel channel)\r
712 {\r
713     uint16_t ret = 0;\r
714 \r
715         TRACE_ASSERT(name != NULL, "prvTraceCreateSymbolTableEntry: name == NULL", 0);\r
716         TRACE_ASSERT(len != 0, "prvTraceCreateSymbolTableEntry: len == 0", 0);\r
717 \r
718     if (RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + len + 4 >= SYMBOL_TABLE_SIZE)\r
719     {\r
720         vTraceError("Symbol table full. Increase SYMBOL_TABLE_SIZE in trcConfig.h");\r
721         ret = 0;\r
722     }\r
723     else\r
724     {\r
725 \r
726         RecorderDataPtr->SymbolTable.symbytes\r
727             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] =\r
728             (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] & 0x00FF);\r
729 \r
730         RecorderDataPtr->SymbolTable.symbytes\r
731             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] =\r
732             (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] / 0x100);\r
733 \r
734         RecorderDataPtr->SymbolTable.symbytes\r
735             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] =\r
736             (uint8_t)(channel & 0x00FF);\r
737 \r
738         RecorderDataPtr->SymbolTable.symbytes\r
739             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] =\r
740             (uint8_t)(channel / 0x100);\r
741 \r
742         /* set name (bytes 4...4+len-1) */\r
743         (void)strncpy((char*)&(RecorderDataPtr->SymbolTable.symbytes\r
744             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4]), name, len);\r
745 \r
746         /* Set zero termination (at offset 4+len) */\r
747         RecorderDataPtr->SymbolTable.symbytes\r
748             [RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4 + len] = '\0';\r
749 \r
750         /* store index of entry (for return value, and as head of LL[crc6]) */\r
751         RecorderDataPtr->SymbolTable.latestEntryOfChecksum\r
752             [ crc6 ] = (uint16_t)RecorderDataPtr->SymbolTable.nextFreeSymbolIndex;\r
753 \r
754         RecorderDataPtr->SymbolTable.nextFreeSymbolIndex += (len + 5);\r
755 \r
756         ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex -\r
757             (len + 5));\r
758     }\r
759 \r
760     return ret;\r
761 }\r
762 \r
763 \r
764 /*******************************************************************************\r
765  * prvTraceGetChecksum\r
766  *\r
767  * Calculates a simple 6-bit checksum from a string, used to index the string\r
768  * for fast symbol table lookup.\r
769  ******************************************************************************/\r
770 void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength)\r
771 {\r
772    unsigned char c;\r
773    int length = 0;\r
774    int crc = 0;\r
775 \r
776    TRACE_ASSERT(pname != NULL, "prvTraceGetChecksum: pname == NULL", );\r
777    TRACE_ASSERT(pcrc != NULL, "prvTraceGetChecksum: pcrc == NULL", );\r
778    TRACE_ASSERT(plength != NULL, "prvTraceGetChecksum: plength == NULL", );\r
779 \r
780    if (pname != (const char *) 0)\r
781    {\r
782       for (; (c = *pname++) != '\0';)\r
783       {\r
784          crc += c;\r
785          length++;\r
786       }\r
787    }\r
788    *pcrc = (uint8_t)(crc & 0x3F);\r
789    *plength = (uint8_t)length;\r
790 }\r
791 \r
792 #endif