From 3e05d6bf915c7dcbd32392c57a56f77432b69ec2 Mon Sep 17 00:00:00 2001 From: richardbarry Date: Wed, 5 Jun 2013 13:38:56 +0000 Subject: [PATCH] Update to latest FreeRTOS+Trace recorder code. git-svn-id: https://svn.code.sf.net/p/freertos/code/trunk@1905 1d2547de-c912-0410-9cb9-b8ca96c0e9e2 --- .../Readme Config.txt | 22 - .../trcConfig.h | 185 +- .../trcHardwarePort.h} | 146 +- .../FreeRTOS-Plus-Trace/Include/trcBase.h | 521 +++--- .../FreeRTOS-Plus-Trace/Include/trcHooks.h | 467 ++--- .../FreeRTOS-Plus-Trace/Include/trcKernel.h | 252 +-- .../FreeRTOS-Plus-Trace/Include/trcTypes.h | 40 +- .../FreeRTOS-Plus-Trace/Include/trcUser.h | 298 ++-- .../debugger trace upload.txt | 36 +- .../Source/FreeRTOS-Plus-Trace/readme.txt | 18 +- .../Source/FreeRTOS-Plus-Trace/trcBase.c | 793 ++++----- .../FreeRTOS-Plus-Trace/trcHardwarePort.c | 119 ++ .../Source/FreeRTOS-Plus-Trace/trcKernel.c | 521 +++--- .../FreeRTOS-Plus-Trace/trcKernelPort.c | 191 ++ .../FreeRTOS-Plus-Trace/trcKernelPort.h | 749 ++++++++ .../Source/FreeRTOS-Plus-Trace/trcPort.c | 208 --- .../Source/FreeRTOS-Plus-Trace/trcUser.c | 1573 ++++++++--------- 17 files changed, 3143 insertions(+), 2996 deletions(-) delete mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/Readme Config.txt rename FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/{Configuration - template => ConfigurationTemplate}/trcConfig.h (75%) rename FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/{Configuration - template/trcPort.h => ConfigurationTemplate/trcHardwarePort.h} (74%) create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c create mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.h delete mode 100644 FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcPort.c diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/Readme Config.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/Readme Config.txt deleted file mode 100644 index 8883a59aa..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/Readme Config.txt +++ /dev/null @@ -1,22 +0,0 @@ -FreeRTOS+Trace v2.3.0 ---------------------- - -This directory contains the recorder files that the typical FreeRTOS+Trace user needs to be aware of. - -- trcPort.h - contains the hardware ports and the setting of what port to use. -- trcConfig.h - contains the recorder configuration. - -The files in this directory are however not referenced by any of the demo projects. -Copies of these files are instead found in each Demo project directory. - -These copies are included here to make the TraceRecorderSrc directory complete. - -If you use this template, you will need to update the following macro definitions in trcPort.h: -- SELECTED_PORT -- IRQ_PRIORITY_ORDER -- vTraceConsoleMessage (optional, if console prints are desired) - -Always remember to check the settings used in trcConfig.h. - -Percepio AB -www.percepio.com diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/trcConfig.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h similarity index 75% rename from FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/trcConfig.h rename to FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h index 1ffa3efec..f016dbc86 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/trcConfig.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcConfig.h @@ -1,5 +1,5 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * * trcConfig.h @@ -9,12 +9,12 @@ * appropriate for your system, and if necessary adjust these. Most likely, you * will need to adjust the NTask, NISR, NQueue, NMutex and NSemaphore values to * reflect the number of such objects in your system. These may be - * overapproximated, although larger values values implies more RAM usage. + * over-approximated, although larger values values implies more RAM usage. * * 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 + * in its original form, including modifications in trcHardwarePort.c/.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 @@ -36,11 +36,7 @@ * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ @@ -61,7 +57,7 @@ * vTracePrintF may use multiple records depending on the number of data args. ******************************************************************************/ -#define EVENT_BUFFER_SIZE 1000 /* Adjust wrt. to available RAM */ +#define EVENT_BUFFER_SIZE 4000 /* Adjust wrt. to available RAM */ /******************************************************************************* @@ -99,6 +95,43 @@ ******************************************************************************/ #define SYMBOL_TABLE_SIZE 1000 +/******************************************************************************* + * USE_SEPARATE_USER_EVENT_BUFFER + * + * Macro which should be defined as an integer value. + * Default is zero (0). + * + * This enables and disables the use of the separate user event buffer. + * + * Note: When using the separate user event buffer, you may get an artificial + * task instance named "Unknown actor". This is added as a placeholder when the + * user event history is longer than the task scheduling history. + ******************************************************************************/ +#define USE_SEPARATE_USER_EVENT_BUFFER 0 + +/******************************************************************************* + * USER_EVENT_BUFFER_SIZE + * + * Macro which should be defined as an integer value. + * + * This defines the capacity of the user event buffer, in number of slots. + * A single user event can use between 1 and X slots, depending on the data. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define USER_EVENT_BUFFER_SIZE 500 + +/******************************************************************************* + * USER_EVENT_CHANNELS + * + * Macro which should be defined as an integer value. + * + * This defines the number of allowed user event channels. + * + * Only in use if USE_SEPARATE_USER_EVENT_BUFFER is set to 1. + ******************************************************************************/ +#define CHANNEL_FORMAT_PAIRS 32 + /******************************************************************************* * NTask, NISR, NQueue, NSemaphore, NMutex * @@ -114,35 +147,33 @@ * * Using too small values will give an error message through the vTraceError * routine, which makes the error message appear when opening the trace data - * in FreeRTOS+Trace. If you are using the recorder status monitor task, + * in Tracealyzer. If you are using the recorder status monitor task, * any error messages are displayed in console prints, assuming that the * print macro has been defined properly (vConsolePrintMessage). * * It can be wise to start with very large values for these constants, * unless you are very confident on these numbers. Then do a recording and - * check the actual usage in FreeRTOS+Trace. This is shown by selecting + * check the actual usage in Tracealyzer. This is shown by selecting * View -> Trace Details -> Resource Usage -> Object Table * - * NOTE 2: Remember to account for all tasks created by FreeRTOS, such as the - * IDLE task, the FreeRTOS timer task, and any tasks created by other 3rd party + * NOTE 2: Remember to account for all tasks created by the kernel, such as the + * IDLE task, timer task, and any tasks created by other 3rd party * software components, such as communication stacks. The recorder also has an * optional monitor task to account for, if this is used. * Moreover, one task slot is used to indicate "(startup)", i.e., a fictive - * task that represent the time before the FreeRTOS scheduler starts. + * task that represent the time before the scheduler starts. * NTask should thus be at least 2-3 slots larger than your application task count. * - * NOTE 3: The FreeRTOS timer task creates a Queue, that should be accounted - * for in NQueue. ******************************************************************************/ #define NTask 15 -#define NISR 4 -#define NQueue 3 -#define NSemaphore 4 -#define NMutex 2 +#define NISR 5 +#define NQueue 5 +#define NSemaphore 5 +#define NMutex 5 /* Maximum object name length for each class (includes zero termination) */ -#define NameLenTask configMAX_TASK_NAME_LEN -#define NameLenISR 10 +#define NameLenTask 15 +#define NameLenISR 15 #define NameLenQueue 15 #define NameLenSemaphore 15 #define NameLenMutex 15 @@ -152,12 +183,12 @@ * * Macro which should be defined as a string. * - * This string is stored in the trace and displayed in FreeRTOS+Trace. Can be + * This string is stored in the trace and displayed in Tracealyzer. Can be * used to store, e.g., system version or build date. This is also used to store * internal error messages from the recorder, which if occurs overwrites the * value defined here. This may be maximum 256 chars. *****************************************************************************/ -#define TRACE_DESCRIPTION "FreeRTOS+Trace Demo" +#define TRACE_DESCRIPTION "Tracealyzer Recorder Test Program" /****************************************************************************** * TRACE_DESCRIPTION_MAX_LENGTH @@ -195,6 +226,17 @@ * CONFIGURATION REGARDING WHAT CODE/FEATURES TO INCLUDE *****************************************************************************/ +/****************************************************************************** + * USE_TRACE_ASSERT + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 0. + * + * If this is one (1), the TRACE_ASSERT macro will verify that a condition is + * true. If the condition is false, vTraceError() will be called. + *****************************************************************************/ +#define USE_TRACE_ASSERT 0 + /****************************************************************************** * INCLUDE_FLOAT_SUPPORT * @@ -223,8 +265,8 @@ * much faster than a printf and can therefore be used in timing critical code. * See vTraceUserEvent() and vTracePrintF() in trcUser.h * - * Note that FreeRTOS+Trace Standard Edition or Professional Edition is required - * for User Events, they are not displayed in FreeRTOS+Trace Free Edition. + * Note that Tracealyzer Standard Edition or Professional Edition is required + * for User Events, they are not displayed in Tracealyzer Free Edition. *****************************************************************************/ #define INCLUDE_USER_EVENTS 1 @@ -240,6 +282,17 @@ *****************************************************************************/ #define INCLUDE_READY_EVENTS 1 +/***************************************************************************** + * INCLUDE_NEW_TIME_EVENTS + * + * Macro which should be defined as either zero (0) or one (1). + * Default is 0. + * + * If this is zero (1), events will be generated whenever the os clock is + * increased. + *****************************************************************************/ +#define INCLUDE_NEW_TIME_EVENTS 0 + /***************************************************************************** * INCLUDE_ISR_TRACING * @@ -247,10 +300,11 @@ * Default is 1. * * If this is zero (0), the code for recording Interrupt Service Routines is - * excluded to reduce code size. Note, recording ISRs require that you insert - * calls to vTraceStoreISRBegin and vTraceStoreISREnd in your interrupt handlers. - * There is no automatic recording of ISRs like for task scheduling, since - * FreeRTOS does not have a central interrupt dispatcher. + * excluded to reduce code size. + * + * Note, if the kernel has no central interrupt dispatcher, recording ISRs + * require that you insert calls to vTraceStoreISRBegin and vTraceStoreISREnd + * in your interrupt handlers. *****************************************************************************/ #define INCLUDE_ISR_TRACING 1 @@ -261,9 +315,8 @@ * Default is 1. * * This must be enabled (1) if tasks, queues or other - * traced kernel objects are deleted at runtime, e.g., using vTaskDelete or - * vQueueDelete. If no deletes are made, this can be set to 0 in order to - * exclude the delete-handling code. + * traced kernel objects are deleted at runtime. If no deletes are made, this + * can be set to 0 in order to exclude the delete-handling code. *****************************************************************************/ #define INCLUDE_OBJECT_DELETE 1 @@ -272,32 +325,32 @@ *****************************************************************************/ /****************************************************************************** - * RECORDER_STORE_MODE + * TRACE_RECORDER_STORE_MODE * * Macro which should be defined as one of: - * - STORE_MODE_RING_BUFFER - * - STORE_MODE_STOP_WHEN_FULL - * Default is STORE_MODE_RING_BUFFER. - * - * With RECORDER_STORE_MODE set to STORE_MODE_RING_BUFFER, the events are stored - * in a ring buffer, i.e., where the oldest events are overwritten when the - * buffer becomes full. This allows you to get the last events leading up to an - * interesting state, e.g., an error, without having a large trace buffer for - * string the whole run since startup. In this mode, the recorder can run + * - TRACE_STORE_MODE_RING_BUFFER + * - TRACE_STORE_MODE_STOP_WHEN_FULL + * Default is TRACE_STORE_MODE_RING_BUFFER. + * + * With TRACE_RECORDER_STORE_MODE set to TRACE_STORE_MODE_RING_BUFFER, the events are + * stored in a ring buffer, i.e., where the oldest events are overwritten when + * the buffer becomes full. This allows you to get the last events leading up + * to an interesting state, e.g., an error, without having a large trace buffer + * for string the whole run since startup. In this mode, the recorder can run * "forever" as the buffer never gets full, i.e., in the sense that it always * has room for more events. * - * To fetch the trace in mode STORE_MODE_RING_BUFFER, you need to first halt the + * To fetch the trace in mode TRACE_STORE_MODE_RING_BUFFER, you need to first halt the * system using your debugger and then do a RAM dump, or to explicitly stop the * recorder using vTraceStop() and then store/upload the trace data using a - * FreeRTOS task that you need to provide yourself. The trace data is found in - * the struct RecorderData, initialized in trcBase.c. + * task that you need to provide yourself. The trace data is found in the struct + * RecorderData, initialized in trcBase.c. * * Note that, if you upload the trace using a RAM dump, i.e., when the system is * halted on a breakpoint or by a debugger command, there is no need to stop the * recorder first. * - * When RECORDER_STORE_MODE is STORE_MODE_STOP_WHEN_FULL, the recording is + * When TRACE_RECORDER_STORE_MODE is TRACE_STORE_MODE_STOP_WHEN_FULL, the recording is * stopped when the buffer becomes full. When the recorder stops itself this way * vTracePortEnd() is called which allows for custom actions, such as triggering * a task that stores the trace buffer, i.e., in case taking a RAM dump @@ -305,12 +358,8 @@ * saves the trace to file directly, but this is not recommended in a real-time * system since the scheduler is blocked during the processing of vTracePortEnd. *****************************************************************************/ -#ifndef WIN32 -#define RECORDER_STORE_MODE STORE_MODE_RING_BUFFER -#else -/* Default in the Win32 demo */ -#define RECORDER_STORE_MODE STORE_MODE_STOP_WHEN_FULL -#endif + +#define TRACE_RECORDER_STORE_MODE TRACE_STORE_MODE_RING_BUFFER /****************************************************************************** * STOP_AFTER_N_EVENTS @@ -337,27 +386,21 @@ * * For tasks with "infinite" main loops (non-terminating tasks), the concept * of a task instance has no clear definition, it is an application-specific - * thing. FreeRTOS+Trace allows you to define Instance Finish Events (IFEs), + * thing. Tracealyzer allows you to define Instance Finish Events (IFEs), * which marks the point in a cyclic task when the "task instance" ends. * The IFE is a blocking kernel call, typically in the main loop of a task * which typically reads a message queue, waits for a semaphore or performs * an explicit delay. * - * If USE_IMPLICIT_IFE_RULES is one (1), the following FreeRTOS kernel calls - * are considered by default to be IFEs (Implicit IFEs): - * - vTaskDelay - * - vTaskDelayUntil - * - vTaskSuspend - * - xQueueReceive (blocking cases only) - * - xSemaphoreTake (blocking cases only) + * If USE_IMPLICIT_IFE_RULES is one (1), the kernel macros (trcKernelPort.h) + * will define what kernel calls are considered by default to be IFEs. * - * However, Implicit IFEs only applies to blocking kernel calls. If an - * xQueueReceive reads a message without blocking, it does not create a new + * However, Implicit IFEs only applies to blocking kernel calls. If a + * service reads a message without blocking, it does not create a new * instance since no blocking occurred. * - * Moreover, the actual IFE might sometimes be another blocking call such as - * xQueueSend or xSemaphoreGive. We therefore allow for user-defined - * Explicit IFEs by calling + * Moreover, the actual IFE might sometimes be another blocking call. We + * therefore allow for user-defined Explicit IFEs by calling * * vTraceTaskInstanceIsFinished() * @@ -365,8 +408,8 @@ * additional event but instead stores the service code and object handle * of the IFE call as properties of the task. * - * If using Explicit IFEs and the task also calls an Implicit IFE like - * vTaskDelay, this may result in additional incorrect task instances. + * If using Explicit IFEs and the task also calls an Implicit IFE, this may + * result in additional incorrect task instances. * This is solved by disabling the Implicit IFEs for the task, by adding * a call to * @@ -440,9 +483,9 @@ * be mapped to your console "printf" routine. The task is named TraceMon but * is intentionally excluded from the demo trace. * - * Default is 1000 FreeRTOS ticks (typically 1 second). On the Windows port, a - * lower value is suggested since the Windows port runs very slowly, often 20-40 - * times slower than the simulated FreeRTOS time. + * Default is 1000 ticks (typically 1 second). On the Windows port, a lower + * value is suggested since the Windows port runs very slowly, often 20-40 + * times slower than the simulated time. * * See vTraceMonitorTask in trcUser.c *****************************************************************************/ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/trcPort.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcHardwarePort.h similarity index 74% rename from FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/trcPort.h rename to FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcHardwarePort.h index a2d4bf1a4..0e97b8ec1 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Configuration - template/trcPort.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/ConfigurationTemplate/trcHardwarePort.h @@ -1,11 +1,11 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * - * trcPort.h + * trcHardwarePort.h * - * Contains together with trcPort.c all portability issues of the trace recorder - * library. + * Contains together with trcHardwarePort.c all hardware portability issues of + * the trace recorder library. * * Terms of Use * This software is copyright Percepio AB. The recorder library is free for @@ -32,18 +32,16 @@ * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ #ifndef TRCPORT_H #define TRCPORT_H -/* If FreeRTOS Win32 port */ +#include "trcKernelPort.h" + +/* If Win32 port */ #ifdef WIN32 #undef _WIN32_WINNT @@ -74,16 +72,13 @@ * A hardware independent fallback option for event timestamping. Provides low * resolution timestamps based on the OS tick. * This may be used on the Win32 port, but may also be used on embedded hardware - * platforms. Note that this gives suboptimal display in FreeRTOS+Trace. All - * time durations will be truncated to the OS tick frequency, typically 1 KHz. - * This means that a task or ISR that executes in less than 1 ms get an exection - * time of zero. They are however still visible in FreeRTOS+Trace. + * platforms. All time durations will be truncated to the OS tick frequency, + * typically 1 KHz. This means that a task or ISR that executes in less than + * 1 ms get an execution time of zero. * * PORT_Win32 - * "Accurate" timestamping based on the Windows permance counter. Note that - * this gives the host machine time, not the simulated FreeRTOS time (tick - * count). The timing of the Win32 FreeRTOS build is not real-time, since it - * depends on the scheduling and tick rate of Windows, which is very slow. + * "Accurate" timestamping based on the Windows performance counter. Note that + * this gives the host machine time. * * Officially supported hardware timer ports: * - PORT_Atmel_AT91SAM7 @@ -96,7 +91,7 @@ * been developed by external contributors, and have not yet been verified * by Percepio AB. Let us know if you have problems getting these to work. * - * Unoffical hardware specific ports provided are: + * Unofficial hardware specific ports provided are: * - PORT_TEXAS_INSTRUMENTS_TMS570 * - PORT_TEXAS_INSTRUMENTS_MSP430 * - PORT_MICROCHIP_PIC32 @@ -140,29 +135,29 @@ * * Macro which should be defined as an integer of 0 or 1. * - * This should be 0 if lower irq priority values implies higher priority + * 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. + * if higher IRQ priority values means higher priority, this should be 1. * * This setting is not critical. It is used only to sort and colorize the * interrupts in priority order, in case you record interrupts using * the vTraceStoreISRBegin and vTraceStoreISREnd routines. * * We provide this setting for some hardware architectures below: - * - ARM Cortex M: 0 (lower irq priority values are more significant) - * - Atmel AT91SAM7x: 1 (higher irq priority values are more significant) - * - Atmel AVR32: 1 (higher irq priority values are more significant) - * - Renesas RX600: 1 (higher irq priority values are more significant) - * - Microchip PIC24: 0 (lower irq priority values are more significant) - * - Microchip dsPIC: 0 (lower irq priority values are more significant) - * - TI TMS570: 0 (lower irq priority values are more significant) - * - Freescale HCS08: 0 (lower irq priority values are more significant) - * - Freescale HCS12: 0 (lower irq priority values are more significant) - * - PowerPC 405: 0 (lower irq priority values are more significant) - * - PowerPC 440: 0 (lower irq priority values are more significant) - * - Freescale ColdFire: 1 (higher irq priority values are more significant) - * - NXP LPC210x: 0 (lower irq priority values are more significant) - * - MicroBlaze: 0 (lower irq priority values are more significant) + * - ARM Cortex M: 0 (lower IRQ priority values are more significant) + * - Atmel AT91SAM7x: 1 (higher IRQ priority values are more significant) + * - Atmel AVR32: 1 (higher IRQ priority values are more significant) + * - Renesas RX600: 1 (higher IRQ priority values are more significant) + * - Microchip PIC24: 0 (lower IRQ priority values are more significant) + * - Microchip dsPIC: 0 (lower IRQ priority values are more significant) + * - TI TMS570: 0 (lower IRQ priority values are more significant) + * - Freescale HCS08: 0 (lower IRQ priority values are more significant) + * - Freescale HCS12: 0 (lower IRQ priority values are more significant) + * - PowerPC 405: 0 (lower IRQ priority values are more significant) + * - PowerPC 440: 0 (lower IRQ priority values are more significant) + * - Freescale ColdFire: 1 (higher IRQ priority values are more significant) + * - NXP LPC210x: 0 (lower IRQ priority values are more significant) + * - MicroBlaze: 0 (lower IRQ priority values are more significant) * * If your chip is not on the above list, and you perhaps know this detail by * heart, please inform us by e-mail to support@percepio.com. @@ -206,17 +201,9 @@ * Cortex M chip running at 72 MHZ should use a HWTC_DIVISOR of 2, while a * faster chip require a higher HWTC_DIVISOR value. * - * The HWTC macros and uiTracePortGetTimeStamp is the main porting issue + * The HWTC macros and vTracePortGetTimeStamp is the main porting issue * or the trace recorder library. Typically you should not need to change - * the code of uiTracePortGetTimeStamp if using the HWTC macros. - * - * FREE LICENSE OFFER FROM PERCEPIO - * - * For silicon companies and non-corporate FreeRTOS users (researchers, students, - * hobbyists or early-phase startups) we have the following offer: - * Provide a hardware port for our FreeRTOS recorder and get a FREE single-user - * license for FreeRTOS+Trace Professional Edition. Read more about this offer - * at www.percepio.com or contact us directly at support@percepio.com. + * the code of vTracePortGetTimeStamp if using the HWTC macros. * ******************************************************************************/ @@ -248,7 +235,7 @@ #define HWTC_PERIOD 2995 #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 1 // higher irq priority values are more significant + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant #elif (SELECTED_PORT == PORT_Atmel_UC3A0) @@ -256,10 +243,10 @@ #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING #define HWTC_COUNT sysreg_read(AVR32_COUNT) - #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 1 // higher irq priority values are more significant + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant #elif (SELECTED_PORT == PORT_ARM_CortexM) @@ -270,7 +257,7 @@ #define HWTC_PERIOD ((*(uint32_t*)0xE000E014) + 1) #define HWTC_DIVISOR 2 - #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_Renesas_RX600) @@ -278,19 +265,19 @@ #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING #define HWTC_COUNT (CMT0.CMCNT) - #define HWTC_PERIOD ((((configPERIPHERAL_CLOCK_HZ/configTICK_RATE_HZ)-1)/8)) + #define HWTC_PERIOD ((((TRACE_PERIPHERAL_CLOCK_HZ/TRACE_TICK_RATE_HZ)-1)/8)) #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 1 // higher irq priority values are more significant + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant -#elif (SELECTED_PORT == PORT_MICROCHIP_dsPIC_AND_PIC24) +#elif (SELECTED_PORT == PORT_Microchip_dsPIC_AND_PIC24) /* For Microchip PIC24 and dsPIC (16 bit) */ /* Note: The trace library was originally designed for 32-bit MCUs, and is slower than intended on 16-bit MCUs. Storing an event on a PIC24 takes about 70 µs. In comparison, 32-bit MCUs are often 10-20 times faster. If recording overhead - becomes a problem on PIC24, use the filters to exclude less interresting tasks + becomes a problem on PIC24, use the filters to exclude less interesting tasks or system calls. */ #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING @@ -298,21 +285,19 @@ #define HWTC_PERIOD (PR1+1) #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_NXP_LPC210X) /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - /* Tested with LPC2106, but should work with most LPC21XX chips. - Assumption: prescaler is 1:1 (this setting is hardcoded in - FreeRTOS port for LPC21XX) */ + /* Tested with LPC2106, but should work with most LPC21XX chips. */ #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING #define HWTC_COUNT *((uint32_t *)0xE0004008 ) - #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_TMS570) /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ @@ -325,17 +310,17 @@ #define HWTC_PERIOD (RTIUDCP0) #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_TEXAS_INSTRUMENTS_MSP430) /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ #define HWTC_COUNT_DIRECTION DIRECTION_INCREMENTING #define HWTC_COUNT (TA0R) - #define HWTC_PERIOD configCPU_CLOCKS_PER_TICK + #define HWTC_PERIOD TRACE_CPU_CLOCKS_PER_TICK #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 1 // higher irq priority values are more significant + #define IRQ_PRIORITY_ORDER 1 // higher IRQ priority values are more significant #elif (SELECTED_PORT == PORT_MICROCHIP_PIC32) /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ @@ -345,17 +330,17 @@ #define HWTC_PERIOD (ReadPeriod1()+1) /* Should be available in BSP */ #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_XILINX_PPC405) /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING #define HWTC_COUNT mfspr( 0x3db) - #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_XILINX_PPC440) /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ @@ -364,16 +349,15 @@ #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING #define HWTC_COUNT mfspr( 0x016 ) - #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) #define HWTC_DIVISOR 1 - #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT == PORT_XILINX_MICROBLAZE) /* UNOFFICIAL PORT - NOT YET VERIFIED BY PERCEPIO */ - /* This should work with most Microblaze configurations - * This port is based on the official FreeRTOS Microlaze port and example application. + /* This should work with most Microblaze configurations. * It uses the AXI Timer 0 - the tick interrupt source. * If an AXI Timer 0 peripheral is available on your hardware platform, no modifications are required. */ @@ -381,10 +365,10 @@ #define HWTC_COUNT_DIRECTION DIRECTION_DECREMENTING #define HWTC_COUNT XTmrCtr_GetTimerCounterReg( XPAR_TMRCTR_0_BASEADDR, 0 ) - #define HWTC_PERIOD ( configCPU_CLOCK_HZ / configTICK_RATE_HZ ) + #define HWTC_PERIOD ( TRACE_CPU_CLOCK_HZ / TRACE_TICK_RATE_HZ ) #define HWTC_DIVISOR 16 - #define IRQ_PRIORITY_ORDER 0 // lower irq priority values are more significant + #define IRQ_PRIORITY_ORDER 0 // lower IRQ priority values are more significant #elif (SELECTED_PORT != PORT_NOT_SET) @@ -437,23 +421,17 @@ #define vTraceConsoleMessage(x) /******************************************************************************* - * uiTracePortGetTimeStamp + * vTracePortGetTimeStamp * * Returns the current time based on the HWTC macros which provide a hardware * isolation layer towards the hardware timer/counter. * - * The HWTC macros and uiTracePortGetTimeStamp is the main porting issue + * The HWTC macros and vTracePortGetTimeStamp is the main porting issue * or the trace recorder library. Typically you should not need to change - * the code of uiTracePortGetTimeStamp if using the HWTC macros. + * the code of vTracePortGetTimeStamp if using the HWTC macros. * - * OFFER FROM PERCEPIO: - * For silicon companies and non-corporate FreeRTOS users (researchers, - * students, hobbyists or early-phase startups) we have an attractive offer: - * Provide a hardware timer port and get a FREE single-user licence for - * FreeRTOS+Trace Professional Edition. Read more about this offer at - * www.percepio.com or contact us directly at support@percepio.com. ******************************************************************************/ -void uiTracePortGetTimeStamp(uint32_t *puiTimestamp); +void vTracePortGetTimeStamp(uint32_t *puiTimestamp); /******************************************************************************* * vTracePortEnd @@ -485,6 +463,12 @@ void vTracePortSetOutFile(char* path); ******************************************************************************/ void vTracePortSave(void); +#else + +#define vTraceConsoleMessage(x) +#define vTracePortSetOutFile(path) +#define vTracePortSave(void) + #endif #endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h index 4ffd55c6a..9196f73d2 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcBase.h @@ -1,67 +1,118 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * * trcBase.h * - * Core functionallity of the FreeRTOS+Trace recorder library. + * Core functionality of the Tracealyzer 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 + * in its original form, including modifications in trcHardwarePort.c/.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 + * 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 + * 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.com/products/downloads/ * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ #ifndef TRCBASE_H #define TRCBASE_H +#define TRACE_MINOR_VERSION 2 +#define TRACE_STORE_MODE_STOP_WHEN_FULL 1 +#define TRACE_STORE_MODE_RING_BUFFER 2 +#define TRACE_DATA_ALLOCATION_STATIC 1 +#define TRACE_DATA_ALLOCATION_DYNAMIC 2 +#define TRACE_DATA_ALLOCATION_CUSTOM 3 + +#include "trcKernelPort.h" + +#if (USE_TRACEALYZER_RECORDER == 1) + #include #include -#include "FreeRTOS.h" -#include "trcConfig.h" -#include "trcTypes.h" -#include "trcPort.h" +#ifndef USE_SEPARATE_USER_EVENT_BUFFER +#define USE_SEPARATE_USER_EVENT_BUFFER 0 +#endif -extern volatile int recorder_busy; +/* Max number of event codes supported */ +#define NEventCodes 0x100 -#define trcCRITICAL_SECTION_BEGIN() {taskENTER_CRITICAL(); recorder_busy++;} -#define trcCRITICAL_SECTION_END() {recorder_busy--; taskEXIT_CRITICAL();} +extern volatile int recorder_busy; // This is used to keep track of the recorder's critical sections, to determine if it is busy +// Our local critical sections for the recorder - updates an internal busy flag +#define trcCRITICAL_SECTION_BEGIN() {TRACE_ENTER_CRITICAL_SECTION(); recorder_busy++;} +#define trcCRITICAL_SECTION_END() {recorder_busy--; TRACE_EXIT_CRITICAL_SECTION();} -#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 +/* Structure to handle the exclude flags for all objects and tasks. We add some extra objects since index 0 is not used for each object class. */ +extern uint8_t excludedObjects[(TRACE_KERNEL_OBJECT_COUNT + TRACE_NCLASSES) / 8 + 1]; + +/* Structure to handle the exclude flags for all event codes */ +extern uint8_t excludedEventCodes[NEventCodes / 8 + 1]; + +/****************************************************************************** + * 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 */ + int16_t indexOfNextAvailableHandle[ TRACE_NCLASSES ]; + + /* The lowest index of this class (constant) */ + int16_t lowestIndexOfClass[ TRACE_NCLASSES ]; + + /* The highest index of this class (constant) */ + int16_t highestIndexOfClass[ TRACE_NCLASSES ]; + + /* The highest use count for this class (for statistics) */ + int16_t handleCountWaterMarksOfClass[ TRACE_NCLASSES ]; + + /* The free object handles - a set of stacks within this array */ + objectHandleType objectHandles[ TRACE_KERNEL_OBJECT_COUNT ]; + +} objectHandleStackType; + +extern objectHandleStackType objectHandleStacks; /****************************************************************************** * Object Property Table @@ -69,96 +120,67 @@ extern volatile int recorder_busy; * 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 + * 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 is the taskswitch event type + * and for "isActive", where the value decides if the task switch 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 + + /* This is used to calculate the index in the dynamic object table (handle - 1 - nofStaticObjects = index)*/ - uint8_t NumberOfObjectsPerClass[ 4*((NCLASSES+3)/4)]; + uint8_t NumberOfObjectsPerClass[ 4*((TRACE_NCLASSES+3)/4)]; + + /* 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 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) ]; + uint16_t StartIndexOfClass[ 2*((TRACE_NCLASSES+1)/2) ]; - /* The actual handles issued, should be Initiated to all zeros */ - uint8_t objbytes[ 4*((DynObjTableSize+3)/4) ]; + /* 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; - + uint32_t symTableSize; + /* Entry 0 is reserved. Any reference to entry 0 implies NULL*/ - uint32_t nextFreeSymbolIndex; - + 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. + 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]; + uint16_t latestEntryOfChecksum[64]; } symbolTableType; /******************************************************************************* - * The data structures of the different events, all 4 bytes long + * The data structures of the different events, all 4 bytes long ******************************************************************************/ typedef struct { - uint8_t type; + uint8_t type; objectHandleType objHandle; - uint16_t dts; /* differential timestamp - time since last event */ + uint16_t dts; /* differential timestamp - time since last event */ } TSEvent, TREvent; typedef struct @@ -173,13 +195,13 @@ typedef struct uint8_t type; objectHandleType objHandle; uint8_t param; - uint8_t dts; + uint8_t dts; } KernelCallWithParamAndHandle; typedef struct { uint8_t type; - uint8_t dts; + uint8_t dts; uint16_t param; } KernelCallWithParam16; @@ -193,37 +215,73 @@ typedef struct typedef struct { uint8_t type; - uint8_t arg1; - uint8_t arg2; - uint8_t arg3; + uint8_t arg1; + uint8_t arg2; + uint8_t arg3; } ObjClosePropEvent; typedef struct { uint8_t type; - uint8_t dts; + 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 + 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; - + uint8_t xts_8; + /* 16 bits extra for storing DTS, if it does not fit in ordinary event. */ - uint16_t xts_16; + uint16_t xts_16; } XTSEvent; +typedef struct +{ + uint8_t type; + + uint8_t xps_8; + uint16_t xps_16; +} XPSEvent; /******************************************************************************* - * The main datastructure, read by FreeRTOS+Trace from the RAM dump + * The separate user event buffer structure. Can be enabled in trcConfig.h. ******************************************************************************/ +#if (USE_SEPARATE_USER_EVENT_BUFFER == 1) typedef struct -{ +{ + traceLabel name; + traceLabel 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[CHANNEL_FORMAT_PAIRS+1]; + uint8_t channelBuffer[(USER_EVENT_BUFFER_SIZE + 3) & 0xFFFFFFFC]; /* 1 byte per slot, with padding for 4 byte alignment */ + uint8_t dataBuffer[USER_EVENT_BUFFER_SIZE * 4]; /* 4 bytes per slot */ + +} UserEventBuffer; +#endif + +/******************************************************************************* + * The main data structure, read by Tracealyzer from the RAM dump + ******************************************************************************/ + +typedef struct +{ uint8_t startmarker0; uint8_t startmarker1; uint8_t startmarker2; @@ -237,92 +295,99 @@ typedef struct uint8_t startmarker10; uint8_t startmarker11; - /* For FreeRTOS: 0x1AA1 */ - uint16_t version; - + /* Used to determine Kernel and Endianess */ + 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. */ + + /* 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 + /* The absolute timestamp of the last stored event, in the native timebase, modulo frequency! */ - uint32_t absTimeLastEvent; - + uint32_t absTimeLastEvent; + /* The number of seconds in total - lasts for 136 years */ - uint32_t absTimeLastEventSecond; - + 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; + uint32_t recorderActive; /* For storing a Team License key */ uint8_t teamLicenceKey[32]; /* 0xF0F0F0F0 - for control only */ - int32_t debugMarker0; + 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; + /* 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. */ + /* 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 */ + /* For inclusion 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; + float exampleFloatEncoding; #else - uint32_t exampleFloatEncoding; + 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 + /* 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; - - /* Generic system information string, presented in the tool. Note that this + + /* 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]; + char systemInfo[TRACE_DESCRIPTION_MAX_LENGTH]; /* 0xF3F3F3F3 - for control only */ - int32_t debugMarker3; + int32_t debugMarker3; /* The event data, in 4-byte records */ uint8_t eventData[ EVENT_BUFFER_SIZE * 4 ]; +#if (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; @@ -335,103 +400,51 @@ typedef struct 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; - -/* Structures to handle the exclude flags for all objects, tasks and event codes */ -#define NEventCodes 0x100 -extern uint8_t excludedFlags[(NEventCodes+NQueue+NSemaphore+NMutex+NTask) / 8 + 1]; -extern uint8_t ifeFlags[NTask / 8 + 1]; - /* Internal functions */ uint16_t prvTraceGetDTS(uint16_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 prvTraceCreateSymbolTableEntry(const char* name, + uint8_t crc6, + uint8_t len, traceLabel channel); -traceLabel prvTraceLookupSymbolTableEntry(const char* name, - uint8_t crc6, - uint8_t len, +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(uint8_t nEntries); +void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nEntries); objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass); -void vTraceFreeObjectHandle(traceObjectClass objectclass, +void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handle); -void vTraceSetObjectName(traceObjectClass objectclass, - objectHandleType handle, - const char* name); +void vTraceSetObjectName(traceObjectClass objectclass, + objectHandleType handle, + const char* name); void* xTraceNextFreeEventBufferSlot(void); -uint16_t uiIndexOfObject(objectHandleType objecthandle, - uint8_t objectclass); +uint16_t uiIndexOfObject(objectHandleType objecthandle, + uint8_t objectclass); /******************************************************************************* * vTraceError * - * Called by various parts in the recorder. Stops the recorder and stores a + * 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(const char* msg); @@ -445,80 +458,48 @@ void vTraceError(const char* msg); char* xTraceGetLastError(void); /******************************************************************************* - * xTraceInitTraceData + * prvTraceInitTraceData * - * Allocates and initializes the recorder datastructure, based on the constants + * Allocates and initializes the recorder data structure, 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); +void prvTraceInitTraceData(void); /* Internal macros */ -#define PROPERTY_NAME_GET(objectclass, objecthandle) \ +#define TRACE_PROPERTY_NAME_GET(objectclass, objecthandle) \ (const char*)(& RecorderDataPtr->ObjectPropertyTable.objbytes \ [uiIndexOfObject(objecthandle, objectclass)]) -#define PROPERTY_OBJECT_STATE(objectclass, handle) \ +#define TRACE_PROPERTY_OBJECT_STATE(objectclass, handle) \ RecorderDataPtr->ObjectPropertyTable.objbytes[uiIndexOfObject(handle, objectclass) \ + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[objectclass]] -#define PROPERTY_ACTOR_PRIORITY(objectclass, handle) \ +#define TRACE_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 SET_FLAG_ISEXCLUDED(bitIndex) excludedFlags[(bitIndex) >> 3] |= (1 << ((bitIndex) & 7)) -#define CLEAR_FLAG_ISEXCLUDED(bitIndex) excludedFlags[(bitIndex) >> 3] &= ~(1 << ((bitIndex) & 7)) -#define GET_FLAG_ISEXCLUDED(bitIndex) (excludedFlags[(bitIndex) >> 3] & (1 << ((bitIndex) & 7))) - -#define SET_FLAG_MARKIFE(bitIndex) ifeFlags[(bitIndex) >> 3] |= (1 << ((bitIndex) & 7)) -#define CLEAR_FLAG_MARKIFE(bitIndex) ifeFlags[(bitIndex) >> 3] &= ~(1 << ((bitIndex) & 7)) -#define GET_FLAG_MARKIFE(bitIndex) (ifeFlags[(bitIndex) >> 3] & (1 << ((bitIndex) & 7))) - -#define SET_EVENT_CODE_FLAG_ISEXCLUDED(eventCode) SET_FLAG_ISEXCLUDED(eventCode) -#define CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(eventCode) CLEAR_FLAG_ISEXCLUDED(eventCode) -#define GET_EVENT_CODE_FLAG_ISEXCLUDED(eventCode) GET_FLAG_ISEXCLUDED(eventCode) - -#define SET_QUEUE_FLAG_ISEXCLUDED(queueHandle) SET_FLAG_ISEXCLUDED(NEventCodes+queueHandle-1) -#define CLEAR_QUEUE_FLAG_ISEXCLUDED(queueHandle) CLEAR_FLAG_ISEXCLUDED(NEventCodes+queueHandle-1) -#define GET_QUEUE_FLAG_ISEXCLUDED(queueHandle) GET_FLAG_ISEXCLUDED(NEventCodes+queueHandle-1) - -#define SET_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreHandle) SET_FLAG_ISEXCLUDED(NEventCodes+NQueue+semaphoreHandle-1) -#define CLEAR_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreHandle) CLEAR_FLAG_ISEXCLUDED(NEventCodes+NQueue+semaphoreHandle-1) -#define GET_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreHandle) GET_FLAG_ISEXCLUDED(NEventCodes+NQueue+semaphoreHandle-1) - -#define SET_MUTEX_FLAG_ISEXCLUDED(mutexHandle) SET_FLAG_ISEXCLUDED(NEventCodes+NQueue+NSemaphore+mutexHandle-1) -#define CLEAR_MUTEX_FLAG_ISEXCLUDED(mutexHandle) CLEAR_FLAG_ISEXCLUDED(NEventCodes+NQueue+NSemaphore+mutexHandle-1) -#define GET_MUTEX_FLAG_ISEXCLUDED(mutexHandle) GET_FLAG_ISEXCLUDED(NEventCodes+NQueue+NSemaphore+mutexHandle-1) - -#define SET_TASK_FLAG_ISEXCLUDED(taskHandle) SET_FLAG_ISEXCLUDED(NEventCodes+NQueue+NSemaphore+NMutex+taskHandle-1) -#define CLEAR_TASK_FLAG_ISEXCLUDED(taskHandle) CLEAR_FLAG_ISEXCLUDED(NEventCodes+NQueue+NSemaphore+NMutex+taskHandle-1) -#define GET_TASK_FLAG_ISEXCLUDED(taskHandle) GET_FLAG_ISEXCLUDED(NEventCodes+NQueue+NSemaphore+NMutex+taskHandle-1) - -#define SET_TASK_FLAG_MARKIFE(bitIndex) SET_FLAG_MARKIFE(bitIndex-1) -#define CLEAR_TASK_FLAG_MARKIFE(bitIndex) CLEAR_FLAG_MARKIFE(bitIndex-1) -#define GET_TASK_FLAG_MARKIFE(bitIndex) GET_FLAG_MARKIFE(bitIndex-1) - -/* For debug printouts - the names of the object classes */ -extern char OBJECTCLASSNAME[NCLASSES][10]; -/*= -{ - "QUEUE" - "SEMAPHORE", - "MUTEX", - "TASK", - "ISR" -};*/ +#define TRACE_SET_FLAG_ISEXCLUDED(flags, bitIndex) flags[(bitIndex) >> 3] |= (1 << ((bitIndex) & 7)) +#define TRACE_CLEAR_FLAG_ISEXCLUDED(flags, bitIndex) flags[(bitIndex) >> 3] &= ~(1 << ((bitIndex) & 7)) +#define TRACE_GET_FLAG_ISEXCLUDED(flags, bitIndex) (flags[(bitIndex) >> 3] & (1 << ((bitIndex) & 7))) + +#define TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(eventCode) TRACE_SET_FLAG_ISEXCLUDED(excludedEventCodes, eventCode) +#define TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(eventCode) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedEventCodes, eventCode) +#define TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(eventCode) TRACE_GET_FLAG_ISEXCLUDED(excludedEventCodes, eventCode) + +/* DEBUG ASSERTS */ +#if defined USE_TRACE_ASSERT && USE_TRACE_ASSERT != 0 +#define TRACE_ASSERT(eval, msg, defRetVal) \ +if (!(eval)) \ +{ \ + vTraceError("TRACE_ASSERT: " msg); \ + return defRetVal; \ +} +#else +#define TRACE_ASSERT(eval, msg, defRetVal) +#endif #endif +#endif \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHooks.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHooks.h index c5fc9a4d1..66c381406 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHooks.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcHooks.h @@ -1,308 +1,193 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library - * Percepio AB, www.percepio.com - * - * trcHooks.h - * - * The kernel integration hooks for FreeRTOS (v7.1.0 or later). This file should - * be included in the end of FreeRTOSConfig.h, together with: - * - * #define configUSE_TRACE_FACILITY 1 - * - * NOTE: - * For IAR Embedded Workbench for ARM, you need to have a preprocessor condition - * on the include, to except it from the assembler step which otherwise give - * compile-time errors. - * - * #ifdef __ICCARM__ - * #include "percepio/Include/trcHooks.h" - * #endif - * - * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. - * www.percepio.com - ******************************************************************************/ +* Tracealyzer v2.4.1 Recorder Library +* Percepio AB, www.percepio.com +* +* trcKernelHooks.h +* +* The kernel integration hooks. +* +* NOTE: +* For IAR Embedded Workbench for ARM, you need to have a preprocessor condition +* on the include, to except it from the assembler step which otherwise give +* compile-time errors. +* +* #ifdef __ICCARM__ +* #include "percepio/Include/trcKernelHooks.h" +* #endif +* +* 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. +* +* Copyright Percepio AB, 2013. +* www.percepio.com +******************************************************************************/ + +#ifndef TRCKERNELHOOKS_H +#define TRCKERNELHOOKS_H + +#if (USE_TRACEALYZER_RECORDER == 1) + +#undef INCLUDE_xTaskGetSchedulerState +#define INCLUDE_xTaskGetSchedulerState 1 + +#undef INCLUDE_xTaskGetCurrentTaskHandle +#define INCLUDE_xTaskGetCurrentTaskHandle 1 -#ifndef TRCHOOKS_H -#define TRCHOOKS_H - -#if (configUSE_TRACE_FACILITY == 1) - - #include "trcUser.h" - - #undef INCLUDE_xTaskGetSchedulerState - #define INCLUDE_xTaskGetSchedulerState 1 - - #undef INCLUDE_xTaskGetCurrentTaskHandle - #define INCLUDE_xTaskGetCurrentTaskHandle 1 - -#if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1 - /* Called for each task that becomes ready */ - #undef traceMOVED_TASK_TO_READY_STATE - #define traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ - vTraceStoreTaskReady((unsigned char)pxTCB->uxTaskNumber); +#ifndef INCLUDE_OBJECT_DELETE +#define INCLUDE_OBJECT_DELETE 0 #endif - - /* Called on each OS tick. Will call uiPortGetTimestamp to make sure it is called at least once every OS tick. */ - #undef traceTASK_INCREMENT_TICK - #define traceTASK_INCREMENT_TICK( xTickCount ) \ - if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || uxMissedTicks == 0) {extern uint32_t uiTraceTickCount; uiTraceTickCount++; uiTracePortGetTimeStamp(0);} - - /* Called on each task-switch */ - #undef traceTASK_SWITCHED_IN - #define traceTASK_SWITCHED_IN() \ - vTraceStoreTaskswitch(); - /* Called on vTaskSuspend */ - #undef traceTASK_SUSPEND - #define traceTASK_SUSPEND( pxTaskToSuspend ) \ - vTraceStoreKernelCall(TASK_SUSPEND, TRACE_CLASS_TASK, pxTaskToSuspend->uxTaskNumber); \ - vTraceSetTaskInstanceFinished((uint8_t)pxTaskToSuspend->uxTaskNumber); - - /* Called on vTaskDelay - note the use of FreeRTOS variable xTicksToDelay */ - #undef traceTASK_DELAY - #define traceTASK_DELAY() \ - portENTER_CRITICAL(); \ - vTraceStoreKernelCallWithNumericParamOnly(TASK_DELAY, (uint16_t)xTicksToDelay);\ - vTraceSetTaskInstanceFinished((uint8_t)pxCurrentTCB->uxTaskNumber);\ - portEXIT_CRITICAL(); - - /* Called on vTaskDelayUntil - note the use of FreeRTOS variable xTimeToWake */ - #undef traceTASK_DELAY_UNTIL - #define traceTASK_DELAY_UNTIL() \ - portENTER_CRITICAL(); \ - vTraceStoreKernelCallWithNumericParamOnly(TASK_DELAY_UNTIL, (uint16_t)xTimeToWake); \ - vTraceSetTaskInstanceFinished((uint8_t)pxCurrentTCB->uxTaskNumber); \ - portEXIT_CRITICAL(); +#ifndef INCLUDE_READY_EVENTS +#define INCLUDE_READY_EVENTS 1 +#endif -#ifndef INCLUDE_OBJECT_DELETE -#define INCLUDE_OBJECT_DELETE 1 +#ifndef INCLUDE_NEW_TIME_EVENTS +#define INCLUDE_NEW_TIME_EVENTS 0 #endif #if (INCLUDE_OBJECT_DELETE == 1) - /* Called on vTaskDelete */ - #undef traceTASK_DELETE - #define traceTASK_DELETE( pxTaskToDelete ) \ - trcCRITICAL_SECTION_BEGIN(); \ - vTraceStoreKernelCall(EVENTGROUP_DELETE + TRACE_CLASS_TASK, TRACE_CLASS_TASK, pxTaskToDelete->uxTaskNumber); \ - vTraceStoreObjectNameOnCloseEvent((objectHandleType)pxTaskToDelete->uxTaskNumber, TRACE_CLASS_TASK); \ - vTraceStoreObjectPropertiesOnCloseEvent((objectHandleType)pxTaskToDelete->uxTaskNumber, TRACE_CLASS_TASK); \ - vTraceSetPriorityProperty(TRACE_CLASS_TASK, (objectHandleType)pxTaskToDelete->uxTaskNumber, (uint8_t)pxTaskToDelete->uxPriority); \ - vTraceSetObjectState(TRACE_CLASS_TASK, (objectHandleType)pxTaskToDelete->uxTaskNumber, TASK_STATE_INSTANCE_NOT_ACTIVE); \ - vTraceFreeObjectHandle(TRACE_CLASS_TASK, (objectHandleType)pxTaskToDelete->uxTaskNumber); \ - trcCRITICAL_SECTION_END(); +/* This macro will remove the task and store it in the event buffer */ +#undef trcKERNEL_HOOKS_TASK_DELETE +#define trcKERNEL_HOOKS_TASK_DELETE(SERVICE, pxTCB) \ + vTraceStoreKernelCall(TRACE_GET_TASK_EVENT_CODE(SERVICE, SUCCESS, CLASS, pxTCB), TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); \ + vTraceStoreObjectNameOnCloseEvent(TRACE_GET_TASK_NUMBER(pxTCB), TRACE_CLASS_TASK); \ + vTraceStoreObjectPropertiesOnCloseEvent(TRACE_GET_TASK_NUMBER(pxTCB), TRACE_CLASS_TASK); \ + vTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_PRIORITY(pxTCB)); \ + vTraceSetObjectState(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TASK_STATE_INSTANCE_NOT_ACTIVE); \ + vTraceFreeObjectHandle(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); +#else +#undef trcKERNEL_HOOKS_TASK_DELETE +#define trcKERNEL_HOOKS_TASK_DELETE(SERVICE, pxTCB) #endif - /* Called on vTaskCreate */ - #undef traceTASK_CREATE - #define traceTASK_CREATE( pxNewTCB ) \ - if (pxNewTCB != NULL){ \ - pxNewTCB->uxTaskNumber = xTraceGetObjectHandle(TRACE_CLASS_TASK); \ - vTraceSetObjectName(TRACE_CLASS_TASK, (objectHandleType)pxNewTCB->uxTaskNumber, (char*)pxNewTCB->pcTaskName); \ - vTraceSetPriorityProperty(TRACE_CLASS_TASK, (objectHandleType)pxNewTCB->uxTaskNumber, (uint8_t)pxNewTCB->uxPriority); \ - vTraceStoreKernelCall(EVENTGROUP_CREATE + TRACE_CLASS_TASK, TRACE_CLASS_TASK, pxNewTCB->uxTaskNumber);\ - } - - /* Called in vTaskCreate, if it fails (typically if the stack can not be allocated) */ - #undef traceTASK_CREATE_FAILED - #define traceTASK_CREATE_FAILED() \ - portENTER_CRITICAL();\ - vTraceStoreKernelCall(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_TASK, TRACE_CLASS_TASK, 0); \ - portEXIT_CRITICAL(); - - /* Called in xQueueCreate, and thereby for all other object based on queues, such as semaphores. */ - #undef traceQUEUE_CREATE - #define traceQUEUE_CREATE( pxNewQueue )\ - portENTER_CRITICAL(); \ - pxNewQueue->ucQueueNumber = xTraceGetObjectHandle(TraceObjectClassTable[pxNewQueue->ucQueueType]);\ - vTraceStoreKernelCall(EVENTGROUP_CREATE + TraceObjectClassTable[pxNewQueue->ucQueueType], TraceObjectClassTable[pxNewQueue->ucQueueType], pxNewQueue->ucQueueNumber); \ - vTraceSetObjectState(TraceObjectClassTable[pxNewQueue->ucQueueType], pxNewQueue->ucQueueNumber, 0); \ - portEXIT_CRITICAL(); - - /* Called in xQueueCreate, if the queue creation fails */ - #undef traceQUEUE_CREATE_FAILED - #define traceQUEUE_CREATE_FAILED( queueType ) \ - portENTER_CRITICAL();\ - vTraceStoreKernelCall((uint8_t)(EVENTGROUP_FAILED_CREATE + TraceObjectClassTable[queueType]), TraceObjectClassTable[queueType], 0); \ - portEXIT_CRITICAL(); - - /* Called in xQueueCreateMutex, and thereby also from xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex */ - #undef traceCREATE_MUTEX - #define traceCREATE_MUTEX( pxNewQueue ) \ - portENTER_CRITICAL();\ - pxNewQueue->ucQueueNumber = xTraceGetObjectHandle(TRACE_CLASS_MUTEX); \ - vTraceStoreKernelCall(EVENTGROUP_CREATE + TraceObjectClassTable[pxNewQueue->ucQueueType], TraceObjectClassTable[pxNewQueue->ucQueueType], pxNewQueue->ucQueueNumber); \ - vTraceSetObjectState(TraceObjectClassTable[pxNewQueue->ucQueueType], pxNewQueue->ucQueueNumber, 0); \ - portEXIT_CRITICAL(); - - /* Called in xQueueCreateMutex when the operation fails (when memory allocation fails) */ - #undef traceCREATE_MUTEX_FAILED - #define traceCREATE_MUTEX_FAILED() \ - portENTER_CRITICAL();\ - vTraceStoreKernelCall(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_MUTEX, TRACE_CLASS_MUTEX, 0);\ - portEXIT_CRITICAL(); - - /* Called when the Mutex can not be given, since not holder */ - #undef traceGIVE_MUTEX_RECURSIVE_FAILED - #define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) \ - portENTER_CRITICAL();\ - vTraceStoreKernelCall(EVENTGROUP_FAILED_SEND + TRACE_CLASS_MUTEX, TRACE_CLASS_MUTEX, pxMutex->ucQueueNumber); \ - portEXIT_CRITICAL(); - - /* Called when a message is sent to a queue */ - #undef traceQUEUE_SEND - #define traceQUEUE_SEND( pxQueue ) \ - vTraceStoreKernelCall(EVENTGROUP_SEND + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - if (TraceObjectClassTable[pxQueue->ucQueueType] == TRACE_CLASS_MUTEX){\ - vTraceSetObjectState(TraceObjectClassTable[pxQueue->ucQueueType], (uint8_t)pxQueue->ucQueueNumber, (uint8_t)0); \ - }else{\ - vTraceSetObjectState(TraceObjectClassTable[pxQueue->ucQueueType], (uint8_t)pxQueue->ucQueueNumber, (uint8_t)(pxQueue->uxMessagesWaiting + 1)); \ - } - - /* Called when a message failed to be sent to a queue (timeout) */ - #undef traceQUEUE_SEND_FAILED - #define traceQUEUE_SEND_FAILED( pxQueue ) \ - portENTER_CRITICAL();\ - vTraceStoreKernelCall(EVENTGROUP_FAILED_SEND + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - portEXIT_CRITICAL(); - - /* Called when the task is blocked due to a send operation on a full queue */ - #undef traceBLOCKING_ON_QUEUE_SEND - #define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) \ - portENTER_CRITICAL();\ - vTraceStoreKernelCall(EVENTGROUP_BLOCK_ON_SEND + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - portEXIT_CRITICAL(); - - /* Called when a message is received from a queue */ - #undef traceQUEUE_RECEIVE - #define traceQUEUE_RECEIVE( pxQueue ) \ - vTraceStoreKernelCall(EVENTGROUP_RECEIVE + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - if (TraceObjectClassTable[pxQueue->ucQueueType] == TRACE_CLASS_MUTEX){\ - extern volatile void * volatile pxCurrentTCB; \ - vTraceSetObjectState(TraceObjectClassTable[pxQueue->ucQueueType], (objectHandleType)pxQueue->ucQueueNumber, (objectHandleType)uxTaskGetTaskNumber((xTaskHandle)pxCurrentTCB)); /*For mutex, store the new owner rather than queue length */ \ - }else{\ - vTraceSetObjectState(TraceObjectClassTable[pxQueue->ucQueueType], (objectHandleType)pxQueue->ucQueueNumber, (uint8_t)(pxQueue->uxMessagesWaiting - 1)); \ - } - - /* Called when the task is blocked due to a receive operation on an empty queue */ - #undef traceBLOCKING_ON_QUEUE_RECEIVE - #define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) \ - portENTER_CRITICAL(); \ - vTraceStoreKernelCall(EVENTGROUP_BLOCK_ON_RECEIVE + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - if (TraceObjectClassTable[pxQueue->ucQueueType] != TRACE_CLASS_MUTEX){\ - extern volatile void * volatile pxCurrentTCB; \ - vTraceSetTaskInstanceFinished((objectHandleType)uxTaskGetTaskNumber((xTaskHandle)pxCurrentTCB)); \ - }\ - portEXIT_CRITICAL(); - - /* Called on xQueuePeek */ - #undef traceQUEUE_PEEK - #define traceQUEUE_PEEK( pxQueue ) \ - vTraceStoreKernelCall(EVENTGROUP_PEEK + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); - - /* Called when a receive operation on a queue fails (timeout) */ - #undef traceQUEUE_RECEIVE_FAILED - #define traceQUEUE_RECEIVE_FAILED( pxQueue ) \ - portENTER_CRITICAL(); \ - vTraceStoreKernelCall(EVENTGROUP_FAILED_RECEIVE + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - portEXIT_CRITICAL(); - - /* Called when a message is sent from interrupt context, e.g., using xQueueSendFromISR */ - #undef traceQUEUE_SEND_FROM_ISR - #define traceQUEUE_SEND_FROM_ISR( pxQueue ) \ - vTraceStoreKernelCall(EVENTGROUP_SEND_FROM_ISR + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - vTraceSetObjectState(TraceObjectClassTable[pxQueue->ucQueueType], (objectHandleType)pxQueue->ucQueueNumber, (uint8_t)(pxQueue->uxMessagesWaiting + 1)); - - /* Called when a message send from interrupt context fails (since the queue was full) */ - #undef traceQUEUE_SEND_FROM_ISR_FAILED - #define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) \ - vTraceStoreKernelCall(EVENTGROUP_FAILED_SEND_FROM_ISR + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); - - /* Called when a message is received in interrupt context, e.g., using xQueueReceiveFromISR */ - #undef traceQUEUE_RECEIVE_FROM_ISR - #define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) \ - vTraceStoreKernelCall(EVENTGROUP_RECEIVE_FROM_ISR + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - vTraceSetObjectState(TraceObjectClassTable[pxQueue->ucQueueType], (objectHandleType)pxQueue->ucQueueNumber, (uint8_t)(pxQueue->uxMessagesWaiting - 1)); - - /* Called when a message receive from interrupt context fails (since the queue was empty) */ - #undef traceQUEUE_RECEIVE_FROM_ISR_FAILED - #define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) \ - vTraceStoreKernelCall(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); - #if (INCLUDE_OBJECT_DELETE == 1) - /* Called on vQueueDelete */ - #undef traceQUEUE_DELETE - #define traceQUEUE_DELETE( pxQueue ) \ - { \ - portENTER_CRITICAL();\ - vTraceStoreKernelCall(EVENTGROUP_DELETE + TraceObjectClassTable[pxQueue->ucQueueType], TraceObjectClassTable[pxQueue->ucQueueType], pxQueue->ucQueueNumber); \ - vTraceStoreObjectNameOnCloseEvent((objectHandleType)pxQueue->ucQueueNumber, TraceObjectClassTable[pxQueue->ucQueueType]); \ - vTraceStoreObjectPropertiesOnCloseEvent((objectHandleType)pxQueue->ucQueueNumber, TraceObjectClassTable[pxQueue->ucQueueType]); \ - if (TraceObjectClassTable[pxQueue->ucQueueType] == TRACE_CLASS_MUTEX){ \ - vTraceSetObjectState(TraceObjectClassTable[pxQueue->ucQueueType], (objectHandleType)pxQueue->ucQueueNumber, (objectHandleType)uxTaskGetTaskNumber((xTaskHandle)pxQueue->pxMutexHolder)); \ - }else{ \ - vTraceSetObjectState(TraceObjectClassTable[pxQueue->ucQueueType], (objectHandleType)pxQueue->ucQueueNumber, (uint8_t)uxQueueMessagesWaiting(pxQueue)); \ - } \ - vTraceFreeObjectHandle(TraceObjectClassTable[pxQueue->ucQueueType], (objectHandleType)pxQueue->ucQueueNumber); \ - portEXIT_CRITICAL();\ - } +/* This macro will remove the object and store it in the event buffer */ +#undef trcKERNEL_HOOKS_OBJECT_DELETE +#define trcKERNEL_HOOKS_OBJECT_DELETE(SERVICE, CLASS, pxObject) \ + vTraceStoreKernelCall(TRACE_GET_OBJECT_EVENT_CODE(SERVICE, SUCCESS, CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); \ + vTraceStoreObjectNameOnCloseEvent(TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)); \ + vTraceStoreObjectPropertiesOnCloseEvent(TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)); \ + vTraceFreeObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); +#else +#undef trcKERNEL_HOOKS_OBJECT_DELETE +#define trcKERNEL_HOOKS_OBJECT_DELETE(SERVICE, CLASS, pxObject) #endif - - /* Called in vTaskPrioritySet */ - #undef traceTASK_PRIORITY_SET - #define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) \ - vTraceStoreKernelCallWithParam(TASK_PRIORITY_SET, TRACE_CLASS_TASK, pxTask->uxTaskNumber, uiTraceGetPriorityProperty(TRACE_CLASS_TASK, (uint8_t)pxTask->uxTaskNumber));\ - vTraceSetPriorityProperty( TRACE_CLASS_TASK, (uint8_t)pxTask->uxTaskNumber, (uint8_t)uxNewPriority); - - /* Called in vTaskPriorityInherit, which is called by Mutex operations */ - #undef traceTASK_PRIORITY_INHERIT - #define traceTASK_PRIORITY_INHERIT( pxTask, uxNewPriority ) \ - vTraceStoreKernelCallWithParam(TASK_PRIORITY_INHERIT, TRACE_CLASS_TASK, pxTask->uxTaskNumber, uiTraceGetPriorityProperty(TRACE_CLASS_TASK, (uint8_t)pxTask->uxTaskNumber));\ - vTraceSetPriorityProperty( TRACE_CLASS_TASK, (uint8_t)pxTask->uxTaskNumber, (uint8_t)uxNewPriority ); - /* Called in vTaskPriorityDisinherit, which is called by Mutex operations */ - #undef traceTASK_PRIORITY_DISINHERIT - #define traceTASK_PRIORITY_DISINHERIT( pxTask, uxNewPriority ) \ - vTraceStoreKernelCallWithParam(TASK_PRIORITY_DISINHERIT, TRACE_CLASS_TASK, pxTask->uxTaskNumber, uiTraceGetPriorityProperty(TRACE_CLASS_TASK, (uint8_t)pxTask->uxTaskNumber));\ - vTraceSetPriorityProperty( TRACE_CLASS_TASK, (uint8_t)pxTask->uxTaskNumber, (uint8_t)uxNewPriority ); +/* This macro will create a task in the object table */ +#undef trcKERNEL_HOOKS_TASK_CREATE +#define trcKERNEL_HOOKS_TASK_CREATE(SERVICE, pxTCB) \ + TRACE_SET_TASK_NUMBER(pxTCB) \ + vTraceSetObjectName(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_NAME(pxTCB)); \ + vTraceSetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), TRACE_GET_TASK_PRIORITY(pxTCB)); \ + vTraceStoreKernelCall(TRACE_GET_TASK_EVENT_CODE(SERVICE, SUCCESS, CLASS, pxTCB), TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); + +/* This macro will create a failed create call to create a task */ +#undef trcKERNEL_HOOKS_TASK_CREATE_FAILED +#define trcKERNEL_HOOKS_TASK_CREATE_FAILED(SERVICE) \ + vTraceStoreKernelCall(TRACE_GET_TASK_EVENT_CODE(SERVICE, FAILED, CLASS, pxTCB), TRACE_CLASS_TASK, 0); + +/* 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);\ + vTraceStoreKernelCall(TRACE_GET_OBJECT_EVENT_CODE(SERVICE, SUCCESS, CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); \ + vTraceSetObjectState(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), 0); + +/* This macro will create a failed create call to create an object */ +#undef trcKERNEL_HOOKS_OBJECT_CREATE_FAILED +#define trcKERNEL_HOOKS_OBJECT_CREATE_FAILED(SERVICE, CLASS, kernelClass) \ + vTraceStoreKernelCall(TRACE_GET_CLASS_EVENT_CODE(SERVICE, FAILED, CLASS, kernelClass), TRACE_GET_CLASS_TRACE_CLASS(CLASS, kernelClass), 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 +#define trcKERNEL_HOOKS_KERNEL_SERVICE(SERVICE, RESULT, CLASS, pxObject) \ + vTraceStoreKernelCall(TRACE_GET_OBJECT_EVENT_CODE(SERVICE, RESULT, CLASS, pxObject), TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject)); + +/* This macro will set the state for an object */ +#undef trcKERNEL_HOOKS_SET_OBJECT_STATE +#define trcKERNEL_HOOKS_SET_OBJECT_STATE(CLASS, pxObject, STATE) \ + vTraceSetObjectState(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject), TRACE_GET_OBJECT_NUMBER(CLASS, pxObject), 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(CLASS, pxObject) \ + vTraceSetTaskInstanceFinished(TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK())); + +#if 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) \ + vTraceStoreTaskReady(TRACE_GET_TASK_NUMBER(pxTCB)); +#else +#undef trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE +#define trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB) +#endif - /* Called in vTaskResume */ - #undef traceTASK_RESUME - #define traceTASK_RESUME( pxTaskToResume ) \ - vTraceStoreKernelCall(TASK_RESUME, TRACE_CLASS_TASK, pxTaskToResume->uxTaskNumber); +/* This macro will update the internal tick counter and call vTracePortGetTimeStamp(0) to update the internal counters */ +#undef trcKERNEL_HOOKS_INCREMENT_TICK +#define trcKERNEL_HOOKS_INCREMENT_TICK() \ + { extern uint32_t uiTraceTickCount; uiTraceTickCount++; vTracePortGetTimeStamp(0); } + +#if INCLUDE_NEW_TIME_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) \ + vTraceStoreKernelCallWithNumericParamOnly(SERVICE, xValue); +#else +#undef trcKERNEL_HOOKS_NEW_TIME +#define trcKERNEL_HOOKS_NEW_TIME(SERVICE, xValue) +#endif - /* Called in vTaskResumeFromISR */ - #undef traceTASK_RESUME_FROM_ISR - #define traceTASK_RESUME_FROM_ISR( pxTaskToResume )\ - vTraceStoreKernelCall(TASK_RESUME_FROM_ISR, TRACE_CLASS_TASK, pxTaskToResume->uxTaskNumber); +/* This macro will create a task switch event to the currently executing task */ +#undef trcKERNEL_HOOKS_TASK_SWITCH +#define trcKERNEL_HOOKS_TASK_SWITCH( pxTCB ) \ + vTraceStoreTaskswitch(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) \ + vTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); \ + vTraceSetTaskInstanceFinished((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) \ + vTraceStoreKernelCallWithNumericParamOnly(SERVICE, xValue); \ + vTraceSetTaskInstanceFinished((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) \ + vTraceStoreKernelCallWithParam(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB), uiTraceGetPriorityProperty(TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)));\ + vTraceSetPriorityProperty(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) \ + vTraceStoreKernelCall(SERVICE, TRACE_CLASS_TASK, TRACE_GET_TASK_NUMBER(pxTCB)); #endif -#endif + +#endif /* TRCKERNELHOOKS_H */ diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h index c81db92e1..709e128c9 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcKernel.h @@ -1,64 +1,61 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * * trcKernel.h * - * Functions used by trcHooks.h, for the FreeRTOS kernel integration. + * Functions used by trcKernelHooks.h. * * 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 + * in its original form, including modifications in trcHardwarePort.c/.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 + * 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 + * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ #ifndef TRCKERNEL_H #define TRCKERNEL_H -#include "trcBase.h" +#include "trcKernelPort.h" -/* Internal functions */ +#if (USE_TRACEALYZER_RECORDER == 1) +/* Internal functions */ #if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1 void vTraceStoreTaskReady(objectHandleType handle); #endif -void vTraceStoreTaskswitch(void); +void vTraceStoreTaskswitch(objectHandleType task_handle); -void vTraceStoreKernelCall(uint32_t eventcode, traceObjectClass objectClass, uint32_t byteParam); +void vTraceStoreKernelCall(uint32_t eventcode, traceObjectClass objectClass, uint32_t byteParam); -void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, - uint16_t param); +void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, + uint32_t param); -void vTraceStoreKernelCallWithParam(uint32_t evtcode, traceObjectClass objectClass, +void vTraceStoreKernelCallWithParam(uint32_t evtcode, traceObjectClass objectClass, uint32_t objectNumber, uint8_t param); void vTraceSetTaskInstanceFinished(objectHandleType handle); @@ -71,12 +68,12 @@ void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value); uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id); -#if (INCLUDE_OBJECT_DELETE == 1) +#if (INCLUDE_OBJECT_DELETE == 1) -void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, +void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, traceObjectClass objectclass); -void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, +void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, traceObjectClass objectclass); #endif @@ -85,190 +82,7 @@ void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, #define TASK_STATE_INSTANCE_ACTIVE 1 #define TASK_STATE_INSTANCE_MARKED_FINISHED 2 -extern objectHandleType handle_of_running_task; - -/* This defines the mapping between FreeRTOS queue types and our internal -class IDs */ -extern traceObjectClass TraceObjectClassTable[5]; - -/******************************************************************************* - * The event codes - should match the offline config file. - * - * Some sections below are encoded to allow for constructions like: - * - * vTraceStoreKernelCall(EVENTGROUP_CREATE + objectclass, ... - * - * The object class ID is given by the three LSB bits, in such cases. Since each - * object class has a separate object property table, the class ID is needed to - * know what section in the object table to use for getting an object name from - * an object handle. - ******************************************************************************/ - -#define NULL_EVENT (0x00) /* Ignored in the analysis*/ - -/******************************************************************************* - * EVENTGROUP_RE - * - * Events that indicate that something is ready to execute. - ******************************************************************************/ -#define EVENTGROUP_RE (NULL_EVENT + 2) /*0x02*/ -#define TR_TASK_READY (EVENTGROUP_RE + 0) /*0x02*/ - -/******************************************************************************* - * EVENTGROUP_TS - * - * Events for storing task-switches and interrupts. The RESUME events are - * generated if the task/interrupt is already marked active. - ******************************************************************************/ -#define EVENTGROUP_TS (EVENTGROUP_RE + 2) /*0x04*/ -#define TS_ISR_BEGIN (EVENTGROUP_TS + 0) /*0x04*/ -#define TS_ISR_RESUME (EVENTGROUP_TS + 1) /*0x05*/ -#define TS_TASK_BEGIN (EVENTGROUP_TS + 2) /*0x06*/ -#define TS_TASK_RESUME (EVENTGROUP_TS + 3) /*0x07*/ - -/******************************************************************************* - * EVENTGROUP_OBJCLOSE_NAME - * - * About Close Events - * When an object is evicted from the object property table (object close), two - * internal events are stored (EVENTGROUP_OBJCLOSE_NAME and - * EVENTGROUP_OBJCLOSE_PROP), containg the handle-name mapping and object - * properties valid up to this point. - ******************************************************************************/ -#define EVENTGROUP_OBJCLOSE_NAME (EVENTGROUP_TS + 4) /*0x08*/ - -/******************************************************************************* - * EVENTGROUP_OBJCLOSE_PROP - * - * The internal event carrying properties of deleted objects - * The handle and object class of the closed object is not stored in this event, - * but is assumed to be the same as in the preceeding CLOSE event. Thus, these - * two events must be generated from within a critical section. - * When queues are closed, arg1 is the "state" property (i.e., number of - * buffered messages/signals). - * When actors are closed, arg1 is priority, arg2 is handle of the "instance - * finish" event, and arg3 is event code of the "instance finish" event. - * In this case, the lower three bits is the object class of the instance finish - * handle. The lower three bits are not used (always zero) when queues are - * closed since the queue type is given in the previous OBJCLOSE_NAME event. - ******************************************************************************/ -#define EVENTGROUP_OBJCLOSE_PROP (EVENTGROUP_OBJCLOSE_NAME + 8) /*0x10*/ - -/******************************************************************************* - * EVENTGROUP_CREATE - * - * The events in this group are used to log Kernel object creations. - * The lower three bits in the event code gives the object class, i.e., type of - * create operation (task, queue, semaphore, etc). - ******************************************************************************/ -#define EVENTGROUP_CREATE (EVENTGROUP_OBJCLOSE_PROP + 8) /*0x18*/ - -/******************************************************************************* - * EVENTGROUP_SEND - * - * The events in this group are used to log Send/Give events on queues, - * semaphores and mutexeds The lower three bits in the event code gives the - * object class, i.e., what type of object that is operated on (queue, semaphore - * or mutex). - ******************************************************************************/ -#define EVENTGROUP_SEND (EVENTGROUP_CREATE + 8) /*0x20*/ - -/******************************************************************************* - * EVENTGROUP_RECEIVE - * - * The events in this group are used to log Receive/Take events on queues, - * semaphores and mutexes. The lower three bits in the event code gives the - * object class, i.e., what type of object that is operated on (queue, semaphore - * or mutex). - ******************************************************************************/ -#define EVENTGROUP_RECEIVE (EVENTGROUP_SEND + 8) /*0x28*/ - -/* Send/Give operations, from ISR */ -#define EVENTGROUP_SEND_FROM_ISR (EVENTGROUP_RECEIVE + 8) /*0x30*/ - -/* Receive/Take operations, from ISR */ -#define EVENTGROUP_RECEIVE_FROM_ISR (EVENTGROUP_SEND_FROM_ISR + 8) /*0x38*/ - -/* "Failed" event type versions of above (timeout, failed allocation, etc) */ -#define EVENTGROUP_FAILED_KSE (EVENTGROUP_RECEIVE_FROM_ISR + 8) /*0x40*/ - -/* Failed create calls - memory allocation failed */ -#define EVENTGROUP_FAILED_CREATE (EVENTGROUP_FAILED_KSE) /*0x40*/ - -/* Failed send/give - timeout! */ -#define EVENTGROUP_FAILED_SEND (EVENTGROUP_FAILED_CREATE + 8) /*0x48*/ - -/* Failed receive/take - timeout! */ -#define EVENTGROUP_FAILED_RECEIVE (EVENTGROUP_FAILED_SEND + 8) /*0x50*/ - -/* Failed non-blocking send/give - queue full */ -#define EVENTGROUP_FAILED_SEND_FROM_ISR (EVENTGROUP_FAILED_RECEIVE + 8) /*0x58*/ - -/* Failed non-blocking receive/take - queue empty */ -#define EVENTGROUP_FAILED_RECEIVE_FROM_ISR \ - (EVENTGROUP_FAILED_SEND_FROM_ISR + 8) /*0x60*/ - -/* Events when blocking on receive/take */ -#define EVENTGROUP_BLOCK_ON_RECEIVE \ - (EVENTGROUP_FAILED_RECEIVE_FROM_ISR + 8) /*0x68*/ - -/* Events when blocking on send/give */ -#define EVENTGROUP_BLOCK_ON_SEND (EVENTGROUP_BLOCK_ON_RECEIVE + 8) /*0x70*/ - -/* Events on queue peek (receive) */ -#define EVENTGROUP_PEEK (EVENTGROUP_BLOCK_ON_SEND + 8) /*0x78*/ - -/* Events on object delete (vTaskDelete or vQueueDelete) */ -#define EVENTGROUP_DELETE (EVENTGROUP_PEEK + 8) /*0x80*/ - -/* Other events - object class is implied: TASK */ -#define EVENTGROUP_OTHERS (EVENTGROUP_DELETE + 8) /*0x88*/ -#define TASK_DELAY_UNTIL (EVENTGROUP_OTHERS + 0) /*0x88*/ -#define TASK_DELAY (EVENTGROUP_OTHERS + 1) /*0x89*/ -#define TASK_SUSPEND (EVENTGROUP_OTHERS + 2) /*0x8A*/ -#define TASK_RESUME (EVENTGROUP_OTHERS + 3) /*0x8B*/ -#define TASK_RESUME_FROM_ISR (EVENTGROUP_OTHERS + 4) /*0x8C*/ -#define TASK_PRIORITY_SET (EVENTGROUP_OTHERS + 5) /*0x8D*/ -#define TASK_PRIORITY_INHERIT (EVENTGROUP_OTHERS + 6) /*0x8E*/ -#define TASK_PRIORITY_DISINHERIT (EVENTGROUP_OTHERS + 7) /*0x8F*/ - -/* Not yet used */ -#define EVENTGROUP_FTRACE_PLACEHOLDER (EVENTGROUP_OTHERS + 8) /*0x90*/ - -/* User events */ -#define EVENTGROUP_USEREVENT (EVENTGROUP_FTRACE_PLACEHOLDER + 8) /*0x98*/ -#define USER_EVENT (EVENTGROUP_USEREVENT + 0) - -/* Allow for 0-15 arguments (the number of args is added to event code) */ -#define USER_EVENT_LAST (EVENTGROUP_USEREVENT + 15) /*0xA7*/ - -/******************************************************************************* - * XTS Event - eXtended TimeStamp events - * The timestamps used in the recorder are "differential timestamps" (DTS), i.e. - * the time since the last stored event. The DTS fields are either 1 or 2 bytes - * in the other events, depending on the bytes available in the event struct. - * If the time since the last event (the DTS) is larger than allowed for by - * the DTS field of the current event, an XTS event is inserted immidiatly - * before the original event. The XTS event contains up to 3 additional bytes - * of the DTS value - the higher bytes of the true DTS value. The lower 1-2 - * bytes are stored in the normal DTS field. - * There are two types of XTS events, XTS8 and XTS16. An XTS8 event is stored - * when there is only room for 1 byte (8 bit) DTS data in the original event, - * which means a limit of 0xFF (255). The XTS16 is used when the original event - * has a 16 bit DTS field and thereby can handle values up to 0xFFFF (65535). - * - * Using a very high frequency time base can result in many XTS events. - * Preferably, the time between two OS ticks should fit in 16 bits, i.e., - * at most 65535. If your time base has a higher frequency, you can define - * the TRACE - ******************************************************************************/ - -#define EVENTGROUP_SYS (EVENTGROUP_USEREVENT + 16) /*0xA8*/ -#define XTS8 (EVENTGROUP_SYS + 0) /*0xA8*/ -#define XTS16 (EVENTGROUP_SYS + 1) /*0xA9*/ - -#define EVENT_BEING_WRITTEN (EVENTGROUP_SYS + 2) /*0xAA*/ - -#define RESERVED_DUMMY_CODE (EVENTGROUP_SYS + 3) /*0xAB*/ #endif + +#endif \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h index 7bf438c8b..a01791216 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcTypes.h @@ -1,5 +1,5 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * * trcTypes.h @@ -9,7 +9,7 @@ * 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 + * in its original form, including modifications in trcHardwarePort.c/.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 @@ -31,11 +31,7 @@ * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ @@ -46,36 +42,10 @@ typedef uint16_t traceLabel; +typedef uint8_t UserEventChannel; + typedef uint8_t objectHandleType; typedef uint8_t traceObjectClass; -#define TRACE_CLASS_QUEUE ((traceObjectClass)0) -#define TRACE_CLASS_SEMAPHORE ((traceObjectClass)1) -#define TRACE_CLASS_MUTEX ((traceObjectClass)2) -#define TRACE_CLASS_TASK ((traceObjectClass)3) -#define TRACE_CLASS_ISR ((traceObjectClass)4) - -typedef uint8_t traceKernelService; - -#define TRACE_KERNEL_SERVICE_TASK_CREATE ((traceKernelService)0) -#define TRACE_KERNEL_SERVICE_TASK_DELETE ((traceKernelService)1) -#define TRACE_KERNEL_SERVICE_TASK_DELAY ((traceKernelService)2) -#define TRACE_KERNEL_SERVICE_PRIORITY_SET ((traceKernelService)3) -#define TRACE_KERNEL_SERVICE_TASK_SUSPEND ((traceKernelService)4) -#define TRACE_KERNEL_SERVICE_TASK_RESUME ((traceKernelService)5) -#define TRACE_KERNEL_SERVICE_QUEUE_CREATE ((traceKernelService)6) -#define TRACE_KERNEL_SERVICE_QUEUE_DELETE ((traceKernelService)7) -#define TRACE_KERNEL_SERVICE_QUEUE_SEND ((traceKernelService)8) -#define TRACE_KERNEL_SERVICE_QUEUE_RECEIVE ((traceKernelService)9) -#define TRACE_KERNEL_SERVICE_QUEUE_PEEK ((traceKernelService)10) -#define TRACE_KERNEL_SERVICE_MUTEX_CREATE ((traceKernelService)11) -#define TRACE_KERNEL_SERVICE_MUTEX_DELETE ((traceKernelService)12) -#define TRACE_KERNEL_SERVICE_MUTEX_GIVE ((traceKernelService)13) -#define TRACE_KERNEL_SERVICE_MUTEX_TAKE ((traceKernelService)14) -#define TRACE_KERNEL_SERVICE_SEMAPHORE_CREATE ((traceKernelService)15) -#define TRACE_KERNEL_SERVICE_SEMAPHORE_DELETE ((traceKernelService)16) -#define TRACE_KERNEL_SERVICE_SEMAPHORE_GIVE ((traceKernelService)17) -#define TRACE_KERNEL_SERVICE_SEMAPHORE_TAKE ((traceKernelService)18) - #endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h index 3e80162fa..273e87074 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/Include/trcUser.h @@ -1,5 +1,5 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * * trcUser.h @@ -8,72 +8,103 @@ * 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 + * in its original form, including modifications in trcHardwarePort.c/.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 + * 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 + * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ #ifndef TRCUSER_H #define TRCUSER_H -#include "FreeRTOS.h" +#ifdef __cplusplus +extern "C" { +#endif + +#include "trcKernelPort.h" -#include "trcKernel.h" +#if (USE_TRACEALYZER_RECORDER == 1) -#if (configUSE_TRACE_FACILITY == 1) +#ifndef USE_SEPARATE_USER_EVENT_BUFFER +#define USE_SEPARATE_USER_EVENT_BUFFER 0 +#endif -#ifdef __cplusplus -extern "C" { +/******************************************************************************* + * 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. + ******************************************************************************/ +typedef void (*TRACE_STOP_HOOK)(void); + +/******************************************************************************* + * vTraceStopHookPtr + * + * Points to a call back function that is called from vTraceStop(). + ******************************************************************************/ +extern TRACE_STOP_HOOK vTraceStopHookPtr; + +/******************************************************************************* + * vTraceInitTraceData + * + * Allocates, if necessary, and initializes the recorder data structure, based + * on the constants in trcConfig.h. + ******************************************************************************/ +void vTraceInitTraceData(void); + +/******************************************************************************* + * vTraceSetRecorderData + * + * If custom allocation is used, this function must be called so the recorder + * library knows where to save the trace data. + ******************************************************************************/ +#if (TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_CUSTOM) +void vTraceSetRecorderData(void* pRecorderData); #endif /******************************************************************************* * uiTraceStart * * Starts the recorder. The recorder will not be started if an error has been - * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h + * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h * has a too small value (NTASK, NQUEUE, etc). - * + * * Returns 1 if the recorder was started successfully. - * Returns 0 if the recorder start was prevented due to a previous internal + * Returns 0 if the recorder start was prevented due to a previous internal * error. In that case, check vTraceGetLastError to get the error message. - * Any error message is also presented when opening a trace file in - * FreeRTOS+Trace v2.2.2 or later. + * Any error message is also presented when opening a trace file. + * ******************************************************************************/ uint32_t uiTraceStart(void); /******************************************************************************* - * vTraceStart + * vTraceStart * * Starts the recorder. The recorder will not be started if an error has been - * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h + * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h * has a too small value (NTASK, NQUEUE, etc). - * - * This function is obsolete, but has been saved for backwards compatibility. + * + * This function is obsolete, but has been saved for backwards compatibility. * We recommend using uiTraceStart instead. ******************************************************************************/ void vTraceStart(void); @@ -81,12 +112,12 @@ void vTraceStart(void); /******************************************************************************* * vTraceStartStatusMonitor * - * This starts a task to monitor the status of the recorder module. - * This task periodically prints a line to the console window, which shows the - * recorder status, the number of events recorded and the latest timestamp. - * This task calls vTracePortEnd (trcPort.c) when it detects that the recorder - * has been stopped. This allows for adding custom actions, e.g., to store the - * trace to a file in case a file system is available on the device. + * This starts a task to monitor the status of the recorder module. + * This task periodically prints a line to the console window, which shows the + * recorder status, the number of events recorded and the latest timestamp. + * This task calls vTracePortEnd (trcHardwarePort.c) when it detects that the + * recorder has been stopped. This allows for adding custom actions, e.g., to + * store the trace to a file in case a file system is available on the device. ******************************************************************************/ void vTraceStartStatusMonitor(void); @@ -101,33 +132,19 @@ void vTraceStop(void); /******************************************************************************* * vTraceClear * - * Resets the recorder. Only necessary if a restart is desired - this is not + * Resets the recorder. Only necessary if a restart is desired - this is not * needed in the startup initialization. ******************************************************************************/ void vTraceClear(void); -/******************************************************************************* - * vTraceSetQueueName - * - * Assigns a name to a FreeRTOS Queue, Semaphore or Mutex. This function should - * be called right after creation of the queue/mutex/semaphore. If not using - * this function, the queues/mutexes/semaphores will be presented by their - * numeric handle only. - * - * Example: - * actuatorQ = xQueueCreate(3, sizeof(QueueMessage)); - * vTraceSetQueueName(actuatorQ, "ActuatorQueue"); - ******************************************************************************/ -void vTraceSetQueueName(void* queue, const char* name); - #if (INCLUDE_ISR_TRACING == 1) /******************************************************************************* * vTraceSetISRProperties - * + * * Registers an Interrupt Service Routine in the recorder library, This must be - * called before using vTraceStoreISRBegin to store ISR events. This is - * typically called in the startup of the system, before the scheduler is + * called before using vTraceStoreISRBegin to store ISR events. This is + * typically called in the startup of the system, before the scheduler is * started. * * Example: @@ -151,18 +168,9 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio /******************************************************************************* * vTraceStoreISRBegin - * - * Registers the beginning of an Interrupt Service Routine. * - * Note! This may only be used for interrupts affected by portENTER_CRITICAL. - * In some FreeRTOS ports, such as ARM Cortex M3, this does not disable all - * interrupts. Interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY are still - * enabled, but may not call the FreeRTOS API. Such may not call the recorder - * API, including this function. - * - * See http://www.freertos.org/a00110.html - * - * If allowing nested ISRs, this must be called with interrupts disabled. + * Registers the beginning of an Interrupt Service Routine. + * If allowing nested ISRs, this must be called with interrupts disabled. * * Example: * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 @@ -180,23 +188,16 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio * vTraceStoreISREnd(); * portEXIT_CRITICAL(); * } + * ******************************************************************************/ void vTraceStoreISRBegin(objectHandleType id); /******************************************************************************* * vTraceStoreISREnd - * - * Registers the end of an Interrupt Service Routine. * - * Note! This may only be used for interrupts affected by portENTER_CRITICAL. - * In some FreeRTOS ports, such as ARM Cortex M3, this does not disable all - * interrupts. Interrupts above configMAX_SYSCALL_INTERRUPT_PRIORITY are still - * enabled, but may not call the FreeRTOS API. Such may not call the recorder - * API, including this function. + * Registers the end of an Interrupt Service Routine. * - * See http://www.freertos.org/a00110.html - * - * If allowing nested ISRs, this must be called with interrupts disabled. + * If allowing nested ISRs, this must be called with interrupts disabled. * * Example: * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 @@ -214,6 +215,7 @@ void vTraceStoreISRBegin(objectHandleType id); * vTraceStoreISREnd(); * portEXIT_CRITICAL(); * } + * ******************************************************************************/ void vTraceStoreISREnd(void); @@ -233,41 +235,41 @@ void vTraceDecreaseISRActive(void); /******************************************************************************* * vvTraceTaskSkipDefaultInstanceFinishedEvents * - * This is useful if there are implicit Instance Finish Events, such as - * vTaskDelayUntil or xQueueReceive, in a task where an explicit Instance Finish - * Event has been defined. This function tells the recorder that only the + * This is useful if there are implicit Instance Finish Events, such as + * vTaskDelayUntil or xQueueReceive, in a task where an explicit Instance Finish + * Event has been defined. This function tells the recorder that only the * explicitly defined functions (using vTraceTaskInstanceIsFinished) should be - * treated as Instance Finish Events for this task. The implicit Instance Finish + * treated as Instance Finish Events for this task. The implicit Instance Finish * Events are thus disregarded for this task. ******************************************************************************/ void vTraceTaskSkipDefaultInstanceFinishedEvents(void); /******************************************************************************* * vTraceTaskInstanceIsFinished - * - * This defines an explicit Instance Finish Event for the current task. It tells - * the recorder that the current instance of this task is finished at the next - * kernel call of the task, e.g., a taskDelay or a queue receive. This function - * should be called right before the api function call considered to be the end + * + * This defines an explicit Instance Finish Event for the current task. It tells + * the recorder that the current instance of this task is finished at the next + * kernel call of the task, e.g., a taskDelay or a queue receive. This function + * should be called right before the api function call considered to be the end * of the task instamce, i.e., the Instance Finish Event. ******************************************************************************/ void vTraceTaskInstanceIsFinished(void); /******************************************************************************* * vTraceGetTraceBuffer - * - * 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 + * + * 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* vTraceGetTraceBuffer(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, + * + * 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); @@ -276,14 +278,14 @@ uint32_t uiTraceGetTraceBufferSize(void); /******************************************************************************* * xTraceOpenLabel - * + * * Creates user event labels for user event channels or for individual events. * User events can be used to log application events and data for display in * the visualization tool. A user event is identified by a label, i.e., a string, * which is stored in the recorder's symbol table. * When logging a user event, a numeric handle (reference) to this string is - * used to identify the event. This is obtained by calling - * + * used to identify the event. This is obtained by calling + * * xTraceOpenLabel() * * whihc adds the string to the symbol table (if not already present) @@ -304,7 +306,7 @@ uint32_t uiTraceGetTraceBufferSize(void); * ... * vTraceUserEvent(myEventHandle); * - * The second option is faster since no lookup is required on each event, and + * The second option is faster since no lookup is required on each event, and * therefore recommended for user events that are frequently * executed and/or located in time-critical code. The lookup operation is * however fairly fast due to the design of the symbol table. @@ -315,40 +317,40 @@ traceLabel xTraceOpenLabel(const char* label); * vTraceUserEvent * * Basic user event (Standard and Professional Edition only) - * + * * Generates a User Event with a text label. The label is created/looked up * in the symbol table using xTraceOpenLabel. ******************************************************************************/ void vTraceUserEvent(traceLabel eventLabel); /****************************************************************************** - * vTracePrintF - * + * vTracePrintF + * * Advanced user events (Professional Edition only) * * Generates User Event with formatted text and data, similar to a "printf". - * It is very fast compared to a normal "printf" since this function only + * It is very fast compared to a normal "printf" since this function only * stores the arguments. The actual formatting is done - * on the host PC when the trace is displayed in the viewer tool. + * on the host PC when the trace is displayed in the viewer tool. * * User Event labels are created using xTraceOpenLabel. * Example: * * traceLabel adc_uechannel = xTraceOpenLabel("ADC User Events"); * ... - * vTracePrint(adc_uechannel, - * "ADC channel %d: %lf volts", + * vTracePrint(adc_uechannel, + * "ADC channel %d: %lf volts", * ch, (double)adc_reading/(double)scale); * * This can be combined into one line, if desired, but this is slower: * - * vTracePrint(xTraceOpenLabel("ADC User Events"), - * "ADC channel %d: %lf volts", + * vTracePrint(xTraceOpenLabel("ADC User Events"), + * "ADC channel %d: %lf volts", * ch, (double)adc_reading/(double)scale); * * Calling xTraceOpenLabel multiple times will not create duplicate entries, but - * it is of course faster to just do it once, and then keep the handle for later - * use. If you don´t have any data arguments, only a text label/string, it is + * it is of course faster to just do it once, and then keep the handle for later + * use. If you don´t have any data arguments, only a text label/string, it is * better to use vTraceUserEvent - it is faster. * * Format specifiers supported: @@ -361,84 +363,62 @@ void vTraceUserEvent(traceLabel eventLabel); * %bd - 8 bit signed integer * %bu - 8 bit unsigned integer * %lf - double-precision float (Note! See below...) - * + * * Up to 15 data arguments are allowed, with a total size of maximum 32 byte. * In case this is exceeded, the user event is changed into an error message. - * - * The data is stored in trace buffer, and is packed to allow storing multiple + * + * The data is stored in trace buffer, and is packed to allow storing multiple * smaller data entries in the same 4-byte record, e.g., four 8-bit values. - * A string requires two bytes, as the symbol table is limited to 64K. Storing - * a double (%lf) uses two records, so this is quite costly. Use float (%f) + * A string requires two bytes, as the symbol table is limited to 64K. Storing + * a double (%lf) uses two records, so this is quite costly. Use float (%f) * unless the higher precision is really necessary. - * - * Note that the double-precision float (%lf) assumes a 64 bit double - * representation. This does not seem to be the case on e.g. PIC24F. - * Before using a %lf argument on a 16-bit MCU, please verify that + * + * Note that the double-precision float (%lf) assumes a 64 bit double + * representation. This does not seem to be the case on e.g. PIC24F. + * Before using a %lf argument on a 16-bit MCU, please verify that * "sizeof(double)" actually gives 8 as expected. If not, use %f instead. - ******************************************************************************/ + ******************************************************************************/ void vTracePrintF(traceLabel eventLabel, const char* formatStr, ...); +#if (USE_SEPARATE_USER_EVENT_BUFFER == 1) +UserEventChannel xTraceRegisterChannelFormat(traceLabel channel, traceLabel formatStr); +void vTraceChannelPrintF(UserEventChannel channel, ...); +void vTraceChannelUserEvent(UserEventChannel channel); +#endif + #else #define vTracePrintF(eventLabel, formatStr, ...); #define xTraceOpenLabel(label) 0 -#define vTraceUserEvent(eventLabel) - -#endif - -/****************************************************************************** - * vTraceExclude______FromTrace - * - * Excludes a task or object from the trace. - * This can be useful if some irrelevant task is very frequent and is "eating - * up the buffer". This should be called after the task has been created, but - * before starting the FreeRTOS scheduler. - *****************************************************************************/ -void vTraceExcludeQueueFromTrace(void* handle); -void vTraceExcludeSemaphoreFromTrace(void* handle); -void vTraceExcludeMutexFromTrace(void* handle); -void vTraceExcludeTaskFromTrace(void* handle); -void vTraceExcludeKernelServiceFromTrace(traceKernelService kernelService); - -/****************************************************************************** - * vTraceInclude______InTrace - * - * Includes a task, object or kernel service in the trace. This is only - * necessary if the task or object has been previously exluded. - *****************************************************************************/ -void vTraceIncludeQueueInTrace(void* handle); -void vTraceIncludeSemaphoreInTrace(void* handle); -void vTraceIncludeMutexInTrace(void* handle); -void vTraceIncludeTaskInTrace(void* handle); -void vTraceIncludeKernelServiceInTrace(traceKernelService kernelService); +#define vTraceUserEvent(eventLabel) -#ifdef __cplusplus -} #endif #else -#include "trcPort.h" +/* Empty defines for user functions to avoid compiler errors if trace is not to be used */ -#define vTraceInit() -#define uiTraceStart() (1) +#define vTraceInitTraceData() +#define uiTraceStart() (1) // Fake "success", if used when recorder is excluded from build #define vTraceStart() #define vTraceStop() #define vTraceClear() #define vTraceStartStatusMonitor() -#define vTracePortSetOutFile(f) #define vTraceGetTraceBuffer() ((void*)0) #define uiTraceGetTraceBufferSize() 0 #define xTraceOpenLabel(label) 0 #define vTraceUserEvent(eventLabel) #define vTracePrintF(eventLabel,formatStr,...) #define vTraceExcludeTaskFromSchedulingTrace(name) -#define vTraceSetQueueName(queue, name) #define vTraceTaskSkipDefaultInstanceFinishedEvents() #define vTraceSetISRProperties(handle, name, priority) #define vTraceStoreISRBegin(id) #define vTraceStoreISREnd() #endif + +#ifdef __cplusplus +} #endif +#endif diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/debugger trace upload.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/debugger trace upload.txt index 417a54bb7..f815e8b21 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/debugger trace upload.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/debugger trace upload.txt @@ -1,24 +1,28 @@ -FreeRTOS+Trace - Uploading the trace data +Tracealyzer - Uploading the trace data ----------------------------------------- Percepio AB, Nov. 8, 2012 This document decribes how to upload the trace data from the target system to -FreeRTOS+Trace. For information on how to integrate and enable the recorder -library in your FreeRTOS project, see the FreeRTOS+Trace User Manual. +Tracealyzer. -FreeRTOS+Trace uses your existing debugger to upload the trace data from the +Tracealyzer uses your existing debugger to upload the trace data from the chip RAM. This is a plain RAM dump, that is done whenever you want to look at the trace buffer contents. This means it works with essentially with any debug probe on the market. -Note that hardware-generated trace is not required (or used by) FreeRTOS+Trace. -We however plan to add support for that in future versions of FreeRTOS+Trace +If the device has a file system and some possibility of accessing this file +system from the development PC, it is also possible to write the recorder data +to a file, using vTraceGetTraceBuffer() and uiTraceGetTraceBufferSize() +found in trcUser.h/.c. + +Note that hardware-generated trace is not required (or used by) Tracealyzer. +We however plan to add support for that in future versions of Tracealyzer and other Tracealyzer products. Built-in support for Segger J-Link/J-Trace and Atmel SAM-ICE ------------------------------------------------------------ -FreeRTOS+Trace v2.3 supports Segger J-Link and J-Link compatible debuggers +Tracealyzer v2.3 supports Segger J-Link and J-Link compatible debuggers directly, without any debugger IDE involved. Using other debug probes is also possible, but requires some extra steps, described below. @@ -36,7 +40,7 @@ can be found can by inspecting the "RecorderData" struct or the Typical values are 0x0, 0x10000000 or 0x20000000 as start address and 0x10000 or 0x20000 as size (64 KB or 128 KB). -This makes FreeRTOS+Trace reads the chip RAM and locate the trace data. +This makes Tracealyzer reads the chip RAM and locate the trace data. Note that this option is only available if a compatible debug probe is found. J-Link compatible debug probes also include Atmel SAM-ICE and many built-in @@ -46,17 +50,17 @@ connection directly to the board). Look for a Segger J-Link label on the board. MemoryLogger extension in Atmel Studio 6 ---------------------------------------- Atmel's new MemoryLogger extension provides a superb integration with -FreeRTOS+Trace. Look for "MemoryLogger" in Atmel Gallery, available in +Tracealyzer. Look for "MemoryLogger" in Atmel Gallery, available in Atmel Studio and at the Atmel website. -This extension automatically detects the path to FreeRTOS+Trace, if +This extension automatically detects the path to Tracealyzer, if installed, and gives you a single-click upload/refresh. You can use it while debugging and optionally get an automatic refresh eash time the MCU is halted, e.g., on each breakpoint. Using other development environments and debug probes ----------------------------------------------------- -Most debuggers are able to save the RAM contents to a file. FreeRTOS+Trace +Most debuggers are able to save the RAM contents to a file. Tracealyzer supports the following common formats: - Binary (.bin), supporting gdb, J-Link and Renesas HEW. - Intel Hex (.hex), supporting IAR Embedded Workbench and Atmel Studio (atprogram.exe) @@ -66,7 +70,7 @@ When you store the RAM dump, you must also make sure to select the right region, i.e., start address and size. The recorder data is stored in a single data block, identified by the pointer RecorderDataPtr. It is not necessary to match the begin and end of the recorder data, as long as -it is fully included by the dumped memory region. FreeRTOS+Trace automatically +it is fully included by the dumped memory region. Tracealyzer automatically finds the trace data in the RAM dump, thanks to special signatures. For chips with on-chip RAM only, we therefore recommend to dump the entire RAM. This is usually very fast. @@ -84,7 +88,7 @@ In the debugger view, when stopped on a breakpoint: - File format: Intel Extended - Filename: .hex - Press "Save" button -You can now open .hex in FreeRTOS+Trace. +You can now open .hex in Tracealyzer. To find the right Start and End addresses, check the address of the symbol "RecorderData". The addresses does not need to match this symbol exactly, as @@ -100,7 +104,7 @@ In the debugger view, when stopped on a breakpoint: - Start Address: 00000000 (For RX62N in the demo project) - End Address: 0000FFFF (For RX62N in the demo project) - Access size: 1 - - Press "Save" button and open .bin in FreeRTOS+Trace. + - Press "Save" button and open .bin in Tracealyzer. Using Microchip MPLAB v8.86 ------------------------------------------------------ @@ -110,7 +114,7 @@ Using Microchip MPLAB v8.86 - In the dialog ("Export As"), make sure "Single Column Output" is selected (seems to be default). - Select start address 0x0000 and make sure the end address is beyond the RecorderData structure. The default values seems to be the whole RAM, so you probably don't need to change this. -- Save as a .mch file and open this file in FreeRTOS+Trace v2.2.4 or later (support for the .mch format was added in v2.2.4). +- Save as a .mch file and open this file in Tracealyzer v2.2.4 or later (support for the .mch format was added in v2.2.4). Using STM32 ST-Link ------------------------------------------------------ @@ -118,7 +122,7 @@ Using STM32 ST-Link - Connect to the device and view the device memory. - Set the view to display the entire RAM, or at least the section containing the RecorderData structure. - Select "Save as" and choose binary (.bin) or Intel Hex (.hex) format. -- Open the resulting file in FreeRTOS+Trace. +- Open the resulting file in Tracealyzer. In case you have any question, contact support@percepio.com diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt index 0553c8bd1..d8337b1a8 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/readme.txt @@ -1,20 +1,13 @@ -FreeRTOS+Trace Trace Recorder Library +Tracealyzer Trace Recorder Library ------------------------------------- Percepio AB www.percepio.com -This directory contains the core trace recorder library used by FreeRTOS+Trace v2.3. - -Ready-to-run demonstrations projects are found at www.percepio.com. - -For information on how to integrate the recorder library in your FreeRTOS build, see -the FreeRTOS+Trace User Manual, section 2. +This directory contains the a generic trace recorder library for Tracealyzer v2.4. For information on how to upload the trace data from your target system RAM to -FreeRTOS+Trace, see "debugger trace upload.txt" - -NOTE: This trace recorder library requires FreeRTOS v7.3.0 or later. +Tracealyzer, see "debugger trace upload.txt" Files included -------------- @@ -22,8 +15,9 @@ Files included - trcUser.c / trcUser.h - The main API towards the application (trcUser.h in the only include necessary). - trcKernel.c / trcKernel.h - Internal routines for storing kernel events. - trcBase.c / trcBase.h - Internal routines for manipulating the data structures and calculating timestamps. -- trcPort.c / trcPort.h - The port layer, abstracting the hardware (mainly the timer used for timestamping). -- trcHooks.h - The interface between FreeRTOS and the recorder, containing trace macro defintions. +- trcHardwarePort.c / trcHardwarePort.h - The port layer, abstracting the hardware (mainly the timer used for timestamping). +- trcKernelHooks.h - The interface between the Kernel and the recorder, containing trace macro defintions. +- trcKernelPort.h - Kernel specific implementations of macros and data. - trcTypes.h - Type definitions used. Hardware Timer Ports diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c index c80915cc9..67f34bc33 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcBase.c @@ -1,5 +1,5 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * * trcBase.c @@ -9,70 +9,75 @@ * 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 + * in its original form, including modifications in trcHardwarePort.c/.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 + * 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 + * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ -#include "trcUser.h" -#include "task.h" +#include "trcBase.h" + +#if (USE_TRACEALYZER_RECORDER == 1) -#if (configUSE_TRACE_FACILITY == 1) +#include /******************************************************************************* * Static data initializations ******************************************************************************/ +/* Structure to handle the exclude flags for all objects and tasks. We add some extra objects since index 0 is not used for each object class. */ +uint8_t excludedObjects[(TRACE_KERNEL_OBJECT_COUNT + TRACE_NCLASSES) / 8 + 1] = { 0 }; + +/* Structure to handle the exclude flags for all event codes */ +uint8_t excludedEventCodes[NEventCodes / 8 + 1] = { 0 }; + +/* Keeps track of available handles */ +objectHandleStackType objectHandleStacks = { { 0 }, { 0 }, { 0 }, { 0 }, { 0 } }; /******************************************************************************* * RecorderData * - * The main data structure. This is the data read by FreeRTOS+Trace, typically + * The main data structure. This is the data read by Tracealyzer, typically * through a debugger RAM dump. The recorder access this through the pointer * RecorderDataPtr, to allow for dynamic memory allocation as well. * * On the NXP LPC17xx you may use the secondary RAM bank (AHB RAM) for this - * purpose. For instance, the LPC1766 has 32 KB AHB RAM which allows for + * purpose. For instance, the LPC1766 has 32 KB AHB RAM which allows for * allocating a buffer size of at least 7500 events without affecting the main * RAM. To place RecorderData in this RAM bank, use the below declaration. - * + * * #pragma location="AHB_RAM_MEMORY" * RecorderDataType RecorderData = ... - * - * This of course works for other hardware architectures with additional RAM - * banks as well, just replace "AHB_RAM_MEMORY" with the name of the right + * + * This of course works for other hardware architectures with additional RAM + * banks as well, just replace "AHB_RAM_MEMORY" with the name of the right * address section from the linker file. * * However, to keep trcBase.c portable and still have a preconfigured IAR demo - * using AHB RAM, we don't add the pragma directly in trcBase.c but in a header + * using AHB RAM, we don't add the pragma directly in trcBase.c but in a header * included where the pragma should go. This is used depending on the setting * USE_LINKER_PRAGMA, defined in trcConfig.h. - * + * * If using GCC, this is instead done by adding a "section" attribute: * * RecorderDataType RecorderData __attribute__ ((section ("name"))) = ... @@ -80,315 +85,120 @@ * Remember to replace "name" with the correct section name. ******************************************************************************/ +static void vInitStartMarkers(void); + #if (TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_STATIC) #if (USE_LINKER_PRAGMA == 1) #include "recorderdata_linker_pragma.h" #endif -RecorderDataType RecorderData = -{ - /* start marker, 12 chars */ - 0x01, 0x02, 0x03, 0x04, - 0x71, 0x72, 0x73, 0x74, - 0xF1, 0xF2, 0xF3, 0xF4, - - /* version code - also used to determine endianness */ - VERSION, - - /* minor file format version */ - MINOR_VERSION, - - /* irq priority order */ - IRQ_PRIORITY_ORDER, - - /* file size (for control) */ - sizeof(RecorderDataType), - - /* number of events stored so far */ - 0, - - /* size of events buffer (in event records, each 4 bytes) */ - EVENT_BUFFER_SIZE, - - /* next free event index (event index, not byte address) */ - 0, - /* buffer is full */ - 0, +RecorderDataType RecorderData; - /* frequency of clock user for timestamps, in Hz - should be 0 here - as this is used to indicate "not yet initialized" - this is instead - initialized on the first taskswitch event. */ - 0, - - /* the absolute timestamp of the last stored event, modulo frequency */ - 0, - - /* the number of seconds so far */ - 0, +#endif - /* is recorder active (yes = 1) - note that "close" events are always - stored to keep the name-handle mapping updated!*/ - 0, +RecorderDataType* RecorderDataPtr = NULL; - /* Generated by FreeRTOS+Trace in Team Admin mode. Otherwise this should be "". */ - TEAM_LICENSE_CODE, +/* This version of the function dynamically allocates the trace data */ +void prvTraceInitTraceData() +{ +#if TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_STATIC + RecorderDataPtr = &RecorderData; +#elif TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_DYNAMIC + RecorderDataPtr = (RecorderDataType*)TRACE_MALLOC(sizeof(RecorderDataType)); +#elif TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_CUSTOM + /* DO NOTHING */ +#endif - /* debug marker 0 */ - 0xF0F0F0F0, + TRACE_ASSERT(RecorderDataPtr != NULL, "prvTraceInitTraceData, RecorderDataPtr == NULL", ); - /* The Object Property Table - holds info of all active objects */ + if (! RecorderDataPtr) { - /* Number of object classes, also those not used */ - NCLASSES, + vTraceError("No recorder data structure allocated!"); + return; + } - /* The size in bytes of the object table byte pool */ - DynObjTableSize, + (void)memset(RecorderDataPtr, 0, sizeof(RecorderDataType)); - /* The number of slots/handles available for each class */ - { - NQueue, - NSemaphore, - NMutex, - NTask, - NISR - }, - - /* The maximum name length for each object class */ - { - NameLenQueue, - NameLenSemaphore, - NameLenMutex, - NameLenTask, - NameLenISR - }, - - /* The total length a property table entry of the class */ - { - PropertyTableSizeQueue, - PropertyTableSizeSemaphore, - PropertyTableSizeMutex, - PropertyTableSizeTask, - PropertyTableSizeISR - }, - - /* The start index of each class in the object property table */ - { - StartIndexQueue, - StartIndexSemaphore, - StartIndexMutex, - StartIndexTask, - StartIndexISR - }, - - /* the object property table - encoded in a byte array using above - definitions */ - {0} - }, - - /* debug marker 1 */ - 0xF1F1F1F1, - - /* The Symbol Table - holds all object names used since system - startup. Every string is unique, so objects with same name will share - an entry. Each name entry has four extra bytes: byte 0-1 is a link - reference in an internal linked list, used for fast lookups, byte 2-3 - holds a reference to a channel label used for vTracePrintF format - strings, and byte 4.. holds the object name, followed by a - zero-termination.*/ - { - SYMBOL_TABLE_SIZE, + RecorderDataPtr->startmarker0 = 0x00; + RecorderDataPtr->startmarker1 = 0x01; + RecorderDataPtr->startmarker2 = 0x02; + RecorderDataPtr->startmarker3 = 0x03; + RecorderDataPtr->startmarker4 = 0x70; + RecorderDataPtr->startmarker5 = 0x71; + RecorderDataPtr->startmarker6 = 0x72; + RecorderDataPtr->startmarker7 = 0x73; + RecorderDataPtr->startmarker8 = 0xF0; + RecorderDataPtr->startmarker9 = 0xF1; + RecorderDataPtr->startmarker10 = 0xF2; + RecorderDataPtr->startmarker11 = 0xF3; - /* next free index (0 is reserved to mean NULL) */ - 1, + RecorderDataPtr->version = TRACE_KERNEL_VERSION; + RecorderDataPtr->minor_version = TRACE_MINOR_VERSION; + RecorderDataPtr->irq_priority_order = IRQ_PRIORITY_ORDER; + RecorderDataPtr->filesize = sizeof(RecorderDataType); - /* the symbol table byte pool */ - {0}, + RecorderDataPtr->maxEvents = EVENT_BUFFER_SIZE; - /* this is a 64 entry array holding 16-bit references (indexes) - to the most recent entry of each checksum - i.e., list heads.*/ - {0}, + RecorderDataPtr->debugMarker0 = 0xF0F0F0F0; - }, + /* This function is kernel specific */ + vTraceInitObjectPropertyTable(); + RecorderDataPtr->debugMarker1 = 0xF1F1F1F1; + RecorderDataPtr->SymbolTable.symTableSize = SYMBOL_TABLE_SIZE; + RecorderDataPtr->SymbolTable.nextFreeSymbolIndex = 1; #if (INCLUDE_FLOAT_SUPPORT == 1) - /* example float, for float endian detection */ - (float)1.0, -#else - /* This code signals that no float support is included */ - (uint32_t)0, + RecorderDataPtr->exampleFloatEncoding = (float)1.0; /* otherwise already zero */ +#endif + RecorderDataPtr->debugMarker2 = 0xF2F2F2F2; + (void)strncpy(RecorderDataPtr->systemInfo, TRACE_DESCRIPTION, TRACE_DESCRIPTION_MAX_LENGTH); + RecorderDataPtr->debugMarker3 = 0xF3F3F3F3; + RecorderDataPtr->endmarker0 = 0x0A; + RecorderDataPtr->endmarker1 = 0x0B; + RecorderDataPtr->endmarker2 = 0x0C; + RecorderDataPtr->endmarker3 = 0x0D; + RecorderDataPtr->endmarker4 = 0x71; + RecorderDataPtr->endmarker5 = 0x72; + RecorderDataPtr->endmarker6 = 0x73; + RecorderDataPtr->endmarker7 = 0x74; + RecorderDataPtr->endmarker8 = 0xF1; + RecorderDataPtr->endmarker9 = 0xF2; + RecorderDataPtr->endmarker10 = 0xF3; + RecorderDataPtr->endmarker11 = 0xF4; + +#if USE_SEPARATE_USER_EVENT_BUFFER + RecorderDataPtr->userEventBuffer.bufferID = 1; + RecorderDataPtr->userEventBuffer.version = 0; + RecorderDataPtr->userEventBuffer.numberOfSlots = USER_EVENT_BUFFER_SIZE; + RecorderDataPtr->userEventBuffer.numberOfChannels = CHANNEL_FORMAT_PAIRS + 1; #endif - /* internalErrorOccured */ - 0, - - /* debug marker 2 */ - 0xF2F2F2F2, - - /* The trace description string, can hold any information about the system, - e.g., version, configuration. Error messages from the recorder are - copied to this buffer. Also used for internal error messages.*/ - TRACE_DESCRIPTION, - - /* debug marker 3 */ - 0xF3F3F3F3, - - /* the event data buffer, size EVENT_BUFFER_SIZE*4 */ - {0}, - - /* end markers, used to extract the trace from a RAM dump image */ - 0x0A, 0x0B, 0x0C, 0x0D, - 0x71, 0x72, 0x73, 0x74, - 0xF1, 0xF2, 0xF3, 0xF4 -}; - -RecorderDataType* RecorderDataPtr = &RecorderData; - -/* This version of the function does nothing as the trace data is statically allocated */ -RecorderDataType* xTraceInitTraceData(void) -{ - return 0; -} - -#elif (TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_DYNAMIC) + /* Kernel specific initialization of the objectHandleStacks variable */ + vTraceInitObjectHandleStack(); -RecorderDataType* RecorderDataPtr = NULL; + /* Fix the start markers of the trace data structure */ + vInitStartMarkers(); +} -/* This version of the function dynamically allocates the trace data */ -RecorderDataType* xTraceInitTraceData(void) +static void vInitStartMarkers() { - RecorderDataType* tmp = (RecorderDataType*)pvPortMalloc(sizeof(RecorderDataType)); - - if (! tmp) - { - vTraceError("Malloc failed in xTraceInitTraceData! Reduce size constants in trcConfig.h"); - return NULL; - } - - (void)memset(tmp, 0, sizeof(RecorderDataType)); - - tmp->startmarker0 = 0x01; - tmp->startmarker1 = 0x02; - tmp->startmarker2 = 0x03; - tmp->startmarker3 = 0x04; - tmp->startmarker4 = 0x71; - tmp->startmarker5 = 0x72; - tmp->startmarker6 = 0x73; - tmp->startmarker7 = 0x74; - tmp->startmarker8 = 0xF1; - tmp->startmarker9 = 0xF2; - tmp->startmarker10 = 0xF3; - tmp->startmarker11 = 0xF4; - tmp->version = VERSION; - tmp->minor_version = MINOR_VERSION; - tmp->irq_priority_order = IRQ_PRIORITY_ORDER; - tmp->filesize = sizeof(RecorderDataType); - - tmp->maxEvents = EVENT_BUFFER_SIZE; - - tmp->debugMarker0 = 0xF0F0F0F0; - tmp->ObjectPropertyTable.NumberOfObjectClasses = NCLASSES; - tmp->ObjectPropertyTable.ObjectPropertyTableSizeInBytes = DynObjTableSize; - tmp->ObjectPropertyTable.NumberOfObjectsPerClass[0] = NQueue; - tmp->ObjectPropertyTable.NumberOfObjectsPerClass[1] = NSemaphore; - tmp->ObjectPropertyTable.NumberOfObjectsPerClass[2] = NMutex; - tmp->ObjectPropertyTable.NumberOfObjectsPerClass[3] = NTask; - tmp->ObjectPropertyTable.NumberOfObjectsPerClass[4] = NISR; - tmp->ObjectPropertyTable.NameLengthPerClass[0] = NameLenQueue; - tmp->ObjectPropertyTable.NameLengthPerClass[1] = NameLenSemaphore; - tmp->ObjectPropertyTable.NameLengthPerClass[2] = NameLenMutex; - tmp->ObjectPropertyTable.NameLengthPerClass[3] = NameLenTask; - tmp->ObjectPropertyTable.NameLengthPerClass[4] = NameLenISR; - tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue; - tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore; - tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex; - tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[3] = PropertyTableSizeTask; - tmp->ObjectPropertyTable.TotalPropertyBytesPerClass[4] = PropertyTableSizeISR; - tmp->ObjectPropertyTable.StartIndexOfClass[0] = StartIndexQueue; - tmp->ObjectPropertyTable.StartIndexOfClass[1] = StartIndexSemaphore; - tmp->ObjectPropertyTable.StartIndexOfClass[2] = StartIndexMutex; - tmp->ObjectPropertyTable.StartIndexOfClass[3] = StartIndexTask; - tmp->ObjectPropertyTable.StartIndexOfClass[4] = StartIndexISR; - tmp->debugMarker1 = 0xF1F1F1F1; - tmp->SymbolTable.symTableSize = SYMBOL_TABLE_SIZE; - tmp->SymbolTable.nextFreeSymbolIndex = 1; -#if (INCLUDE_FLOAT_SUPPORT == 1) - tmp->exampleFloatEncoding = (float)1.0; /* otherwize already zero */ -#endif - tmp->debugMarker2 = 0xF2F2F2F2; - (void)strncpy(tmp->systemInfo, TRACE_DESCRIPTION, TRACE_DESCRIPTION_MAX_LENGTH); - tmp->debugMarker3 = 0xF3F3F3F3; - tmp->endmarker0 = 0x0A; - tmp->endmarker1 = 0x0B; - tmp->endmarker2 = 0x0C; - tmp->endmarker3 = 0x0D; - tmp->endmarker4 = 0x71; - tmp->endmarker5 = 0x72; - tmp->endmarker6 = 0x73; - tmp->endmarker7 = 0x74; - tmp->endmarker8 = 0xF1; - tmp->endmarker9 = 0xF2; - tmp->endmarker10 = 0xF3; - tmp->endmarker11 = 0xF4; - - RecorderDataPtr = tmp; - - return (RecorderDataType*)RecorderDataPtr; + uint32_t i; + uint8_t *ptr = (uint8_t*)&(RecorderDataPtr->startmarker0); + if ((*ptr) == 0) + { + for (i = 0; i < 12; i++) + { + ptr[i] += 1; + } + } + else + { + vTraceError("Trace start markers already initialized!"); + } } -#endif - volatile int recorder_busy = 0; -char sprintfBuffer[150]; - -/* For debug printouts - the names of the object classes */ -char OBJECTCLASSNAME[NCLASSES][10] = -{ - "QUEUE", - "SEMAPHORE", - "MUTEX", - "TASK", - "ISR" -}; - -/* Initialization of the handle mechanism, see e.g, xTraceGetObjectHandle */ -objectHandleStackType objectHandleStacks = -{ - /* indexOfNextAvailableHandle */ - { - 0, - NQueue, - NQueue + NSemaphore, - NQueue + NSemaphore + NMutex, - NQueue + NSemaphore + NMutex + NTask - }, - - /* lowestIndexOfClass */ - { - 0, - NQueue, - NQueue + NSemaphore, - NQueue + NSemaphore + NMutex, - NQueue + NSemaphore + NMutex + NTask - }, - - /* highestIndexOfClass */ - { - NQueue - 1, - NQueue + NSemaphore - 1, - NQueue + NSemaphore + NMutex - 1, - NQueue + NSemaphore + NMutex + NTask - 1, - NQueue + NSemaphore + NMutex + NTask + NISR - 1 - }, - {0}, - {0} -}; - - -/* Used for internal state flags of objects */ -uint8_t excludedFlags[(NEventCodes+NQueue+NSemaphore+NMutex+NTask) / 8 + 1]; -uint8_t ifeFlags[NTask / 8 + 1]; - /* Gives the last error message of the recorder. NULL if no error message. */ char* traceErrorMessage = NULL; @@ -399,47 +209,46 @@ void* xTraceNextFreeEventBufferSlot(void) vTraceError("Attempt to index outside event buffer!"); return NULL; } - return (void*)(&RecorderDataPtr-> - eventData[RecorderDataPtr->nextFreeIndex*4]); + return (void*)(&RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex*4]); } uint16_t uiIndexOfObject(objectHandleType objecthandle, uint8_t objectclass) { - if ((objectclass < NCLASSES) && (objecthandle > 0) && (objecthandle <= + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiIndexOfObject: Invalid value for objectclass", 0); + TRACE_ASSERT(objecthandle > 0 && objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiIndexOfObject: Invalid value for objecthandle", 0); + + if ((objectclass < TRACE_NCLASSES) && (objecthandle > 0) && (objecthandle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass])) { - return (uint16_t)(RecorderDataPtr-> - ObjectPropertyTable.StartIndexOfClass[objectclass] + - (RecorderDataPtr-> - ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * - (objecthandle-1))); + return (uint16_t)(RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[objectclass] + + (RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[objectclass] * (objecthandle-1))); } - - vTraceError("Object table lookup with invalid object handle or object class!"); + + vTraceError("Object table lookup with invalid object handle or object class!"); return 0; } /******************************************************************************* - * Object handle system + * Object handle system * This provides a mechanism to assign each kernel object (tasks, queues, etc) * with a 1-byte handle, that is used to identify the object in the trace. * This way, only one byte instead of four is necessary to identify the object. * This allows for maximum 255 objects, of each object class, active at any * moment. * Note that zero is reserved as an error code and is not a valid handle. - * - * In order to allow for fast dynamic allocation and release of object handles, - * the handles of each object class (e.g., TASK) are stored in a stack. When a - * handle is needed, e.g., on task creation, the next free handle is popped from - * the stack. When an object (e.g., task) is deleted, its handle is pushed back + * + * In order to allow for fast dynamic allocation and release of object handles, + * the handles of each object class (e.g., TASK) are stored in a stack. When a + * handle is needed, e.g., on task creation, the next free handle is popped from + * the stack. When an object (e.g., task) is deleted, its handle is pushed back * on the stack and can thereby be reused for other objects. - * - * Since this allows for reuse of object handles, a specific handle (e.g, "8") - * may refer to TASK_X at one point, and later mean "TASK_Y". To resolve this, - * the recorder uses "Close events", which are stored in the main event buffer - * when objects are deleted and their handles are released. The close event + * + * Since this allows for reuse of object handles, a specific handle (e.g, "8") + * may refer to TASK_X at one point, and later mean "TASK_Y". To resolve this, + * the recorder uses "Close events", which are stored in the main event buffer + * when objects are deleted and their handles are released. The close event * contains the mapping between object handle and object name which was valid up - * to this point in time. The object name is stored as a symbol table entry. + * to this point in time. The object name is stored as a symbol table entry. ******************************************************************************/ objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass) @@ -447,61 +256,45 @@ objectHandleType xTraceGetObjectHandle(traceObjectClass objectclass) static objectHandleType handle; static int indexOfHandle; + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "xTraceGetObjectHandle: Invalid value for objectclass", (objectHandleType)0); + indexOfHandle = objectHandleStacks.indexOfNextAvailableHandle[objectclass]; if (objectHandleStacks.objectHandles[indexOfHandle] == 0) { /* Zero is used to indicate a never before used handle, i.e., - new slots in the handle stack. The handle slot needs to + new slots in the handle stack. The handle slot needs to be initialized here (starts at 1). */ - objectHandleStacks.objectHandles[indexOfHandle] = - (objectHandleType)(1 + indexOfHandle - + objectHandleStacks.objectHandles[indexOfHandle] = + (objectHandleType)(1 + indexOfHandle - objectHandleStacks.lowestIndexOfClass[objectclass]); } handle = objectHandleStacks.objectHandles[indexOfHandle]; - - if ( objectHandleStacks.indexOfNextAvailableHandle[objectclass] - > objectHandleStacks.highestIndexOfClass[objectclass] ) + + if (objectHandleStacks.indexOfNextAvailableHandle[objectclass] + > objectHandleStacks.highestIndexOfClass[objectclass]) { /* ERROR */ - switch(objectclass) - { - case TRACE_CLASS_TASK: - vTraceError("Not enough TASK handles - increase NTask in trcConfig.h"); - break; - case TRACE_CLASS_ISR: - vTraceError("Not enough ISR handles - increase NISR in trcConfig.h"); - break; - case TRACE_CLASS_SEMAPHORE: - vTraceError("Not enough SEMAPHORE handles - increase NSemaphore in trcConfig.h"); - break; - case TRACE_CLASS_MUTEX: - vTraceError("Not enough MUTEX handles - increase NMutex in trcConfig.h"); - break; - case TRACE_CLASS_QUEUE: - vTraceError("Not enough QUEUE handles - increase NQueue in trcConfig.h"); - break; - default: - vTraceError("Invalid object class."); - break; - } - + vTraceError(pszTraceGetErrorNotEnoughHandles(objectclass)); + handle = 0; /* an invalid/anonymous handle - but the recorder is stopped now... */ } else { int hndCount; objectHandleStacks.indexOfNextAvailableHandle[objectclass]++; - - hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] - + + hndCount = objectHandleStacks.indexOfNextAvailableHandle[objectclass] - objectHandleStacks.lowestIndexOfClass[objectclass]; - - if (hndCount > + + if (hndCount > objectHandleStacks.handleCountWaterMarksOfClass[objectclass]) { - objectHandleStacks.handleCountWaterMarksOfClass[objectclass] = + objectHandleStacks.handleCountWaterMarksOfClass[objectclass] = (objectHandleType)hndCount; } + + TRACE_CLEAR_OBJECT_FLAG_ISEXCLUDED(objectclass, handle); } return handle; @@ -511,9 +304,12 @@ void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handl { int indexOfHandle; + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceFreeObjectHandle: Invalid value for objectclass", ); + TRACE_ASSERT(handle > 0 && handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceFreeObjectHandle: Invalid value for handle", ); + /* Check that there is room to push the handle on the stack */ - if ( (objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) < - objectHandleStacks.lowestIndexOfClass[objectclass] ) + if ((objectHandleStacks.indexOfNextAvailableHandle[objectclass] - 1) < + objectHandleStacks.lowestIndexOfClass[objectclass]) { /* Error */ vTraceError("Attempt to free more handles than allocated! (duplicate xTaskDelete or xQueueDelete?)"); @@ -528,7 +324,7 @@ void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handl } /******************************************************************************* - * Objects Property Table + * Objects Property Table * * This holds the names and properties of the currently active objects, such as * tasks and queues. This is developed to support "dynamic" objects which might @@ -548,52 +344,30 @@ void vTraceFreeObjectHandle(traceObjectClass objectclass, objectHandleType handl * Registers the names of queues, semaphores and other kernel objects in the * recorder's Object Property Table, at the given handle and object class. ******************************************************************************/ -void vTraceSetObjectName(traceObjectClass objectclass, - objectHandleType handle, +void vTraceSetObjectName(traceObjectClass objectclass, + objectHandleType handle, const char* name) { static uint16_t idx; - if (handle == 0) + TRACE_ASSERT(name != NULL, "vTraceSetObjectName: name == NULL", ); + + if (objectclass >= TRACE_NCLASSES) { - vTraceError("Illegal handle (0) in vTraceSetObjectName."); + vTraceError("Illegal object class in vTraceSetObjectName"); return; } - - switch(objectclass) + + if (handle == 0) { - case TRACE_CLASS_TASK: - case TRACE_CLASS_ISR: - case TRACE_CLASS_SEMAPHORE: - case TRACE_CLASS_MUTEX: - case TRACE_CLASS_QUEUE: - break; - default: - vTraceError("Illegal object class in vTraceSetObjectName"); - break; + vTraceError("Illegal handle (0) in vTraceSetObjectName."); + return; } - if (handle > - RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]) + if (handle > RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass]) { - switch(objectclass) - { - case TRACE_CLASS_TASK: - vTraceError("Not enough TASK handles - increase NTask in trcConfig.h"); - break; - case TRACE_CLASS_ISR: - vTraceError("Not enough ISR handles - increase NISR in trcConfig.h"); - break; - case TRACE_CLASS_SEMAPHORE: - vTraceError("Not enough SEMAPHORE handles - increase NSemaphore in trcConfig.h"); - break; - case TRACE_CLASS_MUTEX: - vTraceError("Not enough MUTEX handles - increase NMutex in trcConfig.h"); - break; - case TRACE_CLASS_QUEUE: - vTraceError("Not enough QUEUE handles - increase NQueue in trcConfig.h"); - break; - } + /* ERROR */ + vTraceError(pszTraceGetErrorNotEnoughHandles(objectclass)); } else { @@ -603,21 +377,21 @@ void vTraceSetObjectName(traceObjectClass objectclass, { (void)strncpy((char*)&(RecorderDataPtr->ObjectPropertyTable.objbytes[idx]), name, - RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ] ); -#ifdef WIN32 - printf("vTraceSetObjectName(%d, %d, %s)\n", objectclass, handle, name); -#endif + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[ objectclass ]); } } } traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel) { - static uint16_t result; - static uint8_t len; - static uint8_t crc; + uint16_t result; + uint8_t len; + uint8_t crc; len = 0; crc = 0; + + TRACE_ASSERT(name != NULL, "prvTraceOpenSymbol: name == NULL", (traceLabel)0); + prvTraceGetChecksum(name, &crc, &len); trcCRITICAL_SECTION_BEGIN(); @@ -635,38 +409,46 @@ traceLabel prvTraceOpenSymbol(const char* name, traceLabel userEventChannel) * Supporting functions ******************************************************************************/ +extern volatile uint32_t rtest_error_flag; + /******************************************************************************* * vTraceError * - * Called by various parts in the recorder. Stops the recorder and stores a + * 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. - * If you are not using the monitor task, you may use xTraceGetLastError() + * If you are not using the monitor task, you may use xTraceGetLastError() * from your application to check if the recorder is OK. * - * Note: If a recorder error is registered before vTraceStart is called, the - * trace start will be aborted. This can occur if any of the Nxxxx constants + * Note: If a recorder error is registered before vTraceStart is called, the + * trace start will be aborted. This can occur if any of the Nxxxx constants * (e.g., NTask) in trcConfig.h is too small. ******************************************************************************/ void vTraceError(const char* msg) { - vTraceStop(); + TRACE_ASSERT(msg != NULL, "vTraceError: msg == NULL", ); + TRACE_ASSERT(RecorderDataPtr != NULL, "vTraceError: RecorderDataPtr == NULL", ); + + // Stop the recorder. Note: We do not call vTraceStop, since that adds a weird + // and unnecessary dependency to trcUser.c. + + RecorderDataPtr->recorderActive = 0; + if (traceErrorMessage == NULL) { traceErrorMessage = (char*)msg; - (void)strncpy(RecorderDataPtr->systemInfo, - traceErrorMessage, - TRACE_DESCRIPTION_MAX_LENGTH); - RecorderDataPtr->internalErrorOccured = 1; + (void)strncpy(RecorderDataPtr->systemInfo, traceErrorMessage, TRACE_DESCRIPTION_MAX_LENGTH); + RecorderDataPtr->internalErrorOccured = 1; } + } /****************************************************************************** - * prvCheckDataToBeOverwrittenForMultiEntryUserEvents + * prvCheckDataToBeOverwrittenForMultiEntryEvents * - * This checks if the next event to be overwritten is a multi-entry user event, + * This checks if the next event to be overwritten is a multi-entry user event, * i.e., a USER_EVENT followed by data entries. * Such data entries do not have an event code at byte 0, as other events. - * All 4 bytes are user data, so the first byte of such data events must + * All 4 bytes are user data, so the first byte of such data events must * not be interpreted as type field. The number of data entries following * a USER_EVENT is given in the event code of the USER_EVENT. * Therefore, when overwriting a USER_EVENT (when using in ringbuffer mode) @@ -675,16 +457,18 @@ void vTraceError(const char* msg) * This is assumed to execute within a critical section... *****************************************************************************/ -void prvCheckDataToBeOverwrittenForMultiEntryUserEvents( - uint8_t nofEntriesToCheck) +void prvCheckDataToBeOverwrittenForMultiEntryEvents(uint8_t nofEntriesToCheck) { /* Generic "int" type is desired - should be 16 bit variable on 16 bit HW */ - unsigned int i = 0; + unsigned int i = 0; unsigned int e = 0; + + TRACE_ASSERT(nofEntriesToCheck != 0, "prvCheckDataToBeOverwrittenForMultiEntryEvents: nofEntriesToCheck == 0", ); + while (i < nofEntriesToCheck) - { + { e = RecorderDataPtr->nextFreeIndex + i; - if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) && + if ((RecorderDataPtr->eventData[e*4] > USER_EVENT) && (RecorderDataPtr->eventData[e*4] < USER_EVENT + 16)) { uint8_t nDataEvents = (uint8_t)(RecorderDataPtr->eventData[e*4] - USER_EVENT); @@ -692,6 +476,20 @@ void prvCheckDataToBeOverwrittenForMultiEntryUserEvents( { (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4 * nDataEvents); } + } + else if (RecorderDataPtr->eventData[e*4] == DIV_XPS) + { + if ((e + 1) < RecorderDataPtr->maxEvents) + { + /* Clear 8 bytes */ + (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4 + 4); + } + else + { + /* Clear 8 bytes, 4 first and 4 last */ + (void)memset(& RecorderDataPtr->eventData[0], 0, 4); + (void)memset(& RecorderDataPtr->eventData[e*4], 0, 4); + } } i++; } @@ -708,14 +506,14 @@ void prvTraceUpdateCounters(void) { return; } - + RecorderDataPtr->numEvents++; RecorderDataPtr->nextFreeIndex++; - + if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) - { -#if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER) + { +#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) RecorderDataPtr->bufferIsFull = 1; RecorderDataPtr->nextFreeIndex = 0; #else @@ -723,10 +521,10 @@ void prvTraceUpdateCounters(void) #endif } -#if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER) - prvCheckDataToBeOverwrittenForMultiEntryUserEvents(1); +#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) + prvCheckDataToBeOverwrittenForMultiEntryEvents(1); #endif - + #ifdef STOP_AFTER_N_EVENTS #if (STOP_AFTER_N_EVENTS > -1) if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS) @@ -736,7 +534,7 @@ void prvTraceUpdateCounters(void) #endif #endif } - + /****************************************************************************** * prvTraceGetDTS * @@ -754,26 +552,25 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) uint32_t dts = 0; uint32_t timestamp = 0; + TRACE_ASSERT(param_maxDTS == 0xFF || param_maxDTS == 0xFFFF, "prvTraceGetDTS: Invalid value for param_maxDTS", 0); + if (RecorderDataPtr->frequency == 0) { /* If HWTC_PERIOD is mapped to the timer reload register, - such as in the Cortex M port, it is not initialized before - FreeRTOS has been started. We therefore store the frequency - of the timer at the first timestamped event after the - scheduler has started. (Note that this function is called - also by vTraceStart and uiTraceStart, which might be - called before the scheduler has been started.) */ - -#if (SELECTED_PORT == PORT_Win32) + such as in the Cortex M port, it might not be initialized + before the Kernel scheduler has been started has been + started. We therefore store the frequency of the timer at + the first timestamped event after the scheduler has started. + (Note that this function is called also by vTraceStart and + uiTraceStart, which might be called before the scheduler + has been started.) */ + +#if (SELECTED_PORT == PORT_Win32) RecorderDataPtr->frequency = 100000; -#elif (SELECTED_PORT == PORT_HWIndependent) - RecorderDataPtr->frequency = configTICK_RATE_HZ; -#else - if (xTaskGetSchedulerState() != 0) /* Has the scheduler started? */ - { - RecorderDataPtr->frequency = - (uint32_t)HWTC_PERIOD * (uint32_t)configTICK_RATE_HZ / (uint32_t)HWTC_DIVISOR; - } +#elif (SELECTED_PORT == PORT_HWIndependent) + RecorderDataPtr->frequency = TRACE_TICK_RATE_HZ; +#else + RecorderDataPtr->frequency = TRACE_CPU_CLOCK_HZ / (uint32_t)HWTC_DIVISOR; #endif } @@ -782,26 +579,16 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) * If necessary, whole seconds are extracted using division while the rest * comes from the modulo operation. **************************************************************************/ - - uiTracePortGetTimeStamp(×tamp); + + vTracePortGetTimeStamp(×tamp); /*************************************************************************** - * This condition is only for the Win32 port, since it does not use the tick - * count but instead only HWTC_COUNT (from the performance counter). - * Without this condition, you sometimes get a negative dts value (converted - * into a very large unsiged value) when the performance counter wraps - * around. In other "normal" ports also using the FreeRTOS tick counter, this - * condition can not occur and therefore has no impact. + * Since dts is unsigned the result will be correct even if timestamp has + * wrapped around. ***************************************************************************/ - if (timestamp < old_timestamp) - { - timestamp += RecorderDataPtr->frequency; - } - - dts = timestamp - old_timestamp; old_timestamp = timestamp; - + if (RecorderDataPtr->frequency > 0) { /* Check if dts > 1 second */ @@ -813,8 +600,10 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) RecorderDataPtr->absTimeLastEvent += dts % RecorderDataPtr->frequency; } else + { RecorderDataPtr->absTimeLastEvent += dts; - + } + /* Check if absTimeLastEvent >= 1 second */ if (RecorderDataPtr->absTimeLastEvent >= RecorderDataPtr->frequency) { @@ -858,7 +647,7 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) } } - return (uint16_t)(dts % (param_maxDTS + 1)); + return (uint16_t)dts & param_maxDTS; } /******************************************************************************* @@ -874,13 +663,16 @@ uint16_t prvTraceGetDTS(uint16_t param_maxDTS) * byte 4..(4 + length): the string (object name or user event label), with * zero-termination ******************************************************************************/ -traceLabel prvTraceLookupSymbolTableEntry(const char* name, - uint8_t crc6, - uint8_t len, +traceLabel prvTraceLookupSymbolTableEntry(const char* name, + uint8_t crc6, + uint8_t len, traceLabel chn) { uint16_t i = RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ]; + TRACE_ASSERT(name != NULL, "prvTraceLookupSymbolTableEntry: name == NULL", (traceLabel)0); + TRACE_ASSERT(len != 0, "prvTraceLookupSymbolTableEntry: len == 0", (traceLabel)0); + while (i != 0) { if (RecorderDataPtr->SymbolTable.symbytes[i + 2] == (chn & 0x00FF)) @@ -914,54 +706,58 @@ traceLabel prvTraceLookupSymbolTableEntry(const char* name, * byte 4..(4 + length): the string (object name or user event label), with * zero-termination ******************************************************************************/ -uint16_t prvTraceCreateSymbolTableEntry(const char* name, - uint8_t crc6, - uint8_t len, +uint16_t prvTraceCreateSymbolTableEntry(const char* name, + uint8_t crc6, + uint8_t len, traceLabel channel) { uint16_t ret = 0; + + TRACE_ASSERT(name != NULL, "prvTraceCreateSymbolTableEntry: name == NULL", 0); + TRACE_ASSERT(len != 0, "prvTraceCreateSymbolTableEntry: len == 0", 0); + if (RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + len + 4 >= SYMBOL_TABLE_SIZE) { vTraceError("Symbol table full. Increase SYMBOL_TABLE_SIZE in trcConfig.h"); - ret = 0; + ret = 0; } else { RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] = + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex] = (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] & 0x00FF); RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] = + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 1] = (uint8_t)(RecorderDataPtr->SymbolTable.latestEntryOfChecksum[ crc6 ] / 0x100); RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] = + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 2] = (uint8_t)(channel & 0x00FF); RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] = + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 3] = (uint8_t)(channel / 0x100); /* set name (bytes 4...4+len-1) */ - (void)strncpy((char*)&( RecorderDataPtr->SymbolTable.symbytes - [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4] ), name, len); + (void)strncpy((char*)&(RecorderDataPtr->SymbolTable.symbytes + [ RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4]), name, len); - /* Set zero termination (at offest 4+len) */ + /* Set zero termination (at offset 4+len) */ RecorderDataPtr->SymbolTable.symbytes [RecorderDataPtr->SymbolTable.nextFreeSymbolIndex + 4 + len] = '\0'; /* store index of entry (for return value, and as head of LL[crc6]) */ RecorderDataPtr->SymbolTable.latestEntryOfChecksum [ crc6 ] = (uint16_t)RecorderDataPtr->SymbolTable.nextFreeSymbolIndex; - + RecorderDataPtr->SymbolTable.nextFreeSymbolIndex += (len + 5); - - ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex - + + ret = (uint16_t)(RecorderDataPtr->SymbolTable.nextFreeSymbolIndex - (len + 5)); } - + return ret; } @@ -969,7 +765,7 @@ uint16_t prvTraceCreateSymbolTableEntry(const char* name, /******************************************************************************* * prvTraceGetChecksum * - * Calculates a simple 6-bit checksum from a string, used to index the string + * Calculates a simple 6-bit checksum from a string, used to index the string * for fast symbol table lookup. ******************************************************************************/ void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength) @@ -977,16 +773,21 @@ void prvTraceGetChecksum(const char *pname, uint8_t* pcrc, uint8_t* plength) unsigned char c; int length = 0; int crc = 0; - if ( pname != (const char *) 0 ) + + TRACE_ASSERT(pname != NULL, "prvTraceGetChecksum: pname == NULL", ); + TRACE_ASSERT(pcrc != NULL, "prvTraceGetChecksum: pcrc == NULL", ); + TRACE_ASSERT(plength != NULL, "prvTraceGetChecksum: plength == NULL", ); + + if (pname != (const char *) 0) { - for ( ; (c = *pname++) != '\0'; ) + for (; (c = *pname++) != '\0';) { crc += c; length++; } } - *pcrc = (uint8_t)(crc % 64); + *pcrc = (uint8_t)(crc & 0x3F); *plength = (uint8_t)length; } -#endif +#endif \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c new file mode 100644 index 000000000..754b3211d --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcHardwarePort.c @@ -0,0 +1,119 @@ +/******************************************************************************* + * Tracealyzer v2.4.1 Recorder Library + * Percepio AB, www.percepio.com + * + * trcHardwarePort.c + * + * Contains together with trcHardwarePort.h all hardware portability issues of + * the 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. + * + * Copyright Percepio AB, 2013. + * www.percepio.com + ******************************************************************************/ + +#include "trcHardwarePort.h" + +#if (USE_TRACEALYZER_RECORDER == 1) + +#include + + +/******************************************************************************* + * uiTraceTickCount + * + * This variable is should be updated by the Kernel tick interrupt. This does + * not need to be modified when developing a new timer port. It is preferred to + * keep any timer port changes in the HWTC macro definitions, which typically + * give sufficient flexibility. + ******************************************************************************/ +uint32_t uiTraceTickCount = 0; + +/****************************************************************************** + * vTracePortGetTimeStamp + * + * Returns the current time based on the HWTC macros which provide a hardware + * isolation layer towards the hardware timer/counter. + * + * The HWTC macros and vTracePortGetTimeStamp is the main porting issue + * or the trace recorder library. Typically you should not need to change + * the code of vTracePortGetTimeStamp if using the HWTC macros. + * + ******************************************************************************/ +void vTracePortGetTimeStamp(uint32_t *pTimestamp) +{ + static uint32_t last_traceTickCount = 0; + static uint32_t last_hwtc_count = 0; + uint32_t traceTickCount = 0; + uint32_t hwtc_count = 0; + + /* Retrieve HWTC_COUNT only once since the same value should be used all throughout this function. */ +#if (HWTC_COUNT_DIRECTION == DIRECTION_INCREMENTING) + hwtc_count = HWTC_COUNT; +#elif (HWTC_COUNT_DIRECTION == DIRECTION_DECREMENTING) + hwtc_count = HWTC_PERIOD - HWTC_COUNT; +#else + Junk text to cause compiler error - HWTC_COUNT_DIRECTION is not set correctly! + Should be DIRECTION_INCREMENTING or DIRECTION_DECREMENTING +#endif + + if (last_traceTickCount - uiTraceTickCount - 1 < 0x80000000) + { + /* This means last_traceTickCount is higher than uiTraceTickCount, + so we have previously compensated for a missed tick. + Therefore we use the last stored value because that is more accurate. */ + traceTickCount = last_traceTickCount; + } + else + { + /* Business as usual */ + traceTickCount = uiTraceTickCount; + } + + /* Check for overflow. May occur if the update of uiTraceTickCount has been + delayed due to disabled interrupts. */ + if (traceTickCount == last_traceTickCount && hwtc_count < last_hwtc_count) + { + /* A trace tick has occurred but not been executed by the kernel, so we compensate manually. */ + traceTickCount++; + } + + /* Check if the return address is OK, then we perform the calculation. */ + if (pTimestamp) + { + /* Get timestamp from trace ticks. Scale down the period to avoid unwanted overflows. */ + *pTimestamp = traceTickCount * (HWTC_PERIOD / HWTC_DIVISOR); + /* Increase timestamp by (hwtc_count + "lost hardware ticks from scaling down period") / HWTC_DIVISOR. */ + *pTimestamp += (hwtc_count + traceTickCount * (HWTC_PERIOD % HWTC_DIVISOR)) / HWTC_DIVISOR; + } + + /* Store the previous values. */ + last_traceTickCount = traceTickCount; + last_hwtc_count = hwtc_count; +} + +#endif \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c index 98b84a8ea..ce9b14a84 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernel.c @@ -1,106 +1,52 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * * trcKernel.c * - * Functions for integration of the trace recorder library in the FreeRTOS - * kernel (requires FreeRTOS v7.1.0 or later). - * + * Functions used by trcKernelHooks.h. + * * 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 + * in its original form, including modifications in trcHardwarePort.c/.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 + * 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 + * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ -#include "trcUser.h" -#include "task.h" +#include "trcKernel.h" -#if (configUSE_TRACE_FACILITY == 1) +#if (USE_TRACEALYZER_RECORDER == 1) - - -/****************************************************************************** - * TraceObjectClassTable - * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_). - * This was added since we want to map both types of Mutex and both types of - * Semaphores on common classes for all Mutexes and all Semaphores respectively. - * - * FreeRTOS Queue types - * #define queueQUEUE_TYPE_BASE ( 0U ) => TRACE_CLASS_QUEUE - * #define queueQUEUE_TYPE_MUTEX ( 1U ) => TRACE_CLASS_MUTEX - * #define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( 2U ) => TRACE_CLASS_SEMAPHORE - * #define queueQUEUE_TYPE_BINARY_SEMAPHORE ( 3U ) => TRACE_CLASS_SEMAPHORE - * #define queueQUEUE_TYPE_RECURSIVE_MUTEX ( 4U ) => TRACE_CLASS_MUTEX - ******************************************************************************/ -traceObjectClass TraceObjectClassTable[5] = {TRACE_CLASS_QUEUE, - TRACE_CLASS_MUTEX, - TRACE_CLASS_SEMAPHORE, - TRACE_CLASS_SEMAPHORE, - TRACE_CLASS_MUTEX }; - -/* This is defined in FreeRTOS! */ -extern volatile void * volatile pxCurrentTCB; +#include /* Internal variables */ uint8_t nISRactive = 0; objectHandleType handle_of_last_logged_task = 0; uint8_t inExcludedTask = 0; -static uint8_t prvTraceIsObjectExcluded(traceObjectClass, uint32_t); - -/******************************************************************************* - * prvTraceIsObjectExcluded - * - * Private function that accepts an object class and an object number and uses - * that to determine if the object has been flagged as excluded. - ******************************************************************************/ -static uint8_t prvTraceIsObjectExcluded(traceObjectClass objectClass, uint32_t objectNumber) -{ - switch(objectClass) - { - case TRACE_CLASS_QUEUE: - return GET_QUEUE_FLAG_ISEXCLUDED(objectNumber); - break; - case TRACE_CLASS_SEMAPHORE: - return GET_SEMAPHORE_FLAG_ISEXCLUDED(objectNumber); - break; - case TRACE_CLASS_MUTEX: - return GET_MUTEX_FLAG_ISEXCLUDED(objectNumber); - break; - case TRACE_CLASS_TASK: - return GET_TASK_FLAG_ISEXCLUDED(objectNumber); - break; - } - return 0; -} +static uint32_t prvTraceGetParam(uint32_t, uint32_t); #if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1 /******************************************************************************* @@ -112,79 +58,91 @@ void vTraceStoreTaskReady(objectHandleType handle) { uint16_t dts3; TREvent* tr; + + TRACE_ASSERT(handle > 0 && handle <= NTask, "vTraceStoreTaskReady: Invalid value for handle", ); - if (!GET_TASK_FLAG_ISEXCLUDED(handle)) + if (recorder_busy) { - dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - tr = (TREvent*)xTraceNextFreeEventBufferSlot(); - - if (tr != NULL) - { - tr->type = TR_TASK_READY; - tr->dts = dts3; - tr->objHandle = handle; - - prvTraceUpdateCounters(); - } - } + /*********************************************************************** + * This should never occur, as the tick- and kernel call ISR is on lowest + * interrupt priority and always are disabled during the critical sections + * of the recorder. + ***********************************************************************/ + + vTraceError("Recorder busy - high priority ISR using syscall? (1)"); + return; } + + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { + if (!TRACE_GET_TASK_FLAG_ISEXCLUDED(handle)) + { + dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { + tr = (TREvent*)xTraceNextFreeEventBufferSlot(); + + if (tr != NULL) + { + tr->type = DIV_TASK_READY; + tr->dts = dts3; + tr->objHandle = handle; + + prvTraceUpdateCounters(); + } + } + } + } } #endif /******************************************************************************* * vTraceStoreKernelCall * - * This is the main integration point for storing FreeRTOS kernel calls, and - * is called by the hooks in FreeRTOS.h (see trcKernel.h for event codes). + * This is the main integration point for storing kernel calls, and + * is called by the hooks in trcKernelHooks.h (see trcKernelPort.h for event codes). ******************************************************************************/ void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber) { KernelCall * kse; uint16_t dts1; + + TRACE_ASSERT(ecode < 0xFF, "vTraceStoreKernelCall: ecode >= 0xFF", ); + TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCall: objectClass >= TRACE_NCLASSES", ); + TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCall: Invalid value for objectNumber", ); + + if (recorder_busy) + { + /************************************************************************* + * This may occur if a high-priority ISR is illegally using a system call, + * or creates a user event. + * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls + * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). + *************************************************************************/ + + vTraceError("Recorder busy - high priority ISR using syscall? (2)"); + return; + } if (handle_of_last_logged_task == 0) { return; } - + if (RecorderDataPtr->recorderActive) { - + /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */ if (nISRactive || !inExcludedTask) { - /* Make sure ISRs never change the IFE flags of tasks */ - if (!nISRactive) - { - /* This checks if this is the first kernel call after a call to - vTraceTaskInstanceIsFinished. In that case, calls to this kernel service - with this specific kernel object become the "instance finish event" - (IFE) of the calling task.*/ - if (GET_TASK_FLAG_MARKIFE(handle_of_last_logged_task)) - { - /* Reset the flag - this has been handled now */ - CLEAR_TASK_FLAG_MARKIFE(handle_of_last_logged_task); - - /* Store the kernel service tagged as instance finished event */ - PROPERTY_TASK_IFE_SERVICECODE(handle_of_last_logged_task) = - (uint8_t)ecode; - - /* Store the handle of the specific kernel object */ - PROPERTY_TASK_IFE_OBJHANDLE(handle_of_last_logged_task) = - (objectHandleType)objectNumber; - } - } - /* Check if the referenced object or the event code is excluded */ - if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode)) + if (!uiTraceIsObjectExcluded(objectClass, objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode)) { trcCRITICAL_SECTION_BEGIN(); dts1 = (uint16_t)prvTraceGetDTS(0xFFFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { + { kse = (KernelCall*) xTraceNextFreeEventBufferSlot(); if (kse != NULL) { @@ -214,17 +172,34 @@ void vTraceStoreKernelCallWithParam(uint32_t evtcode, KernelCallWithParamAndHandle * kse; uint8_t dts2; - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && + TRACE_ASSERT(evtcode < 0xFF, "vTraceStoreKernelCall: evtcode >= 0xFF", ); + TRACE_ASSERT(objectClass < TRACE_NCLASSES, "vTraceStoreKernelCallWithParam: objectClass >= TRACE_NCLASSES", ); + TRACE_ASSERT(objectNumber <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectClass], "vTraceStoreKernelCallWithParam: Invalid value for objectNumber", ); + + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && (! inExcludedTask || nISRactive)) { + if (recorder_busy) + { + /************************************************************************* + * This may occur if a high-priority ISR is illegally using a system call, + * or creates a user event. + * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls + * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). + *************************************************************************/ + + vTraceError("Recorder busy - high priority ISR using syscall? (3)"); + return; + } + /* Check if the referenced object or the event code is excluded */ - if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) + if (!uiTraceIsObjectExcluded(objectClass, objectNumber) && !TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) { trcCRITICAL_SECTION_BEGIN(); dts2 = (uint8_t)prvTraceGetDTS(0xFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { + { kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot(); if (kse != NULL) { @@ -232,7 +207,7 @@ void vTraceStoreKernelCallWithParam(uint32_t evtcode, kse->type = (uint8_t)evtcode; kse->objHandle = (uint8_t)objectNumber; kse->param = param; - prvTraceUpdateCounters(); + prvTraceUpdateCounters(); } } trcCRITICAL_SECTION_END(); @@ -240,6 +215,35 @@ void vTraceStoreKernelCallWithParam(uint32_t evtcode, } } +/******************************************************************************* + * prvTraceGetParam + * + * Used for storing extra bytes for kernel calls with numeric parameters. + ******************************************************************************/ +static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param) +{ + XPSEvent* xps; + + TRACE_ASSERT(param_max == 0xFF || param_max == 0xFFFF, "prvTraceGetParam: Invalid value for param_max", param); + + if (param <= param_max) + { + return param; + } + else + { + xps = (XPSEvent*) xTraceNextFreeEventBufferSlot(); + if (xps != NULL) + { + xps->type = DIV_XPS; + xps->xps_8 = (param & (0xFF00 & ~param_max)) >> 8; + xps->xps_16 = (param & (0xFFFF0000 & ~param_max)) >> 16; + prvTraceUpdateCounters(); + } + + return param & param_max; + } +} /******************************************************************************* * vTraceStoreKernelCallWithNumericParamOnly @@ -247,124 +251,117 @@ void vTraceStoreKernelCallWithParam(uint32_t evtcode, * Used for storing kernel calls with numeric parameters only. This is * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment. ******************************************************************************/ -void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint16_t param) +void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint32_t param) { KernelCallWithParam16 * kse; uint8_t dts6; + uint16_t restParam = 0; - if (RecorderDataPtr->recorderActive && handle_of_last_logged_task + TRACE_ASSERT(evtcode < 0xFF, "vTraceStoreKernelCallWithNumericParamOnly: Invalid value for evtcode", ); + + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && (! inExcludedTask || nISRactive)) { /* Check if the event code is excluded */ - if (!GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) + if (!TRACE_GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) { + if (recorder_busy) + { + /************************************************************************* + * This may occur if a high-priority ISR is illegally using a system call, + * or creates a user event. + * Only ISRs that are disabled by TRACE_ENTER_CRITICAL_SECTION may use system calls + * or user events (see TRACE_MAX_SYSCALL_INTERRUPT_PRIORITY). + *************************************************************************/ + + vTraceError("Recorder busy - high priority ISR using syscall? (4)"); + return; + } + trcCRITICAL_SECTION_BEGIN(); dts6 = (uint8_t)prvTraceGetDTS(0xFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot(); - if (kse != NULL) - { - kse->dts = dts6; - kse->type = (uint8_t)evtcode; - kse->param = param; - prvTraceUpdateCounters(); - } + { + restParam = (uint16_t)prvTraceGetParam(0xFFFF, param); + + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { + kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot(); + if (kse != NULL) + { + kse->dts = dts6; + kse->type = (uint8_t)evtcode; + kse->param = restParam; + prvTraceUpdateCounters(); + } + } } trcCRITICAL_SECTION_END(); } } } -objectHandleType handle_of_running_task = 0; - /******************************************************************************* * vTraceStoreTaskswitch * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart. * At this point interrupts are assumed to be disabled! ******************************************************************************/ -void vTraceStoreTaskswitch(void) +void vTraceStoreTaskswitch(objectHandleType task_handle) { uint16_t dts3; - TSEvent* ts; + TSEvent* ts; int8_t skipEvent = 0; - uint32_t schedulerState = 0; - - /*************************************************************************** - This is used to detect if a high-priority ISRs is illegally using the - recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the + + TRACE_ASSERT(task_handle <= NTask, "vTraceStoreTaskswitch: Invalid value for task_handle", ); + + /*************************************************************************** + This is used to detect if a high-priority ISRs is illegally using the + recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the recorder is busy with a task-level event or lower priority ISR event. - - If this is detected, it triggers a call to vTraceError with the error + + If this is detected, it triggers a call to vTraceError with the error "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means - that the macro taskENTER_CRITICAL does not disable this ISR, as required. - You can solve this by adjusting the value of the FreeRTOS constant - configMAX_SYSCALL_INTERRUPT_PRIORITY, which is defined in FreeRTOSConfig.h + that the macro trcCRITICAL_SECTION_BEGIN does not disable this ISR, as required. Note: Setting recorder_busy is normally handled in our macros - trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this - function since critical sections should not be used in the context switch - event...) + trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this + function since critical sections should not be used in the context switch + event...) ***************************************************************************/ - recorder_busy++; - - schedulerState = xTaskGetSchedulerState(); - - if (schedulerState == 0) - { - /* This occurs on the very first taskswitch event, generated by - vTraceStart and uiTraceStart if the scheduler is not yet started. - This creates a dummy "(startup)" task entry internally in the - recorder */ - if (handle_of_running_task == 0) - { - handle_of_running_task = xTraceGetObjectHandle(TRACE_CLASS_TASK); - - vTraceSetObjectName(TRACE_CLASS_TASK, - handle_of_running_task, - "(startup)"); + recorder_busy++; - vTraceSetPriorityProperty(TRACE_CLASS_TASK, - handle_of_running_task, - 0); - } - } - else - { - handle_of_running_task = - (objectHandleType)uxTaskGetTaskNumber(xTaskGetCurrentTaskHandle()); - } - /* Skip the event if the task has been excluded, using vTraceExcludeTask */ - if (GET_TASK_FLAG_ISEXCLUDED(handle_of_running_task)) - { + if (TRACE_GET_TASK_FLAG_ISEXCLUDED(task_handle)) + { skipEvent = 1; - inExcludedTask = 1; + inExcludedTask = 1; } else + { inExcludedTask = 0; - + } - /* Skip the event if the same task is scheduled */ - if (handle_of_running_task == handle_of_last_logged_task) - { - skipEvent = 1; - } - - if (! RecorderDataPtr->recorderActive) + /* Skip the event if the same task is scheduled */ + if (task_handle == handle_of_last_logged_task) + { + skipEvent = 1; + } + + + if (!RecorderDataPtr->recorderActive) { skipEvent = 1; } /* If this event should be logged, log it! */ - if (skipEvent == 0) - { + if (skipEvent == 0) + { dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); - + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { - handle_of_last_logged_task = handle_of_running_task; + handle_of_last_logged_task = task_handle; ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); if (ts != NULL) @@ -382,17 +379,17 @@ void vTraceStoreTaskswitch(void) ts->dts = dts3; ts->objHandle = handle_of_last_logged_task; - vTraceSetObjectState(TRACE_CLASS_TASK, - handle_of_last_logged_task, + vTraceSetObjectState(TRACE_CLASS_TASK, + handle_of_last_logged_task, TASK_STATE_INSTANCE_ACTIVE); - prvTraceUpdateCounters(); + prvTraceUpdateCounters(); } } - } + } /* See comment on recorder_busy++ above. */ - recorder_busy--; + recorder_busy--; } /******************************************************************************* @@ -404,88 +401,102 @@ void vTraceStoreTaskswitch(void) * "old" one, valid up until this point. ******************************************************************************/ #if (INCLUDE_OBJECT_DELETE == 1) -void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, +void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, traceObjectClass objectclass) -{ +{ ObjCloseNameEvent * ce; const char * name; traceLabel idx; - name = PROPERTY_NAME_GET(objectclass, handle); + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceStoreObjectNameOnCloseEvent: objectclass >= TRACE_NCLASSES", ); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceStoreObjectNameOnCloseEvent: Invalid value for handle", ); - idx = prvTraceOpenSymbol(name, 0); - - // Interrupt disable not necessary, already done in trcHooks.h macro - ce = (ObjCloseNameEvent*) xTraceNextFreeEventBufferSlot(); - if (ce != NULL) - { - ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass; - ce->objHandle = handle; - ce->symbolIndex = idx; - prvTraceUpdateCounters(); - } - + if (RecorderDataPtr->recorderActive) + { + name = TRACE_PROPERTY_NAME_GET(objectclass, handle); + + idx = prvTraceOpenSymbol(name, 0); + + // Interrupt disable not necessary, already done in trcHooks.h macro + ce = (ObjCloseNameEvent*) xTraceNextFreeEventBufferSlot(); + if (ce != NULL) + { + ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass; + ce->objHandle = handle; + ce->symbolIndex = idx; + prvTraceUpdateCounters(); + } + } } -void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, +void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, traceObjectClass objectclass) { ObjClosePropEvent * pe; + + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceStoreObjectPropertiesOnCloseEvent: objectclass >= TRACE_NCLASSES", ); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceStoreObjectPropertiesOnCloseEvent: Invalid value for handle", ); - if (objectclass == TRACE_CLASS_ISR) - { - /* ISR handles should not be closed - never called for ISR */ - return; - } - - // Interrupt disable not necessary, already done in trcHooks.h macro - pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot(); - if (pe != NULL) - { - if (objectclass == TRACE_CLASS_TASK) - { - pe->arg1 = PROPERTY_ACTOR_PRIORITY(objectclass, handle); - pe->arg2 = PROPERTY_TASK_IFE_SERVICECODE(handle); - pe->arg3 = PROPERTY_TASK_IFE_OBJHANDLE(handle); - PROPERTY_TASK_IFE_SERVICECODE(handle) = 0; - PROPERTY_TASK_IFE_OBJHANDLE(handle) = 0; - }else{ - pe->arg1 = PROPERTY_OBJECT_STATE(objectclass, handle); - } - pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass; - prvTraceUpdateCounters(); - } + if (RecorderDataPtr->recorderActive) + { + // Interrupt disable not necessary, already done in trcHooks.h macro + pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot(); + if (pe != NULL) + { + if (objectclass == TRACE_CLASS_TASK) + { + pe->arg1 = TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, handle); + pe->arg2 = 0; // Legacy - IFE info removed. + pe->arg3 = 0; // Legacy - IFE info removed. + }else{ + pe->arg1 = TRACE_PROPERTY_OBJECT_STATE(objectclass, handle); + } + pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass; + prvTraceUpdateCounters(); + } + } } #endif void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value) { - PROPERTY_ACTOR_PRIORITY(objectclass, id) = value; + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceSetPriorityProperty: objectclass >= TRACE_NCLASSES", ); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceSetPriorityProperty: Invalid value for id", ); + + TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id) = value; } uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id) { - return PROPERTY_ACTOR_PRIORITY(objectclass, id); + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiTraceGetPriorityProperty: objectclass >= TRACE_NCLASSES", 0); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceGetPriorityProperty: Invalid value for id", 0); + + return TRACE_PROPERTY_ACTOR_PRIORITY(objectclass, id); } void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value) { - PROPERTY_OBJECT_STATE(objectclass, id) = value; + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "vTraceSetObjectState: objectclass >= TRACE_NCLASSES", ); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "vTraceSetObjectState: Invalid value for id", ); + + TRACE_PROPERTY_OBJECT_STATE(objectclass, id) = value; } -void vTraceSetTaskInstanceFinished(objectHandleType handle) +uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id) { -#if (USE_IMPLICIT_IFE_RULES == 1) - if (PROPERTY_TASK_IFE_SERVICECODE(handle) == 0) - { - PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0; - } -#endif + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "uiTraceGetObjectState: objectclass >= TRACE_NCLASSES", 0); + TRACE_ASSERT(id <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceGetObjectState: Invalid value for id", 0); + + return TRACE_PROPERTY_OBJECT_STATE(objectclass, id); } -uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id) +void vTraceSetTaskInstanceFinished(objectHandleType handle) { - return PROPERTY_OBJECT_STATE(objectclass, id); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_TASK], "vTraceSetTaskInstanceFinished: Invalid value for handle", ); + +#if (USE_IMPLICIT_IFE_RULES == 1) + TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0; +#endif } -#endif +#endif \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c new file mode 100644 index 000000000..427d770e2 --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.c @@ -0,0 +1,191 @@ +/******************************************************************************* + * Tracealyzer v2.4.1 Recorder Library + * Percepio AB, www.percepio.com + * + * trcKernelPort.c + * + * Kernel-specific functionality for FreeRTOS, used by the 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 trcHardwarePort.c/.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. + * + * Copyright Percepio AB, 2013. + * www.percepio.com + ******************************************************************************/ + +#include "trcKernelPort.h" + +#if (USE_TRACEALYZER_RECORDER == 1) + +#include + +#include "task.h" + +traceObjectClass TraceObjectClassTable[5] = { + TRACE_CLASS_QUEUE, + TRACE_CLASS_MUTEX, + TRACE_CLASS_SEMAPHORE, + TRACE_CLASS_SEMAPHORE, + TRACE_CLASS_MUTEX +}; + +extern unsigned char ucQueueGetQueueType(void*); +extern unsigned char ucQueueGetQueueNumber(void*); + +objectHandleType prvTraceGetObjectNumber(void* handle) +{ + return ucQueueGetQueueNumber(handle); +} + +unsigned char prvTraceGetObjectType(void* handle) +{ + return ucQueueGetQueueType(handle); +} + +objectHandleType prvTraceGetTaskNumber(void* handle) +{ + return (objectHandleType)uxTaskGetTaskNumber(handle); +} + +void prvTraceEnterCritical() +{ + taskENTER_CRITICAL(); +} + +void prvTraceExitCritical() +{ + taskEXIT_CRITICAL(); +} + +unsigned char prvTraceIsSchedulerActive() +{ + return xTaskGetSchedulerState() == taskSCHEDULER_RUNNING; +} + +unsigned char prvTraceIsSchedulerSuspended() +{ + return xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED; +} + +unsigned char prvTraceIsSchedulerStarted() +{ + return xTaskGetSchedulerState() != taskSCHEDULER_NOT_STARTED; +} + +void* prvTraceGetCurrentTaskHandle() +{ + return xTaskGetCurrentTaskHandle(); +} + +/* Initialization of the object property table */ +void vTraceInitObjectPropertyTable() +{ + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectClasses = TRACE_NCLASSES; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[0] = NQueue; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[1] = NSemaphore; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[2] = NMutex; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[3] = NTask; + RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[4] = NISR; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[0] = NameLenQueue; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[1] = NameLenSemaphore; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[2] = NameLenMutex; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[3] = NameLenTask; + RecorderDataPtr->ObjectPropertyTable.NameLengthPerClass[4] = NameLenISR; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[0] = PropertyTableSizeQueue; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[1] = PropertyTableSizeSemaphore; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[2] = PropertyTableSizeMutex; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[3] = PropertyTableSizeTask; + RecorderDataPtr->ObjectPropertyTable.TotalPropertyBytesPerClass[4] = PropertyTableSizeISR; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[0] = StartIndexQueue; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[1] = StartIndexSemaphore; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[2] = StartIndexMutex; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[3] = StartIndexTask; + RecorderDataPtr->ObjectPropertyTable.StartIndexOfClass[4] = StartIndexISR; + RecorderDataPtr->ObjectPropertyTable.ObjectPropertyTableSizeInBytes = TRACE_OBJECT_TABLE_SIZE; +} + +/* Initialization of the handle mechanism, see e.g, xTraceGetObjectHandle */ +void vTraceInitObjectHandleStack() +{ + objectHandleStacks.indexOfNextAvailableHandle[0] = 0; + objectHandleStacks.indexOfNextAvailableHandle[1] = NQueue; + objectHandleStacks.indexOfNextAvailableHandle[2] = NQueue + NSemaphore; + objectHandleStacks.indexOfNextAvailableHandle[3] = NQueue + NSemaphore + NMutex; + objectHandleStacks.indexOfNextAvailableHandle[4] = NQueue + NSemaphore + NMutex + NTask; + objectHandleStacks.lowestIndexOfClass[0] = 0; + objectHandleStacks.lowestIndexOfClass[1] = NQueue; + objectHandleStacks.lowestIndexOfClass[2] = NQueue + NSemaphore; + objectHandleStacks.lowestIndexOfClass[3] = NQueue + NSemaphore + NMutex; + objectHandleStacks.lowestIndexOfClass[4] = NQueue + NSemaphore + NMutex + NTask; + objectHandleStacks.highestIndexOfClass[0] = NQueue - 1; + objectHandleStacks.highestIndexOfClass[1] = NQueue + NSemaphore - 1; + objectHandleStacks.highestIndexOfClass[2] = NQueue + NSemaphore + NMutex - 1; + objectHandleStacks.highestIndexOfClass[3] = NQueue + NSemaphore + NMutex + NTask - 1; + objectHandleStacks.highestIndexOfClass[4] = NQueue + NSemaphore + NMutex + NTask + NISR - 1; +} + +/* Returns the "Not enough handles" error message for this object class */ +const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass) +{ + switch(objectclass) + { + case TRACE_CLASS_TASK: + return "Not enough TASK handles - increase NTask in trcConfig.h"; + case TRACE_CLASS_ISR: + return "Not enough ISR handles - increase NISR in trcConfig.h"; + case TRACE_CLASS_SEMAPHORE: + return "Not enough SEMAPHORE handles - increase NSemaphore in trcConfig.h"; + case TRACE_CLASS_MUTEX: + return "Not enough MUTEX handles - increase NMutex in trcConfig.h"; + case TRACE_CLASS_QUEUE: + return "Not enough QUEUE handles - increase NQueue in trcConfig.h"; + default: + return "pszTraceGetErrorHandles: Invalid objectclass!"; + } +} + +/* Returns the exclude state of the object */ +uint8_t uiTraceIsObjectExcluded(traceObjectClass objectclass, objectHandleType handle) +{ + TRACE_ASSERT(objectclass < TRACE_NCLASSES, "prvTraceIsObjectExcluded: objectclass >= TRACE_NCLASSES", 1); + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[objectclass], "uiTraceIsObjectExcluded: Invalid value for handle", 1); + + switch(objectclass) + { + case TRACE_CLASS_TASK: + return TRACE_GET_TASK_FLAG_ISEXCLUDED(handle); + case TRACE_CLASS_SEMAPHORE: + return TRACE_GET_SEMAPHORE_FLAG_ISEXCLUDED(handle); + case TRACE_CLASS_MUTEX: + return TRACE_GET_MUTEX_FLAG_ISEXCLUDED(handle); + case TRACE_CLASS_QUEUE: + return TRACE_GET_QUEUE_FLAG_ISEXCLUDED(handle); + } + + /* Must never reach */ + return 1; +} + +#endif \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.h b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.h new file mode 100644 index 000000000..25de1e74f --- /dev/null +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcKernelPort.h @@ -0,0 +1,749 @@ +/******************************************************************************* + * Tracealyzer v2.4.1 Recorder Library + * Percepio AB, www.percepio.com + * + * trcKernelPort.h + * + * Kernel-specific functionality for FreeRTOS, used by the 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 trcHardwarePort.c/.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. + * + * Copyright Percepio AB, 2013. + * www.percepio.com + ******************************************************************************/ + + +#ifndef TRCKERNELPORT_H_ +#define TRCKERNELPORT_H_ + +#include "FreeRTOS.h" // Defines configUSE_TRACE_FACILITY + +#define USE_TRACEALYZER_RECORDER configUSE_TRACE_FACILITY + +#if (USE_TRACEALYZER_RECORDER == 1) + +/* Defines that must be set for the recorder to work properly */ +#define TRACE_KERNEL_VERSION 0x1AA1 +#define TRACE_CPU_CLOCK_HZ configCPU_CLOCK_HZ /* Defined in "FreeRTOS.h" */ +#define TRACE_PERIPHERAL_CLOCK_HZ configPERIPHERAL_CLOCK_HZ /* Defined in "FreeRTOS.h" */ +#define TRACE_TICK_RATE_HZ configTICK_RATE_HZ /* Defined in "FreeRTOS.h" */ +#define TRACE_CPU_CLOCKS_PER_TICK configCPU_CLOCKS_PER_TICK /* Defined in "FreeRTOS.h" */ + +/************************************************************************/ +/* KERNEL SPECIFIC OBJECT CONFIGURATION */ +/************************************************************************/ +#define TRACE_NCLASSES 5 +#define TRACE_CLASS_QUEUE ((traceObjectClass)0) +#define TRACE_CLASS_SEMAPHORE ((traceObjectClass)1) +#define TRACE_CLASS_MUTEX ((traceObjectClass)2) +#define TRACE_CLASS_TASK ((traceObjectClass)3) +#define TRACE_CLASS_ISR ((traceObjectClass)4) + +#define TRACE_KERNEL_OBJECT_COUNT (NQueue + NSemaphore + NMutex + NTask + NISR) + +/* 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: legacy, not used + Byte 3: legacy, not used */ +#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 + +/* Number of bytes used by the object table */ +#define TRACE_OBJECT_TABLE_SIZE StartIndexISR + NISR * PropertyTableSizeISR + + +/* Includes */ +#include "trcTypes.h" +#include "trcConfig.h" +#include "trcKernelHooks.h" +#include "trcHardwarePort.h" +#include "trcBase.h" +#include "trcKernel.h" +#include "trcUser.h" + +/* Initialization of the object property table */ +void vTraceInitObjectPropertyTable(void); + +/* Initialization of the handle mechanism, see e.g, xTraceGetObjectHandle */ +void vTraceInitObjectHandleStack(void); + +/* Returns the "Not enough handles" error message for the specified object class */ +const char* pszTraceGetErrorNotEnoughHandles(traceObjectClass objectclass); + +/******************************************************************************* + * The event codes - should match the offline config file. + * + * Some sections below are encoded to allow for constructions like: + * + * vTraceStoreKernelCall(EVENTGROUP_CREATE + objectclass, ... + * + * The object class ID is given by the three LSB bits, in such cases. Since each + * object class has a separate object property table, the class ID is needed to + * know what section in the object table to use for getting an object name from + * an object handle. + ******************************************************************************/ + +#define NULL_EVENT (0x00) /* Ignored in the analysis*/ + +/******************************************************************************* + * EVENTGROUP_DIV + * + * Miscellaneous events. + ******************************************************************************/ +#define EVENTGROUP_DIV (NULL_EVENT + 1) /*0x01*/ +#define DIV_XPS (EVENTGROUP_DIV + 0) /*0x01*/ +#define DIV_TASK_READY (EVENTGROUP_DIV + 1) /*0x02*/ +#define DIV_NEW_TIME (EVENTGROUP_DIV + 2) /*0x03*/ + +/******************************************************************************* + * EVENTGROUP_TS + * + * Events for storing task-switches and interrupts. The RESUME events are + * generated if the task/interrupt is already marked active. + ******************************************************************************/ +#define EVENTGROUP_TS (EVENTGROUP_DIV + 3) /*0x04*/ +#define TS_ISR_BEGIN (EVENTGROUP_TS + 0) /*0x04*/ +#define TS_ISR_RESUME (EVENTGROUP_TS + 1) /*0x05*/ +#define TS_TASK_BEGIN (EVENTGROUP_TS + 2) /*0x06*/ +#define TS_TASK_RESUME (EVENTGROUP_TS + 3) /*0x07*/ + +/******************************************************************************* + * EVENTGROUP_OBJCLOSE_NAME + * + * About Close Events + * When an object is evicted from the object property table (object close), two + * internal events are stored (EVENTGROUP_OBJCLOSE_NAME and + * EVENTGROUP_OBJCLOSE_PROP), containing the handle-name mapping and object + * properties valid up to this point. + ******************************************************************************/ +#define EVENTGROUP_OBJCLOSE_NAME (EVENTGROUP_TS + 4) /*0x08*/ + +/******************************************************************************* + * EVENTGROUP_OBJCLOSE_PROP + * + * The internal event carrying properties of deleted objects + * The handle and object class of the closed object is not stored in this event, + * but is assumed to be the same as in the preceding CLOSE event. Thus, these + * two events must be generated from within a critical section. + * When queues are closed, arg1 is the "state" property (i.e., number of + * buffered messages/signals). + * When actors are closed, arg1 is priority, arg2 is handle of the "instance + * finish" event, and arg3 is event code of the "instance finish" event. + * In this case, the lower three bits is the object class of the instance finish + * handle. The lower three bits are not used (always zero) when queues are + * closed since the queue type is given in the previous OBJCLOSE_NAME event. + ******************************************************************************/ +#define EVENTGROUP_OBJCLOSE_PROP (EVENTGROUP_OBJCLOSE_NAME + 8) /*0x10*/ + +/******************************************************************************* + * EVENTGROUP_CREATE + * + * The events in this group are used to log Kernel object creations. + * The lower three bits in the event code gives the object class, i.e., type of + * create operation (task, queue, semaphore, etc). + ******************************************************************************/ +#define EVENTGROUP_CREATE_SUCCESS (EVENTGROUP_OBJCLOSE_PROP + 8) /*0x18*/ + +/******************************************************************************* + * EVENTGROUP_SEND + * + * The events in this group are used to log Send/Give events on queues, + * semaphores and mutexes The lower three bits in the event code gives the + * object class, i.e., what type of object that is operated on (queue, semaphore + * or mutex). + ******************************************************************************/ +#define EVENTGROUP_SEND_SUCCESS (EVENTGROUP_CREATE_SUCCESS + 8) /*0x20*/ + +/******************************************************************************* + * EVENTGROUP_RECEIVE + * + * The events in this group are used to log Receive/Take events on queues, + * semaphores and mutexes. The lower three bits in the event code gives the + * object class, i.e., what type of object that is operated on (queue, semaphore + * or mutex). + ******************************************************************************/ +#define EVENTGROUP_RECEIVE_SUCCESS (EVENTGROUP_SEND_SUCCESS + 8) /*0x28*/ + +/* Send/Give operations, from ISR */ +#define EVENTGROUP_SEND_FROM_ISR_SUCCESS (EVENTGROUP_RECEIVE_SUCCESS + 8) /*0x30*/ + +/* Receive/Take operations, from ISR */ +#define EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS (EVENTGROUP_SEND_FROM_ISR_SUCCESS + 8) /*0x38*/ + +/* "Failed" event type versions of above (timeout, failed allocation, etc) */ +#define EVENTGROUP_KSE_FAILED (EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS + 8) /*0x40*/ + +/* Failed create calls - memory allocation failed */ +#define EVENTGROUP_CREATE_FAILED (EVENTGROUP_KSE_FAILED) /*0x40*/ + +/* Failed send/give - timeout! */ +#define EVENTGROUP_SEND_FAILED (EVENTGROUP_CREATE_FAILED + 8) /*0x48*/ + +/* Failed receive/take - timeout! */ +#define EVENTGROUP_RECEIVE_FAILED (EVENTGROUP_SEND_FAILED + 8) /*0x50*/ + +/* Failed non-blocking send/give - queue full */ +#define EVENTGROUP_SEND_FROM_ISR_FAILED (EVENTGROUP_RECEIVE_FAILED + 8) /*0x58*/ + +/* Failed non-blocking receive/take - queue empty */ +#define EVENTGROUP_RECEIVE_FROM_ISR_FAILED \ + (EVENTGROUP_SEND_FROM_ISR_FAILED + 8) /*0x60*/ + +/* Events when blocking on receive/take */ +#define EVENTGROUP_RECEIVE_BLOCK \ + (EVENTGROUP_RECEIVE_FROM_ISR_FAILED + 8) /*0x68*/ + +/* Events when blocking on send/give */ +#define EVENTGROUP_SEND_BLOCK (EVENTGROUP_RECEIVE_BLOCK + 8) /*0x70*/ + +/* Events on queue peek (receive) */ +#define EVENTGROUP_PEEK_SUCCESS (EVENTGROUP_SEND_BLOCK + 8) /*0x78*/ + +/* Events on object delete (vTaskDelete or vQueueDelete) */ +#define EVENTGROUP_DELETE_SUCCESS (EVENTGROUP_PEEK_SUCCESS + 8) /*0x80*/ + +/* Other events - object class is implied: TASK */ +#define EVENTGROUP_OTHERS (EVENTGROUP_DELETE_SUCCESS + 8) /*0x88*/ +#define TASK_DELAY_UNTIL (EVENTGROUP_OTHERS + 0) /*0x88*/ +#define TASK_DELAY (EVENTGROUP_OTHERS + 1) /*0x89*/ +#define TASK_SUSPEND (EVENTGROUP_OTHERS + 2) /*0x8A*/ +#define TASK_RESUME (EVENTGROUP_OTHERS + 3) /*0x8B*/ +#define TASK_RESUME_FROM_ISR (EVENTGROUP_OTHERS + 4) /*0x8C*/ +#define TASK_PRIORITY_SET (EVENTGROUP_OTHERS + 5) /*0x8D*/ +#define TASK_PRIORITY_INHERIT (EVENTGROUP_OTHERS + 6) /*0x8E*/ +#define TASK_PRIORITY_DISINHERIT (EVENTGROUP_OTHERS + 7) /*0x8F*/ + +/* Not yet used */ +#define EVENTGROUP_FTRACE_PLACEHOLDER (EVENTGROUP_OTHERS + 8) /*0x90*/ + +/* User events */ +#define EVENTGROUP_USEREVENT (EVENTGROUP_FTRACE_PLACEHOLDER + 8) /*0x98*/ +#define USER_EVENT (EVENTGROUP_USEREVENT + 0) + +/* Allow for 0-15 arguments (the number of args is added to event code) */ +#define USER_EVENT_LAST (EVENTGROUP_USEREVENT + 15) /*0xA7*/ + +/******************************************************************************* + * XTS Event - eXtended TimeStamp events + * The timestamps used in the recorder are "differential timestamps" (DTS), i.e. + * the time since the last stored event. The DTS fields are either 1 or 2 bytes + * in the other events, depending on the bytes available in the event struct. + * If the time since the last event (the DTS) is larger than allowed for by + * the DTS field of the current event, an XTS event is inserted immediately + * before the original event. The XTS event contains up to 3 additional bytes + * of the DTS value - the higher bytes of the true DTS value. The lower 1-2 + * bytes are stored in the normal DTS field. + * There are two types of XTS events, XTS8 and XTS16. An XTS8 event is stored + * when there is only room for 1 byte (8 bit) DTS data in the original event, + * which means a limit of 0xFF (255). The XTS16 is used when the original event + * has a 16 bit DTS field and thereby can handle values up to 0xFFFF (65535). + * + * Using a very high frequency time base can result in many XTS events. + * Preferably, the time between two OS ticks should fit in 16 bits, i.e., + * at most 65535. If your time base has a higher frequency, you can define + * the TRACE + ******************************************************************************/ + +#define EVENTGROUP_SYS (EVENTGROUP_USEREVENT + 16) /*0xA8*/ +#define XTS8 (EVENTGROUP_SYS + 0) /*0xA8*/ +#define XTS16 (EVENTGROUP_SYS + 1) /*0xA9*/ + +#define EVENT_BEING_WRITTEN (EVENTGROUP_SYS + 2) /*0xAA*/ + +#define RESERVED_DUMMY_CODE (EVENTGROUP_SYS + 3) /*0xAB*/ + + + +/************************************************************************/ +/* KERNEL SPECIFIC DATA AND FUNCTIONS NEEDED TO PROVIDE THE */ +/* FUNCTIONALITY REQUESTED BY THE TRACE RECORDER */ +/************************************************************************/ + +/****************************************************************************** + * TraceObjectClassTable + * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_). + * This was added since we want to map both types of Mutex and both types of + * Semaphores on common classes for all Mutexes and all Semaphores respectively. + * + * FreeRTOS Queue types + * #define queueQUEUE_TYPE_BASE (0U) => TRACE_CLASS_QUEUE + * #define queueQUEUE_TYPE_MUTEX (1U) => TRACE_CLASS_MUTEX + * #define queueQUEUE_TYPE_COUNTING_SEMAPHORE (2U) => TRACE_CLASS_SEMAPHORE + * #define queueQUEUE_TYPE_BINARY_SEMAPHORE (3U) => TRACE_CLASS_SEMAPHORE + * #define queueQUEUE_TYPE_RECURSIVE_MUTEX (4U) => TRACE_CLASS_MUTEX + ******************************************************************************/ + +extern traceObjectClass TraceObjectClassTable[5]; + +/* These functions are implemented in the .c file since certain header files must not be included in this one */ +objectHandleType prvTraceGetObjectNumber(void* handle); +unsigned char prvTraceGetObjectType(void* handle); +objectHandleType prvTraceGetTaskNumber(void* handle); +unsigned char prvTraceIsSchedulerActive(void); +unsigned char prvTraceIsSchedulerSuspended(void); +unsigned char prvTraceIsSchedulerStarted(void); +void prvTraceEnterCritical(void); +void prvTraceExitCritical(void); +void* prvTraceGetCurrentTaskHandle(void); + + +/************************************************************************/ +/* KERNEL SPECIFIC MACROS USED BY THE TRACE RECORDER */ +/************************************************************************/ + +#define TRACE_MALLOC(size) pvPortMalloc(size) + +#define TRACE_ENTER_CRITICAL_SECTION() prvTraceEnterCritical(); +#define TRACE_EXIT_CRITICAL_SECTION() prvTraceExitCritical(); + +#define TRACE_IS_SCHEDULER_ACTIVE() prvTraceIsSchedulerActive() +#define TRACE_IS_SCHEDULER_STARTED() prvTraceIsSchedulerStarted() +#define TRACE_IS_SCHEDULER_SUSPENDED() prvTraceIsSchedulerSuspended() +#define TRACE_GET_CURRENT_TASK() prvTraceGetCurrentTaskHandle() + +#define TRACE_GET_TASK_PRIORITY(pxTCB) ((uint8_t)pxTCB->uxPriority) +#define TRACE_GET_TASK_NAME(pxTCB) ((char*)pxTCB->pcTaskName) +#define TRACE_GET_TASK_NUMBER(pxTCB) (prvTraceGetTaskNumber(pxTCB)) +#define TRACE_SET_TASK_NUMBER(pxTCB) pxTCB->uxTaskNumber = xTraceGetObjectHandle(TRACE_CLASS_TASK); + +#define TRACE_GET_CLASS_TRACE_CLASS(CLASS, kernelClass) TraceObjectClassTable[kernelClass] +#define TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject) TRACE_GET_CLASS_TRACE_CLASS(CLASS, prvTraceGetObjectType(pxObject)) + +#define TRACE_GET_OBJECT_NUMBER(CLASS, pxObject) (prvTraceGetObjectNumber(pxObject)) +#define TRACE_SET_OBJECT_NUMBER(CLASS, pxObject) pxObject->ucQueueNumber = xTraceGetObjectHandle(TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)); + +#define TRACE_GET_CLASS_EVENT_CODE(SERVICE, RESULT, CLASS, kernelClass) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_CLASS_TRACE_CLASS(CLASS, kernelClass)) +#define TRACE_GET_OBJECT_EVENT_CODE(SERVICE, RESULT, CLASS, pxObject) (uint8_t)(EVENTGROUP_##SERVICE##_##RESULT + TRACE_GET_OBJECT_TRACE_CLASS(CLASS, pxObject)) +#define TRACE_GET_TASK_EVENT_CODE(SERVICE, RESULT, CLASS, pxTCB) (EVENTGROUP_##SERVICE##_##RESULT + TRACE_CLASS_TASK) + + + +/************************************************************************/ +/* KERNEL SPECIFIC WRAPPERS THAT SHOULD BE CALLED BY THE KERNEL */ +/************************************************************************/ + +/* Called for each task that becomes ready */ +#undef traceMOVED_TASK_TO_READY_STATE +#define traceMOVED_TASK_TO_READY_STATE( pxTCB ) \ + trcKERNEL_HOOKS_MOVED_TASK_TO_READY_STATE(pxTCB); + +/* Called on each OS tick. Will call uiPortGetTimestamp to make sure it is called at least once every OS tick. */ +#undef traceTASK_INCREMENT_TICK +#define traceTASK_INCREMENT_TICK( xTickCount ) \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdTRUE || uxMissedTicks == 0) { trcKERNEL_HOOKS_INCREMENT_TICK(); } \ + if (uxSchedulerSuspended == ( unsigned portBASE_TYPE ) pdFALSE) { trcKERNEL_HOOKS_NEW_TIME(DIV_NEW_TIME, xTickCount + 1); } + +/* Called on each task-switch */ +#undef traceTASK_SWITCHED_IN +#define traceTASK_SWITCHED_IN() \ + trcKERNEL_HOOKS_TASK_SWITCH(TRACE_GET_CURRENT_TASK()); + +/* Called on vTaskSuspend */ +#undef traceTASK_SUSPEND +#define traceTASK_SUSPEND( pxTaskToSuspend ) \ + trcKERNEL_HOOKS_TASK_SUSPEND(TASK_SUSPEND, pxTaskToSuspend); + +/* Called on vTaskDelay - note the use of FreeRTOS variable xTicksToDelay */ +#undef traceTASK_DELAY +#define traceTASK_DELAY() \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY, pxCurrentTCB, xTicksToDelay); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(UNUSED,pxCurrentTCB); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called on vTaskDelayUntil - note the use of FreeRTOS variable xTimeToWake */ +#undef traceTASK_DELAY_UNTIL +#define traceTASK_DELAY_UNTIL() \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_TASK_DELAY(TASK_DELAY_UNTIL, pxCurrentTCB, xTimeToWake); \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(UNUSED,pxCurrentTCB); \ + TRACE_EXIT_CRITICAL_SECTION(); + +#if (INCLUDE_OBJECT_DELETE == 1) +/* Called on vTaskDelete */ +#undef traceTASK_DELETE +#define traceTASK_DELETE( pxTaskToDelete ) \ + trcKERNEL_HOOKS_TASK_DELETE(DELETE, pxTaskToDelete); +#endif + +#if (INCLUDE_OBJECT_DELETE == 1) +/* Called on vQueueDelete */ +#undef traceQUEUE_DELETE +#define traceQUEUE_DELETE( pxQueue ) \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_DELETE(DELETE, UNUSED, pxQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); +#endif + +/* Called on vTaskCreate */ +#undef traceTASK_CREATE +#define traceTASK_CREATE(pxNewTCB) \ + if (pxNewTCB != NULL) \ + { \ + trcKERNEL_HOOKS_TASK_CREATE(CREATE, pxNewTCB); \ + } + +/* Called in vTaskCreate, if it fails (typically if the stack can not be allocated) */ +#undef traceTASK_CREATE_FAILED +#define traceTASK_CREATE_FAILED() \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_TASK_CREATE_FAILED(CREATE); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called in xQueueCreate, and thereby for all other object based on queues, such as semaphores. */ +#undef traceQUEUE_CREATE +#define traceQUEUE_CREATE( pxNewQueue )\ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_CREATE(CREATE, UNUSED, pxNewQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called in xQueueCreate, if the queue creation fails */ +#undef traceQUEUE_CREATE_FAILED +#define traceQUEUE_CREATE_FAILED( queueType ) \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_CREATE_FAILED(CREATE, UNUSED, queueType); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called in xQueueCreateMutex, and thereby also from xSemaphoreCreateMutex and xSemaphoreCreateRecursiveMutex */ +#undef traceCREATE_MUTEX +#define traceCREATE_MUTEX( pxNewQueue ) \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_CREATE(CREATE, UNUSED, pxNewQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called in xQueueCreateMutex when the operation fails (when memory allocation fails) */ +#undef traceCREATE_MUTEX_FAILED +#define traceCREATE_MUTEX_FAILED() \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_OBJECT_CREATE_FAILED(CREATE, UNUSED, queueQUEUE_TYPE_MUTEX); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called when the Mutex can not be given, since not holder */ +#undef traceGIVE_MUTEX_RECURSIVE_FAILED +#define traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ) \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, FAILED, UNUSED, pxMutex); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called when a message is sent to a queue */ +#undef traceQUEUE_SEND +#define traceQUEUE_SEND( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, SUCCESS, UNUSED, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(UNUSED, pxQueue, TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, pxQueue) == TRACE_CLASS_MUTEX ? (uint8_t)0 : (uint8_t)(pxQueue->uxMessagesWaiting + 1)); /*For mutex, store the new owner rather than queue length */ + +/* Called when a message failed to be sent to a queue (timeout) */ +#undef traceQUEUE_SEND_FAILED +#define traceQUEUE_SEND_FAILED( pxQueue ) \ + TRACE_ENTER_CRITICAL_SECTION();\ + trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, FAILED, UNUSED, pxQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called when the task is blocked due to a send operation on a full queue */ +#undef traceBLOCKING_ON_QUEUE_SEND +#define traceBLOCKING_ON_QUEUE_SEND( pxQueue ) \ + TRACE_ENTER_CRITICAL_SECTION();\ + trcKERNEL_HOOKS_KERNEL_SERVICE(SEND, BLOCK, UNUSED, pxQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called when a message is received from a queue */ +#undef traceQUEUE_RECEIVE +#define traceQUEUE_RECEIVE( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE, SUCCESS, UNUSED, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(UNUSED, pxQueue, TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, pxQueue) == TRACE_CLASS_MUTEX ? TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK()) : (uint8_t)(pxQueue->uxMessagesWaiting - 1)); /*For mutex, store the new owner rather than queue length */ + +/* Called when a receive operation on a queue fails (timeout) */ +#undef traceQUEUE_RECEIVE_FAILED +#define traceQUEUE_RECEIVE_FAILED( pxQueue ) \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE, FAILED, UNUSED, pxQueue); \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called when the task is blocked due to a receive operation on an empty queue */ +#undef traceBLOCKING_ON_QUEUE_RECEIVE +#define traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ) \ + TRACE_ENTER_CRITICAL_SECTION(); \ + trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE, BLOCK, UNUSED, pxQueue); \ + if (TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, pxQueue) != TRACE_CLASS_MUTEX) \ + { \ + trcKERNEL_HOOKS_SET_TASK_INSTANCE_FINISHED(UNUSED, pxQueue); \ + } \ + TRACE_EXIT_CRITICAL_SECTION(); + +/* Called on xQueuePeek */ +#undef traceQUEUE_PEEK +#define traceQUEUE_PEEK( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(PEEK, SUCCESS, UNUSED, pxQueue); + +/* Called when a message is sent from interrupt context, e.g., using xQueueSendFromISR */ +#undef traceQUEUE_SEND_FROM_ISR +#define traceQUEUE_SEND_FROM_ISR( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(SEND_FROM_ISR, SUCCESS, UNUSED, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(UNUSED, pxQueue, (uint8_t)(pxQueue->uxMessagesWaiting + 1)); + +/* Called when a message send from interrupt context fails (since the queue was full) */ +#undef traceQUEUE_SEND_FROM_ISR_FAILED +#define traceQUEUE_SEND_FROM_ISR_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(SEND_FROM_ISR, FAILED, UNUSED, pxQueue); + +/* Called when a message is received in interrupt context, e.g., using xQueueReceiveFromISR */ +#undef traceQUEUE_RECEIVE_FROM_ISR +#define traceQUEUE_RECEIVE_FROM_ISR( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE_FROM_ISR, SUCCESS, UNUSED, pxQueue); \ + trcKERNEL_HOOKS_SET_OBJECT_STATE(UNUSED, pxQueue, (uint8_t)(pxQueue->uxMessagesWaiting - 1)); + +/* Called when a message receive from interrupt context fails (since the queue was empty) */ +#undef traceQUEUE_RECEIVE_FROM_ISR_FAILED +#define traceQUEUE_RECEIVE_FROM_ISR_FAILED( pxQueue ) \ + trcKERNEL_HOOKS_KERNEL_SERVICE(RECEIVE_FROM_ISR, FAILED, UNUSED, pxQueue); + +/* Called in vTaskPrioritySet */ +#undef traceTASK_PRIORITY_SET +#define traceTASK_PRIORITY_SET( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_SET, pxTask, uxNewPriority); + +/* Called in vTaskPriorityInherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_INHERIT +#define traceTASK_PRIORITY_INHERIT( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_INHERIT, pxTask, uxNewPriority); + +/* Called in vTaskPriorityDisinherit, which is called by Mutex operations */ +#undef traceTASK_PRIORITY_DISINHERIT +#define traceTASK_PRIORITY_DISINHERIT( pxTask, uxNewPriority ) \ + trcKERNEL_HOOKS_TASK_PRIORITY_CHANGE(TASK_PRIORITY_DISINHERIT, pxTask, uxNewPriority); + +/* Called in vTaskResume */ +#undef traceTASK_RESUME +#define traceTASK_RESUME( pxTaskToResume ) \ + trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME, pxTaskToResume); + +/* Called in vTaskResumeFromISR */ +#undef traceTASK_RESUME_FROM_ISR +#define traceTASK_RESUME_FROM_ISR( pxTaskToResume ) \ + trcKERNEL_HOOKS_TASK_RESUME(TASK_RESUME_FROM_ISR, pxTaskToResume); + + +/************************************************************************/ +/* KERNEL SPECIFIC MACROS TO EXCLUDE OR INCLUDE THINGS IN TRACE */ +/************************************************************************/ + +/* Returns the exclude state of the object */ +uint8_t uiTraceIsObjectExcluded(traceObjectClass objectclass, objectHandleType handle); + +#define TRACE_SET_QUEUE_FLAG_ISEXCLUDED(queueIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, queueIndex) +#define TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(queueIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, queueIndex) +#define TRACE_GET_QUEUE_FLAG_ISEXCLUDED(queueIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, queueIndex) + +#define TRACE_SET_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+semaphoreIndex) +#define TRACE_CLEAR_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+semaphoreIndex) +#define TRACE_GET_SEMAPHORE_FLAG_ISEXCLUDED(semaphoreIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+semaphoreIndex) + +#define TRACE_SET_MUTEX_FLAG_ISEXCLUDED(mutexIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+mutexIndex) +#define TRACE_CLEAR_MUTEX_FLAG_ISEXCLUDED(mutexIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+mutexIndex) +#define TRACE_GET_MUTEX_FLAG_ISEXCLUDED(mutexIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+mutexIndex) + +#define TRACE_SET_TASK_FLAG_ISEXCLUDED(taskIndex) TRACE_SET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+taskIndex) +#define TRACE_CLEAR_TASK_FLAG_ISEXCLUDED(taskIndex) TRACE_CLEAR_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+taskIndex) +#define TRACE_GET_TASK_FLAG_ISEXCLUDED(taskIndex) TRACE_GET_FLAG_ISEXCLUDED(excludedObjects, NQueue+1+NSemaphore+1+NMutex+1+taskIndex) + +#define TRACE_CLEAR_OBJECT_FLAG_ISEXCLUDED(objectclass, handle) \ +switch (objectclass) \ +{ \ +case TRACE_CLASS_QUEUE: \ + TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(handle); \ + break; \ +case TRACE_CLASS_SEMAPHORE: \ + TRACE_CLEAR_SEMAPHORE_FLAG_ISEXCLUDED(handle); \ + break; \ +case TRACE_CLASS_MUTEX: \ + TRACE_CLEAR_MUTEX_FLAG_ISEXCLUDED(handle); \ + break; \ +case TRACE_CLASS_TASK: \ + TRACE_CLEAR_TASK_FLAG_ISEXCLUDED(handle); \ + break; \ +} + +#define TRACE_SET_OBJECT_FLAG_ISEXCLUDED(objectclass, handle) \ +switch (objectclass) \ +{ \ +case TRACE_CLASS_QUEUE: \ + TRACE_SET_QUEUE_FLAG_ISEXCLUDED(handle); \ + break; \ +case TRACE_CLASS_SEMAPHORE: \ + TRACE_SET_SEMAPHORE_FLAG_ISEXCLUDED(handle); \ + break; \ +case TRACE_CLASS_MUTEX: \ + TRACE_SET_MUTEX_FLAG_ISEXCLUDED(handle); \ + break; \ +case TRACE_CLASS_TASK: \ + TRACE_SET_TASK_FLAG_ISEXCLUDED(handle); \ + break; \ +} + +/* Task */ +#define vTraceExcludeTaskFromTrace(handle) \ +TRACE_SET_TASK_FLAG_ISEXCLUDED(TRACE_GET_TASK_NUMBER(handle)); + +#define vTraceIncludeTaskInTrace(handle) \ +TRACE_CLEAR_TASK_FLAG_ISEXCLUDED(TRACE_GET_TASK_NUMBER(handle)); + + +/* Queue */ +#define vTraceExcludeQueueFromTrace(handle) \ +TRACE_SET_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); + +#define vTraceIncludeQueueInTrace(handle) \ +TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); + + +/* Semaphore */ +#define vTraceExcludeSemaphoreFromTrace(handle) \ +TRACE_SET_SEMAPHORE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); + +#define vTraceIncludeSemaphoreInTrace(handle) \ +TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); + + +/* Mutex */ +#define vTraceExcludeMutexFromTrace(handle) \ +TRACE_SET_MUTEX_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); + +#define vTraceIncludeMutexInTrace(handle) \ +TRACE_CLEAR_QUEUE_FLAG_ISEXCLUDED(TRACE_GET_OBJECT_NUMBER(UNUSED, handle)); + + +/* Kernel Services */ +#define vTraceExcludeKernelServiceDelayFromTrace() \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY_UNTIL); + +#define vTraceIncludeKernelServiceDelayInTrace() \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY_UNTIL); + +/* HELPER MACROS FOR KERNEL SERVICES FOR OBJECTS */ +#define vTraceExcludeKernelServiceSendFromTrace_HELPER(class) \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_SUCCESS + class); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_BLOCK + class); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FAILED + class); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR_SUCCESS + class); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR_FAILED + class); + +#define vTraceIncludeKernelServiceSendInTrace_HELPER(class) \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_SUCCESS + class); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_BLOCK + class); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FAILED + class); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR_SUCCESS + class); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR_FAILED + class); + +#define vTraceExcludeKernelServiceReceiveFromTrace_HELPER(class) \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_SUCCESS + class); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_BLOCK + class); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FAILED + class); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS + class); \ +TRACE_SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR_FAILED + class); + +#define vTraceIncludeKernelServiceReceiveInTrace_HELPER(class) \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_SUCCESS + class); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_BLOCK + class); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FAILED + class); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR_SUCCESS + class); \ +TRACE_CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR_FAILED + class); + +/* EXCLUDE AND INCLUDE FOR QUEUE */ +#define vTraceExcludeKernelServiceQueueSendFromTrace() \ +vTraceExcludeKernelServiceSendFromTrace_HELPER(TRACE_CLASS_QUEUE); + +#define vTraceIncludeKernelServiceQueueSendInTrace() \ +vTraceIncludeKernelServiceSendInTrace_HELPER(TRACE_CLASS_QUEUE); + +#define vTraceExcludeKernelServiceQueueReceiveFromTrace() \ +vTraceExcludeKernelServiceReceiveFromTrace_HELPER(TRACE_CLASS_QUEUE); + +#define vTraceIncludeKernelServiceQueueReceiveInTrace() \ +vTraceIncludeKernelServiceReceiveInTrace_HELPER(TRACE_CLASS_QUEUE); + +/* EXCLUDE AND INCLUDE FOR SEMAPHORE */ +#define vTraceExcludeKernelServiceSemaphoreSendFromTrace() \ +vTraceExcludeKernelServiceSendFromTrace_HELPER(TRACE_CLASS_SEMAPHORE); + +#define vTraceIncludeKernelServicSemaphoreSendInTrace() \ +vTraceIncludeKernelServiceSendInTrace_HELPER(TRACE_CLASS_SEMAPHORE); + +#define vTraceExcludeKernelServiceSemaphoreReceiveFromTrace() \ +vTraceExcludeKernelServiceReceiveFromTrace_HELPER(TRACE_CLASS_SEMAPHORE); + +#define vTraceIncludeKernelServiceSemaphoreReceiveInTrace() \ +vTraceIncludeKernelServiceReceiveInTrace_HELPER(TRACE_CLASS_SEMAPHORE); + +/* EXCLUDE AND INCLUDE FOR MUTEX */ +#define vTraceExcludeKernelServiceMutexSendFromTrace() \ +vTraceExcludeKernelServiceSendFromTrace_HELPER(TRACE_CLASS_MUTEX); + +#define vTraceIncludeKernelServiceMutexSendInTrace() \ +vTraceIncludeKernelServiceSendInTrace_HELPER(TRACE_CLASS_MUTEX); + +#define vTraceExcludeKernelServiceMutexReceiveFromTrace() \ +vTraceExcludeKernelServiceReceiveFromTrace_HELPER(TRACE_CLASS_MUTEX); + +#define vTraceIncludeKernelServiceMutexReceiveInTrace() \ +vTraceIncludeKernelServiceReceiveInTrace_HELPER(TRACE_CLASS_MUTEX); + +/************************************************************************/ +/* KERNEL SPECIFIC MACROS TO NAME OBJECTS, IF NECESSARY */ +/************************************************************************/ +#define vTraceSetQueueName(object, name) \ +vTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, object), TRACE_GET_OBJECT_NUMBER(UNUSED, object), name); + +#define vTraceSetSemaphoreName(object, name) \ +vTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, object), TRACE_GET_OBJECT_NUMBER(UNUSED, object), name); + +#define vTraceSetMutexName(object, name) \ +vTraceSetObjectName(TRACE_GET_OBJECT_TRACE_CLASS(UNUSED, object), TRACE_GET_OBJECT_NUMBER(UNUSED, object), name); + +#endif + +#endif /* TRCKERNELPORT_H_ */ \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcPort.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcPort.c deleted file mode 100644 index e98dd57a8..000000000 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcPort.c +++ /dev/null @@ -1,208 +0,0 @@ -/******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library - * Percepio AB, www.percepio.com - * - * trcPort.c - * - * Contains all portability issues of the trace recorder library. - * See also trcPort.h, where port-specific macros are defined. - * - * 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. - * - * OFFER FROM PERCEPIO: - * For silicon companies and non-corporate FreeRTOS users (researchers, students - * , hobbyists or early-phase startups) we have an attractive offer: - * Provide a hardware timer port and get a FREE single-user licence for - * FreeRTOS+Trace Professional Edition. Read more about this offer at - * www.percepio.com or contact us directly at support@percepio.com. - * - * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. - * www.percepio.com - ******************************************************************************/ - -#include "trcUser.h" - -#if (configUSE_TRACE_FACILITY == 1) - -#if (INCLUDE_SAVE_TO_FILE == 1) -static char* prvFileName = NULL; -#endif - - -/******************************************************************************* - * uiTraceTickCount - * - * This variable is updated by the traceTASK_INCREMENT_TICK macro in the - * FreeRTOS tick handler. This does not need to be modified when developing a - * new timer port. It is prefered to keep any timer port changes in the HWTC - * macro definitions, which typically give sufficient flexibility. - ******************************************************************************/ -uint32_t uiTraceTickCount = 0; - -/****************************************************************************** - * uiTracePortGetTimeStamp - * - * Returns the current time based on the HWTC macros which provide a hardware - * isolation layer towards the hardware timer/counter. - * - * The HWTC macros and uiTracePortGetTimeStamp is the main porting issue - * or the trace recorder library. Typically you should not need to change - * the code of uiTracePortGetTimeStamp if using the HWTC macros. - * - * OFFER FROM PERCEPIO: - * For silicon companies and non-corporate FreeRTOS users (researchers, students - * , hobbyists or early-phase startups) we have an attractive offer: - * Provide a hardware timer port and get a FREE single-user license for - * FreeRTOS+Trace Professional Edition. Read more about this offer at - * www.percepio.com or contact us directly at support@percepio.com. - ******************************************************************************/ -void uiTracePortGetTimeStamp(uint32_t *pTimestamp) -{ - static uint32_t last_traceTickCount = 0; - static uint32_t last_hwtc_count = 0; - uint32_t traceTickCount = 0; - uint32_t hwtc_count = 0; - - /* Retrieve HWTC_COUNT only once since the same value should be used all throughout this function. */ -#if (HWTC_COUNT_DIRECTION == DIRECTION_INCREMENTING) - hwtc_count = HWTC_COUNT; -#elif (HWTC_COUNT_DIRECTION == DIRECTION_DECREMENTING) - hwtc_count = HWTC_PERIOD - HWTC_COUNT; -#else - Junk text to cause compiler error - HWTC_COUNT_DIRECTION is not set correctly! - Should be DIRECTION_INCREMENTING or DIRECTION_DECREMENTING -#endif - - if (last_traceTickCount - uiTraceTickCount - 1 < 0x80000000) - { - /* This means last_traceTickCount is higher than uiTraceTickCount, - so we have previously compensated for a missed tick. - Therefore we use the last stored value because that is more accurate. */ - traceTickCount = last_traceTickCount; - } - else - { - /* Business as usual */ - traceTickCount = uiTraceTickCount; - } - - /* Check for overflow. May occur if the update of uiTraceTickCount has been - delayed due to disabled interrupts. */ - if (traceTickCount == last_traceTickCount && hwtc_count < last_hwtc_count) - { - /* A trace tick has occurred but not been executed by the kernel, so we compensate manually. */ - traceTickCount++; - } - - /* Check if the return address is OK, then we perform the calculation. */ - if (pTimestamp) - { - /* Get timestamp from trace ticks. Scale down the period to avoid unwanted overflows. */ - *pTimestamp = traceTickCount * (HWTC_PERIOD / HWTC_DIVISOR); - /* Increase timestamp by (hwtc_count + "lost hardware ticks from scaling down period") / HWTC_DIVISOR. */ - *pTimestamp += (hwtc_count + traceTickCount * (HWTC_PERIOD % HWTC_DIVISOR)) / HWTC_DIVISOR; - } - - /* Store the previous values. */ - last_traceTickCount = traceTickCount; - last_hwtc_count = hwtc_count; -} - -/******************************************************************************* - * vTracePortEnd - * - * This function is called by the monitor when a recorder stop is detected. - * This is used by the Win32 port to store the trace to a file. The file path is - * set using vTracePortSetOutFile. - ******************************************************************************/ -void vTracePortEnd() -{ - vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Running vTracePortEnd.\n\r"); - - #if (WIN32_PORT_SAVE_WHEN_STOPPED == 1) - vTracePortSave(); - #endif - - #if (WIN32_PORT_EXIT_WHEN_STOPPED == 1) - /* In the FreeRTOS/Win32 demo, this allows for killing the application - when the recorder is stopped (e.g., when the buffer is full) */ - system("pause"); - exit(0); - #endif -} - -#if (INCLUDE_SAVE_TO_FILE == 1) -/******************************************************************************* - * vTracePortSetOutFile - * - * Sets the filename/path used in vTracePortSave. - * This is set in a separate function, since the Win32 port calls vTracePortSave - * in vTracePortEnd if WIN32_PORT_SAVE_WHEN_STOPPED is set. - ******************************************************************************/ -void vTracePortSetOutFile(char* path) -{ - prvFileName = path; -} - -/******************************************************************************* - * vTracePortSave - * - * Saves the trace to a file on a local file system. The path is set in a - * separate function, vTracePortSetOutFile, since the Win32 port calls - * vTracePortSave in vTracePortEnd if WIN32_PORT_SAVE_WHEN_STOPPED is set. - ******************************************************************************/ -void vTracePortSave() -{ - char buf[180]; - FILE* f; - - if (prvFileName == NULL) - { - prvFileName = "FreeRTOSPlusTrace.dump"; - sprintf(buf, "No filename specified, using default \"%s\".", prvFileName); - vTraceConsoleMessage(buf); - } - - fopen_s(&f, prvFileName, "wb"); - if (f) - { - fwrite(RecorderDataPtr, sizeof(RecorderDataType), 1, f); - fclose(f); - sprintf(buf, "\n\r[FreeRTOS+Trace] Saved in: %s\n\r", prvFileName); - vTraceConsoleMessage(buf); - } - else - { - sprintf(buf, "\n\r[FreeRTOS+Trace] Failed to write to output file!\n\r"); - vTraceConsoleMessage(buf); - } -} -#endif -#endif \ No newline at end of file diff --git a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c index 2e4bc1aac..3f33cc004 100644 --- a/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c +++ b/FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c @@ -1,5 +1,5 @@ /******************************************************************************* - * FreeRTOS+Trace v2.3.0 Recorder Library + * Tracealyzer v2.4.1 Recorder Library * Percepio AB, www.percepio.com * * trcUser.c @@ -9,44 +9,41 @@ * 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 + * in its original form, including modifications in trcHardwarePort.c/.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 + * 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 + * 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.com/products/downloads/ - * - * Copyright Percepio AB, 2012. + * Copyright Percepio AB, 2013. * www.percepio.com ******************************************************************************/ +#include "trcUser.h" + +#if (USE_TRACEALYZER_RECORDER == 1) + #include #include +#include -#include "trcUser.h" -#include "task.h" -#include "semphr.h" - -#if (configUSE_TRACE_FACILITY == 1) +TRACE_STOP_HOOK vTraceStopHookPtr = (TRACE_STOP_HOOK)0; extern uint8_t inExcludedTask; extern uint8_t nISRactive; @@ -55,145 +52,104 @@ extern uint32_t dts_min; extern uint32_t hwtc_count_max_after_tick; extern uint32_t hwtc_count_sum_after_tick; extern uint32_t hwtc_count_sum_after_tick_counter; -extern unsigned char ucQueueGetQueueType(void*); -extern unsigned char ucQueueGetQueueNumber(void*); extern char* traceErrorMessage; -static void vTraceMonitorTask(void); -static void prvTraceExcludeOrIncludeKernelServiceFromTrace(traceKernelService, uint8_t); - + +/*** private functions *******************************************************/ +void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list vl); + +#if (USE_SEPARATE_USER_EVENT_BUFFER == 1) +void vTraceChannelPrintF_Helper(UserEventChannel channelPair, va_list vl); +static void prvTraceUserEventHelper1(UserEventChannel channel, traceLabel eventLabel, traceLabel formatLabel, va_list vl); +static void prvTraceUserEventHelper2(UserEventChannel channel, uint32_t* data, uint32_t noOfSlots); +#endif +/*****************************************************************************/ + + + /******************************************************************************* - * vTraceMonitorTask + * vTraceInitTraceData * - * A task which periodically reports the recorder status to the console. - * This is included depending on USE_TRACE_PROGRESS_MONITOR_TASK. + * Allocates, if necessary, and initializes the recorder data structure, based + * on the constants in trcConfig.h. ******************************************************************************/ -static void vTraceMonitorTask(void) -{ - portTickType xNextWakeTime; - char localsprintbuffer[90]; - char* err = NULL; - char* lastErr = NULL; - #define STATE_INIT 0 - #define STATE_STARTED 1 - #define STATE_STOPPED 2 - int state = STATE_INIT; - - vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Monitor task started...\n\r"); - - /* Initialise xNextWakeTime - this only needs to be done once. */ - xNextWakeTime = xTaskGetTickCount(); - - for (;;) - { - lastErr = err; - err = xTraceGetLastError(); - if (err != lastErr) - { - sprintf(localsprintbuffer, "\n\r[FreeRTOS+Trace] Error: %s\n\r", err); - vTraceConsoleMessage(localsprintbuffer); - } - - if (state == STATE_STOPPED || state == STATE_INIT) - { - if (RecorderDataPtr->recorderActive == 1) - { - state = STATE_STARTED; - vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Recorder started.\n\r"); - } - else - { - if (state == STATE_INIT) - { - - vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Recorder not started.\n\r"); - state = STATE_STOPPED; - } - } - } - - if (state == STATE_STARTED) - { - if (RecorderDataPtr->frequency > 0) - { - sprintf(localsprintbuffer, - "\n\r[FreeRTOS+Trace] Event count: %d, Duration: %d ms. [%d ticks]\n\r", - (int)RecorderDataPtr->numEvents, - (int)(RecorderDataPtr->absTimeLastEventSecond*1000 + (RecorderDataPtr->absTimeLastEvent*1000)/ RecorderDataPtr->frequency), (int)xTaskGetTickCount()); - vTraceConsoleMessage(localsprintbuffer); - } - - if (RecorderDataPtr->recorderActive == 0) - { - state = STATE_STOPPED; - vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Recorder stopped.\n\r"); - vTracePortEnd(); - } - - - } +void vTraceInitTraceData(void) +{ + prvTraceInitTraceData(); +} - /* Place this task in the blocked state until it is time to run again. */ - vTaskDelayUntil( &xNextWakeTime, TRACE_PROGRESS_MONITOR_TASK_PERIOD); - - } +/******************************************************************************* + * vTraceSetRecorderData + * + * If custom allocation is used, this function must be called so the recorder + * library knows where to save the trace data. + ******************************************************************************/ +#if TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_CUSTOM +void vTraceSetRecorderData(void* pRecorderData) +{ + TRACE_ASSERT(pRecorderData != NULL, "vTraceSetTraceData, pRecorderData == NULL", ); + RecorderDataPtr = pRecorderData; } +#endif /******************************************************************************* * vTraceClear * - * Resets the recorder. Only necessary if a restart is desired - this is not + * Resets the recorder. Only necessary if a restart is desired - this is not * needed in the startup initialization. ******************************************************************************/ void vTraceClear(void) { trcCRITICAL_SECTION_BEGIN(); - + RecorderDataPtr->absTimeLastEvent = 0; RecorderDataPtr->nextFreeIndex = 0; RecorderDataPtr->numEvents = 0; RecorderDataPtr->bufferIsFull = 0; trcCRITICAL_SECTION_END(); - -} -/******************************************************************************* - * vTraceStartStatusMonitor - * - * This starts a task to monitor the state of½ the recorder. - * This task periodically prints a line to the console window, which shows the - * number of events recorded and the latest timestamp. This task - * calls vTracePortEnd when the recorder has been stopped, where custom - * actions can be added, e.g., to store the trace to a file - * if a file system is available on the device. - ******************************************************************************/ -void vTraceStartStatusMonitor(void) -{ - vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Starting Trace Status Monitor...\n\r"); - (void)xTaskCreate( (pdTASK_CODE)vTraceMonitorTask, (const signed char*)"TraceMon", TRACE_PROGRESS_MONITOR_TASK_STACKSIZE, NULL, TRACE_PROGRESS_MONITOR_TASK_PRIORITY, NULL ); } /******************************************************************************* * uiTraceStart * * Starts the recorder. The recorder will not be started if an error has been - * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h + * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h * has a too small value (NTASK, NQUEUE, etc). - * + * * Returns 1 if the recorder was started successfully. - * Returns 0 if the recorder start was prevented due to a previous internal + * Returns 0 if the recorder start was prevented due to a previous internal * error. In that case, check vTraceGetLastError to get the error message. - * Any error message is also presented when opening a trace file in - * FreeRTOS+Trace v2.2.2 or later. + * Any error message is also presented when opening a trace file. ******************************************************************************/ uint32_t uiTraceStart(void) -{ +{ + objectHandleType handle = 0; + + if (RecorderDataPtr == NULL) + { + vTraceError("RecorderDataPtr is NULL. Call vTraceInitTraceData() before starting trace."); + return 0; + } if (traceErrorMessage == NULL) { trcCRITICAL_SECTION_BEGIN(); RecorderDataPtr->recorderActive = 1; - vTraceStoreTaskswitch(); /* Register the currently running task */ + + handle = TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK()); + if (handle == 0) + { + /* This occurs if the scheduler is not yet started. + This creates a dummy "(startup)" task entry internally in the + recorder */ + handle = xTraceGetObjectHandle(TRACE_CLASS_TASK); + vTraceSetObjectName(TRACE_CLASS_TASK, handle, "(startup)"); + + vTraceSetPriorityProperty(TRACE_CLASS_TASK, handle, 0); + } + + vTraceStoreTaskswitch(handle); /* Register the currently running task */ trcCRITICAL_SECTION_END(); } @@ -201,17 +157,17 @@ uint32_t uiTraceStart(void) } /******************************************************************************* - * vTraceStart + * vTraceStart * * Starts the recorder. The recorder will not be started if an error has been - * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h + * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h * has a too small value (NTASK, NQUEUE, etc). - * - * This function is obsolete, but has been saved for backwards compatibility. + * + * This function is obsolete, but has been saved for backwards compatibility. * We recommend using uiTraceStart instead. ******************************************************************************/ void vTraceStart(void) -{ +{ (void)uiTraceStart(); } @@ -219,11 +175,16 @@ void vTraceStart(void) * vTraceStop * * Stops the recorder. The recording can be resumed by calling vTraceStart. - * This does not reset the recorder. Use vTraceClear is that is desired. + * This does not reset the recorder. Use vTraceClear if that is desired. ******************************************************************************/ void vTraceStop(void) { RecorderDataPtr->recorderActive = 0; + + if (vTraceStopHookPtr != (TRACE_STOP_HOOK)0) + { + (*vTraceStopHookPtr)(); /* Call an application level call back function. */ + } } /******************************************************************************* @@ -231,20 +192,19 @@ void vTraceStop(void) * * Gives the last error message, if any. NULL if no error message is stored. * The message is cleared on read. - * Any error message is also presented when opening a trace file in - * FreeRTOS+Trace v2.2.2 or later. + * Any error message is also presented when opening a trace file. ******************************************************************************/ char* xTraceGetLastError(void) -{ - return traceErrorMessage; +{ + return traceErrorMessage; } /******************************************************************************* * vTraceGetTraceBuffer - * - * 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 + * + * 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* vTraceGetTraceBuffer(void) @@ -254,9 +214,9 @@ void* vTraceGetTraceBuffer(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, + * + * 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) @@ -264,396 +224,24 @@ uint32_t uiTraceGetTraceBufferSize(void) return sizeof(RecorderDataType); } -/******************************************************************************* - * prvTraceExcludeOrIncludeKernelServiceFromTrace - * - * Includes or excludes all events that is related to the kernel service. - ******************************************************************************/ -static void prvTraceExcludeOrIncludeKernelServiceFromTrace(traceKernelService kernelService, uint8_t flag) -{ - switch(kernelService) - { - case TRACE_KERNEL_SERVICE_TASK_CREATE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_TASK); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_TASK); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_TASK); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_TASK); - } - break; - case TRACE_KERNEL_SERVICE_TASK_DELETE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_TASK); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_TASK); - } - break; - case TRACE_KERNEL_SERVICE_TASK_DELAY: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY); - SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY_UNTIL); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY_UNTIL); - } - break; - case TRACE_KERNEL_SERVICE_PRIORITY_SET: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_PRIORITY_SET); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_PRIORITY_SET); - } - break; - case TRACE_KERNEL_SERVICE_TASK_SUSPEND: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_SUSPEND); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_SUSPEND); - } - break; - case TRACE_KERNEL_SERVICE_TASK_RESUME: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_RESUME); - SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_RESUME_FROM_ISR); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_RESUME); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_RESUME_FROM_ISR); - } - break; - case TRACE_KERNEL_SERVICE_QUEUE_CREATE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_QUEUE); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_QUEUE); - } - break; - case TRACE_KERNEL_SERVICE_QUEUE_DELETE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_QUEUE); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_QUEUE); - } - break; - case TRACE_KERNEL_SERVICE_QUEUE_SEND: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_QUEUE); - - - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_QUEUE); - } - break; - case TRACE_KERNEL_SERVICE_QUEUE_RECEIVE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_QUEUE); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_QUEUE); - } - break; - case TRACE_KERNEL_SERVICE_QUEUE_PEEK: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_QUEUE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_MUTEX); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_QUEUE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_MUTEX); - } - break; - case TRACE_KERNEL_SERVICE_MUTEX_CREATE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_MUTEX); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_MUTEX); - } - break; - case TRACE_KERNEL_SERVICE_MUTEX_DELETE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_MUTEX); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_MUTEX); - } - break; - case TRACE_KERNEL_SERVICE_MUTEX_GIVE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_MUTEX); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_MUTEX); - } - break; - case TRACE_KERNEL_SERVICE_MUTEX_TAKE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_MUTEX); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_MUTEX); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_MUTEX); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_MUTEX); - } - break; - case TRACE_KERNEL_SERVICE_SEMAPHORE_CREATE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_SEMAPHORE); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_SEMAPHORE); - } - break; - case TRACE_KERNEL_SERVICE_SEMAPHORE_DELETE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_SEMAPHORE); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_SEMAPHORE); - } - break; - case TRACE_KERNEL_SERVICE_SEMAPHORE_GIVE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_SEMAPHORE); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_SEMAPHORE); - } - break; - case TRACE_KERNEL_SERVICE_SEMAPHORE_TAKE: - if (flag) - { - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_SEMAPHORE); - SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_SEMAPHORE); - } - else - { - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_SEMAPHORE); - CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_SEMAPHORE); - } - break; - } -} - -/****************************************************************************** - * vTraceExclude______FromTrace - * - * Excludes a task or object from the trace. - * This can be useful if some irrelevant task is very frequent and is "eating - * up the buffer". This should be called after the task has been created, but - * before starting the FreeRTOS scheduler. - *****************************************************************************/ -void vTraceExcludeQueueFromTrace(void* handle) -{ - SET_QUEUE_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle)); -} - -void vTraceExcludeSemaphoreFromTrace(void* handle) -{ - SET_SEMAPHORE_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle)); -} - -void vTraceExcludeMutexFromTrace(void* handle) -{ - SET_MUTEX_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle)); -} - -void vTraceExcludeTaskFromTrace(void* handle) -{ - SET_TASK_FLAG_ISEXCLUDED(uxTaskGetTaskNumber(handle)); -} - -void vTraceExcludeKernelServiceFromTrace(traceKernelService kernelService) -{ - prvTraceExcludeOrIncludeKernelServiceFromTrace(kernelService, 1); -} - -/****************************************************************************** - * vTraceInclude______InTrace - * - * Includes a task, object or kernel service in the trace. This is only - * necessary if the task or object has been previously exluded. - *****************************************************************************/ -void vTraceIncludeQueueInTrace(void* handle) -{ - CLEAR_QUEUE_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle)); -} - -void vTraceIncludeSemaphoreInTrace(void* handle) -{ - CLEAR_SEMAPHORE_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle)); -} - -void vTraceIncludeMutexInTrace(void* handle) -{ - CLEAR_MUTEX_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle)); -} - -void vTraceIncludeTaskInTrace(void* handle) -{ - CLEAR_TASK_FLAG_ISEXCLUDED(uxTaskGetTaskNumber(handle)); -} - -void vTraceIncludeKernelServiceInTrace(traceKernelService kernelService) -{ - prvTraceExcludeOrIncludeKernelServiceFromTrace(kernelService, 0); -} - -/******************************************************************************* - * vTraceSetQueueName - * - * Assigns a name to a FreeRTOS Queue, Semaphore or Mutex. This function should - * be called right after creation of the queue/mutex/semaphore. If not using - * this function, the queues/mutexes/semaphores will be presented by their - * numeric handle only. - * - * Example: - * actuatorQ = xQueueCreate(3, sizeof(QueueMessage)); - * vTraceSetQueueName(actuatorQ, "ActuatorQueue"); - ******************************************************************************/ -void vTraceSetQueueName(void* queue, const char* name) -{ - int t = ucQueueGetQueueType(queue); - vTraceSetObjectName(TraceObjectClassTable[t], - (objectHandleType)ucQueueGetQueueNumber(queue), name); -} - - /****************************************************************************** * vTraceTaskInstanceIsFinished - * - * This defines an explicit Instance Finish Event for the current task. It tells - * the recorder that the current instance of this task is finished at the next - * kernel call of the task, e.g., a taskDelay or a queue receive. This function - * should be called right before the api function call considered to be the end - * of the current task instance, i.e., the Instance Finish Event. + * + * This defines an explicit Instance Finish Event for the current task. It tells + * the recorder that the current instance of this task is finished at the + * context-switch. This function should be called right before the API function + * call considered to be the Instance Finish Event. *****************************************************************************/ void vTraceTaskInstanceIsFinished() { if (handle_of_last_logged_task) { - SET_TASK_FLAG_MARKIFE(handle_of_last_logged_task); - } -} - -/******************************************************************************* - * vvTraceTaskSkipDefaultInstanceFinishedEvents - * - * This is useful if there are implicit Instance Finish Events, such as - * vTaskDelayUntil or xQueueReceive, in a task where an explicit Instance Finish - * Event has been defined. This function tells the recorder that only the - * explicitly defined functions, using vTraceTaskInstanceIsFinished, should be - * treated as Instance Finish Events for this task. The implicit Instance Finish - * Events are thus disregarded for the calling task. - ******************************************************************************/ -void vTraceTaskSkipDefaultInstanceFinishedEvents() -{ - if (handle_of_last_logged_task) - { - PROPERTY_TASK_IFE_SERVICECODE(handle_of_last_logged_task) = - RESERVED_DUMMY_CODE; + TRACE_PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle_of_last_logged_task) = 0; } } /******************************************************************************* - * Interrupt recording functions + * Interrupt recording functions ******************************************************************************/ #if (INCLUDE_ISR_TRACING == 1) @@ -663,10 +251,10 @@ static uint8_t isrstack[MAX_ISR_NESTING]; /******************************************************************************* * vTraceSetISRProperties - * + * * Registers an Interrupt Service Routine in the recorder library, This must be - * called before using vTraceStoreISRBegin to store ISR events. This is - * typically called in the startup of the system, before the scheduler is + * called before using vTraceStoreISRBegin to store ISR events. This is + * typically called in the startup of the system, before the scheduler is * started. * * Example: @@ -682,23 +270,25 @@ static uint8_t isrstack[MAX_ISR_NESTING]; * vTraceStoreISREnd(); * } * - * NOTE: To safely record ISRs, you need to make sure that all traced - * interrupts actually are disabled by trcCRITICAL_SECTION_BEGIN(), which - * typically is mapped to portENTER_CRITICAL(), which uses the macro - * portDISABLE_INTERRUPTS. However, in some ports of FreeRTOS and depending on - * FreeRTOS configuration, this does not disable high priority interrupts! + * NOTE: To safely record ISRs, you need to make sure that all traced + * interrupts actually are disabled by trcCRITICAL_SECTION_BEGIN(). However, + * in some ports this does not disable high priority interrupts! * If an ISR calls vTraceStoreISRBegin while the recorder is busy, it will * stop the recording and give an error message. ******************************************************************************/ void vTraceSetISRProperties(objectHandleType handle, const char* name, char priority) { + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceSetISRProperties: Invalid value for handle", ); + TRACE_ASSERT(name != NULL, "vTraceSetISRProperties: name == NULL", ); + TRACE_ASSERT(priority >= 0, "vTraceSetISRProperties: Invalid value for priority", ); + vTraceSetObjectName(TRACE_CLASS_ISR, handle, name); vTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority); } /******************************************************************************* * vTraceStoreISRBegin - * + * * Registers the beginning of an Interrupt Service Routine. * * Example: @@ -714,13 +304,10 @@ void vTraceSetISRProperties(objectHandleType handle, const char* name, char prio * vTraceStoreISREnd(); * } * - * NOTE: You need to make sure that any traced interrupts actually are - * disabled by trcCRITICAL_SECTION_BEGIN(), i.e., taskENTER_CRITICAL() which - * uses portDISABLE_INTERRUPTS(). - * In some ports of FreeRTOS, this does not disable high-priority interrupts, - * i.e., with priorities above configMAX_SYSCALL_INTERRUPT_PRIORITY. + * NOTE: You need to make sure that any traced interrupts actually are + * disabled by trcCRITICAL_SECTION_BEGIN(). * If an invalid call to vTraceStoreISRBegin is detected (i.e., that preempted - * a critical section of the recorder) this will generate a recorder error + * a critical section of the recorder) this will generate a recorder error * using vTraceError. ******************************************************************************/ void vTraceStoreISRBegin(objectHandleType handle) @@ -728,55 +315,57 @@ void vTraceStoreISRBegin(objectHandleType handle) uint16_t dts4; TSEvent* ts = NULL; + TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid value for handle", ); + if (recorder_busy) { - vTraceError("Illegal call to vTraceStoreISRBegin/End"); + vTraceError("Illegal call to vTraceStoreISRBegin, recorder busy!"); return; } if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) - { + { trcCRITICAL_SECTION_BEGIN(); dts4 = (uint16_t)prvTraceGetDTS(0xFFFF); - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { if (nISRactive < MAX_ISR_NESTING) - { + { isrstack[nISRactive] = handle; - nISRactive++; + nISRactive++; ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); if (ts != NULL) { ts->type = TS_ISR_BEGIN; ts->dts = dts4; ts->objHandle = handle; - prvTraceUpdateCounters(); + prvTraceUpdateCounters(); } } else - { - /* This should not occur unless something is very wrong */ + { + /* This should not occur unless something is very wrong */ vTraceError("Too many nested interrupts!"); - } + } } - trcCRITICAL_SECTION_END(); + trcCRITICAL_SECTION_END(); } } #if (SELECTED_PORT == PORT_ARM_CortexM) -int tailchain_irq_pending(void); +static int tailchain_irq_pending(void); /******************************************************************************* * tailchain_irq_pending * - * For Cortex-M chips only. Returns 1 if an interrupt is pending, by checking - * the 8 NVIC IRQ pend registers at 0xE000E200 to 0xE000E21C. Returns 0 if no + * For Cortex-M chips only. Returns 1 if an interrupt is pending, by checking + * the 8 NVIC IRQ pend registers at 0xE000E200 to 0xE000E21C. Returns 0 if no * interrupt is pending. This is used to predict tailchaining of ISRs. ******************************************************************************/ -int tailchain_irq_pending(void) +static int tailchain_irq_pending(void) { uint32_t* pend_reg = ((uint32_t*)0xE000E200); int i; @@ -788,15 +377,15 @@ int tailchain_irq_pending(void) return 1; } } - return 0; + return 0; } #endif /******************************************************************************* * vTraceStoreISREnd - * - * Registers the end of an Interrupt Service Routine. + * + * Registers the end of an Interrupt Service Routine. * * Example: * #define ID_ISR_TIMER1 1 // lowest valid ID is 1 @@ -811,13 +400,10 @@ int tailchain_irq_pending(void) * vTraceStoreISREnd(); * } * - * NOTE: You need to make sure that any traced interrupts actually are - * disabled by trcCRITICAL_SECTION_BEGIN(), i.e., taskENTER_CRITICAL() which - * uses portDISABLE_INTERRUPTS(). - * In some ports of FreeRTOS, this does not disable high-priority interrupts, - * i.e., with priorities above configMAX_SYSCALL_INTERRUPT_PRIORITY. + * NOTE: You need to make sure that any traced interrupts actually are + * disabled by trcCRITICAL_SECTION_BEGIN(). * If an invalid call to vTraceStoreISREnd is detected (i.e., that preempted - * a critical section of the recorder) this will generate a recorder error + * a critical section of the recorder) this will generate a recorder error * using vTraceError. ******************************************************************************/ void vTraceStoreISREnd(void) @@ -827,28 +413,28 @@ void vTraceStoreISREnd(void) if (recorder_busy) { - vTraceError("Illegal call to vTraceStoreISRBegin/End"); + vTraceError("Illegal call to vTraceStoreISREnd, recorder busy!"); return; } - + if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) { #if (SELECTED_PORT == PORT_ARM_CortexM) if (tailchain_irq_pending() > 0) { - nISRactive--; /* If an IRQ strikes exactly here, the resulting - ISR tailchaining is not detected. The trace instead shows a very + nISRactive--; /* If an IRQ strikes exactly here, the resulting + ISR tailchaining is not detected. The trace instead shows a very short fragment of the earlier preempted task/ISR, and then the new ISR begins. */ return; } #endif - + trcCRITICAL_SECTION_BEGIN(); dts5 = (uint16_t)prvTraceGetDTS(0xFFFF); - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); if (ts != NULL) { @@ -869,7 +455,7 @@ void vTraceStoreISREnd(void) prvTraceUpdateCounters(); } } - trcCRITICAL_SECTION_END(); + trcCRITICAL_SECTION_END(); } } @@ -882,7 +468,7 @@ void vTraceIncreaseISRActive(void) nISRactive++; } -void vTraceDecreaseISRActive(objectHandleType handle) +void vTraceDecreaseISRActive(void) { if (RecorderDataPtr->recorderActive && handle_of_last_logged_task) nISRactive--; @@ -896,59 +482,12 @@ void vTraceDecreaseISRActive(objectHandleType handle) #if (INCLUDE_USER_EVENTS == 1) - /****************************************************************************** - * vTraceUserEvent - * - * Basic user event (Standard and Professional Edition only) - * - * Generates a User Event with a text label. The label is created/looked up - * in the symbol table using xTraceOpenLabel. - ******************************************************************************/ -void vTraceUserEvent(traceLabel eventLabel) -{ - UserEvent* ue; - uint8_t dts1; - - if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive ) && handle_of_last_logged_task) - { - trcCRITICAL_SECTION_BEGIN(); - - dts1 = (uint8_t)prvTraceGetDTS(0xFF); - - if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ - { - ue = (UserEvent*) xTraceNextFreeEventBufferSlot(); - if (ue != NULL) - { - ue->dts = dts1; - ue->type = USER_EVENT; - ue->payload = eventLabel; - prvTraceUpdateCounters(); - } - } - trcCRITICAL_SECTION_END(); - } -} - -/*** Locally used in vTracePrintF ***/ - -/* one word (32 bit) is required for the USER_EVENT entry, 8 words -(8*32 bit = 32 byte) available for argument data */ -#define MAX_ARG_SIZE (4+32) - -static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value); -static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value); -static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value); - -#if (INCLUDE_FLOAT_SUPPORT) -static uint8_t writeFloat(void * buffer, uint8_t i, float value); -static uint8_t writeDouble(void * buffer, uint8_t i, double value); -#endif - +#define MAX_ARG_SIZE (4+32) /*** Locally used in vTracePrintF ***/ static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value) -{ - +{ + TRACE_ASSERT(buffer != NULL, "writeInt8: buffer == NULL", 0); + if (i >= MAX_ARG_SIZE) { return 255; @@ -966,7 +505,9 @@ static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value) /*** Locally used in vTracePrintF ***/ static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value) -{ +{ + TRACE_ASSERT(buffer != NULL, "writeInt16: buffer == NULL", 0); + /* Align to multiple of 2 */ while ((i % 2) != 0) { @@ -974,11 +515,11 @@ static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value) { return 255; } - + ((uint8_t*)buffer)[i] = 0; - i++; + i++; } - + if (i + 2 > MAX_ARG_SIZE) { return 255; @@ -992,7 +533,8 @@ static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value) /*** Locally used in vTracePrintF ***/ static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value) { - + TRACE_ASSERT(buffer != NULL, "writeInt32: buffer == NULL", 0); + /* A 32 bit value should begin at an even 4-byte address */ while ((i % 4) != 0) { @@ -1000,15 +542,15 @@ static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value) { return 255; } - + ((uint8_t*)buffer)[i] = 0; i++; } - + if (i + 4 > MAX_ARG_SIZE) { return 255; - } + } ((uint32_t*)buffer)[i/4] = value; @@ -1020,6 +562,8 @@ static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value) /*** Locally used in vTracePrintF ***/ static uint8_t writeFloat(void * buffer, uint8_t i, float value) { + TRACE_ASSERT(buffer != NULL, "writeFloat: buffer == NULL", 0); + /* A 32 bit value should begin at an even 4-byte address */ while ((i % 4) != 0) { @@ -1035,19 +579,21 @@ static uint8_t writeFloat(void * buffer, uint8_t i, float value) if (i + 4 > MAX_ARG_SIZE) { return 255; - } + } ((float*)buffer)[i/4] = value; - + return i + 4; } /*** Locally used in vTracePrintF ***/ static uint8_t writeDouble(void * buffer, uint8_t i, double value) { + TRACE_ASSERT(buffer != NULL, "writeDouble: buffer == NULL", 0); + uint32_t * dest = buffer; uint32_t * src = (void*)&value; - /* The double is written as two 32 bit values, and should begin at an even + /* The double is written as two 32 bit values, and should begin at an even 4-byte address (to avoid having to align with 8 byte) */ while (i % 4 != 0) { @@ -1057,50 +603,400 @@ static uint8_t writeDouble(void * buffer, uint8_t i, double value) } ((uint8_t*)buffer)[i] = 0; - i++; + i++; } - + if (i + 8 > MAX_ARG_SIZE) { return 255; - } - + } + dest[i/4+0] = src[0]; dest[i/4+1] = src[1]; - + return i + 8; } #endif +/******************************************************************************* + * prvTraceUserEventFormat + * + * Parses the format string and stores the arguments in the buffer. + ******************************************************************************/ +static uint8_t prvTraceUserEventFormat(const char* formatStr, va_list vl, uint8_t* buffer, uint8_t byteOffset) +{ + uint16_t formatStrIndex = 0; + uint8_t argCounter = 0; + uint8_t i = byteOffset; + + while (formatStr[formatStrIndex] != '\0') + { + if (formatStr[formatStrIndex] == '%') + { + argCounter++; + + if (argCounter > 15) + { + vTraceError("vTracePrintF - Too many arguments, max 15 allowed!"); + return 0; + } + +/******************************************************************************* +* These below code writes raw data (primitive datatypes) in the event buffer, +* instead of the normal event structs (where byte 0 is event type). +* These data entries must never be interpreted as real event data, as the type +* field would be misleading since used for payload data. +* +* The correctness of this encoding depends on two mechanisms: +* +* 1. An initial USER_EVENT, which type code tells the number of 32-bit data +* entires that follows. (code - USER_EVENT = number of data entries). +* Note that a data entry corresponds to the slots that normally corresponds to +* one (1) event, i.e., 32 bits. vTracePrintF may encode several pieces of data +* in one data entry, e.g., two 16-bit values or four 8-bit values, one 16-bit +* value followed by two 8-bit values, etc. +* +* 2. A two-phase commit procedure, where the USER_EVENT and data entries are +* written to a local buffer at first, and when all checks are OK then copied to +* the main event buffer using a fast memcpy. The event code is finalized as the +* very last step. Before that step, the event code indicates an unfinished +* event, which causes it to be ignored and stop the loading of the file (since +* an unfinished event is the last event in the trace). +*******************************************************************************/ + formatStrIndex++; + + while ((formatStr[formatStrIndex] >= '0' && formatStr[formatStrIndex] <= '9') || formatStr[formatStrIndex] == '#' || formatStr[formatStrIndex] == '.') + formatStrIndex++; + + if (formatStr[formatStrIndex] != '\0') + { + switch (formatStr[formatStrIndex]) + { + case 'd': i = writeInt32(buffer, + i, + (uint32_t)va_arg(vl, uint32_t)); + break; + case 'x': + case 'X': + case 'u': i = writeInt32(buffer, + i, + (uint32_t)va_arg(vl, uint32_t)); + break; + case 's': i = writeInt16(buffer, + i, + (uint16_t)xTraceOpenLabel((char*)va_arg(vl, char*))); + break; + +#if (INCLUDE_FLOAT_SUPPORT) + /* Yes, "double" as type also in the float + case. This since "float" is promoted into "double" + by the va_arg stuff. */ + case 'f': i = writeFloat(buffer, + i, + (float)va_arg(vl, double)); + break; +#else + /* No support for floats, but attempt to store a float user event + avoid a possible crash due to float reference. Instead store the + data on uint_32 format (will not be displayed anyway). This is just + to keep va_arg and i consistent. */ + + case 'f': i = writeInt32(buffer, + i, + (uint32_t)va_arg(vl, double)); + break; +#endif + case 'l': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { +#if (INCLUDE_FLOAT_SUPPORT) + case 'f': i = writeDouble(buffer, + i, + (double)va_arg(vl, double)); + break; +#else + /* No support for floats, but attempt to store a float user event + avoid a possible crash due to float reference. Instead store the + data on uint_32 format (will not be displayed anyway). This is just + to keep va_arg and i consistent. */ + case 'f': i = writeInt32(buffer, /* In this case, the value will not be shown anyway */ + i, + (uint32_t)va_arg(vl, double)); + i = writeInt32(buffer, /* Do it twice, to write in total 8 bytes */ + i, + (uint32_t)va_arg(vl, double)); + break; +#endif + + } + break; + case 'h': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { + case 'd': i = writeInt16(buffer, + i, + (uint16_t)va_arg(vl, uint32_t)); + break; + case 'u': i = writeInt16(buffer, + i, + (uint16_t)va_arg(vl, uint32_t)); + break; + } + break; + case 'b': + formatStrIndex++; + switch (formatStr[formatStrIndex]) + { + case 'd': i = writeInt8(buffer, + i, + (uint8_t)va_arg(vl, uint32_t)); + break; + case 'u': i = writeInt8(buffer, + i, + (uint8_t)va_arg(vl, uint32_t)); + break; + } + break; + } + } + else + break; + } + formatStrIndex++; + if (i == 255) + { + vTraceError("vTracePrintF - Too large arguments, max 32 byte allowed!"); + return 0; + } + } + return (i+3)/4; +} + +#if (USE_SEPARATE_USER_EVENT_BUFFER == 1) + +/******************************************************************************* + * prvTraceClearChannelBuffer + * + * Clears a number of items in the channel buffer, starting from nextSlotToWrite. + ******************************************************************************/ +static void prvTraceClearChannelBuffer(uint32_t count) +{ + uint32_t slots; + + TRACE_ASSERT(USER_EVENT_BUFFER_SIZE >= count, "prvTraceClearChannelBuffer: USER_EVENT_BUFFER_SIZE is too small to handle this event.", ); + + /* Check if we're close to the end of the buffer */ + if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > USER_EVENT_BUFFER_SIZE) + { + slots = USER_EVENT_BUFFER_SIZE - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */ + (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, slots); + (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[0], 0, (count - slots)); + } + else + (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, count); +} + +/******************************************************************************* + * prvTraceCopyToDataBuffer + * + * Copies a number of items to the data buffer, starting from nextSlotToWrite. + ******************************************************************************/ +static void prvTraceCopyToDataBuffer(uint32_t* data, uint32_t count) +{ + TRACE_ASSERT(data != NULL, "prvTraceCopyToDataBuffer: data == NULL.", ); + TRACE_ASSERT(count <= USER_EVENT_BUFFER_SIZE, "prvTraceCopyToDataBuffer: USER_EVENT_BUFFER_SIZE is too small to handle this event.", ); + + uint32_t slots; + /* Check if we're close to the end of the buffer */ + if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > USER_EVENT_BUFFER_SIZE) + { + slots = USER_EVENT_BUFFER_SIZE - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */ + (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, slots * 4); + (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[0], data + slots, (count - slots) * 4); + } + else + { + (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, count * 4); + } +} + +/******************************************************************************* + * prvTraceUserEventHelper1 + * + * Calls on prvTraceUserEventFormat() to do the actual formatting, then goes on to the next helper function. + ******************************************************************************/ +static void prvTraceUserEventHelper1(UserEventChannel channel, traceLabel eventLabel, traceLabel formatLabel, va_list vl) +{ + uint32_t data[(3 + MAX_ARG_SIZE) / 4]; + uint8_t byteOffset = 4; /* Need room for timestamp */ + uint8_t noOfSlots; + + if (channel == 0) + { + /* We are dealing with an unknown channel format pair */ + byteOffset += 4; /* Also need room for channel and format */ + ((uint16_t*)data)[2] = eventLabel; + ((uint16_t*)data)[3] = formatLabel; + } + + noOfSlots = prvTraceUserEventFormat((char*)&(RecorderDataPtr->SymbolTable.symbytes[formatLabel+4]), vl, (uint8_t*)data, byteOffset); + + prvTraceUserEventHelper2(channel, data, noOfSlots); +} + +/******************************************************************************* + * prvTraceUserEventHelper2 + * + * This function simply copies the data buffer to the actual user event buffer. + ******************************************************************************/ +static void prvTraceUserEventHelper2(UserEventChannel channel, uint32_t* data, uint32_t noOfSlots) +{ + static uint32_t old_timestamp = 0; + uint32_t old_nextSlotToWrite = 0; + + TRACE_ASSERT(USER_EVENT_BUFFER_SIZE >= noOfSlots, "vTracePrintF: USER_EVENT_BUFFER_SIZE is too small to handle this event.", ); + + trcCRITICAL_SECTION_BEGIN(); + /* Store the timestamp */ + vTracePortGetTimeStamp(data); + + if (*data < old_timestamp) + RecorderDataPtr->userEventBuffer.wraparoundCounter++; + old_timestamp = *data; + + /* Start by erasing any information in the channel buffer */ + prvTraceClearChannelBuffer(noOfSlots); + + prvTraceCopyToDataBuffer(data, noOfSlots); /* Will wrap around the data if necessary */ + + old_nextSlotToWrite = RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Save the index that we want to write the channel data at when we're done */ + RecorderDataPtr->userEventBuffer.nextSlotToWrite = (RecorderDataPtr->userEventBuffer.nextSlotToWrite + noOfSlots) % USER_EVENT_BUFFER_SIZE; /* Make sure we never end up outside the buffer */ + + /* Write to the channel buffer to indicate that this user event is ready to be used */ + if (channel != 0) + RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = channel; + else + RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = (UserEventChannel)0xFF; /* 0xFF indicates that this is not a normal channel id */ + trcCRITICAL_SECTION_END(); +} + +/******************************************************************************* + * xTraceRegisterChannelFormat + * + * Attempts to create a pair of the channel and format string. + * + * Note: This is only available if USE_SEPARATE_USER_EVENT_BUFFER is enabled in + * trcConfig.h + ******************************************************************************/ +UserEventChannel xTraceRegisterChannelFormat(traceLabel channel, traceLabel formatStr) +{ + uint8_t i; + UserEventChannel retVal = 0; + + TRACE_ASSERT(formatStr != 0, "vTraceRegisterChannelFormat: formatStr == 0", (UserEventChannel)0); + + trcCRITICAL_SECTION_BEGIN(); + for (i = 1; i <= CHANNEL_FORMAT_PAIRS; i++) /* Size of the channels buffer is CHANNEL_FORMAT_PAIRS + 1. Index 0 is unused. */ + { + if(RecorderDataPtr->userEventBuffer.channels[i].name == 0 && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == 0) + { + /* Found empty slot */ + RecorderDataPtr->userEventBuffer.channels[i].name = channel; + RecorderDataPtr->userEventBuffer.channels[i].defaultFormat = formatStr; + retVal = (UserEventChannel)i; + break; + } + + if (RecorderDataPtr->userEventBuffer.channels[i].name == channel && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == formatStr) + { + /* Found a match */ + retVal = (UserEventChannel)i; + break; + } + } + trcCRITICAL_SECTION_END(); + return retVal; +} + +/****************************************************************************** + * vTraceChannelPrintF + * + * Slightly faster version of vTracePrintF() due to no lookups. + * + * Note: This is only available if USE_SEPARATE_USER_EVENT_BUFFER is enabled in + * trcConfig.h + * + ******************************************************************************/ +void vTraceChannelPrintF(UserEventChannel channelPair, ...) +{ + va_list vl; + + va_start(vl, channelPair); + vTraceChannelPrintF_Helper(channelPair, vl); + va_end(vl); +} + +void vTraceChannelPrintF_Helper(UserEventChannel channelPair, va_list vl) +{ + traceLabel channel; + traceLabel formatStr; + + TRACE_ASSERT(channelPair != 0, "vTraceChannelPrintF: channelPair == 0", ); + TRACE_ASSERT(channelPair <= CHANNEL_FORMAT_PAIRS, "vTraceChannelPrintF: ", ); + + channel = RecorderDataPtr->userEventBuffer.channels[channelPair].name; + formatStr = RecorderDataPtr->userEventBuffer.channels[channelPair].defaultFormat; + + prvTraceUserEventHelper1(channelPair, channel, formatStr, vl); +} + +/****************************************************************************** + * vTraceChannelUserEvent + * + * Slightly faster version of vTraceUserEvent() due to no lookups. + ******************************************************************************/ +void vTraceChannelUserEvent(UserEventChannel channelPair) +{ + uint32_t data[(3 + MAX_ARG_SIZE) / 4]; + + TRACE_ASSERT(channelPair != 0, "vTraceChannelPrintF: channelPair == 0", ); + TRACE_ASSERT(channelPair <= CHANNEL_FORMAT_PAIRS, "vTraceChannelPrintF: ", ); + + prvTraceUserEventHelper2(channelPair, data, 1); /* Only need one slot for timestamp */ +} +#endif /* USE_SEPARATE_USER_EVENT_BUFFER == 1 */ + /****************************************************************************** - * vTracePrintF - * + * vTracePrintF + * * Advanced user events (Professional Edition only) * * Generates User Event with formatted text and data, similar to a "printf". - * It is very fast compared to a normal "printf" since this function only + * It is very fast compared to a normal "printf" since this function only * stores the arguments. The actual formatting is done - * on the host PC when the trace is displayed in the viewer tool. + * on the host PC when the trace is displayed in the viewer tool. * * User Event labels are created using xTraceOpenLabel. * Example: * * traceLabel adc_uechannel = xTraceOpenLabel("ADC User Events"); * ... - * vTracePrint(adc_uechannel, - * "ADC channel %d: %lf volts", + * vTracePrint(adc_uechannel, + * "ADC channel %d: %lf volts", * ch, (double)adc_reading/(double)scale); * * This can be combined into one line, if desired, but this is slower: * - * vTracePrint(xTraceOpenLabel("ADC User Events"), - * "ADC channel %d: %lf volts", + * vTracePrint(xTraceOpenLabel("ADC User Events"), + * "ADC channel %d: %lf volts", * ch, (double)adc_reading/(double)scale); * * Calling xTraceOpenLabel multiple times will not create duplicate entries, but - * it is of course faster to just do it once, and then keep the handle for later - * use. If you don´t have any data arguments, only a text label/string, it is + * it is of course faster to just do it once, and then keep the handle for later + * use. If you don´t have any data arguments, only a text label/string, it is * better to use vTraceUserEvent - it is faster. * * Format specifiers supported: @@ -1113,217 +1009,79 @@ static uint8_t writeDouble(void * buffer, uint8_t i, double value) * %bd - 8 bit signed integer * %bu - 8 bit unsigned integer * %lf - double-precision float - * + * * Up to 15 data arguments are allowed, with a total size of maximum 32 byte. * In case this is exceeded, the user event is changed into an error message. - * - * The data is stored in trace buffer, and is packed to allow storing multiple + * + * The data is stored in trace buffer, and is packed to allow storing multiple * smaller data entries in the same 4-byte record, e.g., four 8-bit values. - * A string requires two bytes, as the symbol table is limited to 64K. Storing a + * A string requires two bytes, as the symbol table is limited to 64K. Storing a * double (%lf) uses two records, so this is quite costly. Use float (%f) unless * the higher precision is really necessary. ******************************************************************************/ + void vTracePrintF(traceLabel eventLabel, const char* formatStr, ...) { + va_list vl; + + va_start(vl, formatStr); + vTracePrintF_Helper(eventLabel, formatStr, vl); + va_end(vl); +} + +void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list vl) +{ +#if (USE_SEPARATE_USER_EVENT_BUFFER == 0) + uint32_t noOfSlots; UserEvent* ue1; - va_list vl; - uint8_t argCounter = 0; - uint8_t i = 0; - uint8_t nofEventEntries = 0; - uint16_t formatStrIndex = 0; + uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; /************************************************************************** - * The array tempDataBuffer is a local buffer used in a two-phase commit of - * the event data, since a vTracePrintF may span over multiple slots in the + * The array tempDataBuffer is a local buffer used in a two-phase commit of + * the event data, since a vTracePrintF may span over multiple slots in the * buffer. - * This buffer can be made larger, of course, but remember the risk for - * stack overflow. Note: This should be a LOCAL buffer, must not be made + * This buffer can be made larger, of course, but remember the risk for + * stack overflow. Note: This should be a LOCAL buffer, must not be made * global. That would cause data corruption when two calls to vTracePrintF - * from different tasks overlaps (interrupts are only disabled in a small + * from different tasks overlaps (interrupts are only disabled in a small * part of this function, otherwise enabled) ***************************************************************************/ - - uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; - - - if ((inExcludedTask == 0) && - (nISRactive == 0) && - (RecorderDataPtr->recorderActive == 1) && - (handle_of_last_logged_task > 0)) - { - /* First, write the "primary" user event entry in the local buffer, but - let the event type be "EVENT_BEING_WRITTEN" for now...*/ - ue1 = (UserEvent*)(&tempDataBuffer[0]); - ue1->type = EVENT_BEING_WRITTEN; /* Update this as the last step */ - - i = 4; - formatStrIndex = 0; - va_start(vl, formatStr); /* Begin reading the arguments list */ + TRACE_ASSERT(formatStr != NULL, "vTracePrintF: formatStr == NULL", ); - while (formatStr[formatStrIndex] != '\0') - { - if (formatStr[formatStrIndex] == '%') - { - argCounter++; - - if (argCounter > 15) - { - vTraceError("vTracePrintF - Too many arguments, max 15 allowed!"); - va_end(vl); - formatStr = "[vTracePrintF error] Too many arguments, max 15 allowed!"; - i = 4; - break; - } - -/******************************************************************************* - * These below code writes raw data (primitive datatypes) in the event buffer, - * instead of the normal event structs (where byte 0 is event type). - * These data entries must never be interpreted as real event data, as the type - * field would be misleading since used for payload data. - * - * The correctness of this encoding depends on two mechanisms: - * - * 1. An initial USER_EVENT, which type code tells the number of 32-bit data - * entires that follows. (code - USER_EVENT = number of data entries). - * Note that a data entry corresponds to the slots that normally corresponds to - * one (1) event, i.e., 32 bits. vTracePrintF may encode several pieces of data - * in one data entry, e.g., two 16-bit values or four 8-bit values, one 16-bit - * value followes by two 8-bit values, etc. - * - * 2. A two-phase commit procedure, where the USER_EVENT and data entries are - * written to a local buffer at first, and when all checks are OK then copied to - * the main event buffer using a fast memcpy. The event code is finalized as the - * very last step. Before that that step, the event code indicates an unfinished - * event, which causes it to be ignored and stop the loading of the file (since - * an unfinished event is the last event in the trace). -*******************************************************************************/ - formatStrIndex++; - switch (formatStr[formatStrIndex]) - { - case 'd': i = writeInt32((uint8_t*)tempDataBuffer, - i, - (uint32_t)va_arg(vl, uint32_t)); - break; - case 'u': i = writeInt32((uint8_t*)tempDataBuffer, - i, - (uint32_t)va_arg(vl, uint32_t)); - break; - case 's': i = writeInt16((uint8_t*)tempDataBuffer, - i, - (uint16_t)xTraceOpenLabel((char*)va_arg(vl, char*))); - break; + if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) + { + /* First, write the "primary" user event entry in the local buffer, but + let the event type be "EVENT_BEING_WRITTEN" for now...*/ -#if (INCLUDE_FLOAT_SUPPORT) - /* Yes, "double" as type also in the float - case. This since "float" is promoted into "double" - by the va_arg stuff. */ - case 'f': i = writeFloat((uint8_t*)tempDataBuffer, - i, - (float)va_arg(vl, double)); - break; -#else -/* No support for floats, but attempt to store a float user event -avoid a possible crash due to float reference. Instead store the -data on uint_32 format (will not be displayed anyway). This is just -to keep va_arg and i consistent. */ - - case 'f': i = writeInt32((uint8_t*)tempDataBuffer, - i, - (uint32_t)va_arg(vl, double)); -#endif - case 'l': - formatStrIndex++; - switch (formatStr[formatStrIndex]) - { -#if (INCLUDE_FLOAT_SUPPORT) - case 'f': i = writeDouble((uint8_t*)tempDataBuffer, - i, - (double)va_arg(vl, double)); - break; -#else -/* No support for floats, but attempt to store a float user event -avoid a possible crash due to float reference. Instead store the -data on uint_32 format (will not be displayed anyway). This is just -to keep va_arg and i consistent. */ - case 'f': i = writeInt32((uint8_t*)tempDataBuffer, /* In this case, the value will not be shown anyway */ - i, - (uint32_t)va_arg(vl, double)); - i = writeInt32((uint8_t*)tempDataBuffer, /* Do it twice, to write in total 8 bytes */ - i, - (uint32_t)va_arg(vl, double)); -#endif + ue1 = (UserEvent*)(&tempDataBuffer[0]); + ue1->type = EVENT_BEING_WRITTEN; /* Update this as the last step */ - } - break; - case 'h': - formatStrIndex++; - switch (formatStr[formatStrIndex]) - { - case 'd': i = writeInt16((uint8_t*)tempDataBuffer, - i, - (uint16_t)va_arg(vl, uint32_t)); - break; - case 'u': i = writeInt16((uint8_t*)tempDataBuffer, - i, - (uint16_t)va_arg(vl, uint32_t)); - break; - } - break; - case 'b': - formatStrIndex++; - switch (formatStr[formatStrIndex]) - { - case 'd': i = writeInt8((uint8_t*)tempDataBuffer, - i, - (uint8_t)va_arg(vl, uint32_t)); - break; - case 'u': i = writeInt8((uint8_t*)tempDataBuffer, - i, - (uint8_t)va_arg(vl, uint32_t)); - break; - } - break; - } - } - formatStrIndex++; - if (i == 255) - { - va_end(vl); - //vTraceError("vTracePrintF - Too large arguments, max 32 byte allowed!"); - formatStr = "[vTracePrintF error] Too large arguments, max 32 byte allowed!"; - i = 4; - break; - } - } + noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4); - va_end(vl); - /* Store the format string, with a reference to the channel symbol */ - ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel); + ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel); - trcCRITICAL_SECTION_BEGIN(); + trcCRITICAL_SECTION_BEGIN(); ue1->dts = (uint8_t)prvTraceGetDTS(0xFF); if (! RecorderDataPtr->recorderActive) { - /* Abort, since an XTS event (created by prvTraceGetDTS) filled the + /* Abort, since an XTS event (created by prvTraceGetDTS) filled the buffer, and the recorder stopped since not circular buffer. */ trcCRITICAL_SECTION_END(); - + return; } - - nofEventEntries = (i+3)/4; - /* If the data does not fit in the remaining main buffer, wrap around to + /* If the data does not fit in the remaining main buffer, wrap around to 0 if allowed, otherwise stop the recorder and quit). */ - if (RecorderDataPtr->nextFreeIndex + nofEventEntries > RecorderDataPtr->maxEvents) + if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents) { -#if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER) - (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], - 0, +#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) + (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], + 0, (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4); RecorderDataPtr->nextFreeIndex = 0; RecorderDataPtr->bufferIsFull = 1; @@ -1333,60 +1091,150 @@ to keep va_arg and i consistent. */ trcCRITICAL_SECTION_END(); vTraceStop(); - + return; #endif } - -#if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER) - /* Check that the buffer to be overwritten does not contain any user + +#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) + /* Check that the buffer to be overwritten does not contain any user events that would be partially overwritten. If so, they must be "killed" - by replacing the user event and following data with NULL events (i.e., + by replacing the user event and following data with NULL events (i.e., using a memset to zero).*/ - prvCheckDataToBeOverwrittenForMultiEntryUserEvents(nofEventEntries); + prvCheckDataToBeOverwrittenForMultiEntryEvents(noOfSlots); #endif /* Copy the local buffer to the main buffer */ - (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], - tempDataBuffer, - i); + (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], + tempDataBuffer, + noOfSlots * 4); - /* Update the event type, i.e., number of data entries following the - main USER_EVENT entry (Note: important that this is after the memcpy, + /* Update the event type, i.e., number of data entries following the + main USER_EVENT entry (Note: important that this is after the memcpy, but within the critical section!)*/ - RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] = - (uint8_t) USER_EVENT + nofEventEntries - 1; - - /* Update the main buffer event index (already checked that it fits in + RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] = + (uint8_t) USER_EVENT + noOfSlots - 1; + + /* Update the main buffer event index (already checked that it fits in the buffer, so no need to check for wrapping)*/ - - RecorderDataPtr->nextFreeIndex += nofEventEntries; - RecorderDataPtr->numEvents += nofEventEntries; - - if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) - { - -#if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER) - RecorderDataPtr->nextFreeIndex = 0; - RecorderDataPtr->bufferIsFull = 1; + + RecorderDataPtr->nextFreeIndex += noOfSlots; + RecorderDataPtr->numEvents += noOfSlots; + + + + if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE) + { +#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) + /* We have reached the end, but this is a ring buffer. Start from the beginning again. */ + RecorderDataPtr->bufferIsFull = 1; + RecorderDataPtr->nextFreeIndex = 0; #else - vTraceStop(); + /* We have reached the end so we stop. */ + vTraceStop(); #endif - } + } +#if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER) + /* Make sure the next entry is cleared correctly */ + prvCheckDataToBeOverwrittenForMultiEntryEvents(1); +#endif + +#ifdef STOP_AFTER_N_EVENTS +#if (STOP_AFTER_N_EVENTS > -1) + /* Check if we have reached the desired number of events */ + if (RecorderDataPtr->numEvents >= STOP_AFTER_N_EVENTS) + { + vTraceStop(); + } +#endif +#endif + + trcCRITICAL_SECTION_END(); + } + +#elif (USE_SEPARATE_USER_EVENT_BUFFER == 1) + /* Use the separate user event buffer */ + traceLabel formatLabel; + UserEventChannel channel; + + if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) + { + formatLabel = xTraceOpenLabel(formatStr); + + channel = xTraceRegisterChannelFormat(eventLabel, formatLabel); + + prvTraceUserEventHelper1(channel, eventLabel, formatLabel, vl); + } +#endif +} + +/****************************************************************************** + * vTraceUserEvent + * + * Basic user event (Standard and Professional Edition only) + * + * Generates a User Event with a text label. The label is created/looked up + * in the symbol table using xTraceOpenLabel. + ******************************************************************************/ +void vTraceUserEvent(traceLabel eventLabel) +{ +#if (USE_SEPARATE_USER_EVENT_BUFFER == 0) + UserEvent* ue; + uint8_t dts1; + + TRACE_ASSERT(eventLabel > 0, "vTraceUserEvent: Invalid value for eventLabel", ); + + if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) + { + trcCRITICAL_SECTION_BEGIN(); + + dts1 = (uint8_t)prvTraceGetDTS(0xFF); + + if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ + { + ue = (UserEvent*) xTraceNextFreeEventBufferSlot(); + if (ue != NULL) + { + ue->dts = dts1; + ue->type = USER_EVENT; + ue->payload = eventLabel; + prvTraceUpdateCounters(); + } + } trcCRITICAL_SECTION_END(); - } + } +#elif (USE_SEPARATE_USER_EVENT_BUFFER == 1) + UserEventChannel channel; + uint32_t noOfSlots = 1; + uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4]; + + if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task) + { + channel = xTraceRegisterChannelFormat(0, eventLabel); + + if (channel == 0) + { + /* We are dealing with an unknown channel format pair */ + noOfSlots++; /* Also need room for channel and format */ + ((uint16_t*)tempDataBuffer)[2] = 0; + ((uint16_t*)tempDataBuffer)[3] = eventLabel; + } + + prvTraceUserEventHelper2(channel, tempDataBuffer, noOfSlots); + } +#endif } - + /******************************************************************************* * xTraceOpenLabel - * + * * Creates user event labels for user event channels or for individual events. * User events can be used to log application events and data for display in * the visualization tool. A user event is identified by a label, i.e., a string, * which is stored in the recorder's symbol table. * When logging a user event, a numeric handle (reference) to this string is - * used to identify the event. This is obtained by calling - * + * used to identify the event. This is obtained by calling + * * xTraceOpenLabel() * * which adds the string to the symbol table (if not already present) @@ -1407,15 +1255,18 @@ to keep va_arg and i consistent. */ * ... * vTraceUserEvent(myEventHandle); * - * The second option is faster since no lookup is required on each event, and + * The second option is faster since no lookup is required on each event, and * therefore recommended for user events that are frequently * executed and/or located in time-critical code. The lookup operation is * however fairly fast due to the design of the symbol table. ******************************************************************************/ traceLabel xTraceOpenLabel(const char* label) { + TRACE_ASSERT(label != NULL, "xTraceOpenLabel: label == NULL", (traceLabel)0); + return prvTraceOpenSymbol(label, 0); } -#endif + #endif +#endif \ No newline at end of file -- 2.39.5