]> git.sur5r.net Git - freertos/blobdiff - FreeRTOS-Plus/Source/FreeRTOS-Plus-Trace/trcUser.c
+ New feature added: Task notifications.
[freertos] / FreeRTOS-Plus / Source / FreeRTOS-Plus-Trace / trcUser.c
index 2e4bc1aac9565056c1843d760ac55f0bb8b3de74..57c53ffbca848973f108a4a20d364ffebeb757c2 100644 (file)
@@ -1,5 +1,5 @@
 /*******************************************************************************\r
- * FreeRTOS+Trace v2.3.0 Recorder Library\r
+ * Tracealyzer v2.7.0 Recorder Library\r
  * Percepio AB, www.percepio.com\r
  *\r
  * trcUser.c\r
  * Terms of Use\r
  * This software is copyright Percepio AB. The recorder library is free for\r
  * use together with Percepio products. You may distribute the recorder library\r
- * in its original form, including modifications in trcPort.c and trcPort.h\r
+ * in its original form, including modifications in trcHardwarePort.c/.h\r
  * given that these modification are clearly marked as your own modifications\r
- * and documented in the initial comment section of these source files. \r
- * This software is the intellectual property of Percepio AB and may not be \r
- * sold or in other ways commercially redistributed without explicit written \r
+ * and documented in the initial comment section of these source files.\r
+ * This software is the intellectual property of Percepio AB and may not be\r
+ * sold or in other ways commercially redistributed without explicit written\r
  * permission by Percepio AB.\r
  *\r
- * Disclaimer \r
- * The trace tool and recorder library is being delivered to you AS IS and \r
- * Percepio AB makes no warranty as to its use or performance. Percepio AB does \r
- * not and cannot warrant the performance or results you may obtain by using the \r
- * software or documentation. Percepio AB make no warranties, express or \r
- * implied, as to noninfringement of third party rights, merchantability, or \r
- * fitness for any particular purpose. In no event will Percepio AB, its \r
- * technology partners, or distributors be liable to you for any consequential, \r
- * incidental or special damages, including any lost profits or lost savings, \r
- * even if a representative of Percepio AB has been advised of the possibility \r
- * of such damages, or for any claim by any third party. Some jurisdictions do \r
- * not allow the exclusion or limitation of incidental, consequential or special \r
- * damages, or the exclusion of implied warranties or limitations on how long an \r
+ * Disclaimer\r
+ * The trace tool and recorder library is being delivered to you AS IS and\r
+ * Percepio AB makes no warranty as to its use or performance. Percepio AB does\r
+ * not and cannot warrant the performance or results you may obtain by using the\r
+ * software or documentation. Percepio AB make no warranties, express or\r
+ * implied, as to noninfringement of third party rights, merchantability, or\r
+ * fitness for any particular purpose. In no event will Percepio AB, its\r
+ * technology partners, or distributors be liable to you for any consequential,\r
+ * incidental or special damages, including any lost profits or lost savings,\r
+ * even if a representative of Percepio AB has been advised of the possibility\r
+ * of such damages, or for any claim by any third party. Some jurisdictions do\r
+ * not allow the exclusion or limitation of incidental, consequential or special\r
+ * damages, or the exclusion of implied warranties or limitations on how long an\r
  * implied warranty may last, so the above limitations may not apply to you.\r
  *\r
- * FreeRTOS+Trace is available as Free Edition and in two premium editions.\r
- * You may use the premium features during 30 days for evaluation.\r
- * Download FreeRTOS+Trace at http://www.percepio.com/products/downloads/\r
+ * Tabs are used for indent in this file (1 tab = 4 spaces)\r
  *\r
- * Copyright Percepio AB, 2012.\r
+ * Copyright Percepio AB, 2014.\r
  * www.percepio.com\r
  ******************************************************************************/\r
+#include "FreeRTOS.h"\r
+#include "task.h"\r
+\r
+#include "trcUser.h"\r
+\r
+#if (USE_TRACEALYZER_RECORDER == 1)\r
 \r
 #include <string.h>\r
 #include <stdarg.h>\r
+#include <stdint.h>\r
 \r
-#include "trcUser.h"\r
-#include "task.h"\r
-#include "semphr.h"\r
-\r
-#if (configUSE_TRACE_FACILITY == 1)\r
+TRACE_STOP_HOOK vTraceStopHookPtr = (TRACE_STOP_HOOK)0;\r
 \r
 extern uint8_t inExcludedTask;\r
 extern uint8_t nISRactive;\r
-extern uint8_t handle_of_last_logged_task;\r
+extern objectHandleType handle_of_last_logged_task;\r
 extern uint32_t dts_min;\r
 extern uint32_t hwtc_count_max_after_tick;\r
 extern uint32_t hwtc_count_sum_after_tick;\r
 extern uint32_t hwtc_count_sum_after_tick_counter;\r
-extern unsigned char ucQueueGetQueueType(void*);\r
-extern unsigned char ucQueueGetQueueNumber(void*);\r
 extern char* traceErrorMessage;\r
-static void vTraceMonitorTask(void);\r
-static void prvTraceExcludeOrIncludeKernelServiceFromTrace(traceKernelService, uint8_t);\r
-    \r
+\r
+/*** Private functions *******************************************************/\r
+void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list vl);\r
+\r
+#if (USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
+void vTraceChannelPrintF_Helper(UserEventChannel channelPair, va_list vl);\r
+static void prvTraceUserEventHelper1(UserEventChannel channel, traceLabel eventLabel, traceLabel formatLabel, va_list vl);\r
+static void prvTraceUserEventHelper2(UserEventChannel channel, uint32_t* data, uint32_t noOfSlots);\r
+#endif\r
+\r
+static void prvTraceTaskInstanceFinish(int8_t direct);\r
+\r
+\r
 /*******************************************************************************\r
- * vTraceMonitorTask\r
+ * vTraceInitTraceData\r
  *\r
- * A task which periodically reports the recorder status to the console.\r
- * This is included depending on USE_TRACE_PROGRESS_MONITOR_TASK.\r
+ * Allocates, if necessary, and initializes the recorder data structure, based\r
+ * on the constants in trcConfig.h.\r
  ******************************************************************************/\r
