]> git.sur5r.net Git - freertos/blob - FreeRTOS-Plus/Demo/FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC/ThirdParty/TraceRecorderSrc/trcBase.c
Split the LPC18xx FreeRTOS+UDP drivers between those that use the LPCOpen library...
[freertos] / FreeRTOS-Plus / Demo / FreeRTOS_Plus_UDP_and_CLI_LPC1830_GCC / ThirdParty / TraceRecorderSrc / trcBase.c
1 /*******************************************************************************\r
2  * FreeRTOS+Trace v2.3.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 trcPort.c and trcPort.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  * FreeRTOS+Trace is available as Free Edition and in two premium editions.\r
35  * You may use the premium features during 30 days for evaluation.\r
36  * Download FreeRTOS+Trace at http://www.percepio.com/products/downloads/\r
37  *\r
38  * Copyright Percepio AB, 2012.\r
39  * www.percepio.com\r
40  ******************************************************************************/\r
41 \r
42 #include "trcUser.h"\r
43 #include "task.h"\r
44 \r
45 #if (configUSE_TRACE_FACILITY == 1)\r
46 \r
47 /*******************************************************************************\r
48  * Static data initializations\r
49  ******************************************************************************/\r
50 \r
51 \r
52 /*******************************************************************************\r
53  * RecorderData\r
54  *\r
55  * The main data structure. This is the data read by FreeRTOS+Trace, typically\r
56  * through a debugger RAM dump. The recorder access this through the pointer\r
57  * RecorderDataPtr, to allow for dynamic memory allocation as well.\r
58  *\r
59  * On the NXP LPC17xx you may use the secondary RAM bank (AHB RAM) for this\r
60  * purpose. For instance, the LPC1766 has 32 KB AHB RAM which allows for \r
61  * allocating a buffer size of at least 7500 events without affecting the main\r
62  * RAM. To place RecorderData in this RAM bank, use the below declaration.\r
63  * \r
64  *     #pragma location="AHB_RAM_MEMORY"\r
65  *     RecorderDataType RecorderData = ...\r
66  * \r
67  * This of course works for other hardware architectures with additional RAM \r
68  * banks as well, just replace "AHB_RAM_MEMORY" with the name of the right \r
69  * address section from the linker file.\r
70  *\r
71  * However, to keep trcBase.c portable and still have a preconfigured IAR demo\r
72  * using AHB RAM, we don't add the pragma directly in trcBase.c but in a header \r
73  * included where the pragma should go. This is used depending on the setting\r
74  * USE_LINKER_PRAGMA, defined in trcConfig.h.\r
75  * \r
76  * If using GCC, this is instead done by adding a "section" attribute:\r
77  *\r
78  *     RecorderDataType RecorderData __attribute__ ((section ("name"))) = ...\r
79  *\r
80  * Remember to replace "name" with the correct section name.\r
81  ******************************************************************************/\r
82 \r
83 #if (TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_STATIC)\r
84 #if (USE_LINKER_PRAGMA == 1)\r
85 #include "recorderdata_linker_pragma.h"\r
86 #endif\r
87 RecorderDataType RecorderData =\r
88 {\r
89     /* start marker, 12 chars */\r
90     0x01, 0x02, 0x03, 0x04,\r
91     0x71, 0x72, 0x73, 0x74,\r
92     0xF1, 0xF2, 0xF3, 0xF4,\r
93 \r
94     /* version code - also used to determine endianness */\r
95     VERSION,\r
96 \r
97     /* minor file format version */\r
98     MINOR_VERSION,\r
99     \r
100     /* irq priority order */\r
101     IRQ_PRIORITY_ORDER,\r
102 \r
103     /* file size (for control) */\r
104     sizeof(RecorderDataType),\r
105 \r
106     /* number of events stored so far */\r
107     0,\r
108 \r
109     /* size of events buffer (in event records, each 4 bytes) */\r
110     EVENT_BUFFER_SIZE,\r
111 \r
112     /* next free event index (event index, not byte address) */\r
113     0,\r
114 \r
115     /* buffer is full */ \r
116     0,\r
117 \r
118     /* frequency of clock user for timestamps, in Hz - should be 0 here\r
119     as this is used to indicate "not yet initialized" - this is instead\r
120     initialized on the first taskswitch event. */\r
121     0,\r
122 \r
123     /* the absolute timestamp of the last stored event, modulo frequency */\r
124     0,\r
125 \r
126     /* the number of seconds so far */\r
127     0,\r
128 \r
129     /* is recorder active (yes = 1) - note that "close" events are always \r
130         stored to keep the name-handle mapping updated!*/\r
131     0,\r
132 \r
133     /* Generated by FreeRTOS+Trace in Team Admin mode. Otherwise this should be "". */\r
134     TEAM_LICENSE_CODE,\r
135 \r
136     /* debug marker 0 */\r
137     0xF0F0F0F0,\r
138 \r
139     /* The Object Property Table - holds info of all active objects */ \r
140     {\r
141         /* Number of object classes, also those not used */\r
142         NCLASSES,\r
143 \r
144         /* The size in bytes of the object table byte pool */\r
145         DynObjTableSize,\r
146 \r
147         /* The number of slots/handles available for each class */\r
148         {\r
149             NQueue,\r
150             NSemaphore,\r
151             NMutex,\r
152             NTask,\r
153             NISR\r
154         },\r
155 \r
156         /* The maximum name length for each object class */\r
157         {\r
158             NameLenQueue,\r
159             NameLenSemaphore,\r
160             NameLenMutex,\r
161             NameLenTask,\r
162             NameLenISR\r
163         },\r
164 \r
165         /* The total length a property table entry of the class */\r
166         {\r
167             PropertyTableSizeQueue,\r
168             PropertyTableSizeSemaphore,\r
169             PropertyTableSizeMutex,\r
170             PropertyTableSizeTask,\r
171             PropertyTableSizeISR\r
172         },\r
173 \r
174         /* The start index of each class in the object property table */\r
175         {\r
176             StartIndexQueue,\r
177             StartIndexSemaphore,\r
178             StartIndexMutex,\r
179             StartIndexTask,\r
180             StartIndexISR\r
181         },\r
182 \r
183         /* the object property table - encoded in a byte array using above \r
184         definitions */\r
185         {0}\r
186     },\r
187 \r
188     /* debug marker 1 */\r
189     0xF1F1F1F1,\r
190 \r
191     /* The Symbol Table - holds all object names used since system \r
192        startup. Every string is unique, so objects with same name will share \r
193        an entry. Each name entry has four extra bytes: byte 0-1 is a link \r
194        reference in an internal linked list, used for fast lookups, byte 2-3 \r
195        holds a reference to a channel label used for vTracePrintF format \r
196        strings, and byte 4.. holds the object name, followed by a \r
197        zero-termination.*/\r
198     {\r
199         SYMBOL_TABLE_SIZE,\r
200 \r
201         /* next free index (0 is reserved to mean NULL) */\r
202         1,\r
203 \r
204         /* the symbol table byte pool */\r
205         {0},\r
206 \r
207         /* this is a 64 entry array holding 16-bit references (indexes) \r
208            to the most recent entry of each checksum - i.e., list heads.*/\r
209         {0},\r
210 \r
211     },\r
212 \r
213 #if (INCLUDE_FLOAT_SUPPORT == 1)\r
214     /* example float, for float endian detection */\r
215     (float)1.0,\r
216 #else\r
217     /* This code signals that no float support is included */\r
218     (uint32_t)0, \r
219 #endif\r
220 \r
221     /* internalErrorOccured */\r
222     0,\r
223     \r
224     /* debug marker 2 */\r
225     0xF2F2F2F2,\r
226     \r
227     /* The trace description string, can hold any information about the system, \r
228         e.g., version, configuration. Error messages from the recorder are\r
229         copied to this buffer. Also used for internal error messages.*/\r
230     TRACE_DESCRIPTION,\r
231         \r
232     /* debug marker 3 */\r
233     0xF3F3F3F3,\r
234 \r
235     /* the event data buffer, size EVENT_BUFFER_SIZE*4 */\r
236     {0},\r
237 \r
238     /* end markers, used to extract the trace from a RAM dump image */\r
239     0x0A, 0x0B, 0x0C, 0x0D,\r
240     0x71, 0x72, 0x73, 0x74,\r
241     0xF1, 0xF2, 0xF3, 0xF4\r
242 };\r
243 \r
244 RecorderDataType* RecorderDataPtr = &RecorderData;\r
245 \r
246 /* This version of the function does nothing as the trace data is statically allocated */\r
247 RecorderDataType* xTraceInitTraceData(void)\r
248 {\r
249     return 0;\r
250 }\r
251 \r
252 #elif (TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_DYNAMIC)\r
253 \r
254 RecorderDataType* RecorderDataPtr = NULL;\r
255 \r
256 /* This version of the function dynamically allocates the trace data */\r
257 RecorderDataType* xTraceInitTraceData(void)\r
258 {\r
259     RecorderDataType* tmp = (RecorderDataType*)pvPortMalloc(sizeof(RecorderDataType));\r
260 \r
261     if (! tmp)\r
262     {\r
263         vTraceError("Malloc failed in xTraceInitTraceData! Reduce size constants in trcConfig.h");\r
264         return NULL;\r
265     }\r
266     \r
267     (void)memset(tmp, 0, sizeof(RecorderDataType));\r
268 \r
269     tmp->startmarker0 = 0x01;\r
270     tmp->startmarker1 = 0x02;\r
271     tmp->startmarker2 = 0x03;\r
272     tmp->startmarker3 = 0x04;\r
273     tmp->startmarker4 = 0x71;\r
274     tmp->startmarker5 = 0x72;\r
275     tmp->startmarker6 = 0x73;\r
276     tmp->startmarker7 = 0x74;\r
277     tmp->startmarker8 = 0xF1;\r
278     tmp->startmarker9 = 0xF2;\r
279     tmp->startmarker10 = 0xF3;\r
280     tmp->startmarker11 = 0xF4;\r
281     tmp->version = VERSION;\r
282     tmp->minor_version = MINOR_VERSION;\r
283     tmp->irq_priority_order = IRQ_PRIORITY_ORDER;\r
284     tmp->filesize = sizeof(RecorderDataType);\r
285     \r
286     tmp->maxEvents = EVENT_BUFFER_SIZE;\r
287     \r
288     tmp->debugMarker0 = 0xF0F0F0F0;\r
289     tmp->ObjectPropertyTable.NumberOfObjectClasses = NCLASSES;\r
290     tmp->ObjectPropertyTable.ObjectPropertyTableSizeInBytes = DynObjTableSize;\r
291     tmp->ObjectPropertyTable.NumberOfObjectsPerClass[0] = NQueue;\r
292     tmp->ObjectPropertyTable.NumberOfObjectsPerClass[1] = NSemaphore;\r
293     tmp->ObjectPropertyTable.NumberOfObjectsPerClass[2] = NMutex;\r
294     tmp->ObjectPropertyTable.NumberOfObjectsPerClass[3] = NTask;\r
295     tmp->ObjectPropertyTable.NumberOfObjectsPerClass[4] = NISR;\r
296     tmp->ObjectPropertyTable.NameLengthPerClass[0] = NameLenQueue;\r
297     tmp->ObjectPropertyTable.NameLengthPerClass[1] = NameLenSemaphore;\r
298     tmp->ObjectPropertyTable.NameLengthPerClass[2] = NameLenMutex;\r
299     tmp->ObjectPropertyTable.NameLengthPerClass[3] = NameLenTask;\r
300     tmp->ObjectPropertyTable.NameLengthPerClass[4] = NameLenISR;\r
301     tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue;\r
302     tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore;\r
303     tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex;\r
304     tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[3] = PropertyTableSizeTask;\r
305     tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[4] = PropertyTableSizeISR;\r
306     tmp->ObjectPropertyTable.StartIndexOfClass[0] = StartIndexQueue;\r
307     tmp->ObjectPropertyTable.StartIndexOfClass[1] = StartIndexSemaphore;\r
308     tmp->ObjectPropertyTable.StartIndexOfClass[2] = StartIndexMutex;\r
309     tmp->ObjectPropertyTable.StartIndexOfClass[3] = StartIndexTask;\r
310     tmp->ObjectPropertyTable.StartIndexOfClass[4] = StartIndexISR;    \r
311     tmp->debugMarker1 = 0xF1F1F1F1;\r
312     tmp->SymbolTable.symTableSize = SYMBOL_TABLE_SIZE;\r
313     tmp->SymbolTable.nextFreeSymbolIndex = 1;\r
314 #if (INCLUDE_FLOAT_SUPPORT == 1)\r
315     tmp->exampleFloatEncoding = (float)1.0; /* otherwize already zero */\r
316 #endif\r
317     tmp->debugMarker2 = 0xF2F2F2F2;    \r
318     (void)strncpy(tmp->systemInfo, TRACE_DESCRIPTION, TRACE_DESCRIPTION_MAX_LENGTH);\r
319     tmp->debugMarker3 = 0xF3F3F3F3;\r
320     tmp->endmarker0 = 0x0A;\r
321     tmp->endmarker1 = 0x0B;\r
322     tmp->endmarker2 = 0x0C;\r
323     tmp->endmarker3 = 0x0D;\r
324     tmp->endmarker4 = 0x71;\r
325     tmp->endmarker5 = 0x72;\r
326     tmp->endmarker6 = 0x73;\r
327     tmp->endmarker7 = 0x74;\r
328     tmp->endmarker8 = 0xF1;\r
329     tmp->endmarker9 = 0xF2;\r
330     tmp->endmarker10 = 0xF3;\r
331     tmp->endmarker11 = 0xF4;\r
332     \r
333     RecorderDataPtr = tmp;\r
334 \r
335     return (RecorderDataType*)RecorderDataPtr;\r
336 }\r
337 \r
338 #endif\r
339 \r
340 volatile int recorder_busy = 0;\r
341 \r
342 char sprintfBuffer[150];\r
343 \r
344 /* For debug printouts - the names of the object classes */\r
345 char OBJECTCLASSNAME[NCLASSES][10] =\r
346 {\r
347         "QUEUE",\r
348         "SEMAPHORE",\r
349         "MUTEX",\r
350         "TASK",\r
351         "ISR"\r
352 };\r
353 \r
354 /* Initialization of the handle mechanism, see e.g, xTraceGetObjectHandle */\r
355 objectHandleStackType objectHandleStacks =\r
356 {\r
357         /* indexOfNextAvailableHandle */\r
358         {\r
359                 0,\r
360                 NQueue,\r
361                 NQueue + NSemaphore,\r
362                 NQueue + NSemaphore + NMutex,\r
363                 NQueue + NSemaphore + NMutex + NTask\r
364         },\r
365 \r
366         /* lowestIndexOfClass */\r
367         {\r
368                 0,\r
369                 NQueue,\r
370                 NQueue + NSemaphore,\r
371                 NQueue + NSemaphore + NMutex,\r
372                 NQueue + NSemaphore + NMutex + NTask\r
373         },\r
374 \r
375         /* highestIndexOfClass */\r
376         {\r
377                 NQueue - 1,\r
378                 NQueue + NSemaphore - 1,\r
379                 NQueue + NSemaphore + NMutex - 1,\r
380                 NQueue + NSemaphore + NMutex + NTask - 1,\r
381                 NQueue + NSemaphore + NMutex + NTask + NISR - 1\r
382         },\r
383         {0},\r
384         {0}\r
385 };\r
386 \r
387 \r
388 /* Used for internal state flags of objects */\r
389 uint8_t excludedFlags[(NEventCodes+NQueue+NSemaphore+NMutex+NTask) / 8 + 1];\r
390 uint8_t ifeFlags[NTask / 8 + 1];\r
391 \r
392 /* Gives the last error message of the recorder. NULL if no error message. */\r
393 char* traceErrorMessage = NULL;\r
394 \r
395 void* xTraceNextFreeEventBufferSlot(void)\r
396 {\r
397     if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE)\r
398     {\r
399         vTraceError("Attempt to index outside event buffer!");\r
400         return NULL;\r
401     }\r
402     return (void*)(&RecorderDataPtr->\r
403                    eventData[RecorderDataPtr->nextFreeIndex*4]);\r
404 }\r
405 \r
406 uint16_t uiIndexOfObject(objectHandleType objecthandle, uint8_t objectclass)\r
407 {\r
408     if ((objectclass < NCLASSES) && (objecthandle > 0) && (objecthandle <= \r
409     RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]))\r
410     {\r
411         return (uint16_t)(RecorderDataPtr->\r
412             ObjectPropertyTable.StartIndexOfClass[objectclass] + \r
413             (RecorderDataPtr->\r
414             ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * \r
415             (objecthandle-1)));\r
416     }\r
417     \r
418     vTraceError("Object table lookup with invalid object handle or object class!");    \r
419     return 0;\r
420 }\r
421 \r
422 /*******************************************************************************\r
423  * Object handle system \r
424  * This provides a mechanism to assign each kernel object (tasks, queues, etc)\r
425  * with a 1-byte handle, that is used to identify the object in the trace.\r
426  * This way, only one byte instead of four is necessary to identify the object.\r
427  * This allows for maximum 255 objects, of each object class, active at any\r
428  * moment.\r
429  * Note that zero is reserved as an error code and is not a valid handle.\r
430  * \r
431  * In order to allow for fast dynamic allocation and release of object handles, \r
432  * the handles of each object class (e.g., TASK) are stored in a stack. When a \r
433  * handle is needed, e.g., on task creation, the next free handle is popped from \r
434  * the stack. When an object (e.g., task) is deleted, its handle is pushed back \r
435  * on the stack and can thereby be reused for other objects.\r
436  * \r
437  * Since this allows for reuse of object handles, a specific handle (e.g, "8") \r
438  * may refer to TASK_X at one point, and later mean "TASK_Y". To resolve this, \r
439  * the recorder uses "Close events", which are stored in the main event buffer \r
440  * when objects are deleted and their handles are released. The close event \r
441  * contains the mapping between object handle and object name which was valid up\r
442  * to this point in time. The object name is stored as a symbol table entry. \r
443  ******************************************************************************/\r
444 \r
445 objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass)\r
446 {\r
447     static objectHandleType handle;\r
448     static int indexOfHandle;\r
449 \r
450     indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass];\r
451     if (objectHandleStacks.objectHandles[indexOfHandle] == 0)\r
452     {\r
453         /* Zero is used to indicate a never before used handle, i.e.,\r
454            new slots in the handle stack. The handle slot needs to \r
455            be initialized here (starts at 1). */\r
456         objectHandleStacks.objectHandles[indexOfHandle] = \r
457             (objectHandleType)(1 + indexOfHandle - \r
458             objectHandleStacks.lowestIndexOfClass[objectclass]);\r
459     }\r
460 \r
461     handle = objectHandleStacks.objectHandles[indexOfHandle];\r
462     \r
463     if ( objectHandleStacks.indexOfNextAvailableHandle[objectclass] \r
464         > objectHandleStacks.highestIndexOfClass[objectclass] )\r
465     {\r
466         /* ERROR */\r
467         switch(objectclass)\r
468         {\r
469         case TRACE_CLASS_TASK:\r
470             vTraceError("Not enough TASK handles - increase NTask in trcConfig.h");         \r
471             break;\r
472         case TRACE_CLASS_ISR:\r
473             vTraceError("Not enough ISR handles - increase NISR in trcConfig.h");         \r
474             break;\r
475         case TRACE_CLASS_SEMAPHORE:\r
476             vTraceError("Not enough SEMAPHORE handles - increase NSemaphore in trcConfig.h");         \r
477             break;\r
478         case TRACE_CLASS_MUTEX:\r
479             vTraceError("Not enough MUTEX handles - increase NMutex in trcConfig.h");         \r
480             break;\r
481         case TRACE_CLASS_QUEUE:\r
482             vTraceError("Not enough QUEUE handles - increase NQueue in trcConfig.h");         \r
483             break;\r
484         default:\r
485             vTraceError("Invalid object class.");\r
486             break;\r
487         }\r
488         \r
489         handle = 0; /* an invalid/anonymous handle - but the recorder is stopped now... */\r
490     }\r
491     else\r
492     {\r
493         int hndCount;\r
494         objectHandleStacks.indexOfNextAvailableHandle[objectclass]++;\r
495         \r
496         hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] - \r
497             objectHandleStacks.lowestIndexOfClass[objectclass];\r
498         \r
499         if (hndCount > \r
500             objectHandleStacks.handleCountWaterMarksOfClass[objectclass])\r
501         {\r
502             objectHandleStacks.handleCountWaterMarksOfClass[objectclass] = \r
503                 (objectHandleType)hndCount;\r
504         }\r
505     }\r
506 \r
507     return handle;\r
508 }\r
509 \r
510 void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handle)\r
511 {\r
512     int indexOfHandle;\r
513 \r
514     /* Check that there is room to push the handle on the stack */\r
515     if ( (objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) < \r
516         objectHandleStacks.lowestIndexOfClass[objectclass] )\r
517     {\r
518         /* Error */\r
519         vTraceError("Attempt to free more handles than allocated! (duplicate xTaskDelete or xQueueDelete?)");\r
520     }\r
521     else\r
522     {\r
523         objectHandleStacks.indexOfNextAvailableHandle[objectclass]--;\r
524         indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass];\r
525         objectHandleStacks.objectHandles[indexOfHandle] = handle;\r
526     }\r
527 \r
528 }\r
529 \r
530 /*******************************************************************************\r
531  * Objects Property Table \r
532  *\r
533  * This holds the names and properties of the currently active objects, such as\r
534  * tasks and queues. This is developed to support "dynamic" objects which might\r
535  * be deleted during runtime. Their handles are only valid during their\r
536  * lifetime, i.e., from create to delete, as they might be reused on later\r
537  * create operations. When an object is deleted from the OPT, its data is moved\r
538  * to the trace buffer and/or the symbol table.\r
539  * When an object (task, queue, etc.) is created, it receives a handle, which\r
540  * together with the object class specifies its location in the OPT. Thus,\r
541  * objects of different types may share the same name and/or handle, but still\r
542  * be independent objects.\r
543  ******************************************************************************/\r
544 \r
545 /*******************************************************************************\r
546  * vTraceSetObjectName\r
547  *\r
548  * Registers the names of queues, semaphores and other kernel objects in the\r
549  * recorder's Object Property Table, at the given handle and object class.\r
550  ******************************************************************************/\r
551 void vTraceSetObjectName(traceObjectClass objectclass, \r
552                          objectHandleType handle, \r
553                          const char* name)\r
554 {\r
555     static uint16_t idx;\r
556 \r
557     if (handle == 0)\r
558     {\r
559         vTraceError("Illegal handle (0) in vTraceSetObjectName.");   \r
560         return;\r
561     }\r
562     \r
563     switch(objectclass)\r
564     {\r
565         case TRACE_CLASS_TASK:\r
566         case TRACE_CLASS_ISR:\r
567         case TRACE_CLASS_SEMAPHORE:\r
568         case TRACE_CLASS_MUTEX:\r
569         case TRACE_CLASS_QUEUE:\r
570         break;\r
571     default:\r
572         vTraceError("Illegal object class in vTraceSetObjectName");   \r
573         break;            \r
574     }\r
575 \r
576     if (handle > \r
577         RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass])\r
578     {\r
579         switch(objectclass)\r
580         {\r
581             case TRACE_CLASS_TASK:\r
582             vTraceError("Not enough TASK handles - increase NTask in trcConfig.h");         \r
583             break;\r
584             case TRACE_CLASS_ISR:\r
585             vTraceError("Not enough ISR handles - increase NISR in trcConfig.h");       \r
586             break;\r
587             case TRACE_CLASS_SEMAPHORE:\r
588             vTraceError("Not enough SEMAPHORE handles - increase NSemaphore in trcConfig.h");\r
589             break;\r
590             case TRACE_CLASS_MUTEX:\r
591             vTraceError("Not enough MUTEX handles - increase NMutex in trcConfig.h");\r
592             break;\r
593             case TRACE_CLASS_QUEUE:\r
594             vTraceError("Not enough QUEUE handles - increase NQueue in trcConfig.h");\r
595             break;\r
596         }\r
597     }\r
598     else\r
599     {\r
600         idx = uiIndexOfObject(handle, objectclass);\r
601 \r
602         if (traceErrorMessage == NULL)\r
603         {\r
604             (void)strncpy((char*)&(RecorderDataPtr->ObjectPropertyTable.objbytes[idx]),\r
605                     name,\r
606                     RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ] );\r
607 #ifdef WIN32\r
608             printf("vTraceSetObjectName(%d, %d, %s)\n", objectclass, handle, name);\r
609 #endif\r
610         }\r
611     }\r
612 }\r
613 \r
614 traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel)\r
615 {\r
616     static uint16_t result;\r
617     static uint8_t len;\r
618     static uint8_t crc;\r
619     len = 0;\r
620     crc = 0;\r
621     prvTraceGetChecksum(name, &crc, &len);\r
622 \r
623     trcCRITICAL_SECTION_BEGIN();\r
624     result = prvTraceLookupSymbolTableEntry(name, crc, len, userEventChannel);\r
625     if (!result)\r
626     {\r
627         result = prvTraceCreateSymbolTableEntry(name, crc, len, userEventChannel);\r
628     }\r
629     trcCRITICAL_SECTION_END();\r
630 \r
631     return result;\r
632 }\r
633 \r
634 /*******************************************************************************\r
635  * Supporting functions\r
636  ******************************************************************************/\r
637 \r
638 /*******************************************************************************\r
639  * vTraceError\r
640  *\r
641  * Called by various parts in the recorder. Stops the recorder and stores a \r
642  * pointer to an error message, which is printed by the monitor task.\r
643  * If you are not using the monitor task, you may use xTraceGetLastError() \r
644  * from your application to check if the recorder is OK.\r
645  *\r
646  * Note: If a recorder error is registered before vTraceStart is called, the \r
647  * trace start will be aborted. This can occur if any of the Nxxxx constants \r
648  * (e.g., NTask) in trcConfig.h is too small.\r
649  ******************************************************************************/\r
650 void vTraceError(const char* msg)\r
651 {\r
652     vTraceStop();\r
653     if (traceErrorMessage == NULL)\r
654     {\r
655       traceErrorMessage = (char*)msg;\r
656       (void)strncpy(RecorderDataPtr->systemInfo, \r
657           traceErrorMessage, \r
658           TRACE_DESCRIPTION_MAX_LENGTH);\r
659       RecorderDataPtr->internalErrorOccured = 1;\r
660     }\r
661 }\r
662 \r
663 /******************************************************************************\r
664  * prvCheckDataToBeOverwrittenForMultiEntryUserEvents\r
665  *\r
666  * This checks if the next event to be overwritten is a multi-entry user event, \r
667  * i.e., a USER_EVENT followed by data entries.\r
668  * Such data entries do not have an event code at byte 0, as other events.\r
669  * All 4 bytes are user data, so the first byte of such data events must \r
670  * not be interpreted as type field. The number of data entries following\r
671  * a USER_EVENT is given in the event code of the USER_EVENT.\r
672  * Therefore, when overwriting a USER_EVENT (when using in ringbuffer mode)\r
673  * any data entries following must be replaced with NULL events (code 0).\r
674  *\r
675  * This is assumed to execute within a critical section...\r
676  *****************************************************************************/\r
677 \r
678 void prvCheckDataToBeOverwrittenForMultiEntryUserEvents(\r
679     uint8_t nofEntriesToCheck)\r
680 {\r
681     /* Generic "int" type is desired - should be 16 bit variable on 16 bit HW */\r
682     unsigned int i = 0; \r
683     unsigned int e = 0;\r
684     while (i < nofEntriesToCheck)\r
685     {        \r
686         e = RecorderDataPtr->nextFreeIndex + i;\r
687         if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) && \r
688             (RecorderDataPtr->eventData[e*4] < USER_EVENT + 16))\r
689         {\r
690             uint8_t nDataEvents = (uint8_t)(RecorderDataPtr->eventData[e*4] - USER_EVENT);\r
691             if ((e + nDataEvents) < RecorderDataPtr->maxEvents)\r
692             {\r
693                 (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4 * nDataEvents);\r
694             }\r
695         }\r
696         i++;\r
697     }\r
698 }\r
699 \r
700 /*******************************************************************************\r
701  * prvTraceUpdateCounters\r
702  *\r
703  * Updates the index of the event buffer.\r
704  ******************************************************************************/\r
705 void prvTraceUpdateCounters(void)\r
706 {\r
707     if (RecorderDataPtr->recorderActive == 0)\r
708     {\r
709         return;\r
710     }\r
711     \r
712     RecorderDataPtr->numEvents++;\r
713 \r
714     RecorderDataPtr->nextFreeIndex++;\r
715     \r
716     if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE)\r
717     {   \r
718 #if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER)       \r
719         RecorderDataPtr->bufferIsFull = 1;\r
720         RecorderDataPtr->nextFreeIndex = 0;\r
721 #else\r
722         vTraceStop();\r
723 #endif\r
724     }\r
725 \r
726 #if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER)\r
727     prvCheckDataToBeOverwrittenForMultiEntryUserEvents(1);\r
728 #endif\r
729     \r
730 #ifdef STOP_AFTER_N_EVENTS\r
731 #if (STOP_AFTER_N_EVENTS > -1)\r
732     if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS)\r
733     {\r
734         vTraceStop();\r
735     }\r
736 #endif\r
737 #endif\r
738 }\r
739     \r
740 /******************************************************************************\r
741  * prvTraceGetDTS\r
742  *\r
743  * Returns a differential timestamp (DTS), i.e., the time since\r
744  * last event, and creates an XTS event if the DTS does not fit in the\r
745  * number of bits given. The XTS event holds the MSB bytes of the DTS.\r
746  *\r
747  * The parameter param_maxDTS should be 0xFF for 8-bit dts or 0xFFFF for\r
748  * events with 16-bit dts fields.\r
749  *****************************************************************************/\r
750 uint16_t prvTraceGetDTS(uint16_t param_maxDTS)\r
751 {\r
752     static uint32_t old_timestamp = 0;\r
753     XTSEvent* xts = 0;\r
754     uint32_t dts = 0;\r
755     uint32_t timestamp = 0;\r
756 \r
757     if (RecorderDataPtr->frequency == 0)\r
758     {\r
759         /* If HWTC_PERIOD is mapped to the timer reload register,\r
760         such as in the Cortex M port, it is not initialized before\r
761         FreeRTOS has been started. We therefore store the frequency\r
762         of the timer at the first timestamped event after the \r
763         scheduler has started. (Note that this function is called\r
764         also by vTraceStart and uiTraceStart, which might be\r
765         called before the scheduler has been started.) */\r
766 \r
767 #if (SELECTED_PORT == PORT_Win32)    \r
768         RecorderDataPtr->frequency = 100000;\r
769 #elif (SELECTED_PORT == PORT_HWIndependent)    \r
770         RecorderDataPtr->frequency = configTICK_RATE_HZ;\r
771 #else        \r
772         if (xTaskGetSchedulerState() != 0) /* Has the scheduler started? */\r
773         {            \r
774             RecorderDataPtr->frequency = \r
775                  (uint32_t)HWTC_PERIOD * (uint32_t)configTICK_RATE_HZ / (uint32_t)HWTC_DIVISOR; \r
776         }\r
777 #endif\r
778     }\r
779 \r
780     /**************************************************************************\r
781     * The below statements read the timestamp from the timer port module.\r
782     * If necessary, whole seconds are extracted using division while the rest\r
783     * comes from the modulo operation.\r
784     **************************************************************************/\r
785     \r
786     uiTracePortGetTimeStamp(&timestamp);\r
787 \r
788     /***************************************************************************\r
789     * This condition is only for the Win32 port, since it does not use the tick\r
790     * count but instead only HWTC_COUNT (from the performance counter).\r
791     * Without this condition, you sometimes get a negative dts value (converted\r
792     * into a very large unsiged value) when the performance counter wraps \r
793     * around. In other "normal" ports also using the FreeRTOS tick counter, this \r
794     * condition can not occur and therefore has no impact.\r
795     ***************************************************************************/\r
796     if (timestamp < old_timestamp)\r
797     {\r
798         timestamp += RecorderDataPtr->frequency;\r
799     }\r
800 \r
801 \r
802         dts = timestamp - old_timestamp;\r
803     old_timestamp = timestamp;\r
804     \r
805     if (RecorderDataPtr->frequency > 0)\r
806     {\r
807         /* Check if dts > 1 second */\r
808         if (dts > RecorderDataPtr->frequency)\r
809         {\r
810             /* More than 1 second has passed */\r
811             RecorderDataPtr->absTimeLastEventSecond += dts / RecorderDataPtr->frequency;\r
812             /* The part that is not an entire second is added to absTimeLastEvent */\r
813             RecorderDataPtr->absTimeLastEvent += dts % RecorderDataPtr->frequency;\r
814         }\r
815         else\r
816             RecorderDataPtr->absTimeLastEvent += dts;\r
817         \r
818         /* Check if absTimeLastEvent >= 1 second */\r
819         if (RecorderDataPtr->absTimeLastEvent >= RecorderDataPtr->frequency)\r
820         {\r
821             /* RecorderDataPtr->absTimeLastEvent is more than or equal to 1 second, but always less than 2 seconds */\r
822             RecorderDataPtr->absTimeLastEventSecond++;\r
823             RecorderDataPtr->absTimeLastEvent -= RecorderDataPtr->frequency;\r
824             /* RecorderDataPtr->absTimeLastEvent is now less than 1 second */\r
825         }\r
826     }\r
827     else\r
828     {\r
829         /* Special case if the recorder has not yet started (frequency may be uninitialized, i.e., zero) */\r
830         RecorderDataPtr->absTimeLastEvent = timestamp;\r
831     }\r
832 \r
833     /* If the dts (time since last event) does not fit in event->dts (only 8 or 16 bits) */\r
834     if (dts > param_maxDTS)\r
835     {\r
836         /* Create an XTS event (eXtended TimeStamp) containing the higher dts bits*/\r
837         xts = (XTSEvent*) xTraceNextFreeEventBufferSlot();\r
838 \r
839         if (xts != NULL)\r
840         {\r
841             if (param_maxDTS == 0xFFFF)\r
842             {\r
843                 xts->type = XTS16;\r
844                 xts->xts_16 = (uint16_t)((dts / 0x10000) & 0xFFFF);\r
845                 xts->xts_8 = 0;\r
846             }\r
847             else if (param_maxDTS == 0xFF)\r
848             {\r
849                 xts->type = XTS8;\r
850                 xts->xts_16 = (uint16_t)((dts / 0x100) & 0xFFFF);\r
851                 xts->xts_8 = (uint8_t)((dts / 0x1000000) & 0xFF);\r
852             }\r
853             else\r
854             {\r
855                 vTraceError("Bad param_maxDTS in prvTraceGetDTS");\r
856             }\r
857             prvTraceUpdateCounters();\r
858         }\r
859     }\r
860 \r
861     return (uint16_t)(dts % (param_maxDTS + 1));\r
862 }\r
863 \r
864 /*******************************************************************************\r
865  * prvTraceLookupSymbolTableEntry\r
866  *\r
867  * Find an entry in the symbol table, return 0 if not present.\r
868  *\r
869  * The strings are stored in a byte pool, with four bytes of "meta-data" for\r
870  * every string.\r
871  * byte 0-1: index of next entry with same checksum (for fast lookup).\r
872  * byte 2-3: reference to a symbol table entry, a label for vTracePrintF\r
873  * format strings only (the handle of the destination channel).\r
874  * byte 4..(4 + length): the string (object name or user event label), with\r
875  * zero-termination\r
876  ******************************************************************************/\r
877 traceLabel prvTraceLookupSymbolTableEntry(const char* name, \r
878                                           uint8_t crc6, \r
879                                           uint8_t len, \r
880                                           traceLabel chn)\r
881 {\r
882     uint16_t i = RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ];\r
883 \r
884     while (i != 0)\r
885     {\r
886         if (RecorderDataPtr->SymbolTable.symbytes[i + 2] == (chn & 0x00FF))\r
887         {\r
888             if (RecorderDataPtr->SymbolTable.symbytes[i + 3] == (chn / 0x100))\r
889             {\r
890                 if (RecorderDataPtr->SymbolTable.symbytes[i + 4 + len] == '\0')\r
891                 {\r
892                     if (strncmp((char*)(& RecorderDataPtr->SymbolTable.symbytes[i + 4]), name, len) == 0)\r
893                     {\r
894                         break; /* found */\r
895                     }\r
896                 }\r
897             }\r
898         }\r
899         i = (uint16_t)(RecorderDataPtr->SymbolTable.symbytes[i] + (RecorderDataPtr->SymbolTable.symbytes[i + 1] * 0x100));\r
900     }\r
901     return i;\r
902 }\r
903 \r
904 /*******************************************************************************\r
905  * prvTraceCreateSymbolTableEntry\r
906  *\r
907  * Creates an entry in the symbol table, independent if it exists already.\r
908  *\r
909  * The strings are stored in a byte pool, with four bytes of "meta-data" for\r
910  * every string.\r
911  * byte 0-1: index of next entry with same checksum (for fast lookup).\r
912  * byte 2-3: reference to a symbol table entry, a label for vTracePrintF\r
913  * format strings only (the handle of the destination channel).\r
914  * byte 4..(4 + length): the string (object name or user event label), with\r
915  * zero-termination\r
916  ******************************************************************************/\r
917 uint16_t prvTraceCreateSymbolTableEntry(const char* name, \r
918                                         uint8_t crc6, \r
919                                         uint8_t len, \r
920                                         traceLabel channel)\r
921 {\r
922     uint16_t ret = 0;\r
923     if (RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + len + 4 >= SYMBOL_TABLE_SIZE)\r
924     {\r
925         vTraceError("Symbol table full. Increase SYMBOL_TABLE_SIZE in trcConfig.h");\r
926         ret = 0;        \r
927     }\r
928     else\r
929     {\r
930 \r
931         RecorderDataPtr->SymbolTable.symbytes\r
932             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] = \r
933             (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] & 0x00FF);\r
934 \r
935         RecorderDataPtr->SymbolTable.symbytes\r
936             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] = \r
937             (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] / 0x100);\r
938 \r
939         RecorderDataPtr->SymbolTable.symbytes\r
940             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] = \r
941             (uint8_t)(channel & 0x00FF);\r
942 \r
943         RecorderDataPtr->SymbolTable.symbytes\r
944             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] = \r
945             (uint8_t)(channel / 0x100);\r
946 \r
947         /* set name (bytes 4...4+len-1) */\r
948         (void)strncpy((char*)&( RecorderDataPtr->SymbolTable.symbytes\r
949             [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4] ), name, len);\r
950 \r
951         /* Set zero termination (at offest 4+len) */\r
952         RecorderDataPtr->SymbolTable.symbytes\r
953             [RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4 + len] = '\0';\r
954 \r
955         /* store index of entry (for return value, and as head of LL[crc6]) */\r
956         RecorderDataPtr->SymbolTable.latestEntryOfChecksum\r
957             [ crc6 ] = (uint16_t)RecorderDataPtr->SymbolTable.nextFreeSymbolIndex;\r
958         \r
959         RecorderDataPtr->SymbolTable.nextFreeSymbolIndex += (len + 5);\r
960         \r
961         ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex - \r
962             (len + 5));\r
963     }\r
964     \r
965     return ret;\r
966 }\r
967 \r
968 \r
969 /*******************************************************************************\r
970  * prvTraceGetChecksum\r
971  *\r
972  * Calculates a simple 6-bit checksum from a string, used to index the string \r
973  * for fast symbol table lookup.\r
974  ******************************************************************************/\r
975 void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength)\r
976 {\r
977    unsigned char c;\r
978    int length = 0;\r
979    int crc = 0;\r
980    if ( pname != (const char *) 0 )\r
981    {\r
982       for ( ; (c = *pname++) != '\0'; )\r
983       {\r
984          crc += c;\r
985          length++;\r
986       }\r
987    }\r
988    *pcrc = (uint8_t)(crc % 64);\r
989    *plength = (uint8_t)length;\r
990 }\r
991 \r
992 #endif\r