/******************************************************************************* | |
* FreeRTOS+Trace v2.2.3 Recorder Library | |
* Percepio AB, www.percepio.se | |
* | |
* trcBase.h | |
* | |
* Core functionallity of the FreeRTOS+Trace recorder library. | |
* | |
* Terms of Use | |
* This software is copyright Percepio AB. The recorder library is free for | |
* use together with Percepio products. You may distribute the recorder library | |
* in its original form, including modifications in trcPort.c and trcPort.h | |
* given that these modification are clearly marked as your own modifications | |
* and documented in the initial comment section of these source files. | |
* This software is the intellectual property of Percepio AB and may not be | |
* sold or in other ways commercially redistributed without explicit written | |
* permission by Percepio AB. | |
* | |
* Disclaimer | |
* The trace tool and recorder library is being delivered to you AS IS and | |
* Percepio AB makes no warranty as to its use or performance. Percepio AB does | |
* not and cannot warrant the performance or results you may obtain by using the | |
* software or documentation. Percepio AB make no warranties, express or | |
* implied, as to noninfringement of third party rights, merchantability, or | |
* fitness for any particular purpose. In no event will Percepio AB, its | |
* technology partners, or distributors be liable to you for any consequential, | |
* incidental or special damages, including any lost profits or lost savings, | |
* even if a representative of Percepio AB has been advised of the possibility | |
* of such damages, or for any claim by any third party. Some jurisdictions do | |
* not allow the exclusion or limitation of incidental, consequential or special | |
* damages, or the exclusion of implied warranties or limitations on how long an | |
* implied warranty may last, so the above limitations may not apply to you. | |
* | |
* FreeRTOS+Trace is available as Free Edition and in two premium editions. | |
* You may use the premium features during 30 days for evaluation. | |
* Download FreeRTOS+Trace at http://www.percepio.se/index.php?page=downloads | |
* | |
* Copyright Percepio AB, 2012. | |
* www.percepio.se | |
******************************************************************************/ | |
#ifndef TRCBASE_H | |
#define TRCBASE_H | |
#include <stdio.h> | |
#include <string.h> | |
#include <stdint.h> | |
#include "FreeRTOS.h" | |
#include "trcConfig.h" | |
#include "trcTypes.h" | |
#include "trcPort.h" | |
#define NCLASSES 5 | |
#define VERSION 0x1AA1 | |
#define MINOR_VERSION 1 | |
#define STORE_MODE_STOP_WHEN_FULL 1 | |
#define STORE_MODE_RING_BUFFER 2 | |
#define TRACE_DATA_ALLOCATION_STATIC 1 | |
#define TRACE_DATA_ALLOCATION_DYNAMIC 2 | |
/****************************************************************************** | |
* Object Property Table | |
* The Object Table contains name and other properties of the objects (tasks, | |
* queues, mutexes, etc). The below data structures defines the properties of | |
* each object class and are used to cast the byte buffer into a cleaner format. | |
* | |
* The values in the object table are continously overwritten and always | |
* represent the current state. If a property is changed during runtime, the OLD | |
* value should be stored in the trace buffer, not the new value (since the new | |
* value is found in the Object Property Table). | |
* For close events this mechanism is the old names are stored in the symbol | |
* table), for "priority set" (the old priority is stored in the event data) | |
* and for "isActive", where the value decides is the taskswitch event type | |
* should be "new" or "resume". | |
******************************************************************************/ | |
/* The size of the Object Property Table entries, in bytes, per object */ | |
/* Queue properties (except name): current number of message in queue */ | |
#define PropertyTableSizeQueue (NameLenQueue + 1) | |
/* Semaphore properties (except name): state (signaled = 1, cleared = 0) */ | |
#define PropertyTableSizeSemaphore (NameLenSemaphore + 1) | |
/* Mutex properties (except name): owner (task handle, 0 = free) */ | |
#define PropertyTableSizeMutex (NameLenMutex + 1) | |
/* Task properties (except name): Byte 0: Current priority | |
Byte 1: state (if already active) | |
Byte 2: InstanceFinishEvent_ServiceCode | |
Byte 3: InstanceFinishEvent_ObjHandle */ | |
#define PropertyTableSizeTask (NameLenTask + 4) | |
/* ISR properties: Byte 0: priority | |
Byte 1: state (if already active) */ | |
#define PropertyTableSizeISR (NameLenISR + 2) | |
/* The layout of the byte array representing the Object Property Table */ | |
#define StartIndexQueue 0 | |
#define StartIndexSemaphore StartIndexQueue + NQueue * PropertyTableSizeQueue | |
#define StartIndexMutex StartIndexSemaphore + NSemaphore * PropertyTableSizeSemaphore | |
#define StartIndexTask StartIndexMutex + NMutex * PropertyTableSizeMutex | |
#define StartIndexISR StartIndexTask + NTask * PropertyTableSizeTask | |
#define DynObjTableSize StartIndexISR + NISR * PropertyTableSizeISR | |
typedef struct | |
{ | |
/* = NCLASSES */ | |
uint32_t NumberOfObjectClasses; | |
uint32_t ObjectPropertyTableSizeInBytes; | |
/* This is used to calculate the index in the dynamic object table | |
(handle - 1 - nofStaticObjects = index)*/ | |
uint8_t NumberOfObjectsPerClass[ 4*((NCLASSES+3)/4)]; | |
/* Allocation size rounded up to the closest multiple of 4 */ | |
uint8_t NameLengthPerClass[ 4*((NCLASSES+3)/4) ]; | |
uint8_t TotalPropertyBytesPerClass[ 4*((NCLASSES+3)/4) ]; | |
/* Allocation size rounded up to the closest multiple of 2 */ | |
uint16_t StartIndexOfClass[ 2*((NCLASSES+1)/2) ]; | |
/* The actual handles issued, should be Initiated to all zeros */ | |
uint8_t objbytes[ 4*((DynObjTableSize+3)/4) ]; | |
} ObjectPropertyTableType; | |
/* Symbol table data structure */ | |
typedef struct | |
{ | |
/* = SYMBOL_HISTORY_TABLE_SIZE_IN_BYTES */ | |
uint32_t symTableSize; | |
/* Entry 0 is reserved. Any reference to entry 0 implies NULL*/ | |
uint32_t nextFreeSymbolIndex; | |
/* Size rounded up to closest multiple of 4, to avoid alignment issues*/ | |
uint8_t symbytes[4*((SYMBOL_TABLE_SIZE+3)/4)]; | |
/* Used for lookups - Up to 64 linked lists within the symbol table | |
connecting all entries with the same 6 bit checksum. | |
This field holds the current list heads. Should be initiated to zeros */ | |
uint16_t latestEntryOfChecksum[64]; | |
} symbolTableType; | |
/******************************************************************************* | |
* The data structures of the different events, all 4 bytes long | |
******************************************************************************/ | |
typedef struct | |
{ | |
uint8_t type; | |
objectHandleType objHandle; | |
uint16_t dts; /* differential timestamp - time since last event */ | |
} TSEvent; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t objHandle; | |
uint16_t dts; | |
} KernelCall; | |
typedef struct | |
{ | |
uint8_t type; | |
objectHandleType objHandle; | |
uint8_t param; | |
uint8_t dts; | |
} KernelCallWithParamAndHandle; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t dts; | |
uint16_t param; | |
} KernelCallWithParam16; | |
typedef struct | |
{ | |
uint8_t type; | |
objectHandleType objHandle; /* the handle of the closed object */ | |
uint16_t symbolIndex; /* the name of the closed object */ | |
} ObjCloseNameEvent; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t arg1; | |
uint8_t arg2; | |
uint8_t arg3; | |
} ObjClosePropEvent; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t dts; | |
uint16_t payload; /* the name of the user event */ | |
} UserEvent; | |
typedef struct | |
{ | |
uint8_t type; | |
/* 8 bits extra for storing DTS, if it does not fit in ordinary event | |
(this one is always MSB if used) */ | |
uint8_t xts_8; | |
/* 16 bits extra for storing DTS, if it does not fit in ordinary event. */ | |
uint16_t xts_16; | |
} XTSEvent; | |
/******************************************************************************* | |
* The main datastructure, read by FreeRTOS+Trace from the RAM dump | |
******************************************************************************/ | |
typedef struct | |
{ | |
uint8_t startmarker0; | |
uint8_t startmarker1; | |
uint8_t startmarker2; | |
uint8_t startmarker3; | |
uint8_t startmarker4; | |
uint8_t startmarker5; | |
uint8_t startmarker6; | |
uint8_t startmarker7; | |
uint8_t startmarker8; | |
uint8_t startmarker9; | |
uint8_t startmarker10; | |
uint8_t startmarker11; | |
/* For FreeRTOS: 0x1AA1 */ | |
uint16_t version; | |
/* Currently 1 for v2.2.2 (0 earlier)*/ | |
uint8_t minor_version; | |
/* This should be 0 if lower irq priority values implies higher priority | |
levels, such as on ARM Cortex M. If the opposite scheme is used, i.e., | |
if higher irq priority values means higher priority, this should be 1. */ | |
uint8_t irq_priority_order; | |
/* sizeof(RecorderDataType) - just for control */ | |
uint32_t filesize; | |
/* Current number of events recorded */ | |
uint32_t numEvents; | |
/* The buffer size, in number of event records */ | |
uint32_t maxEvents; | |
/* The event buffer index, where to write the next event */ | |
uint32_t nextFreeIndex; | |
/* 1 if the buffer is full, 0 otherwise */ | |
uint32_t bufferIsFull; | |
/* The frequency of the clock/timer/counter used as time base */ | |
uint32_t frequency; | |
/* The absolute timestamp of the last stored event, in the native | |
timebase, modulo frequency! */ | |
uint32_t absTimeLastEvent; | |
/* The number of seconds in total - lasts for 136 years */ | |
uint32_t absTimeLastEventSecond; | |
/* 1 if the recorder has been started, 0 if not yet started or stopped. | |
This is a 32 bit variable due to alignment issues. */ | |
uint32_t recorderActive; | |
/* For storing a Team License key */ | |
uint8_t teamLicenceKey[32]; | |
/* 0xF0F0F0F0 - for control only */ | |
int32_t debugMarker0; | |
/* The Object Property Table holds information about currently active | |
tasks, queues, and other recorded objects. This is updated on each | |
create call and includes object name and other properties. */ | |
ObjectPropertyTableType ObjectPropertyTable; | |
/* 0xF1F1F1F1 - for control only */ | |
int32_t debugMarker1; | |
/* The Symbol Table stores strings for User Events and is also used to | |
store names of deleted objects, which still may be in the trace but no | |
longer are available. */ | |
symbolTableType SymbolTable; | |
/* For includsion of float support, and for endian detection of floats. | |
The value should be (float)1 or (uint32_t)0 */ | |
#if (INCLUDE_FLOAT_SUPPORT == 1) | |
float exampleFloatEncoding; | |
#else | |
uint32_t exampleFloatEncoding; | |
#endif | |
/* This is non-zero if an internal error occured in the recorder, e.g., if | |
one of the Nxxx constants was too small. The systemInfo string will then | |
contain an error message that is displayed when attempting to view the | |
trace file. */ | |
uint32_t internalErrorOccured; | |
/* 0xF2F2F2F2 - for control only */ | |
int32_t debugMarker2; | |
/* Generic system information string, presented in the tool. Note that this | |
is also used for storing any internal error messages from the recorder, so | |
do not make TRACE_DESCRIPTION_MAX_LENGTH too small. 80 is recommended. */ | |
char systemInfo[TRACE_DESCRIPTION_MAX_LENGTH]; | |
/* 0xF3F3F3F3 - for control only */ | |
int32_t debugMarker3; | |
/* The event data, in 4-byte records */ | |
uint8_t eventData[ EVENT_BUFFER_SIZE * 4 ]; | |
uint8_t endmarker0; | |
uint8_t endmarker1; | |
uint8_t endmarker2; | |
uint8_t endmarker3; | |
uint8_t endmarker4; | |
uint8_t endmarker5; | |
uint8_t endmarker6; | |
uint8_t endmarker7; | |
uint8_t endmarker8; | |
uint8_t endmarker9; | |
uint8_t endmarker10; | |
uint8_t endmarker11; | |
} RecorderDataType; | |
extern RecorderDataType* RecorderDataPtr; | |
/****************************************************************************** | |
* ObjectHandleStack | |
* This data-structure is used to provide a mechanism for 1-byte trace object | |
* handles. This way, only 1 byte is necessary instead of 4 bytes (a pointer) | |
* when storing a reference to an object. This allows for up to 255 objects of | |
* each object class - Task, ISR, Semaphore, CountingSemaphore, Mutex and Queue, | |
* active at any given moment. There can be more "historic" objects, that have | |
* been deleted - that number is only limited by the size of the symbol table. | |
* Note that handle zero (0) is not used, it is a code for an invalid handle. | |
* | |
* This data structure keeps track of the FREE handles, not the handles in use. | |
* This datastructure contains one stack per object class. When a handle is | |
* allocated to an object, the next free handle is popped from the stack. When | |
* a handle is released (on object delete), it is pushed back on the stack. | |
* Note that there is no initialization code that pushed the free handles | |
* initially, that is not necessary due to the following optimization: | |
* | |
* The stack of handles (objectHandles) is initially all zeros. Since zero | |
* is not a valid handle, that is a signal of additional handles needed. | |
* If a zero is received when popping a new handle, it is replaced by the | |
* index of the popped handle instead. | |
* | |
*****************************************************************************/ | |
typedef struct | |
{ | |
/* For each object class, the index of the next handle to allocate */ | |
int16_t indexOfNextAvailableHandle[ NCLASSES ]; | |
/* The lowest index of this class (constant) */ | |
int16_t lowestIndexOfClass[ NCLASSES ]; | |
/* The highest index of this class (constant) */ | |
int16_t highestIndexOfClass[ NCLASSES ]; | |
/* The highest use count for this class (for statistics) */ | |
int16_t handleCountWaterMarksOfClass[ NCLASSES ]; | |
/* The free object handles - a set of stacks within this array */ | |
objectHandleType objectHandles[ NTask+NISR+NSemaphore+NMutex+NQueue ]; | |
} objectHandleStackType; | |
/* Internal data */ | |
extern objectHandleStackType objectHandleStacks; | |
extern uint8_t taskFlags[NTask]; | |
/* Internal functions */ | |
uint32_t prvTraceGetDTS(uint32_t param_maxDTS); | |
void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength); | |
traceLabel prvTraceCreateSymbolTableEntry(const char* name, | |
uint8_t crc6, | |
uint8_t len, | |
traceLabel channel); | |
traceLabel prvTraceLookupSymbolTableEntry(const char* name, | |
uint8_t crc6, | |
uint8_t len, | |
traceLabel channel); | |
traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel); | |
void prvTraceUpdateCounters(void); | |
void prvCheckDataToBeOverwrittenForMultiEntryUserEvents(uint32_t nEntries); | |
objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass); | |
void vTraceFreeObjectHandle(traceObjectClass objectclass, | |
objectHandleType handle); | |
void vTraceSetObjectName(traceObjectClass objectclass, | |
objectHandleType handle, | |
const char* name); | |
void* xTraceNextFreeEventBufferSlot(void); | |
uint32_t uiIndexOfObject(objectHandleType objecthandle, | |
uint8_t objectclass); | |
/******************************************************************************* | |
* vTraceError | |
* | |
* Called by various parts in the recorder. Stops the recorder and stores a | |
* pointer to an error message, which is printed by the monitor task. | |
******************************************************************************/ | |
void vTraceError(char* msg); | |
/******************************************************************************* | |
* xTraceGetLastError | |
* | |
* Gives the last error message, if any. NULL if no error message is stored. | |
* The message is cleared on read. | |
******************************************************************************/ | |
char* xTraceGetLastError(void); | |
/******************************************************************************* | |
* xTraceInitTraceData | |
* | |
* Allocates and initializes the recorder datastructure, based on the constants | |
* in trcConfig.h. This allows for allocating the data on the heap, instead of | |
* using a static declaration. | |
******************************************************************************/ | |
RecorderDataType* xTraceInitTraceData(void); | |
/* Internal macros */ | |
#define PROPERTY_NAME_GET(objectclass, objecthandle) \ | |
(const char*)(& RecorderDataPtr->ObjectPropertyTable.objbytes \ | |
[uiIndexOfObject(objecthandle, objectclass)]) | |
#define PROPERTY_OBJECT_STATE(objectclass, handle) \ | |
RecorderDataPtr->ObjectPropertyTable.objbytes[uiIndexOfObject(handle, objectclass) \ | |
+ RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[objectclass]] | |
#define PROPERTY_ACTOR_PRIORITY(objectclass, handle) \ | |
RecorderDataPtr->ObjectPropertyTable.objbytes[uiIndexOfObject(handle, objectclass) \ | |
+ RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[objectclass] + 1] | |
#define PROPERTY_TASK_IFE_SERVICECODE(handle) \ | |
RecorderDataPtr->ObjectPropertyTable.objbytes \ | |
[uiIndexOfObject(handle, TRACE_CLASS_TASK) \ | |
+ RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[TRACE_CLASS_TASK]+2] | |
#define PROPERTY_TASK_IFE_OBJHANDLE(handle) \ | |
RecorderDataPtr->ObjectPropertyTable.objbytes \ | |
[uiIndexOfObject(handle, TRACE_CLASS_TASK) \ | |
+ RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[TRACE_CLASS_TASK]+3] | |
#define TASK_FLAG_BITMASK_ExcludeTaskFromTrace 1 | |
#define TASK_FLAG_BITMASK_MarkNextEventAsTaskInstanceFinish 2 | |
#define SET_TASK_FLAG_ISEXCLUDED(taskHandle) taskFlags[taskHandle] |= 0x01 | |
#define CLEAR_TASK_FLAG_ISEXCLUDED(taskHandle) taskFlags[taskHandle] &= 0xFE | |
#define GET_TASK_FLAG_ISEXCLUDED(taskHandle) (taskFlags[taskHandle] & 0x01) | |
#define SET_TASK_FLAG_MARKIFE(taskHandle) taskFlags[taskHandle] |= 0x02 | |
#define CLEAR_TASK_FLAG_MARKIFE(taskHandle) taskFlags[taskHandle] &= 0xFD | |
#define GET_TASK_FLAG_MARKIFE(taskHandle) (taskFlags[taskHandle] & 0x02) | |
/* For debug printouts - the names of the object classes */ | |
extern char OBJECTCLASSNAME[NCLASSES][10]; | |
/*= | |
{ | |
"QUEUE" | |
"SEMAPHORE", | |
"MUTEX", | |
"TASK", | |
"ISR" | |
};*/ | |
#endif | |