-static void vTraceMonitorTask(void)\r
-{    \r
-    portTickType xNextWakeTime;\r
-    char localsprintbuffer[90];\r
-    char* err = NULL;    \r
-    char* lastErr = NULL;      \r
-    #define STATE_INIT 0\r
-    #define STATE_STARTED 1\r
-    #define STATE_STOPPED 2    \r
-    int state = STATE_INIT;\r
-    \r
-    vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Monitor task started...\n\r");\r
-\r
-    /* Initialise xNextWakeTime - this only needs to be done once. */\r
-    xNextWakeTime = xTaskGetTickCount();\r
-\r
-    for (;;)\r
-    {\r
-        lastErr = err;        \r
-        err = xTraceGetLastError();\r
-        if (err != lastErr)\r
-        {\r
-            sprintf(localsprintbuffer, "\n\r[FreeRTOS+Trace] Error: %s\n\r", err);\r
-            vTraceConsoleMessage(localsprintbuffer); \r
-        }\r
-        \r
-        if (state == STATE_STOPPED || state == STATE_INIT) \r
-        {\r
-            if (RecorderDataPtr->recorderActive == 1)\r
-            {\r
-                state = STATE_STARTED;\r
-                vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Recorder started.\n\r");                                       \r
-            }\r
-            else\r
-            {\r
-                if (state == STATE_INIT)\r
-                {\r
-                    \r
-                    vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Recorder not started.\n\r");\r
-                    state = STATE_STOPPED;\r
-                }\r
-            }\r
-        }\r
-        \r
-        if (state == STATE_STARTED)\r
-        {\r
-            if (RecorderDataPtr->frequency > 0)\r
-            {\r
-                sprintf(localsprintbuffer, \r
-                    "\n\r[FreeRTOS+Trace] Event count: %d, Duration: %d ms. [%d ticks]\n\r", \r
-                    (int)RecorderDataPtr->numEvents, \r
-                    (int)(RecorderDataPtr->absTimeLastEventSecond*1000 + (RecorderDataPtr->absTimeLastEvent*1000)/ RecorderDataPtr->frequency), (int)xTaskGetTickCount());\r
-                vTraceConsoleMessage(localsprintbuffer);\r
-            }\r
-\r
-            if (RecorderDataPtr->recorderActive == 0)\r
-            {\r
-                state = STATE_STOPPED;\r
-                vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Recorder stopped.\n\r");                                       \r
-                vTracePortEnd();\r
-            }\r
-                \r
-\r
-        }\r
-\r
-    /* Place this task in the blocked state until it is time to run again. */\r
-        vTaskDelayUntil( &xNextWakeTime, TRACE_PROGRESS_MONITOR_TASK_PERIOD);\r
-        \r
-    }\r
+void vTraceInitTraceData(void)\r
+{\r
+       prvTraceInitTraceData();\r
 }\r
 \r
 /*******************************************************************************\r
- * vTraceClear\r
+ * vTraceSetRecorderData\r
  *\r
- * Resets the recorder. Only necessary if a restart is desired - this is not \r
- * needed in the startup initialization.\r
+ * If custom allocation is used, this function must be called so the recorder\r
+ * library knows where to save the trace data.\r
  ******************************************************************************/\r
-void vTraceClear(void)\r
+#if TRACE_DATA_ALLOCATION == TRACE_DATA_ALLOCATION_CUSTOM\r
+void vTraceSetRecorderData(void* pRecorderData)\r
 {\r
-    trcCRITICAL_SECTION_BEGIN();\r
-    \r
-    RecorderDataPtr->absTimeLastEvent = 0;\r
-    RecorderDataPtr->nextFreeIndex = 0;\r
-    RecorderDataPtr->numEvents = 0;\r
-    RecorderDataPtr->bufferIsFull = 0;\r
-\r
-    trcCRITICAL_SECTION_END();\r
-    \r
+       TRACE_ASSERT(pRecorderData != NULL, "vTraceSetTraceData, pRecorderData == NULL", );\r
+       RecorderDataPtr = pRecorderData;\r
 }\r
+#endif\r
 \r
 /*******************************************************************************\r
- * vTraceStartStatusMonitor\r
- *\r
- * This starts a task to monitor the state of½ the recorder. \r
- * This task periodically prints a line to the console window, which shows the \r
- * number of events recorded and the latest timestamp. This task\r
- * calls vTracePortEnd when the recorder has been stopped, where custom\r
- * actions can be added, e.g., to store the trace to a file\r
- * if a file system is available on the device.\r
+ * vTraceSetStopHook\r
+ *\r
+ * Sets a function to be called when the recorder is stopped.\r
  ******************************************************************************/\r
-void vTraceStartStatusMonitor(void)\r
-{    \r
-    vTraceConsoleMessage("\n\r[FreeRTOS+Trace] Starting Trace Status Monitor...\n\r");\r
-    (void)xTaskCreate( (pdTASK_CODE)vTraceMonitorTask, (const signed char*)"TraceMon", TRACE_PROGRESS_MONITOR_TASK_STACKSIZE, NULL, TRACE_PROGRESS_MONITOR_TASK_PRIORITY, NULL );\r
+void vTraceSetStopHook(TRACE_STOP_HOOK stopHookFunction)\r
+{\r
+       vTraceStopHookPtr = stopHookFunction;\r
+}\r
+\r
+/*******************************************************************************\r
+ * vTraceClear\r
+ *\r
+ * Resets the recorder. Only necessary if a restart is desired - this is not\r
+ * needed in the startup initialization.\r
+ ******************************************************************************/\r
+void vTraceClear(void)\r
+{\r
+       TRACE_SR_ALLOC_CRITICAL_SECTION();\r
+       trcCRITICAL_SECTION_BEGIN();\r
+\r
+       RecorderDataPtr->absTimeLastEventSecond = 0;\r
+\r
+       RecorderDataPtr->absTimeLastEvent = 0;\r
+       RecorderDataPtr->nextFreeIndex = 0;\r
+       RecorderDataPtr->numEvents = 0;\r
+       RecorderDataPtr->bufferIsFull = 0;\r
+       traceErrorMessage = NULL;\r
+       RecorderDataPtr->internalErrorOccured = 0;\r
+\r
+       memset(RecorderDataPtr->eventData, 0, RecorderDataPtr->maxEvents * 4);\r
+\r
+       trcCRITICAL_SECTION_END();\r
+\r
 }\r
 \r
 /*******************************************************************************\r
  * uiTraceStart\r
  *\r
  * Starts the recorder. The recorder will not be started if an error has been\r
- * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h \r
+ * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h\r
  * has a too small value (NTASK, NQUEUE, etc).\r
- * \r
+ *\r
  * Returns 1 if the recorder was started successfully.\r
- * Returns 0 if the recorder start was prevented due to a previous internal \r
+ * Returns 0 if the recorder start was prevented due to a previous internal\r
  * error. In that case, check vTraceGetLastError to get the error message.\r
- * Any error message is also presented when opening a trace file in \r
- * FreeRTOS+Trace v2.2.2 or later.\r
+ * Any error message is also presented when opening a trace file.\r
  ******************************************************************************/\r
 \r
 uint32_t uiTraceStart(void)\r
-{        \r
-    if (traceErrorMessage == NULL)\r
-    {\r
-        trcCRITICAL_SECTION_BEGIN();\r
-        RecorderDataPtr->recorderActive = 1;\r
-        vTraceStoreTaskswitch(); /* Register the currently running task */\r
-        trcCRITICAL_SECTION_END();\r
-    }\r
-\r
-    return RecorderDataPtr->recorderActive;\r
+{\r
+       objectHandleType handle;\r
+       TRACE_SR_ALLOC_CRITICAL_SECTION();\r
+\r
+       handle = 0;\r
+\r
+       if (RecorderDataPtr == NULL)\r
+       {\r
+               vTraceError("RecorderDataPtr is NULL. Call vTraceInitTraceData() before starting trace.");\r
+               return 0;\r
+       }\r
+\r
+       if (traceErrorMessage == NULL)\r
+       {\r
+               trcCRITICAL_SECTION_BEGIN();\r
+               RecorderDataPtr->recorderActive = 1;\r
+\r
+               handle = TRACE_GET_TASK_NUMBER(TRACE_GET_CURRENT_TASK());\r
+               if (handle == 0)\r
+               {\r
+                       /* This occurs if the scheduler is not yet started.\r
+                       This creates a dummy "(startup)" task entry internally in the\r
+                       recorder */\r
+                       handle = xTraceGetObjectHandle(TRACE_CLASS_TASK);\r
+                       vTraceSetObjectName(TRACE_CLASS_TASK, handle, "(startup)");\r
+\r
+                       vTraceSetPriorityProperty(TRACE_CLASS_TASK, handle, 0);\r
+               }\r
+\r
+               vTraceStoreTaskswitch(handle); /* Register the currently running task */\r
+               trcCRITICAL_SECTION_END();\r
+       }\r
+\r
+       return RecorderDataPtr->recorderActive;\r
 }\r
 \r
 /*******************************************************************************\r
- * vTraceStart \r
+ * vTraceStart\r
  *\r
  * Starts the recorder. The recorder will not be started if an error has been\r
- * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h \r
+ * indicated using vTraceError, e.g. if any of the Nx constants in trcConfig.h\r
  * has a too small value (NTASK, NQUEUE, etc).\r
- * \r
- * This function is obsolete, but has been saved for backwards compatibility. \r
+ *\r
+ * This function is obsolete, but has been saved for backwards compatibility.\r
  * We recommend using uiTraceStart instead.\r
  ******************************************************************************/\r
 void vTraceStart(void)\r
-{        \r
-    (void)uiTraceStart();\r
+{\r
+       (void)uiTraceStart();\r
 }\r
 \r
 /*******************************************************************************\r
  * vTraceStop\r
  *\r
  * Stops the recorder. The recording can be resumed by calling vTraceStart.\r
- * This does not reset the recorder. Use vTraceClear is that is desired.\r
+ * This does not reset the recorder. Use vTraceClear if that is desired.\r
  ******************************************************************************/\r
 void vTraceStop(void)\r
 {\r
-    RecorderDataPtr->recorderActive = 0;\r
+       RecorderDataPtr->recorderActive = 0;\r
+\r
+       if (vTraceStopHookPtr != (TRACE_STOP_HOOK)0)\r
+       {\r
+               (*vTraceStopHookPtr)();                 /* An application call-back function. */\r
+       }\r
 }\r
 \r
 /*******************************************************************************\r
  * xTraceGetLastError\r
  *\r
  * Gives the last error message, if any. NULL if no error message is stored.\r
- * The message is cleared on read.\r
- * Any error message is also presented when opening a trace file in \r
- * FreeRTOS+Trace v2.2.2 or later.\r
+ * Any error message is also presented when opening a trace file.\r
  ******************************************************************************/\r
 char* xTraceGetLastError(void)\r
-{   \r
-    return traceErrorMessage;\r
+{\r
+       return traceErrorMessage;\r
+}\r
+\r
+/*******************************************************************************\r
+* vTraceClearError\r
+*\r
+* Removes any previous error message generated by recorder calling vTraceError.\r
+* By calling this function, it may be possible to start/restart the trace\r
+* despite errors in the recorder, but there is no guarantee that the trace\r
+* recorder will work correctly in that case, depending on the type of error.\r
+******************************************************************************/\r
+void vTraceClearError(int resetErrorMessage)\r
+{\r
+       ( void ) resetErrorMessage;\r
+       traceErrorMessage = NULL;\r
+       RecorderDataPtr->internalErrorOccured = 0;\r
 }\r
 \r
 /*******************************************************************************\r
  * vTraceGetTraceBuffer\r
- * \r
- * Returns a pointer to the recorder data structure. Use this together with \r
- * uiTraceGetTraceBufferSize if you wish to implement an own store/upload \r
- * solution, e.g., in case a debugger connection is not available for uploading \r
+ *\r
+ * Returns a pointer to the recorder data structure. Use this together with\r
+ * uiTraceGetTraceBufferSize if you wish to implement an own store/upload\r
+ * solution, e.g., in case a debugger connection is not available for uploading\r
  * the data.\r
  ******************************************************************************/\r
 void* vTraceGetTraceBuffer(void)\r
 {\r
-    return RecorderDataPtr;\r
+       return RecorderDataPtr;\r
 }\r
 \r
 /*******************************************************************************\r
  * uiTraceGetTraceBufferSize\r
- * \r
- * Gets the size of the recorder data structure. For use together with \r
- * vTraceGetTraceBuffer if you wish to implement an own store/upload solution, \r
+ *\r
+ * Gets the size of the recorder data structure. For use together with\r
+ * vTraceGetTraceBuffer if you wish to implement an own store/upload solution,\r
  * e.g., in case a debugger connection is not available for uploading the data.\r
  ******************************************************************************/\r
 uint32_t uiTraceGetTraceBufferSize(void)\r
 {\r
-    return sizeof(RecorderDataType);\r
-}\r
-\r
-/*******************************************************************************\r
- * prvTraceExcludeOrIncludeKernelServiceFromTrace\r
- * \r
- * Includes or excludes all events that is related to the kernel service.\r
- ******************************************************************************/\r
-static void prvTraceExcludeOrIncludeKernelServiceFromTrace(traceKernelService kernelService, uint8_t flag)\r
-{\r
-    switch(kernelService)\r
-    {\r
-    case TRACE_KERNEL_SERVICE_TASK_CREATE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_TASK);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_TASK);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_TASK);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_TASK);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_TASK_DELETE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_TASK);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_TASK);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_TASK_DELAY:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY_UNTIL);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_DELAY_UNTIL);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_PRIORITY_SET:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_PRIORITY_SET);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_PRIORITY_SET);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_TASK_SUSPEND:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_SUSPEND);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_SUSPEND);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_TASK_RESUME:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_RESUME);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(TASK_RESUME_FROM_ISR);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_RESUME);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(TASK_RESUME_FROM_ISR);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_QUEUE_CREATE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_QUEUE);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_QUEUE);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_QUEUE_DELETE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_QUEUE);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_QUEUE);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_QUEUE_SEND:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_QUEUE);\r
-            \r
-            \r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_QUEUE);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_QUEUE_RECEIVE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_QUEUE);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_QUEUE);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_QUEUE_PEEK:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_QUEUE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_MUTEX);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_QUEUE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_PEEK + TRACE_CLASS_MUTEX);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_MUTEX_CREATE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_MUTEX);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_MUTEX);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_MUTEX_DELETE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_MUTEX);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_MUTEX);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_MUTEX_GIVE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_MUTEX);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_MUTEX);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_MUTEX_TAKE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_MUTEX);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_MUTEX);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_MUTEX);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_MUTEX);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_SEMAPHORE_CREATE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_SEMAPHORE);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_CREATE + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_CREATE + TRACE_CLASS_SEMAPHORE);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_SEMAPHORE_DELETE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_SEMAPHORE);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_DELETE + TRACE_CLASS_SEMAPHORE);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_SEMAPHORE_GIVE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_SEMAPHORE);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_SEND + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_SEND_FROM_ISR + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_SEND_FROM_ISR + TRACE_CLASS_SEMAPHORE);\r
-        }\r
-        break;\r
-    case TRACE_KERNEL_SERVICE_SEMAPHORE_TAKE:\r
-        if (flag)\r
-        {\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_SEMAPHORE);\r
-            SET_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_SEMAPHORE);\r
-        }\r
-        else\r
-        {\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_BLOCK_ON_RECEIVE + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_RECEIVE_FROM_ISR + TRACE_CLASS_SEMAPHORE);\r
-            CLEAR_EVENT_CODE_FLAG_ISEXCLUDED(EVENTGROUP_FAILED_RECEIVE_FROM_ISR + TRACE_CLASS_SEMAPHORE);\r
-        }\r
-        break;\r
-    }\r
+       return sizeof(RecorderDataType);\r
 }\r
 \r
 /******************************************************************************\r
- * vTraceExclude______FromTrace\r
+ * prvTraceTaskInstanceFinish.\r
  *\r
- * Excludes a task or object from the trace.\r
- * This can be useful if some irrelevant task is very frequent and is "eating\r
- * up the buffer". This should be called after the task has been created, but \r
- * before starting the FreeRTOS scheduler.\r
+ * Private common function for the vTraceTaskInstanceFinishXXX functions.\r
+ * \r
  *****************************************************************************/\r
-void vTraceExcludeQueueFromTrace(void* handle)\r
+void prvTraceTaskInstanceFinish(int8_t direct)\r
 {\r
-    SET_QUEUE_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle));\r
-}\r
+       TaskInstanceStatusEvent* tis;\r
+       uint8_t dts45;\r
 \r
-void vTraceExcludeSemaphoreFromTrace(void* handle)\r
-{\r
-    SET_SEMAPHORE_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle));\r
-}\r
-\r
-void vTraceExcludeMutexFromTrace(void* handle)\r
-{\r
-    SET_MUTEX_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle));\r
-}\r
+       TRACE_SR_ALLOC_CRITICAL_SECTION();\r
 \r
-void vTraceExcludeTaskFromTrace(void* handle)\r
-{\r
-    SET_TASK_FLAG_ISEXCLUDED(uxTaskGetTaskNumber(handle));\r
-}\r
+       trcCRITICAL_SECTION_BEGIN();\r
+       if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task)\r
+       {\r
+               dts45 = (uint8_t)prvTraceGetDTS(0xFF);\r
+               tis = (TaskInstanceStatusEvent*) xTraceNextFreeEventBufferSlot();\r
+               if (tis != NULL)\r
+               {\r
+                       if (direct == 0)\r
+                               tis->type = TASK_INSTANCE_FINISHED_NEXT_KSE;\r
+                       else\r
+                               tis->type = TASK_INSTANCE_FINISHED_DIRECT;\r
 \r
-void vTraceExcludeKernelServiceFromTrace(traceKernelService kernelService)\r
-{\r
-    prvTraceExcludeOrIncludeKernelServiceFromTrace(kernelService, 1);\r
+                       tis->dts = dts45;\r
+                       prvTraceUpdateCounters();\r
+               }\r
+       }\r
+       trcCRITICAL_SECTION_END();\r
 }\r
 \r
 /******************************************************************************\r
- * vTraceInclude______InTrace\r
+ * vTraceTaskInstanceFinish(void)\r
  *\r
- * Includes a task, object or kernel service in the trace. This is only\r
- * necessary if the task or object has been previously exluded.\r
- *****************************************************************************/\r
-void vTraceIncludeQueueInTrace(void* handle)\r
-{\r
-    CLEAR_QUEUE_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle));\r
-}\r
-\r
-void vTraceIncludeSemaphoreInTrace(void* handle)\r
-{\r
-    CLEAR_SEMAPHORE_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle));\r
-}\r
-\r
-void vTraceIncludeMutexInTrace(void* handle)\r
-{\r
-    CLEAR_MUTEX_FLAG_ISEXCLUDED(ucQueueGetQueueNumber(handle));\r
-}\r
-\r
-void vTraceIncludeTaskInTrace(void* handle)\r
-{\r
-    CLEAR_TASK_FLAG_ISEXCLUDED(uxTaskGetTaskNumber(handle));\r
-}\r
-\r
-void vTraceIncludeKernelServiceInTrace(traceKernelService kernelService)\r
-{\r
-    prvTraceExcludeOrIncludeKernelServiceFromTrace(kernelService, 0);\r
-}\r
-\r
-/*******************************************************************************\r
- * vTraceSetQueueName\r
+ * Marks the current task instance as finished on the next kernel call.\r
+ *\r
+ * If that kernel call is blocking, the instance ends after the blocking event\r
+ * and the corresponding return event is then the start of the next instance.\r
+ * If the kernel call is not blocking, the viewer instead splits the current\r
+ * fragment right before the kernel call, which makes this call the first event\r
+ * of the next instance.\r
  *\r
- * Assigns a name to a FreeRTOS Queue, Semaphore or Mutex. This function should\r
- * be called right after creation of the queue/mutex/semaphore. If not using \r
- * this function, the queues/mutexes/semaphores will be presented by their\r
- * numeric handle only.\r
+ * See also USE_IMPLICIT_IFE_RULES in trcConfig.h\r
  *\r
  * Example:\r
- *     actuatorQ = xQueueCreate(3, sizeof(QueueMessage));\r
- *     vTraceSetQueueName(actuatorQ, "ActuatorQueue");\r
- ******************************************************************************/\r
-void vTraceSetQueueName(void* queue, const char* name)\r
+ *\r
+ *             while(1)\r
+ *             {\r
+ *                     xQueueReceive(CommandQueue, &command, timeoutDuration);\r
+ *                     processCommand(command);\r
+ *          vTraceInstanceFinish();\r
+ *             }\r
+ *\r
+ * Note: This is only supported in Tracealyzer tools v2.7 or later\r
+ *\r
+ *****************************************************************************/\r
+void vTraceTaskInstanceFinish(void)\r
 {\r
-    int t = ucQueueGetQueueType(queue);    \r
-    vTraceSetObjectName(TraceObjectClassTable[t], \r
-                        (objectHandleType)ucQueueGetQueueNumber(queue), name);\r
+    prvTraceTaskInstanceFinish(0);\r
 }\r
 \r
