/*******************************************************************************
 * Trace Recorder Library for Tracealyzer v4.4.1
 * Percepio AB, www.percepio.com
 *
 * trcExtensions.h
 *
 * The extension interface of the recorder library, allowing for tracing
 * function calls to any API without modifications. All that is needed is a
 * single #include line in the .c files calling the API.
 *
 * This can be used to provide more detailed traces, including calls to e.g.
 * middleware, drivers or important APIs in your application code. This can be
 * applied selectively to specified functions and may include selected
 * parameters as well as the return value.
 *
 * Unlike the "User Event" concept, an extension is intended for systematic use
 * and can benefit from all powerful features in Tracealyzer via host-side XML
 * files that configure how Tracealyzer should interpret each event.
 *
 * Extensions are self-contained and easy to integrate, which makes them
 * convenient for distribution. Software vendors can thus develop such
 * extensions and provide trace support for their users.
 *
 * An extension consists of two files:
 *
 *  - An extension header file (e.g. "api.tzext.h") - this defines how to
 *  trace the API function calls.
 *
 *  - An XML file for the Tracealyzer application (e.g. "api-v1.0.0.xml").
 *  This needs to match the tracing setup in your extension header file.
 *
 *
 * USAGE
 *
 * This description assumes you already have the extension files for the APIs you
 * like to trace. To include them, follow these steps:
 *
 * 1. Update trcExtensions.h with respect to:
 *
 *    1.1. TRC_CFG_EXTENSION_COUNT: The number of extensions to enable (max 4).
 *
 *    1.2. The name(s) of the extension header file(s) to include.
 *
 *    1.3. The Extension Prefix, i.e., the first part of the definition names
 *         used in each header file.
 *
 * 2. Add #include "trcExtensions.h" in all .c files calling the API:
 *
 *    #include ...
 *    #include "api.h"  // The API you like to trace
 *    #include ...
 *    #include "trcExtensions.h"
 *
 *    We recommend to put this as the LAST #include statement.
 *
 *    HOWEVER, don't include "trcExtensions.h" in the .c files containing the
 *    functions you intend to trace. The compiler will then complain about
 *    multiple definitions of the trace wrapper function.
 *
 * 3. Copy the extension XML file to the "Tracealyzer 4/cfg" folder.
 *    On Windows this is typically
 *
 *    C:\Program Files\Percepio\Tracealyzer 4\cfg
 *
 *
 * HOW IT WORKS
 *
 * By including "trcExtensions.h" in your .c files, the preprocessor will
 * redefine all calls of the functions specified in the extension header file.
 * Calls to those functions will now instead call the "trace wrapper functions"
 * defined in the extension header. The trace wrapper functions then call the
 * original function as well as the trace recorder library.
 *
 * call foo(a) ----> foo__trace(a) -----> foo(a)
 *                                 -----> trace recorder library
 *
 * Note that the trace wrapper function should have the same declaration as the
 * original function (apart from the name) and also returns any return value
 * back to the original caller. So functionally this is completely transparent.
 *
 * This works also for calls via function pointers, as the assignments of the
 * function pointers will be affected, so the function pointers will point to
 * the trace wrapper function.
 *
 * It even works when calling binary libraries, since only the calling code
 * is modified, not the API itself.
 *
 * Extensions include a version code (Major.Minor.Patch), which is registered
 * in the trace and also part of the XML file name. This way, Tracealyzer
 * automatically finds the matching XML file, even if you open a old trace
 * recorded using a earlier version of the extension (e.g. if the API has
 * changed).
 *
 * LIMITATIONS
 *
 * The main limitation of this automatic approach is that it only allows for
 * tracing call between different .c files. Moreover, you can't trace multiple
 * APIs with calls between them. This since the calling file must include
 * trcExtensions.h, while the called file must NOT include this.
 *
 * It is however possible to get around this limitation. You need to add
 * #undef lines for each affected function to locally disable the redefinition,
 * and modify each function call to instead call the trace wrapper function.
 *
 *   #include "trcExtensions.h"
 *   #undef foo
 *   ...
 *   void foo(int a)
 *   {
 *     ...
 *   }
 *   ...
 *   foo__trace(a); // in another function - call foo and trace it
 *
 * These changes can remain in your code if you like, as the trace wrappers
 * works even if the recorder is disabled.
 *
 * MAKING YOUR OWN EXTENSIONS
 *
 * Examples are found in the extensions directory. We recommend that you start
 * by looking at aws_secure_sockets files (.h and .xml) that provides a basic
 * example. The aws_wifi files provides a more advanced example.
 * The header files include detailed documentation about how to design them,
 *
 * The XML files should have the same name as specified in the NAME property
 * in the header file, followed by the version, i.e.
 *
 * <NAME>-v<VERSION_MAJOR>.<<VERSION_MINOR>.<VERSION_PATCH>.xml
 *
 * Documentation for the XML file format is not yet available, but is under
 * development.
 *
 *
 * Terms of Use
 * This file is part of the trace recorder library (RECORDER), which is the
 * intellectual property of Percepio AB (PERCEPIO) and provided under a
 * license as follows.
 * The RECORDER may be used free of charge for the purpose of recording data
 * intended for analysis in PERCEPIO products. It may not be used or modified
 * for other purposes without explicit permission from PERCEPIO.
 * You may distribute the RECORDER in its original source code form, assuming
 * this text (terms of use, disclaimer, copyright notice) is unchanged. You are
 * allowed to distribute the RECORDER with minor modifications intended for
 * configuration or porting of the RECORDER, e.g., to allow using it on a
 * specific processor, processor family or with a specific communication
 * interface. Any such modifications should be documented directly below
 * this comment block.
 *
 * Disclaimer
 * The RECORDER is being delivered to you AS IS and PERCEPIO makes no warranty
 * as to its use or performance. PERCEPIO does not and cannot warrant the
 * performance or results you may obtain by using the RECORDER or documentation.
 * PERCEPIO make no warranties, express or implied, as to noninfringement of
 * third party rights, merchantability, or fitness for any particular purpose.
 * In no event will PERCEPIO, its technology partners, or distributors be liable
 * to you for any consequential, incidental or special damages, including any
 * lost profits or lost savings, even if a representative of PERCEPIO has been
 * advised of the possibility of such damages, or for any claim by any third
 * party. Some jurisdictions do not allow the exclusion or limitation of
 * incidental, consequential or special damages, or the exclusion of implied
 * warranties or limitations on how long an implied warranty may last, so the
 * above limitations may not apply to you.
 *
 * Tabs are used for indent in this file (1 tab = 4 spaces)
 *
 * Copyright Percepio AB, 2018.
 * www.percepio.com
 ******************************************************************************/

