1 /*******************************************************************************
\r
2 * FreeRTOS+Trace v2.3.0 Recorder Library
\r
3 * Percepio AB, www.percepio.com
\r
7 * Functions for integration of the trace recorder library in the FreeRTOS
\r
8 * kernel (requires FreeRTOS v7.1.0 or later).
\r
11 * This software is copyright Percepio AB. The recorder library is free for
\r
12 * use together with Percepio products. You may distribute the recorder library
\r
13 * in its original form, including modifications in trcPort.c and trcPort.h
\r
14 * given that these modification are clearly marked as your own modifications
\r
15 * and documented in the initial comment section of these source files.
\r
16 * This software is the intellectual property of Percepio AB and may not be
\r
17 * sold or in other ways commercially redistributed without explicit written
\r
18 * permission by Percepio AB.
\r
21 * The trace tool and recorder library is being delivered to you AS IS and
\r
22 * Percepio AB makes no warranty as to its use or performance. Percepio AB does
\r
23 * not and cannot warrant the performance or results you may obtain by using the
\r
24 * software or documentation. Percepio AB make no warranties, express or
\r
25 * implied, as to noninfringement of third party rights, merchantability, or
\r
26 * fitness for any particular purpose. In no event will Percepio AB, its
\r
27 * technology partners, or distributors be liable to you for any consequential,
\r
28 * incidental or special damages, including any lost profits or lost savings,
\r
29 * even if a representative of Percepio AB has been advised of the possibility
\r
30 * of such damages, or for any claim by any third party. Some jurisdictions do
\r
31 * not allow the exclusion or limitation of incidental, consequential or special
\r
32 * damages, or the exclusion of implied warranties or limitations on how long an
\r
33 * implied warranty may last, so the above limitations may not apply to you.
\r
35 * FreeRTOS+Trace is available as Free Edition and in two premium editions.
\r
36 * You may use the premium features during 30 days for evaluation.
\r
37 * Download FreeRTOS+Trace at http://www.percepio.com/products/downloads/
\r
39 * Copyright Percepio AB, 2012.
\r
41 ******************************************************************************/
\r
43 #include "trcUser.h"
\r
46 #if (configUSE_TRACE_FACILITY == 1)
\r
50 /******************************************************************************
\r
51 * TraceObjectClassTable
\r
52 * Translates a FreeRTOS QueueType into trace objects classes (TRACE_CLASS_).
\r
53 * This was added since we want to map both types of Mutex and both types of
\r
54 * Semaphores on common classes for all Mutexes and all Semaphores respectively.
\r
56 * FreeRTOS Queue types
\r
57 * #define queueQUEUE_TYPE_BASE ( 0U ) => TRACE_CLASS_QUEUE
\r
58 * #define queueQUEUE_TYPE_MUTEX ( 1U ) => TRACE_CLASS_MUTEX
\r
59 * #define queueQUEUE_TYPE_COUNTING_SEMAPHORE ( 2U ) => TRACE_CLASS_SEMAPHORE
\r
60 * #define queueQUEUE_TYPE_BINARY_SEMAPHORE ( 3U ) => TRACE_CLASS_SEMAPHORE
\r
61 * #define queueQUEUE_TYPE_RECURSIVE_MUTEX ( 4U ) => TRACE_CLASS_MUTEX
\r
62 ******************************************************************************/
\r
63 traceObjectClass TraceObjectClassTable[5] = {TRACE_CLASS_QUEUE,
\r
65 TRACE_CLASS_SEMAPHORE,
\r
66 TRACE_CLASS_SEMAPHORE,
\r
67 TRACE_CLASS_MUTEX };
\r
69 /* This is defined in FreeRTOS! */
\r
70 extern volatile void * volatile pxCurrentTCB;
\r
72 /* Internal variables */
\r
73 uint8_t nISRactive = 0;
\r
74 objectHandleType handle_of_last_logged_task = 0;
\r
75 uint8_t inExcludedTask = 0;
\r
77 static uint8_t prvTraceIsObjectExcluded(traceObjectClass, uint32_t);
\r
79 /*******************************************************************************
\r
80 * prvTraceIsObjectExcluded
\r
82 * Private function that accepts an object class and an object number and uses
\r
83 * that to determine if the object has been flagged as excluded.
\r
84 ******************************************************************************/
\r
85 static uint8_t prvTraceIsObjectExcluded(traceObjectClass objectClass, uint32_t objectNumber)
\r
89 case TRACE_CLASS_QUEUE:
\r
90 return GET_QUEUE_FLAG_ISEXCLUDED(objectNumber);
\r
92 case TRACE_CLASS_SEMAPHORE:
\r
93 return GET_SEMAPHORE_FLAG_ISEXCLUDED(objectNumber);
\r
95 case TRACE_CLASS_MUTEX:
\r
96 return GET_MUTEX_FLAG_ISEXCLUDED(objectNumber);
\r
98 case TRACE_CLASS_TASK:
\r
99 return GET_TASK_FLAG_ISEXCLUDED(objectNumber);
\r
105 #if !defined INCLUDE_READY_EVENTS || INCLUDE_READY_EVENTS == 1
\r
106 /*******************************************************************************
\r
107 * vTraceStoreTaskReady
\r
109 * This function stores a ready state for the task handle sent in as parameter.
\r
110 ******************************************************************************/
\r
111 void vTraceStoreTaskReady(objectHandleType handle)
\r
116 if (!GET_TASK_FLAG_ISEXCLUDED(handle))
\r
118 dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);
\r
119 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
121 tr = (TREvent*)xTraceNextFreeEventBufferSlot();
\r
125 tr->type = TR_TASK_READY;
\r
127 tr->objHandle = handle;
\r
129 prvTraceUpdateCounters();
\r
136 /*******************************************************************************
\r
137 * vTraceStoreKernelCall
\r
139 * This is the main integration point for storing FreeRTOS kernel calls, and
\r
140 * is called by the hooks in FreeRTOS.h (see trcKernel.h for event codes).
\r
141 ******************************************************************************/
\r
142 void vTraceStoreKernelCall(uint32_t ecode, traceObjectClass objectClass, uint32_t objectNumber)
\r
147 if (handle_of_last_logged_task == 0)
\r
152 if (RecorderDataPtr->recorderActive)
\r
155 /* If it is an ISR or NOT an excluded task, this kernel call will be stored in the trace */
\r
156 if (nISRactive || !inExcludedTask)
\r
158 /* Make sure ISRs never change the IFE flags of tasks */
\r
161 /* This checks if this is the first kernel call after a call to
\r
162 vTraceTaskInstanceIsFinished. In that case, calls to this kernel service
\r
163 with this specific kernel object become the "instance finish event"
\r
164 (IFE) of the calling task.*/
\r
165 if (GET_TASK_FLAG_MARKIFE(handle_of_last_logged_task))
\r
167 /* Reset the flag - this has been handled now */
\r
168 CLEAR_TASK_FLAG_MARKIFE(handle_of_last_logged_task);
\r
170 /* Store the kernel service tagged as instance finished event */
\r
171 PROPERTY_TASK_IFE_SERVICECODE(handle_of_last_logged_task) =
\r
174 /* Store the handle of the specific kernel object */
\r
175 PROPERTY_TASK_IFE_OBJHANDLE(handle_of_last_logged_task) =
\r
176 (objectHandleType)objectNumber;
\r
180 /* Check if the referenced object or the event code is excluded */
\r
181 if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(ecode))
\r
183 trcCRITICAL_SECTION_BEGIN();
\r
184 dts1 = (uint16_t)prvTraceGetDTS(0xFFFF);
\r
186 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
188 kse = (KernelCall*) xTraceNextFreeEventBufferSlot();
\r
192 kse->type = (uint8_t)ecode;
\r
193 kse->objHandle = (uint8_t)objectNumber;
\r
194 prvTraceUpdateCounters();
\r
197 trcCRITICAL_SECTION_END();
\r
203 /*******************************************************************************
\r
204 * vTraceStoreKernelCallWithParam
\r
206 * Used for storing kernel calls with a handle and a numeric parameter. This is
\r
207 * only used for traceTASK_PRIORITY_SET at the moment.
\r
208 ******************************************************************************/
\r
209 void vTraceStoreKernelCallWithParam(uint32_t evtcode,
\r
210 traceObjectClass objectClass,
\r
211 uint32_t objectNumber,
\r
214 KernelCallWithParamAndHandle * kse;
\r
217 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task &&
\r
218 (! inExcludedTask || nISRactive))
\r
220 /* Check if the referenced object or the event code is excluded */
\r
221 if (!prvTraceIsObjectExcluded(objectClass, objectNumber) && !GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))
\r
223 trcCRITICAL_SECTION_BEGIN();
\r
224 dts2 = (uint8_t)prvTraceGetDTS(0xFF);
\r
226 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
228 kse = (KernelCallWithParamAndHandle*) xTraceNextFreeEventBufferSlot();
\r
232 kse->type = (uint8_t)evtcode;
\r
233 kse->objHandle = (uint8_t)objectNumber;
\r
234 kse->param = param;
\r
235 prvTraceUpdateCounters();
\r
238 trcCRITICAL_SECTION_END();
\r
244 /*******************************************************************************
\r
245 * vTraceStoreKernelCallWithNumericParamOnly
\r
247 * Used for storing kernel calls with numeric parameters only. This is
\r
248 * only used for traceTASK_DELAY and traceDELAY_UNTIL at the moment.
\r
249 ******************************************************************************/
\r
250 void vTraceStoreKernelCallWithNumericParamOnly(uint32_t evtcode, uint16_t param)
\r
252 KernelCallWithParam16 * kse;
\r
255 if (RecorderDataPtr->recorderActive && handle_of_last_logged_task
\r
256 && (! inExcludedTask || nISRactive))
\r
258 /* Check if the event code is excluded */
\r
259 if (!GET_EVENT_CODE_FLAG_ISEXCLUDED(evtcode))
\r
261 trcCRITICAL_SECTION_BEGIN();
\r
262 dts6 = (uint8_t)prvTraceGetDTS(0xFF);
\r
264 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
266 kse = (KernelCallWithParam16*) xTraceNextFreeEventBufferSlot();
\r
270 kse->type = (uint8_t)evtcode;
\r
271 kse->param = param;
\r
272 prvTraceUpdateCounters();
\r
275 trcCRITICAL_SECTION_END();
\r
280 objectHandleType handle_of_running_task = 0;
\r
282 /*******************************************************************************
\r
283 * vTraceStoreTaskswitch
\r
284 * Called by the scheduler from the SWITCHED_OUT hook, and by uiTraceStart.
\r
285 * At this point interrupts are assumed to be disabled!
\r
286 ******************************************************************************/
\r
287 void vTraceStoreTaskswitch(void)
\r
291 int8_t skipEvent = 0;
\r
292 uint32_t schedulerState = 0;
\r
294 /***************************************************************************
\r
295 This is used to detect if a high-priority ISRs is illegally using the
\r
296 recorder ISR trace functions (vTraceStoreISRBegin and ...End) while the
\r
297 recorder is busy with a task-level event or lower priority ISR event.
\r
299 If this is detected, it triggers a call to vTraceError with the error
\r
300 "Illegal call to vTraceStoreISRBegin/End". If you get this error, it means
\r
301 that the macro taskENTER_CRITICAL does not disable this ISR, as required.
\r
302 You can solve this by adjusting the value of the FreeRTOS constant
\r
303 configMAX_SYSCALL_INTERRUPT_PRIORITY, which is defined in FreeRTOSConfig.h
\r
305 Note: Setting recorder_busy is normally handled in our macros
\r
306 trcCRITICAL_SECTION_BEGIN and _END, but is needed explicitly in this
\r
307 function since critical sections should not be used in the context switch
\r
309 ***************************************************************************/
\r
312 schedulerState = xTaskGetSchedulerState();
\r
314 if (schedulerState == 0)
\r
316 /* This occurs on the very first taskswitch event, generated by
\r
317 vTraceStart and uiTraceStart if the scheduler is not yet started.
\r
318 This creates a dummy "(startup)" task entry internally in the
\r
320 if (handle_of_running_task == 0)
\r
322 handle_of_running_task = xTraceGetObjectHandle(TRACE_CLASS_TASK);
\r
324 vTraceSetObjectName(TRACE_CLASS_TASK,
\r
325 handle_of_running_task,
\r
328 vTraceSetPriorityProperty(TRACE_CLASS_TASK,
\r
329 handle_of_running_task,
\r
335 handle_of_running_task =
\r
336 (objectHandleType)uxTaskGetTaskNumber(xTaskGetCurrentTaskHandle());
\r
339 /* Skip the event if the task has been excluded, using vTraceExcludeTask */
\r
340 if (GET_TASK_FLAG_ISEXCLUDED(handle_of_running_task))
\r
343 inExcludedTask = 1;
\r
346 inExcludedTask = 0;
\r
349 /* Skip the event if the same task is scheduled */
\r
350 if (handle_of_running_task == handle_of_last_logged_task)
\r
355 if (! RecorderDataPtr->recorderActive)
\r
360 /* If this event should be logged, log it! */
\r
361 if (skipEvent == 0)
\r
363 dts3 = (uint16_t)prvTraceGetDTS(0xFFFF);
\r
365 if (RecorderDataPtr->recorderActive) /* Need to repeat this check! */
\r
367 handle_of_last_logged_task = handle_of_running_task;
\r
368 ts = (TSEvent*)xTraceNextFreeEventBufferSlot();
\r
372 if (uiTraceGetObjectState(TRACE_CLASS_TASK,
\r
373 handle_of_last_logged_task) == TASK_STATE_INSTANCE_ACTIVE)
\r
375 ts->type = TS_TASK_RESUME;
\r
379 ts->type = TS_TASK_BEGIN;
\r
383 ts->objHandle = handle_of_last_logged_task;
\r
385 vTraceSetObjectState(TRACE_CLASS_TASK,
\r
386 handle_of_last_logged_task,
\r
387 TASK_STATE_INSTANCE_ACTIVE);
\r
389 prvTraceUpdateCounters();
\r
394 /* See comment on recorder_busy++ above. */
\r
398 /*******************************************************************************
\r
399 * vTraceStoreNameCloseEvent
\r
401 * Updates the symbol table with the name of this object from the dynamic
\r
402 * objects table and stores a "close" event, holding the mapping between handle
\r
403 * and name (a symbol table handle). The stored name-handle mapping is thus the
\r
404 * "old" one, valid up until this point.
\r
405 ******************************************************************************/
\r
406 #if (INCLUDE_OBJECT_DELETE == 1)
\r
407 void vTraceStoreObjectNameOnCloseEvent(objectHandleType handle,
\r
408 traceObjectClass objectclass)
\r
410 ObjCloseNameEvent * ce;
\r
414 name = PROPERTY_NAME_GET(objectclass, handle);
\r
416 idx = prvTraceOpenSymbol(name, 0);
\r
418 // Interrupt disable not necessary, already done in trcHooks.h macro
\r
419 ce = (ObjCloseNameEvent*) xTraceNextFreeEventBufferSlot();
\r
422 ce->type = EVENTGROUP_OBJCLOSE_NAME + objectclass;
\r
423 ce->objHandle = handle;
\r
424 ce->symbolIndex = idx;
\r
425 prvTraceUpdateCounters();
\r
430 void vTraceStoreObjectPropertiesOnCloseEvent(objectHandleType handle,
\r
431 traceObjectClass objectclass)
\r
433 ObjClosePropEvent * pe;
\r
435 if (objectclass == TRACE_CLASS_ISR)
\r
437 /* ISR handles should not be closed - never called for ISR */
\r
441 // Interrupt disable not necessary, already done in trcHooks.h macro
\r
442 pe = (ObjClosePropEvent*) xTraceNextFreeEventBufferSlot();
\r
445 if (objectclass == TRACE_CLASS_TASK)
\r
447 pe->arg1 = PROPERTY_ACTOR_PRIORITY(objectclass, handle);
\r
448 pe->arg2 = PROPERTY_TASK_IFE_SERVICECODE(handle);
\r
449 pe->arg3 = PROPERTY_TASK_IFE_OBJHANDLE(handle);
\r
450 PROPERTY_TASK_IFE_SERVICECODE(handle) = 0;
\r
451 PROPERTY_TASK_IFE_OBJHANDLE(handle) = 0;
\r
453 pe->arg1 = PROPERTY_OBJECT_STATE(objectclass, handle);
\r
455 pe->type = EVENTGROUP_OBJCLOSE_PROP + objectclass;
\r
456 prvTraceUpdateCounters();
\r
461 void vTraceSetPriorityProperty(uint8_t objectclass, uint8_t id, uint8_t value)
\r
463 PROPERTY_ACTOR_PRIORITY(objectclass, id) = value;
\r
466 uint8_t uiTraceGetPriorityProperty(uint8_t objectclass, uint8_t id)
\r
468 return PROPERTY_ACTOR_PRIORITY(objectclass, id);
\r
471 void vTraceSetObjectState(uint8_t objectclass, uint8_t id, uint8_t value)
\r
473 PROPERTY_OBJECT_STATE(objectclass, id) = value;
\r
476 void vTraceSetTaskInstanceFinished(objectHandleType handle)
\r
478 #if (USE_IMPLICIT_IFE_RULES == 1)
\r
479 if (PROPERTY_TASK_IFE_SERVICECODE(handle) == 0)
\r
481 PROPERTY_OBJECT_STATE(TRACE_CLASS_TASK, handle) = 0;
\r
486 uint8_t uiTraceGetObjectState(uint8_t objectclass, uint8_t id)
\r
488 return PROPERTY_OBJECT_STATE(objectclass, id);
\r