-\r
 /******************************************************************************\r
- * vTraceTaskInstanceIsFinished\r
- * \r
- * This defines an explicit Instance Finish Event for the current task. It tells \r
- * the recorder that the current instance of this task is finished at the next \r
- * kernel call of the task, e.g., a taskDelay or a queue receive. This function \r
- * should be called right before the api function call considered to be the end \r
- * of the current task instance, i.e., the Instance Finish Event.\r
+ * vTraceTaskInstanceFinishDirect(void)\r
+ *\r
+ * Marks the current task instance as finished at this very instant.\r
+ * This makes the viewer to splits the current fragment at this point and begin\r
+ * a new actor instance.\r
+ *\r
+ * See also USE_IMPLICIT_IFE_RULES in trcConfig.h\r
+ *\r
+ * Example:\r
+ *\r
+ *             This example will generate two instances for each loop iteration.\r
+ *             The first instance ends at vTraceInstanceFinishDirect(), while the second\r
+ *      instance ends at the next xQueueReceive call.\r
+ *\r
+ *             while (1)\r
+ *             {\r
+ *          xQueueReceive(CommandQueue, &command, timeoutDuration);\r
+ *                     ProcessCommand(command);\r
+ *                     vTraceInstanceFinishDirect();\r
+ *                     DoSometingElse();\r
+ *          vTraceInstanceFinish();\r
+ *      }\r
+ *\r
+ * Note: This is only supported in Tracealyzer tools v2.7 or later\r
+ *\r
  *****************************************************************************/\r
-void vTraceTaskInstanceIsFinished()\r
+void vTraceTaskInstanceFinishDirect(void)\r
 {\r
-    if (handle_of_last_logged_task)\r
-    {\r
-        SET_TASK_FLAG_MARKIFE(handle_of_last_logged_task);    \r
-    }\r
+       prvTraceTaskInstanceFinish(1);\r
 }\r
 \r
 /*******************************************************************************\r
- * vvTraceTaskSkipDefaultInstanceFinishedEvents\r
- *\r
- * This is useful if there are implicit Instance Finish Events, such as \r
- * vTaskDelayUntil or xQueueReceive, in a task where an explicit Instance Finish \r
- * Event has been defined. This function tells the recorder that only the \r
- * explicitly defined functions, using vTraceTaskInstanceIsFinished, should be\r
- * treated as Instance Finish Events for this task. The implicit Instance Finish \r
- * Events are thus disregarded for the calling task.\r
- ******************************************************************************/\r
-void vTraceTaskSkipDefaultInstanceFinishedEvents()\r
-{    \r
-    if (handle_of_last_logged_task)\r
-    {\r
-        PROPERTY_TASK_IFE_SERVICECODE(handle_of_last_logged_task) = \r
-          RESERVED_DUMMY_CODE;\r
-    }\r
-}\r
-\r
-/*******************************************************************************\r
- * Interrupt recording functions \r
+ * Interrupt recording functions\r
  ******************************************************************************/\r
 \r
 #if (INCLUDE_ISR_TRACING == 1)\r
@@ -663,214 +368,319 @@ static uint8_t isrstack[MAX_ISR_NESTING];
 \r
 /*******************************************************************************\r
  * vTraceSetISRProperties\r
- * \r
+ *\r
  * Registers an Interrupt Service Routine in the recorder library, This must be\r
- * called before using vTraceStoreISRBegin to store ISR events. This is \r
- * typically called in the startup of the system, before the scheduler is \r
+ * called before using vTraceStoreISRBegin to store ISR events. This is\r
+ * typically called in the startup of the system, before the scheduler is\r
  * started.\r
  *\r
  * Example:\r
- *     #define ID_ISR_TIMER1 1       // lowest valid ID is 1\r
- *     #define PRIO_OF_ISR_TIMER1 3  // the hardware priority of the interrupt\r
- *     ...\r
- *     vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);\r
- *     ...\r
- *     void ISR_handler()\r
- *     {\r
- *         vTraceStoreISRBegin(ID_OF_ISR_TIMER1);\r
- *         ...\r
- *         vTraceStoreISREnd();\r
- *     }\r
- *\r
- * NOTE: To safely record ISRs, you need to make sure that all traced \r
- * interrupts actually are disabled by trcCRITICAL_SECTION_BEGIN(), which \r
- * typically is mapped to portENTER_CRITICAL(), which uses the macro \r
- * portDISABLE_INTERRUPTS. However, in some ports of FreeRTOS and depending on \r
- * FreeRTOS configuration, this does not disable high priority interrupts!\r
+ *      #define ID_ISR_TIMER1 1                // lowest valid ID is 1\r
+ *      #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt\r
+ *      ...\r
+ *      vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);\r
+ *      ...\r
+ *      void ISR_handler()\r
+ *      {\r
+ *              vTraceStoreISRBegin(ID_OF_ISR_TIMER1);\r
+ *              ...\r
+ *              vTraceStoreISREnd(0);\r
+ *      }\r
+ *\r
+ * NOTE: To safely record ISRs, you need to make sure that all traced\r
+ * interrupts actually are disabled by trcCRITICAL_SECTION_BEGIN(). However,\r
+ * in some ports this does not disable high priority interrupts!\r
  * If an ISR calls vTraceStoreISRBegin while the recorder is busy, it will\r
  * stop the recording and give an error message.\r
  ******************************************************************************/\r
 void vTraceSetISRProperties(objectHandleType handle, const char* name, char priority)\r
 {\r
-    vTraceSetObjectName(TRACE_CLASS_ISR, handle, name);\r
-    vTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority);\r
+       TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceSetISRProperties: Invalid value for handle", );\r
+       TRACE_ASSERT(name != NULL, "vTraceSetISRProperties: name == NULL", );\r
+\r
+       vTraceSetObjectName(TRACE_CLASS_ISR, handle, name);\r
+       vTraceSetPriorityProperty(TRACE_CLASS_ISR, handle, priority);\r
 }\r
 \r
+#if (SELECTED_PORT == PORT_ARM_CortexM)\r
+/******************************************************************************\r
+ * (Advanced...)\r
+ *\r
+ * ISR_TAILCHAINING_THRESHOLD (For Cortex-M devices only)\r
+ *\r
+ * ARM Cortex-M devices may execute ISRs back-to-back (tail-chained) without\r
+ * resuming the previous context in between. Since this is decided in\r
+ * hardware, we can only detect this indirectly, in the following manner:\r
+ *\r
+ * When entering vTraceStoreISRBegin, we check the number of CPU cycles since\r
+ * the last return of vTraceStoreISREnd. If less or equal to the constant\r
+ * ISR_TAILCHAINING_THRESHOLD it is assumed that the ISRs executed back-to-back\r
+ * (tail-chained). In that case, the previously stored RESUME event\r
+ * (pointed to by ptrLastISRExitEvent) is then deleted to avoid showing a\r
+ * fragment of the previous context in between the ISR events. The delete is\r
+ * made by replacing the event code with a XTS16L event, that serves to keep\r
+ * the differential timestamp from the earlier event.\r
+ *\r
+ * The value of ISR_TAILCHAINING_THRESHOLD depends on the interrupt latency of\r
+ * the processor, on the compiler and on the compiler settings, but should be\r
+ * around 70 cycles. The default value is 66 cycles, which should be correct when\r
+ * using GCC with optimizations disabled (-O0) and Cortex-M3/M4.\r
+ *\r
+ * To measure this value, see MEASURE_ISR_TAILCHAINING_THRESHOLD below.\r
+ *\r
+ * If this value set too low, tail-chained ISRs will incorrectly be shown\r
+ * separated, with a short fragment of the previous task or ISR in between.\r
+ * If this value is set too high, you get the opposite effect - separate ISRs\r
+ * will appear to execute tail-chained and will appear to have higher execution\r
+ * time and response time (maximum ISR_TAILCHAINING_THRESHOLD cycles more).\r
+ *\r
+ * Read the blog post explaining this on our website:\r
+ * http://percepio.com/2014/05/06/sw-based-exc-tracing-arm-cortex-m/\r
+ *\r
+ *****************************************************************************/\r
+#define ISR_TAILCHAINING_THRESHOLD 66\r
+\r
+uint8_t* ptrLastISRExitEvent = NULL;\r
+uint32_t DWTCycleCountAtLastISRExit = 0;\r
+\r
+/******************************************************************************\r
+ * (Advanced...)\r
+ *\r
+ * MEASURE_ISR_TAILCHAINING_THRESHOLD (For Cortex-M devices only)\r
+ *\r
+ * Allows for calibrating the value of ISR_TAILCHAINING_THRESHOLD (see above).\r
+ *\r
+ * This is intended to measure the minimum number of clock cycles from the end\r
+ * of vTraceStoreISREnd to the beginning of the following vTraceStoreISRBegin.\r
+ * For this purpose, we assume a test setup using the SysTick interrupt, which\r
+ * is available on most Cortex-M devices and typically used by the RTOS kernel.\r
+ * To do the measurement, follow these steps:\r
+ *\r
+ * 1. Make sure MEASURE_ISR_TAILCHAINING_THRESHOLD is enabled (defined as 1)\r
+ *\r
+ * 2. Temporarily replace your SysTick handler with the following:\r
+ *\r
+ *     void xPortSysTickHandler( void )\r
+ *     {\r
+ *             vTraceStoreISRBegin(1);\r
+ *             vTraceStoreISREnd(0);\r
+ *     }\r
+ *\r
+ * 3. To make sure that the ISRs execute back-to-back, increase the OS tick\r
+ *     frequency to a very high level so that the OS tick interrupt execute\r
+ *     continuously with no application tasks in between, e.g. 10 MHz.\r
+ *\r
+ * 4. Put a breakpoint in the highest priority task and make sure it is not\r
+ *     reached. This means that the SysTick handler is executing at maximum rate\r
+ *     and thereby tail-chained, where the interrupt latency is 6 cycles.\r
+ *\r
+ * 5. Let the system run without breakpoints and inspect the value of\r
+ *     threshold_low_watermark. This is the minimum total latency observed.\r
+ *     The hardware latency is 6 clock cycles due to the tail-chaining, so the\r
+ *     software latency (SL) is then SL = threshold_low_watermark - 6.\r
+ *\r
+ * The threshold value ISR_TAILCHAINING_THRESHOLD should be SL + 2 * HL, where\r
+ * HL is the normal hardware interrupt latency, i.e., the number of CPU\r
+ * cycles to enter or exit the exception handler for an exception in task\r
+ * context. The HL value is 12-16 depending on core, as shown below.\r
+ *\r
+ * Values for ISR_TAILCHAINING_THRESHOLD, assuming SL = 42\r
+ *     Cortex-M3 and M4 (HL = 12):     66 cycles\r
+ *     Cortex-M0 (HL = 16):            74 cycles\r
+ *     Cortex-M0+ (HL = 15):           72 cycles\r
+ *\r
+ * If the ISR_TAILCHAINING_THRESHOLD value is set too low, some tail-chained\r
+ * ISRs be shown separated, with a short fragment of the previous context\r
+ * in between. On the other hand, if the value is set too high, ISRs that \r
+ * actually are separated may appear to execute back-to-back (tail-chained).\r
+ *\r
+ * Read the blog post explaining this on our website:\r
+ * http://percepio.com/2014/05/06/sw-based-exc-tracing-arm-cortex-m/\r
+ *\r
+ *****************************************************************************/\r
+#define MEASURE_ISR_TAILCHAINING_THRESHOLD 1\r
+\r
+#if (MEASURE_ISR_TAILCHAINING_THRESHOLD == 1)\r
+volatile uint32_t threshold_low_watermark = 2000000000;\r
+#endif\r
+\r
+#endif\r
+\r
 /*******************************************************************************\r
  * vTraceStoreISRBegin\r
- * \r
+ *\r
  * Registers the beginning of an Interrupt Service Routine.\r
  *\r
  * Example:\r
- *     #define ID_ISR_TIMER1 1       // lowest valid ID is 1\r
- *     #define PRIO_OF_ISR_TIMER1 3  // the hardware priority of the interrupt\r
- *     ...\r
- *     vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);\r
- *     ...\r
- *     void ISR_handler()\r
- *     {\r
- *         vTraceStoreISRBegin(ID_OF_ISR_TIMER1);\r
- *         ...\r
- *         vTraceStoreISREnd();\r
- *     }\r
- *\r
- * NOTE: You need to make sure that any traced interrupts actually are \r
- * disabled by trcCRITICAL_SECTION_BEGIN(), i.e., taskENTER_CRITICAL() which\r
- * uses portDISABLE_INTERRUPTS(). \r
- * In some ports of FreeRTOS, this does not disable high-priority interrupts,\r
- * i.e., with priorities above configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
- * If an invalid call to vTraceStoreISRBegin is detected (i.e., that preempted\r
- * a critical section of the recorder) this will generate a recorder error \r
- * using vTraceError.\r
+ *      #define ID_ISR_TIMER1 1                // lowest valid ID is 1\r
+ *      #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt\r
+ *      ...\r
+ *      vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);\r
+ *      ...\r
+ *      void ISR_handler()\r
+ *      {\r
+ *              vTraceStoreISRBegin(ID_OF_ISR_TIMER1);\r
+ *              ...\r
+ *              vTraceStoreISREnd(0);\r
+ *      }\r
+ *\r
  ******************************************************************************/\r
 void vTraceStoreISRBegin(objectHandleType handle)\r
 {\r
-    uint16_t dts4;\r
-    TSEvent* ts = NULL;\r
-\r
-    if (recorder_busy)\r
-    {\r
-      vTraceError("Illegal call to vTraceStoreISRBegin/End");\r
-      return;\r
-    }\r
-    if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
-    {    \r
-        trcCRITICAL_SECTION_BEGIN();\r
-        dts4 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
-\r
-        if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */    \r
-        {    \r
-\r
-            if (nISRactive < MAX_ISR_NESTING)\r
-            {    \r
-                isrstack[nISRactive] = handle;\r
-                nISRactive++;            \r
-                ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
-                if (ts != NULL)\r
-                {\r
-                    ts->type = TS_ISR_BEGIN;\r
-                    ts->dts = dts4;\r
-                    ts->objHandle = handle;\r
-                    prvTraceUpdateCounters();                \r
-                }\r
-            }\r
-            else\r
-            {            \r
-                /* This should not occur unless something is very wrong */            \r
-                vTraceError("Too many nested interrupts!");\r
-            }        \r
-        }\r
-        trcCRITICAL_SECTION_END();        \r
-    }\r
-}\r
+       uint16_t dts4;\r
+       #if (SELECTED_PORT == PORT_ARM_CortexM)\r
+       uint32_t CPUCyclesSinceLastISRExit = REG_DWT_CYCCNT - DWTCycleCountAtLastISRExit;\r
+       #endif\r
+       TSEvent* ts;\r
+       TRACE_SR_ALLOC_CRITICAL_SECTION();\r
 \r
