/******************************************************************************* | |
* Trace Recorder Library for Tracealyzer v4.1.5 | |
* Percepio AB, www.percepio.com | |
* | |
* trcRecorder.h | |
* | |
* The public API of the trace recorder. | |
* | |
* Terms of Use | |
* This file is part of the trace recorder library (RECORDER), which is the | |
* intellectual property of Percepio AB (PERCEPIO) and provided under a | |
* license as follows. | |
* The RECORDER may be used free of charge for the purpose of recording data | |
* intended for analysis in PERCEPIO products. It may not be used or modified | |
* for other purposes without explicit permission from PERCEPIO. | |
* You may distribute the RECORDER in its original source code form, assuming | |
* this text (terms of use, disclaimer, copyright notice) is unchanged. You are | |
* allowed to distribute the RECORDER with minor modifications intended for | |
* configuration or porting of the RECORDER, e.g., to allow using it on a | |
* specific processor, processor family or with a specific communication | |
* interface. Any such modifications should be documented directly below | |
* this comment block. | |
* | |
* Disclaimer | |
* The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty | |
* as to its use or performance. PERCEPIO does not and cannot warrant the | |
* performance or results you may obtain by using the RECORDER or documentation. | |
* PERCEPIO 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, 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 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. | |
* | |
* Tabs are used for indent in this file (1 tab = 4 spaces) | |
* | |
* Copyright Percepio AB, 2018. | |
* www.percepio.com | |
******************************************************************************/ | |
#ifndef TRC_RECORDER_H | |
#define TRC_RECORDER_H | |
#ifdef __cplusplus | |
extern "C" { | |
#endif | |
#include <stdint.h> | |
#include <stddef.h> | |
#include "trcConfig.h" | |
#include "trcPortDefines.h" | |
#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) | |
typedef uint16_t traceString; | |
typedef uint8_t traceUBChannel; | |
typedef uint8_t traceObjectClass; | |
#if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1) | |
typedef uint16_t traceHandle; | |
#else | |
typedef uint8_t traceHandle; | |
#endif | |
#include "trcHardwarePort.h" | |
#include "trcKernelPort.h" | |
// Not available in snapshot mode | |
#define vTraceConsoleChannelPrintF(fmt, ...) | |
#endif | |
#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) | |
typedef const char* traceString; | |
typedef const void* traceHandle; | |
#include "trcHardwarePort.h" | |
#include "trcStreamingPort.h" | |
#include "trcKernelPort.h" | |
#endif | |
#if (TRC_USE_TRACEALYZER_RECORDER == 1) | |
/* The user event channel for recorder warnings, must be defined in trcKernelPort.c */ | |
extern traceString trcWarningChannel; | |
#define TRACE_GET_LOW16(value) ((uint16_t)((value) & 0x0000FFFF)) | |
#define TRACE_GET_HIGH16(value) ((uint16_t)(((value) >> 16) & 0x0000FFFF)) | |
#define TRACE_SET_LOW16(current, value) (((current) & 0xFFFF0000) | (value)) | |
#define TRACE_SET_HIGH16(current, value) (((current) & 0x0000FFFF) | (((uint32_t)(value)) << 16)) | |
/******************************************************************************/ | |
/*** Common API - both Snapshot and Streaming mode ****************************/ | |
/******************************************************************************/ | |
/****************************************************************************** | |
* vTraceEnable(int startOption); | |
* | |
* Initializes and optionally starts the trace, depending on the start option. | |
* To use the trace recorder, the startup must call vTraceEnable before any RTOS | |
* calls are made (including "create" calls). Three start options are provided: | |
* | |
* TRC_START: Starts the tracing directly. In snapshot mode this allows for | |
* starting the trace at any point in your code, assuming vTraceEnable(TRC_INIT) | |
* has been called in the startup. | |
* Can also be used for streaming without Tracealyzer control, e.g. to a local | |
* flash file system (assuming such a "stream port", see trcStreamingPort.h). | |
* | |
* TRC_START_AWAIT_HOST: For streaming mode only. Initializes the trace recorder | |
* if necessary and waits for a Start command from Tracealyzer ("Start Recording" | |
* button). This call is intentionally blocking! By calling vTraceEnable with | |
* this option from the startup code, you start tracing at this point and capture | |
* the early events. | |
* | |
* TRC_INIT: Initializes the trace recorder, but does not start the tracing. | |
* In snapshot mode, this must be followed by a vTraceEnable(TRC_START) sometime | |
* later. | |
* | |
* Usage examples: | |
* | |
* Snapshot trace, from startup: | |
* <board init> | |
* vTraceEnable(TRC_START); | |
* <RTOS init> | |
* | |
* Snapshot trace, from a later point: | |
* <board init> | |
* vTraceEnable(TRC_INIT); | |
* <RTOS init> | |
* ... | |
* vTraceEnable(TRC_START); // e.g., in task context, at some relevant event | |
* | |
* Streaming trace, from startup: | |
* <board init> | |
* vTraceEnable(TRC_START_AWAIT_HOST); // Blocks! | |
* <RTOS init> | |
* | |
* Streaming trace, from a later point: | |
* <board startup> | |
* vTraceEnable(TRC_INIT); | |
* <RTOS startup> | |
* | |
******************************************************************************/ | |
void vTraceEnable(int startOption); | |
/****************************************************************************** | |
* vTracePrintF | |
* | |
* Generates "User Events", with formatted text and data, similar to a "printf". | |
* User Events can be used for very efficient logging from your application code. | |
* It is very fast since the actual string formatting is done on the host side, | |
* when the trace is displayed. The execution time is just some microseconds on | |
* a 32-bit MCU. | |
* | |
* User Events are shown as yellow labels in the main trace view of $PNAME. | |
* | |
* An advantage of User Events is that data can be plotted in the "User Event | |
* Signal Plot" view, visualizing any data you log as User Events, discrete | |
* states or control system signals (e.g. system inputs or outputs). | |
* | |
* You may group User Events into User Event Channels. The yellow User Event | |
* labels show the logged string, preceded by the channel name within brackets. | |
* | |
* Example: | |
* | |
* "[MyChannel] Hello World!" | |
* | |
* The User Event Channels are shown in the View Filter, which makes it easy to | |
* select what User Events you wish to display. User Event Channels are created | |
* using xTraceRegisterString(). | |
* | |
* Example: | |
* | |
* traceString adc_uechannel = xTraceRegisterString("ADC User Events"); | |
* ... | |
* vTracePrintF(adc_uechannel, | |
* "ADC channel %d: %d volts", | |
* ch, adc_reading); | |
* | |
* The following format specifiers are supported in both modes: | |
* %d - signed integer. | |
* %u - unsigned integer. | |
* %X - hexadecimal, uppercase. | |
* %x - hexadecimal, lowercase. | |
* %s - string (see comment below) | |
* | |
* For integer formats (%d, %u, %x, %X) you may also use width and padding. | |
* If using -42 as data argument, two examples are: | |
* "%05d" -> "-0042" | |
* "%5d" -> " -42". | |
* | |
* String arguments are supported in both snapshot and streaming, but in streaming | |
* mode you need to use xTraceRegisterString and use the returned traceString as | |
* the argument. In snapshot you simply provide a char* as argument. | |
* | |
* Snapshot: vTracePrintF(myChn, "my string: %s", str); | |
* Streaming: vTracePrintF(myChn, "my string: %s", xTraceRegisterString(str)); | |
* | |
* In snapshot mode you can specify 8-bit or 16-bit arguments to reduce RAM usage: | |
* %hd -> 16 bit (h) signed integer (d). | |
* %bu -> 8 bit (b) unsigned integer (u). | |
* | |
* However, in streaming mode all data arguments are assumed to be 32 bit wide. | |
* Width specifiers (e.g. %hd) are accepted but ignored (%hd treated like %d). | |
* | |
* The maximum event size also differs between the modes. In streaming this is | |
* limited by a maximum payload size of 52 bytes, including format string and | |
* data arguments. So if using one data argument, the format string is limited | |
* to 48 byte, etc. If this is exceeded, the format string is truncated and you | |
* get a warning in Tracealyzer. | |
* | |
* In snapshot mode you are limited to maximum 15 arguments, that must not exceed | |
* 32 bytes in total (not counting the format string). If exceeded, the recorder | |
* logs an internal error (displayed when opening the trace) and stops recording. | |
******************************************************************************/ | |
#if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) | |
void vTracePrintF(traceString chn, const char* fmt, ...); | |
#else | |
#define vTracePrintF(chn, ...) (void)chn | |
#endif | |
/****************************************************************************** | |
* vTracePrint | |
* | |
* A faster version of vTracePrintF, that only allows for logging a string. | |
* | |
* Example: | |
* | |
* traceString chn = xTraceRegisterString("MyChannel"); | |
* ... | |
* vTracePrint(chn, "Hello World!"); | |
******************************************************************************/ | |
#if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) | |
void vTracePrint(traceString chn, const char* str); | |
#else | |
#define vTracePrint(chn, ...) (void)chn | |
#endif | |
/******************************************************************************* | |
* vTraceConsoleChannelPrintF | |
* | |
* Wrapper for vTracePrint, using the default channel. Can be used as a drop-in | |
* replacement for printf and similar functions, e.g. in a debug logging macro. | |
* | |
* Example: | |
* | |
* // Old: #define LogString debug_console_printf | |
* | |
* // New, log to Tracealyzer instead: | |
* #define LogString vTraceConsoleChannelPrintF | |
* ... | |
* LogString("My value is: %d", myValue); | |
******************************************************************************/ | |
#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) | |
void vTraceConsoleChannelPrintF(const char* fmt, ...); | |
#endif | |
/******************************************************************************* | |
* xTraceRegisterString | |
* | |
* Register strings in the recorder, e.g. for names of user event channels. | |
* | |
* Example: | |
* myEventHandle = xTraceRegisterString("MyUserEvent"); | |
* ... | |
* vTracePrintF(myEventHandle, "My value is: %d", myValue); | |
******************************************************************************/ | |
#if (TRC_CFG_SCHEDULING_ONLY == 0) && (TRC_CFG_INCLUDE_USER_EVENTS == 1) | |
traceString xTraceRegisterString(const char* name); | |
#else | |
#define xTraceRegisterString(x) (x) | |
#endif | |
/******************************************************************************* | |
* vTraceSet...Name(void* object, const char* name) | |
* | |
* Parameter object: pointer to the kernel object that shall be named | |
* Parameter name: the name to set | |
* | |
* Kernel-specific functions for setting names of kernel objects, for display in | |
* Tracealyzer. | |
******************************************************************************/ | |
/* See trcKernelPort.h for details (kernel-specific) */ | |
/******************************************************************************* | |
* xTraceSetISRProperties | |
* | |
* Stores a name and priority level for an Interrupt Service Routine, to allow | |
* for better visualization. Returns a traceHandle used by vTraceStoreISRBegin. | |
* | |
* Example: | |
* #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt | |
* ... | |
* traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); | |
* ... | |
* void ISR_handler() | |
* { | |
* vTraceStoreISRBegin(Timer1Handle); | |
* ... | |
* vTraceStoreISREnd(0); | |
* } | |
******************************************************************************/ | |
traceHandle xTraceSetISRProperties(const char* name, uint8_t priority); | |
/******************************************************************************* | |
* vTraceStoreISRBegin | |
* | |
* Registers the beginning of an Interrupt Service Routine, using a traceHandle | |
* provided by xTraceSetISRProperties. | |
* | |
* Example: | |
* #define PRIO_ISR_TIMER1 3 // the hardware priority of the interrupt | |
* ... | |
* traceHandle Timer1Handle = xTraceSetISRProperties("ISRTimer1", PRIO_ISR_TIMER1); | |
* ... | |
* void ISR_handler() | |
* { | |
* vTraceStoreISRBegin(Timer1Handle); | |
* ... | |
* vTraceStoreISREnd(0); | |
* } | |
******************************************************************************/ | |
void vTraceStoreISRBegin(traceHandle handle); | |
/******************************************************************************* | |
* vTraceStoreISREnd | |
* | |
* Registers the end of an Interrupt Service Routine. | |
* | |
* The parameter pendingISR indicates if the interrupt has requested a | |
* task-switch (= 1), e.g., by signaling a semaphore. Otherwise (= 0) the | |
* interrupt is assumed to return to the previous context. | |
* | |
* Example: | |
* #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt | |
* traceHandle traceHandleIsrTimer1 = 0; // The ID set by the recorder | |
* ... | |
* traceHandleIsrTimer1 = xTraceSetISRProperties("ISRTimer1", PRIO_OF_ISR_TIMER1); | |
* ... | |
* void ISR_handler() | |
* { | |
* vTraceStoreISRBegin(traceHandleIsrTimer1); | |
* ... | |
* vTraceStoreISREnd(0); | |
* } | |
******************************************************************************/ | |
void vTraceStoreISREnd(int isTaskSwitchRequired); | |
/******************************************************************************* | |
* vTraceInstanceFinishNow | |
* | |
* Creates an event that ends the current task instance at this very instant. | |
* This makes the viewer to splits the current fragment at this point and begin | |
* a new actor instance, even if no task-switch has occurred. | |
*****************************************************************************/ | |
void vTraceInstanceFinishedNow(void); | |
/******************************************************************************* | |
* vTraceInstanceFinishedNext | |
* | |
* Marks the current "task instance" as finished on the next kernel call. | |
* | |
* If that kernel call is blocking, the instance ends after the blocking event | |
* and the corresponding return event is then the start of the next instance. | |
* If the kernel call is not blocking, the viewer instead splits the current | |
* fragment right before the kernel call, which makes this call the first event | |
* of the next instance. | |
*****************************************************************************/ | |
void vTraceInstanceFinishedNext(void); | |
/******************************************************************************* | |
* xTraceGetLastError | |
* | |
* Returns the last error or warning as a string, or NULL if none. | |
*****************************************************************************/ | |
const char* xTraceGetLastError(void); | |
/******************************************************************************* | |
* vTraceClearError | |
* | |
* Clears any errors. | |
*****************************************************************************/ | |
void vTraceClearError(void); | |
/******************************************************************************* | |
* vTraceStop | |
* | |
* Stops the recording. Intended for snapshot mode or if streaming without | |
* Tracealyzer control (e.g., to a device file system). | |
******************************************************************************/ | |
void vTraceStop(void); | |
/****************************************************************************** | |
* vTraceSetFrequency | |
* | |
* Registers the clock rate of the time source for the event timestamping. | |
* This is normally not required, but if the default value (TRC_HWTC_FREQ_HZ) | |
* should be incorrect for your setup, you can override it using this function. | |
* | |
* Must be called prior to vTraceEnable, and the time source is assumed to | |
* have a fixed clock frequency after the startup. | |
* | |
* Note that, in snapshot mode, the value is divided by the TRC_HWTC_DIVISOR. | |
* This is a software "prescaler" that is also applied on the timestamps. | |
*****************************************************************************/ | |
void vTraceSetFrequency(uint32_t frequency); | |
/******************************************************************************* | |
* vTraceSetRecorderDataBuffer | |
* | |
* The trcConfig.h setting TRC_CFG_RECORDER_BUFFER_ALLOCATION allows for selecting | |
* custom allocation (TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM), which allows you to | |
* control where the recorder trace buffer is allocated. | |
* | |
* When custom allocation is selected, use TRC_ALLOC_CUSTOM_BUFFER to make the | |
* allocation (in global context) and then call vTraceSetRecorderDataBuffer to | |
* register the allocated buffer. This supports both snapshot and streaming, | |
* and has no effect if using other allocation modes than CUSTOM. | |
* | |
* NOTE: vTraceSetRecorderDataBuffer must be called before vTraceEnable. | |
******************************************************************************/ | |
#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM) | |
void vTraceSetRecorderDataBuffer(void* pRecorderData); | |
#else | |
#define vTraceSetRecorderDataBuffer(pRecorderData) | |
#endif | |
/******************************************************************************* | |
* TRC_ALLOC_CUSTOM_BUFFER | |
* | |
* If using custom allocation of the trace buffer (i.e., your trcConfig.h has the | |
* setting TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM), this macro allows you to declare | |
* the trace buffer in a portable way that works both in snapshot and streaming. | |
* | |
* This macro has no effect if using another allocation mode, so you can easily | |
* switch between different recording modes and configurations, using the same | |
* initialization code. | |
* | |
* This translates to a single static allocation, on which you can apply linker | |
* directives to place it in a particular memory region. | |
* | |
* - Snapshot mode: "RecorderDataType <name>" | |
* | |
* - Streaming mode: "char <name> [<size>]", | |
* where <size> is defined in trcStreamingConfig.h. | |
* | |
* Example: | |
* | |
* // GCC example: place myTraceBuffer in section .tz, defined in the .ld file. | |
* TRC_ALLOC_CUSTOM_BUFFER(myTraceBuffer) __attribute__((section(".tz"))); | |
* | |
* int main(void) | |
* { | |
* ... | |
* vTraceSetRecorderDataBuffer(&myTraceBuffer); // Note the "&" | |
* ... | |
* vTraceEnable(TRC_INIT); // Initialize the data structure | |
******************************************************************************/ | |
#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_CUSTOM) | |
#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) | |
#define TRC_ALLOC_CUSTOM_BUFFER(bufname) RecorderDataType bufname; | |
#elif (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) | |
#ifdef TRC_CFG_RTT_BUFFER_SIZE_UP /* J-Link RTT */ | |
#define TRC_ALLOC_CUSTOM_BUFFER(bufname) char bufname [TRC_CFG_RTT_BUFFER_SIZE_UP]; /* Not static in this case, since declared in user code */ | |
#else | |
#define TRC_ALLOC_CUSTOM_BUFFER(bufname) char bufname [(TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; | |
#endif | |
#endif | |
#else | |
#define TRC_ALLOC_CUSTOM_BUFFER(bufname) | |
#endif | |
/****************************************************************************** | |
* xTraceIsRecordingEnabled | |
* | |
* Returns true (1) if the recorder is enabled (i.e. is recording), otherwise 0. | |
******************************************************************************/ | |
int xTraceIsRecordingEnabled(void); | |
/******************************************************************************* | |
* vTraceSetFilterGroup | |
* | |
* Sets the "filter group" to assign when creating RTOS objects, such as tasks, | |
* queues, semaphores and mutexes. This together with vTraceSetFilterMask | |
* allows you to control what events that are recorded, based on the | |
* objects they refer to. | |
* | |
* There are 16 filter groups named FilterGroup0 .. FilterGroup15. | |
* | |
* Note: We don't recommend filtering out the Idle task, so make sure to call | |
* vTraceSetFilterGroup just before initializing the RTOS, in order to assign | |
* such "default" objects to the right Filter Group (typically group 0). | |
* | |
* Example: | |
* | |
* // Assign tasks T1 to FilterGroup0 (default) | |
* <Create Task T1> | |
* | |
* // Assign Q1 and Q2 to FilterGroup1 | |
* vTraceSetFilterGroup(FilterGroup1); | |
* <Create Queue Q1> | |
* <Create Queue Q2> | |
* | |
* // Assigns Q3 to FilterGroup2 | |
* vTraceSetFilterGroup(FilterGroup2); | |
* <Create Queue Q3> | |
* | |
* // Only include FilterGroup0 and FilterGroup2, exclude FilterGroup1 (Q1 and Q2) from the trace | |
* vTraceSetFilterMask( FilterGroup0 | FilterGroup2 ); | |
* | |
* // Assign the default RTOS objects (e.g. Idle task) to FilterGroup0 | |
* vTraceSetFilterGroup(FilterGroup0); | |
* <Start the RTOS scheduler> | |
* | |
* Note that you may define your own names for the filter groups using | |
* preprocessor definitions, to make the code easier to understand. | |
* | |
* Example: | |
* | |
* #define BASE FilterGroup0 | |
* #define USB_EVENTS FilterGroup1 | |
* #define CAN_EVENTS FilterGroup2 | |
* | |
* Note that filtering per event type (regardless of object) is also available | |
* in trcConfig.h. | |
******************************************************************************/ | |
void vTraceSetFilterGroup(uint16_t filterGroup); | |
/****************************************************************************** | |
* vTraceSetFilterMask | |
* | |
* Sets the "filter mask" that is used to filter the events by object. This can | |
* be used to reduce the trace data rate, i.e., if your streaming interface is | |
* a bottleneck or if you want longer snapshot traces without increasing the | |
* buffer size. | |
* | |
* Note: There are two kinds of filters in the recorder. The other filter type | |
* excludes all events of certain kinds (e.g., OS ticks). See trcConfig.h. | |
* | |
* The filtering is based on bitwise AND with the Filter Group ID, assigned | |
* to RTOS objects such as tasks, queues, semaphores and mutexes. | |
* This together with vTraceSetFilterGroup allows you to control what | |
* events that are recorded, based on the objects they refer to. | |
* | |
* See example for vTraceSetFilterGroup. | |
******************************************************************************/ | |
void vTraceSetFilterMask(uint16_t filterMask); | |
#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT) | |
/******************************************************************************/ | |
/*** Extended API for Snapshot mode *******************************************/ | |
/******************************************************************************/ | |
/****************************************************************************** | |
* TRACE_STOP_HOOK - Hook Pointer Data Type | |
* | |
* Declares a data type for a call back function that will be invoked whenever | |
* the recorder is stopped. | |
* | |
* Snapshot mode only! | |
******************************************************************************/ | |
typedef void(*TRACE_STOP_HOOK)(void); | |
/******************************************************************************* | |
* vTraceStopHookPtr | |
* | |
* Points to a call back function that is called from vTraceStop(). | |
* | |
* Snapshot mode only! | |
******************************************************************************/ | |
extern TRACE_STOP_HOOK vTraceStopHookPtr; | |
/******************************************************************************* | |
* vTraceSetStopHook | |
* | |
* Sets a function to be called when the recorder is stopped. | |
* | |
* Snapshot mode only! | |
******************************************************************************/ | |
void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction); | |
/******************************************************************************* | |
* uiTraceStart | |
* | |
* [DEPRECATED] Use vTraceEnable instead. | |
* | |
* Starts the recorder. The recorder will not be started if an error has been | |
* indicated using prvTraceError, e.g. if any of the Nx constants in | |
* trcSnapshotConfig.h has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc). | |
* | |
* Returns 1 if the recorder was started successfully. | |
* Returns 0 if the recorder start was prevented due to a previous internal | |
* error. In that case, check xTraceGetLastError to get the error message. | |
* Any error message is also presented when opening a trace file. | |
* | |
* Snapshot mode only! | |
******************************************************************************/ | |
uint32_t uiTraceStart(void); | |
/******************************************************************************* | |
* vTraceStart | |
* | |
* [DEPRECATED] Use vTraceEnable instead. | |
* | |
* Starts the recorder. The recorder will not be started if an error has been | |
* indicated using prvTraceError, e.g. if any of the Nx constants in | |
* trcSnapshotConfig.h has a too small value (TRC_CFG_NTASK, TRC_CFG_NQUEUE, etc). | |
* | |
* Snapshot mode only! | |
******************************************************************************/ | |
void vTraceStart(void); | |
/******************************************************************************* | |
* vTraceClear | |
* | |
* Resets the recorder. Only necessary if a restart is desired - this is not | |
* needed in the startup initialization. | |
* | |
* Snapshot mode only! | |
******************************************************************************/ | |
void vTraceClear(void); | |
/*****************************************************************************/ | |
/*** INTERNAL SNAPSHOT FUNCTIONS *********************************************/ | |
/*****************************************************************************/ | |
#define TRC_UNUSED | |
#ifndef TRC_CFG_INCLUDE_OBJECT_DELETE | |
#define TRC_CFG_INCLUDE_OBJECT_DELETE 0 | |
#endif | |
#ifndef TRC_CFG_INCLUDE_READY_EVENTS | |
#define TRC_CFG_INCLUDE_READY_EVENTS 1 | |
#endif | |
#ifndef TRC_CFG_INCLUDE_OSTICK_EVENTS | |
#define TRC_CFG_INCLUDE_OSTICK_EVENTS 0 | |
#endif | |
/* This macro will create a task in the object table */ | |
#undef trcKERNEL_HOOKS_TASK_CREATE | |
#define trcKERNEL_HOOKS_TASK_CREATE(SERVICE, CLASS, pxTCB) \ | |
TRACE_SET_OBJECT_NUMBER(TASK, pxTCB); \ | |
TRACE_SET_OBJECT_FILTER(TASK, pxTCB, CurrentFilterGroup); \ | |
prvTraceSetObjectName(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_NAME(pxTCB)); \ | |
prvTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_PRIORITY(pxTCB)); \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); | |
/* This macro will remove the task and store it in the event buffer */ | |
#undef trcKERNEL_HOOKS_TASK_DELETE | |
#define trcKERNEL_HOOKS_TASK_DELETE(SERVICE, SERVICE_NAME, SERVICE_PROP, pxTCB) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); \ | |
prvTraceStoreObjectNameOnCloseEvent(SERVICE_NAME, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_CLASS_TASK); \ | |
prvTraceStoreObjectPropertiesOnCloseEvent(SERVICE_PROP, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_CLASS_TASK); \ | |
prvTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_PRIORITY(pxTCB)); \ | |
prvTraceSetObjectState(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TASK_STATE_INSTANCE_NOT_ACTIVE); \ | |
prvTraceFreeObjectHandle(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); | |
/* This macro will setup a task in the object table */ | |
#undef trcKERNEL_HOOKS_OBJECT_CREATE | |
#define trcKERNEL_HOOKS_OBJECT_CREATE(SERVICE, CLASS, pxObject)\ | |
TRACE_SET_OBJECT_NUMBER(CLASS, pxObject);\ | |
TRACE_SET_OBJECT_FILTER(CLASS, pxObject, CurrentFilterGroup); \ | |
prvMarkObjectAsUsed(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject));\ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); \ | |
prvTraceSetObjectState(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), 0); | |
/* This macro will remove the object and store it in the event buffer */ | |
#undef trcKERNEL_HOOKS_OBJECT_DELETE | |
#define trcKERNEL_HOOKS_OBJECT_DELETE(SERVICE, SERVICE_NAME, SERVICE_PROP, CLASS, pxObject) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); \ | |
prvTraceStoreObjectNameOnCloseEvent(SERVICE_NAME, TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)); \ | |
prvTraceStoreObjectPropertiesOnCloseEvent(SERVICE_PROP, TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)); \ | |
prvTraceFreeObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); | |
/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ | |
#undef trcKERNEL_HOOKS_KERNEL_SERVICE | |
#define trcKERNEL_HOOKS_KERNEL_SERVICE(SERVICE, CLASS, pxObject) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); | |
/* This macro will create a call to a kernel service with a certain result, with a null object as parameter */ | |
#undef trcKERNEL_HOOKS_KERNEL_SERVICE_NULL_OBJECT | |
#define trcKERNEL_HOOKS_KERNEL_SERVICE_NULL_OBJECT(SERVICE, TRACECLASS) \ | |
if (TRACE_GET_TASK_FILTER(TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACECLASS, 0); | |
/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ | |
#undef trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM | |
#define trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM(SERVICE, CLASS, pxObject, param) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ | |
prvTraceStoreKernelCallWithParam(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), (uint32_t)param); | |
/* This macro will create a call to a kernel service with a certain result, with a null object and other value as parameter */ | |
#undef trcKERNEL_HOOKS_KERNEL_SERVICE_NULL_OBJECT_WITH_PARAM | |
#define trcKERNEL_HOOKS_KERNEL_SERVICE_NULL_OBJECT_WITH_PARAM(SERVICE, TRACECLASS, param) \ | |
if (TRACE_GET_TASK_FILTER(TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
prvTraceStoreKernelCallWithParam(SERVICE, TRACECLASS, 0, param); | |
/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ | |
#undef trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY | |
#define trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY(SERVICE, param) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
prvTraceStoreKernelCallWithNumericParamOnly(SERVICE, (uint32_t)param); | |
/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ | |
#undef trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR | |
#define trcKERNEL_HOOKS_KERNEL_SERVICE_FROM_ISR(SERVICE, CLASS, pxObject) \ | |
if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); | |
/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ | |
#undef trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM_FROM_ISR | |
#define trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_PARAM_FROM_ISR(SERVICE, CLASS, pxObject, param) \ | |
if (TRACE_GET_OBJECT_FILTER(CLASS, pxObject) & CurrentFilterMask) \ | |
prvTraceStoreKernelCallWithParam(SERVICE, TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), (uint32_t)param); | |
/* This macro will create a call to a kernel service with a certain result, with an object as parameter */ | |
#undef trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY_FROM_ISR | |
#define trcKERNEL_HOOKS_KERNEL_SERVICE_WITH_NUMERIC_PARAM_ONLY_FROM_ISR(SERVICE, param) \ | |
prvTraceStoreKernelCallWithNumericParamOnly(SERVICE, (uint32_t)param); | |
/* This macro will set the state for an object */ | |
#undef trcKERNEL_HOOKS_SET_OBJECT_STATE | |
#define trcKERNEL_HOOKS_SET_OBJECT_STATE(CLASS, pxObject, STATE) \ | |
prvTraceSetObjectState(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), (uint8_t)STATE); | |
/* This macro will flag a certain task as a finished instance */ | |
#undef trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED | |
#define trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED() \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
prvTraceSetTaskInstanceFinished(TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK())); | |
#if (TRC_CFG_INCLUDE_READY_EVENTS == 1) | |
/* This macro will create an event to indicate that a task became Ready */ | |
#undef trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE | |
#define trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
prvTraceStoreTaskReady(TRACE_GET_TASK_NUMBER(pxTCB)); | |
#else /*(TRC_CFG_INCLUDE_READY_EVENTS == 1)*/ | |
#undef trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE | |
#define trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB) | |
#endif /*(TRC_CFG_INCLUDE_READY_EVENTS == 1)*/ | |
/* This macro will update the internal tick counter and call prvTracePortGetTimeStamp(0) to update the internal counters */ | |
#undef trcKERNEL_HOOKS_INCREMENT_TICK | |
#define trcKERNEL_HOOKS_INCREMENT_TICK() \ | |
{ \ | |
extern uint32_t uiTraceTickCount; \ | |
uiTraceTickCount++; \ | |
prvTracePortGetTimeStamp(0); \ | |
} | |
#if (TRC_CFG_INCLUDE_OSTICK_EVENTS == 1) | |
/* This macro will create an event indicating that the OS tick count has increased */ | |
#undef trcKERNEL_HOOKS_NEW_TIME | |
#define trcKERNEL_HOOKS_NEW_TIME(SERVICE, xValue) \ | |
prvTraceStoreKernelCallWithNumericParamOnly(SERVICE, xValue); | |
#else /*(TRC_CFG_INCLUDE_OSTICK_EVENTS == 1)*/ | |
#undef trcKERNEL_HOOKS_NEW_TIME | |
#define trcKERNEL_HOOKS_NEW_TIME(SERVICE, xValue) | |
#endif /*(TRC_CFG_INCLUDE_OSTICK_EVENTS == 1)*/ | |
/* This macro will create a task switch event to the currently executing task */ | |
#undef trcKERNEL_HOOKS_TASK_SWITCH | |
#define trcKERNEL_HOOKS_TASK_SWITCH( pxTCB ) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
prvTraceStoreTaskswitch(TRACE_GET_TASK_NUMBER(pxTCB)); | |
/* This macro will create an event to indicate that the task has been suspended */ | |
#undef trcKERNEL_HOOKS_TASK_SUSPEND | |
#define trcKERNEL_HOOKS_TASK_SUSPEND(SERVICE, pxTCB) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); \ | |
prvTraceSetTaskInstanceFinished((uint8_t)TRACE_GET_TASK_NUMBER(pxTCB)); | |
/* This macro will create an event to indicate that a task has called a wait/delay function */ | |
#undef trcKERNEL_HOOKS_TASK_DELAY | |
#define trcKERNEL_HOOKS_TASK_DELAY(SERVICE, pxTCB, xValue) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
{ \ | |
prvTraceStoreKernelCallWithNumericParamOnly(SERVICE, xValue); \ | |
prvTraceSetTaskInstanceFinished((uint8_t)TRACE_GET_TASK_NUMBER(pxTCB)); \ | |
} | |
/* This macro will create an event to indicate that a task has gotten its priority changed */ | |
#undef trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE | |
#define trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(SERVICE, pxTCB, uxNewPriority) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
{ \ | |
prvTraceStoreKernelCallWithParam(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), prvTraceGetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)));\ | |
prvTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), (uint8_t)uxNewPriority); \ | |
} | |
/* This macro will create an event to indicate that the task has been resumed */ | |
#undef trcKERNEL_HOOKS_TASK_RESUME | |
#define trcKERNEL_HOOKS_TASK_RESUME(SERVICE, pxTCB) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, TRACE_GET_CURRENT_TASK()) & CurrentFilterMask) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); | |
#undef trcKERNEL_HOOKS_TASK_RESUME_FROM_ISR | |
#define trcKERNEL_HOOKS_TASK_RESUME_FROM_ISR(SERVICE, pxTCB) \ | |
if (TRACE_GET_OBJECT_FILTER(TASK, pxTCB) & CurrentFilterMask) \ | |
prvTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); | |
#if !defined TRC_CFG_INCLUDE_READY_EVENTS || TRC_CFG_INCLUDE_READY_EVENTS == 1 | |
void prvTraceSetReadyEventsEnabled(int status); | |
void prvTraceStoreTaskReady(traceHandle handle); | |
#else | |
#define prvTraceSetReadyEventsEnabled(status) | |
#endif | |
void prvTraceStoreLowPower(uint32_t flag); | |
void prvTraceStoreTaskswitch(traceHandle task_handle); | |
#if (TRC_CFG_SCHEDULING_ONLY == 0) | |
void prvTraceStoreKernelCall(uint32_t eventcode, traceObjectClass objectClass, uint32_t byteParam); | |
void prvTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param); | |
void prvTraceStoreKernelCallWithParam(uint32_t evtcode, traceObjectClass objectClass, | |
uint32_t objectNumber, uint32_t param); | |
#else | |
#define prvTraceStoreKernelCall(eventcode, objectClass, byteParam) {} | |
#define prvTraceStoreKernelCallWithNumericParamOnly(evtcode, param) {} | |
#define prvTraceStoreKernelCallWithParam(evtcode, objectClass, objectNumber, param) {} | |
#endif | |
void prvTraceSetTaskInstanceFinished(traceHandle handle); | |
void prvTraceSetPriorityProperty(uint8_t objectclass, traceHandle id, uint8_t value); | |
uint8_t prvTraceGetPriorityProperty(uint8_t objectclass, traceHandle id); | |
void prvTraceSetObjectState(uint8_t objectclass, traceHandle id, uint8_t value); | |
void prvMarkObjectAsUsed(traceObjectClass objectclass, traceHandle handle); | |
void prvTraceStoreObjectNameOnCloseEvent(uint8_t evtcode, traceHandle handle, | |
traceObjectClass objectclass); | |
void prvTraceStoreObjectPropertiesOnCloseEvent(uint8_t evtcode, traceHandle handle, | |
traceObjectClass objectclass); | |
/* Internal constants for task state */ | |
#define TASK_STATE_INSTANCE_NOT_ACTIVE 0 | |
#define TASK_STATE_INSTANCE_ACTIVE 1 | |
#if (TRC_CFG_INCLUDE_ISR_TRACING == 0) | |
#undef vTraceSetISRProperties | |
#define vTraceSetISRProperties(handle, name, priority) | |
#undef vTraceStoreISRBegin | |
#define vTraceStoreISRBegin(x) (void)x | |
#undef vTraceStoreISREnd | |
#define vTraceStoreISREnd(x) (void)x | |
#undef xTraceSetISRProperties | |
#define xTraceSetISRProperties(name, priority) 0 | |
#endif /*(TRC_CFG_INCLUDE_ISR_TRACING == 0)*/ | |
/******************************************************************************* | |
* xTraceGetTraceBuffer | |
* | |
* Returns a pointer to the recorder data structure. Use this together with | |
* uiTraceGetTraceBufferSize if you wish to implement an own store/upload | |
* solution, e.g., in case a debugger connection is not available for uploading | |
* the data. | |
******************************************************************************/ | |
void* xTraceGetTraceBuffer(void); | |
/******************************************************************************* | |
* uiTraceGetTraceBufferSize | |
* | |
* Gets the size of the recorder data structure. For use together with | |
* vTraceGetTraceBuffer if you wish to implement an own store/upload solution, | |
* e.g., in case a debugger connection is not available for uploading the data. | |
******************************************************************************/ | |
uint32_t uiTraceGetTraceBufferSize(void); | |
#if (TRC_CFG_SCHEDULING_ONLY == 1) | |
#undef TRC_CFG_INCLUDE_USER_EVENTS | |
#define TRC_CFG_INCLUDE_USER_EVENTS 0 | |
#endif /*(TRC_CFG_SCHEDULING_ONLY == 1)*/ | |
#if ((TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_SCHEDULING_ONLY == 0)) | |
#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) | |
traceUBChannel xTraceRegisterUBChannel(traceString channel, traceString formatStr); | |
void vTraceUBData(traceUBChannel channel, ...); | |
void vTraceUBEvent(traceUBChannel channel); | |
#endif /*(TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1)*/ | |
#else /*((TRC_CFG_INCLUDE_USER_EVENTS == 1) && (TRC_CFG_SCHEDULING_ONLY == 0))*/ | |
#undef vTracePrint | |
#define vTracePrint(chn, ...) (void)chn | |
#undef vTracePrintF | |
#define vTracePrintF(chn, ...) (void)chn | |
#undef xTraceRegisterString | |
#define xTraceRegisterString(x) 0; (void)x; | |
#undef xTraceRegisterChannelFormat | |
#define xTraceRegisterChannelFormat(eventLabel, formatStr) 0 | |
#undef vTraceUBData | |
#define vTraceUBData(label, ...) {} | |
#undef vTraceChannelPrint | |
#define vTraceChannelPrint(label) {} | |
#endif /*(TRC_CFG_INCLUDE_USER_EVENTS == 1)*/ | |
#define NEventCodes 0x100 | |
/* Our local critical sections for the recorder */ | |
#define trcCRITICAL_SECTION_BEGIN() {TRACE_ENTER_CRITICAL_SECTION(); recorder_busy++;} | |
#define trcCRITICAL_SECTION_END() {recorder_busy--; TRACE_EXIT_CRITICAL_SECTION();} | |
#if (TRC_CFG_HARDWARE_PORT == TRC_HARDWARE_PORT_ARM_Cortex_M) | |
#define trcSR_ALLOC_CRITICAL_SECTION_ON_CORTEX_M_ONLY TRACE_ALLOC_CRITICAL_SECTION | |
#define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_BEGIN | |
#define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY trcCRITICAL_SECTION_END | |
#else | |
#define trcSR_ALLOC_CRITICAL_SECTION_ON_CORTEX_M_ONLY() {} | |
#define trcCRITICAL_SECTION_BEGIN_ON_CORTEX_M_ONLY() recorder_busy++; | |
#define trcCRITICAL_SECTION_END_ON_CORTEX_M_ONLY() recorder_busy--; | |
#endif | |
/****************************************************************************** | |
* 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 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 data structure 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 */ | |
uint16_t indexOfNextAvailableHandle[ TRACE_NCLASSES ]; | |
/* The lowest index of this class (constant) */ | |
uint16_t lowestIndexOfClass[ TRACE_NCLASSES ]; | |
/* The highest index of this class (constant) */ | |
uint16_t highestIndexOfClass[ TRACE_NCLASSES ]; | |
/* The highest use count for this class (for statistics) */ | |
uint16_t handleCountWaterMarksOfClass[ TRACE_NCLASSES ]; | |
/* The free object handles - a set of stacks within this array */ | |
traceHandle objectHandles[ TRACE_KERNEL_OBJECT_COUNT ]; | |
} objectHandleStackType; | |
extern objectHandleStackType objectHandleStacks; | |
/****************************************************************************** | |
* 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 continuously 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 if the task switch event type | |
* should be "new" or "resume". | |
******************************************************************************/ | |
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)*/ | |
#if (TRC_CFG_USE_16BIT_OBJECT_HANDLES == 1) | |
traceHandle NumberOfObjectsPerClass[2*((TRACE_NCLASSES+1)/2)]; | |
#else | |
traceHandle NumberOfObjectsPerClass[4*((TRACE_NCLASSES+3)/4)]; | |
#endif | |
/* Allocation size rounded up to the closest multiple of 4 */ | |
uint8_t NameLengthPerClass[ 4*((TRACE_NCLASSES+3)/4) ]; | |
uint8_t TotalPropertyBytesPerClass[ 4*((TRACE_NCLASSES+3)/4) ]; | |
/* Allocation size rounded up to the closest multiple of 2 */ | |
uint16_t StartIndexOfClass[ 2*((TRACE_NCLASSES+1)/2) ]; | |
/* The actual handles issued, should be Initiated to all zeros */ | |
uint8_t objbytes[ 4*((TRACE_OBJECT_TABLE_SIZE+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*(((TRC_CFG_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; | |
uint8_t objHandle; | |
uint16_t dts; /* differential timestamp - time since last event */ | |
} TSEvent, TREvent; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t dummy; | |
uint16_t dts; /* differential timestamp - time since last event */ | |
} LPEvent; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t objHandle; | |
uint16_t dts; /* differential timestamp - time since last event */ | |
} KernelCall; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t objHandle; | |
uint8_t param; | |
uint8_t dts; /* differential timestamp - time since last event */ | |
} KernelCallWithParamAndHandle; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t dts; /* differential timestamp - time since last event */ | |
uint16_t param; | |
} KernelCallWithParam16; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t 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 unused1; | |
uint8_t unused2; | |
uint8_t dts; | |
} TaskInstanceStatusEvent; | |
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; | |
typedef struct | |
{ | |
uint8_t type; | |
uint8_t xps_8; | |
uint16_t xps_16; | |
} XPSEvent; | |
typedef struct{ | |
uint8_t type; | |
uint8_t dts; | |
uint16_t size; | |
} MemEventSize; | |
typedef struct{ | |
uint8_t type; | |
uint8_t addr_high; | |
uint16_t addr_low; | |
} MemEventAddr; | |
/******************************************************************************* | |
* The separate user event buffer structure. Can be enabled in trcConfig.h. | |
******************************************************************************/ | |
#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) | |
typedef struct | |
{ | |
traceString name; | |
traceString defaultFormat; | |
} ChannelFormatPair; | |
typedef struct | |
{ | |
uint16_t bufferID; | |
uint16_t version; | |
uint32_t wraparoundCounter; | |
uint32_t numberOfSlots; | |
uint32_t nextSlotToWrite; | |
uint8_t numberOfChannels; | |
uint8_t padding1; | |
uint8_t padding2; | |
uint8_t padding3; | |
ChannelFormatPair channels[(TRC_CFG_UB_CHANNELS)+1]; | |
uint8_t channelBuffer[((TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) + 3) & 0xFFFFFFFC]; /* 1 byte per slot, with padding for 4 byte alignment */ | |
uint8_t dataBuffer[(TRC_CFG_SEPARATE_USER_EVENT_BUFFER_SIZE) * 4]; /* 4 bytes per slot */ | |
} UserEventBuffer; | |
#endif | |
/******************************************************************************* | |
* The main data structure, read by Tracealyzer from the RAM dump | |
******************************************************************************/ | |
typedef struct | |
{ | |
volatile uint8_t startmarker0; /* Volatile is important, see init code. */ | |
volatile uint8_t startmarker1; | |
volatile uint8_t startmarker2; | |
volatile uint8_t startmarker3; | |
volatile uint8_t startmarker4; | |
volatile uint8_t startmarker5; | |
volatile uint8_t startmarker6; | |
volatile uint8_t startmarker7; | |
volatile uint8_t startmarker8; | |
volatile uint8_t startmarker9; | |
volatile uint8_t startmarker10; | |
volatile uint8_t startmarker11; | |
/* Used to determine Kernel and Endianess */ | |
uint16_t version; | |
/* Currently 5 */ | |
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; | |
/* If > 0, tells the maximum time between two traced ISRs that execute | |
back-to-back. If the time between vTraceStoreISREnd and a directly | |
following vTraceISRBegin is above isrTailchainingThreshold, we assume a | |
return to the previous context in between the ISRs, otherwise we assume | |
the have executed back-to-back and don't show any fragment of the previous | |
context in between. */ | |
uint32_t isrTailchainingThreshold; | |
/* Not used, remains for compatibility and future use */ | |
uint8_t notused[24]; | |
/* The amount of heap memory remaining at the last malloc or free event */ | |
uint32_t heapMemUsage; | |
/* 0xF0F0F0F0 - for control only */ | |
int32_t debugMarker0; | |
/* Set to value of TRC_CFG_USE_16BIT_OBJECT_HANDLES */ | |
uint32_t isUsing16bitHandles; | |
/* 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 inclusion of float support, and for endian detection of floats. | |
The value should be (float)1 or (uint32_t)0 */ | |
#if (TRC_CFG_INCLUDE_FLOAT_SUPPORT == 1) | |
float exampleFloatEncoding; | |
#else | |
uint32_t exampleFloatEncoding; | |
#endif | |
/* This is non-zero if an internal error occurred 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; | |
/* Error messages from the recorder. */ | |
char systemInfo[80]; | |
/* 0xF3F3F3F3 - for control only */ | |
int32_t debugMarker3; | |
/* The event data, in 4-byte records */ | |
uint8_t eventData[ (TRC_CFG_EVENT_BUFFER_SIZE) * 4 ]; | |
#if (TRC_CFG_USE_SEPARATE_USER_EVENT_BUFFER == 1) | |
UserEventBuffer userEventBuffer; | |
#endif | |
/* This should always be 0 */ | |
uint32_t endOfSecondaryBlocks; | |
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; | |
/* Internal functions */ | |
/* Signal an error. */ | |
void prvTraceError(const char* msg); | |
/******************************************************************************* | |
* prvTracePortGetTimeStamp | |
* | |
* Returns the current time based on the HWTC macros which provide a hardware | |
* isolation layer towards the hardware timer/counter. | |
* | |
* The HWTC macros and prvTracePortGetTimeStamp is the main porting issue | |
* or the trace recorder library. Typically you should not need to change | |
* the code of prvTracePortGetTimeStamp if using the HWTC macros. | |
* | |
******************************************************************************/ | |
void prvTracePortGetTimeStamp(uint32_t *puiTimestamp); | |
traceHandle prvTraceGetObjectHandle(traceObjectClass objectclass); | |
void prvTraceFreeObjectHandle(traceObjectClass objectclass, | |
traceHandle handle); | |
/* Private function. Use the public functions in trcKernelPort.h */ | |
void prvTraceSetObjectName(traceObjectClass objectclass, | |
traceHandle handle, | |
const char* name); | |
/* Internal macros */ | |
#define TRACE_PROPERTY_NAME_GET(objectclass, objecthandle) \ | |
(const char*)(& RecorderDataPtr->ObjectPropertyTable.objbytes \ | |
[uiIndexOfObject(objecthandle, objectclass)]) | |
#define TRACE_PROPERTY_OBJECT_STATE(objectclass, handle) \ | |
RecorderDataPtr->ObjectPropertyTable.objbytes[uiIndexOfObject(handle, objectclass) \ | |
+ RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[objectclass]] | |
#define TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle) \ | |
RecorderDataPtr->ObjectPropertyTable.objbytes[uiIndexOfObject(handle, objectclass) \ | |
+ RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[objectclass] + 1] | |
/* DEBUG ASSERTS */ | |
#if defined TRC_CFG_USE_TRACE_ASSERT && TRC_CFG_USE_TRACE_ASSERT != 0 | |
#define TRACE_ASSERT(eval, msg, defRetVal) \ | |
if (!(eval)) \ | |
{ \ | |
prvTraceError("TRACE_ASSERT: " msg); \ | |
return defRetVal; \ | |
} | |
#else | |
#define TRACE_ASSERT(eval, msg, defRetVal) | |
#endif | |
#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_SNAPSHOT)*/ | |
#if (TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING) | |
/****************************************************************************** | |
* Default values for STREAM PORT macros | |
* | |
* As a normal user, this is nothing you don't need to bother about. This is | |
* only important if you want to define your own custom streaming interface. | |
* | |
* You may override these in your own trcStreamingPort.h to create a custom | |
* stream port, and thereby stream the trace on any host-target interface. | |
* These default values are suitable for most cases, except the J-Link port. | |
******************************************************************************/ | |
/****************************************************************************** | |
* TRC_STREAM_PORT_USE_INTERNAL_BUFFER | |
* | |
* There are two kinds of stream ports, those that store the event to the | |
* internal buffer (with periodic flushing by the TzCtrl task) and those that | |
* write directly to the streaming interface. Most stream ports use the | |
* recorder's internal buffer, except for the SEGGER J-Link port (also uses a | |
* RAM buffer, but one defined in the SEGGER code). | |
* | |
* If the stream port (trcStreamingPort.h) defines this as zero (0), it is | |
* expected to transmit the data directly using TRC_STREAM_PORT_COMMIT_EVENT. | |
* Otherwise it is expected that the trace data is stored in the internal buffer | |
* and the TzCtrl task will then send the buffer pages when they become full. | |
******************************************************************************/ | |
#ifndef TRC_STREAM_PORT_USE_INTERNAL_BUFFER | |
#define TRC_STREAM_PORT_USE_INTERNAL_BUFFER 1 | |
#endif | |
/****************************************************************************** | |
* TRC_STREAM_PORT_ON_TRACE_BEGIN | |
* | |
* Defining any actions needed in the stream port when the recording is activated. | |
*******************************************************************************/ | |
#ifndef TRC_STREAM_PORT_ON_TRACE_BEGIN | |
#define TRC_STREAM_PORT_ON_TRACE_BEGIN() /* Do nothing */ | |
#endif | |
/****************************************************************************** | |
* TRC_STREAM_PORT_ON_TRACE_BEGIN | |
* | |
* Defining any actions needed in the stream port when the tracing stops. | |
* Empty by default. | |
*******************************************************************************/ | |
#ifndef TRC_STREAM_PORT_ON_TRACE_END | |
#define TRC_STREAM_PORT_ON_TRACE_END() /* Do nothing */ | |
#endif | |
/****************************************************************************** | |
* TRC_STREAM_PORT_ALLOCATE_EVENT | |
* | |
* This macro is used to allocate memory for each event record, just before | |
* assigning the record fields. | |
* Depending on "TRC_STREAM_PORT_USE_INTERNAL_BUFFER", this either allocates | |
* space in the paged event buffer, or on the local stack. In the latter case, | |
* the COMMIT event is used to write the data to the streaming interface. | |
******************************************************************************/ | |
#ifndef TRC_STREAM_PORT_ALLOCATE_EVENT | |
#if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) | |
#define TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) _type* _ptrData; _ptrData = (_type*)prvPagedEventBufferGetWritePointer(_size); | |
#else | |
#define TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) _type _tmpArray[_size / sizeof(_type)]; _type* _ptrData = _tmpArray; | |
#endif | |
#endif | |
/****************************************************************************** | |
* TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT | |
* | |
* This macro is used to allocate memory for each event record, just before | |
* assigning the record fields. | |
* This has the same purpose as TRC_STREAM_PORT_ALLOCATE_EVENT and by default | |
* it has the same definition as TRC_STREAM_PORT_ALLOCATE_EVENT. This is used | |
* for events carrying variable-sized payload, such as strings. | |
* In the SEGGER RTT port, we need this in order to make a worst-case | |
* allocation on the stack. | |
******************************************************************************/ | |
#ifndef TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT | |
#if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) | |
#define TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(_type, _ptrData, _size) TRC_STREAM_PORT_ALLOCATE_EVENT(_type, _ptrData, _size) /* We do the same thing as for non-dynamic event sizes */ | |
#else | |
#define TRC_STREAM_PORT_ALLOCATE_DYNAMIC_EVENT(_type, _ptrData, _size) _type _tmpArray[sizeof(largestEventType) / sizeof(_type)]; _type* _ptrData = _tmpArray; | |
#endif | |
#endif | |
/****************************************************************************** | |
* TRC_STREAM_PORT_COMMIT_EVENT | |
* | |
* The COMMIT macro is used to write a single event record directly to the | |
* streaming inteface, without first storing the event in the internal buffer. | |
* This is currently only used in the SEGGER J-Link RTT port. | |
* | |
* This relies on the TRC_STREAM_PORT_WRITE_DATA macro, defined in by the | |
* stream port in trcStreamingPort.h. The COMMIT macro calls | |
* prvTraceWarning(TRC_STREAM_PORT_WRITE_DATA) if a non-zero value is returned | |
* from TRC_STREAM_PORT_WRITE_DATA. If zero (0) is returned, it is assumed | |
* that all data was successfully written. | |
* | |
* In ports using the internal buffer, this macro has no purpose as the events | |
* are written to the internal buffer instead. They are then flushed to the | |
* streaming interface in the TzCtrl task using TRC_STREAM_PORT_WRITE_DATA. | |
******************************************************************************/ | |
#ifndef TRC_STREAM_PORT_COMMIT_EVENT | |
#if (TRC_STREAM_PORT_USE_INTERNAL_BUFFER == 1) | |
#define TRC_STREAM_PORT_COMMIT_EVENT(_ptrData, _size) /* Not used */ | |
#else | |
#define TRC_STREAM_PORT_COMMIT_EVENT(_ptrData, _size) \ | |
{ \ | |
if (TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, 0) != 0)\ | |
prvTraceWarning(PSF_WARNING_STREAM_PORT_WRITE); \ | |
} | |
#endif | |
#endif | |
/****************************************************************************** | |
* TRC_STREAM_PORT_READ_DATA (defined in trcStreamingPort.h) | |
* | |
* Defining how to read data from host (commands from Tracealyzer). | |
* | |
* If there is no direct interface to host (e.g., if streaming to a file | |
* system) this should be defined as 0. Instead use vTraceEnable(TRC_START) and | |
* vTraceStop() to control the recording from target. | |
* | |
* Parameters: | |
* | |
* - _ptrData: a pointer to a data buffer, where the received data shall be | |
* stored (TracealyzerCommandType*). | |
* | |
* - _size: the number of bytes to read (int). | |
* | |
* - _ptrBytesRead: a pointer to an integer (int), that should be assigned | |
* with the number of bytes that was received. | |
* | |
* Example: | |
* | |
* int32_t myRead(void* ptrData, uint32_t size, int32_t* ptrBytesRead); | |
* | |
* #define TRC_STREAM_PORT_READ_DATA(_ptrData, _size, _ptrBytesRead) \ | |
* myRead(_ptrData, _size, _ptrBytesRead) | |
* | |
* Your "myRead" function should return 0 if successful, i.e. if at least some | |
* bytes were received. A non-zero value should be returned if the streaming | |
* interface returned an error (e.g. a closed socket), which results in the | |
* recorder calling prvTraceWarning with the error code | |
* PSF_WARNING_STREAM_PORT_WRITE. | |
* | |
* If developing your own custom stream port and using the default internal | |
* buffer, it is important that the _ptrBytesRead parameter is assigned | |
* correctly by "myRead", i.e. with the number of bytes actually written. | |
* Otherwise the data stream may get out of sync in case the streaming interface | |
* can't swallow all data at once. | |
******************************************************************************/ | |
#ifndef TRC_STREAM_PORT_READ_DATA | |
#error "No definition for TRC_STREAM_PORT_READ_DATA (should be in trcStreamingPort.h)" | |
#endif | |
/****************************************************************************** | |
* TRC_STREAM_PORT_WRITE_DATA (defined in trcStreamingPort.h) | |
* | |
* Defining how to write trace data to the streaming interface. | |
* | |
* Parameters: | |
* | |
* - _ptrData: a pointer (void*) to the data to write. | |
* | |
* - _size: the number of bytes to write (uint32_t). | |
* | |
* - _ptrBytesWritten: a pointer to an integer (int32_t), that should be | |
* assigned with the number of bytes actually written. | |
* | |
* Example: | |
* | |
* int32_t myWrite(void* ptrData, uint32_t size, int32_t* ptrBytesWritten); | |
* | |
* #define TRC_STREAM_PORT_WRITE_DATA(_ptrData, _size, _ptrBytesWritten) \ | |
* myWrite(_ptrData, _size, _ptrBytesWritten) | |
* | |
* Your "myWrite" function should return 0 if successful, i.e. if at least some | |
* bytes were sent. A non-zero value should be returned if the streaming interface | |
* returned an error (e.g. a closed socket), which results in the recorder calling | |
* prvTraceWarning with the error code PSF_WARNING_STREAM_PORT_WRITE. | |
* | |
* If developing your own custom stream port and using the default internal | |
* buffer, it is important that the _ptrBytesWritten parameter is assigned | |
* correctly by "myWrite", i.e. with the number of bytes actually written. | |
* Otherwise the data stream may get out of sync in case the streaming interface | |
* can't swallow all data at once. | |
* | |
* Assuming TRC_STREAM_PORT_USE_INTERNAL_BUFFER is 1 (default), the TzCtrl task | |
* will use this macro to send one buffer page at a time. In case all data can't | |
* be written at once (if _ptrBytesWritten is less than _size), the TzCtrl task | |
* is smart enough to make repeated calls (with updated parameters) in order to | |
* send the remaining data. | |
* | |
* However, if TRC_STREAM_PORT_USE_INTERNAL_BUFFER is 0, this is used from the | |
* COMMIT macro, directly in the "event functions". In that case, the | |
* _ptrBytesWritten parameter will be NULL and should be ignored by the write | |
* function. In this case, it is assumed that all data can be sent in a single | |
* call, otherwise the write function should return a non-zero error code. | |
******************************************************************************/ | |
#ifndef TRC_STREAM_PORT_WRITE_DATA | |
#error "No definition for TRC_STREAM_PORT_WRITE_DATA (should be in trcStreamingPort.h)" | |
#endif | |
/****************************************************************************** | |
* Data structure declaration, depending on TRC_CFG_RECORDER_BUFFER_ALLOCATION | |
*******************************************************************************/ | |
#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_STATIC) | |
/* Static allocation. */ | |
/* If not defined in trcStreamingPort.h */ | |
#ifndef TRC_STREAM_PORT_ALLOCATE_FIELDS | |
#define TRC_STREAM_PORT_ALLOCATE_FIELDS() \ | |
char _TzTraceData[(TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; | |
extern char _TzTraceData[(TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)]; | |
#endif | |
/* If not defined in trcStreamingPort.h */ | |
#ifndef TRC_STREAM_PORT_MALLOC | |
#define TRC_STREAM_PORT_MALLOC() /* Static allocation. Not used. */ | |
#endif | |
#else | |
/* For Dynamic or Custom Allocation mode */ | |
/* If not defined in trcStreamingPort.h */ | |
#ifndef TRC_STREAM_PORT_ALLOCATE_FIELDS | |
#define TRC_STREAM_PORT_ALLOCATE_FIELDS() char* _TzTraceData = NULL; | |
extern char* _TzTraceData; | |
#endif | |
/* If not defined in trcStreamingPort.h */ | |
#ifndef TRC_STREAM_PORT_MALLOC | |
#if (TRC_CFG_RECORDER_BUFFER_ALLOCATION == TRC_RECORDER_BUFFER_ALLOCATION_DYNAMIC) | |
#define TRC_STREAM_PORT_MALLOC() \ | |
_TzTraceData = TRC_PORT_MALLOC((TRC_CFG_PAGED_EVENT_BUFFER_PAGE_COUNT) * (TRC_CFG_PAGED_EVENT_BUFFER_PAGE_SIZE)); | |
extern char* _TzTraceData; | |
#else | |
#define TRC_STREAM_PORT_MALLOC() /* Custom allocation. Not used. */ | |
#endif | |
#endif | |
#endif | |
#ifndef TRC_STREAM_PORT_INIT | |
#define TRC_STREAM_PORT_INIT() \ | |
TRC_STREAM_PORT_MALLOC(); /* Empty if static allocation mode */ \ | |
prvPagedEventBufferInit(_TzTraceData); | |
#endif | |
/* Signal an error. */ | |
void prvTraceError(int errCode); | |
/* Signal an warning (does not stop the recorder). */ | |
void prvTraceWarning(int errCode); | |
/******************************************************************************/ | |
/*** ERROR AND WARNING CODES (check using xTraceGetLastError) *****************/ | |
/******************************************************************************/ | |
#define PSF_ERROR_NONE 0 | |
#define PSF_ERROR_EVENT_CODE_TOO_LARGE 1 | |
#define PSF_ERROR_ISR_NESTING_OVERFLOW 2 | |
#define PSF_ERROR_DWT_NOT_SUPPORTED 3 | |
#define PSF_ERROR_DWT_CYCCNT_NOT_SUPPORTED 4 | |
#define PSF_ERROR_TZCTRLTASK_NOT_CREATED 5 | |
#define PSF_WARNING_SYMBOL_TABLE_SLOTS 101 | |
#define PSF_WARNING_SYMBOL_MAX_LENGTH 102 | |
#define PSF_WARNING_OBJECT_DATA_SLOTS 103 | |
#define PSF_WARNING_STRING_TOO_LONG 104 | |
#define PSF_WARNING_STREAM_PORT_READ 105 | |
#define PSF_WARNING_STREAM_PORT_WRITE 106 | |
/******************************************************************************/ | |
/*** INTERNAL STREAMING FUNCTIONS *********************************************/ | |
/******************************************************************************/ | |
/* Saves a symbol name (task name etc.) in symbol table */ | |
void prvTraceSaveSymbol(const void *address, const char *name); | |
/* Deletes a symbol name (task name etc.) from symbol table */ | |
void prvTraceDeleteSymbol(void *address); | |
/* Saves an object data entry (task base priority) in object data table */ | |
void prvTraceSaveObjectData(const void *address, uint32_t data); | |
/* Removes an object data entry (task base priority) from object data table */ | |
void prvTraceDeleteObjectData(void *address); | |
/* Store an event with zero parameters (event ID only) */ | |
void prvTraceStoreEvent0(uint16_t eventID); | |
/* Store an event with one 32-bit parameter (pointer address or an int) */ | |
void prvTraceStoreEvent1(uint16_t eventID, | |
uint32_t param1); | |
/* Store an event with two 32-bit parameters */ | |
void prvTraceStoreEvent2(uint16_t eventID, | |
uint32_t param1, | |
uint32_t param2); | |
/* Store an event with three 32-bit parameters */ | |
void prvTraceStoreEvent3(uint16_t eventID, | |
uint32_t param1, | |
uint32_t param2, | |
uint32_t param3); | |
/* Stores an event with <nParam> 32-bit integer parameters */ | |
void prvTraceStoreEvent(int nParam, uint16_t EventID, ...); | |
/* Stories an event with a string and <nParam> 32-bit integer parameters */ | |
void prvTraceStoreStringEvent(int nArgs, uint16_t eventID, const char* str, ...); | |
/* Initializes the paged event buffer used by certain stream ports */ | |
void prvPagedEventBufferInit(char* buffer); | |
/* Retrieve a pointer to the paged event buffer */ | |
void* prvPagedEventBufferGetWritePointer(int sizeOfEvent); | |
/* Transfer a full buffer page */ | |
uint32_t prvPagedEventBufferTransfer(void); | |
/* The data structure for commands (a bit overkill) */ | |
typedef struct | |
{ | |
unsigned char cmdCode; | |
unsigned char param1; | |
unsigned char param2; | |
unsigned char param3; | |
unsigned char param4; | |
unsigned char param5; | |
unsigned char checksumLSB; | |
unsigned char checksumMSB; | |
} TracealyzerCommandType; | |
/* Checks if the provided command is a valid command */ | |
int prvIsValidCommand(TracealyzerCommandType* cmd); | |
/* Executed the received command (Start or Stop) */ | |
void prvProcessCommand(TracealyzerCommandType* cmd); | |
#define vTraceSetStopHook(x) | |
#endif /*(TRC_CFG_RECORDER_MODE == TRC_RECORDER_MODE_STREAMING)*/ | |
#else /* when TRC_USE_TRACEALYZER_RECORDER == 0 */ | |
#define vTraceEnable(x) | |
#define xTraceRegisterString(x) 0; (void)x; | |
#define vTracePrint(chn, ...) (void)chn | |
#define vTracePrintF(chn, ...) (void)chn | |
#define vTraceInstanceFinishedNow() | |
#define vTraceInstanceFinishedNext() | |
#define vTraceStoreISRBegin(x) (void)x | |
#define vTraceStoreISREnd(x) (void)x | |
#define xTraceSetISRProperties(a, b) 0 | |
#define vTraceStoreKernelObjectName(a, b) | |
#define xTraceRegisterChannelFormat(eventLabel, formatStr) 0 | |
#define vTraceChannelPrint(label) | |
#define vTraceUBData(label, ...) | |
#define vTraceSetFilterGroup(x) | |
#define vTraceSetFilterMask(x) | |
#define prvTraceSetReadyEventsEnabled(status) | |
#define vTraceExcludeTask(handle) | |
#define uiTraceStart() (1) | |
#define vTraceStart() | |
#define vTraceStop() | |
#ifndef vTraceSetRecorderDataBuffer | |
#define vTraceSetRecorderDataBuffer(pRecorderData) | |
#endif | |
#define vTraceConsoleChannelPrintF(fmt, ...) | |
#ifndef TRC_ALLOC_CUSTOM_BUFFER | |
#define TRC_ALLOC_CUSTOM_BUFFER(bufname) | |
#endif | |
#define xTraceIsRecordingEnabled() (0) | |
#define vTraceSetStopHook(x) | |
#endif /*(TRC_USE_TRACEALYZER_RECORDER == 1)*/ | |
#ifdef __cplusplus | |
} | |
#endif | |
#endif /* TRC_RECORDER_H */ |