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