#ifndef TRCEXTENSIONS_H_
#define TRCEXTENSIONS_H_

#include "trcRecorder.h"

/******************************************************************************
 * TRC_CFG_EXTENSION_COUNT
 *
 * Defines the number of extensions included in the trace. Maximum 4 extensions
 * can be included.
 *
 * Default value is 0 (extension support disabled).
 *
 *****************************************************************************/
#define TRC_CFG_EXTENSION_COUNT 0

/******************************************************************************
 * TRC_CFG_EXT_MAX_NAME_LEN
 *
 * Defines the maximum length of extension name(s), i.e. the <EXTENSION>_NAME
 * macro(s) in trcExtensions.h.
 *
 * This value should will by rounded up to the nearest multiple of 4, and must
 * not be zero. To disable extension support, see TRC_CFG_EXTENSION_COUNT.
 *
 * It is important that this setting is large enough so extension names are
 * not truncated, otherwise the host-side Tracealyzer application won't be able
 * to find the corresponding XML file.
 *
 * You may adjust this to reduce memory usage, or increase it to allow for
 * longer extension names.
 *
 * Default value is 20.
 *****************************************************************************/
#define TRC_CFG_EXT_MAX_NAME_LEN	20

/******************************************************************************
 * TRC_EXTENSION_EVENTCODE_BASE
 *
 * The first event code used for the Extension system. This will be the first
 * event code of the first extension, and other event codes are relative to
 * this. This can be modified but this is normally not required.
 *****************************************************************************/
#define TRC_EXTENSION_EVENTCODE_BASE 256

/*** Included Extensions ******************************************************
 *
 * Below you specify what extensions to include. For each
 * extension you must define:
 *
 * - HEADER: The header file that defines the trace extension.
 *
 * - EXTENSION_PREFIX: The first part of the HEADER definition names.
 *
 *****************************************************************************/
#define TRC_EXT1_HEADER 	"aws_secure_sockets.tzext.h"
#define TRC_EXT1_PREFIX 	TRC_EXT_SOCKETS

#define TRC_EXT2_HEADER 	"aws_wifi.tzext.h"
#define TRC_EXT2_PREFIX 	TRC_EXT_WIFI

#define TRC_EXT3_HEADER		"Here you specify the header file for Extensions 3."
#define TRC_EXT3_PREFIX		NOT_DEFINED

#define TRC_EXT4_HEADER		"Here you specify the header file for Extensions 4."
#define TRC_EXT4_PREFIX		NOT_DEFINED

