--- /dev/null
+/*******************************************************************************\r
+ * FreeRTOS+Trace v2.3.0 Recorder Library\r
+ * Percepio AB, www.percepio.com\r
+ *\r
+ * trcKernel.c\r
+ *\r
+ * Functions for integration of the trace recorder library in the FreeRTOS \r
+ * kernel (requires FreeRTOS v7.1.0 or later).\r
+ * \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
+ * 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
+ * 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
+ * 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
+ *\r
+ * Copyright Percepio AB, 2012.\r
+ * www.percepio.com\r
+ ******************************************************************************/\r
+\r
+#include "trcUser.h"\r
+#include "task.h"\r
+\r
+#if (configUSE_TRACE_FACILITY == 1)\r
+\r
+\r
+\r
+/******************************************************************************\r
+ * TraceObjectClassTable\r
+ * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_).\r
+ * This was added since we want to map both types of Mutex and both types of \r
+ * Semaphores on common classes for all Mutexes and all Semaphores respectively. \r
+ * \r
+ * FreeRTOS Queue types\r
+ * #define queueQUEUE_TYPE_BASE ( 0U ) => TRACE_CLASS_QUEUE\r
+ * #define queueQUEUE_TYPE_MUTEX ( 1U ) => TRACE_CLASS_MUTEX\r
+ * #define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( 2U ) => TRACE_CLASS_SEMAPHORE\r
+ * #define queueQUEUE_TYPE_BINARY_SEMAPHORE ( 3U ) => TRACE_CLASS_SEMAPHORE\r
+ * #define queueQUEUE_TYPE_RECURSIVE_MUTEX ( 4U ) => TRACE_CLASS_MUTEX \r
+ ******************************************************************************/\r
+traceObjectClass TraceObjectClassTable[5] = {TRACE_CLASS_QUEUE, \r
+ TRACE_CLASS_MUTEX, \r
+ TRACE_CLASS_SEMAPHORE, \r
+ TRACE_CLASS_SEMAPHORE,\r
+ TRACE_CLASS_MUTEX };\r
+\r
+/* This is defined in FreeRTOS! */\r
+extern volatile void * volatile pxCurrentTCB; \r
+\r
+/* Internal variables */\r
+uint8_t nISRactive = 0;\r
+objectHandleType handle_of_last_logged_task = 0;\r
+uint8_t inExcludedTask = 0;\r
+\r
+static uint8_t prvTraceIsObjectExcluded(traceObjectClass, uint32_t);\r
+\r
+/*******************************************************************************\r
+ * prvTraceIsObjectExcluded\r
+ *\r
+ * Private function that accepts an object class and an object number and uses\r
+ * that to determine if the object has been flagged as excluded.\r
+ ******************************************************************************/\r
+static uint8_t prvTraceIsObjectExcluded(traceObjectClass objectClass, uint32_t objectNumber)\r
+{\r
+ switch(objectClass)\r
+ {\r
+ case TRACE_CLASS_QUEUE:\r
+ return GET_QUEUE_FLAG_ISEXCLUDED(objectNumber);\r
+ break;\r
+ case TRACE_CLASS_SEMAPHORE:\r
+ return GET_SEMAPHORE_FLAG_ISEXCLUDED(objectNumber);\r
+ break;\r
+ case TRACE_CLASS_MUTEX:\r
+ return GET_MUTEX_FLAG_ISEXCLUDED(objectNumber);\r
+ break;\r
+ case TRACE_CLASS_TASK:\r
+ return GET_TASK_FLAG_ISEXCLUDED(objectNumber);\r
+ break;\r
+ }\r
+ return 0;\r
+}\r
+\r
+#if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1\r
+/*******************************************************************************\r
+ * vTraceStoreTaskReady\r
+ *\r
+ * This function stores a ready state for the task handle sent in as parameter.\r
+ ******************************************************************************/\r
+void vTraceStoreTaskReady(objectHandleType handle)\r
+{\r
+ uint16_t dts3;\r
+ TREvent* tr;\r
+\r
+ if (!GET_TASK_FLAG_ISEXCLUDED(handle))\r
+ {\r
+ dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+ if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+ {\r
+ tr = (TREvent*)xTraceNextFreeEventBufferSlot();\r
+\r
+ if (tr != NULL)\r
+ {\r
+ tr->type = TR_TASK_READY;\r
+ tr->dts = dts3;\r
+ tr->objHandle = handle;\r
+\r
+ prvTraceUpdateCounters(); \r
+ }\r
+ }\r
+ }\r
+}\r
+#endif\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreKernelCall\r
+ *\r
+ * This is the main integration point for storing FreeRTOS kernel calls, and\r
+ * is called by the hooks in FreeRTOS.h (see trcKernel.h for event codes).\r
+ ******************************************************************************/\r
+void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber)\r
+{\r
+ KernelCall * kse;\r
+ uint16_t dts1;\r
+\r
+ if (handle_of_last_logged_task == 0)\r
+ {\r
+ return;\r
+ }\r
+ \r
+ if (RecorderDataPtr->recorderActive)\r
+ {\r
+ \r
+ /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */\r
+ if (nISRactive || !inExcludedTask)\r
+ {\r
+ /* Make sure ISRs never change the IFE flags of tasks */\r
+ if (!nISRactive)\r
+ {\r
+ /* This checks if this is the first kernel call after a call to\r
+ vTraceTaskInstanceIsFinished. In that case, calls to this kernel service \r
+ with this specific kernel object become the "instance finish event"\r
+ (IFE) of the calling task.*/\r
+ if (GET_TASK_FLAG_MARKIFE(handle_of_last_logged_task))\r
+ {\r
+ /* Reset the flag - this has been handled now */\r
+ CLEAR_TASK_FLAG_MARKIFE(handle_of_last_logged_task);\r
+\r
+ /* Store the kernel service tagged as instance finished event */\r
+ PROPERTY_TASK_IFE_SERVICECODE(handle_of_last_logged_task) = \r
+ (uint8_t)ecode; \r
+\r
+ /* Store the handle of the specific kernel object */\r
+ PROPERTY_TASK_IFE_OBJHANDLE(handle_of_last_logged_task) =\r
+ (objectHandleType)objectNumber; \r
+ }\r
+ }\r
+ \r
+ /* Check if the referenced object or the event code is excluded */\r
+ if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode))\r
+ {\r
+ trcCRITICAL_SECTION_BEGIN();\r
+ dts1 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+\r
+ if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+ { \r
+ kse = (KernelCall*) xTraceNextFreeEventBufferSlot();\r
+ if (kse != NULL)\r
+ {\r
+ kse->dts = dts1;\r
+ kse->type = (uint8_t)ecode;\r
+ kse->objHandle = (uint8_t)objectNumber;\r
+ prvTraceUpdateCounters();\r
+ }\r
+ }\r
+ trcCRITICAL_SECTION_END();\r
+ }\r
+ }\r
+ }\r
+}\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreKernelCallWithParam\r
+ *\r
+ * Used for storing kernel calls with a handle and a numeric parameter. This is\r
+ * only used for traceTASK_PRIORITY_SET at the moment.\r
+ ******************************************************************************/\r
+void vTraceStoreKernelCallWithParam(uint32_t evtcode,\r
+ traceObjectClass objectClass,\r
+ uint32_t objectNumber,\r
+ uint8_t param)\r
+{\r
+ KernelCallWithParamAndHandle * kse;\r
+ uint8_t dts2;\r
+\r
+ if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && \r
+ (! inExcludedTask || nISRactive))\r
+ {\r
+ /* Check if the referenced object or the event code is excluded */\r
+ if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))\r
+ {\r
+ trcCRITICAL_SECTION_BEGIN();\r
+ dts2 = (uint8_t)prvTraceGetDTS(0xFF);\r
+\r
+ if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+ { \r
+ kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot();\r
+ if (kse != NULL)\r
+ {\r
+ kse->dts = dts2;\r
+ kse->type = (uint8_t)evtcode;\r
+ kse->objHandle = (uint8_t)objectNumber;\r
+ kse->param = param;\r
+ prvTraceUpdateCounters(); \r
+ }\r
+ }\r
+ trcCRITICAL_SECTION_END();\r
+ }\r
+ }\r
+}\r
+\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreKernelCallWithNumericParamOnly\r
+ *\r
+ * Used for storing kernel calls with numeric parameters only. This is\r
+ * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment.\r
+ ******************************************************************************/\r
+void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint16_t param)\r
+{\r
+ KernelCallWithParam16 * kse;\r
+ uint8_t dts6;\r
+\r
+ if (RecorderDataPtr->recorderActive && handle_of_last_logged_task \r
+ && (! inExcludedTask || nISRactive))\r
+ {\r
+ /* Check if the event code is excluded */\r
+ if (!GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))\r
+ {\r
+ trcCRITICAL_SECTION_BEGIN();\r
+ dts6 = (uint8_t)prvTraceGetDTS(0xFF);\r
+\r
+ if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+ { \r
+ kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot();\r
+ if (kse != NULL)\r
+ {\r
+ kse->dts = dts6;\r
+ kse->type = (uint8_t)evtcode;\r
+ kse->param = param;\r
+ prvTraceUpdateCounters(); \r
+ }\r
+ }\r
+ trcCRITICAL_SECTION_END();\r
+ }\r
+ }\r
+}\r
+\r
+objectHandleType handle_of_running_task = 0;\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreTaskswitch\r
+ * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart.\r
+ * At this point interrupts are assumed to be disabled!\r
+ ******************************************************************************/\r
+void vTraceStoreTaskswitch(void)\r
+{\r
+ uint16_t dts3;\r
+ TSEvent* ts; \r
+ int8_t skipEvent = 0;\r
+ uint32_t schedulerState = 0;\r
+ \r
+ /*************************************************************************** \r
+ This is used to detect if a high-priority ISRs is illegally using the \r
+ recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the \r
+ recorder is busy with a task-level event or lower priority ISR event.\r
+ \r
+ If this is detected, it triggers a call to vTraceError with the error \r
+ "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means\r
+ that the macro taskENTER_CRITICAL does not disable this ISR, as required.\r
+ You can solve this by adjusting the value of the FreeRTOS constant\r
+ configMAX_SYSCALL_INTERRUPT_PRIORITY, which is defined in FreeRTOSConfig.h\r
+\r
+ Note: Setting recorder_busy is normally handled in our macros\r
+ trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this \r
+ function since critical sections should not be used in the context switch \r
+ event...) \r
+ ***************************************************************************/\r
+ recorder_busy++; \r
+ \r
+ schedulerState = xTaskGetSchedulerState();\r
+\r
+ if (schedulerState == 0)\r
+ {\r
+ /* This occurs on the very first taskswitch event, generated by \r
+ vTraceStart and uiTraceStart if the scheduler is not yet started.\r
+ This creates a dummy "(startup)" task entry internally in the\r
+ recorder */\r
+ if (handle_of_running_task == 0)\r
+ {\r
+ handle_of_running_task = xTraceGetObjectHandle(TRACE_CLASS_TASK);\r
+\r
+ vTraceSetObjectName(TRACE_CLASS_TASK, \r
+ handle_of_running_task,\r
+ "(startup)");\r
+\r
+ vTraceSetPriorityProperty(TRACE_CLASS_TASK,\r
+ handle_of_running_task,\r
+ 0);\r
+ } \r
+ }\r
+ else\r
+ { \r
+ handle_of_running_task = \r
+ (objectHandleType)uxTaskGetTaskNumber(xTaskGetCurrentTaskHandle());\r
+ }\r
+ \r
+ /* Skip the event if the task has been excluded, using vTraceExcludeTask */\r
+ if (GET_TASK_FLAG_ISEXCLUDED(handle_of_running_task))\r
+ { \r
+ skipEvent = 1;\r
+ inExcludedTask = 1; \r
+ }\r
+ else\r
+ inExcludedTask = 0;\r
+ \r
+\r
+ /* Skip the event if the same task is scheduled */\r
+ if (handle_of_running_task == handle_of_last_logged_task)\r
+ {\r
+ skipEvent = 1;\r
+ }\r
+ \r
+ if (! RecorderDataPtr->recorderActive)\r
+ {\r
+ skipEvent = 1;\r
+ }\r
+\r
+ /* If this event should be logged, log it! */\r
+ if (skipEvent == 0) \r
+ { \r
+ dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);\r
+ \r
+ if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */\r
+ {\r
+ handle_of_last_logged_task = handle_of_running_task; \r
+ ts = (TSEvent*)xTraceNextFreeEventBufferSlot();\r
+\r
+ if (ts != NULL)\r
+ {\r
+ if (uiTraceGetObjectState(TRACE_CLASS_TASK,\r
+ handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE)\r
+ {\r
+ ts->type = TS_TASK_RESUME;\r
+ }\r
+ else\r
+ {\r
+ ts->type = TS_TASK_BEGIN;\r
+ }\r
+\r
+ ts->dts = dts3;\r
+ ts->objHandle = handle_of_last_logged_task;\r
+\r
+ vTraceSetObjectState(TRACE_CLASS_TASK, \r
+ handle_of_last_logged_task, \r
+ TASK_STATE_INSTANCE_ACTIVE);\r
+\r
+ prvTraceUpdateCounters(); \r
+ }\r
+ }\r
+ } \r
+\r
+ /* See comment on recorder_busy++ above. */\r
+ recorder_busy--; \r
+}\r
+\r
+/*******************************************************************************\r
+ * vTraceStoreNameCloseEvent\r
+ *\r
+ * Updates the symbol table with the name of this object from the dynamic\r
+ * objects table and stores a "close" event, holding the mapping between handle\r
+ * and name (a symbol table handle). The stored name-handle mapping is thus the\r
+ * "old" one, valid up until this point.\r
+ ******************************************************************************/\r
+#if (INCLUDE_OBJECT_DELETE == 1)\r
+void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, \r
+ traceObjectClass objectclass)\r
+{ \r
+ ObjCloseNameEvent * ce;\r
+ const char * name;\r
+ traceLabel idx;\r
+\r
+ name = PROPERTY_NAME_GET(objectclass, handle);\r
+\r
+ idx = prvTraceOpenSymbol(name, 0);\r
+ \r
+ // Interrupt disable not necessary, already done in trcHooks.h macro\r
+ ce = (ObjCloseNameEvent*) xTraceNextFreeEventBufferSlot(); \r
+ if (ce != NULL)\r
+ {\r
+ ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass;\r
+ ce->objHandle = handle;\r
+ ce->symbolIndex = idx;\r
+ prvTraceUpdateCounters();\r
+ }\r
+ \r
+}\r
+\r
+void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, \r
+ traceObjectClass objectclass)\r
+{\r
+ ObjClosePropEvent * pe;\r
+\r
+ if (objectclass == TRACE_CLASS_ISR)\r
+ { \r
+ /* ISR handles should not be closed - never called for ISR */\r
+ return;\r
+ }\r
+\r
+ // Interrupt disable not necessary, already done in trcHooks.h macro\r
+ pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot();\r
+ if (pe != NULL)\r
+ {\r
+ if (objectclass == TRACE_CLASS_TASK)\r
+ {\r
+ pe->arg1 = PROPERTY_ACTOR_PRIORITY(objectclass, handle);\r
+ pe->arg2 = PROPERTY_TASK_IFE_SERVICECODE(handle);\r
+ pe->arg3 = PROPERTY_TASK_IFE_OBJHANDLE(handle);\r
+ PROPERTY_TASK_IFE_SERVICECODE(handle) = 0;\r
+ PROPERTY_TASK_IFE_OBJHANDLE(handle) = 0;\r
+ }else{\r
+ pe->arg1 = PROPERTY_OBJECT_STATE(objectclass, handle);\r
+ }\r
+ pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass; \r
+ prvTraceUpdateCounters();\r
+ }\r
+}\r
+#endif\r
+\r
+void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value)\r
+{\r
+ PROPERTY_ACTOR_PRIORITY(objectclass, id) = value;\r
+}\r
+\r
+uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id)\r
+{\r
+ return PROPERTY_ACTOR_PRIORITY(objectclass, id);\r
+}\r
+\r
+void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value)\r
+{\r
+ PROPERTY_OBJECT_STATE(objectclass, id) = value;\r
+}\r
+\r
+void vTraceSetTaskInstanceFinished(objectHandleType handle)\r
+{\r
+#if (USE_IMPLICIT_IFE_RULES == 1)\r
+ if (PROPERTY_TASK_IFE_SERVICECODE(handle) == 0)\r
+ {\r
+ PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0;\r
+ }\r
+#endif\r
+}\r
+\r
+uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id)\r
+{\r
+ return PROPERTY_OBJECT_STATE(objectclass, id);\r
+}\r
+\r
+#endif\r