+       ts = NULL;\r
 \r
 #if (SELECTED_PORT == PORT_ARM_CortexM)\r
+       if (DWTCycleCountAtLastISRExit > 0)\r
+       {\r
+               #if (MEASURE_ISR_TAILCHAINING_THRESHOLD == 1)\r
+               /* Allows for verifying the value of ISR_TAILCHAINING_THRESHOLD */\r
+               if (CPUCyclesSinceLastISRExit < threshold_low_watermark)\r
+               {\r
+                       threshold_low_watermark = CPUCyclesSinceLastISRExit;\r
+               }\r
+               #endif\r
 \r
-int tailchain_irq_pending(void);\r
-\r
-/*******************************************************************************\r
- * tailchain_irq_pending\r
- *\r
- * For Cortex-M chips only. Returns 1 if an interrupt is pending, by checking \r
- * the 8 NVIC IRQ pend registers at 0xE000E200 to 0xE000E21C. Returns 0 if no \r
- * interrupt is pending. This is used to predict tailchaining of ISRs.\r
- ******************************************************************************/\r
-int tailchain_irq_pending(void)\r
-{\r
-  uint32_t* pend_reg = ((uint32_t*)0xE000E200);\r
-  int i;\r
-\r
-  for (i=0; i<8; i++)\r
-  {\r
-    if (pend_reg[i] != 0)\r
-    {\r
-      return 1;\r
-    }\r
-  }\r
-  return 0;  \r
-}\r
+               if (CPUCyclesSinceLastISRExit <= ISR_TAILCHAINING_THRESHOLD)\r
+               {\r
+                       /* This is judged to be a case of ISR tail-chaining since the\r
+                       number of cycles since the last vTraceStoreISREnd is shorter or equal to\r
+                       the threshold (ISR_TAILCHAINING_THRESHOLD) */\r
+\r
+                       if (ptrLastISRExitEvent != NULL)\r
+                       {\r
+                               /* Overwrite the last ISR exit event with a "neutral" event that only\r
+                                       accounts for the time passed */\r
+                               *ptrLastISRExitEvent = XTS16L;\r
+                       }\r
+               }\r
 \r
+       }\r
 #endif\r
 \r
+       if (recorder_busy)\r
+       {\r
+        vTraceError("Illegal call to vTraceStoreISRBegin, recorder busy!");\r
+        return;\r
+       }\r
+       trcCRITICAL_SECTION_BEGIN();\r
+       if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
+       {\r
+\r
+               TRACE_ASSERT(handle <= RecorderDataPtr->ObjectPropertyTable.NumberOfObjectsPerClass[TRACE_CLASS_ISR], "vTraceStoreISRBegin: Invalid value for handle", );\r
+\r
+               dts4 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+\r
+               if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+               {\r
+                       if (nISRactive < MAX_ISR_NESTING)\r
+                       {\r
+                               uint8_t hnd8 = prvTraceGet8BitHandle(handle);\r
+                               isrstack[nISRactive] = handle;\r
+                               nISRactive++;\r
+                               ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
+                               if (ts != NULL)\r
+                               {\r
+                                       ts->type = TS_ISR_BEGIN;\r
+                                       ts->dts = dts4;\r
+                                       ts->objHandle = hnd8;\r
+                                       prvTraceUpdateCounters();\r
+                               }\r
+                       }\r
+                       else\r
+                       {\r
+                               /* This should not occur unless something is very wrong */\r
+                               vTraceError("Too many nested interrupts!");\r
+                       }\r
+               }\r
+       }\r
+       trcCRITICAL_SECTION_END();\r
+}\r
+\r
 /*******************************************************************************\r
  * vTraceStoreISREnd\r
- * \r
- * Registers the end of an Interrupt Service Routine. \r
+ *\r
+ * Registers the end of an Interrupt Service Routine.\r
+ *\r
+ * The parameter pendingISR indicates if the interrupt has requested a\r
+ * task-switch (= 1) or if the interrupt returns to the earlier context (= 0)\r
  *\r
  * Example:\r
- *     #define ID_ISR_TIMER1 1       // lowest valid ID is 1\r
- *     #define PRIO_OF_ISR_TIMER1 3  // the hardware priority of the interrupt\r
- *     ...\r
- *     vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);\r
- *     ...\r
- *     void ISR_handler()\r
- *     {\r
- *         vTraceStoreISRBegin(ID_OF_ISR_TIMER1);\r
- *         ...\r
- *         vTraceStoreISREnd();\r
- *     }\r
- *\r
- * NOTE: You need to make sure that any traced interrupts actually are \r
- * disabled by trcCRITICAL_SECTION_BEGIN(), i.e., taskENTER_CRITICAL() which\r
- * uses portDISABLE_INTERRUPTS(). \r
- * In some ports of FreeRTOS, this does not disable high-priority interrupts,\r
- * i.e., with priorities above configMAX_SYSCALL_INTERRUPT_PRIORITY.\r
- * If an invalid call to vTraceStoreISREnd is detected (i.e., that preempted\r
- * a critical section of the recorder) this will generate a recorder error \r
- * using vTraceError.\r
+ *\r
+ *      #define ID_ISR_TIMER1 1                // lowest valid ID is 1\r
+ *      #define PRIO_OF_ISR_TIMER1 3 // the hardware priority of the interrupt\r
+ *      ...\r
+ *      vTraceSetISRProperties(ID_ISR_TIMER1, "ISRTimer1", PRIO_OF_ISR_TIMER1);\r
+ *      ...\r
+ *      void ISR_handler()\r
+ *      {\r
+ *              vTraceStoreISRBegin(ID_OF_ISR_TIMER1);\r
+ *              ...\r
+ *              vTraceStoreISREnd(0);\r
+ *      }\r
+ *\r
  ******************************************************************************/\r
-void vTraceStoreISREnd(void)\r
+void vTraceStoreISREnd(int pendingISR)\r
 {\r
-    TSEvent* ts;\r
-    uint16_t dts5;\r
-\r
-    if (recorder_busy)\r
-    {\r
-      vTraceError("Illegal call to vTraceStoreISRBegin/End");\r
-      return;\r
-    }\r
-    \r
-    if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
-    {\r
-        #if (SELECTED_PORT == PORT_ARM_CortexM)\r
-        if (tailchain_irq_pending() > 0)\r
-        {\r
-            nISRactive--; /* If an IRQ strikes exactly here, the resulting \r
-            ISR tailchaining is not detected. The trace instead shows a very \r
-            short fragment of the earlier preempted task/ISR, and then the new\r
-            ISR begins. */\r
-            return;\r
-        }\r
-        #endif\r
-      \r
-        trcCRITICAL_SECTION_BEGIN();\r
-        dts5 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
-\r
-        if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */    \r
-        {    \r
-            ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
-            if (ts != NULL)\r
-            {\r
-                if (nISRactive > 1)\r
-                {\r
-                    /* return to another isr */\r
-                    ts->type = TS_ISR_RESUME;\r
-                    ts->objHandle = isrstack[nISRactive];\r
-                }\r
-                else\r
-                {\r
-                    /* return to task */\r
-                    ts->type = TS_TASK_RESUME;\r
-                    ts->objHandle = handle_of_last_logged_task;\r
-                }\r
-                ts->dts = dts5;\r
-                nISRactive--;\r
-                prvTraceUpdateCounters();\r
-            }\r
-        }\r
-        trcCRITICAL_SECTION_END();        \r
-    }\r
+       TSEvent* ts;\r
+       uint16_t dts5;\r
+       TRACE_SR_ALLOC_CRITICAL_SECTION();\r
+\r
+       if (recorder_busy)\r
+       {\r
+               vTraceError("Illegal call to vTraceStoreISREnd, recorder busy!");\r
+               return;\r
+       }\r
+\r
+       trcCRITICAL_SECTION_BEGIN();\r
+       if (pendingISR == 0)\r
+       {\r
+               if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
+               {\r
+                       uint8_t hnd8, type;\r
+                       dts5 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+\r
+                       if (nISRactive > 1)\r
+                       {\r
+                               /* return to another isr */\r
+                               type = TS_ISR_RESUME;\r
+                               hnd8 = prvTraceGet8BitHandle(isrstack[nISRactive]);\r
+                       }\r
+                       else\r
+                       {\r
+                               /* return to task */\r
+                               type = TS_TASK_RESUME;\r
+                               hnd8 = prvTraceGet8BitHandle(handle_of_last_logged_task);\r
+                       }\r
+\r
+                       ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
+                       if (ts != NULL)\r
+                       {\r
+                               ts->type = type;\r
+                               ts->objHandle = hnd8;\r
+                               ts->dts = dts5;\r
+                               prvTraceUpdateCounters();\r
+                       }\r
+\r
+                       #if (SELECTED_PORT == PORT_ARM_CortexM)\r
+                       /* Remember the last ISR exit event, as the event needs to be modified in case of a following ISR entry (if tail-chained ISRs) */\r
+                       ptrLastISRExitEvent = (uint8_t*)ts;\r
+                       #endif\r
+               }\r
+       }\r
+       nISRactive--;\r
+\r
+       #if (SELECTED_PORT == PORT_ARM_CortexM)\r
+       DWTCycleCountAtLastISRExit = REG_DWT_CYCCNT;\r
+       #endif\r
+\r
+       trcCRITICAL_SECTION_END();\r
 }\r
 \r
 #else\r
@@ -878,141 +688,97 @@ void vTraceStoreISREnd(void)
 /* ISR tracing is turned off */\r
 void vTraceIncreaseISRActive(void)\r
 {\r
-    if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
-        nISRactive++;\r
+       if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
+               nISRactive++;\r
 }\r
 \r