/*** Don't modify below ******************************************************/

#define ROUNDUP4(n) (4*((n+3)/4))

typedef struct{
	uint16_t firstEventCode;
	uint16_t lastEventCode;
	uint16_t patchVersion;
	uint8_t minorVersion;
	uint8_t majorVersion;
	char name[ROUNDUP4(TRC_CFG_EXT_MAX_NAME_LEN)];
} PSFExtensionEntryType;

typedef struct{
	uint16_t extensionEntryCount;
	uint16_t baseEventCode;
#if (TRC_CFG_EXTENSION_COUNT > 0)
	uint8_t extensionEntryNameMaxLength;
	uint8_t extensionEntrySize;
	PSFExtensionEntryType extension[TRC_CFG_EXTENSION_COUNT];
#endif
} PSFExtensionInfoType;


extern PSFExtensionInfoType PSFExtensionInfo;

#define CAT(a, ...) PRIMITIVE_CAT(a, __VA_ARGS__)
#define PRIMITIVE_CAT(a, ...) a ## __VA_ARGS__

#define TRC_EXT_BASECODE (PSFExtensionInfo.extension[TRC_EXT_NUMBER-1].firstEventCode)

#if (TRC_CFG_EXTENSION_COUNT >= 1)
	#ifdef TRC_EXT1_HEADER
		#define TRC_EXT_NUMBER 1
		#include TRC_EXT1_HEADER
		#undef TRC_EXT_NUMBER
	#endif
#endif

#if (TRC_CFG_EXTENSION_COUNT >= 2)
	#ifdef TRC_EXT2_HEADER
		#define TRC_EXT_NUMBER 2
		#include TRC_EXT2_HEADER
		#undef TRC_EXT_NUMBER
	#endif
#endif

#if (TRC_CFG_EXTENSION_COUNT >= 3)
	#ifdef TRC_EXT3_HEADER
		#define TRC_EXT_NUMBER 3
		#include TRC_EXT3_HEADER
		#undef TRC_EXT_NUMBER
	#endif
#endif

#if (TRC_CFG_EXTENSION_COUNT == 4)
	#ifdef TRC_EXT3_HEADER
		#define TRC_EXT_NUMBER 4
		#include TRC_EXT4_HEADER
		#undef TRC_EXT_NUMBER
	#endif
#endif

#define TRC_EXT1_COUNT CAT(TRC_EXT1_PREFIX, _COUNT)
#define TRC_EXT2_COUNT CAT(TRC_EXT2_PREFIX, _COUNT)
#define TRC_EXT3_COUNT CAT(TRC_EXT3_PREFIX, _COUNT)
#define TRC_EXT4_COUNT CAT(TRC_EXT4_PREFIX, _COUNT)

#define TRC_EXT1_NAME CAT(TRC_EXT1_PREFIX, _NAME)
#define TRC_EXT2_NAME CAT(TRC_EXT2_PREFIX, _NAME)
#define TRC_EXT3_NAME CAT(TRC_EXT3_PREFIX, _NAME)
#define TRC_EXT4_NAME CAT(TRC_EXT4_PREFIX, _NAME)

#define TRC_EXT1_VERSION_MAJOR CAT(TRC_EXT1_PREFIX, _VERSION_MAJOR)
#define TRC_EXT2_VERSION_MAJOR CAT(TRC_EXT2_PREFIX, _VERSION_MAJOR)
#define TRC_EXT3_VERSION_MAJOR CAT(TRC_EXT3_PREFIX, _VERSION_MAJOR)
#define TRC_EXT4_VERSION_MAJOR CAT(TRC_EXT4_PREFIX, _VERSION_MAJOR)

#define TRC_EXT1_VERSION_MINOR CAT(TRC_EXT1_PREFIX, _VERSION_MINOR)
#define TRC_EXT2_VERSION_MINOR CAT(TRC_EXT2_PREFIX, _VERSION_MINOR)
#define TRC_EXT3_VERSION_MINOR CAT(TRC_EXT3_PREFIX, _VERSION_MINOR)
#define TRC_EXT4_VERSION_MINOR CAT(TRC_EXT4_PREFIX, _VERSION_MINOR)

#define TRC_EXT1_VERSION_PATCH CAT(TRC_EXT1_PREFIX, _VERSION_PATCH)
#define TRC_EXT2_VERSION_PATCH CAT(TRC_EXT2_PREFIX, _VERSION_PATCH)
#define TRC_EXT3_VERSION_PATCH CAT(TRC_EXT3_PREFIX, _VERSION_PATCH)
#define TRC_EXT4_VERSION_PATCH CAT(TRC_EXT4_PREFIX, _VERSION_PATCH)

