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