-void vTraceDecreaseISRActive(objectHandleType handle)\r
+void vTraceDecreaseISRActive(void)\r
 {\r
-    if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
-        nISRactive--;\r
+       if (RecorderDataPtr->recorderActive && handle_of_last_logged_task)\r
+               nISRactive--;\r
 }\r
 #endif\r
 \r
 \r
-/*******************************************************************************\r
- * User Event functions\r
- ******************************************************************************/\r
+/********************************************************************************/\r
+/* User Event functions                                                                                                                        */\r
+/********************************************************************************/\r
 \r
 #if (INCLUDE_USER_EVENTS == 1)\r
 \r
- /******************************************************************************\r
- * vTraceUserEvent\r
- *\r
- * Basic user event (Standard and Professional Edition only)\r
- * \r
- * Generates a User Event with a text label. The label is created/looked up\r
- * in the symbol table using xTraceOpenLabel.\r
- ******************************************************************************/\r
-void vTraceUserEvent(traceLabel eventLabel)\r
-{\r
-    UserEvent* ue;\r
-    uint8_t dts1;\r
-\r
-    if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive ) && handle_of_last_logged_task)\r
-    {\r
-        trcCRITICAL_SECTION_BEGIN();\r
-\r
-        dts1 = (uint8_t)prvTraceGetDTS(0xFF);\r
-\r
-        if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */    \r
-        {       \r
-            ue = (UserEvent*) xTraceNextFreeEventBufferSlot();\r
-            if (ue != NULL)\r
-            {\r
-                ue->dts = dts1;\r
-                ue->type = USER_EVENT;\r
-                ue->payload = eventLabel;\r
-                prvTraceUpdateCounters();\r
-            }\r
-        }\r
-        trcCRITICAL_SECTION_END();        \r
-    }\r
-}\r
-\r
-/*** Locally used in vTracePrintF ***/\r
-\r
-/* one word (32 bit) is required for the USER_EVENT entry, 8 words \r
-(8*32 bit = 32 byte) available for argument data */\r
-#define MAX_ARG_SIZE (4+32)    \r
-\r
-static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value);\r
-static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value);\r
-static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value);\r
-\r
-#if (INCLUDE_FLOAT_SUPPORT)\r
-static uint8_t writeFloat(void * buffer, uint8_t i, float value);\r
-static uint8_t writeDouble(void * buffer, uint8_t i, double value);\r
-#endif\r
-\r
+#define MAX_ARG_SIZE (4+32)\r
 /*** Locally used in vTracePrintF ***/\r
 static uint8_t writeInt8(void * buffer, uint8_t i, uint8_t value)\r