#if ((TRC_CFG_EXTENSION_COUNT > 4) || (TRC_CFG_EXTENSION_COUNT < 0))
	#error "TRC_CFG_EXTENSION_COUNT must be in range [0..4]"
#endif

#if (TRC_CFG_EXTENSION_COUNT == 0)
#define TRC_EXTENSIONS_DATA
#endif

#if (TRC_CFG_EXTENSION_COUNT == 1)
#define TRC_EXTENSIONS_DATA \
{ \
	{	TRC_EXTENSION_EVENTCODE_BASE, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT-1, \
		TRC_EXT1_VERSION_PATCH, \
		TRC_EXT1_VERSION_MINOR, \
		TRC_EXT1_VERSION_MAJOR, \
		TRC_EXT1_NAME } \
}
#endif

#if (TRC_CFG_EXTENSION_COUNT == 2)
#define TRC_EXTENSIONS_DATA \
{ \
	{	TRC_EXTENSION_EVENTCODE_BASE, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT-1, \
		TRC_EXT1_VERSION_PATCH, \
		TRC_EXT1_VERSION_MINOR, \
		TRC_EXT1_VERSION_MAJOR, \
		TRC_EXT1_NAME } \
	,{	TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT-1, \
		TRC_EXT2_VERSION_PATCH, \
		TRC_EXT2_VERSION_MINOR, \
		TRC_EXT2_VERSION_MAJOR, \
		TRC_EXT2_NAME } \
}
#endif

#if (TRC_CFG_EXTENSION_COUNT == 3)
#define TRC_EXTENSIONS_DATA \
{ \
	{	TRC_EXTENSION_EVENTCODE_BASE, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT-1, \
		TRC_EXT1_VERSION_PATCH, \
		TRC_EXT1_VERSION_MINOR, \
		TRC_EXT1_VERSION_MAJOR, \
		TRC_EXT1_NAME } \
	,{	TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT-1, \
		TRC_EXT2_VERSION_PATCH, \
		TRC_EXT2_VERSION_MINOR, \
		TRC_EXT2_VERSION_MAJOR, \
		TRC_EXT2_NAME } \
	,{	TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT + TRC_EXT3_COUNT - 1, \
		TRC_EXT3_VERSION_PATCH, \
		TRC_EXT3_VERSION_MINOR, \
		TRC_EXT3_VERSION_MAJOR, \
		TRC_EXT3_NAME } \
}
#endif
#if (TRC_CFG_EXTENSION_COUNT == 4)
#define TRC_EXTENSIONS_DATA \
{ \
	{	TRC_EXTENSION_EVENTCODE_BASE, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT-1, \
		TRC_EXT1_VERSION_PATCH, \
		TRC_EXT1_VERSION_MINOR, \
		TRC_EXT1_VERSION_MAJOR, \
		TRC_EXT1_NAME } \
	,{	TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT-1, \
		TRC_EXT2_VERSION_PATCH, \
		TRC_EXT2_VERSION_MINOR, \
		TRC_EXT2_VERSION_MAJOR, \
		TRC_EXT2_NAME } \
	,{	TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT + TRC_EXT3_COUNT - 1, \
		TRC_EXT3_VERSION_PATCH, \
		TRC_EXT3_VERSION_MINOR, \
		TRC_EXT3_VERSION_MAJOR, \
		TRC_EXT3_NAME } \
	,{	TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT + TRC_EXT3_COUNT, \
		TRC_EXTENSION_EVENTCODE_BASE + TRC_EXT1_COUNT + TRC_EXT2_COUNT + TRC_EXT3_COUNT + TRC_EXT4_COUNT- 1, \
		TRC_EXT4_VERSION_PATCH, \
		TRC_EXT4_VERSION_MINOR, \
		TRC_EXT4_VERSION_MAJOR, \
		TRC_EXT4_NAME } \
}
#endif

#if (TRC_CFG_EXTENSION_COUNT > 0)
#define TRC_EXTENSION_INFO {TRC_CFG_EXTENSION_COUNT, TRC_EXTENSION_EVENTCODE_BASE, ROUNDUP4(TRC_CFG_EXT_MAX_NAME_LEN), sizeof(PSFExtensionEntryType), TRC_EXTENSIONS_DATA}
#else
#define TRC_EXTENSION_INFO {TRC_CFG_EXTENSION_COUNT, TRC_EXTENSION_EVENTCODE_BASE}
#endif

#endif /* TRCEXTENSIONS_H_ */
