/*******************************************************************************
 * Tracealyzer v2.5.0 Recorder Library
 * Percepio AB, www.percepio.com
 *
 * trcUser.h
 * The public API 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 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 TRCUSER_H
#define TRCUSER_H

#ifdef __cplusplus
extern "C" {
#endif

#include "trcKernelPort.h"

#if (USE_TRACEALYZER_RECORDER == 1)

#ifndef USE_SEPARATE_USER_EVENT_BUFFER
#define USE_SEPARATE_USER_EVENT_BUFFER 0
#endif

/*******************************************************************************
 * 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
 * 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
 * error. In that case, check vTraceGetLastError to get the error message.
 * Any error message is also presented when opening a trace file.
 *
 ******************************************************************************/
uint32_t uiTraceStart(void);

/*******************************************************************************
 * 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
 * has a too small value (NTASK, NQUEUE, etc).
 *
 * This function is obsolete, but has been saved for backwards compatibility.
 * We recommend using uiTraceStart instead.
 ******************************************************************************/
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.
 ******************************************************************************/
void vTraceStop(void);

/*******************************************************************************
 * xTraceGetLastError
 *
 * Gives the last error message, if any. NULL if no error message is stored.
 * Any error message is also presented when opening a trace file.
 ******************************************************************************/
char* xTraceGetLastError(void);

/*******************************************************************************
 * vTraceClear
 *
 * Resets the recorder. Only necessary if a restart is desired - this is not
 * needed in the startup initialization.
 ******************************************************************************/
void vTraceClear(void);

/*******************************************************************************
* vTraceClearError
*
* Removes any previous error message generated by recorder calling vTraceError.
* By calling this function, it may be possible to start/restart the trace
* despite errors in the recorder, but there is no guarantee that the trace
* recorder will work correctly in that case, depending on the type of error.
******************************************************************************/
void vTraceClearError(int resetErrorMessage);

#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
 * started.
 *
 * Example:
 *     #define ID_ISR_TIMER1 1       // lowest valid ID is 1
 *     #define PRIO_OF_ISR_TIMER1 3  // the hardware priority of the interrupt
 *     ...
 *     vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);
 *     ...
 *     void ISR_handler()
 *     {
 *         portENTER_CRITICAL(); // Required if nested ISRs are allowed
 *         vTraceStoreISRBegin(ID_OF_ISR_TIMER1);
 *         portEXIT_CRITICAL();
 *         ...
 *         portENTER_CRITICAL(); // Required if nested ISRs are allowed
 *         vTraceStoreISREnd();
 *         portEXIT_CRITICAL();
 *     }
 ******************************************************************************/
void vTraceSetISRProperties(objectHandleType handle, const char* name, char priority);

/*******************************************************************************
 * vTraceStoreISRBegin
 *
 * 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
 *     #define PRIO_OF_ISR_TIMER1 3  // the hardware priority of the interrupt
 *     ...
 *     vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);
 *     ...
 *     void ISR_handler()
 *     {
 *         portENTER_CRITICAL(); // Required if nested ISRs are allowed
 *         vTraceStoreISRBegin(ID_OF_ISR_TIMER1);
 *         portEXIT_CRITICAL();
 *         ...
 *         portENTER_CRITICAL(); // Required if nested ISRs are allowed
 *         vTraceStoreISREnd();
 *         portEXIT_CRITICAL();
 *     }
 *
 ******************************************************************************/
void vTraceStoreISRBegin(objectHandleType id);

/*******************************************************************************
 * vTraceStoreISREnd
 *
 * Registers the end 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
 *     #define PRIO_OF_ISR_TIMER1 3  // the hardware priority of the interrupt
 *     ...
 *     vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);
 *     ...
 *     void ISR_handler()
 *     {
 *         portENTER_CRITICAL(); // Required if nested ISRs are allowed
 *         vTraceStoreISRBegin(ID_OF_ISR_TIMER1);
 *         portEXIT_CRITICAL();
 *         ...
 *         portENTER_CRITICAL(); // Required if nested ISRs are allowed
 *         vTraceStoreISREnd();
 *         portEXIT_CRITICAL();
 *     }
 *
 ******************************************************************************/
void vTraceStoreISREnd(void);

#else
   /* If not including the ISR recording */

void vTraceIncreaseISRActive(void);

void vTraceDecreaseISRActive(void);

#define vTraceSetISRProperties(handle, name, priority)
#define vTraceStoreISRBegin(id) vTraceIncreaseISRActive()
#define vTraceStoreISREnd() vTraceDecreaseISRActive()

#endif

/*******************************************************************************
 * 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 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
 * 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
 * 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,
 * e.g., in case a debugger connection is not available for uploading the data.
 ******************************************************************************/
uint32_t uiTraceGetTraceBufferSize(void);

#if (INCLUDE_USER_EVENTS == 1)

/*******************************************************************************
 * 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
 *
 *     xTraceOpenLabel()
 *
 * whihc adds the string to the symbol table (if not already present)
 * and returns the corresponding handle.
 *
 * This can be used in two ways:
 *
 * 1. The handle is looked up every time, when storing the user event.
 *
 * Example:
 *     vTraceUserEvent(xTraceOpenLabel("MyUserEvent"));
 *
 * 2. The label is registered just once, with the handle stored in an
 *  application variable - much like using a file handle.
 *
 * Example:
 *     myEventHandle = xTraceOpenLabel("MyUserEvent");
 *     ...
 *     vTraceUserEvent(myEventHandle);
 *
 * 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);

 /******************************************************************************
 * 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
 *
 * 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
 * stores the arguments. The actual formatting is done
 * 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",
 *                 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",
 *                 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
 * better to use vTraceUserEvent - it is faster.
 *
 * Format specifiers supported:
 *  %d - 32 bit signed integer
 *  %u - 32 bit unsigned integer
 *  %f - 32 bit float
 *  %s - string (is copied to the recorder symbol table)
 *  %hd - 16 bit signed integer
 *  %hu - 16 bit unsigned integer
 *  %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
 * 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)
 * 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
 * "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

#else

/* Empty defines for user functions to avoid compiler errors if trace is not to be used */

#define vTraceInitTraceData()
#define uiTraceStart() (1) // Fake "success", if used when recorder is excluded from build
#define vTraceStart()
#define vTraceStop()
#define vTraceClear()
#define vTraceStartStatusMonitor()
#define vTraceGetTraceBuffer() ((void*)0)
#define uiTraceGetTraceBufferSize() 0
#define xTraceOpenLabel(label) 0
#define vTraceUserEvent(eventLabel)
#define vTracePrintF(eventLabel,formatStr,...)
#define vTraceExcludeTaskFromSchedulingTrace(name)

#define vTraceTaskSkipDefaultInstanceFinishedEvents()
#define vTraceSetISRProperties(handle, name, priority)
#define vTraceStoreISRBegin(id)
#define vTraceStoreISREnd()
#endif

#ifdef __cplusplus
}
#endif

#endif