-{    \r
-    \r
-    if (i >= MAX_ARG_SIZE)\r
-    {\r
-        return 255;\r
-    }\r
+{\r
+       TRACE_ASSERT(buffer != NULL, "writeInt8: buffer == NULL", 0);\r
+\r
+       if (i >= MAX_ARG_SIZE)\r
+       {\r
+               return 255;\r
+       }\r
 \r
-    ((uint8_t*)buffer)[i] = value;\r
+       ((uint8_t*)buffer)[i] = value;\r
 \r
        if (i + 1 > MAX_ARG_SIZE)\r
        {\r
                return 255;\r
        }\r
 \r
-    return i + 1;\r
+       return i + 1;\r
 }\r
 \r
 /*** Locally used in vTracePrintF ***/\r
 static uint8_t writeInt16(void * buffer, uint8_t i, uint16_t value)\r
-{      \r
-    /* Align to multiple of 2 */\r
-    while ((i % 2) != 0)\r
-    {\r
+{\r
+       TRACE_ASSERT(buffer != NULL, "writeInt16: buffer == NULL", 0);\r
+\r
+       /* Align to multiple of 2 */\r
+       while ((i % 2) != 0)\r
+       {\r
                if (i >= MAX_ARG_SIZE)\r
                {\r
                        return 255;\r
                }\r
-                       \r
-        ((uint8_t*)buffer)[i] = 0;\r
-        i++;        \r
-    }\r
-    \r
-    if (i + 2 > MAX_ARG_SIZE)\r
-    {\r
-        return 255;\r
-    }\r
-\r
-    ((uint16_t*)buffer)[i/2] = value;\r
-\r
-    return i + 2;\r
+\r
+               ((uint8_t*)buffer)[i] = 0;\r
+               i++;\r
+       }\r
+\r
+       if (i + 2 > MAX_ARG_SIZE)\r
+       {\r
+               return 255;\r
+       }\r
+\r
+       ((uint16_t*)buffer)[i/2] = value;\r
+\r
+       return i + 2;\r
 }\r
 \r
 /*** Locally used in vTracePrintF ***/\r
 static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value)\r
 {\r
-    \r
-    /* A 32 bit value should begin at an even 4-byte address */\r
-    while ((i % 4) != 0)\r
-    {\r
+       TRACE_ASSERT(buffer != NULL, "writeInt32: buffer == NULL", 0);\r
+\r
+       /* A 32 bit value should begin at an even 4-byte address */\r
+       while ((i % 4) != 0)\r
+       {\r
                if (i >= MAX_ARG_SIZE)\r
                {\r
                        return 255;\r
                }\r
-               \r
-        ((uint8_t*)buffer)[i] = 0;\r
-        i++;\r
-    }\r
-    \r
-    if (i + 4 > MAX_ARG_SIZE)\r
-    {\r
-        return 255;\r
-    }        \r
-\r
-    ((uint32_t*)buffer)[i/4] = value;\r
-\r
-    return i + 4;\r
+\r
+               ((uint8_t*)buffer)[i] = 0;\r
+               i++;\r
+       }\r
+\r
+       if (i + 4 > MAX_ARG_SIZE)\r
+       {\r
+               return 255;\r
+       }\r
+\r
+       ((uint32_t*)buffer)[i/4] = value;\r
+\r
+       return i + 4;\r
 }\r
 \r
 #if (INCLUDE_FLOAT_SUPPORT)\r
@@ -1020,374 +786,693 @@ static uint8_t writeInt32(void * buffer, uint8_t i, uint32_t value)
 /*** Locally used in vTracePrintF ***/\r
 static uint8_t writeFloat(void * buffer, uint8_t i, float value)\r
 {\r
-    /* A 32 bit value should begin at an even 4-byte address */\r
-    while ((i % 4) != 0)\r
-    {\r
+       TRACE_ASSERT(buffer != NULL, "writeFloat: buffer == NULL", 0);\r
+\r
+       /* A 32 bit value should begin at an even 4-byte address */\r
+       while ((i % 4) != 0)\r
+       {\r
                if (i >= MAX_ARG_SIZE)\r
                {\r
                        return 255;\r
                }\r
 \r
-        ((uint8_t*)buffer)[i] = 0;\r
-        i++;\r
-    }\r
+               ((uint8_t*)buffer)[i] = 0;\r
+               i++;\r
+       }\r
+\r
+       if (i + 4 > MAX_ARG_SIZE)\r
+       {\r
+               return 255;\r
+       }\r
 \r
-    if (i + 4 > MAX_ARG_SIZE)\r
-    {\r
-        return 255;\r
-    }        \r
+       ((float*)buffer)[i/4] = value;\r
 \r
-    ((float*)buffer)[i/4] = value;\r
-    \r
-    return i + 4;\r
+       return i + 4;\r
 }\r
 \r
 /*** Locally used in vTracePrintF ***/\r
 static uint8_t writeDouble(void * buffer, uint8_t i, double value)\r
 {\r
-    uint32_t * dest = buffer;\r
-    uint32_t * src = (void*)&value;\r
-    /* The double is written as two 32 bit values, and should begin at an even \r
-    4-byte address (to avoid having to align with 8 byte) */\r
-    while (i % 4 != 0)\r
-    {\r
+       uint32_t * dest;\r
+       uint32_t * src = (uint32_t*)&value;\r
+\r
+       TRACE_ASSERT(buffer != NULL, "writeDouble: buffer == NULL", 0);\r
+\r
+       /* The double is written as two 32 bit values, and should begin at an even\r
+       4-byte address (to avoid having to align with 8 byte) */\r
+       while (i % 4 != 0)\r
+       {\r
                if (i >= MAX_ARG_SIZE)\r
                {\r
                        return 255;\r
                }\r
 \r
-        ((uint8_t*)buffer)[i] = 0;\r
-        i++;        \r
-    }\r
-    \r
-    if (i + 8 > MAX_ARG_SIZE)\r
-    {\r
-        return 255;\r
-    }       \r
-    \r
-    dest[i/4+0] = src[0];\r
-    dest[i/4+1] = src[1];\r
-    \r
-    return i + 8;\r
+               ((uint8_t*)buffer)[i] = 0;\r
+               i++;\r
+       }\r
+\r
+       if (i + 8 > MAX_ARG_SIZE)\r
+       {\r
+               return 255;\r
+       }\r
+\r
+       dest = &(((uint32_t *)buffer)[i/4]);\r
+\r
+       dest[0] = src[0];\r
+       dest[1] = src[1];\r
+\r
+       return i + 8;\r
 }\r
 \r
 #endif\r
 \r
- /******************************************************************************\r
- * vTracePrintF \r
- * \r
+/*******************************************************************************\r
+ * prvTraceUserEventFormat\r
+ *\r
+ * Parses the format string and stores the arguments in the buffer.\r
+ ******************************************************************************/\r
+static uint8_t prvTraceUserEventFormat(const char* formatStr, va_list vl, uint8_t* buffer, uint8_t byteOffset)\r
+{\r
+       uint16_t formatStrIndex = 0;\r
+       uint8_t argCounter = 0;\r
+       uint8_t i = byteOffset;\r
+\r
+       while (formatStr[formatStrIndex] != '\0')\r
+       {\r
+               if (formatStr[formatStrIndex] == '%')\r
+               {\r
+                       argCounter++;\r
+\r
+                       if (argCounter > 15)\r
+                       {\r
+                               vTraceError("vTracePrintF - Too many arguments, max 15 allowed!");\r
+                               return 0;\r
+                       }\r
+\r
+                       /*******************************************************************************\r
+                       * These below code writes raw data (primitive datatypes) in the event buffer,\r
+                       * instead of the normal event structs (where byte 0 is event type).\r
+                       * These data entries must never be interpreted as real event data, as the type\r
+                       * field would be misleading since used for payload data.\r
+                       *\r
+                       * The correctness of this encoding depends on two mechanisms:\r
+                       *\r
+                       * 1. An initial USER_EVENT, which type code tells the number of 32-bit data\r
+                       * entires that follows. (code - USER_EVENT = number of data entries).\r
+                       * Note that a data entry corresponds to the slots that normally corresponds to\r
+                       * one (1) event, i.e., 32 bits. vTracePrintF may encode several pieces of data\r
+                       * in one data entry, e.g., two 16-bit values or four 8-bit values, one 16-bit\r
+                       * value followed by two 8-bit values, etc.\r
+                       *\r
+                       * 2. A two-phase commit procedure, where the USER_EVENT and data entries are\r
+                       * written to a local buffer at first, and when all checks are OK then copied to\r
+                       * the main event buffer using a fast memcpy. The event code is finalized as the\r
+                       * very last step. Before that step, the event code indicates an unfinished\r
+                       * event, which causes it to be ignored and stop the loading of the file (since\r
+                       * an unfinished event is the last event in the trace).\r
+                       *******************************************************************************/\r
+                       formatStrIndex++;\r
+\r
+                       while ((formatStr[formatStrIndex] >= '0' && formatStr[formatStrIndex] <= '9') || formatStr[formatStrIndex] == '#' || formatStr[formatStrIndex] == '.')\r
+                               formatStrIndex++;\r
+\r
+                       if (formatStr[formatStrIndex] != '\0')\r
+                       {\r
+                               switch (formatStr[formatStrIndex])\r
+                               {\r
+                                       case 'd':       i = writeInt32( buffer,\r
+                                                                                               i,\r
+                                                                                               (uint32_t)va_arg(vl, uint32_t));\r
+                                                               break;\r
+                                       case 'x':\r
+                                       case 'X':\r
+                                       case 'u':       i = writeInt32( buffer,\r
+                                                                                               i,\r
+                                                                                               (uint32_t)va_arg(vl, uint32_t));\r
+                                                               break;\r
+                                       case 's':       i = writeInt16( buffer,\r
+                                                                                               i,\r
+                                                                                               (uint16_t)xTraceOpenLabel((char*)va_arg(vl, char*)));\r
+                                                               break;\r
+\r
+#if (INCLUDE_FLOAT_SUPPORT)\r
+                                       /* Yes, "double" as type also in the float\r
+                                       case. This since "float" is promoted into "double"\r
+                                       by the va_arg stuff. */\r
+                                       case 'f':       i = writeFloat( buffer,\r
+                                                                                               i,\r
+                                                                                               (float)va_arg(vl, double));\r
+                                                               break;\r
+#else\r
+                                       /* No support for floats, but attempt to store a float user event\r
+                                       avoid a possible crash due to float reference. Instead store the\r
+                                       data on uint_32 format (will not be displayed anyway). This is just\r
+                                       to keep va_arg and i consistent. */\r
+\r
+                                       case 'f':       i = writeInt32( buffer,\r
+                                                                                               i,\r
+                                                                                               (uint32_t)va_arg(vl, double));\r
+                                                               break;\r
+#endif\r
+                                       case 'l':\r
+                                                               formatStrIndex++;\r
+                                                               switch (formatStr[formatStrIndex])\r
+                                                               {\r
+#if (INCLUDE_FLOAT_SUPPORT)\r
+                                                                       case 'f':       i = writeDouble(buffer,\r
+                                                                                                                               i,\r
+                                                                                                                               (double)va_arg(vl, double));\r
+                                                                                               break;\r
+#else\r
+                                                                       /* No support for floats, but attempt to store a float user event\r
+                                                                       avoid a possible crash due to float reference. Instead store the\r
+                                                                       data on uint_32 format (will not be displayed anyway). This is just\r
+                                                                       to keep va_arg and i consistent. */\r
+                                                                       case 'f':       i = writeInt32( buffer, /* In this case, the value will not be shown anyway */\r
+                                                                                                                               i,\r
+                                                                                                                               (uint32_t)va_arg(vl, double));\r
+\r
+                                                                                               i = writeInt32( buffer, /* Do it twice, to write in total 8 bytes */\r
+                                                                                                                               i,\r
+                                                                                                                               (uint32_t)va_arg(vl, double));\r
+                                                                               break;\r
+#endif\r
+\r
+                                                               }\r
+                                                               break;\r
+                                       case 'h':\r
+                                                               formatStrIndex++;\r
+                                                               switch (formatStr[formatStrIndex])\r
+                                                               {\r
+                                                                       case 'd':       i = writeInt16( buffer,\r
+                                                                                                                               i,\r
+                                                                                                                               (uint16_t)va_arg(vl, uint32_t));\r
+                                                                                               break;\r
+                                                                       case 'u':       i = writeInt16( buffer,\r
+                                                                                                                               i,\r
+                                                                                                                               (uint16_t)va_arg(vl, uint32_t));\r
+                                                                                               break;\r
+                                                               }\r
+                                                               break;\r
+                                       case 'b':\r
+                                                               formatStrIndex++;\r
+                                                               switch (formatStr[formatStrIndex])\r
+                                                               {\r
+                                                                       case 'd':       i = writeInt8(  buffer,\r
+                                                                                                                               i,\r
+                                                                                                                               (uint8_t)va_arg(vl, uint32_t));\r
+                                                                                               break;\r
+\r
+                                                                       case 'u':       i = writeInt8(  buffer,\r
+                                                                                                                               i,\r
+                                                                                                                               (uint8_t)va_arg(vl, uint32_t));\r
+                                                                                               break;\r
+                                                               }\r
+                                                               break;\r
+                               }\r
+                       }\r
+                       else\r
+                               break;\r
+               }\r
+               formatStrIndex++;\r
+               if (i == 255)\r
+               {\r
+                       vTraceError("vTracePrintF - Too large arguments, max 32 byte allowed!");\r
+                       return 0;\r
+               }\r
+       }\r
+       return (i+3)/4;\r
+}\r
+\r
+#if (USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
+\r
+/*******************************************************************************\r
+ * prvTraceClearChannelBuffer\r
+ *\r
+ * Clears a number of items in the channel buffer, starting from nextSlotToWrite.\r
+ ******************************************************************************/\r
+static void prvTraceClearChannelBuffer(uint32_t count)\r
+{\r
+       uint32_t slots;\r
+\r
+       TRACE_ASSERT(USER_EVENT_BUFFER_SIZE >= count,\r
+               "prvTraceClearChannelBuffer: USER_EVENT_BUFFER_SIZE is too small to handle this event.", );\r
+\r
+       /* Check if we're close to the end of the buffer */\r
+       if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > USER_EVENT_BUFFER_SIZE)\r
+       {\r
+               slots = USER_EVENT_BUFFER_SIZE - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */\r
+               (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, slots);\r
+               (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[0], 0, (count - slots));\r
+       }\r
+       else\r
+               (void)memset(&RecorderDataPtr->userEventBuffer.channelBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite], 0, count);\r
+}\r
+\r
+/*******************************************************************************\r
+ * prvTraceCopyToDataBuffer\r
+ *\r
+ * Copies a number of items to the data buffer, starting from nextSlotToWrite.\r
+ ******************************************************************************/\r
+static void prvTraceCopyToDataBuffer(uint32_t* data, uint32_t count)\r
+{\r
+       TRACE_ASSERT(data != NULL,\r
+               "prvTraceCopyToDataBuffer: data == NULL.", );\r
+       TRACE_ASSERT(count <= USER_EVENT_BUFFER_SIZE,\r
+               "prvTraceCopyToDataBuffer: USER_EVENT_BUFFER_SIZE is too small to handle this event.", );\r
+\r
+       uint32_t slots;\r
+       /* Check if we're close to the end of the buffer */\r
+       if (RecorderDataPtr->userEventBuffer.nextSlotToWrite + count > USER_EVENT_BUFFER_SIZE)\r
+       {\r
+               slots = USER_EVENT_BUFFER_SIZE - RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Number of slots before end of buffer */\r
+               (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, slots * 4);\r
+               (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[0], data + slots, (count - slots) * 4);\r
+       }\r
+       else\r
+       {\r
+               (void)memcpy(&RecorderDataPtr->userEventBuffer.dataBuffer[RecorderDataPtr->userEventBuffer.nextSlotToWrite * 4], data, count * 4);\r
+       }\r
+}\r
+\r
+/*******************************************************************************\r
+ * prvTraceUserEventHelper1\r
+ *\r
+ * Calls on prvTraceUserEventFormat() to do the actual formatting, then goes on\r
+ * to the next helper function.\r
+ ******************************************************************************/\r
+static void prvTraceUserEventHelper1(UserEventChannel channel, traceLabel eventLabel, traceLabel formatLabel, va_list vl)\r
+{\r
+       uint32_t data[(3 + MAX_ARG_SIZE) / 4];\r
+       uint8_t byteOffset = 4; /* Need room for timestamp */\r
+       uint8_t noOfSlots;\r
+\r
+       if (channel == 0)\r
+       {\r
+               /* We are dealing with an unknown channel format pair */\r
+               byteOffset += 4; /* Also need room for channel and format */\r
+               ((uint16_t*)data)[2] = eventLabel;\r
+               ((uint16_t*)data)[3] = formatLabel;\r
+       }\r
+\r
+       noOfSlots = prvTraceUserEventFormat((char*)&(RecorderDataPtr->SymbolTable.symbytes[formatLabel+4]), vl, (uint8_t*)data, byteOffset);\r
+\r
+       prvTraceUserEventHelper2(channel, data, noOfSlots);\r
+}\r
+\r
+/*******************************************************************************\r
+ * prvTraceUserEventHelper2\r
+ *\r
+ * This function simply copies the data buffer to the actual user event buffer.\r
+ ******************************************************************************/\r
+static void prvTraceUserEventHelper2(UserEventChannel channel, uint32_t* data, uint32_t noOfSlots)\r
+{\r
+       static uint32_t old_timestamp = 0;\r
+       uint32_t old_nextSlotToWrite = 0;\r
+\r
+       TRACE_ASSERT(USER_EVENT_BUFFER_SIZE >= noOfSlots, "vTracePrintF: USER_EVENT_BUFFER_SIZE is too small to handle this event.", );\r
+\r
+       trcCRITICAL_SECTION_BEGIN();\r
+       /* Store the timestamp */\r
+       vTracePortGetTimeStamp(data);\r
+\r
+       if (*data < old_timestamp)\r
+       {\r
+               RecorderDataPtr->userEventBuffer.wraparoundCounter++;\r
+       }\r
+\r
+       old_timestamp = *data;\r
+\r
+       /* Start by erasing any information in the channel buffer */\r
+       prvTraceClearChannelBuffer(noOfSlots);\r
+\r
+       prvTraceCopyToDataBuffer(data, noOfSlots); /* Will wrap around the data if necessary */\r
+\r
+       old_nextSlotToWrite = RecorderDataPtr->userEventBuffer.nextSlotToWrite; /* Save the index that we want to write the channel data at when we're done */\r
+       RecorderDataPtr->userEventBuffer.nextSlotToWrite = (RecorderDataPtr->userEventBuffer.nextSlotToWrite + noOfSlots) % USER_EVENT_BUFFER_SIZE; /* Make sure we never end up outside the buffer */\r
+\r
+       /* Write to the channel buffer to indicate that this user event is ready to be used */\r
+       if (channel != 0)\r
+       {\r
+               RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = channel;\r
+       }\r
+       else\r
+       {\r
+               /* 0xFF indicates that this is not a normal channel id */\r
+               RecorderDataPtr->userEventBuffer.channelBuffer[old_nextSlotToWrite] = (UserEventChannel)0xFF;\r
+       }\r
+       trcCRITICAL_SECTION_END();\r
+}\r
+\r
+/*******************************************************************************\r
+ * xTraceRegisterChannelFormat\r
+ *\r
+ * Attempts to create a pair of the channel and format string.\r
+ *\r
+ * Note: This is only available if USE_SEPARATE_USER_EVENT_BUFFER is enabled in\r
+ * trcConfig.h\r
+ ******************************************************************************/\r
+UserEventChannel xTraceRegisterChannelFormat(traceLabel channel, traceLabel formatStr)\r
+{\r
+       uint8_t i;\r
+       UserEventChannel retVal = 0;\r
+\r
+       TRACE_ASSERT(formatStr != 0, "vTraceRegisterChannelFormat: formatStr == 0", (UserEventChannel)0);\r
+\r
+       trcCRITICAL_SECTION_BEGIN();\r
+       for (i = 1; i <= CHANNEL_FORMAT_PAIRS; i++) /* Size of the channels buffer is CHANNEL_FORMAT_PAIRS + 1. Index 0 is unused. */\r
+       {\r
+               if(RecorderDataPtr->userEventBuffer.channels[i].name == 0 && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == 0)\r
+               {\r
+                       /* Found empty slot */\r
+                       RecorderDataPtr->userEventBuffer.channels[i].name = channel;\r
+                       RecorderDataPtr->userEventBuffer.channels[i].defaultFormat = formatStr;\r
+                       retVal = (UserEventChannel)i;\r
+                       break;\r
+               }\r
+\r
+               if (RecorderDataPtr->userEventBuffer.channels[i].name == channel && RecorderDataPtr->userEventBuffer.channels[i].defaultFormat == formatStr)\r
+               {\r
+                       /* Found a match */\r
+                       retVal = (UserEventChannel)i;\r
+                       break;\r
+               }\r
+       }\r
+       trcCRITICAL_SECTION_END();\r
+       return retVal;\r
+}\r
+\r
+/******************************************************************************\r
+ * vTraceChannelPrintF\r
+ *\r
+ * Slightly faster version of vTracePrintF() due to no lookups.\r
+ *\r
+ * Note: This is only available if USE_SEPARATE_USER_EVENT_BUFFER is enabled in\r
+ * trcConfig.h\r
+ *\r
+ ******************************************************************************/\r
+void vTraceChannelPrintF(UserEventChannel channelPair, ...)\r
+{\r
+#if (TRACE_SCHEDULING_ONLY == 0)\r
+       va_list vl;\r
+\r
+       va_start(vl, channelPair);\r
+       vTraceChannelPrintF_Helper(channelPair, vl);\r
+       va_end(vl);\r
+#endif /* TRACE_SCHEDULING_ONLY */\r
+}\r
+\r
+void vTraceChannelPrintF_Helper(UserEventChannel channelPair, va_list vl)\r
+{\r
+       traceLabel channel;\r
+       traceLabel formatStr;\r
+\r
+       TRACE_ASSERT(channelPair != 0, "vTraceChannelPrintF: channelPair == 0", );\r
+       TRACE_ASSERT(channelPair <= CHANNEL_FORMAT_PAIRS, "vTraceChannelPrintF: ", );\r
+\r
+       channel = RecorderDataPtr->userEventBuffer.channels[channelPair].name;\r
+       formatStr = RecorderDataPtr->userEventBuffer.channels[channelPair].defaultFormat;\r
+\r
+       prvTraceUserEventHelper1(channelPair, channel, formatStr, vl);\r
+}\r
+\r
+/******************************************************************************\r
+ * vTraceChannelUserEvent\r
+ *\r
+ * Slightly faster version of vTraceUserEvent() due to no lookups.\r
+ ******************************************************************************/\r
+void vTraceChannelUserEvent(UserEventChannel channelPair)\r
+{\r
+#if (TRACE_SCHEDULING_ONLY == 0)\r
+       uint32_t data[(3 + MAX_ARG_SIZE) / 4];\r
+\r
+       TRACE_ASSERT(channelPair != 0, "vTraceChannelPrintF: channelPair == 0", );\r
+       TRACE_ASSERT(channelPair <= CHANNEL_FORMAT_PAIRS, "vTraceChannelPrintF: ", );\r
+\r
+       prvTraceUserEventHelper2(channelPair, data, 1); /* Only need one slot for timestamp */\r
+#endif /* TRACE_SCHEDULING_ONLY */\r
+}\r
+#endif /* USE_SEPARATE_USER_EVENT_BUFFER == 1 */\r
+\r
+/******************************************************************************\r
+ * vTracePrintF\r
+ *\r
  * Advanced user events (Professional Edition only)\r
  *\r
  * Generates User Event with formatted text and data, similar to a "printf".\r
- * It is very fast compared to a normal "printf" since this function only \r
+ * It is very fast compared to a normal "printf" since this function only\r
  * stores the arguments. The actual formatting is done\r
- * on the host PC when the trace is displayed in the viewer tool. \r
+ * on the host PC when the trace is displayed in the viewer tool.\r
  *\r
  * User Event labels are created using xTraceOpenLabel.\r
  * Example:\r
  *\r
- *     traceLabel adc_uechannel = xTraceOpenLabel("ADC User Events");\r
- *     ...\r
- *     vTracePrint(adc_uechannel, \r
- *                 "ADC channel %d: %lf volts", \r
- *                 ch, (double)adc_reading/(double)scale);\r
+ *      traceLabel adc_uechannel = xTraceOpenLabel("ADC User Events");\r
+ *      ...\r
+ *      vTracePrint(adc_uechannel,\r
+ *                              "ADC channel %d: %lf volts",\r
+ *                              ch, (double)adc_reading/(double)scale);\r
  *\r
  * This can be combined into one line, if desired, but this is slower:\r
  *\r
- *     vTracePrint(xTraceOpenLabel("ADC User Events"), \r
- *                 "ADC channel %d: %lf volts", \r
- *                 ch, (double)adc_reading/(double)scale);\r
+ *      vTracePrint(xTraceOpenLabel("ADC User Events"),\r
+ *                              "ADC channel %d: %lf volts",\r
+ *                              ch, (double)adc_reading/(double)scale);\r
  *\r
  * Calling xTraceOpenLabel multiple times will not create duplicate entries, but\r
- * it is of course faster to just do it once, and then keep the handle for later \r
- * use. If you don´t have any data arguments, only a text label/string, it is \r
+ * it is of course faster to just do it once, and then keep the handle for later\r
+ * use. If you don´t have any data arguments, only a text label/string, it is\r
  * better to use vTraceUserEvent - it is faster.\r
  *\r
  * Format specifiers supported:\r
- *  %d - 32 bit signed integer\r
- *  %u - 32 bit unsigned integer\r
- *  %f - 32 bit float\r
- *  %s - string (is copied to the recorder symbol table)\r
- *  %hd - 16 bit signed integer\r
- *  %hu - 16 bit unsigned integer\r
- *  %bd - 8 bit signed integer\r
- *  %bu - 8 bit unsigned integer\r
- *  %lf - double-precision float\r
- * \r
+ * %d - 32 bit signed integer\r
+ * %u - 32 bit unsigned integer\r
+ * %f - 32 bit float\r
+ * %s - string (is copied to the recorder symbol table)\r
+ * %hd - 16 bit signed integer\r
+ * %hu - 16 bit unsigned integer\r
+ * %bd - 8 bit signed integer\r
+ * %bu - 8 bit unsigned integer\r
+ * %lf - double-precision float (Note! See below...)\r
+ *\r
  * Up to 15 data arguments are allowed, with a total size of maximum 32 byte.\r
  * In case this is exceeded, the user event is changed into an error message.\r
- * \r
- * The data is stored in trace buffer, and is packed to allow storing multiple \r
+ *\r
+ * The data is stored in trace buffer, and is packed to allow storing multiple\r
  * smaller data entries in the same 4-byte record, e.g., four 8-bit values.\r
- * A string requires two bytes, as the symbol table is limited to 64K. Storing a \r
- * double (%lf) uses two records, so this is quite costly. Use float (%f) unless\r
- * the higher precision is really necessary.\r
+ * A string requires two bytes, as the symbol table is limited to 64K. Storing\r
+ * a double (%lf) uses two records, so this is quite costly. Use float (%f)\r
+ * unless the higher precision is really necessary.\r
+ *\r
+ * Note that the double-precision float (%lf) assumes a 64 bit double\r
+ * representation. This does not seem to be the case on e.g. PIC24 and PIC32.\r
+ * Before using a %lf argument on a 16-bit MCU, please verify that\r
+ * "sizeof(double)" actually gives 8 as expected. If not, use %f instead.\r
  ******************************************************************************/\r
