/******************************************************************************* * vTraceStoreKernelCallWithNumericParamOnly * * Used for storing kernel calls with numeric parameters only. This is * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment. ******************************************************************************/ void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint16_t param) { KernelCallWithParam16 * kse; uint8_t dts6; if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && (! inExcludedTask || nISRactive)) { /* Check if the event code is excluded */ if (!GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) { trcCRITICAL_SECTION_BEGIN(); dts6 = (uint8_t)prvTraceGetDTS(0xFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot(); if (kse != NULL) { kse->dts = dts6; kse->type = (uint8_t)evtcode; kse->param = param; prvTraceUpdateCounters(); } } trcCRITICAL_SECTION_END(); } } }
void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle, traceObjectClass objectclass) { ObjClosePropEvent * pe; if (objectclass == TRACE_CLASS_ISR) { /* ISR handles should not be closed - never called for ISR */ return; } // Interrupt disable not necessary, already done in trcHooks.h macro pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot(); if (pe != NULL) { if (objectclass == TRACE_CLASS_TASK) { pe->arg1 = PROPERTY_ACTOR_PRIORITY(objectclass, handle); pe->arg2 = PROPERTY_TASK_IFE_SERVICECODE(handle); pe->arg3 = PROPERTY_TASK_IFE_OBJHANDLE(handle); PROPERTY_TASK_IFE_SERVICECODE(handle) = 0; PROPERTY_TASK_IFE_OBJHANDLE(handle) = 0; }else{ pe->arg1 = PROPERTY_OBJECT_STATE(objectclass, handle); } pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass; prvTraceUpdateCounters(); } }
/******************************************************************************* * vTraceStoreKernelCallWithParam * * Used for storing kernel calls with a handle and a numeric parameter. This is * only used for traceTASK_PRIORITY_SET at the moment. ******************************************************************************/ void vTraceStoreKernelCallWithParam(uint32_t evtcode, traceObjectClass objectClass, uint32_t objectNumber, uint8_t param) { KernelCallWithParamAndHandle * kse; uint8_t dts2; if (RecorderDataPtr->recorderActive && handle_of_last_logged_task && (! inExcludedTask || nISRactive)) { /* Check if the referenced object or the event code is excluded */ if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode)) { trcCRITICAL_SECTION_BEGIN(); dts2 = (uint8_t)prvTraceGetDTS(0xFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot(); if (kse != NULL) { kse->dts = dts2; kse->type = (uint8_t)evtcode; kse->objHandle = (uint8_t)objectNumber; kse->param = param; prvTraceUpdateCounters(); } } trcCRITICAL_SECTION_END(); } } }
/******************************************************************************* * vTraceStoreKernelCall * * This is the main integration point for storing FreeRTOS kernel calls, and * is called by the hooks in FreeRTOS.h (see trcKernel.h for event codes). ******************************************************************************/ void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber) { KernelCall * kse; uint16_t dts1; if (handle_of_last_logged_task == 0) { return; } if (RecorderDataPtr->recorderActive) { /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */ if (nISRactive || !inExcludedTask) { /* Make sure ISRs never change the IFE flags of tasks */ if (!nISRactive) { /* This checks if this is the first kernel call after a call to vTraceTaskInstanceIsFinished. In that case, calls to this kernel service with this specific kernel object become the "instance finish event" (IFE) of the calling task.*/ if (GET_TASK_FLAG_MARKIFE(handle_of_last_logged_task)) { /* Reset the flag - this has been handled now */ CLEAR_TASK_FLAG_MARKIFE(handle_of_last_logged_task); /* Store the kernel service tagged as instance finished event */ PROPERTY_TASK_IFE_SERVICECODE(handle_of_last_logged_task) = (uint8_t)ecode; /* Store the handle of the specific kernel object */ PROPERTY_TASK_IFE_OBJHANDLE(handle_of_last_logged_task) = (objectHandleType)objectNumber; } } /* Check if the referenced object or the event code is excluded */ if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode)) { trcCRITICAL_SECTION_BEGIN(); dts1 = (uint16_t)prvTraceGetDTS(0xFFFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { kse = (KernelCall*) xTraceNextFreeEventBufferSlot(); if (kse != NULL) { kse->dts = dts1; kse->type = (uint8_t)ecode; kse->objHandle = (uint8_t)objectNumber; prvTraceUpdateCounters(); } } trcCRITICAL_SECTION_END(); } } } }
/******************************************************************************* * prvTraceGetParam * * Used for storing extra bytes for kernel calls with numeric parameters. ******************************************************************************/ static uint32_t prvTraceGetParam(uint32_t param_max, uint32_t param) { XPSEvent* xps; if (param <= param_max) { return param; } else { xps = (XPSEvent*) xTraceNextFreeEventBufferSlot(); if (xps != NULL) { xps->type = DIV_XPS; xps->xps_8 = (param & (0xFF00 & ~param_max)) >> 8; xps->xps_16 = (param & (0xFFFF0000 & ~param_max)) >> 16; prvTraceUpdateCounters(); } return param & param_max; }
void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle, traceObjectClass objectclass) { ObjCloseNameEvent * ce; const char * name; traceLabel idx; name = PROPERTY_NAME_GET(objectclass, handle); idx = prvTraceOpenSymbol(name, 0); // Interrupt disable not necessary, already done in trcHooks.h macro ce = (ObjCloseNameEvent*) xTraceNextFreeEventBufferSlot(); if (ce != NULL) { ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass; ce->objHandle = handle; ce->symbolIndex = idx; prvTraceUpdateCounters(); } }
/******************************************************************************* * vTraceStoreTaskReady * * This function stores a ready state for the task handle sent in as parameter. ******************************************************************************/ void vTraceStoreTaskReady(objectHandleType handle) { uint16_t dts3; TREvent* tr; if (!GET_TASK_FLAG_ISEXCLUDED(handle)) { dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { tr = (TREvent*)xTraceNextFreeEventBufferSlot(); if (tr != NULL) { tr->type = TR_TASK_READY; tr->dts = dts3; tr->objHandle = handle; prvTraceUpdateCounters(); } } } }
/******************************************************************************* * vTraceStoreTaskswitch * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart. * At this point interrupts are assumed to be disabled! ******************************************************************************/ void vTraceStoreTaskswitch(void) { uint16_t dts3; TSEvent* ts; int8_t skipEvent = 0; uint32_t schedulerState = 0; /*************************************************************************** This is used to detect if a high-priority ISRs is illegally using the recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the recorder is busy with a task-level event or lower priority ISR event. If this is detected, it triggers a call to vTraceError with the error "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means that the macro taskENTER_CRITICAL does not disable this ISR, as required. You can solve this by adjusting the value of the FreeRTOS constant configMAX_SYSCALL_INTERRUPT_PRIORITY, which is defined in FreeRTOSConfig.h Note: Setting recorder_busy is normally handled in our macros trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this function since critical sections should not be used in the context switch event...) ***************************************************************************/ recorder_busy++; schedulerState = xTaskGetSchedulerState(); if (schedulerState == 0) { /* This occurs on the very first taskswitch event, generated by vTraceStart and uiTraceStart if the scheduler is not yet started. This creates a dummy "(startup)" task entry internally in the recorder */ if (handle_of_running_task == 0) { handle_of_running_task = xTraceGetObjectHandle(TRACE_CLASS_TASK); vTraceSetObjectName(TRACE_CLASS_TASK, handle_of_running_task, "(startup)"); vTraceSetPriorityProperty(TRACE_CLASS_TASK, handle_of_running_task, 0); } } else { handle_of_running_task = (objectHandleType)uxTaskGetTaskNumber(xTaskGetCurrentTaskHandle()); } /* Skip the event if the task has been excluded, using vTraceExcludeTask */ if (GET_TASK_FLAG_ISEXCLUDED(handle_of_running_task)) { skipEvent = 1; inExcludedTask = 1; } else inExcludedTask = 0; /* Skip the event if the same task is scheduled */ if (handle_of_running_task == handle_of_last_logged_task) { skipEvent = 1; } if (! RecorderDataPtr->recorderActive) { skipEvent = 1; } /* If this event should be logged, log it! */ if (skipEvent == 0) { dts3 = (uint16_t)prvTraceGetDTS(0xFFFF); if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */ { handle_of_last_logged_task = handle_of_running_task; ts = (TSEvent*)xTraceNextFreeEventBufferSlot(); if (ts != NULL) { if (uiTraceGetObjectState(TRACE_CLASS_TASK, handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE) { ts->type = TS_TASK_RESUME; } else { ts->type = TS_TASK_BEGIN; } ts->dts = dts3; ts->objHandle = handle_of_last_logged_task; vTraceSetObjectState(TRACE_CLASS_TASK, handle_of_last_logged_task, TASK_STATE_INSTANCE_ACTIVE); prvTraceUpdateCounters(); } } } /* See comment on recorder_busy++ above. */ recorder_busy--; }
/****************************************************************************** * prvTraceGetDTS * * Returns a differential timestamp (DTS), i.e., the time since * last event, and creates an XTS event if the DTS does not fit in the * number of bits given. The XTS event holds the MSB bytes of the DTS. * * The parameter param_maxDTS should be 0xFF for 8-bit dts or 0xFFFF for * events with 16-bit dts fields. *****************************************************************************/ uint32_t prvTraceGetDTS(uint32_t param_maxDTS) { XTSEvent* xts; int32_t dts = 0; uint32_t old_ts = RecorderDataPtr->absTimeLastEvent; if (RecorderDataPtr->frequency == 0) { /* If HWTC_PERIOD is mapped to the timer reload register, such as in the Cortex M port, it is not initialized before FreeRTOS has been started. We therefore store the frequency of the timer at the first timestamped event after the scheduler has started. (Note that this function is called also by vTraceStart and uiTraceStart, which might be called before the scheduler has been started.) */ #if (SELECTED_PORT == PORT_Win32) RecorderDataPtr->frequency = 100000; #elif (SELECTED_PORT == PORT_HWIndependent) RecorderDataPtr->frequency = configTICK_RATE_HZ; #else if (xTaskGetSchedulerState() != 0) /* Has the scheduler started? */ { RecorderDataPtr->frequency = HWTC_PERIOD * configTICK_RATE_HZ / HWTC_DIVISOR; } #endif } /************************************************************************** * The below statement reads the timestamp from the timer port module. Note * the modulo operation on RecorderDataPtr->frequency, which makes the overflow * case (if (dts < 0)) occur every 1 sec. * This is to make it easier to test. The overflow will happen sooner * or later anyway. **************************************************************************/ if (RecorderDataPtr->frequency > 0) { RecorderDataPtr->absTimeLastEvent = uiTracePortGetTimeStamp() % RecorderDataPtr->frequency; } else { /* Special case if the recorder has not yet started (frequency may be uninitialized, i.e., zero) The modulo operation is not necessary on the first events, since it is surely much less than one second since startup. */ RecorderDataPtr->absTimeLastEvent = uiTracePortGetTimeStamp(); } dts = (int32_t)(RecorderDataPtr->absTimeLastEvent - old_ts); if (dts < 0) /* when the modulo operation wraps around (after 1 second) */ { if (RecorderDataPtr->frequency == 0) { /* Frequency should normally be initialized on the first logged event after the FreeRTOS scheduler has started. In this case, it has not yet been initialized (frequency is 0) and the dts (time since last event) was negative. This is an illegal combination that indicates a problem in uiTracePortGetTimeStamp, probably due to incorrect HWTC macros in trcPort.h. The dts variable normally becomes negative when the modulo operation wraps around, but since the modulo operation is not used in this case (only used if frequency has been set), dts only becomes negative if uiTracePortGetTimeStamp returned a smaller value than last time. This is an error. The values returned by uiTracePortGetTimeStamp should be monotonically incresing (since it is a timestamp). */ vTraceError("Timestamping error, see comment in prvTraceGetDTS (trcBase.c)"); return 0; } dts = (int32_t)(RecorderDataPtr->frequency - old_ts + RecorderDataPtr->absTimeLastEvent); /* This is good for 136 years (incremented every 1 second) */ RecorderDataPtr->absTimeLastEventSecond++; } /* If the dts (time since last event) does not fit in event->dts (only 8 or 16 bits) */ if (dts > (int32_t)param_maxDTS) { /* Create an XTS event (eXtended TimeStamp) containing the higher dts bits*/ xts = (XTSEvent*) xTraceNextFreeEventBufferSlot(); if (xts != NULL) { if (param_maxDTS == 0xFFFF) { xts->type = XTS16; xts->xts_16 = (uint16_t)((dts / 0x10000) & 0xFFFF); xts->xts_8 = 0; } else if (param_maxDTS == 0xFF) { xts->type = XTS8; xts->xts_16 = (uint16_t)((dts / 0x100) & 0xFFFF); xts->xts_8 = (uint8_t)((dts / 0x1000000) & 0xFF); } else { vTraceError("Bad param_maxDTS in prvTraceGetDTS"); } prvTraceUpdateCounters(); } } return dts % (param_maxDTS + 1); }