+\r
 void vTracePrintF(traceLabel eventLabel, const char* formatStr, ...)\r
 {\r
-    UserEvent* ue1;\r
-    va_list vl;\r
-    uint8_t argCounter = 0;\r
-    uint8_t i = 0;\r
-    uint8_t nofEventEntries = 0;\r
-    uint16_t formatStrIndex = 0;    \r
-\r
-    /**************************************************************************\r
-    * The array tempDataBuffer is a local buffer used in a two-phase commit of \r
-    * the event data, since a vTracePrintF may span over multiple slots in the \r
-    * buffer.\r
-    * This buffer can be made larger, of course, but remember the risk for \r
-    * stack overflow. Note: This should be a LOCAL buffer, must not be made \r
-    * global. That would cause data corruption when two calls to vTracePrintF\r
-    * from different tasks overlaps (interrupts are only disabled in a small \r
-    * part of this function, otherwise enabled)\r
-    ***************************************************************************/\r
-               \r
-    uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];   \r
-       \r
-       \r
-    if ((inExcludedTask == 0) &&\r
-        (nISRactive == 0) &&\r
-        (RecorderDataPtr->recorderActive == 1) &&\r
-        (handle_of_last_logged_task > 0))\r
-    {        \r
-        /* First, write the "primary" user event entry in the local buffer, but \r
-        let the event type be "EVENT_BEING_WRITTEN" for now...*/\r
-\r
-        ue1 = (UserEvent*)(&tempDataBuffer[0]);         \r
-        ue1->type = EVENT_BEING_WRITTEN;      /* Update this as the last step */\r
-        \r
-        i = 4;\r
-        formatStrIndex = 0;\r
-        va_start(vl, formatStr);          /* Begin reading the arguments list */\r
-\r
-        while (formatStr[formatStrIndex] != '\0')\r
-        {\r
-            if (formatStr[formatStrIndex] == '%')\r
-            {\r
-                argCounter++;\r
-\r
-                if (argCounter > 15)\r
-                {\r
-                    vTraceError("vTracePrintF - Too many arguments, max 15 allowed!");\r
-                    va_end(vl);                    \r
-                    formatStr = "[vTracePrintF error] Too many arguments, max 15 allowed!";\r
-                    i = 4;\r
-                    break;            \r
-                }\r
+#if (TRACE_SCHEDULING_ONLY == 0)\r
+       va_list vl;\r
 \r
-/*******************************************************************************\r
- * These below code writes raw data (primitive datatypes) in the event buffer, \r
- * instead of the normal event structs (where byte 0 is event type).\r
- * These data entries must never be interpreted as real event data, as the type\r
- * field would be misleading since used for payload data. \r
- * \r
- * The correctness of this encoding depends on two mechanisms:\r
- * \r
- * 1. An initial USER_EVENT, which type code tells the number of 32-bit data \r
- * entires that follows. (code - USER_EVENT = number of data entries). \r
- * Note that a data entry corresponds to the slots that normally corresponds to \r
- * one (1) event, i.e., 32 bits. vTracePrintF may encode several pieces of data \r
- * in one data entry, e.g., two 16-bit values or four 8-bit values, one 16-bit\r
- * value followes by two 8-bit values, etc.\r
- *\r
- * 2. A two-phase commit procedure, where the USER_EVENT and data entries are \r
- * written to a local buffer at first, and when all checks are OK then copied to\r
- * the main event buffer using a fast memcpy. The event code is finalized as the\r
- * very last step. Before that that step, the event code indicates an unfinished\r
- * event, which causes it to be ignored and stop the loading of the file (since \r
- * an unfinished event is the last event in the trace).\r
-*******************************************************************************/\r
-                formatStrIndex++;\r
-                switch (formatStr[formatStrIndex])\r
-                {\r
-                case 'd':    i = writeInt32((uint8_t*)tempDataBuffer, \r
-                                                i, \r
-                                                (uint32_t)va_arg(vl, uint32_t)); \r
-                             break;\r
-                case 'u':    i = writeInt32((uint8_t*)tempDataBuffer, \r
-                                                i, \r
-                                                (uint32_t)va_arg(vl, uint32_t)); \r
-                             break;\r
-                case 's':    i = writeInt16((uint8_t*)tempDataBuffer, \r
-                                                i, \r
-                                                (uint16_t)xTraceOpenLabel((char*)va_arg(vl, char*))); \r
-                             break;\r
+       va_start(vl, formatStr);\r
+       vTracePrintF_Helper(eventLabel, formatStr, vl);\r
+       va_end(vl);\r
+#endif /* TRACE_SCHEDULING_ONLY */\r
+}\r
 \r
-#if (INCLUDE_FLOAT_SUPPORT)\r
-                             /* Yes, "double" as type also in the float \r
-                             case. This since "float" is promoted into "double" \r
-                             by the va_arg stuff. */\r
-                case 'f':    i = writeFloat((uint8_t*)tempDataBuffer, \r
-                                                i, \r
-                                                (float)va_arg(vl, double)); \r
-                             break;    \r
-#else\r
-/* No support for floats, but attempt to store a float user event\r
-avoid a possible crash due to float reference. Instead store the \r
-data on uint_32 format (will not be displayed anyway). This is just\r
-to keep va_arg and i consistent. */\r
-\r
-                case 'f':    i = writeInt32((uint8_t*)tempDataBuffer,\r
-                                                i, \r
-                                                (uint32_t)va_arg(vl, double)); \r
-#endif\r
-                case 'l':\r
-                    formatStrIndex++;\r
-                    switch (formatStr[formatStrIndex])\r
-                    {\r
-#if (INCLUDE_FLOAT_SUPPORT)\r
-                    case 'f':     i = writeDouble((uint8_t*)tempDataBuffer, \r
-                                                      i, \r
-                                                      (double)va_arg(vl, double)); \r
-                                  break;\r
-#else\r
-/* No support for floats, but attempt to store a float user event\r
-avoid a possible crash due to float reference. Instead store the \r
-data on uint_32 format (will not be displayed anyway). This is just\r
-to keep va_arg and i consistent. */\r
-                    case 'f':    i = writeInt32((uint8_t*)tempDataBuffer, /* In this case, the value will not be shown anyway */\r
-                                                    i, \r
-                                                    (uint32_t)va_arg(vl, double)); \r
-                                 i = writeInt32((uint8_t*)tempDataBuffer, /* Do it twice, to write in total 8 bytes */\r
-                                                    i, \r
-                                                    (uint32_t)va_arg(vl, double)); \r
-#endif\r
+void vTracePrintF_Helper(traceLabel eventLabel, const char* formatStr, va_list vl)\r
+{\r
+#if (USE_SEPARATE_USER_EVENT_BUFFER == 0)\r
+       uint32_t noOfSlots;\r
+       UserEvent* ue1;\r
+       uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];\r
+       TRACE_SR_ALLOC_CRITICAL_SECTION();\r
+\r
+       /**************************************************************************\r
+       * The array tempDataBuffer is a local buffer used in a two-phase commit of\r
+       * the event data, since a vTracePrintF may span over multiple slots in the\r
+       * buffer.\r
+       * This buffer can be made larger, of course, but remember the risk for\r
+       * stack overflow. Note: This should be a LOCAL buffer, must not be made\r
+       * global. That would cause data corruption when two calls to vTracePrintF\r
+       * from different tasks overlaps (interrupts are only disabled in a small\r
+       * part of this function, otherwise enabled)\r
+       ***************************************************************************/\r
+\r
+       TRACE_ASSERT(formatStr != NULL, "vTracePrintF: formatStr == NULL", );\r
+\r
+       trcCRITICAL_SECTION_BEGIN();\r
+\r
+       if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task)\r
+       {\r
+               /* First, write the "primary" user event entry in the local buffer, but\r
+               let the event type be "EVENT_BEING_WRITTEN" for now...*/\r
 \r
-                    }\r
-                    break;\r
-                case 'h':\r
-                    formatStrIndex++;\r
-                    switch (formatStr[formatStrIndex])\r
-                    {\r
-                    case 'd':    i = writeInt16((uint8_t*)tempDataBuffer, \r
-                                                    i, \r
-                                                    (uint16_t)va_arg(vl, uint32_t)); \r
-                                 break;\r
-                    case 'u':    i = writeInt16((uint8_t*)tempDataBuffer, \r
-                                                    i, \r
-                                                    (uint16_t)va_arg(vl, uint32_t)); \r
-                                 break;\r
-                    }\r
-                    break;\r
-                case 'b':\r
-                    formatStrIndex++;\r
-                    switch (formatStr[formatStrIndex])\r
-                    {\r
-                    case 'd':    i = writeInt8((uint8_t*)tempDataBuffer, \r
-                                                   i, \r
-                                                   (uint8_t)va_arg(vl, uint32_t)); \r
-                                 break;\r
-                    case 'u':    i = writeInt8((uint8_t*)tempDataBuffer, \r
-                                                   i, \r
-                                                   (uint8_t)va_arg(vl, uint32_t)); \r
-                                 break;\r
-                    }\r
-                    break;\r
-                }\r
-            }                                    \r
-            formatStrIndex++;    \r
-            if (i == 255)\r
-            {\r
-                va_end(vl);\r
-                //vTraceError("vTracePrintF - Too large arguments, max 32 byte allowed!");\r
-                formatStr = "[vTracePrintF error] Too large arguments, max 32 byte allowed!";\r
-                i = 4;\r
-                break;\r
-            }\r
-        }\r
-\r
-        va_end(vl);\r
-               \r
-        /* Store the format string, with a reference to the channel symbol */\r
-        ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel);     \r
-\r
-        trcCRITICAL_SECTION_BEGIN();  \r
-\r
-        ue1->dts = (uint8_t)prvTraceGetDTS(0xFF);\r
-        if (! RecorderDataPtr->recorderActive)\r
-        {\r
-\r
-            /* Abort, since an XTS event (created by prvTraceGetDTS) filled the \r
-            buffer, and the recorder stopped since not circular buffer. */\r
-            trcCRITICAL_SECTION_END();\r
-        \r
-            return;\r
-        }\r
-            \r
-        nofEventEntries = (i+3)/4;\r
-\r
-        /* If the data does not fit in the remaining main buffer, wrap around to \r
-        0 if allowed, otherwise stop the recorder and quit). */\r
-        if (RecorderDataPtr->nextFreeIndex + nofEventEntries > RecorderDataPtr->maxEvents)\r
-        {\r
-#if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER)\r
-            (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], \r
-                   0, \r
-                   (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4);\r
-            RecorderDataPtr->nextFreeIndex = 0;\r
-            RecorderDataPtr->bufferIsFull = 1;\r
-#else\r
-            /* Abort and stop recorder, since the event data will not fit in the\r
-            buffer and not circular buffer in this case... */\r
-            trcCRITICAL_SECTION_END();\r
-            vTraceStop();\r
+               ue1 = (UserEvent*)(&tempDataBuffer[0]);\r
 \r
-            \r
-            return;\r
-#endif\r
-        }\r
-    \r
-#if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER)\r
-        /* Check that the buffer to be overwritten does not contain any user \r
-        events that would be partially overwritten. If so, they must be "killed"\r
-        by replacing the user event and following data with NULL events (i.e., \r
-        using a memset to zero).*/\r
-        prvCheckDataToBeOverwrittenForMultiEntryUserEvents(nofEventEntries);\r
-#endif\r
-        /* Copy the local buffer to the main buffer */\r
-        (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4], \r
-               tempDataBuffer, \r
-               i);\r
-\r
-        /* Update the event type, i.e., number of data entries following the \r
-        main USER_EVENT entry (Note: important that this is after the memcpy, \r
-        but within the critical section!)*/\r
-        RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] = \r
-          (uint8_t) USER_EVENT + nofEventEntries - 1;    \r
-        \r
-        /* Update the main buffer event index (already checked that it fits in \r
-        the buffer, so no need to check for wrapping)*/\r
-        \r
-        RecorderDataPtr->nextFreeIndex += nofEventEntries;\r
-        RecorderDataPtr->numEvents += nofEventEntries;\r
-        \r
-        if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE)\r
-        {\r
-        \r
-#if (RECORDER_STORE_MODE == STORE_MODE_RING_BUFFER)\r
-            RecorderDataPtr->nextFreeIndex = 0;\r
-            RecorderDataPtr->bufferIsFull = 1;\r
-#else\r
-            vTraceStop();\r
+               ue1->type = EVENT_BEING_WRITTEN;         /* Update this as the last step */\r
+\r
+               noOfSlots = prvTraceUserEventFormat(formatStr, vl, (uint8_t*)tempDataBuffer, 4);\r
+\r
+               /* Store the format string, with a reference to the channel symbol */\r
+               ue1->payload = prvTraceOpenSymbol(formatStr, eventLabel);\r
+\r
+               ue1->dts = (uint8_t)prvTraceGetDTS(0xFF);\r
+\r
+                /* prvTraceGetDTS might stop the recorder in some cases... */\r
+               if (RecorderDataPtr->recorderActive)\r
+               {\r
+\r
+                       /* If the data does not fit in the remaining main buffer, wrap around to\r
+                       0 if allowed, otherwise stop the recorder and quit). */\r
+                       if (RecorderDataPtr->nextFreeIndex + noOfSlots > RecorderDataPtr->maxEvents)\r
+                       {\r
+                               #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
+                               (void)memset(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],\r
+                                               0,\r
+                                               (RecorderDataPtr->maxEvents - RecorderDataPtr->nextFreeIndex)*4);\r
+                               RecorderDataPtr->nextFreeIndex = 0;\r
+                               RecorderDataPtr->bufferIsFull = 1;\r
+                               #else\r
+\r
+                               /* Stop recorder, since the event data will not fit in the\r
+                               buffer and not circular buffer in this case... */\r
+                               vTraceStop();\r
+                               #endif\r
+                       }\r
+\r
+                       /* Check if recorder has been stopped (i.e., vTraceStop above) */\r
+                       if (RecorderDataPtr->recorderActive)\r
+                       {\r
+                               /* Check that the buffer to be overwritten does not contain any user\r
+                               events that would be partially overwritten. If so, they must be "killed"\r
+                               by replacing the user event and following data with NULL events (i.e.,\r
+                               using a memset to zero).*/\r
+                               #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
+                               prvCheckDataToBeOverwrittenForMultiEntryEvents((uint8_t)noOfSlots);\r
+                               #endif\r
+                               /* Copy the local buffer to the main buffer */\r
+                               (void)memcpy(& RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4],\r
+                                               tempDataBuffer,\r
+                                               noOfSlots * 4);\r
+\r
+                               /* Update the event type, i.e., number of data entries following the\r
+                               main USER_EVENT entry (Note: important that this is after the memcpy,\r
+                               but within the critical section!)*/\r
+                               RecorderDataPtr->eventData[RecorderDataPtr->nextFreeIndex * 4] =\r
+                                (uint8_t) ( USER_EVENT + noOfSlots - 1 );\r
+\r
+                               /* Update the main buffer event index (already checked that it fits in\r
+                               the buffer, so no need to check for wrapping)*/\r
+\r
+                               RecorderDataPtr->nextFreeIndex += noOfSlots;\r
+                               RecorderDataPtr->numEvents += noOfSlots;\r
+\r
+                               if (RecorderDataPtr->nextFreeIndex >= EVENT_BUFFER_SIZE)\r
+                               {\r
+                                       #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
+                                       /* We have reached the end, but this is a ring buffer. Start from the beginning again. */\r
+                                       RecorderDataPtr->bufferIsFull = 1;\r
+                                       RecorderDataPtr->nextFreeIndex = 0;\r
+                                       #else\r
+                                       /* We have reached the end so we stop. */\r
+                                       vTraceStop();\r
+                                       #endif\r
+                               }\r
+                       }\r
+\r
+                       #if (TRACE_RECORDER_STORE_MODE == TRACE_STORE_MODE_RING_BUFFER)\r
+                       /* Make sure the next entry is cleared correctly */\r
+                       prvCheckDataToBeOverwrittenForMultiEntryEvents(1);\r
+                       #endif\r
+\r
+               }\r
+       }\r
+       trcCRITICAL_SECTION_END();\r
+\r
+#elif (USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
+       /* Use the separate user event buffer */\r
+       traceLabel formatLabel;\r
+       UserEventChannel channel;\r
+\r
+       if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task)\r
+       {\r
+               formatLabel = xTraceOpenLabel(formatStr);\r
+\r
+               channel = xTraceRegisterChannelFormat(eventLabel, formatLabel);\r
+\r
+               prvTraceUserEventHelper1(channel, eventLabel, formatLabel, vl);\r
+       }\r
 #endif\r
-        }\r
+}\r
+\r
+/******************************************************************************\r
+ * vTraceUserEvent\r
+ *\r
+ * Basic user event (Standard and Professional Edition only)\r
+ *\r
+ * Generates a User Event with a text label. The label is created/looked up\r
+ * in the symbol table using xTraceOpenLabel.\r
+ ******************************************************************************/\r
+void vTraceUserEvent(traceLabel eventLabel)\r
+{\r
+#if (TRACE_SCHEDULING_ONLY == 0)\r
+#if (USE_SEPARATE_USER_EVENT_BUFFER == 0)\r
+       UserEvent* ue;\r
+       uint8_t dts1;\r
+       TRACE_SR_ALLOC_CRITICAL_SECTION();\r
+\r
+       TRACE_ASSERT(eventLabel > 0, "vTraceUserEvent: Invalid value for eventLabel", );\r
+\r
+       trcCRITICAL_SECTION_BEGIN();\r
+       if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task)\r
+       {\r
+               dts1 = (uint8_t)prvTraceGetDTS(0xFF);\r
+               ue = (UserEvent*) xTraceNextFreeEventBufferSlot();\r
+               if (ue != NULL)\r
+               {\r
+                       ue->dts = dts1;\r
+                       ue->type = USER_EVENT;\r
+                       ue->payload = eventLabel;\r
+                       prvTraceUpdateCounters();\r
+               }\r
+       }\r
+       trcCRITICAL_SECTION_END();\r
+\r
+#elif (USE_SEPARATE_USER_EVENT_BUFFER == 1)\r
+       UserEventChannel channel;\r
+       uint32_t noOfSlots = 1;\r
+       uint32_t tempDataBuffer[(3 + MAX_ARG_SIZE) / 4];\r
+       if (RecorderDataPtr->recorderActive && (! inExcludedTask || nISRactive) && handle_of_last_logged_task)\r
+       {\r
+               channel = xTraceRegisterChannelFormat(0, eventLabel);\r
 \r
-        trcCRITICAL_SECTION_END();\r
-    }    \r
+               if (channel == 0)\r
+               {\r
+                       /* We are dealing with an unknown channel format pair */\r
+                       noOfSlots++; /* Also need room for channel and format */\r
+                       ((uint16_t*)tempDataBuffer)[2] = 0;\r
+                       ((uint16_t*)tempDataBuffer)[3] = eventLabel;\r
+               }\r
+\r
+               prvTraceUserEventHelper2(channel, tempDataBuffer, noOfSlots);\r
+       }\r
+#endif\r
+#endif /* TRACE_SCHEDULING_ONLY */\r
 }\r
-    \r
+\r
 /*******************************************************************************\r
  * xTraceOpenLabel\r
- * \r
+ *\r
  * Creates user event labels for user event channels or for individual events.\r
  * User events can be used to log application events and data for display in\r
  * the visualization tool. A user event is identified by a label, i.e., a string,\r
  * which is stored in the recorder's symbol table.\r
  * When logging a user event, a numeric handle (reference) to this string is\r
- * used to identify the event. This is obtained by calling \r
- * \r
- *     xTraceOpenLabel()\r
+ * used to identify the event. This is obtained by calling\r
+ *\r
+ *      xTraceOpenLabel()\r
  *\r
  * which adds the string to the symbol table (if not already present)\r
  * and returns the corresponding handle.\r
@@ -1397,25 +1482,28 @@ to keep va_arg and i consistent. */
  * 1. The handle is looked up every time, when storing the user event.\r
  *\r
  * Example:\r
- *     vTraceUserEvent(xTraceOpenLabel("MyUserEvent"));\r
+ *      vTraceUserEvent(xTraceOpenLabel("MyUserEvent"));\r
  *\r
  * 2. The label is registered just once, with the handle stored in an\r
- *  application variable - much like using a file handle.\r
+ * application variable - much like using a file handle.\r
  *\r
  * Example:\r
- *     myEventHandle = xTraceOpenLabel("MyUserEvent");\r
- *     ...\r
- *     vTraceUserEvent(myEventHandle);\r
+ *      myEventHandle = xTraceOpenLabel("MyUserEvent");\r
+ *      ...\r
+ *      vTraceUserEvent(myEventHandle);\r
  *\r
- * The second option is faster since no lookup is required on each event, and \r
+ * The second option is faster since no lookup is required on each event, and\r
  * therefore recommended for user events that are frequently\r
  * executed and/or located in time-critical code. The lookup operation is\r
  * however fairly fast due to the design of the symbol table.\r
  ******************************************************************************/\r
 traceLabel xTraceOpenLabel(const char* label)\r
 {\r
-    return prvTraceOpenSymbol(label, 0);\r
+       TRACE_ASSERT(label != NULL, "xTraceOpenLabel: label == NULL", (traceLabel)0);\r
+\r
+       return prvTraceOpenSymbol(label, 0);\r
 }\r
-#endif\r
+\r
 #endif\r
 \r
+#endif\r